On Mon, Mar 10, 2014 at 9:28 AM, Sebastian Huber <sebastian.hu...@embedded-brains.de> wrote: > --- > 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 | 60 ++++ > 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 | 396 +++++++++++++++++++++++- > 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/tmtests/tmcontext01/init.c | 2 +- > 24 files changed, 543 insertions(+), 51 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 65550cb..01d83cb 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 7e01ab3..c057056 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 040f8c2..226ba28 100644 > --- a/cpukit/libcsupport/src/sup_fs_location.c > +++ b/cpukit/libcsupport/src/sup_fs_location.c > @@ -29,7 +29,7 @@ > #include <rtems/score/threaddispatch.h> > > 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 65072a0..9582995 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 fbe96b3..76f4c11 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 d67198f..442ee38 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 04bcb72..01820f8 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 3f041ba..267d1cd 100644 > --- a/cpukit/sapi/src/chainsmp.c > +++ b/cpukit/sapi/src/chainsmp.c > @@ -22,7 +22,7 @@ > > #include <rtems/score/smplock.h> > > -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 28c06a4..00a09cd 100644 > --- a/cpukit/sapi/src/profilingiterate.c > +++ b/cpukit/sapi/src/profilingiterate.c > @@ -18,6 +18,7 @@ > > #include <rtems/profiling.h> > #include <rtems/counter.h> > +#include <rtems/score/smplock.h> > #include <rtems.h> > > #include <string.h> > @@ -76,6 +77,64 @@ static void per_cpu_stats_iterate( > #endif > } > > +#ifdef RTEMS_PROFILING > +RTEMS_STATIC_ASSERT( > + RTEMS_PROFILING_SMP_LOCK_CONTENTION_COUNTS > + == SMP_LOCK_STATS_CONTENTION_COUNTS, > + smp_lock_contention_counts > +); Is the requirement these two CPP macros be equal documented somewhere?
> +#endif > + > +static void smp_lock_stats_iterate( > + rtems_profiling_visitor visitor, > + void *visitor_arg, > + rtems_profiling_data *data > +) > +{ > +#ifdef RTEMS_PROFILING > + 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_section_time = > + rtems_counter_ticks_to_nanoseconds(snapshot.max_section_time); > + smp_lock_data->max_acquire_time = > + rtems_counter_ticks_to_nanoseconds(snapshot.max_acquire_time); > + smp_lock_data->usage_count = snapshot.usage_count; > + 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 +143,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 f3f53a9..d747c91 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 27e4aad..b12b174 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 e8f3370..c279ee3 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 > @@ -287,6 +291,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 288fd45..6b98f1c 100644 > --- a/cpukit/score/include/rtems/score/smplock.h > +++ b/cpukit/score/include/rtems/score/smplock.h > @@ -27,6 +27,11 @@ > #include <rtems/score/atomic.h> > #include <rtems/score/isrlevel.h> > > +#if defined( RTEMS_PROFILING ) > +#include <rtems/score/chainimpl.h> > +#include <string.h> > +#endif > + > #ifdef __cplusplus > extern "C" { > #endif /* __cplusplus */ > @@ -50,18 +55,159 @@ 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 section time in CPU counter ticks. > + */ > + CPU_Counter_ticks max_section_time; > + > + /** > + * @brief The maximum lock acquire time in CPU counter ticks. > + */ > + CPU_Counter_ticks max_acquire_time; > + > + /** > + * @brief The count of lock uses. > + * > + * This value may overflow. > + */ > + uint64_t usage_count; > + > + /** > + * @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, 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 +215,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 +237,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 +248,81 @@ 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; > + > + 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 +338,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 +352,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 +392,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 +408,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 +443,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 25edef0..a6c85f1 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 50e5239..6d31ed4 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 0000000..4ab761b > --- /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 > + * <rt...@embedded-brains.de> > + * > + * 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 <rtems/score/smplock.h> > + > +#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 40d2ac3..389a4d6 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 ab004c1..abd8c97 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 a85cebe..752b2d5 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 7c536c3..a445c84 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 4a3e08c..1097dc8 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 4c0c3c3..92ea4ec 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 b445679..2ffd237 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/tmtests/tmcontext01/init.c > b/testsuites/tmtests/tmcontext01/init.c > index bd047a2..aa7bef9 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) { > -- > 1.7.7 > > _______________________________________________ > rtems-devel mailing list > rtems-devel@rtems.org > http://www.rtems.org/mailman/listinfo/rtems-devel _______________________________________________ rtems-devel mailing list rtems-devel@rtems.org http://www.rtems.org/mailman/listinfo/rtems-devel