From 53ad908a646eb6fd67f9b4586f4b484e8255b9d3 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 7 Mar 2014 14:36:22 +0100 Subject: score: Add SMP lock profiling support --- c/src/lib/libbsp/sparc/leon3/amba/amba.c | 3 +- cpukit/libblock/src/diskdevs.c | 3 +- cpukit/libcsupport/src/sup_fs_location.c | 2 +- cpukit/libcsupport/src/termios.c | 2 +- cpukit/posix/src/psignal.c | 2 +- cpukit/rtems/include/rtems/rtems/asrimpl.h | 2 +- cpukit/rtems/include/rtems/rtems/intr.h | 8 +- cpukit/sapi/src/chainsmp.c | 2 +- cpukit/sapi/src/profilingiterate.c | 62 ++++ cpukit/score/Makefile.am | 1 + cpukit/score/include/rtems/score/isrlock.h | 16 +- cpukit/score/include/rtems/score/percpu.h | 21 +- cpukit/score/include/rtems/score/smplock.h | 409 ++++++++++++++++++++++++-- cpukit/score/src/coretod.c | 2 +- cpukit/score/src/percpu.c | 3 +- cpukit/score/src/profilingsmplock.c | 42 +++ cpukit/score/src/smp.c | 2 +- cpukit/score/src/threaddispatchdisablelevel.c | 2 +- cpukit/score/src/threadhandler.c | 3 +- testsuites/smptests/smplock01/init.c | 6 +- testsuites/sptests/sp37/init.c | 8 +- testsuites/sptests/spcache01/init.c | 4 +- testsuites/sptests/spnsext01/init.c | 2 +- testsuites/sptests/spprofiling01/init.c | 92 +++++- testsuites/tmtests/tmcontext01/init.c | 2 +- 25 files changed, 648 insertions(+), 53 deletions(-) create mode 100644 cpukit/score/src/profilingsmplock.c diff --git a/c/src/lib/libbsp/sparc/leon3/amba/amba.c b/c/src/lib/libbsp/sparc/leon3/amba/amba.c index 65550cb07f..01d83cbfb9 100644 --- a/c/src/lib/libbsp/sparc/leon3/amba/amba.c +++ b/c/src/lib/libbsp/sparc/leon3/amba/amba.c @@ -23,7 +23,8 @@ */ struct ambapp_bus ambapp_plb; -rtems_interrupt_lock LEON3_IrqCtrl_Lock = RTEMS_INTERRUPT_LOCK_INITIALIZER; +rtems_interrupt_lock LEON3_IrqCtrl_Lock = + RTEMS_INTERRUPT_LOCK_INITIALIZER("LEON3 IrqCtrl"); /* Pointers to Interrupt Controller configuration registers */ volatile struct irqmp_regs *LEON3_IrqCtrl_Regs; diff --git a/cpukit/libblock/src/diskdevs.c b/cpukit/libblock/src/diskdevs.c index 7e01ab338a..c0570565d5 100644 --- a/cpukit/libblock/src/diskdevs.c +++ b/cpukit/libblock/src/diskdevs.c @@ -57,7 +57,8 @@ static rtems_id diskdevs_mutex; */ static volatile bool diskdevs_protected; -static rtems_interrupt_lock diskdevs_lock = RTEMS_INTERRUPT_LOCK_INITIALIZER; +static rtems_interrupt_lock diskdevs_lock = + RTEMS_INTERRUPT_LOCK_INITIALIZER("diskdevs"); static rtems_status_code disk_lock(void) diff --git a/cpukit/libcsupport/src/sup_fs_location.c b/cpukit/libcsupport/src/sup_fs_location.c index 040f8c274e..226ba28160 100644 --- a/cpukit/libcsupport/src/sup_fs_location.c +++ b/cpukit/libcsupport/src/sup_fs_location.c @@ -29,7 +29,7 @@ #include rtems_interrupt_lock rtems_filesystem_mt_entry_lock_control = - RTEMS_INTERRUPT_LOCK_INITIALIZER; + RTEMS_INTERRUPT_LOCK_INITIALIZER("mount table entry"); static rtems_filesystem_global_location_t *deferred_released_global_locations; diff --git a/cpukit/libcsupport/src/termios.c b/cpukit/libcsupport/src/termios.c index 4022e7c516..ce4c1aad4c 100644 --- a/cpukit/libcsupport/src/termios.c +++ b/cpukit/libcsupport/src/termios.c @@ -230,7 +230,7 @@ rtems_termios_open ( */ tty->device = *callbacks; - rtems_interrupt_lock_initialize (&tty->interrupt_lock); + rtems_interrupt_lock_initialize (&tty->interrupt_lock, "Termios"); /* * Create I/O tasks diff --git a/cpukit/posix/src/psignal.c b/cpukit/posix/src/psignal.c index fbe96b34ea..76f4c119b3 100644 --- a/cpukit/posix/src/psignal.c +++ b/cpukit/posix/src/psignal.c @@ -45,7 +45,7 @@ RTEMS_STATIC_ASSERT( /*** PROCESS WIDE STUFF ****/ -ISR_lock_Control _POSIX_signals_Lock = ISR_LOCK_INITIALIZER; +ISR_lock_Control _POSIX_signals_Lock = ISR_LOCK_INITIALIZER("POSIX signals"); sigset_t _POSIX_signals_Pending; diff --git a/cpukit/rtems/include/rtems/rtems/asrimpl.h b/cpukit/rtems/include/rtems/rtems/asrimpl.h index d67198f175..442ee38e4c 100644 --- a/cpukit/rtems/include/rtems/rtems/asrimpl.h +++ b/cpukit/rtems/include/rtems/rtems/asrimpl.h @@ -46,7 +46,7 @@ RTEMS_INLINE_ROUTINE void _ASR_Initialize ( asr->signals_posted = 0; asr->signals_pending = 0; asr->nest_level = 0; - _ISR_lock_Initialize( &asr->Lock ); + _ISR_lock_Initialize( &asr->Lock, "ASR" ); } /** diff --git a/cpukit/rtems/include/rtems/rtems/intr.h b/cpukit/rtems/include/rtems/rtems/intr.h index 04bcb72ff4..01820f8f31 100644 --- a/cpukit/rtems/include/rtems/rtems/intr.h +++ b/cpukit/rtems/include/rtems/rtems/intr.h @@ -167,7 +167,7 @@ typedef ISR_lock_Context rtems_interrupt_lock_context; /** * @brief Initializer for static initialization of interrupt locks. */ -#define RTEMS_INTERRUPT_LOCK_INITIALIZER ISR_LOCK_INITIALIZER +#define RTEMS_INTERRUPT_LOCK_INITIALIZER( _name ) ISR_LOCK_INITIALIZER( _name ) /** * @brief Initializes an interrupt lock. @@ -175,9 +175,11 @@ typedef ISR_lock_Context rtems_interrupt_lock_context; * Concurrent initialization leads to unpredictable results. * * @param[in,out] _lock The interrupt lock. + * @param[in] _name The name for the interrupt lock. This name must be + * persistent throughout the life time of this lock. */ -#define rtems_interrupt_lock_initialize( _lock ) \ - _ISR_lock_Initialize( _lock ) +#define rtems_interrupt_lock_initialize( _lock, _name ) \ + _ISR_lock_Initialize( _lock, _name ) /** * @brief Destroys an interrupt lock. diff --git a/cpukit/sapi/src/chainsmp.c b/cpukit/sapi/src/chainsmp.c index 3f041ba0b2..267d1cde84 100644 --- a/cpukit/sapi/src/chainsmp.c +++ b/cpukit/sapi/src/chainsmp.c @@ -22,7 +22,7 @@ #include -static SMP_lock_Control chain_lock = SMP_LOCK_INITIALIZER; +static SMP_lock_Control chain_lock = SMP_LOCK_INITIALIZER("chains"); static void chain_acquire( SMP_lock_Context *lock_context ) { diff --git a/cpukit/sapi/src/profilingiterate.c b/cpukit/sapi/src/profilingiterate.c index 28c06a4689..956dbde887 100644 --- a/cpukit/sapi/src/profilingiterate.c +++ b/cpukit/sapi/src/profilingiterate.c @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -76,6 +77,66 @@ static void per_cpu_stats_iterate( #endif } +#if defined(RTEMS_PROFILING) && defined(RTEMS_SMP) +RTEMS_STATIC_ASSERT( + RTEMS_PROFILING_SMP_LOCK_CONTENTION_COUNTS + == SMP_LOCK_STATS_CONTENTION_COUNTS, + smp_lock_contention_counts +); +#endif + +static void smp_lock_stats_iterate( + rtems_profiling_visitor visitor, + void *visitor_arg, + rtems_profiling_data *data +) +{ +#if defined(RTEMS_PROFILING) && defined(RTEMS_SMP) + SMP_lock_Stats_iteration_context iteration_context; + SMP_lock_Stats snapshot; + char name[64]; + + memset(data, 0, sizeof(*data)); + data->header.type = RTEMS_PROFILING_SMP_LOCK; + + _SMP_lock_Stats_iteration_start(&iteration_context); + while ( + _SMP_lock_Stats_iteration_next( + &iteration_context, + &snapshot, + &name[0], + sizeof(name) + ) + ) { + rtems_profiling_smp_lock *smp_lock_data = &data->smp_lock; + + smp_lock_data->name = name; + smp_lock_data->max_acquire_time = + rtems_counter_ticks_to_nanoseconds(snapshot.max_acquire_time); + smp_lock_data->max_section_time = + rtems_counter_ticks_to_nanoseconds(snapshot.max_section_time); + smp_lock_data->usage_count = snapshot.usage_count; + smp_lock_data->total_acquire_time = + rtems_counter_ticks_to_nanoseconds(snapshot.total_acquire_time); + smp_lock_data->total_section_time = + rtems_counter_ticks_to_nanoseconds(snapshot.total_section_time); + + memcpy( + &smp_lock_data->contention_counts[0], + &snapshot.contention_counts[0], + sizeof(smp_lock_data->contention_counts) + ); + + (*visitor)(visitor_arg, data); + } + _SMP_lock_Stats_iteration_stop(&iteration_context); +#else + (void) visitor; + (void) visitor_arg; + (void) data; +#endif +} + void rtems_profiling_iterate( rtems_profiling_visitor visitor, void *visitor_arg @@ -84,4 +145,5 @@ void rtems_profiling_iterate( rtems_profiling_data data; per_cpu_stats_iterate(visitor, visitor_arg, &data); + smp_lock_stats_iterate(visitor, visitor_arg, &data); } diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index f3f53a980c..d747c91094 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -123,6 +123,7 @@ libscore_a_SOURCES += src/mpci.c src/objectmp.c src/threadmp.c endif if HAS_SMP +libscore_a_SOURCES += src/profilingsmplock.c libscore_a_SOURCES += src/schedulerprioritysmp.c libscore_a_SOURCES += src/schedulersimplesmp.c libscore_a_SOURCES += src/schedulersmpstartidle.c diff --git a/cpukit/score/include/rtems/score/isrlock.h b/cpukit/score/include/rtems/score/isrlock.h index 27e4aadffa..b12b174ebc 100644 --- a/cpukit/score/include/rtems/score/isrlock.h +++ b/cpukit/score/include/rtems/score/isrlock.h @@ -71,10 +71,10 @@ typedef struct { * @brief Initializer for static initialization of ISR locks. */ #if defined( RTEMS_SMP ) - #define ISR_LOCK_INITIALIZER \ - { SMP_LOCK_INITIALIZER } + #define ISR_LOCK_INITIALIZER( name ) \ + { SMP_LOCK_INITIALIZER( name ) } #else - #define ISR_LOCK_INITIALIZER \ + #define ISR_LOCK_INITIALIZER( name ) \ { } #endif @@ -84,13 +84,19 @@ typedef struct { * Concurrent initialization leads to unpredictable results. * * @param[in,out] lock The ISR lock control. + * @param[in] name The name for the ISR lock. This name must be persistent + * throughout the life time of this lock. */ -static inline void _ISR_lock_Initialize( ISR_lock_Control *lock ) +static inline void _ISR_lock_Initialize( + ISR_lock_Control *lock, + const char *name +) { #if defined( RTEMS_SMP ) - _SMP_lock_Initialize( &lock->lock ); + _SMP_lock_Initialize( &lock->lock, name ); #else (void) lock; + (void) name; #endif } diff --git a/cpukit/score/include/rtems/score/percpu.h b/cpukit/score/include/rtems/score/percpu.h index 5ba463e812..d9b73029fc 100644 --- a/cpukit/score/include/rtems/score/percpu.h +++ b/cpukit/score/include/rtems/score/percpu.h @@ -40,7 +40,11 @@ extern "C" { * used in assembler code to easily get the per-CPU control for a particular * processor. */ - #define PER_CPU_CONTROL_SIZE_LOG2 7 + #if defined( RTEMS_PROFILING ) + #define PER_CPU_CONTROL_SIZE_LOG2 8 + #else + #define PER_CPU_CONTROL_SIZE_LOG2 7 + #endif #define PER_CPU_CONTROL_SIZE ( 1 << PER_CPU_CONTROL_SIZE_LOG2 ) #endif @@ -286,6 +290,11 @@ typedef struct { */ SMP_ticket_lock_Control Lock; + /** + * @brief Lock statistics context for the per-CPU lock. + */ + SMP_lock_Stats_context Lock_stats_context; + /** * @brief Context for the Giant lock acquire and release pair of this * processor. @@ -333,7 +342,10 @@ extern Per_CPU_Control_envelope _Per_CPU_Information[] CPU_STRUCTURE_ALIGNMENT; #if defined( RTEMS_SMP ) #define _Per_CPU_Acquire( per_cpu ) \ - _SMP_ticket_lock_Acquire( &( per_cpu )->Lock ) + _SMP_ticket_lock_Acquire( \ + &( per_cpu )->Lock, \ + &( per_cpu )->Lock_stats_context \ + ) #else #define _Per_CPU_Acquire( per_cpu ) \ do { \ @@ -343,7 +355,10 @@ extern Per_CPU_Control_envelope _Per_CPU_Information[] CPU_STRUCTURE_ALIGNMENT; #if defined( RTEMS_SMP ) #define _Per_CPU_Release( per_cpu ) \ - _SMP_ticket_lock_Release( &( per_cpu )->Lock ) + _SMP_ticket_lock_Release( \ + &( per_cpu )->Lock, \ + &( per_cpu )->Lock_stats_context \ + ) #else #define _Per_CPU_Release( per_cpu ) \ do { \ diff --git a/cpukit/score/include/rtems/score/smplock.h b/cpukit/score/include/rtems/score/smplock.h index 288fd454da..fc92f285fe 100644 --- a/cpukit/score/include/rtems/score/smplock.h +++ b/cpukit/score/include/rtems/score/smplock.h @@ -27,6 +27,11 @@ #include #include +#if defined( RTEMS_PROFILING ) +#include +#include +#endif + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -49,19 +54,171 @@ extern "C" { * @{ */ +/** + * @brief Count of lock contention counters for lock statistics. + */ +#define SMP_LOCK_STATS_CONTENTION_COUNTS 4 + +/** + * @brief SMP lock statistics. + * + * The lock acquire attempt instant is the point in time right after the + * interrupt disable action in the lock acquire sequence. + * + * The lock acquire instant is the point in time right after the lock + * acquisition. This is the begin of the critical section code execution. + * + * The lock release instant is the point in time right before the interrupt + * enable action in the lock release sequence. + * + * The lock section time is the time elapsed between the lock acquire instant + * and the lock release instant. + * + * The lock acquire time is the time elapsed between the lock acquire attempt + * instant and the lock acquire instant. + */ +typedef struct { +#if defined( RTEMS_PROFILING ) + /** + * @brief Node for SMP lock statistics chain. + */ + Chain_Node Node; + + /** + * @brief The maximum lock acquire time in CPU counter ticks. + */ + CPU_Counter_ticks max_acquire_time; + + /** + * @brief The maximum lock section time in CPU counter ticks. + */ + CPU_Counter_ticks max_section_time; + + /** + * @brief The count of lock uses. + * + * This value may overflow. + */ + uint64_t usage_count; + + /** + * @brief Total lock acquire time in nanoseconds. + * + * The average lock acquire time is the total acquire time divided by the + * lock usage count. The ration of the total section and total acquire times + * gives a measure for the lock contention. + * + * This value may overflow. + */ + uint64_t total_acquire_time; + + /** + * @brief The counts of lock acquire operations by contention. + * + * The contention count for index N corresponds to a lock acquire attempt + * with an initial queue length of N. The last index corresponds to all + * lock acquire attempts with an initial queue length greater than or equal + * to SMP_LOCK_STATS_CONTENTION_COUNTS minus one. + * + * The values may overflow. + */ + uint64_t contention_counts[SMP_LOCK_STATS_CONTENTION_COUNTS]; + + /** + * @brief Total lock section time in CPU counter ticks. + * + * The average lock section time is the total section time divided by the + * lock usage count. + * + * This value may overflow. + */ + uint64_t total_section_time; + + /** + * @brief The lock name. + */ + const char *name; +#endif /* defined( RTEMS_PROFILING ) */ +} SMP_lock_Stats; + +/** + * @brief Local context for SMP lock statistics. + */ +typedef struct { +#if defined( RTEMS_PROFILING ) + /** + * @brief The last lock acquire instant in CPU counter ticks. + * + * This value is used to measure the lock section time. + */ + CPU_Counter_ticks acquire_instant; +#endif +} SMP_lock_Stats_context; + +/** + * @brief SMP lock statistics initializer for static initialization. + */ +#if defined( RTEMS_PROFILING ) +#define SMP_LOCK_STATS_INITIALIZER( name ) \ + { { NULL, NULL }, 0, 0, 0, 0, { 0, 0, 0, 0 }, 0, name } +#else +#define SMP_LOCK_STATS_INITIALIZER( name ) \ + { } +#endif + +/** + * @brief Initializes an SMP lock statistics block. + * + * @param[in, out] stats The SMP lock statistics block. + * @param[in] name The name for the SMP lock statistics. This name must be + * persistent throughout the life time of this statistics block. + */ +static inline void _SMP_lock_Stats_initialize( + SMP_lock_Stats *stats, + const char *name +) +{ + SMP_lock_Stats init = SMP_LOCK_STATS_INITIALIZER( name ); + + *stats = init; +} + +/** + * @brief Destroys an SMP lock statistics block. + * + * @param[in,out] stats The SMP lock statistics block. + */ +static inline void _SMP_lock_Stats_destroy( SMP_lock_Stats *stats ); + +/** + * @brief Destroys an SMP lock statistics block. + * + * @param[in,out] stats The SMP lock statistics block. + * @param[in] stats_context The SMP lock statistics context. + */ +static inline void _SMP_lock_Stats_release_update( + SMP_lock_Stats *stats, + const SMP_lock_Stats_context *stats_context +); + /** * @brief SMP ticket lock control. */ typedef struct { Atomic_Uint next_ticket; Atomic_Uint now_serving; + SMP_lock_Stats Stats; } SMP_ticket_lock_Control; /** * @brief SMP ticket lock control initializer for static initialization. */ -#define SMP_TICKET_LOCK_INITIALIZER \ - { ATOMIC_INITIALIZER_UINT( 0U ), ATOMIC_INITIALIZER_UINT( 0U ) } +#define SMP_TICKET_LOCK_INITIALIZER( name ) \ + { \ + ATOMIC_INITIALIZER_UINT( 0U ), \ + ATOMIC_INITIALIZER_UINT( 0U ), \ + SMP_LOCK_STATS_INITIALIZER( name ) \ + } /** * @brief Initializes an SMP ticket lock. @@ -69,11 +226,17 @@ typedef struct { * Concurrent initialization leads to unpredictable results. * * @param[in,out] lock The SMP ticket lock control. + * @param[in] name The name for the SMP ticket lock. This name must be + * persistent throughout the life time of this lock. */ -static inline void _SMP_ticket_lock_Initialize( SMP_ticket_lock_Control *lock ) +static inline void _SMP_ticket_lock_Initialize( + SMP_ticket_lock_Control *lock, + const char *name +) { _Atomic_Init_uint( &lock->next_ticket, 0U ); _Atomic_Init_uint( &lock->now_serving, 0U ); + _SMP_lock_Stats_initialize( &lock->Stats, name ); } /** @@ -85,7 +248,7 @@ static inline void _SMP_ticket_lock_Initialize( SMP_ticket_lock_Control *lock ) */ static inline void _SMP_ticket_lock_Destroy( SMP_ticket_lock_Control *lock ) { - (void) lock; + _SMP_lock_Stats_destroy( &lock->Stats ); } /** @@ -96,30 +259,83 @@ static inline void _SMP_ticket_lock_Destroy( SMP_ticket_lock_Control *lock ) * the SMP ticket lock. * * @param[in,out] lock The SMP ticket lock control. + * @param[out] stats_context The SMP lock statistics context. */ -static inline void _SMP_ticket_lock_Acquire( SMP_ticket_lock_Control *lock ) +static inline void _SMP_ticket_lock_Acquire( + SMP_ticket_lock_Control *lock, + SMP_lock_Stats_context *stats_context +) { - unsigned int my_ticket = - _Atomic_Fetch_add_uint( &lock->next_ticket, 1U, ATOMIC_ORDER_RELAXED ); + unsigned int my_ticket; unsigned int now_serving; - do { - now_serving = - _Atomic_Load_uint( &lock->now_serving, ATOMIC_ORDER_ACQUIRE ); - } while ( now_serving != my_ticket ); +#if defined( RTEMS_PROFILING ) + SMP_lock_Stats *stats = &lock->Stats; + CPU_Counter_ticks first; + CPU_Counter_ticks second; + CPU_Counter_ticks delta; + unsigned int initial_queue_length; + + first = _CPU_Counter_read(); +#endif + + my_ticket = + _Atomic_Fetch_add_uint( &lock->next_ticket, 1U, ATOMIC_ORDER_RELAXED ); + +#if defined( RTEMS_PROFILING ) + now_serving = + _Atomic_Load_uint( &lock->now_serving, ATOMIC_ORDER_ACQUIRE ); + initial_queue_length = my_ticket - now_serving; + + if ( initial_queue_length > 0 ) { +#endif + + do { + now_serving = + _Atomic_Load_uint( &lock->now_serving, ATOMIC_ORDER_ACQUIRE ); + } while ( now_serving != my_ticket ); + +#if defined( RTEMS_PROFILING ) + } + + second = _CPU_Counter_read(); + stats_context->acquire_instant = second; + delta = _CPU_Counter_difference( second, first ); + + ++stats->usage_count; + + stats->total_acquire_time += delta; + + if ( stats->max_acquire_time < delta ) { + stats->max_acquire_time = delta; + } + + if ( initial_queue_length >= SMP_LOCK_STATS_CONTENTION_COUNTS ) { + initial_queue_length = SMP_LOCK_STATS_CONTENTION_COUNTS - 1; + } + ++stats->contention_counts[initial_queue_length]; +#else + (void) stats_context; +#endif } /** * @brief Releases an SMP ticket lock. * * @param[in,out] lock The SMP ticket lock control. + * @param[in] stats_context The SMP lock statistics context. */ -static inline void _SMP_ticket_lock_Release( SMP_ticket_lock_Control *lock ) +static inline void _SMP_ticket_lock_Release( + SMP_ticket_lock_Control *lock, + const SMP_lock_Stats_context *stats_context +) { unsigned int current_ticket = _Atomic_Load_uint( &lock->now_serving, ATOMIC_ORDER_RELAXED ); unsigned int next_ticket = current_ticket + 1U; + _SMP_lock_Stats_release_update( &lock->Stats, stats_context ); + _Atomic_Store_uint( &lock->now_serving, next_ticket, ATOMIC_ORDER_RELEASE ); } @@ -135,12 +351,13 @@ typedef struct { */ typedef struct { ISR_Level isr_level; + SMP_lock_Stats_context Stats_context; } SMP_lock_Context; /** * @brief SMP lock control initializer for static initialization. */ -#define SMP_LOCK_INITIALIZER { SMP_TICKET_LOCK_INITIALIZER } +#define SMP_LOCK_INITIALIZER( name ) { SMP_TICKET_LOCK_INITIALIZER( name ) } /** * @brief Initializes an SMP lock. @@ -148,10 +365,15 @@ typedef struct { * Concurrent initialization leads to unpredictable results. * * @param[in,out] lock The SMP lock control. + * @param[in] name The name for the SMP lock statistics. This name must be + * persistent throughout the life time of this statistics block. */ -static inline void _SMP_lock_Initialize( SMP_lock_Control *lock ) +static inline void _SMP_lock_Initialize( + SMP_lock_Control *lock, + const char *name +) { - _SMP_ticket_lock_Initialize( &lock->ticket_lock ); + _SMP_ticket_lock_Initialize( &lock->ticket_lock, name ); } /** @@ -183,7 +405,7 @@ static inline void _SMP_lock_Acquire( ) { (void) context; - _SMP_ticket_lock_Acquire( &lock->ticket_lock ); + _SMP_ticket_lock_Acquire( &lock->ticket_lock, &context->Stats_context ); } /** @@ -199,7 +421,7 @@ static inline void _SMP_lock_Release( ) { (void) context; - _SMP_ticket_lock_Release( &lock->ticket_lock ); + _SMP_ticket_lock_Release( &lock->ticket_lock, &context->Stats_context ); } /** @@ -234,6 +456,159 @@ static inline void _SMP_lock_Release_and_ISR_enable( _ISR_Enable_without_giant( context->isr_level ); } +#if defined( RTEMS_PROFILING ) +typedef struct { + SMP_lock_Control Lock; + Chain_Control Stats_chain; + Chain_Control Iterator_chain; +} SMP_lock_Stats_control; + +typedef struct { + Chain_Node Node; + SMP_lock_Stats *current; +} SMP_lock_Stats_iteration_context; + +extern SMP_lock_Stats_control _SMP_lock_Stats_control; + +static inline void _SMP_lock_Stats_iteration_start( + SMP_lock_Stats_iteration_context *iteration_context +) +{ + SMP_lock_Stats_control *control = &_SMP_lock_Stats_control; + SMP_lock_Context lock_context; + + _SMP_lock_ISR_disable_and_acquire( &control->Lock, &lock_context ); + + _Chain_Append_unprotected( + &control->Iterator_chain, + &iteration_context->Node + ); + iteration_context->current = + (SMP_lock_Stats *) _Chain_First( &control->Stats_chain ); + + _SMP_lock_Release_and_ISR_enable( &control->Lock, &lock_context ); +} + +static inline bool _SMP_lock_Stats_iteration_next( + SMP_lock_Stats_iteration_context *iteration_context, + SMP_lock_Stats *snapshot, + char *name, + size_t name_size +) +{ + SMP_lock_Stats_control *control = &_SMP_lock_Stats_control; + SMP_lock_Context lock_context; + SMP_lock_Stats *current; + bool valid; + + _SMP_lock_ISR_disable_and_acquire( &control->Lock, &lock_context ); + + current = iteration_context->current; + if ( !_Chain_Is_tail( &control->Stats_chain, ¤t->Node ) ) { + size_t name_len = strlen(current->name); + + valid = true; + + iteration_context->current = (SMP_lock_Stats *) + _Chain_Next( ¤t->Node ); + + *snapshot = *current; + snapshot->name = name; + + if ( name_len >= name_size ) { + name_len = name_size - 1; + } + + name[name_len] = '\0'; + memcpy(name, current->name, name_len); + } else { + valid = false; + } + + _SMP_lock_Release_and_ISR_enable( &control->Lock, &lock_context ); + + return valid; +} + +static inline void _SMP_lock_Stats_iteration_stop( + SMP_lock_Stats_iteration_context *iteration_context +) +{ + SMP_lock_Stats_control *control = &_SMP_lock_Stats_control; + SMP_lock_Context lock_context; + + _SMP_lock_ISR_disable_and_acquire( &control->Lock, &lock_context ); + _Chain_Extract_unprotected( &iteration_context->Node ); + _SMP_lock_Release_and_ISR_enable( &control->Lock, &lock_context ); +} +#endif + +static inline void _SMP_lock_Stats_destroy( SMP_lock_Stats *stats ) +{ +#if defined( RTEMS_PROFILING ) + if ( !_Chain_Is_node_off_chain( &stats->Node ) ) { + SMP_lock_Stats_control *control = &_SMP_lock_Stats_control; + SMP_lock_Context lock_context; + SMP_lock_Stats_iteration_context *iteration_context; + SMP_lock_Stats_iteration_context *iteration_context_tail; + SMP_lock_Stats *next_stats; + + _SMP_lock_ISR_disable_and_acquire( &control->Lock, &lock_context ); + + next_stats = (SMP_lock_Stats *) _Chain_Next( &stats->Node ); + _Chain_Extract_unprotected( &stats->Node ); + + iteration_context = (SMP_lock_Stats_iteration_context *) + _Chain_First( &control->Iterator_chain ); + iteration_context_tail = (SMP_lock_Stats_iteration_context *) + _Chain_Tail( &control->Iterator_chain ); + + while ( iteration_context != iteration_context_tail ) { + if ( iteration_context->current == stats ) { + iteration_context->current = next_stats; + } + + iteration_context = (SMP_lock_Stats_iteration_context *) + _Chain_Next( &iteration_context->Node ); + } + + _SMP_lock_Release_and_ISR_enable( &control->Lock, &lock_context ); + } +#else + (void) stats; +#endif +} + +static inline void _SMP_lock_Stats_release_update( + SMP_lock_Stats *stats, + const SMP_lock_Stats_context *stats_context +) +{ +#if defined( RTEMS_PROFILING ) + CPU_Counter_ticks first = stats_context->acquire_instant; + CPU_Counter_ticks second = _CPU_Counter_read(); + CPU_Counter_ticks delta = _CPU_Counter_difference( second, first ); + + stats->total_section_time += delta; + + if ( stats->max_section_time < delta ) { + stats->max_section_time = delta; + + if ( _Chain_Is_node_off_chain( &stats->Node ) ) { + SMP_lock_Stats_control *control = &_SMP_lock_Stats_control; + SMP_lock_Context lock_context; + + _SMP_lock_ISR_disable_and_acquire( &control->Lock, &lock_context ); + _Chain_Append_unprotected( &control->Stats_chain, &stats->Node ); + _SMP_lock_Release_and_ISR_enable( &control->Lock, &lock_context ); + } + } +#else + (void) stats; + (void) stats_context; +#endif +} + /**@}*/ #ifdef __cplusplus diff --git a/cpukit/score/src/coretod.c b/cpukit/score/src/coretod.c index 25edef021d..a6c85f128b 100644 --- a/cpukit/score/src/coretod.c +++ b/cpukit/score/src/coretod.c @@ -29,7 +29,7 @@ void _TOD_Handler_initialization(void) { TOD_Control *tod = &_TOD; - _ISR_lock_Initialize( &tod->lock ); + _ISR_lock_Initialize( &tod->lock, "TOD" ); _Timestamp_Set( &tod->now, TOD_SECONDS_1970_THROUGH_1988, 0 ); diff --git a/cpukit/score/src/percpu.c b/cpukit/score/src/percpu.c index 50e523941c..6d31ed40e5 100644 --- a/cpukit/score/src/percpu.c +++ b/cpukit/score/src/percpu.c @@ -26,7 +26,8 @@ #if defined(RTEMS_SMP) -static SMP_lock_Control _Per_CPU_State_lock = SMP_LOCK_INITIALIZER; +static SMP_lock_Control _Per_CPU_State_lock = + SMP_LOCK_INITIALIZER("per-CPU state"); static void _Per_CPU_State_busy_wait( const Per_CPU_Control *per_cpu, diff --git a/cpukit/score/src/profilingsmplock.c b/cpukit/score/src/profilingsmplock.c new file mode 100644 index 0000000000..4ab761b3d0 --- /dev/null +++ b/cpukit/score/src/profilingsmplock.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014 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.com/license/LICENSE. + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include + +#if defined( RTEMS_PROFILING ) +SMP_lock_Stats_control _SMP_lock_Stats_control = { + .Lock = { + .ticket_lock = { + .next_ticket = ATOMIC_INITIALIZER_UINT( 0U ), + .now_serving = ATOMIC_INITIALIZER_UINT( 0U ), + .Stats = { + .Node = CHAIN_NODE_INITIALIZER_ONE_NODE_CHAIN( + &_SMP_lock_Stats_control.Stats_chain + ), + .name = "SMP lock stats" + } + } + }, + .Stats_chain = CHAIN_INITIALIZER_ONE_NODE( + &_SMP_lock_Stats_control.Lock.ticket_lock.Stats.Node + ), + .Iterator_chain = CHAIN_INITIALIZER_EMPTY( + _SMP_lock_Stats_control.Iterator_chain + ) +}; +#endif /* defined( RTEMS_PROFILING ) */ diff --git a/cpukit/score/src/smp.c b/cpukit/score/src/smp.c index 40d2ac3088..389a4d6c99 100644 --- a/cpukit/score/src/smp.c +++ b/cpukit/score/src/smp.c @@ -32,7 +32,7 @@ void _SMP_Handler_initialize( void ) for ( cpu = 0 ; cpu < max_cpus; ++cpu ) { Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu ); - _SMP_ticket_lock_Initialize( &per_cpu->Lock ); + _SMP_ticket_lock_Initialize( &per_cpu->Lock, "per-CPU" ); } /* diff --git a/cpukit/score/src/threaddispatchdisablelevel.c b/cpukit/score/src/threaddispatchdisablelevel.c index ab004c1662..abd8c97cd5 100644 --- a/cpukit/score/src/threaddispatchdisablelevel.c +++ b/cpukit/score/src/threaddispatchdisablelevel.c @@ -29,7 +29,7 @@ typedef struct { } Giant_Control; static Giant_Control _Giant = { - .lock = SMP_LOCK_INITIALIZER, + .lock = SMP_LOCK_INITIALIZER("Giant"), .owner_cpu = NO_OWNER_CPU, .nest_level = 0 }; diff --git a/cpukit/score/src/threadhandler.c b/cpukit/score/src/threadhandler.c index a85cebe905..752b2d5310 100644 --- a/cpukit/score/src/threadhandler.c +++ b/cpukit/score/src/threadhandler.c @@ -56,7 +56,8 @@ bool doCons = false; #if defined(RTEMS_SMP) - static SMP_lock_Control constructor_lock = SMP_LOCK_INITIALIZER; + static SMP_lock_Control constructor_lock = + SMP_LOCK_INITIALIZER("constructor"); SMP_lock_Context lock_context; diff --git a/testsuites/smptests/smplock01/init.c b/testsuites/smptests/smplock01/init.c index 7c536c304c..a445c8404f 100644 --- a/testsuites/smptests/smplock01/init.c +++ b/testsuites/smptests/smplock01/init.c @@ -48,7 +48,7 @@ typedef struct { static global_context context = { .state = ATOMIC_INITIALIZER_UINT(INITIAL), .barrier = SMP_BARRIER_CONTROL_INITIALIZER, - .lock = SMP_LOCK_INITIALIZER + .lock = SMP_LOCK_INITIALIZER("global") }; static const char *test_names[TEST_COUNT] = { @@ -141,7 +141,7 @@ static void test_2_body( SMP_lock_Control lock; SMP_lock_Context lock_context; - _SMP_lock_Initialize(&lock); + _SMP_lock_Initialize(&lock, "local"); while (assert_state(ctx, START_TEST)) { _SMP_lock_Acquire(&lock, &lock_context); @@ -166,7 +166,7 @@ static void test_3_body( SMP_lock_Control lock; SMP_lock_Context lock_context; - _SMP_lock_Initialize(&lock); + _SMP_lock_Initialize(&lock, "local"); while (assert_state(ctx, START_TEST)) { _SMP_lock_Acquire(&lock, &lock_context); diff --git a/testsuites/sptests/sp37/init.c b/testsuites/sptests/sp37/init.c index 4a3e08c862..1097dc8fab 100644 --- a/testsuites/sptests/sp37/init.c +++ b/testsuites/sptests/sp37/init.c @@ -160,11 +160,11 @@ static void test_isr_level( void ) static void test_isr_locks( void ) { ISR_Level normal_interrupt_level = _ISR_Get_level(); - ISR_lock_Control initialized = ISR_LOCK_INITIALIZER; + ISR_lock_Control initialized = ISR_LOCK_INITIALIZER("test"); ISR_lock_Control lock; ISR_lock_Context lock_context; - _ISR_lock_Initialize( &lock ); + _ISR_lock_Initialize( &lock, "test" ); rtems_test_assert( memcmp( &lock, &initialized, sizeof( lock ) ) == 0 ); _ISR_lock_ISR_disable_and_acquire( &lock, &lock_context ); @@ -197,11 +197,11 @@ static rtems_mode get_interrupt_level( void ) static void test_interrupt_locks( void ) { rtems_mode normal_interrupt_level = get_interrupt_level(); - rtems_interrupt_lock initialized = RTEMS_INTERRUPT_LOCK_INITIALIZER; + rtems_interrupt_lock initialized = RTEMS_INTERRUPT_LOCK_INITIALIZER("test"); rtems_interrupt_lock lock; rtems_interrupt_lock_context lock_context; - rtems_interrupt_lock_initialize( &lock ); + rtems_interrupt_lock_initialize( &lock, "test" ); rtems_test_assert( memcmp( &lock, &initialized, sizeof( lock ) ) == 0 ); rtems_interrupt_lock_acquire( &lock, &lock_context ); diff --git a/testsuites/sptests/spcache01/init.c b/testsuites/sptests/spcache01/init.c index 4c0c3c3f61..92ea4ec599 100644 --- a/testsuites/sptests/spcache01/init.c +++ b/testsuites/sptests/spcache01/init.c @@ -48,7 +48,7 @@ static void test_data_flush_and_invalidate(void) printf("data cache flush and invalidate test\n"); - rtems_interrupt_lock_initialize(&lock); + rtems_interrupt_lock_initialize(&lock, "test"); rtems_interrupt_lock_acquire(&lock, &lock_context); for (i = 0; i < n; ++i) { @@ -168,7 +168,7 @@ static void test_timing(void) uint32_t cache_level; size_t cache_size; - rtems_interrupt_lock_initialize(&lock); + rtems_interrupt_lock_initialize(&lock, "test"); printf( "data cache line size %zi bytes\n" diff --git a/testsuites/sptests/spnsext01/init.c b/testsuites/sptests/spnsext01/init.c index b445679fb9..2ffd237ce6 100644 --- a/testsuites/sptests/spnsext01/init.c +++ b/testsuites/sptests/spnsext01/init.c @@ -51,7 +51,7 @@ static rtems_task Init(rtems_task_argument argument) n = (3 * n) / 2; - rtems_interrupt_lock_initialize(&lock); + rtems_interrupt_lock_initialize(&lock, "test"); rtems_interrupt_lock_acquire(&lock, &lock_context); sc = rtems_clock_get_uptime(&uptime); rtems_test_assert(sc == RTEMS_SUCCESSFUL); diff --git a/testsuites/sptests/spprofiling01/init.c b/testsuites/sptests/spprofiling01/init.c index a1af66bba2..a1f6cd7f3c 100644 --- a/testsuites/sptests/spprofiling01/init.c +++ b/testsuites/sptests/spprofiling01/init.c @@ -21,10 +21,97 @@ #include #include +#include #include "tmacros.h" -static void test(void) +typedef struct { + rtems_interrupt_lock a; + rtems_interrupt_lock b; + rtems_interrupt_lock c; + rtems_interrupt_lock d; + enum { + WAIT_FOR_A, + EXPECT_B, + EXPECT_D, + DONE + } state; +} visitor_context; + +static bool is_equal(const rtems_profiling_smp_lock *psl, const char *name) +{ + return strcmp(psl->name, name) == 0; +} + +static void visitor(void *arg, const rtems_profiling_data *data) +{ + visitor_context *ctx = arg; + + if (data->header.type == RTEMS_PROFILING_SMP_LOCK) { + const rtems_profiling_smp_lock *psl = &data->smp_lock; + + switch (ctx->state) { + case WAIT_FOR_A: + rtems_test_assert(!is_equal(psl, "b")); + rtems_test_assert(!is_equal(psl, "c")); + rtems_test_assert(!is_equal(psl, "d")); + + if (is_equal(psl, "a")) { + ctx->state = EXPECT_B; + } + break; + case EXPECT_B: + rtems_test_assert(is_equal(psl, "b")); + rtems_interrupt_lock_destroy(&ctx->c); + ctx->state = EXPECT_D; + break; + case EXPECT_D: + rtems_test_assert(is_equal(psl, "d")); + ctx->state = DONE; + break; + case DONE: + rtems_test_assert(!is_equal(psl, "a")); + rtems_test_assert(!is_equal(psl, "b")); + rtems_test_assert(!is_equal(psl, "c")); + rtems_test_assert(!is_equal(psl, "d")); + break; + } + } +} + +static void lock_init(rtems_interrupt_lock *lock, const char *name) +{ + rtems_interrupt_lock_context lock_context; + + rtems_interrupt_lock_initialize(lock, name); + rtems_interrupt_lock_acquire(lock, &lock_context); + rtems_interrupt_lock_release(lock, &lock_context); +} + +static void test_iterate(void) +{ + visitor_context ctx_instance; + visitor_context *ctx = &ctx_instance; + + ctx->state = WAIT_FOR_A; + lock_init(&ctx->a, "a"); + lock_init(&ctx->b, "b"); + lock_init(&ctx->c, "c"); + lock_init(&ctx->d, "d"); + + rtems_profiling_iterate(visitor, ctx); + + rtems_interrupt_lock_destroy(&ctx->a); + rtems_interrupt_lock_destroy(&ctx->b); + + if (ctx->state != DONE) { + rtems_interrupt_lock_destroy(&ctx->c); + } + + rtems_interrupt_lock_destroy(&ctx->d); +} + +static void test_report_xml(void) { rtems_status_code sc; int rv; @@ -40,7 +127,8 @@ static void Init(rtems_task_argument arg) { puts("\n\n*** TEST SPPROFILING 1 ***"); - test(); + test_iterate(); + test_report_xml(); puts("*** END OF TEST SPPROFILING 1 ***"); diff --git a/testsuites/tmtests/tmcontext01/init.c b/testsuites/tmtests/tmcontext01/init.c index bd047a2ccf..aa7bef9f9b 100644 --- a/testsuites/tmtests/tmcontext01/init.c +++ b/testsuites/tmtests/tmcontext01/init.c @@ -138,7 +138,7 @@ static void test_by_function_level(int fl, bool dirty) uint64_t q3; uint64_t max; - rtems_interrupt_lock_initialize(&lock); + rtems_interrupt_lock_initialize(&lock, "test"); rtems_interrupt_lock_acquire(&lock, &lock_context); for (s = 0; s < SAMPLES; ++s) { -- cgit v1.2.3