LCOV - code coverage report
Current view: top level - disco/metrics - fd_metrics.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 47 72 65.3 %
Date: 2025-07-01 05:00:49 Functions: 14 627 2.2 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_disco_metrics_fd_metrics_h
       2             : #define HEADER_fd_src_disco_metrics_fd_metrics_h
       3             : 
       4             : #include "fd_metrics_base.h"
       5             : 
       6             : #include "generated/fd_metrics_all.h"
       7             : 
       8             : #include "../../tango/tempo/fd_tempo.h"
       9             : #include "../../util/hist/fd_histf.h"
      10             : 
      11             : /* fd_metrics mostly defines way of laying out metrics in shared
      12             :    memory so that a producer and consumer can agree on where they
      13             :    are, and can read and write them quickly and with little to no
      14             :    boilerplate.
      15             : 
      16             :    At initialization time, a thread can call fd_metrics_register
      17             :    which saves a thread local base pointer.  Then, macros are provided
      18             :    which given a macro "name", maps it to an offset from that base
      19             :    pointer and does a write of the corresponding ulong.
      20             : 
      21             :    For low-frequency metrics like incrementing rarely hit error
      22             :    counters, it is OK to use the macros inline.  For high frequency
      23             :    metrics in core loops, it may be preferable to accumulate local
      24             :    metric values in the tile and drain them to the metrics shared
      25             :    memory periodically, eg, via. a housekeeping step.
      26             : 
      27             :    The metrics area is minimal and contains no metadata itself.  For
      28             :    example, histograms in the metrics shared memory are just the bucket
      29             :    values, and there is no metadata about the edges.  The consumer will
      30             :    determine the edges by looking at the statically compiled metadata.
      31             : 
      32             :    This is to reduce cache traffic and keep the metrics area small, so
      33             :    it can be copied to produce a snapshot quickly.  When updating
      34             :    metrics, the producer should do atomic writes so that these snapshots
      35             :    will see consistent values.  In particular, the producer should not
      36             :    do a memcpy into the metrics region. */
      37             : 
      38             : /* The metrics region is laid out like
      39             : 
      40             :     [ in_link_N ulong ]
      41             :     [ out_link_N ulong]
      42             :     [ in_link_0_metrics ... in_link_N_metrics ]
      43             :     [ out_link_0_metrics ... out_link_N_metrics ]
      44             :     [ tile_metrics ]
      45             : 
      46             :    where every value is a ulong.  Tile metrics come after link metrics,
      47             :    so this base pointer points at the very start of the layout.  You
      48             :    shouldn't need to use this directly, instead it's used by the mux
      49             :    tile when it's computing the metrics for specific links. */
      50             : extern FD_TL ulong * fd_metrics_base_tl;
      51             : 
      52             : /* All metrics in the application are ulongs, and are laid out
      53             :    sequentially, so this thread local is a pointer to the first tile
      54             :    specific metric in the layout, or the "tile_metrics" start as defined
      55             :    above.  All tile metrics are defined as an offset from this metrics
      56             :    pointer.  You shouldn't need to use this directly, instead it is used
      57             :    by the macros below like FD_MCNT_SET etc.  The thread local should be
      58             :    set by calling fd_metrics_register. */
      59             : extern FD_TL volatile ulong * fd_metrics_tl;
      60             : 
      61           3 : #define FD_METRICS_ALIGN (128UL)
      62             : #define FD_METRICS_FOOTPRINT(in_link_cnt, out_link_reliable_consumer_cnt)                                   \
      63          12 :   FD_LAYOUT_FINI( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND ( FD_LAYOUT_APPEND ( FD_LAYOUT_INIT, \
      64          12 :     8UL, 16UL ),                                                                                            \
      65          12 :     8UL, (in_link_cnt)*FD_METRICS_ALL_LINK_IN_TOTAL*sizeof(ulong) ),                                        \
      66          12 :     8UL, (out_link_reliable_consumer_cnt)*FD_METRICS_ALL_LINK_OUT_TOTAL*sizeof(ulong) ),                    \
      67          12 :     8UL, FD_METRICS_TOTAL_SZ ),                                                                             \
      68          12 :     FD_METRICS_ALIGN )
      69             : 
      70             : /* The following macros are convenience helpers for updating tile metric
      71             :    values in shared memory, and can be used like
      72             : 
      73             :      FD_MGAUGE_SET( QUIC, CONNECTIONS_CREATED_COUNT, conn_cnt );
      74             : 
      75             :    This compiles to a single write to an offset of the metrics pointer
      76             :    above. */
      77             : 
      78     5189709 : #define FD_MGAUGE_SET( group, measurement, value ) do {         \
      79     5189709 :     fd_metrics_tl[ MIDX(GAUGE, group, measurement) ] = (value); \
      80     5189709 :   } while(0)
      81             : 
      82           0 : #define FD_MGAUGE_GET( group, measurement ) (fd_metrics_tl[ MIDX(GAUGE, group, measurement) ])
      83             : 
      84           0 : #define FD_MCNT_GET( group, measurement ) (fd_metrics_tl[ MIDX(COUNTER, group, measurement) ])
      85             : 
      86           0 : #define FD_MCNT_SET( group, measurement, value ) do {             \
      87           0 :     fd_metrics_tl[ MIDX(COUNTER, group, measurement) ] = (value); \
      88           0 :   } while(0)
      89             : 
      90     4757219 : #define FD_MCNT_INC( group, measurement, value ) do {              \
      91     4757219 :     fd_metrics_tl[ MIDX(COUNTER, group, measurement) ] += (value); \
      92     4757219 :   } while(0)
      93             : 
      94        3150 : #define FD_MHIST_MIN( group, measurement ) (FD_METRICS_HISTOGRAM_##group##_##measurement##_MIN)
      95           0 : #define FD_MHIST_SECONDS_MIN( group, measurement ) (fd_metrics_convert_seconds_to_ticks(FD_METRICS_HISTOGRAM_##group##_##measurement##_MIN))
      96        3150 : #define FD_MHIST_MAX( group, measurement ) (FD_METRICS_HISTOGRAM_##group##_##measurement##_MAX)
      97           0 : #define FD_MHIST_SECONDS_MAX( group, measurement ) (fd_metrics_convert_seconds_to_ticks(FD_METRICS_HISTOGRAM_##group##_##measurement##_MAX))
      98             : 
      99       15876 : #define FD_MHIST_COPY( group, measurement, hist ) do {                   \
     100       15876 :     ulong __fd_metrics_off = MIDX(HISTOGRAM, group, measurement);        \
     101      269892 :     for( ulong i=0; i<FD_HISTF_BUCKET_CNT; i++ ) {                       \
     102      254016 :       fd_metrics_tl[ __fd_metrics_off + i ] = hist->counts[ i ];         \
     103      254016 :     }                                                                    \
     104       15876 :     fd_metrics_tl[ __fd_metrics_off + FD_HISTF_BUCKET_CNT ] = hist->sum; \
     105       15876 :   } while(0)
     106             : 
     107             : #define FD_MHIST_SUM( group, measurement ) (fd_metrics_tl[ MIDX(HISTOGRAM, group, measurement) + FD_HISTF_BUCKET_CNT ])
     108             : 
     109           0 : #define FD_MCNT_ENUM_COPY( group, measurement, values ) do {                    \
     110           0 :     ulong __fd_metrics_off = MIDX(COUNTER, group, measurement);                 \
     111           0 :     for( ulong i=0; i<FD_METRICS_COUNTER_##group##_##measurement##_CNT; i++ ) { \
     112           0 :       fd_metrics_tl[ __fd_metrics_off + i ] = values[ i ];                      \
     113           0 :     }                                                                           \
     114           0 :   } while(0)
     115             : 
     116           0 : #define FD_MGAUGE_ENUM_COPY( group, measurement, values ) do {                \
     117           0 :     ulong __fd_metrics_off = MIDX(GAUGE, group, measurement);                 \
     118           0 :     for( ulong i=0; i<FD_METRICS_GAUGE_##group##_##measurement##_CNT; i++ ) { \
     119           0 :       fd_metrics_tl[ __fd_metrics_off + i ] = values[ i ];                    \
     120           0 :     }                                                                         \
     121           0 :   } while(0)
     122             : 
     123             : FD_PROTOTYPES_BEGIN
     124             : 
     125             : /* fd_metrics_tile returns a pointer to the tile-specific metrics area
     126             :    for the given metrics object.  */
     127             : static inline volatile ulong *
     128         345 : fd_metrics_tile( ulong * metrics ) { return metrics + 2UL + FD_METRICS_ALL_LINK_IN_TOTAL*metrics[ 0 ] + FD_METRICS_ALL_LINK_OUT_TOTAL*metrics[ 1 ]; }
     129             : 
     130             : /* fd_metrics_link_in returns a pointer the in-link metrics area for the
     131             :    given in link index of this metrics object. */
     132             : static inline volatile ulong *
     133           0 : fd_metrics_link_in( ulong * metrics, ulong in_idx ) { return metrics + 2UL + FD_METRICS_ALL_LINK_IN_TOTAL*in_idx; }
     134             : 
     135             : /* fd_metrics_link_in returns a pointer the in-link metrics area for the
     136             :    given out link index of this metrics object. */
     137             : static inline volatile ulong *
     138           0 : fd_metrics_link_out( ulong * metrics, ulong out_idx ) { return metrics + 2UL + FD_METRICS_ALL_LINK_IN_TOTAL*metrics[0] + FD_METRICS_ALL_LINK_OUT_TOTAL*out_idx; }
     139             : 
     140             : /* fd_metrics_new formats an unused memory region for use as a metrics.
     141             :    Assumes shmem is a non-NULL pointer to this region in the local
     142             :    address space with the required footprint and alignment.  All of the
     143             :    mtrics will be initialized to zero.  Returns shmem (and the memory
     144             :    region it points to will be formatted as a metrics, caller is not
     145             :    joined). */
     146             : 
     147             : static inline void *
     148             : fd_metrics_new( void * shmem,
     149             :                 ulong  in_link_cnt,
     150           9 :                 ulong  out_link_consumer_cnt ) {
     151           9 :   fd_memset( shmem, 0, FD_METRICS_FOOTPRINT(in_link_cnt, out_link_consumer_cnt) );
     152           9 :   ulong * metrics = shmem;
     153           9 :   metrics[0] = in_link_cnt;
     154           9 :   metrics[1] = out_link_consumer_cnt;
     155           9 :   return shmem;
     156           9 : }
     157             : 
     158             : /* fd_metrics_register sets the thread local values used by the macros
     159             :    like FD_MCNT_SET to point to the provided metrics object. */
     160             : static inline ulong *
     161           6 : fd_metrics_register( ulong * metrics ) {
     162           6 :   if( FD_UNLIKELY( !metrics ) ) FD_LOG_ERR(( "NULL metrics" ));
     163             : 
     164           6 :   fd_metrics_base_tl = metrics;
     165           6 :   fd_metrics_tl = fd_metrics_tile( metrics );
     166           6 :   return metrics;
     167           6 : }
     168             : 
     169             : static inline ulong
     170          12 : fd_metrics_convert_seconds_to_ticks( double seconds ) {
     171             :   /* The tick_per_ns() value needs to be the same across the tile doing
     172             :      the sampling and the tile doing the reporting so that they compute
     173             :      the same bucket edges for histograms. */
     174          12 :   double tick_per_ns = fd_tempo_tick_per_ns( NULL );
     175          12 :   return (ulong)(seconds * tick_per_ns * 1e9);
     176          12 : }
     177             : 
     178             : static inline double
     179          96 : fd_metrics_convert_ticks_to_seconds( ulong ticks ) {
     180          96 :   double tick_per_ns = fd_tempo_tick_per_ns( NULL );
     181          96 :   return (double)ticks / (tick_per_ns * 1e9);
     182          96 : }
     183             : 
     184             : static inline ulong
     185           0 : fd_metrics_convert_ticks_to_nanoseconds( ulong ticks ) {
     186           0 :   double tick_per_ns = fd_tempo_tick_per_ns( NULL );
     187           0 :   return (ulong)((double)ticks / tick_per_ns);
     188           0 : }
     189             : 
     190           3 : static inline ulong * fd_metrics_join  ( void * mem ) { return mem; }
     191           3 : static inline void *  fd_metrics_leave ( void * mem ) { return (void *)mem; }
     192           3 : static inline void *  fd_metrics_delete( void * mem ) { return (void *)mem; }
     193             : 
     194             : FD_PROTOTYPES_END
     195             : 
     196             : #endif /* HEADER_fd_src_disco_metrics_fd_metrics_h */

Generated by: LCOV version 1.14