From 7f7a3e8f70c46a2a5a5ef120909c8211840ef5cb Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 29 Jun 2017 14:36:26 +0200 Subject: tests: Move busy loop to test support Update #3056. --- cpukit/libmisc/Makefile.am | 1 + cpukit/libmisc/testsupport/test.h | 18 +++- cpukit/libmisc/testsupport/testbusy.c | 107 +++++++++++++++++++++ .../sptests/spintrcritical_support/intrcritical.c | 96 ++---------------- 4 files changed, 135 insertions(+), 87 deletions(-) create mode 100644 cpukit/libmisc/testsupport/testbusy.c diff --git a/cpukit/libmisc/Makefile.am b/cpukit/libmisc/Makefile.am index d8fa47a2a5..6772dd1673 100644 --- a/cpukit/libmisc/Makefile.am +++ b/cpukit/libmisc/Makefile.am @@ -174,6 +174,7 @@ libstringto_a_SOURCES = stringto/stringtodouble.c stringto/stringtofloat.c \ noinst_LIBRARIES += libtestsupport.a libtestsupport_a_SOURCES = libtestsupport_a_SOURCES += testsupport/testbeginend.c +libtestsupport_a_SOURCES += testsupport/testbusy.c libtestsupport_a_SOURCES += testsupport/testextension.c libtestsupport_a_SOURCES += testsupport/testparallel.c diff --git a/cpukit/libmisc/testsupport/test.h b/cpukit/libmisc/testsupport/test.h index a32e2c42c1..d9ac6caf91 100644 --- a/cpukit/libmisc/testsupport/test.h +++ b/cpukit/libmisc/testsupport/test.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016 embedded brains GmbH. All rights reserved. + * Copyright (c) 2014, 2017 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Dornierstr. 4 @@ -260,6 +260,22 @@ void rtems_test_parallel( size_t job_count ); +/** + * @brief Performs a busy loop with the specified iteration count. + * + * This function is optimized to not perform memory accesses and should have a + * small jitter. + * + * @param[in] count The iteration count. + */ +void rtems_test_busy(uint_fast32_t count); + +/** + * @brief Returns a count value for rtems_test_busy() which yields roughly a + * duration of one clock tick. + */ +uint_fast32_t rtems_test_get_one_tick_busy_count(void); + /** @} */ #ifdef __cplusplus diff --git a/cpukit/libmisc/testsupport/testbusy.c b/cpukit/libmisc/testsupport/testbusy.c new file mode 100644 index 0000000000..2d34a805dc --- /dev/null +++ b/cpukit/libmisc/testsupport/testbusy.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2014, 2017 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +static uint_fast32_t estimate_busy_loop_maximum( void ) +{ + uint_fast32_t units = 0; + uint_fast32_t initial = rtems_clock_get_ticks_since_boot(); + + while ( initial == rtems_clock_get_ticks_since_boot() ) { + ++units; + } + + return units; +} + +static uint_fast32_t wait_for_tick_change( void ) +{ + uint_fast32_t initial = rtems_clock_get_ticks_since_boot(); + uint_fast32_t now; + + do { + now = rtems_clock_get_ticks_since_boot(); + } while ( now == initial ); + + return now; +} + +/* + * It is important that we use actually use the same rtems_test_busy() function + * at the various places, since otherwise the obtained maximum value might be + * wrong. So, the compiler must not inline this function. + */ +RTEMS_NO_INLINE void rtems_test_busy( uint_fast32_t count ) +{ + uint_fast32_t i = 0; + + do { + __asm__ volatile (""); + ++i; + } while ( i < count ); +} + +uint_fast32_t rtems_test_get_one_tick_busy_count( void ) +{ + uint_fast32_t last; + uint_fast32_t now; + uint_fast32_t a; + uint_fast32_t b; + uint_fast32_t m; + + /* Choose a lower bound */ + a = 1; + + /* Estimate an upper bound */ + + wait_for_tick_change(); + b = 2 * estimate_busy_loop_maximum(); + + while ( true ) { + last = wait_for_tick_change(); + rtems_test_busy( b ); + now = rtems_clock_get_ticks_since_boot(); + + if ( now != last ) { + break; + } + + b *= 2; + last = now; + } + + /* Find a good value */ + do { + m = ( a + b ) / 2; + + last = wait_for_tick_change(); + rtems_test_busy( m ); + now = rtems_clock_get_ticks_since_boot(); + + if ( now != last ) { + b = m; + } else { + a = m; + } + } while ( b - a > 1 ); + + return m; +} diff --git a/testsuites/sptests/spintrcritical_support/intrcritical.c b/testsuites/sptests/spintrcritical_support/intrcritical.c index a9fcdd2a37..51ab42f5d6 100644 --- a/testsuites/sptests/spintrcritical_support/intrcritical.c +++ b/testsuites/sptests/spintrcritical_support/intrcritical.c @@ -17,9 +17,9 @@ #define INTERRUPT_CRITICAL_NAME rtems_build_name( 'I', 'C', 'R', 'I' ) typedef struct { - rtems_interval minimum; - rtems_interval maximum; - rtems_interval maximum_current; + uint_fast32_t minimum; + uint_fast32_t maximum; + uint_fast32_t maximum_current; rtems_timer_service_routine_entry tsr; rtems_id timer; uint64_t t0; @@ -28,19 +28,7 @@ typedef struct { static interrupt_critical_control interrupt_critical; -static rtems_interval estimate_busy_loop_maximum( void ) -{ - rtems_interval units = 0; - rtems_interval initial = rtems_clock_get_ticks_since_boot(); - - while ( initial == rtems_clock_get_ticks_since_boot() ) { - ++units; - } - - return units; -} - -static rtems_interval wait_for_tick_change( void ) +static void wait_for_tick_change( void ) { rtems_interval initial = rtems_clock_get_ticks_since_boot(); rtems_interval now; @@ -48,75 +36,11 @@ static rtems_interval wait_for_tick_change( void ) do { now = rtems_clock_get_ticks_since_boot(); } while ( now == initial ); - - return now; -} - -/* - * It is important that we use actually use the same busy() function at the - * various places, since otherwise the obtained maximum value might be wrong. - * So the compiler must not inline this function. - */ -static __attribute__( ( noinline ) ) void busy( rtems_interval max ) -{ - rtems_interval i = 0; - - do { - __asm__ volatile (""); - ++i; - } while ( i < max ); -} - -static rtems_interval get_one_tick_busy_value( void ) -{ - rtems_interval last; - rtems_interval now; - rtems_interval a; - rtems_interval b; - rtems_interval m; - - /* Choose a lower bound */ - a = 1; - - /* Estimate an upper bound */ - - wait_for_tick_change(); - b = 2 * estimate_busy_loop_maximum(); - - while ( true ) { - last = wait_for_tick_change(); - busy( b ); - now = rtems_clock_get_ticks_since_boot(); - - if ( now != last ) { - break; - } - - b *= 2; - last = now; - } - - /* Find a good value */ - do { - m = ( a + b ) / 2; - - last = wait_for_tick_change(); - busy( m ); - now = rtems_clock_get_ticks_since_boot(); - - if ( now != last ) { - b = m; - } else { - a = m; - } - } while ( b - a > 1 ); - - return m; } static bool interrupt_critical_busy_wait( void ) { - rtems_interval max = interrupt_critical.maximum_current; + uint_fast32_t max = interrupt_critical.maximum_current; bool reset = max <= interrupt_critical.minimum; if ( reset ) { @@ -125,7 +49,7 @@ static bool interrupt_critical_busy_wait( void ) interrupt_critical.maximum_current = max - 1; } - busy( max ); + rtems_test_busy( max ); return reset; } @@ -134,7 +58,7 @@ void interrupt_critical_section_test_support_initialize( rtems_timer_service_routine_entry tsr ) { - rtems_interval m; + uint_fast32_t m; interrupt_critical.tsr = tsr; @@ -146,7 +70,7 @@ void interrupt_critical_section_test_support_initialize( rtems_test_assert( sc == RTEMS_SUCCESSFUL ); } - m = get_one_tick_busy_value(); + m = rtems_test_get_one_tick_busy_count(); interrupt_critical.minimum = 0; interrupt_critical.maximum = m; @@ -197,7 +121,7 @@ bool interrupt_critical_section_test( rtems_status_code sc; rtems_id id; uint64_t delta; - rtems_interval busy_delta; + uint_fast32_t busy_delta; int retries = 3; interrupt_critical_section_test_support_initialize( tsr ); @@ -222,7 +146,7 @@ bool interrupt_critical_section_test( /* Update minimum */ delta = interrupt_critical.t1 - interrupt_critical.t0; - busy_delta = (rtems_interval) + busy_delta = (uint_fast32_t) ( ( interrupt_critical.maximum * ( 2 * delta ) ) / rtems_configuration_get_nanoseconds_per_tick() ); -- cgit v1.2.3