[rtems commit] SMP: Move lock stats to separate header file

Sebastian Huber sebh at rtems.org
Thu May 19 09:51:19 UTC 2016


Module:    rtems
Branch:    master
Commit:    2aae3a7032ea27a989b76988bba66f4d59518ce3
Changeset: http://git.rtems.org/rtems/commit/?id=2aae3a7032ea27a989b76988bba66f4d59518ce3

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Wed May 18 13:28:52 2016 +0200

SMP: Move lock stats to separate header file

---

 cpukit/score/Makefile.am                        |   1 +
 cpukit/score/include/rtems/score/smplock.h      | 359 ++----------------------
 cpukit/score/include/rtems/score/smplockstats.h | 236 ++++++++++++++++
 cpukit/score/preinstall.am                      |   4 +
 cpukit/score/src/profilingsmplock.c             | 130 ++++++++-
 5 files changed, 397 insertions(+), 333 deletions(-)

diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am
index 937a9ce..0e7ee35 100644
--- a/cpukit/score/Makefile.am
+++ b/cpukit/score/Makefile.am
@@ -129,6 +129,7 @@ include_rtems_score_HEADERS += include/rtems/score/schedulerprioritysmpimpl.h
 include_rtems_score_HEADERS += include/rtems/score/schedulerpriorityaffinitysmp.h
 include_rtems_score_HEADERS += include/rtems/score/schedulersimplesmp.h
 include_rtems_score_HEADERS += include/rtems/score/schedulerstrongapa.h
+include_rtems_score_HEADERS += include/rtems/score/smplockstats.h
 endif
 
 ## src
diff --git a/cpukit/score/include/rtems/score/smplock.h b/cpukit/score/include/rtems/score/smplock.h
index 47797d3..f4196fe 100644
--- a/cpukit/score/include/rtems/score/smplock.h
+++ b/cpukit/score/include/rtems/score/smplock.h
@@ -22,17 +22,13 @@
 
 #include <rtems/score/cpuopts.h>
 
-#if defined( RTEMS_SMP )
+#if defined(RTEMS_SMP)
 
+#include <rtems/score/smplockstats.h>
 #include <rtems/score/atomic.h>
 #include <rtems/score/isrlevel.h>
 
-#if defined( RTEMS_PROFILING )
-#include <rtems/score/chainimpl.h>
-#include <string.h>
-#endif
-
-#if defined( RTEMS_PROFILING ) || defined( RTEMS_DEBUG )
+#if defined(RTEMS_PROFILING) || defined(RTEMS_DEBUG)
 #define RTEMS_SMP_LOCK_DO_NOT_INLINE
 #endif
 
@@ -58,157 +54,6 @@ extern "C" {
  * @{
  */
 
-#if defined( RTEMS_PROFILING )
-
-/**
- * @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 {
-  /**
-   * @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;
-} SMP_lock_Stats;
-
-/**
- * @brief Local context for SMP lock statistics.
- */
-typedef struct {
-  /**
-   * @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;
-
-  /**
-   * @brief The lock stats used for the last lock acquire.
-   */
-  SMP_lock_Stats *stats;
-} SMP_lock_Stats_context;
-
-/**
- * @brief SMP lock statistics initializer for static initialization.
- */
-#define SMP_LOCK_STATS_INITIALIZER( name ) \
-  { { NULL, NULL }, 0, 0, 0, 0, { 0, 0, 0, 0 }, 0, name }
-
-/**
- * @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] stats The SMP lock statistics block.
- */
-static inline void _SMP_lock_Stats_destroy( SMP_lock_Stats *stats );
-
-/**
- * @brief Updates an SMP lock statistics block during a lock release.
- *
- * @param[in] stats_context The SMP lock statistics context.
- */
-static inline void _SMP_lock_Stats_release_update(
-  const SMP_lock_Stats_context *stats_context
-);
-
-#else /* RTEMS_PROFILING */
-
-#define _SMP_lock_Stats_initialize( stats, name ) do { } while ( 0 )
-
-#define _SMP_lock_Stats_destroy( stats ) do { } while ( 0 )
-
-#endif /* RTEMS_PROFILING */
-
 /**
  * @brief SMP ticket lock control.
  */
@@ -257,7 +102,7 @@ static inline void _SMP_ticket_lock_Destroy( SMP_ticket_lock_Control *lock )
 
 static inline void _SMP_ticket_lock_Do_acquire(
   SMP_ticket_lock_Control *lock
-#if defined( RTEMS_PROFILING )
+#if defined(RTEMS_PROFILING)
   ,
   SMP_lock_Stats *stats,
   SMP_lock_Stats_context *stats_context
@@ -267,7 +112,7 @@ static inline void _SMP_ticket_lock_Do_acquire(
   unsigned int my_ticket;
   unsigned int now_serving;
 
-#if defined( RTEMS_PROFILING )
+#if defined(RTEMS_PROFILING)
   CPU_Counter_ticks first;
   CPU_Counter_ticks second;
   CPU_Counter_ticks delta;
@@ -279,7 +124,7 @@ static inline void _SMP_ticket_lock_Do_acquire(
   my_ticket =
     _Atomic_Fetch_add_uint( &lock->next_ticket, 1U, ATOMIC_ORDER_RELAXED );
 
-#if defined( RTEMS_PROFILING )
+#if defined(RTEMS_PROFILING)
   now_serving =
     _Atomic_Load_uint( &lock->now_serving, ATOMIC_ORDER_ACQUIRE );
   initial_queue_length = my_ticket - now_serving;
@@ -292,7 +137,7 @@ static inline void _SMP_ticket_lock_Do_acquire(
         _Atomic_Load_uint( &lock->now_serving, ATOMIC_ORDER_ACQUIRE );
     } while ( now_serving != my_ticket );
 
-#if defined( RTEMS_PROFILING )
+#if defined(RTEMS_PROFILING)
   }
 
   second = _CPU_Counter_read();
@@ -327,7 +172,7 @@ static inline void _SMP_ticket_lock_Do_acquire(
  * @param[in] stats The SMP lock statistics.
  * @param[out] stats_context The SMP lock statistics context.
  */
-#if defined( RTEMS_PROFILING )
+#if defined(RTEMS_PROFILING)
   #define _SMP_ticket_lock_Acquire( lock, stats, stats_context ) \
     _SMP_ticket_lock_Do_acquire( lock, stats, stats_context )
 #else
@@ -337,7 +182,7 @@ static inline void _SMP_ticket_lock_Do_acquire(
 
 static inline void _SMP_ticket_lock_Do_release(
   SMP_ticket_lock_Control *lock
-#if defined( RTEMS_PROFILING )
+#if defined(RTEMS_PROFILING)
   ,
   const SMP_lock_Stats_context *stats_context
 #endif
@@ -347,7 +192,7 @@ static inline void _SMP_ticket_lock_Do_release(
     _Atomic_Load_uint( &lock->now_serving, ATOMIC_ORDER_RELAXED );
   unsigned int next_ticket = current_ticket + 1U;
 
-#if defined( RTEMS_PROFILING )
+#if defined(RTEMS_PROFILING)
   _SMP_lock_Stats_release_update( stats_context );
 #endif
 
@@ -360,7 +205,7 @@ static inline void _SMP_ticket_lock_Do_release(
  * @param[in] lock The SMP ticket lock control.
  * @param[in] stats_context The SMP lock statistics context.
  */
-#if defined( RTEMS_PROFILING )
+#if defined(RTEMS_PROFILING)
   #define _SMP_ticket_lock_Release( lock, stats_context ) \
     _SMP_ticket_lock_Do_release( lock, stats_context )
 #else
@@ -373,7 +218,7 @@ static inline void _SMP_ticket_lock_Do_release(
  */
 typedef struct {
   SMP_ticket_lock_Control Ticket_lock;
-#if defined( RTEMS_DEBUG )
+#if defined(RTEMS_DEBUG)
   /**
    * @brief The index of the owning processor of this lock.
    *
@@ -388,7 +233,7 @@ typedef struct {
    */
   uint32_t owner;
 #endif
-#if defined( RTEMS_PROFILING )
+#if defined(RTEMS_PROFILING)
   SMP_lock_Stats Stats;
 #endif
 } SMP_lock_Control;
@@ -398,32 +243,32 @@ typedef struct {
  */
 typedef struct {
   ISR_Level isr_level;
-#if defined( RTEMS_DEBUG )
+#if defined(RTEMS_DEBUG)
   SMP_lock_Control *lock_used_for_acquire;
 #endif
-#if defined( RTEMS_PROFILING )
+#if defined(RTEMS_PROFILING)
   SMP_lock_Stats_context Stats_context;
 #endif
 } SMP_lock_Context;
 
-#if defined( RTEMS_DEBUG )
+#if defined(RTEMS_DEBUG)
 #define SMP_LOCK_NO_OWNER 0xffffffff
 #endif
 
 /**
  * @brief SMP lock control initializer for static initialization.
  */
-#if defined( RTEMS_DEBUG ) && defined( RTEMS_PROFILING )
+#if defined(RTEMS_DEBUG) && defined(RTEMS_PROFILING)
   #define SMP_LOCK_INITIALIZER( name ) \
     { \
       SMP_TICKET_LOCK_INITIALIZER, \
       SMP_LOCK_NO_OWNER, \
       SMP_LOCK_STATS_INITIALIZER( name ) \
     }
-#elif defined( RTEMS_DEBUG )
+#elif defined(RTEMS_DEBUG)
   #define SMP_LOCK_INITIALIZER( name ) \
     { SMP_TICKET_LOCK_INITIALIZER, SMP_LOCK_NO_OWNER }
-#elif defined( RTEMS_PROFILING )
+#elif defined(RTEMS_PROFILING)
   #define SMP_LOCK_INITIALIZER( name ) \
     { SMP_TICKET_LOCK_INITIALIZER, SMP_LOCK_STATS_INITIALIZER( name ) }
 #else
@@ -439,7 +284,7 @@ typedef struct {
  * @param[in] name The name for the SMP lock statistics.  This name must be
  * persistent throughout the life time of this statistics block.
  */
-#if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE )
+#if defined(RTEMS_SMP_LOCK_DO_NOT_INLINE)
 void _SMP_lock_Initialize(
   SMP_lock_Control *lock,
   const char *name
@@ -454,10 +299,10 @@ static inline void _SMP_lock_Initialize(
 )
 {
   _SMP_ticket_lock_Initialize( &lock->Ticket_lock );
-#if defined( RTEMS_DEBUG )
+#if defined(RTEMS_DEBUG)
   lock->owner = SMP_LOCK_NO_OWNER;
 #endif
-#if defined( RTEMS_PROFILING )
+#if defined(RTEMS_PROFILING)
   _SMP_lock_Stats_initialize( &lock->Stats, name );
 #else
   (void) name;
@@ -471,7 +316,7 @@ static inline void _SMP_lock_Initialize(
  *
  * @param[in] lock The SMP lock control.
  */
-#if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE )
+#if defined(RTEMS_SMP_LOCK_DO_NOT_INLINE)
 void _SMP_lock_Destroy( SMP_lock_Control *lock );
 
 static inline void _SMP_lock_Destroy_body( SMP_lock_Control *lock )
@@ -494,7 +339,7 @@ static inline void _SMP_lock_Destroy( SMP_lock_Control *lock )
  * @param[in] context The local SMP lock context for an acquire and release
  * pair.
  */
-#if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE )
+#if defined(RTEMS_SMP_LOCK_DO_NOT_INLINE)
 void _SMP_lock_Acquire(
   SMP_lock_Control *lock,
   SMP_lock_Context *context
@@ -523,7 +368,7 @@ static inline void _SMP_lock_Acquire(
  * @param[in] context The local SMP lock context for an acquire and release
  * pair.
  */
-#if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE )
+#if defined(RTEMS_SMP_LOCK_DO_NOT_INLINE)
 void _SMP_lock_Release(
   SMP_lock_Control *lock,
   SMP_lock_Context *context
@@ -551,7 +396,7 @@ static inline void _SMP_lock_Release(
  * @param[in] context The local SMP lock context for an acquire and release
  * pair.
  */
-#if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE )
+#if defined(RTEMS_SMP_LOCK_DO_NOT_INLINE)
 void _SMP_lock_ISR_disable_and_acquire(
   SMP_lock_Control *lock,
   SMP_lock_Context *context
@@ -576,7 +421,7 @@ static inline void _SMP_lock_ISR_disable_and_acquire(
  * @param[in] context The local SMP lock context for an acquire and release
  * pair.
  */
-#if defined( RTEMS_SMP_LOCK_DO_NOT_INLINE )
+#if defined(RTEMS_SMP_LOCK_DO_NOT_INLINE)
 void _SMP_lock_Release_and_ISR_enable(
   SMP_lock_Control *lock,
   SMP_lock_Context *context
@@ -592,7 +437,7 @@ static inline void _SMP_lock_Release_and_ISR_enable(
 }
 #endif
 
-#if defined( RTEMS_DEBUG )
+#if defined(RTEMS_DEBUG)
 /**
  * @brief Returns true, if the SMP lock is owned by the current processor,
  * otherwise false.
@@ -602,158 +447,12 @@ static inline void _SMP_lock_Release_and_ISR_enable(
 bool _SMP_lock_Is_owner( const SMP_lock_Control *lock );
 #endif
 
-#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, &current->Node ) ) {
-    size_t name_len = current->name != NULL ? strlen(current->name) : 0;
-
-    valid = true;
-
-    iteration_context->current = (SMP_lock_Stats *)
-      _Chain_Next( &current->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 );
-}
-
-static inline void _SMP_lock_Stats_destroy( SMP_lock_Stats *stats )
-{
-  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 );
-  }
-}
-
-static inline void _SMP_lock_Stats_release_update(
-  const SMP_lock_Stats_context *stats_context
-)
-{
-  SMP_lock_Stats *stats = stats_context->stats;
-  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 );
-    }
-  }
-}
-
-#endif /* RTEMS_PROFILING */
-
 /**@}*/
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 
-#endif /* defined( RTEMS_SMP ) */
+#endif /* RTEMS_SMP */
 
 #endif /* _RTEMS_SCORE_SMPLOCK_H */
diff --git a/cpukit/score/include/rtems/score/smplockstats.h b/cpukit/score/include/rtems/score/smplockstats.h
new file mode 100644
index 0000000..9785c1a
--- /dev/null
+++ b/cpukit/score/include/rtems/score/smplockstats.h
@@ -0,0 +1,236 @@
+/**
+ * @file
+ *
+ * @ingroup ScoreSMPLock
+ *
+ * @brief SMP Lock API
+ */
+
+/*
+ * Copyright (c) 2013, 2016 embedded brains GmbH
+ *
+ * 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.
+ */
+
+#ifndef _RTEMS_SCORE_SMPLOCKSTATS_H
+#define _RTEMS_SCORE_SMPLOCKSTATS_H
+
+#include <rtems/score/cpuopts.h>
+
+#if defined(RTEMS_SMP)
+
+#include <rtems/score/chainimpl.h>
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @addtogroup ScoreSMPLock
+ *
+ * @{
+ */
+
+#if defined(RTEMS_PROFILING)
+
+/**
+ * @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 {
+  /**
+   * @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;
+} SMP_lock_Stats;
+
+/**
+ * @brief Local context for SMP lock statistics.
+ */
+typedef struct {
+  /**
+   * @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;
+
+  /**
+   * @brief The lock stats used for the last lock acquire.
+   */
+  SMP_lock_Stats *stats;
+} SMP_lock_Stats_context;
+
+/**
+ * @brief SMP lock statistics initializer for static initialization.
+ */
+#define SMP_LOCK_STATS_INITIALIZER( name ) \
+  { { NULL, NULL }, 0, 0, 0, 0, { 0, 0, 0, 0 }, 0, name }
+
+/**
+ * @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] stats The SMP lock statistics block.
+ */
+void _SMP_lock_Stats_destroy( SMP_lock_Stats *stats );
+
+void _SMP_lock_Stats_register( SMP_lock_Stats *stats );
+
+/**
+ * @brief Updates an SMP lock statistics block during a lock release.
+ *
+ * @param[in] stats_context The SMP lock statistics context.
+ */
+static inline void _SMP_lock_Stats_release_update(
+  const SMP_lock_Stats_context *stats_context
+)
+{
+  SMP_lock_Stats *stats = stats_context->stats;
+  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_register( stats );
+    }
+  }
+}
+
+typedef struct {
+  Chain_Node Node;
+  SMP_lock_Stats *current;
+} SMP_lock_Stats_iteration_context;
+
+void _SMP_lock_Stats_iteration_start(
+  SMP_lock_Stats_iteration_context *iteration_context
+);
+
+
+bool _SMP_lock_Stats_iteration_next(
+  SMP_lock_Stats_iteration_context *iteration_context,
+  SMP_lock_Stats                   *snapshot,
+  char                             *name,
+  size_t                            name_size
+);
+
+void _SMP_lock_Stats_iteration_stop(
+  SMP_lock_Stats_iteration_context *iteration_context
+);
+
+#else /* RTEMS_PROFILING */
+
+#define _SMP_lock_Stats_initialize( stats, name ) do { } while ( 0 )
+
+#define _SMP_lock_Stats_destroy( stats ) do { } while ( 0 )
+
+#endif /* !RTEMS_PROFILING */
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* RTEMS_SMP */
+
+#endif /* _RTEMS_SCORE_SMPLOCKSTATS_H */
diff --git a/cpukit/score/preinstall.am b/cpukit/score/preinstall.am
index 348185a..59c8269 100644
--- a/cpukit/score/preinstall.am
+++ b/cpukit/score/preinstall.am
@@ -450,4 +450,8 @@ PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/schedulersimplesmp.h
 $(PROJECT_INCLUDE)/rtems/score/schedulerstrongapa.h: include/rtems/score/schedulerstrongapa.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/schedulerstrongapa.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/schedulerstrongapa.h
+
+$(PROJECT_INCLUDE)/rtems/score/smplockstats.h: include/rtems/score/smplockstats.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/smplockstats.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/smplockstats.h
 endif
diff --git a/cpukit/score/src/profilingsmplock.c b/cpukit/score/src/profilingsmplock.c
index a77e1a1..61d4611 100644
--- a/cpukit/score/src/profilingsmplock.c
+++ b/cpukit/score/src/profilingsmplock.c
@@ -18,8 +18,17 @@
 
 #include <rtems/score/smplock.h>
 
-#if defined( RTEMS_PROFILING )
-SMP_lock_Stats_control _SMP_lock_Stats_control = {
+#include <string.h>
+
+#if defined(RTEMS_SMP) && defined(RTEMS_PROFILING)
+
+typedef struct {
+  SMP_lock_Control Lock;
+  Chain_Control Stats_chain;
+  Chain_Control Iterator_chain;
+} SMP_lock_Stats_control;
+
+static SMP_lock_Stats_control _SMP_lock_Stats_control = {
   .Lock = {
     .Ticket_lock = {
       .next_ticket = ATOMIC_INITIALIZER_UINT( 0U ),
@@ -39,4 +48,119 @@ SMP_lock_Stats_control _SMP_lock_Stats_control = {
     _SMP_lock_Stats_control.Iterator_chain
   )
 };
-#endif /* defined( RTEMS_PROFILING ) */
+
+void _SMP_lock_Stats_destroy( SMP_lock_Stats *stats )
+{
+  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 );
+  }
+}
+
+void _SMP_lock_Stats_register( SMP_lock_Stats *stats )
+{
+      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 );
+}
+
+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 );
+}
+
+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, &current->Node ) ) {
+    size_t name_len = current->name != NULL ? strlen(current->name) : 0;
+
+    valid = true;
+
+    iteration_context->current = (SMP_lock_Stats *)
+      _Chain_Next( &current->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;
+}
+
+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 /* RTEMS_SMP && RTEMS_PROFILING */




More information about the vc mailing list