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 */
|