Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:13

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSScoreSMPLock
0007  *
0008  * @brief This header file provides the interfaces of the
0009  *   @ref RTEMSScoreSMPLock related to lock statistics.
0010  */
0011 
0012 /*
0013  * Copyright (C) 2013, 2018 embedded brains GmbH & Co. KG
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 #ifndef _RTEMS_SCORE_SMPLOCKSTATS_H
0038 #define _RTEMS_SCORE_SMPLOCKSTATS_H
0039 
0040 #include <rtems/score/cpu.h>
0041 
0042 #if defined(RTEMS_SMP)
0043 
0044 #include <rtems/score/chain.h>
0045 
0046 #ifdef __cplusplus
0047 extern "C" {
0048 #endif /* __cplusplus */
0049 
0050 /**
0051  * @addtogroup RTEMSScoreSMPLock
0052  *
0053  * @{
0054  */
0055 
0056 #if defined(RTEMS_PROFILING)
0057 
0058 /**
0059  * @brief Count of lock contention counters for lock statistics.
0060  */
0061 #define SMP_LOCK_STATS_CONTENTION_COUNTS 4
0062 
0063 /**
0064  * @brief SMP lock statistics.
0065  *
0066  * The lock acquire attempt instant is the point in time right after the
0067  * interrupt disable action in the lock acquire sequence.
0068  *
0069  * The lock acquire instant is the point in time right after the lock
0070  * acquisition.  This is the begin of the critical section code execution.
0071  *
0072  * The lock release instant is the point in time right before the interrupt
0073  * enable action in the lock release sequence.
0074  *
0075  * The lock section time is the time elapsed between the lock acquire instant
0076  * and the lock release instant.
0077  *
0078  * The lock acquire time is the time elapsed between the lock acquire attempt
0079  * instant and the lock acquire instant.
0080  */
0081 typedef struct {
0082   /**
0083    * @brief Node for SMP lock statistics chain.
0084    */
0085   Chain_Node Node;
0086 
0087   /**
0088    * @brief The maximum lock acquire time in CPU counter ticks.
0089    */
0090   CPU_Counter_ticks max_acquire_time;
0091 
0092   /**
0093    * @brief The maximum lock section time in CPU counter ticks.
0094    */
0095   CPU_Counter_ticks max_section_time;
0096 
0097   /**
0098    * @brief The count of lock uses.
0099    *
0100    * This value may overflow.
0101    */
0102   uint64_t usage_count;
0103 
0104   /**
0105    * @brief Total lock acquire time in nanoseconds.
0106    *
0107    * The average lock acquire time is the total acquire time divided by the
0108    * lock usage count.  The ration of the total section and total acquire times
0109    * gives a measure for the lock contention.
0110    *
0111    * This value may overflow.
0112    */
0113   uint64_t total_acquire_time;
0114 
0115   /**
0116    * @brief The counts of lock acquire operations by contention.
0117    *
0118    * The contention count for index N corresponds to a lock acquire attempt
0119    * with an initial queue length of N.  The last index corresponds to all
0120    * lock acquire attempts with an initial queue length greater than or equal
0121    * to SMP_LOCK_STATS_CONTENTION_COUNTS minus one.
0122    *
0123    * The values may overflow.
0124    */
0125   uint64_t contention_counts[SMP_LOCK_STATS_CONTENTION_COUNTS];
0126 
0127   /**
0128    * @brief Total lock section time in CPU counter ticks.
0129    *
0130    * The average lock section time is the total section time divided by the
0131    * lock usage count.
0132    *
0133    * This value may overflow.
0134    */
0135   uint64_t total_section_time;
0136 
0137   /**
0138    * @brief The lock name.
0139    */
0140   const char *name;
0141 } SMP_lock_Stats;
0142 
0143 /**
0144  * @brief Local context for SMP lock statistics.
0145  */
0146 typedef struct {
0147   /**
0148    * @brief The last lock acquire instant in CPU counter ticks.
0149    *
0150    * This value is used to measure the lock section time.
0151    */
0152   CPU_Counter_ticks acquire_instant;
0153 
0154   /**
0155    * @brief The lock stats used for the last lock acquire.
0156    */
0157   SMP_lock_Stats *stats;
0158 } SMP_lock_Stats_context;
0159 
0160 /**
0161  * @brief SMP lock statistics initializer for static initialization.
0162  */
0163 #define SMP_LOCK_STATS_INITIALIZER( name ) \
0164   { { NULL, NULL }, 0, 0, 0, 0, { 0, 0, 0, 0 }, 0, name }
0165 
0166 /**
0167  * @brief Initializes an SMP lock statistics block.
0168  *
0169  * @param[in, out] stats The SMP lock statistics block.
0170  * @param name The name for the SMP lock statistics.  This name must be
0171  * persistent throughout the life time of this statistics block.
0172  */
0173 static inline void _SMP_lock_Stats_initialize(
0174   SMP_lock_Stats *stats,
0175   const char *name
0176 )
0177 {
0178   SMP_lock_Stats init = SMP_LOCK_STATS_INITIALIZER( name );
0179 
0180   *stats = init;
0181 }
0182 
0183 /**
0184  * @brief Destroys an SMP lock statistics block.
0185  *
0186  * @param[out] stats The SMP lock statistics block.
0187  */
0188 void _SMP_lock_Stats_destroy( SMP_lock_Stats *stats );
0189 
0190 /**
0191  * @brief Sets the max section time of the SMP lock statistics block and
0192  *      registers it.
0193  *
0194  * @param[in, out] stats The SMP lock statistics block.
0195  * @param max_section_time The max section time for @a stats.
0196  */
0197 void _SMP_lock_Stats_register_or_max_section_time(
0198   SMP_lock_Stats    *stats,
0199   CPU_Counter_ticks  max_section_time
0200 );
0201 
0202 typedef struct {
0203   CPU_Counter_ticks first;
0204 } SMP_lock_Stats_acquire_context;
0205 
0206 /**
0207  * @brief Starts the lock stats for acquire.
0208  *
0209  * @param[in, out] acquire_context The acquire context.
0210  */
0211 static inline void _SMP_lock_Stats_acquire_begin(
0212   SMP_lock_Stats_acquire_context *acquire_context
0213 )
0214 {
0215   acquire_context->first = _CPU_Counter_read();
0216 }
0217 
0218 /**
0219  * @brief Ends the lock stats for acquire.
0220  *
0221  * @param acquire_context The acquire context for the operation.
0222  * @param[in, out] stats The stats to modify.
0223  * @param[out] stats_context The context for the stats.
0224  * @param queue_length The queue length for the stats contention counts.
0225  */
0226 static inline void _SMP_lock_Stats_acquire_end(
0227   const SMP_lock_Stats_acquire_context *acquire_context,
0228   SMP_lock_Stats                       *stats,
0229   SMP_lock_Stats_context               *stats_context,
0230   unsigned int                          queue_length
0231 )
0232 {
0233   CPU_Counter_ticks second;
0234   CPU_Counter_ticks delta;
0235 
0236   second = _CPU_Counter_read();
0237   stats_context->acquire_instant = second;
0238   delta = second - acquire_context->first;
0239 
0240   ++stats->usage_count;
0241 
0242   stats->total_acquire_time += delta;
0243 
0244   if ( stats->max_acquire_time < delta ) {
0245     stats->max_acquire_time = delta;
0246   }
0247 
0248   if ( queue_length >= SMP_LOCK_STATS_CONTENTION_COUNTS ) {
0249     queue_length = SMP_LOCK_STATS_CONTENTION_COUNTS - 1;
0250   }
0251   ++stats->contention_counts[ queue_length ];
0252 
0253   stats_context->stats = stats;
0254 }
0255 
0256 /**
0257  * @brief Updates an SMP lock statistics block during a lock release.
0258  *
0259  * @param[in, out] stats_context The SMP lock statistics context.
0260  */
0261 static inline void _SMP_lock_Stats_release_update(
0262   const SMP_lock_Stats_context *stats_context
0263 )
0264 {
0265   SMP_lock_Stats    *stats;
0266   CPU_Counter_ticks  first;
0267   CPU_Counter_ticks  second;
0268   CPU_Counter_ticks  delta;
0269 
0270   stats = stats_context->stats;
0271   first = stats_context->acquire_instant;
0272   second = _CPU_Counter_read();
0273   delta = second - first;
0274 
0275   stats->total_section_time += delta;
0276 
0277   if ( stats->max_section_time < delta ) {
0278     _SMP_lock_Stats_register_or_max_section_time( stats, delta );
0279   }
0280 }
0281 
0282 typedef struct {
0283   Chain_Node Node;
0284   SMP_lock_Stats *current;
0285 } SMP_lock_Stats_iteration_context;
0286 
0287 /**
0288  * @brief Adds a newly initialized node to the iteration context.
0289  *
0290  * @param[in, out] iteration_context The iteration context for the operation.
0291  */
0292 void _SMP_lock_Stats_iteration_start(
0293   SMP_lock_Stats_iteration_context *iteration_context
0294 );
0295 
0296 /**
0297  * @brief Gets the next statistics node, if it is valid.
0298  *
0299  * @param[in, out] iteration_context The iteration context.
0300  * @param[out] snapshot Contains the next node of the stats chain.
0301  * @param[in, out] name The name for @a snapshot.
0302  * @param name_size The size of @a name.
0303  *
0304  * @retval true The node is valid.
0305  * @retval false The node is not valid.
0306  */
0307 bool _SMP_lock_Stats_iteration_next(
0308   SMP_lock_Stats_iteration_context *iteration_context,
0309   SMP_lock_Stats                   *snapshot,
0310   char                             *name,
0311   size_t                            name_size
0312 );
0313 
0314 /**
0315  * @brief Removes a node from the iteration context.
0316  *
0317  * @param[in, out] iteration_context The iteration context for the operation.
0318  */
0319 void _SMP_lock_Stats_iteration_stop(
0320   SMP_lock_Stats_iteration_context *iteration_context
0321 );
0322 
0323 #else /* RTEMS_PROFILING */
0324 
0325 #define _SMP_lock_Stats_initialize( stats, name ) do { } while ( 0 )
0326 
0327 #define _SMP_lock_Stats_destroy( stats ) do { } while ( 0 )
0328 
0329 #endif /* !RTEMS_PROFILING */
0330 
0331 /** @} */
0332 
0333 #ifdef __cplusplus
0334 }
0335 #endif /* __cplusplus */
0336 
0337 #endif /* RTEMS_SMP */
0338 
0339 #endif /* _RTEMS_SCORE_SMPLOCKSTATS_H */