Line data Source code
1 : #include "watch.h"
2 : #include "generated/watch_seccomp.h"
3 :
4 : #include "../../../../discof/restore/fd_snapct_tile.h"
5 : #include "../../../../discof/gossip/fd_gossip_tile.h"
6 : #include "../../../../disco/metrics/fd_metrics.h"
7 : #include "../../../../disco/node_info/fd_node_info.h"
8 : #include "../../../../disco/genesis/fd_genesis_cluster.h"
9 : #include "../../../../util/pod/fd_pod.h"
10 : #include "../../../../util/tile/fd_tile.h"
11 :
12 : #include <errno.h>
13 : #include <unistd.h>
14 : #include <sys/resource.h>
15 : #include <linux/capability.h>
16 :
17 : void
18 : watch_cmd_perm( args_t * args FD_PARAM_UNUSED,
19 : fd_cap_chk_t * chk,
20 0 : config_t const * config ) {
21 0 : ulong mlock_limit = fd_topo_mlock( &config->topo );
22 :
23 0 : fd_cap_chk_raise_rlimit( chk, "watch", RLIMIT_MEMLOCK, mlock_limit, "call `rlimit(2)` to increase `RLIMIT_MEMLOCK` so all memory can be locked with `mlock(2)`" );
24 :
25 0 : if( fd_sandbox_requires_cap_sys_admin( config->uid, config->gid ) )
26 0 : fd_cap_chk_cap( chk, "watch", CAP_SYS_ADMIN, "call `unshare(2)` with `CLONE_NEWUSER` to sandbox the process in a user namespace" );
27 0 : if( FD_LIKELY( getuid() != config->uid ) )
28 0 : fd_cap_chk_cap( chk, "watch", CAP_SETUID, "call `setresuid(2)` to switch uid to the sanbox user" );
29 0 : if( FD_LIKELY( getgid() != config->gid ) )
30 0 : fd_cap_chk_cap( chk, "watch", CAP_SETGID, "call `setresgid(2)` to switch gid to the sandbox user" );
31 0 : }
32 :
33 :
34 : static ulong lines_printed;
35 : static int ended_on_newline = 1;
36 :
37 : static char frame_buf[ 65536UL ];
38 : static ulong frame_len;
39 :
40 : static void
41 0 : flush_frame( void ) {
42 0 : ulong written = 0UL;
43 0 : while( written<frame_len ) {
44 0 : long w = write( STDOUT_FILENO, frame_buf+written, frame_len-written );
45 0 : if( FD_UNLIKELY( -1==w && errno==EAGAIN ) ) continue;
46 0 : else if( FD_UNLIKELY( -1==w ) ) FD_LOG_ERR(( "write() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
47 0 : else if( FD_UNLIKELY( 0==w ) ) break;
48 0 : written += (ulong)w;
49 0 : }
50 0 : frame_len = 0UL;
51 0 : }
52 :
53 : static int
54 0 : drain( int fd ) {
55 0 : int needs_reprint = 0;
56 :
57 0 : while( 1 ) {
58 0 : uchar buf[ 16384UL ];
59 0 : long result = read( fd, buf, sizeof(buf) );
60 0 : if( FD_UNLIKELY( -1==result && errno==EAGAIN ) ) break;
61 0 : else if( FD_UNLIKELY( -1==result ) ) FD_LOG_ERR(( "read() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
62 :
63 0 : if( FD_LIKELY( !needs_reprint ) ) {
64 : /* Buffer the erase sequence and first log chunk together so the
65 : terminal never renders a blank frame between erase and content. */
66 0 : frame_len = 0UL;
67 0 : if( FD_UNLIKELY( !ended_on_newline ) ) {
68 0 : FD_TEST( fd_cstr_printf_check( frame_buf, sizeof(frame_buf), &frame_len, "\033[%luA\033[%luM\033[1A\033[0J", lines_printed, lines_printed ) );
69 0 : } else {
70 0 : FD_TEST( fd_cstr_printf_check( frame_buf, sizeof(frame_buf), &frame_len, "\033[%luA\033[%luM\033[0J", lines_printed, lines_printed ) );
71 0 : }
72 0 : }
73 0 : FD_TEST( frame_len+(ulong)result<=sizeof(frame_buf) );
74 0 : fd_memcpy( frame_buf+frame_len, buf, (ulong)result );
75 0 : frame_len += (ulong)result;
76 0 : flush_frame();
77 0 : needs_reprint = 1;
78 :
79 0 : ended_on_newline = buf[ (ulong)result-1UL ]=='\n';
80 0 : }
81 :
82 0 : return needs_reprint;
83 0 : }
84 :
85 : static char *
86 : fmt_bytes( char * buf,
87 : ulong buf_sz,
88 0 : long bytes ) {
89 0 : char * tmp = fd_alloca_check( 1UL, buf_sz );
90 0 : if( FD_LIKELY( 8L*bytes<1000L ) ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%ld bits", 8L*bytes ) );
91 0 : else if( FD_LIKELY( 8L*bytes<1000000L ) ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1f Kbit", (double)(8L*bytes)/1000.0 ) );
92 0 : else if( FD_LIKELY( 8L*bytes<1000000000L ) ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1f Mbit", (double)(8L*bytes)/1000000.0 ) );
93 0 : else FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1f Gbit", (double)(8L*bytes)/1000000000.0 ) );
94 :
95 0 : FD_TEST( fd_cstr_printf_check( buf, buf_sz, NULL, "%10s", tmp ) );
96 0 : return buf;
97 0 : }
98 :
99 : static char *
100 : fmt_count( char * buf,
101 : ulong buf_sz,
102 0 : ulong count ) {
103 0 : char * tmp = fd_alloca_check( 1UL, buf_sz );
104 0 : if( FD_LIKELY( count<1000UL ) ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%lu", count ) );
105 0 : else if( FD_LIKELY( count<1000000UL ) ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1f K", (double)count/1000.0 ) );
106 0 : else if( FD_LIKELY( count<1000000000UL ) ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1f M", (double)count/1000000.0 ) );
107 :
108 0 : FD_TEST( fd_cstr_printf_check( buf, buf_sz, NULL, "%10s", tmp ) );
109 0 : return buf;
110 0 : }
111 :
112 : static char *
113 : fmt_countf( char * buf,
114 : ulong buf_sz,
115 0 : double count ) {
116 0 : char * tmp = fd_alloca_check( 1UL, buf_sz );
117 0 : if( FD_LIKELY( count<1000UL ) ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1f", count ) );
118 0 : else if( FD_LIKELY( count<1000000UL ) ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1f K", (double)count/1000.0 ) );
119 0 : else if( FD_LIKELY( count<1000000000UL ) ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1f M", (double)count/1000000.0 ) );
120 0 : else memcpy( tmp, "-", 2UL );
121 :
122 0 : FD_TEST( fd_cstr_printf_check( buf, buf_sz, NULL, "%10s", tmp ) );
123 0 : return buf;
124 0 : }
125 :
126 : static char *
127 : fmt_count_tight( char * buf,
128 : ulong buf_sz,
129 0 : ulong count ) {
130 0 : char * tmp = fd_alloca_check( 1UL, buf_sz );
131 0 : if( count<1000UL ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%lu", count ) );
132 0 : else if( count<1000000UL ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1fK", (double)count/1e3 ) );
133 0 : else if( count<1000000000UL ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1fM", (double)count/1e6 ) );
134 0 : else FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1fG", (double)count/1e9 ) );
135 0 : FD_TEST( fd_cstr_printf_check( buf, buf_sz, NULL, "%6s", tmp ) );
136 0 : return buf;
137 0 : }
138 :
139 : static char *
140 : fmt_countf_tight( char * buf,
141 : ulong buf_sz,
142 0 : double count ) {
143 0 : char * tmp = fd_alloca_check( 1UL, buf_sz );
144 0 : if( count<1000.0 ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1f", count ) );
145 0 : else if( count<1000000.0 ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1fK", count/1e3 ) );
146 0 : else if( count<1000000000.0 ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1fM", count/1e6 ) );
147 0 : else FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1fG", count/1e9 ) );
148 0 : FD_TEST( fd_cstr_printf_check( buf, buf_sz, NULL, "%6s", tmp ) );
149 0 : return buf;
150 0 : }
151 :
152 : static long
153 : diff_link( config_t const * config,
154 : char const * link_name,
155 : ulong const * prev_link,
156 : ulong const * cur_link,
157 0 : ulong idx ) {
158 0 : long result = 0L;
159 :
160 0 : ulong overall_polled_idx = 0UL;
161 0 : for( ulong i=0UL; i<config->topo.tile_cnt; i++ ) {
162 0 : fd_topo_tile_t const * tile = &config->topo.tiles[ i ];
163 0 : for( ulong j=0UL; j<config->topo.tiles[ i ].in_cnt; j++ ) {
164 0 : fd_topo_link_t const * link = &config->topo.links[ tile->in_link_id[ j ] ];
165 0 : if( FD_UNLIKELY( !tile->in_link_poll[ j ] ) ) continue;
166 :
167 0 : if( FD_LIKELY( !strcmp( link->name, link_name ) ) ) {
168 0 : result += (long)cur_link[ overall_polled_idx*8UL+idx ]-(long)prev_link[ overall_polled_idx*8UL+idx ];
169 0 : }
170 :
171 0 : overall_polled_idx++;
172 0 : }
173 0 : }
174 0 : return result;
175 0 : }
176 :
177 : static long
178 : diff_tile( config_t const * config,
179 : char const * tile_name,
180 : ulong const * prev_tile,
181 : ulong const * cur_tile,
182 0 : ulong idx ) {
183 0 : long result = 0L;
184 :
185 0 : for( ulong i=0UL; i<config->topo.tile_cnt; i++ ) {
186 0 : fd_topo_tile_t const * tile = &config->topo.tiles[ i ];
187 0 : if( FD_UNLIKELY( strcmp( tile->name, tile_name ) ) ) continue;
188 0 : result += (long)cur_tile[ i*FD_METRICS_TOTAL_SZ+idx ]-(long)prev_tile[ i*FD_METRICS_TOTAL_SZ+idx ];
189 0 : }
190 0 : return result;
191 0 : }
192 :
193 : static ulong
194 0 : total_crds( ulong const * metrics ) {
195 0 : ulong sum = 0UL;
196 0 : for( ulong i=0UL; i<FD_METRICS_ENUM_CRDS_VALUE_CNT; i++ ) {
197 0 : sum += metrics[ MIDX( GAUGE, GOSSIP, CRDS_OCCUPIED_CONTACT_INFO_V1 )+i ];
198 0 : }
199 0 : return sum;
200 0 : }
201 :
202 : static ulong
203 0 : total_regime( ulong const * metrics ) {
204 0 : ulong sum = 0UL;
205 0 : for( ulong i=0UL; i<FD_METRICS_ENUM_TILE_REGIME_CNT; i++ ) {
206 0 : sum += metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS )+i ];
207 0 : }
208 0 : return sum;
209 0 : }
210 :
211 : /* Bench */
212 : static ulong tps_sent_samples_idx = 0UL;
213 : static ulong tps_sent_samples[ 200UL ];
214 : /* Replay */
215 : static ulong cups_samples_idx = 0UL;
216 : static ulong cups_samples[ 100UL ];
217 : static ulong sps_samples_idx = 0UL;
218 : static ulong sps_samples[ 200UL ];
219 : static ulong tps_samples_idx = 0UL;
220 : static ulong tps_samples[ 200UL ];
221 : /* Snapshot */
222 : static ulong snapshot_rx_idx = 0UL;
223 : static ulong snapshot_rx_samples[ 100UL ];
224 : static ulong snapshot_acc_idx = 0UL;
225 : static ulong snapshot_acc_samples[ 100UL ];
226 : static ulong snapshot_wr_idx = 0UL;
227 : static ulong snapshot_wr_samples[ 100UL ];
228 : /* Event */
229 : static ulong events_sent_samples_idx = 0UL;
230 : static ulong events_sent_samples[ 100UL ];
231 : static ulong events_acked_samples_idx = 0UL;
232 : static ulong events_acked_samples[ 100UL ];
233 : static ulong event_bytes_written_samples_idx = 0UL;
234 : static ulong event_bytes_written_samples[ 100UL ];
235 : static ulong event_bytes_read_samples_idx = 0UL;
236 : static ulong event_bytes_read_samples[ 100UL ];
237 : /* Accounts */
238 : static ulong accdb_samples_idx = 0UL;
239 : static ulong accdb_acquired_samples[ 200UL ];
240 : static ulong accdb_writable_samples[ 200UL ];
241 : static ulong accdb_missed_samples [ 200UL ];
242 : static ulong accdb_evicted_samples [ 200UL ];
243 : static ulong accdb_waited_samples [ 200UL ];
244 : static ulong accdb_bytes_rd_samples[ 200UL ];
245 : static ulong accdb_bytes_wr_samples[ 200UL ];
246 : static ulong accdb_bytes_cp_samples[ 200UL ];
247 : static ulong accdb_bytes_pe_samples[ 200UL ];
248 : static ulong accdb_evicted_class_samples[ 8UL ][ 200UL ];
249 : static ulong accdb_preevicted_samples[ 200UL ];
250 : static ulong accdb_preevicted_class_samples[ 8UL ][ 200UL ];
251 : static ulong accdb_committed_new_class_samples[ 8UL ][ 200UL ];
252 : static ulong accdb_committed_overwrite_class_samples[ 8UL ][ 200UL ];
253 : /* Repair server */
254 : static ulong shreds_stored_samples_idx = 0UL;
255 : static ulong shreds_stored_sample[ 200UL ] ;
256 : static ulong rserve_rps_valid_samples_idx = 0UL;
257 : static ulong rserve_rps_valid_samples[ 100UL ];
258 : static ulong rserve_rps_invalid_samples_idx = 0UL;
259 : static ulong rserve_rps_invalid_samples[ 100UL ];
260 :
261 : #define RESET "\033[0m"
262 : #define BOLD "\033[1m"
263 : #define UNBOLD "\033[22m"
264 :
265 : #define RED "\033[31m"
266 : #define GREEN "\033[32m"
267 : #define ORANGE "\033[38;5;208m"
268 : #define YELLOW "\033[33m"
269 : #define BLUE "\033[34m"
270 : #define MAGENTA "\033[35m"
271 : #define CYAN "\033[36m"
272 :
273 : #define BGREEN "\033[92m"
274 : #define BYELLOW "\033[93m"
275 :
276 : #define CLEARLN "\033[K"
277 :
278 0 : #define PRINT(...) do { \
279 0 : ulong _len; \
280 0 : FD_TEST( fd_cstr_printf_check( frame_buf+frame_len, sizeof(frame_buf)-frame_len, &_len, __VA_ARGS__ ) ); \
281 0 : frame_len += _len; \
282 0 : } while(0)
283 :
284 : #define DIFF_LINK_BYTES( link_name, metric_type, metric_subtype, metric ) (__extension__({ \
285 : long bytes = diff_link( config, link_name, prev_link, cur_link, MIDX( metric_type, metric_subtype, metric ) ); \
286 : fmt_bytes( fd_alloca_check( 1UL, 64UL ), 64UL, bytes ); \
287 : }))
288 :
289 0 : #define DIFF_BYTES( tile_name, metric_type, metric_subtype, metric ) (__extension__({ \
290 0 : long bytes = diff_tile( config, tile_name, prev_tile, cur_tile, MIDX( metric_type, metric_subtype, metric ) ); \
291 0 : fmt_bytes( fd_alloca_check( 1UL, 64UL ), 64UL, bytes ); \
292 0 : }))
293 :
294 0 : #define COUNT( count ) (__extension__({ \
295 0 : fmt_count( fd_alloca_check( 1UL, 64UL ), 64UL, count ); \
296 0 : }))
297 :
298 0 : #define COUNTF( count ) (__extension__({ \
299 0 : fmt_countf( fd_alloca_check( 1UL, 64UL ), 64UL, count ); \
300 0 : }))
301 :
302 0 : #define COUNT_T( count ) (__extension__({ \
303 0 : fmt_count_tight( fd_alloca_check( 1UL, 32UL ), 32UL, count ); \
304 0 : }))
305 :
306 0 : #define COUNTF_T( count ) (__extension__({ \
307 0 : fmt_countf_tight( fd_alloca_check( 1UL, 32UL ), 32UL, count ); \
308 0 : }))
309 :
310 : static int
311 : write_bench( config_t const * config,
312 : ulong const * cur_tile,
313 0 : ulong const * prev_tile ) {
314 0 : if( FD_UNLIKELY( fd_topo_find_tile( &config->topo, "benchs", 0UL )==ULONG_MAX ) ) return 0;
315 :
316 0 : ulong tps_sum = 0UL;
317 0 : ulong num_tps_samples = fd_ulong_min( tps_sent_samples_idx, sizeof(tps_sent_samples)/sizeof(tps_sent_samples[0]));
318 0 : for( ulong i=0UL; i<num_tps_samples; i++ ) tps_sum += tps_sent_samples[ i ];
319 0 : char * tps_str = COUNTF( 100.0*(double)tps_sum/(double)num_tps_samples );
320 :
321 0 : PRINT( "๐ถ " BOLD BGREEN "BENCH......." RESET UNBOLD
322 0 : " " BOLD "GENERATED TPS" UNBOLD " %s"
323 0 : " " BOLD "BENCHG BUSY" UNBOLD, tps_str );
324 0 : for( ulong i=0UL; i<config->topo.tile_cnt; i++ ) {
325 0 : if( FD_LIKELY( strcmp( config->topo.tiles[ i ].name, "benchg" ) ) ) continue;
326 :
327 0 : ulong total_ticks = total_regime( &cur_tile[ i*FD_METRICS_TOTAL_SZ ] )-total_regime( &prev_tile[ i*FD_METRICS_TOTAL_SZ ] );
328 0 : double backp_pct = 100.0*(double)( diff_tile( config, "benchg", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) ) )/(double)total_ticks;
329 0 : double idle_pct = 100.0*(double)( diff_tile( config, "benchg", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG ) ) )/(double)total_ticks;
330 0 : double busy_pct = 100.0 - idle_pct - backp_pct;
331 :
332 0 : PRINT( " %.1f %%", busy_pct );
333 0 : }
334 :
335 0 : PRINT( " " BOLD "BENCHS BUSY" UNBOLD );
336 0 : for( ulong i=0UL; i<config->topo.tile_cnt; i++ ) {
337 0 : if( FD_LIKELY( strcmp( config->topo.tiles[ i ].name, "benchs" ) ) ) continue;
338 :
339 0 : ulong total_ticks = total_regime( &cur_tile[ i*FD_METRICS_TOTAL_SZ ] )-total_regime( &prev_tile[ i*FD_METRICS_TOTAL_SZ ] );
340 0 : double backp_pct = 100.0*(double)( diff_tile( config, "benchs", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) ) )/(double)total_ticks;
341 0 : double idle_pct = 100.0*(double)( diff_tile( config, "benchs", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG ) ) )/(double)total_ticks;
342 0 : double busy_pct = 100.0 - idle_pct - backp_pct;
343 :
344 0 : PRINT( " %.1f %%", busy_pct );
345 0 : }
346 :
347 0 : PRINT( CLEARLN "\n" );
348 0 : return 1;
349 0 : }
350 :
351 : static void
352 : write_backtest( config_t const * config,
353 0 : ulong const * cur_tile ) {
354 0 : ulong backt_idx = fd_topo_find_tile( &config->topo, "backt", 0UL );
355 0 : ulong start_slot = cur_tile[ backt_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, BACKT, START_SLOT ) ];
356 0 : ulong final_slot = cur_tile[ backt_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, BACKT, FINAL_SLOT ) ];
357 :
358 0 : ulong replay_idx = fd_topo_find_tile( &config->topo, "replay", 0UL );
359 0 : ulong current_slot = cur_tile[ replay_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, REPLAY, ROOT_SLOT ) ];
360 0 : current_slot = current_slot ? current_slot : start_slot;
361 :
362 0 : ulong completed_slots = current_slot-start_slot;
363 :
364 0 : if( FD_UNLIKELY( final_slot==ULONG_MAX ) ) {
365 0 : PRINT( "๐งช " BOLD BGREEN "BACKTEST...." RESET UNBOLD
366 0 : " " BOLD "PCT" UNBOLD " ? (%lu/?)" CLEARLN "\n", completed_slots );
367 0 : return;
368 0 : }
369 :
370 0 : ulong total_slots = final_slot-start_slot;
371 0 : double progress = total_slots ? 100.0 * (double)completed_slots / (double)total_slots : 100.0;
372 0 : PRINT( "๐งช " BOLD BGREEN "BACKTEST...." RESET UNBOLD
373 0 : " " BOLD "PCT" UNBOLD " %.1f %% (%lu/%lu)" CLEARLN "\n",
374 0 : progress, completed_slots, total_slots );
375 0 : }
376 :
377 : static void
378 : write_snapshots( config_t const * config,
379 : ulong const * cur_tile,
380 0 : ulong const * prev_tile ) {
381 0 : ulong snapct_idx = fd_topo_find_tile( &config->topo, "snapct", 0UL );
382 0 : ulong state = cur_tile[ snapct_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, SNAPCT, STATE ) ];
383 :
384 0 : ulong bytes_read = cur_tile[ snapct_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, SNAPCT, FULL_BYTES_READ ) ];
385 0 : ulong bytes_total = cur_tile[ snapct_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, SNAPCT, FULL_SIZE_BYTES ) ];
386 :
387 0 : double progress = 0.0;
388 0 : switch( state ) {
389 0 : case FD_SNAPCT_STATE_WAITING_FOR_PEERS:
390 0 : case FD_SNAPCT_STATE_WAITING_FOR_PEERS_INCREMENTAL:
391 0 : case FD_SNAPCT_STATE_COLLECTING_PEERS:
392 0 : case FD_SNAPCT_STATE_COLLECTING_PEERS_INCREMENTAL:
393 0 : break;
394 0 : case FD_SNAPCT_STATE_READING_FULL_FILE:
395 0 : case FD_SNAPCT_STATE_FLUSHING_FULL_FILE_FINI:
396 0 : case FD_SNAPCT_STATE_FLUSHING_FULL_FILE_DONE:
397 0 : case FD_SNAPCT_STATE_READING_INCREMENTAL_FILE:
398 0 : case FD_SNAPCT_STATE_FLUSHING_INCREMENTAL_FILE_FINI:
399 0 : case FD_SNAPCT_STATE_FLUSHING_INCREMENTAL_FILE_DONE:
400 0 : case FD_SNAPCT_STATE_READING_FULL_HTTP:
401 0 : case FD_SNAPCT_STATE_FLUSHING_FULL_HTTP_FINI:
402 0 : case FD_SNAPCT_STATE_FLUSHING_FULL_HTTP_DONE:
403 0 : case FD_SNAPCT_STATE_READING_INCREMENTAL_HTTP:
404 0 : case FD_SNAPCT_STATE_FLUSHING_INCREMENTAL_HTTP_FINI:
405 0 : case FD_SNAPCT_STATE_FLUSHING_INCREMENTAL_HTTP_DONE:
406 0 : if( FD_LIKELY( bytes_total>0UL ) ) progress = 100.0 * (double)bytes_read / (double)bytes_total;
407 0 : break;
408 0 : case FD_SNAPCT_STATE_SHUTDOWN:
409 0 : progress = 100.0;
410 0 : break;
411 0 : }
412 :
413 0 : ulong snap_rx_sum = 0UL;
414 0 : ulong num_snap_rx_samples = fd_ulong_min( snapshot_rx_idx, sizeof(snapshot_rx_samples)/sizeof(snapshot_rx_samples[0]) );
415 0 : for( ulong i=0UL; i<num_snap_rx_samples; i++ ) snap_rx_sum += snapshot_rx_samples[ i ];
416 0 : double megabytes_per_second = 0.0;
417 0 : if( FD_LIKELY( num_snap_rx_samples ) ) megabytes_per_second = 100.0*(double)snap_rx_sum/(double)num_snap_rx_samples/1e6;
418 :
419 0 : ulong accounts_sum = 0UL;
420 0 : ulong num_accounts_samples = fd_ulong_min( snapshot_acc_idx, sizeof(snapshot_acc_samples)/sizeof(snapshot_acc_samples[0]) );
421 0 : for( ulong i=0UL; i<num_accounts_samples; i++ ) accounts_sum += snapshot_acc_samples[ i ];
422 0 : double million_accounts_per_second = 0.0;
423 0 : if( FD_LIKELY( num_accounts_samples ) ) million_accounts_per_second = 100.0*(double)accounts_sum/(double)num_accounts_samples/1e6;
424 :
425 0 : ulong snap_wr_sum = 0UL;
426 0 : ulong num_snap_wr_samples = fd_ulong_min( snapshot_wr_idx, sizeof(snapshot_wr_samples)/sizeof(snapshot_wr_samples[0]) );
427 0 : for( ulong i=0UL; i<num_snap_wr_samples; i++ ) snap_wr_sum += snapshot_wr_samples[ i ];
428 0 : double wr_megabytes_per_second = 0.0;
429 0 : if( FD_LIKELY( num_snap_wr_samples ) ) wr_megabytes_per_second = 100.0*(double)snap_wr_sum/(double)num_snap_wr_samples/1e6;
430 :
431 0 : ulong snapct_total_ticks = total_regime( &cur_tile[ snapct_idx*FD_METRICS_TOTAL_SZ ] )-total_regime( &prev_tile[ snapct_idx*FD_METRICS_TOTAL_SZ ] );
432 0 : ulong snapld_total_ticks = total_regime( &cur_tile[ fd_topo_find_tile( &config->topo, "snapld", 0UL )*FD_METRICS_TOTAL_SZ ] )-total_regime( &prev_tile[ fd_topo_find_tile( &config->topo, "snapld", 0UL )*FD_METRICS_TOTAL_SZ ] );
433 0 : ulong snapdc_total_ticks = total_regime( &cur_tile[ fd_topo_find_tile( &config->topo, "snapdc", 0UL )*FD_METRICS_TOTAL_SZ ] )-total_regime( &prev_tile[ fd_topo_find_tile( &config->topo, "snapdc", 0UL )*FD_METRICS_TOTAL_SZ ] );
434 0 : ulong snapin_total_ticks = total_regime( &cur_tile[ fd_topo_find_tile( &config->topo, "snapin", 0UL )*FD_METRICS_TOTAL_SZ ] )-total_regime( &prev_tile[ fd_topo_find_tile( &config->topo, "snapin", 0UL )*FD_METRICS_TOTAL_SZ ] );
435 0 : ulong snapwr_total_ticks = total_regime( &cur_tile[ fd_topo_find_tile( &config->topo, "snapwr", 0UL )*FD_METRICS_TOTAL_SZ ] )-total_regime( &prev_tile[ fd_topo_find_tile( &config->topo, "snapwr", 0UL )*FD_METRICS_TOTAL_SZ ] );
436 0 : snapct_total_ticks = fd_ulong_max( snapct_total_ticks, 1UL );
437 0 : snapld_total_ticks = fd_ulong_max( snapld_total_ticks, 1UL );
438 0 : snapdc_total_ticks = fd_ulong_max( snapdc_total_ticks, 1UL );
439 0 : snapin_total_ticks = fd_ulong_max( snapin_total_ticks, 1UL );
440 0 : snapwr_total_ticks = fd_ulong_max( snapwr_total_ticks, 1UL );
441 :
442 0 : double snapct_backp_pct = 100.0*(double)diff_tile( config, "snapct", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) )/(double)snapct_total_ticks;
443 0 : double snapld_backp_pct = 100.0*(double)diff_tile( config, "snapld", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) )/(double)snapld_total_ticks;
444 0 : double snapdc_backp_pct = 100.0*(double)diff_tile( config, "snapdc", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) )/(double)snapdc_total_ticks;
445 0 : double snapin_backp_pct = 100.0*(double)diff_tile( config, "snapin", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) )/(double)snapin_total_ticks;
446 0 : double snapwr_backp_pct = 100.0*(double)diff_tile( config, "snapwr", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) )/(double)snapwr_total_ticks;
447 :
448 0 : double snapct_idle_pct = 100.0*(double)diff_tile( config, "snapct", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG ) )/(double)snapct_total_ticks;
449 0 : double snapld_idle_pct = 100.0*(double)diff_tile( config, "snapld", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG ) )/(double)snapld_total_ticks;
450 0 : double snapdc_idle_pct = 100.0*(double)diff_tile( config, "snapdc", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG ) )/(double)snapdc_total_ticks;
451 0 : double snapin_idle_pct = 100.0*(double)diff_tile( config, "snapin", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG ) )/(double)snapin_total_ticks;
452 0 : double snapwr_idle_pct = 100.0*(double)diff_tile( config, "snapwr", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG ) )/(double)snapwr_total_ticks;
453 :
454 0 : PRINT( "โก " BOLD BYELLOW "SNAPSHOTS..." RESET UNBOLD
455 0 : " " BOLD "STATE" UNBOLD " %s"
456 0 : " " BOLD "PCT" UNBOLD " %.1f %%"
457 0 : " " BOLD "RX" UNBOLD " %3.f MB/s"
458 0 : " " BOLD "WR" UNBOLD " %3.f MB/s"
459 0 : " " BOLD "ACC" UNBOLD " %3.1f M/s"
460 0 : " " BOLD "BACKP" UNBOLD " %3.0f%%,%3.0f%%,%3.0f%%,%3.0f%%,%3.0f%%"
461 0 : " " BOLD "BUSY" UNBOLD " %3.0f%%,%3.0f%%,%3.0f%%,%3.0f%%,%3.0f%%" CLEARLN "\n",
462 0 : fd_snapct_state_str( (int)state ),
463 0 : progress,
464 0 : megabytes_per_second,
465 0 : wr_megabytes_per_second,
466 0 : million_accounts_per_second,
467 0 : snapct_backp_pct,
468 0 : snapld_backp_pct,
469 0 : snapdc_backp_pct,
470 0 : snapin_backp_pct,
471 0 : snapwr_backp_pct,
472 0 : 100.0-snapct_idle_pct-snapct_backp_pct,
473 0 : 100.0-snapld_idle_pct-snapld_backp_pct,
474 0 : 100.0-snapdc_idle_pct-snapdc_backp_pct,
475 0 : 100.0-snapin_idle_pct-snapin_backp_pct,
476 0 : 100.0-snapwr_idle_pct-snapwr_backp_pct );
477 0 : }
478 :
479 : static long
480 : diff_tile_idx( ulong const * prev_tile,
481 : ulong const * cur_tile,
482 : ulong tile_idx,
483 0 : ulong metric_off ) {
484 0 : return (long)cur_tile [ tile_idx*FD_METRICS_TOTAL_SZ+metric_off ] -
485 0 : (long)prev_tile[ tile_idx*FD_METRICS_TOTAL_SZ+metric_off ];
486 0 : }
487 :
488 : static void
489 : accdb_per_tile_offsets( char const * name,
490 0 : ulong * offs /* 11 entries: acquired, writable, missed, waited, rd, wr, cp, evicted_class_base, preevicted_class_base, committed_new_class_base, committed_overwrite_class_base */ ) {
491 0 : if( !strcmp( name, "execle" ) ) {
492 0 : offs[0] =MIDX(COUNTER,EXECLE,ACCDB_ACCOUNT_ACQUIRED ); offs[1]=MIDX(COUNTER,EXECLE,ACCDB_ACCOUNT_WRITABLE_ACQUIRED);
493 0 : offs[2] =MIDX(COUNTER,EXECLE,ACCDB_ACCOUNT_NOT_FOUND ); offs[3]=MIDX(COUNTER,EXECLE,ACCDB_ACCOUNT_WAITED );
494 0 : offs[4] =MIDX(COUNTER,EXECLE,ACCDB_BYTES_READ ); offs[5]=MIDX(COUNTER,EXECLE,ACCDB_BYTES_WRITTEN );
495 0 : offs[6] =MIDX(COUNTER,EXECLE,ACCDB_BYTES_COPIED ); offs[7]=MIDX(COUNTER,EXECLE,ACCDB_ACCOUNT_EVICTED );
496 0 : offs[8] =ULONG_MAX ; offs[9]=MIDX(COUNTER,EXECLE,ACCDB_ACCOUNT_COMMITTED_NEW );
497 0 : offs[10]=MIDX(COUNTER,EXECLE,ACCDB_ACCOUNT_COMMITTED_OVERWRITE);
498 0 : } else if( !strcmp( name, "execrp" ) ) {
499 0 : offs[0] =MIDX(COUNTER,EXECRP,ACCDB_ACCOUNT_ACQUIRED ); offs[1]=MIDX(COUNTER,EXECRP,ACCDB_ACCOUNT_WRITABLE_ACQUIRED);
500 0 : offs[2] =MIDX(COUNTER,EXECRP,ACCDB_ACCOUNT_NOT_FOUND ); offs[3]=MIDX(COUNTER,EXECRP,ACCDB_ACCOUNT_WAITED );
501 0 : offs[4] =MIDX(COUNTER,EXECRP,ACCDB_BYTES_READ ); offs[5]=MIDX(COUNTER,EXECRP,ACCDB_BYTES_WRITTEN );
502 0 : offs[6] =MIDX(COUNTER,EXECRP,ACCDB_BYTES_COPIED ); offs[7]=MIDX(COUNTER,EXECRP,ACCDB_ACCOUNT_EVICTED );
503 0 : offs[8] =ULONG_MAX ; offs[9]=MIDX(COUNTER,EXECRP,ACCDB_ACCOUNT_COMMITTED_NEW );
504 0 : offs[10]=MIDX(COUNTER,EXECRP,ACCDB_ACCOUNT_COMMITTED_OVERWRITE);
505 0 : } else if( !strcmp( name, "replay" ) ) {
506 0 : offs[0] =MIDX(COUNTER,REPLAY,ACCDB_ACCOUNT_ACQUIRED ); offs[1]=MIDX(COUNTER,REPLAY,ACCDB_ACCOUNT_WRITABLE_ACQUIRED);
507 0 : offs[2] =MIDX(COUNTER,REPLAY,ACCDB_ACCOUNT_NOT_FOUND ); offs[3]=MIDX(COUNTER,REPLAY,ACCDB_ACCOUNT_WAITED );
508 0 : offs[4] =MIDX(COUNTER,REPLAY,ACCDB_BYTES_READ ); offs[5]=MIDX(COUNTER,REPLAY,ACCDB_BYTES_WRITTEN );
509 0 : offs[6] =MIDX(COUNTER,REPLAY,ACCDB_BYTES_COPIED ); offs[7]=MIDX(COUNTER,REPLAY,ACCDB_ACCOUNT_EVICTED );
510 0 : offs[8] =ULONG_MAX ; offs[9]=MIDX(COUNTER,REPLAY,ACCDB_ACCOUNT_COMMITTED_NEW );
511 0 : offs[10]=MIDX(COUNTER,REPLAY,ACCDB_ACCOUNT_COMMITTED_OVERWRITE);
512 0 : } else if( !strcmp( name, "tower" ) ) {
513 0 : offs[0] =MIDX(COUNTER,TOWER,ACCDB_ACCOUNT_ACQUIRED ); offs[1]=MIDX(COUNTER,TOWER,ACCDB_ACCOUNT_WRITABLE_ACQUIRED );
514 0 : offs[2] =MIDX(COUNTER,TOWER,ACCDB_ACCOUNT_NOT_FOUND ); offs[3]=MIDX(COUNTER,TOWER,ACCDB_ACCOUNT_WAITED );
515 0 : offs[4] =MIDX(COUNTER,TOWER,ACCDB_BYTES_READ ); offs[5]=MIDX(COUNTER,TOWER,ACCDB_BYTES_WRITTEN );
516 0 : offs[6] =MIDX(COUNTER,TOWER,ACCDB_BYTES_COPIED ); offs[7]=MIDX(COUNTER,TOWER,ACCDB_ACCOUNT_EVICTED );
517 0 : offs[8] =ULONG_MAX ; offs[9]=MIDX(COUNTER,TOWER,ACCDB_ACCOUNT_COMMITTED_NEW );
518 0 : offs[10]=MIDX(COUNTER,TOWER,ACCDB_ACCOUNT_COMMITTED_OVERWRITE);
519 0 : } else if( !strcmp( name, "accdb" ) ) {
520 : /* The accdb tile only runs background work (compact, preevict,
521 : advance_root, purge); it never acquires/releases. Sentinel
522 : everything that comes from the acquire/release path. */
523 0 : offs[0] =ULONG_MAX ; offs[1]=ULONG_MAX ;
524 0 : offs[2] =ULONG_MAX ; offs[3]=ULONG_MAX ;
525 0 : offs[4] =MIDX(COUNTER,ACCDB,BYTES_READ ); offs[5]=MIDX(COUNTER,ACCDB,BYTES_WRITTEN );
526 0 : offs[6] =ULONG_MAX ; offs[7]=ULONG_MAX ;
527 0 : offs[8] =MIDX(COUNTER,ACCDB,ACCOUNT_PREEVICTED ); offs[9]=ULONG_MAX ;
528 0 : offs[10]=ULONG_MAX;
529 0 : } else if( !strcmp( name, "rpc" ) ) {
530 : /* RPC is a read-only accdb consumer. It only emits the subset
531 : of counters that fd_accdb_read_one_nocache touches; everything
532 : else is sentinel and skipped by sample_accdb. */
533 0 : offs[0] =MIDX(COUNTER,RPC,ACCDB_ACCOUNT_ACQUIRED); offs[1]=ULONG_MAX;
534 0 : offs[2] =MIDX(COUNTER,RPC,ACCDB_ACCOUNT_NOT_FOUND); offs[3]=MIDX(COUNTER,RPC,ACCDB_ACCOUNT_WAITED);
535 0 : offs[4] =MIDX(COUNTER,RPC,ACCDB_BYTES_READ ); offs[5]=ULONG_MAX;
536 0 : offs[6] =MIDX(COUNTER,RPC,ACCDB_BYTES_COPIED ); offs[7]=ULONG_MAX;
537 0 : offs[8] =ULONG_MAX; offs[9]=ULONG_MAX;
538 0 : offs[10]=ULONG_MAX;
539 0 : } else if( !strcmp( name, "resolv" ) ) {
540 : /* Resolv is a read-only accdb consumer (address lookup table
541 : reads on the receive path). Same RO subset as RPC. */
542 0 : offs[0] =MIDX(COUNTER,RESOLV,ACCDB_ACCOUNT_ACQUIRED ); offs[1]=ULONG_MAX;
543 0 : offs[2] =MIDX(COUNTER,RESOLV,ACCDB_ACCOUNT_NOT_FOUND); offs[3]=MIDX(COUNTER,RESOLV,ACCDB_ACCOUNT_WAITED);
544 0 : offs[4] =MIDX(COUNTER,RESOLV,ACCDB_BYTES_READ ); offs[5]=ULONG_MAX;
545 0 : offs[6] =MIDX(COUNTER,RESOLV,ACCDB_BYTES_COPIED ); offs[7]=ULONG_MAX;
546 0 : offs[8] =ULONG_MAX; offs[9]=ULONG_MAX;
547 0 : offs[10]=ULONG_MAX;
548 0 : } else {
549 0 : for( ulong i=0UL; i<11UL; i++ ) offs[i] = ULONG_MAX;
550 0 : }
551 0 : }
552 :
553 : static void
554 : sample_accdb( config_t const * config,
555 : ulong const * prev_tile,
556 0 : ulong const * cur_tile ) {
557 0 : long acquired = 0L, writable = 0L, missed = 0L, evicted = 0L, waited = 0L;
558 0 : long bytes_rd = 0L, bytes_wr = 0L, bytes_cp = 0L, bytes_pe = 0L;
559 0 : long preevicted = 0L;
560 0 : long evicted_class[ 8 ] = {0};
561 0 : long preevicted_class[ 8 ] = {0};
562 0 : long committed_new_class[ 8 ] = {0};
563 0 : long committed_overwrite_class[ 8 ] = {0};
564 :
565 0 : for( ulong i=0UL; i<config->topo.tile_cnt; i++ ) {
566 0 : ulong offs[11];
567 0 : accdb_per_tile_offsets( config->topo.tiles[ i ].name, offs );
568 0 : if( offs[0]!=ULONG_MAX ) {
569 0 : for( ulong c=0UL; c<8UL; c++ ) acquired += diff_tile_idx( prev_tile, cur_tile, i, offs[0] + c );
570 0 : }
571 0 : if( offs[1]!=ULONG_MAX ) {
572 0 : for( ulong c=0UL; c<8UL; c++ ) writable += diff_tile_idx( prev_tile, cur_tile, i, offs[1] + c );
573 0 : }
574 0 : if( offs[3]!=ULONG_MAX ) waited += diff_tile_idx( prev_tile, cur_tile, i, offs[3] );
575 0 : if( offs[4]!=ULONG_MAX ) bytes_rd += diff_tile_idx( prev_tile, cur_tile, i, offs[4] );
576 0 : if( offs[6]!=ULONG_MAX ) bytes_cp += diff_tile_idx( prev_tile, cur_tile, i, offs[6] );
577 0 : if( offs[5]!=ULONG_MAX ) {
578 0 : long this_wr = diff_tile_idx( prev_tile, cur_tile, i, offs[5] );
579 0 : if( !strcmp( config->topo.tiles[ i ].name, "accdb" ) ) bytes_pe += this_wr;
580 0 : else bytes_wr += this_wr;
581 0 : }
582 0 : for( ulong c=0UL; c<8UL; c++ ) {
583 0 : if( offs[2]!=ULONG_MAX ) missed += diff_tile_idx( prev_tile, cur_tile, i, offs[2] + c );
584 0 : if( offs[7]!=ULONG_MAX ) {
585 0 : long d = diff_tile_idx( prev_tile, cur_tile, i, offs[7] + c );
586 0 : evicted_class[ c ] += d;
587 0 : evicted += d;
588 0 : }
589 0 : if( offs[8]!=ULONG_MAX ) {
590 0 : long d = diff_tile_idx( prev_tile, cur_tile, i, offs[8] + c );
591 0 : preevicted_class[ c ] += d;
592 0 : preevicted += d;
593 0 : }
594 0 : if( offs[9] !=ULONG_MAX ) committed_new_class [ c ] += diff_tile_idx( prev_tile, cur_tile, i, offs[9] + c );
595 0 : if( offs[10]!=ULONG_MAX ) committed_overwrite_class[ c ] += diff_tile_idx( prev_tile, cur_tile, i, offs[10] + c );
596 0 : }
597 0 : }
598 :
599 0 : ulong slot = accdb_samples_idx % (sizeof(accdb_acquired_samples)/sizeof(accdb_acquired_samples[0]));
600 0 : accdb_acquired_samples[ slot ] = (ulong)acquired;
601 0 : accdb_writable_samples[ slot ] = (ulong)writable;
602 0 : accdb_missed_samples [ slot ] = (ulong)missed;
603 0 : accdb_evicted_samples [ slot ] = (ulong)evicted;
604 0 : accdb_waited_samples [ slot ] = (ulong)waited;
605 0 : accdb_bytes_rd_samples[ slot ] = (ulong)bytes_rd;
606 0 : accdb_bytes_wr_samples[ slot ] = (ulong)bytes_wr;
607 0 : accdb_bytes_cp_samples[ slot ] = (ulong)bytes_cp;
608 0 : accdb_bytes_pe_samples[ slot ] = (ulong)bytes_pe;
609 0 : accdb_preevicted_samples[ slot ] = (ulong)preevicted;
610 0 : for( ulong c=0UL; c<8UL; c++ ) {
611 0 : accdb_evicted_class_samples [ c ][ slot ] = (ulong)evicted_class [ c ];
612 0 : accdb_preevicted_class_samples [ c ][ slot ] = (ulong)preevicted_class [ c ];
613 0 : accdb_committed_new_class_samples [ c ][ slot ] = (ulong)committed_new_class [ c ];
614 0 : accdb_committed_overwrite_class_samples[ c ][ slot ] = (ulong)committed_overwrite_class[ c ];
615 0 : }
616 0 : accdb_samples_idx++;
617 0 : }
618 :
619 : static uint
620 : write_accdb( config_t const * config,
621 : ulong const * cur_tile,
622 0 : ulong const * prev_tile ) {
623 0 : ulong accdb_tile_idx = fd_topo_find_tile( &config->topo, "accdb", 0UL );
624 0 : if( accdb_tile_idx==ULONG_MAX ) return 0U;
625 :
626 0 : ulong const * t = cur_tile + accdb_tile_idx*FD_METRICS_TOTAL_SZ;
627 :
628 0 : ulong accdb_total_ticks = total_regime( &cur_tile[ accdb_tile_idx*FD_METRICS_TOTAL_SZ ] )-total_regime( &prev_tile[ accdb_tile_idx*FD_METRICS_TOTAL_SZ ] );
629 0 : accdb_total_ticks = fd_ulong_max( accdb_total_ticks, 1UL );
630 0 : double accdb_backp_pct = 100.0*(double)diff_tile( config, "accdb", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) )/(double)accdb_total_ticks;
631 0 : double accdb_idle_pct = 100.0*(double)diff_tile( config, "accdb", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG ) )/(double)accdb_total_ticks;
632 0 : double accdb_busy_pct = 100.0 - accdb_backp_pct - accdb_idle_pct;
633 :
634 0 : ulong acct_cnt = t[ MIDX( GAUGE, ACCDB, ACCOUNT_COUNT ) ];
635 0 : ulong acct_cap = t[ MIDX( GAUGE, ACCDB, ACCOUNT_CAPACITY ) ];
636 0 : ulong used_bytes = t[ MIDX( GAUGE, ACCDB, DISK_USED_BYTES ) ];
637 0 : ulong current_bytes = t[ MIDX( GAUGE, ACCDB, DISK_CURRENT_BYTES ) ];
638 0 : ulong alloc_bytes = t[ MIDX( GAUGE, ACCDB, DISK_ALLOCATED_BYTES ) ];
639 0 : ulong in_compaction = t[ MIDX( GAUGE, ACCDB, IN_COMPACTION ) ];
640 0 : ulong compact_req = t[ MIDX( COUNTER, ACCDB, COMPACTION_REQUESTED ) ];
641 0 : ulong compact_done = t[ MIDX( COUNTER, ACCDB, COMPACTION_COMPLETED ) ];
642 :
643 0 : ulong frag_bytes = current_bytes>used_bytes ? current_bytes-used_bytes : 0UL;
644 0 : double data_gb = (double)alloc_bytes/1e9;
645 0 : double live_gb = (double)used_bytes/1e9;
646 0 : double frag_gb = (double)frag_bytes/1e9;
647 0 : double frag_pct = current_bytes ? 100.0*(double)frag_bytes/(double)current_bytes : 0.0;
648 0 : double index_pct = acct_cap ? 100.0*(double)acct_cnt/(double)acct_cap : 0.0;
649 :
650 0 : PRINT( "๐พ " BOLD GREEN "ACCOUNTS...." RESET UNBOLD
651 0 : " " BOLD "CACHE SIZE" UNBOLD " %lu GiB"
652 0 : " " BOLD "DISK" UNBOLD " %.1f GB"
653 0 : " " BOLD "LIVE DATA" UNBOLD " %.1f GB"
654 0 : " " BOLD "FRAGMENTATION" UNBOLD " %.1f GB (%4.1f%%)"
655 0 : " " BOLD "INDEX" UNBOLD " %4.1f%% (%.1fM / %.1fM)"
656 0 : " " BOLD "COMPACTION" UNBOLD " %s (%lu / %lu)"
657 0 : " " BOLD "BUSY" UNBOLD " %3.0f%%" CLEARLN "\n",
658 0 : config->firedancer.accounts.cache_size_gib,
659 0 : data_gb, live_gb, frag_gb, frag_pct,
660 0 : index_pct, (double)acct_cnt/1e6, (double)acct_cap/1e6,
661 0 : in_compaction ? "running" : "idle", compact_done, compact_req,
662 0 : accdb_busy_pct );
663 :
664 0 : ulong const cap = sizeof(accdb_acquired_samples)/sizeof(accdb_acquired_samples[0]);
665 0 : ulong n = fd_ulong_min( accdb_samples_idx, cap );
666 0 : if( !n ) n = 1UL;
667 :
668 0 : ulong sum_acq = 0UL, sum_wr = 0UL, sum_miss = 0UL, sum_evict = 0UL, sum_wait = 0UL;
669 0 : ulong sum_brd = 0UL, sum_bwr = 0UL, sum_bcp = 0UL, sum_bpe = 0UL;
670 0 : ulong sum_pre = 0UL;
671 0 : for( ulong i=0UL; i<n; i++ ) {
672 0 : sum_acq += accdb_acquired_samples[ i ];
673 0 : sum_wr += accdb_writable_samples[ i ];
674 0 : sum_miss += accdb_missed_samples [ i ];
675 0 : sum_evict += accdb_evicted_samples [ i ];
676 0 : sum_wait += accdb_waited_samples [ i ];
677 0 : sum_brd += accdb_bytes_rd_samples[ i ];
678 0 : sum_bwr += accdb_bytes_wr_samples[ i ];
679 0 : sum_bcp += accdb_bytes_cp_samples[ i ];
680 0 : sum_bpe += accdb_bytes_pe_samples[ i ];
681 0 : sum_pre += accdb_preevicted_samples[ i ];
682 0 : }
683 :
684 : /* Snap interval is 10ms, so per-second rate = mean diff * 100. */
685 0 : double acquired = 100.0*(double)sum_acq /(double)n;
686 0 : double writable = 100.0*(double)sum_wr /(double)n;
687 0 : double missed = 100.0*(double)sum_miss /(double)n;
688 0 : double evicted = 100.0*(double)sum_evict/(double)n;
689 0 : double waited = 100.0*(double)sum_wait /(double)n;
690 0 : double bytes_rd = 100.0*(double)sum_brd /(double)n;
691 0 : double bytes_wr = 100.0*(double)sum_bwr /(double)n;
692 0 : double bytes_cp = 100.0*(double)sum_bcp /(double)n;
693 0 : double bytes_pe = 100.0*(double)sum_bpe /(double)n;
694 0 : double preevicted = 100.0*(double)sum_pre/(double)n;
695 :
696 0 : double hit_pct = acquired>0.0 ? 100.0*(acquired-missed)/acquired : 0.0;
697 :
698 0 : char * read_str = fmt_bytes( fd_alloca_check( 1UL, 64UL ), 64UL, (long)bytes_rd );
699 0 : char * write_str = fmt_bytes( fd_alloca_check( 1UL, 64UL ), 64UL, (long)bytes_wr );
700 0 : char * copy_str = fmt_bytes( fd_alloca_check( 1UL, 64UL ), 64UL, (long)bytes_cp );
701 0 : char * preevict_str= fmt_bytes( fd_alloca_check( 1UL, 64UL ), 64UL, (long)bytes_pe );
702 0 : char * acq_str = COUNTF( acquired );
703 0 : char * wr_str = COUNTF( writable );
704 0 : char * miss_str = COUNTF( missed );
705 0 : char * evict_str = COUNTF( evicted );
706 0 : char * pre_str = COUNTF( preevicted );
707 0 : char * wait_str = COUNTF( waited );
708 :
709 0 : PRINT( " "
710 0 : " " BOLD "ACQUIRE" UNBOLD " %s /s (%s wr /s)"
711 0 : " " BOLD "HIT" UNBOLD " %5.1f%%"
712 0 : " " BOLD "MISS" UNBOLD " %s /s"
713 0 : " " BOLD "EVICT" UNBOLD " %s /s (+%s /s)"
714 0 : " " BOLD "WAIT" UNBOLD " %s /s"
715 0 : " " BOLD "IO" UNBOLD " %s rd %s wr-acq %s wr-pe %s cp" CLEARLN "\n",
716 0 : acq_str, wr_str, hit_pct, miss_str, evict_str, pre_str, wait_str,
717 0 : read_str, write_str, preevict_str, copy_str );
718 :
719 0 : char * evict_class_str[ 8 ];
720 0 : char * preevict_class_str[ 8 ];
721 0 : char * commit_new_class_str[ 8 ];
722 0 : char * commit_overwrite_class_str[ 8 ];
723 0 : for( ulong c=0UL; c<8UL; c++ ) {
724 0 : ulong sum_c = 0UL, sum_pc = 0UL, sum_cn = 0UL, sum_co = 0UL;
725 0 : for( ulong i=0UL; i<n; i++ ) {
726 0 : sum_c += accdb_evicted_class_samples [ c ][ i ];
727 0 : sum_pc += accdb_preevicted_class_samples [ c ][ i ];
728 0 : sum_cn += accdb_committed_new_class_samples [ c ][ i ];
729 0 : sum_co += accdb_committed_overwrite_class_samples[ c ][ i ];
730 0 : }
731 0 : evict_class_str [ c ] = COUNTF_T( 100.0*(double)sum_c /(double)n );
732 0 : preevict_class_str [ c ] = COUNTF_T( 100.0*(double)sum_pc/(double)n );
733 0 : commit_new_class_str [ c ] = COUNTF_T( 100.0*(double)sum_cn/(double)n );
734 0 : commit_overwrite_class_str[ c ] = COUNTF_T( 100.0*(double)sum_co/(double)n );
735 0 : }
736 :
737 0 : PRINT( " "
738 0 : " " BOLD "EVICT/s BY CLASS" UNBOLD
739 0 : " " BOLD "128B" UNBOLD " %s (+%s)"
740 0 : " " BOLD "512B" UNBOLD " %s (+%s)"
741 0 : " " BOLD "2K" UNBOLD " %s (+%s)"
742 0 : " " BOLD "8K" UNBOLD " %s (+%s)"
743 0 : " " BOLD "32K" UNBOLD " %s (+%s)"
744 0 : " " BOLD "128K" UNBOLD " %s (+%s)"
745 0 : " " BOLD "1M" UNBOLD " %s (+%s)"
746 0 : " " BOLD "10M" UNBOLD " %s (+%s)" CLEARLN "\n",
747 0 : evict_class_str[0], preevict_class_str[0],
748 0 : evict_class_str[1], preevict_class_str[1],
749 0 : evict_class_str[2], preevict_class_str[2],
750 0 : evict_class_str[3], preevict_class_str[3],
751 0 : evict_class_str[4], preevict_class_str[4],
752 0 : evict_class_str[5], preevict_class_str[5],
753 0 : evict_class_str[6], preevict_class_str[6],
754 0 : evict_class_str[7], preevict_class_str[7] );
755 :
756 0 : PRINT( " "
757 0 : " " BOLD "COMMIT/s " UNBOLD
758 0 : " " BOLD "128B" UNBOLD " %s (=%s)"
759 0 : " " BOLD "512B" UNBOLD " %s (=%s)"
760 0 : " " BOLD "2K" UNBOLD " %s (=%s)"
761 0 : " " BOLD "8K" UNBOLD " %s (=%s)"
762 0 : " " BOLD "32K" UNBOLD " %s (=%s)"
763 0 : " " BOLD "128K" UNBOLD " %s (=%s)"
764 0 : " " BOLD "1M" UNBOLD " %s (=%s)"
765 0 : " " BOLD "10M" UNBOLD " %s (=%s)" CLEARLN "\n",
766 0 : commit_new_class_str[0], commit_overwrite_class_str[0],
767 0 : commit_new_class_str[1], commit_overwrite_class_str[1],
768 0 : commit_new_class_str[2], commit_overwrite_class_str[2],
769 0 : commit_new_class_str[3], commit_overwrite_class_str[3],
770 0 : commit_new_class_str[4], commit_overwrite_class_str[4],
771 0 : commit_new_class_str[5], commit_overwrite_class_str[5],
772 0 : commit_new_class_str[6], commit_overwrite_class_str[6],
773 0 : commit_new_class_str[7], commit_overwrite_class_str[7] );
774 :
775 0 : ulong cache_used_off = MIDX( GAUGE, ACCDB, CACHE_CLASS_USED );
776 0 : ulong cache_max_off = MIDX( GAUGE, ACCDB, CACHE_CLASS_MAX );
777 0 : char * cache_used_str[ 8 ];
778 0 : char * cache_max_str [ 8 ];
779 0 : double cache_pct [ 8 ];
780 0 : for( ulong c=0UL; c<8UL; c++ ) {
781 0 : ulong used = t[ cache_used_off + c ];
782 0 : ulong max = t[ cache_max_off + c ];
783 0 : cache_used_str[ c ] = COUNT_T( used );
784 0 : cache_max_str [ c ] = COUNT_T( max );
785 0 : cache_pct [ c ] = max ? 100.0*(double)used/(double)max : 0.0;
786 0 : }
787 :
788 0 : PRINT( " "
789 0 : " " BOLD "CACHE FULL" UNBOLD
790 0 : " " BOLD "128B" UNBOLD " %s/%s (%5.1f%%)"
791 0 : " " BOLD "512B" UNBOLD " %s/%s (%5.1f%%)"
792 0 : " " BOLD "2K" UNBOLD " %s/%s (%5.1f%%)"
793 0 : " " BOLD "8K" UNBOLD " %s/%s (%5.1f%%)"
794 0 : " " BOLD "32K" UNBOLD " %s/%s (%5.1f%%)"
795 0 : " " BOLD "128K" UNBOLD " %s/%s (%5.1f%%)"
796 0 : " " BOLD "1M" UNBOLD " %s/%s (%5.1f%%)"
797 0 : " " BOLD "10M" UNBOLD " %s/%s (%5.1f%%)" CLEARLN "\n",
798 0 : cache_used_str[0], cache_max_str[0], cache_pct[0],
799 0 : cache_used_str[1], cache_max_str[1], cache_pct[1],
800 0 : cache_used_str[2], cache_max_str[2], cache_pct[2],
801 0 : cache_used_str[3], cache_max_str[3], cache_pct[3],
802 0 : cache_used_str[4], cache_max_str[4], cache_pct[4],
803 0 : cache_used_str[5], cache_max_str[5], cache_pct[5],
804 0 : cache_used_str[6], cache_max_str[6], cache_pct[6],
805 0 : cache_used_str[7], cache_max_str[7], cache_pct[7] );
806 :
807 0 : ulong cache_resv_off = MIDX( GAUGE, ACCDB, CACHE_CLASS_RESERVED );
808 0 : char * cache_resv_str[ 8 ];
809 0 : for( ulong c=0UL; c<8UL; c++ ) {
810 0 : ulong resv = t[ cache_resv_off + c ];
811 0 : if( resv==ULONG_MAX ) cache_resv_str[ c ] = " off ";
812 0 : else cache_resv_str[ c ] = COUNT_T( resv );
813 0 : }
814 :
815 0 : PRINT( " "
816 0 : " " BOLD "RESERVED " UNBOLD
817 0 : " " BOLD "128B" UNBOLD " %s "
818 0 : " " BOLD "512B" UNBOLD " %s "
819 0 : " " BOLD "2K" UNBOLD " %s "
820 0 : " " BOLD "8K" UNBOLD " %s "
821 0 : " " BOLD "32K" UNBOLD " %s "
822 0 : " " BOLD "128K" UNBOLD " %s "
823 0 : " " BOLD "1M" UNBOLD " %s "
824 0 : " " BOLD "10M" UNBOLD " %s " CLEARLN "\n",
825 0 : cache_resv_str[0], cache_resv_str[1], cache_resv_str[2], cache_resv_str[3],
826 0 : cache_resv_str[4], cache_resv_str[5], cache_resv_str[6], cache_resv_str[7] );
827 0 : return 6;
828 0 : }
829 :
830 : static uint
831 : write_wfs( config_t const * config,
832 0 : ulong const * cur_tile ) {
833 0 : ulong gossip_tile_idx = fd_topo_find_tile( &config->topo, "gossip", 0UL );
834 0 : if( FD_UNLIKELY( gossip_tile_idx==ULONG_MAX ) ) return 0U;
835 :
836 0 : int wfs_state = (int)cur_tile[ gossip_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, GOSSIP, WAIT_FOR_SUPERMAJORITY_STATE ) ];
837 0 : if( FD_LIKELY( wfs_state==FD_GOSSIP_WFS_STATE_DONE ) ) return 0U;
838 :
839 0 : char const * state_str;
840 0 : switch( wfs_state ) {
841 0 : case FD_GOSSIP_WFS_STATE_INIT: state_str = "loading snapshot"; break;
842 0 : case FD_GOSSIP_WFS_STATE_WAIT: state_str = "waiting"; break;
843 0 : case FD_GOSSIP_WFS_STATE_PUBLISH: state_str = "starting"; break;
844 0 : default: return 0U;
845 0 : }
846 :
847 0 : ulong _stake_online = cur_tile[ gossip_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, GOSSIP, WAIT_FOR_SUPERMAJORITY_STAKE_ONLINE ) ];
848 0 : ulong _stake_total = cur_tile[ gossip_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, GOSSIP, WAIT_FOR_SUPERMAJORITY_STAKE_TOTAL ) ];
849 0 : ulong peers_online = cur_tile[ gossip_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, GOSSIP, WAIT_FOR_SUPERMAJORITY_STAKED_PEER_ONLINE ) ];
850 0 : ulong peers_total = cur_tile[ gossip_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, GOSSIP, WAIT_FOR_SUPERMAJORITY_STAKED_PEER_TOTAL ) ];
851 :
852 0 : ulong ipecho_tile_idx = fd_topo_find_tile( &config->topo, "ipecho", 0UL );
853 0 : ulong shred_ver = 0UL;
854 0 : if( FD_LIKELY( ipecho_tile_idx!=ULONG_MAX ) ) shred_ver = cur_tile[ ipecho_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, IPECHO, CURRENT_SHRED_VERSION ) ];
855 :
856 0 : double stake_pct = _stake_total>0UL ? 100.0*(double)_stake_online/(double)_stake_total : 0.0;
857 0 : double stake_div = (_stake_total<(ulong)1e14) ? 1e9 : 1e15;
858 0 : char const * stake_unit = (_stake_total<(ulong)1e14) ? " SOL" : "M";
859 0 : double stake_online = (double)_stake_online / stake_div;
860 0 : double stake_total = (double)_stake_total / stake_div;
861 :
862 0 : PRINT( "โณ " BOLD YELLOW "CLUSTER BOOT" RESET UNBOLD
863 0 : " " BOLD "STATE" UNBOLD " %s"
864 0 : " " BOLD "STAKE" UNBOLD " %3.0f%% (%.1f%s / %.1f%s)"
865 0 : " " BOLD "SHRED VERSION" UNBOLD " %lu"
866 0 : " " BOLD "PEERS" UNBOLD " %lu online %lu offline"
867 0 : " " BOLD "BANK HASH" UNBOLD " %s" CLEARLN "\n",
868 0 : state_str,
869 0 : stake_pct,
870 0 : stake_online,
871 0 : stake_unit,
872 0 : stake_total,
873 0 : stake_unit,
874 0 : shred_ver,
875 0 : peers_online,
876 0 : peers_total>peers_online ? peers_total-peers_online : 0UL,
877 0 : config->firedancer.consensus.wait_for_supermajority_with_bank_hash );
878 0 : return 1U;
879 0 : }
880 :
881 : static uint
882 : write_gossip( config_t const * config,
883 : ulong const * cur_tile,
884 : ulong const * prev_tile,
885 : ulong const * cur_link,
886 0 : ulong const * prev_link ) {
887 0 : ulong gossip_tile_idx = fd_topo_find_tile( &config->topo, "gossip", 0UL );
888 0 : if( gossip_tile_idx==ULONG_MAX ) return 0U;
889 0 : char * contact_info = COUNT( cur_tile[ gossip_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, GOSSIP, CRDS_OCCUPIED_CONTACT_INFO_V2 ) ] );
890 :
891 0 : ulong gossip_total_ticks = total_regime( &cur_tile[ gossip_tile_idx*FD_METRICS_TOTAL_SZ ] )-total_regime( &prev_tile[ gossip_tile_idx*FD_METRICS_TOTAL_SZ ] );
892 0 : gossip_total_ticks = fd_ulong_max( gossip_total_ticks, 1UL );
893 0 : double gossip_backp_pct = 100.0*(double)diff_tile( config, "gossip", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) )/(double)gossip_total_ticks;
894 0 : double gossip_idle_pct = 100.0*(double)diff_tile( config, "gossip", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG ) )/(double)gossip_total_ticks;
895 0 : double gossip_busy_pct = 100.0 - gossip_backp_pct - gossip_idle_pct;
896 :
897 0 : PRINT( "๐ฌ " BOLD BLUE "GOSSIP......" RESET UNBOLD
898 0 : " " BOLD "RX" UNBOLD " %s"
899 0 : " " BOLD "TX" UNBOLD " %s"
900 0 : " " BOLD "CRDS" UNBOLD " %s"
901 0 : " " BOLD "PEERS" UNBOLD " %s"
902 0 : " " BOLD "BUSY" UNBOLD " %3.0f%%"
903 0 : " " BOLD "BACKP" UNBOLD " %3.0f%%" CLEARLN "\n",
904 0 : DIFF_LINK_BYTES( "net_gossvf", COUNTER, LINK, FRAG_CONSUMED_BYTES ),
905 0 : DIFF_LINK_BYTES( "gossip_net", COUNTER, LINK, FRAG_CONSUMED_BYTES ),
906 0 : COUNT( total_crds( &cur_tile[ fd_topo_find_tile( &config->topo, "gossip", 0UL )*FD_METRICS_TOTAL_SZ ] ) ),
907 0 : contact_info,
908 0 : gossip_busy_pct,
909 0 : gossip_backp_pct );
910 0 : return 1U;
911 0 : }
912 :
913 : static uint
914 : write_repair( config_t const * config,
915 : ulong const * cur_tile,
916 : ulong const * cur_link,
917 0 : ulong const * prev_link ) {
918 0 : ulong repair_tile_idx = fd_topo_find_tile( &config->topo, "repair", 0UL );
919 0 : if( repair_tile_idx==ULONG_MAX ) return 0U;
920 0 : ulong repair_slot = cur_tile[ repair_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, REPAIR, SLOT_HIGHEST_REPAIRED ) ];
921 0 : ulong turbine_slot = cur_tile[ repair_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, REPAIR, SLOT_CURRENT ) ];
922 0 : PRINT( "๐งฑ " BOLD RED "REPAIR......" RESET UNBOLD
923 0 : " " BOLD "RX" UNBOLD " %s"
924 0 : " " BOLD "TX" UNBOLD " %s"
925 0 : " " BOLD "REPAIR SLOT" UNBOLD " %lu (%02ld)"
926 0 : " " BOLD "TURBINE SLOT" UNBOLD " %lu" CLEARLN "\n",
927 0 : DIFF_LINK_BYTES( "net_repair", COUNTER, LINK, FRAG_CONSUMED_BYTES ),
928 0 : DIFF_LINK_BYTES( "repair_net", COUNTER, LINK, FRAG_CONSUMED_BYTES ),
929 0 : repair_slot,
930 0 : (long)repair_slot-(long)turbine_slot,
931 0 : turbine_slot );
932 0 : return 1U;
933 0 : }
934 :
935 : static uint
936 : write_rserve( config_t const * config,
937 : ulong const * cur_tile,
938 : ulong const * cur_link,
939 0 : ulong const * prev_link ) {
940 0 : ulong rserve_tile_idx = fd_topo_find_tile( &config->topo, "rserve", 0UL );
941 0 : if( rserve_tile_idx==ULONG_MAX ) return 0UL;
942 :
943 0 : (void)cur_tile;
944 :
945 0 : ulong shreds_stored_sum = 0UL;
946 0 : ulong num_stored_shreds = fd_ulong_min( shreds_stored_samples_idx, sizeof(shreds_stored_sample)/sizeof(shreds_stored_sample[0]));
947 0 : for( ulong i=0UL; i<num_stored_shreds; i++ ) shreds_stored_sum += shreds_stored_sample[ i ];
948 0 : char * shreds_stored = COUNTF( 100.0*(double)shreds_stored_sum/(double)num_stored_shreds );
949 :
950 0 : ulong valid_sum = 0UL;
951 0 : ulong num_valid_samples = fd_ulong_min( rserve_rps_valid_samples_idx, sizeof(rserve_rps_valid_samples)/sizeof(rserve_rps_valid_samples[0]) );
952 0 : for( ulong i=0UL; i<num_valid_samples; i++ ) valid_sum += rserve_rps_valid_samples[ i ];
953 0 : char * valid_str = COUNTF( 100.0*(double)valid_sum/(double)num_valid_samples );
954 :
955 0 : ulong invalid_sum = 0UL;
956 0 : ulong num_invalid_samples = fd_ulong_min( rserve_rps_invalid_samples_idx, sizeof(rserve_rps_invalid_samples)/sizeof(rserve_rps_invalid_samples[0]) );
957 0 : for( ulong i=0UL; i<num_invalid_samples; i++ ) invalid_sum += rserve_rps_invalid_samples[ i ];
958 0 : char * invalid_str = COUNTF( 100.0*(double)invalid_sum/(double)num_invalid_samples );
959 :
960 0 : ulong num_total_samples = fd_ulong_max( num_valid_samples, 1UL );
961 0 : char * total_str = COUNTF( 100.0*(double)(valid_sum+invalid_sum)/(double)num_total_samples );
962 :
963 0 : PRINT( "๐ง " BOLD GREEN "RSERVE......" RESET UNBOLD
964 0 : " " BOLD "RX" UNBOLD " %s"
965 0 : " " BOLD "TX" UNBOLD " %s"
966 0 : " " BOLD "STORED SHREDS" UNBOLD " %s /s"
967 0 : " " BOLD "RPS" UNBOLD " %s (%s valid, %s invalid) /s" CLEARLN "\n",
968 0 : DIFF_LINK_BYTES( "net_rserve", COUNTER, LINK, FRAG_CONSUMED_BYTES ),
969 0 : DIFF_LINK_BYTES( "rserve_net", COUNTER, LINK, FRAG_CONSUMED_BYTES ),
970 0 : shreds_stored,
971 0 : total_str, valid_str, invalid_str );
972 0 : return 1U;
973 0 : }
974 :
975 : static uint
976 : write_replay( config_t const * config,
977 0 : ulong const * cur_tile ) {
978 0 : ulong repair_tile_idx = fd_topo_find_tile( &config->topo, "repair", 0UL );
979 0 : ulong replay_tile_idx = fd_topo_find_tile( &config->topo, "replay", 0UL );
980 0 : if( replay_tile_idx==ULONG_MAX ) return 0U;
981 :
982 0 : ulong reset_slot = cur_tile[ replay_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, REPLAY, RESET_SLOT ) ];
983 0 : ulong next_leader_slot = cur_tile[ replay_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, REPLAY, NEXT_LEADER_SLOT ) ];
984 0 : ulong leader_slot = cur_tile[ replay_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, REPLAY, LEADER_SLOT ) ];
985 0 : char * next_leader_slot_str = fd_alloca_check( 1UL, 64UL );
986 :
987 0 : ulong turbine_slot;
988 0 : if( repair_tile_idx!=ULONG_MAX ) {
989 0 : turbine_slot = cur_tile[ repair_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, REPAIR, SLOT_CURRENT ) ];
990 0 : } else {
991 0 : turbine_slot = reset_slot;
992 0 : }
993 :
994 0 : ulong slot_in_seconds = (ulong)((double)(next_leader_slot-reset_slot)*0.4);
995 0 : if( FD_UNLIKELY( leader_slot ) ) FD_TEST( fd_cstr_printf_check( next_leader_slot_str, 64UL, NULL, "now" ) );
996 0 : else if( FD_LIKELY( next_leader_slot>0UL ) ) FD_TEST( fd_cstr_printf_check( next_leader_slot_str, 64UL, NULL, "%lum %lus", slot_in_seconds/60UL, slot_in_seconds%60UL ) );
997 0 : else FD_TEST( fd_cstr_printf_check( next_leader_slot_str, 64UL, NULL, "never" ) );
998 :
999 0 : ulong root_distance = cur_tile[ replay_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, REPLAY, ROOT_DISTANCE ) ];
1000 0 : ulong live_banks = cur_tile[ replay_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, REPLAY, BANK_LIVE ) ];
1001 :
1002 0 : ulong sps_sum = 0UL;
1003 0 : ulong num_sps_samples = fd_ulong_min( sps_samples_idx, sizeof(sps_samples)/sizeof(sps_samples[0]));
1004 0 : for( ulong i=0UL; i<num_sps_samples; i++ ) sps_sum += sps_samples[ i ];
1005 0 : char * sps_str = COUNTF( 100.0*(double)sps_sum/(double)num_sps_samples );
1006 :
1007 0 : ulong tps_sum = 0UL;
1008 0 : ulong num_tps_samples = fd_ulong_min( tps_samples_idx, sizeof(tps_samples)/sizeof(tps_samples[0]));
1009 0 : for( ulong i=0UL; i<num_tps_samples; i++ ) tps_sum += tps_samples[ i ];
1010 0 : char * tps_str = COUNTF( 100.0*(double)tps_sum/(double)num_tps_samples );
1011 :
1012 0 : ulong cups_sum = 0UL;
1013 0 : ulong num_cups_samples = fd_ulong_min( cups_samples_idx, sizeof(cups_samples)/sizeof(cups_samples[0]));
1014 0 : for( ulong i=0UL; i<num_cups_samples; i++ ) cups_sum += cups_samples[ i ];
1015 0 : char * mcups_str = COUNTF( 100.0*(double)cups_sum/(double)num_cups_samples );
1016 :
1017 0 : PRINT( "๐ฅ " BOLD MAGENTA "REPLAY......" RESET UNBOLD
1018 0 : " " BOLD "SLOT" UNBOLD " %lu (%02ld)"
1019 0 : " " BOLD "CU/s" UNBOLD " %s"
1020 0 : " " BOLD "TPS" UNBOLD " %s"
1021 0 : " " BOLD "SPS" UNBOLD " %s"
1022 0 : " " BOLD "LEADER IN" UNBOLD " %s"
1023 0 : " " BOLD "ROOT DIST" UNBOLD " %lu"
1024 0 : " " BOLD "BANKS" UNBOLD " %2lu" CLEARLN "\n",
1025 0 : reset_slot,
1026 0 : (long)reset_slot-(long)turbine_slot,
1027 0 : mcups_str,
1028 0 : tps_str,
1029 0 : sps_str,
1030 0 : next_leader_slot_str,
1031 0 : root_distance,
1032 0 : live_banks );
1033 0 : return 1U;
1034 0 : }
1035 :
1036 : static uint
1037 : write_gui( config_t const * config,
1038 : ulong const * cur_tile,
1039 0 : ulong const * prev_tile ) {
1040 0 : char const * gui_name = "gui";
1041 0 : ulong gui_tile_idx = fd_topo_find_tile( &config->topo, gui_name, 0UL );
1042 :
1043 0 : ulong off_conn_active, off_websocket_conn_active, off_websocket_frame_tx, off_websocket_frame_rx;
1044 0 : char * bytes_read_s;
1045 0 : char * bytes_written_s;
1046 0 : if( FD_LIKELY( gui_tile_idx!=ULONG_MAX ) ) {
1047 0 : off_conn_active = MIDX( GAUGE, GUI, CONN_ACTIVE );
1048 0 : off_websocket_conn_active = MIDX( GAUGE, GUI, WEBSOCKET_CONN_ACTIVE );
1049 0 : off_websocket_frame_tx = MIDX( COUNTER, GUI, WEBSOCKET_FRAME_TX );
1050 0 : off_websocket_frame_rx = MIDX( COUNTER, GUI, WEBSOCKET_FRAME_RX );
1051 :
1052 0 : bytes_read_s = DIFF_BYTES( gui_name, COUNTER, GUI, BYTES_READ );
1053 0 : bytes_written_s = DIFF_BYTES( gui_name, COUNTER, GUI, BYTES_WRITTEN );
1054 0 : } else {
1055 0 : gui_name = "guih";
1056 0 : gui_tile_idx = fd_topo_find_tile( &config->topo, gui_name, 0UL );
1057 0 : if( FD_UNLIKELY( gui_tile_idx==ULONG_MAX ) ) return 0U;
1058 0 : off_conn_active = MIDX( GAUGE, GUIH, CONN_ACTIVE );
1059 0 : off_websocket_conn_active = MIDX( GAUGE, GUIH, WEBSOCKET_CONN_ACTIVE );
1060 0 : off_websocket_frame_tx = MIDX( COUNTER, GUIH, WEBSOCKET_FRAME_TX );
1061 0 : off_websocket_frame_rx = MIDX( COUNTER, GUIH, WEBSOCKET_FRAME_RX );
1062 :
1063 0 : bytes_read_s = DIFF_BYTES( gui_name, COUNTER, GUIH, BYTES_READ );
1064 0 : bytes_written_s = DIFF_BYTES( gui_name, COUNTER, GUIH, BYTES_WRITTEN );
1065 0 : }
1066 :
1067 0 : ulong connection_count = cur_tile[ gui_tile_idx*FD_METRICS_TOTAL_SZ+off_conn_active ]+cur_tile[ gui_tile_idx*FD_METRICS_TOTAL_SZ+off_websocket_conn_active ];
1068 0 : ulong gui_total_ticks = total_regime( &cur_tile[ gui_tile_idx*FD_METRICS_TOTAL_SZ ] )-total_regime( &prev_tile[ gui_tile_idx*FD_METRICS_TOTAL_SZ ] );
1069 0 : gui_total_ticks = fd_ulong_max( gui_total_ticks, 1UL );
1070 0 : double gui_backp_pct = 100.0*(double)diff_tile( config, gui_name, prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) )/(double)gui_total_ticks;
1071 0 : double gui_idle_pct = 100.0*(double)diff_tile( config, gui_name, prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG ) )/(double)gui_total_ticks;
1072 0 : double gui_busy_pct = 100.0 - gui_backp_pct - gui_idle_pct;
1073 :
1074 0 : long sent_frame_count = diff_tile( config, gui_name, prev_tile, cur_tile, off_websocket_frame_tx );
1075 0 : char * sent_frame_count_s = COUNT( (ulong)sent_frame_count );
1076 0 : long received_frame_count = diff_tile( config, gui_name, prev_tile, cur_tile, off_websocket_frame_rx );
1077 :
1078 0 : PRINT( "๐ " BOLD CYAN "GUI........." RESET UNBOLD
1079 0 : " " BOLD "CONNS" UNBOLD " %lu"
1080 0 : " " BOLD "FRAMES" UNBOLD " %s in %s out"
1081 0 : " " BOLD "BW" UNBOLD " %s in %s out"
1082 0 : " " BOLD "BUSY" UNBOLD " %3.0f%% " CLEARLN "\n",
1083 0 : connection_count,
1084 0 : COUNT( (ulong)received_frame_count ),
1085 0 : sent_frame_count_s,
1086 0 : bytes_read_s,
1087 0 : bytes_written_s,
1088 0 : gui_busy_pct );
1089 0 : return 1U;
1090 0 : }
1091 :
1092 : static uint
1093 : write_event( config_t const * config,
1094 0 : ulong const * cur_tile ) {
1095 0 : ulong event_tile_idx = fd_topo_find_tile( &config->topo, "event", 0UL );
1096 0 : if( event_tile_idx==ULONG_MAX ) return 0U;
1097 :
1098 0 : ulong connection_state = cur_tile[ event_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, EVENT, CONN_STATE ) ];
1099 0 : char const * connection_state_str;
1100 0 : switch( connection_state ) {
1101 0 : case 0UL: connection_state_str = "disconnected"; break;
1102 0 : case 1UL: connection_state_str = "connecting"; break;
1103 0 : case 2UL: connection_state_str = "authenticating"; break;
1104 0 : case 3UL: connection_state_str = "confirming_auth"; break;
1105 0 : case 4UL: connection_state_str = "connected"; break;
1106 0 : default: connection_state_str = "unknown"; break;
1107 0 : }
1108 :
1109 0 : ulong event_queue_count = cur_tile[ event_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, EVENT, QUEUE_DEPTH ) ];
1110 0 : ulong event_queue_unsent = cur_tile[ event_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, EVENT, QUEUE_UNSENT ) ];
1111 0 : ulong event_queue_unacked = event_queue_count>event_queue_unsent ? event_queue_count-event_queue_unsent : 0UL;
1112 0 : ulong event_last_acked_id = cur_tile[ event_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, EVENT, LAST_ACKED_ID ) ];
1113 0 : ulong event_queue_drops = cur_tile[ event_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( COUNTER, EVENT, QUEUE_DROPPED ) ];
1114 0 : ulong event_queue_bytes_used = cur_tile[ event_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, EVENT, QUEUE_BYTES_USED ) ];
1115 0 : ulong event_queue_bytes_capacity = cur_tile[ event_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, EVENT, QUEUE_BYTES_CAPACITY ) ];
1116 :
1117 0 : double event_queue_pct_full = event_queue_bytes_capacity>0UL ? 100.0*(double)event_queue_bytes_used/(double)event_queue_bytes_capacity : 0.0;
1118 :
1119 0 : ulong events_sent_sum = 0UL;
1120 0 : ulong num_events_sent_samples = fd_ulong_min( events_sent_samples_idx, sizeof(events_sent_samples)/sizeof(events_sent_samples[0]));
1121 0 : for( ulong i=0UL; i<num_events_sent_samples; i++ ) events_sent_sum += events_sent_samples[ i ];
1122 0 : char * events_sent_str = COUNTF( 100.0*(double)events_sent_sum/(double)num_events_sent_samples );
1123 :
1124 0 : ulong events_acked_sum = 0UL;
1125 0 : ulong num_events_acked_samples = fd_ulong_min( events_acked_samples_idx, sizeof(events_acked_samples)/sizeof(events_acked_samples[0]));
1126 0 : for( ulong i=0UL; i<num_events_acked_samples; i++ ) events_acked_sum += events_acked_samples[ i ];
1127 0 : char * events_acked_str = COUNTF( 100.0*(double)events_acked_sum/(double)num_events_acked_samples );
1128 :
1129 0 : ulong bytes_written_sum = 0UL;
1130 0 : ulong num_bytes_written_samples = fd_ulong_min( event_bytes_written_samples_idx, sizeof(event_bytes_written_samples)/sizeof(event_bytes_written_samples[0]));
1131 0 : for( ulong i=0UL; i<num_bytes_written_samples; i++ ) bytes_written_sum += event_bytes_written_samples[ i ];
1132 0 : long bytes_written_per_sec = (long)(100.0*(double)bytes_written_sum/(double)num_bytes_written_samples);
1133 0 : char * bytes_written_str = fmt_bytes( fd_alloca_check( 1UL, 64UL ), 64UL, bytes_written_per_sec );
1134 :
1135 0 : ulong bytes_read_sum = 0UL;
1136 0 : ulong num_bytes_read_samples = fd_ulong_min( event_bytes_read_samples_idx, sizeof(event_bytes_read_samples)/sizeof(event_bytes_read_samples[0]));
1137 0 : for( ulong i=0UL; i<num_bytes_read_samples; i++ ) bytes_read_sum += event_bytes_read_samples[ i ];
1138 0 : long bytes_read_per_sec = (long)(100.0*(double)bytes_read_sum/(double)num_bytes_read_samples);
1139 0 : char * bytes_read_str = fmt_bytes( fd_alloca_check( 1UL, 64UL ), 64UL, bytes_read_per_sec );
1140 :
1141 0 : char * event_queue_unacked_s = COUNT( event_queue_unacked );
1142 0 : char * event_queue_unsent_s = COUNT( event_queue_unsent );
1143 0 : char * event_last_acked_id_s = COUNT( event_last_acked_id );
1144 :
1145 0 : PRINT( "๐ก " BOLD YELLOW "EVENT......." RESET UNBOLD
1146 0 : " " BOLD "STATE" UNBOLD " %12s"
1147 0 : " " BOLD "UNACKED" UNBOLD " %s"
1148 0 : " " BOLD "QUEUE" UNBOLD " %s"
1149 0 : " " BOLD "SENT" UNBOLD " %s /s"
1150 0 : " " BOLD "ACKED" UNBOLD " %s /s"
1151 0 : " " BOLD "LAST ACK" UNBOLD " %s"
1152 0 : " " BOLD "BW" UNBOLD " %s in %s out"
1153 0 : " " BOLD "DROPS" UNBOLD " %s"
1154 0 : " " BOLD "FULL" UNBOLD " %3.0f%%" CLEARLN "\n",
1155 0 : connection_state_str,
1156 0 : event_queue_unacked_s,
1157 0 : event_queue_unsent_s,
1158 0 : events_sent_str,
1159 0 : events_acked_str,
1160 0 : event_last_acked_id_s,
1161 0 : bytes_read_str,
1162 0 : bytes_written_str,
1163 0 : COUNT( event_queue_drops ),
1164 0 : event_queue_pct_full );
1165 0 : return 1U;
1166 0 : }
1167 :
1168 : static char *
1169 : base58_short( char out[ static 16 ],
1170 0 : uchar const key[ static 32 ] ) {
1171 0 : char enc[ FD_BASE58_ENCODED_32_SZ ];
1172 0 : ulong len;
1173 0 : fd_base58_encode_32( key, &len, enc );
1174 0 : char * p = fd_cstr_init( out );
1175 0 : p = fd_cstr_append_text( p, enc, 6 ),
1176 0 : p = fd_cstr_append_text( p, "โฆ", sizeof("โฆ")-1 ),
1177 0 : p = fd_cstr_append_text( p, enc+len-6, 6 );
1178 0 : fd_cstr_fini( p );
1179 0 : return out;
1180 0 : }
1181 :
1182 : static void
1183 : fmt_balance( char out[ static 64 ],
1184 0 : ulong lamports ) {
1185 0 : ulong maj = lamports / 1000000000UL;
1186 0 : ulong min = lamports % 1000000000UL;
1187 0 : fd_cstr_printf_check( out, 64UL, NULL, "%lu.%09lu", maj, min );
1188 0 : }
1189 :
1190 : static uint
1191 : write_node_info( config_t const * config,
1192 : ulong const * cur_tile,
1193 0 : fd_node_info_t const * node_info ) {
1194 :
1195 0 : char identity_str[ FD_BASE58_ENCODED_32_SZ ];
1196 0 : if( FD_LIKELY( node_info && !fd_pubkey_check_zero( &node_info->identity ) ) ) {
1197 0 : fd_base58_encode_32( node_info->identity.key, NULL, identity_str );
1198 0 : } else {
1199 0 : strcpy( identity_str, "???" );
1200 0 : }
1201 :
1202 0 : char vote_acc_str[ FD_BASE58_ENCODED_32_SZ ];
1203 0 : if( FD_LIKELY( node_info && !fd_pubkey_check_zero( &node_info->vote_account ) ) ) {
1204 0 : fd_base58_encode_32( node_info->vote_account.key, NULL, vote_acc_str );
1205 0 : } else {
1206 0 : strcpy( vote_acc_str, "???" );
1207 0 : }
1208 :
1209 0 : char shred_ver_str[ 16 ];
1210 0 : ulong ipecho_idx = fd_topo_find_tile( &config->topo, "ipecho", 0UL );
1211 0 : ushort shred_version = 0;
1212 0 : if( FD_LIKELY( ipecho_idx!=ULONG_MAX ) ) shred_version = (ushort)cur_tile[ ipecho_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, IPECHO, CURRENT_SHRED_VERSION ) ];
1213 0 : if( shred_version ) {
1214 0 : fd_cstr_printf_check( shred_ver_str, sizeof(shred_ver_str), NULL, "%hu", shred_version );
1215 0 : } else if( config->consensus.expected_shred_version ) {
1216 0 : fd_cstr_printf_check( shred_ver_str, sizeof(shred_ver_str), NULL, "(%hu)", config->consensus.expected_shred_version );
1217 0 : } else {
1218 0 : fd_cstr_printf_check( shred_ver_str, sizeof(shred_ver_str), NULL, "???" );
1219 0 : }
1220 :
1221 0 : char genesis_hash_b58[ FD_BASE58_ENCODED_32_SZ ] = {0};
1222 0 : char genesis_short[ 16 ] = {0};
1223 0 : int has_genesis_b58 = 0;
1224 0 : if( FD_LIKELY( node_info && !fd_pubkey_check_zero( &node_info->genesis_hash ) ) ) {
1225 0 : fd_base58_encode_32( node_info->genesis_hash.key, NULL, genesis_hash_b58 );
1226 0 : base58_short( genesis_short, node_info->genesis_hash.key );
1227 0 : has_genesis_b58 = 1;
1228 0 : } else {
1229 0 : fd_cstr_ncpy( genesis_short, "???", sizeof(genesis_short) );
1230 0 : }
1231 :
1232 0 : char const * cluster_str = "unknown";
1233 0 : if( has_genesis_b58 ) {
1234 0 : ulong cluster_id = fd_genesis_cluster_identify( genesis_hash_b58 );
1235 0 : cluster_str = fd_genesis_cluster_name( cluster_id );
1236 0 : }
1237 :
1238 0 : char uptime_str[ 32UL ];
1239 0 : long now = fd_log_wallclock();
1240 0 : if( FD_LIKELY( config->boot_timestamp_nanos>0L && now>config->boot_timestamp_nanos ) ) {
1241 0 : ulong elapsed_s = (ulong)( (now - config->boot_timestamp_nanos) / (long)1e9 );
1242 0 : ulong days = elapsed_s / 86400UL;
1243 0 : ulong hours = (elapsed_s % 86400UL) / 3600UL;
1244 0 : ulong mins = (elapsed_s % 3600UL) / 60UL;
1245 0 : ulong secs = elapsed_s % 60UL;
1246 0 : if( days ) fd_cstr_printf_check( uptime_str, sizeof(uptime_str), NULL, "%lud %luh %lum", days, hours, mins );
1247 0 : else if( hours ) fd_cstr_printf_check( uptime_str, sizeof(uptime_str), NULL, "%luh %lum %lus", hours, mins, secs );
1248 0 : else fd_cstr_printf_check( uptime_str, sizeof(uptime_str), NULL, "%lum %lus", mins, secs );
1249 0 : } else {
1250 0 : fd_cstr_printf_check( uptime_str, sizeof(uptime_str), NULL, "???" );
1251 0 : }
1252 :
1253 0 : ulong replay_idx = fd_topo_find_tile( &config->topo, "replay", 0UL );
1254 0 : ulong const * replay_metrics = &cur_tile[ replay_idx*FD_METRICS_TOTAL_SZ ];
1255 0 : ulong identity_balance = replay_metrics[ MIDX( GAUGE, REPLAY, IDENTITY_BALANCE_LAMPORTS ) ];
1256 0 : ulong stake_amount = replay_metrics[ MIDX( GAUGE, REPLAY, ACTIVE_STAKE_LAMPORTS ) ];
1257 0 : ulong epoch_credits = replay_metrics[ MIDX( GAUGE, REPLAY, EPOCH_CREDITS ) ];
1258 0 : ulong tot_stake = replay_metrics[ MIDX( GAUGE, REPLAY, CLUSTER_ACTIVE_STAKE_LAMPORTS ) ];
1259 0 : char identity_balance_str[ 64 ]; fmt_balance( identity_balance_str, identity_balance );
1260 0 : char stake_amount_str [ 64 ]; fmt_balance( stake_amount_str, stake_amount );
1261 0 : double stake_percent = 0.0;
1262 0 : if( tot_stake>0UL ) stake_percent = 100.0*(double)stake_amount/(double)tot_stake;
1263 :
1264 0 : PRINT( "๐" BOLD ORANGE " NODE........" RESET UNBOLD
1265 0 : " " BOLD "ID" UNBOLD " %44s"
1266 0 : " " BOLD "VOTE" UNBOLD " %44s"
1267 0 : " " BOLD "CLUSTER" UNBOLD " %s"
1268 0 : " " BOLD "UPTIME" UNBOLD " %s"
1269 0 : " " BOLD "SHRED" UNBOLD " %s"
1270 0 : " " BOLD "GENESIS" UNBOLD " %s",
1271 0 : identity_str,
1272 0 : vote_acc_str,
1273 0 : cluster_str,
1274 0 : uptime_str,
1275 0 : shred_ver_str,
1276 0 : genesis_short );
1277 0 : PRINT( CLEARLN "\n" );
1278 :
1279 0 : PRINT( " " BOLD "BALANCE" UNBOLD " %s"
1280 0 : " " BOLD "STAKE" UNBOLD " %s (%.2f %%)"
1281 0 : " " BOLD "CREDITS" UNBOLD " %lu" CLEARLN "\n",
1282 0 : identity_balance_str, stake_amount_str, stake_percent, epoch_credits );
1283 :
1284 0 : return 2U;
1285 0 : }
1286 :
1287 : static void
1288 : write_summary( config_t const * config,
1289 : fd_node_info_box_t const * shinfo,
1290 : ulong const * cur_tile,
1291 : ulong const * prev_tile,
1292 : ulong const * cur_link,
1293 : ulong const * prev_link,
1294 0 : int interposing ) {
1295 0 : (void)config;
1296 0 : (void)prev_tile;
1297 0 : (void)cur_tile;
1298 :
1299 0 : if( FD_UNLIKELY( !ended_on_newline ) ) PRINT( "\n" );
1300 0 : PRINT( "\033[?7l" ); /* disable autowrap mode */
1301 0 : lines_printed = 0UL;
1302 0 : if( FD_UNLIKELY( interposing ) ) {
1303 0 : PRINT( "โโโโโโโโโโโโโโโ" CLEARLN "\n" );
1304 0 : lines_printed = 1UL;
1305 0 : }
1306 :
1307 0 : ulong snapct_idx = fd_topo_find_tile( &config->topo, "snapct", 0UL );
1308 0 : int shutdown = 1;
1309 0 : if( FD_LIKELY( snapct_idx!=ULONG_MAX ) ) shutdown = cur_tile[ snapct_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, SNAPCT, STATE ) ]==FD_SNAPCT_STATE_SHUTDOWN;
1310 :
1311 0 : static long snap_shutdown_time = 0L;
1312 0 : if( FD_UNLIKELY( !snap_shutdown_time && !shutdown ) ) snap_shutdown_time = 1L; /* Was not shutdown on boot */
1313 0 : if( FD_UNLIKELY( !snap_shutdown_time && shutdown ) ) snap_shutdown_time = 2L; /* Was shutdown on boot */
1314 0 : if( FD_UNLIKELY( snap_shutdown_time==1L && shutdown ) ) snap_shutdown_time = fd_log_wallclock();
1315 :
1316 0 : fd_node_info_t node_info[1]; fd_node_info_read( node_info, shinfo );
1317 0 : lines_printed += write_node_info( config, cur_tile, node_info );
1318 :
1319 0 : if( FD_UNLIKELY( write_bench( config, cur_tile, prev_tile ) ) ) lines_printed++;
1320 :
1321 0 : ulong backt_idx = fd_topo_find_tile( &config->topo, "backt", 0UL );
1322 0 : if( FD_UNLIKELY( backt_idx!=ULONG_MAX ) ) {
1323 0 : lines_printed++;
1324 0 : write_backtest( config, cur_tile );
1325 0 : }
1326 :
1327 0 : long now = fd_log_wallclock();
1328 0 : if( FD_UNLIKELY( snap_shutdown_time==1L || now<snap_shutdown_time+(long)2e9 ) ) {
1329 0 : lines_printed++;
1330 0 : write_snapshots( config, cur_tile, prev_tile );
1331 0 : }
1332 :
1333 0 : lines_printed += write_accdb( config, cur_tile, prev_tile );
1334 0 : lines_printed += write_wfs( config, cur_tile );
1335 0 : lines_printed += write_gossip( config, cur_tile, prev_tile, cur_link, prev_link );
1336 0 : lines_printed += write_repair( config, cur_tile, cur_link, prev_link );
1337 0 : lines_printed += write_rserve( config, cur_tile, cur_link, prev_link );
1338 0 : lines_printed += write_replay( config, cur_tile );
1339 0 : lines_printed += write_gui( config, cur_tile, prev_tile );
1340 0 : lines_printed += write_event( config, cur_tile );
1341 :
1342 0 : PRINT( "\033[?7h" ); /* enable autowrap mode */
1343 0 : }
1344 :
1345 : static void
1346 : snap_tiles( fd_topo_t const * topo,
1347 0 : ulong * tiles ) {
1348 0 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
1349 0 : fd_topo_tile_t const * tile = &topo->tiles[ i ];
1350 0 : volatile ulong const * metrics = fd_metrics_tile( tile->metrics );
1351 0 : FD_TEST( metrics );
1352 0 : for( ulong j=0UL; j<FD_METRICS_TOTAL_SZ/8UL; j++ ) tiles[ i*FD_METRICS_TOTAL_SZ+j ] = metrics[ j ];
1353 0 : }
1354 0 : }
1355 :
1356 : static void
1357 : snap_links( fd_topo_t const * topo,
1358 0 : ulong * links ) {
1359 0 : ulong overall_polled_idx = 0UL;
1360 :
1361 0 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
1362 0 : fd_topo_tile_t const * tile = &topo->tiles[ i ];
1363 :
1364 0 : ulong polled_in_idx = 0UL;
1365 0 : for( ulong j=0UL; j<topo->tiles[ i ].in_cnt; j++ ) {
1366 0 : if( FD_UNLIKELY( !tile->in_link_poll[ j ] ) ) continue;
1367 :
1368 0 : volatile ulong const * metrics = fd_metrics_link_in( tile->metrics, polled_in_idx );
1369 0 : FD_TEST( metrics );
1370 0 : for( ulong k=0UL; k<FD_METRICS_ALL_LINK_IN_TOTAL; k++ ) links[ overall_polled_idx*8UL+k ] = metrics[ k ];
1371 0 : polled_in_idx++;
1372 0 : overall_polled_idx++;
1373 0 : }
1374 0 : }
1375 0 : }
1376 :
1377 : static ulong tiles[ 2UL*FD_TILE_MAX*FD_METRICS_TOTAL_SZ ];
1378 : static ulong links[ 2UL*4096UL*8UL*FD_METRICS_ALL_LINK_IN_TOTAL ];
1379 :
1380 : static void
1381 : run( config_t const * config,
1382 0 : int drain_output_fd ) {
1383 0 : (void)config;
1384 0 : (void)drain_output_fd;
1385 :
1386 0 : ulong node_info_obj_id = fd_pod_query_ulong( config->topo.props, "node_info", ULONG_MAX );
1387 0 : FD_TEST( node_info_obj_id!=ULONG_MAX );
1388 0 : fd_node_info_box_t * node_info = fd_node_info_box_join( fd_topo_obj_laddr( &config->topo, node_info_obj_id ) );
1389 0 : FD_TEST( node_info );
1390 :
1391 0 : ulong tile_cnt = config->topo.tile_cnt;
1392 :
1393 0 : ulong cons_cnt = 0UL;
1394 0 : for( ulong i=0UL; i<config->topo.tile_cnt; i++ ) {
1395 0 : for( ulong j=0UL; j<config->topo.tiles[ i ].in_cnt; j++ ) {
1396 0 : if( FD_UNLIKELY( config->topo.tiles[ i ].in_link_poll[ j ] ) ) cons_cnt++;
1397 0 : }
1398 0 : }
1399 :
1400 0 : FD_TEST( tile_cnt<=FD_TILE_MAX );
1401 0 : FD_TEST( cons_cnt<=4096UL );
1402 :
1403 0 : snap_tiles( &config->topo, tiles );
1404 0 : fd_memcpy( tiles+tile_cnt*FD_METRICS_TOTAL_SZ, tiles, tile_cnt*FD_METRICS_TOTAL_SZ*sizeof(ulong) );
1405 :
1406 0 : snap_links( &config->topo, links );
1407 0 : fd_memcpy( links+(cons_cnt*8UL*FD_METRICS_ALL_LINK_IN_TOTAL), links, cons_cnt*8UL*FD_METRICS_ALL_LINK_IN_TOTAL*sizeof(ulong) );
1408 :
1409 0 : ulong last_snap = 1UL;
1410 :
1411 0 : int interposing = drain_output_fd>=0;
1412 :
1413 0 : frame_len = 0UL;
1414 0 : write_summary( config, node_info, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, links+last_snap*(cons_cnt*8UL*FD_METRICS_ALL_LINK_IN_TOTAL), links+(1UL-last_snap)*(cons_cnt*8UL*FD_METRICS_ALL_LINK_IN_TOTAL), interposing );
1415 0 : flush_frame();
1416 :
1417 0 : long next = fd_log_wallclock()+(long)1e9;
1418 0 : for(;;) {
1419 0 : if( FD_UNLIKELY( drain_output_fd>=0 ) ) {
1420 0 : if( FD_UNLIKELY( drain( drain_output_fd ) ) ) {
1421 0 : frame_len = 0UL;
1422 0 : write_summary( config, node_info, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, links+last_snap*(cons_cnt*8UL*FD_METRICS_ALL_LINK_IN_TOTAL), links+(1UL-last_snap)*(cons_cnt*8UL*FD_METRICS_ALL_LINK_IN_TOTAL), interposing );
1423 0 : flush_frame();
1424 0 : }
1425 0 : }
1426 :
1427 0 : long now = fd_log_wallclock();
1428 0 : if( FD_UNLIKELY( now>=next ) ) {
1429 0 : last_snap = 1UL-last_snap;
1430 0 : snap_tiles( &config->topo, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ );
1431 0 : snap_links( &config->topo, links+last_snap*(cons_cnt*8UL*FD_METRICS_ALL_LINK_IN_TOTAL) );
1432 :
1433 : /* Bench */
1434 0 : tps_sent_samples[ tps_sent_samples_idx%(sizeof(tps_sent_samples)/sizeof(tps_sent_samples[0])) ] = (ulong)diff_tile( config, "benchs", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, BENCHS, TXN_TX ) );
1435 0 : tps_sent_samples_idx++;
1436 :
1437 : /* Replay */
1438 0 : sps_samples[ sps_samples_idx%(sizeof(sps_samples)/sizeof(sps_samples[0])) ] = (ulong)diff_tile( config, "replay", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, REPLAY, SLOT_REPLAYED ) );
1439 0 : sps_samples_idx++;
1440 0 : tps_samples[ tps_samples_idx%(sizeof(tps_samples)/sizeof(tps_samples[0])) ] = (ulong)diff_tile( config, "replay", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, REPLAY, TXN_PROCESSED ) );
1441 0 : tps_samples_idx++;
1442 0 : cups_samples[ cups_samples_idx%(sizeof(cups_samples)/sizeof(cups_samples[0])) ] =
1443 0 : (ulong)diff_tile( config, "execrp", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, EXECRP, CU_EXECUTED ) ) +
1444 0 : (ulong)diff_tile( config, "execle", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, EXECLE, CU_EXECUTED ) );
1445 0 : cups_samples_idx++;
1446 :
1447 : /* Snapshot */
1448 0 : snapshot_rx_samples[ snapshot_rx_idx%(sizeof(snapshot_rx_samples)/sizeof(snapshot_rx_samples[0])) ] = (ulong)diff_tile( config, "snapct", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( GAUGE, SNAPCT, FULL_BYTES_READ ) ) +
1449 0 : (ulong)diff_tile( config, "snapct", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( GAUGE, SNAPCT, INCREMENTAL_BYTES_READ ) );
1450 0 : snapshot_rx_idx++;
1451 0 : snapshot_acc_samples[ snapshot_acc_idx%(sizeof(snapshot_acc_samples)/sizeof(snapshot_acc_samples[0])) ] = (ulong)diff_tile( config, "snapin", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( GAUGE, SNAPIN, ACCOUNT_LOADED ) );
1452 0 : snapshot_acc_idx++;
1453 0 : snapshot_wr_samples[ snapshot_wr_idx%(sizeof(snapshot_wr_samples)/sizeof(snapshot_wr_samples[0])) ] = (ulong)diff_tile( config, "snapwr", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( GAUGE, SNAPWR, BYTES_WRITTEN ) );
1454 0 : snapshot_wr_idx++;
1455 :
1456 : /* Events */
1457 0 : events_sent_samples[ events_sent_samples_idx%(sizeof(events_sent_samples)/sizeof(events_sent_samples[0])) ] = (ulong)diff_tile( config, "event", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, EVENT, SENT ) );
1458 0 : events_sent_samples_idx++;
1459 0 : events_acked_samples[ events_acked_samples_idx%(sizeof(events_acked_samples)/sizeof(events_acked_samples[0])) ] = (ulong)diff_tile( config, "event", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, EVENT, ACKED ) );
1460 0 : events_acked_samples_idx++;
1461 0 : event_bytes_written_samples[ event_bytes_written_samples_idx%(sizeof(event_bytes_written_samples)/sizeof(event_bytes_written_samples[0])) ] = (ulong)diff_tile( config, "event", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, EVENT, BYTES_WRITTEN ) );
1462 0 : event_bytes_written_samples_idx++;
1463 0 : event_bytes_read_samples[ event_bytes_read_samples_idx%(sizeof(event_bytes_read_samples)/sizeof(event_bytes_read_samples[0])) ] = (ulong)diff_tile( config, "event", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, EVENT, BYTES_READ ) );
1464 0 : event_bytes_read_samples_idx++;
1465 :
1466 : /* Accounts */
1467 0 : sample_accdb( config, tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ );
1468 :
1469 : /* Repair server */
1470 0 : shreds_stored_sample[ shreds_stored_samples_idx%(sizeof(shreds_stored_sample)/sizeof(shreds_stored_sample[0])) ] = (ulong)diff_tile( config, "rserve", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( GAUGE, RSERVE, SHREDS_CURRENT ) );
1471 0 : shreds_stored_samples_idx++;
1472 :
1473 0 : rserve_rps_valid_samples[ rserve_rps_valid_samples_idx%(sizeof(rserve_rps_valid_samples)/sizeof(rserve_rps_valid_samples[0])) ] = (ulong)(
1474 0 : diff_tile( config, "rserve", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, RSERVE, SENT_RESPONSE_TYPES_PING ) ) +
1475 0 : diff_tile( config, "rserve", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, RSERVE, SENT_RESPONSE_TYPES_WINDOW ) ) +
1476 0 : diff_tile( config, "rserve", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, RSERVE, SENT_RESPONSE_TYPES_HIGHEST_WINDOW ) ) +
1477 0 : diff_tile( config, "rserve", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, RSERVE, SENT_RESPONSE_TYPES_ORPHAN ) ) );
1478 0 : rserve_rps_valid_samples_idx++;
1479 :
1480 0 : rserve_rps_invalid_samples[ rserve_rps_invalid_samples_idx%(sizeof(rserve_rps_invalid_samples)/sizeof(rserve_rps_invalid_samples[0])) ] = (ulong)(
1481 0 : diff_tile( config, "rserve", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, RSERVE, MISSED_RESPONSE_TYPES_PING ) ) +
1482 0 : diff_tile( config, "rserve", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, RSERVE, MISSED_RESPONSE_TYPES_WINDOW ) ) +
1483 0 : diff_tile( config, "rserve", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, RSERVE, MISSED_RESPONSE_TYPES_HIGHEST_WINDOW ) ) +
1484 0 : diff_tile( config, "rserve", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, RSERVE, MISSED_RESPONSE_TYPES_ORPHAN ) ) +
1485 0 : diff_tile( config, "rserve", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, RSERVE, FAILED_SIGVERIFY ) ) +
1486 0 : diff_tile( config, "rserve", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, RSERVE, FAILED_OWN_KEY ) ) +
1487 0 : diff_tile( config, "rserve", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, RSERVE, FAILED_INVALID_TOKEN ) ) +
1488 0 : diff_tile( config, "rserve", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, RSERVE, FAILED_NOT_FOR_US ) ) +
1489 0 : diff_tile( config, "rserve", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, RSERVE, FAILED_OUTDATED ) ) +
1490 0 : diff_tile( config, "rserve", tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, MIDX( COUNTER, RSERVE, FAILED_INVALID_SHRED_INDEX ) ) );
1491 0 : rserve_rps_invalid_samples_idx++;
1492 :
1493 : /* Move cursor to top of dashboard and overwrite in place.
1494 : All output is buffered and flushed in a single write() so
1495 : the terminal never renders a partially drawn frame. */
1496 0 : frame_len = 0UL;
1497 0 : PRINT( "\033[?25l" ); /* hide cursor during redraw */
1498 0 : if( FD_UNLIKELY( !ended_on_newline ) ) {
1499 0 : PRINT( "\033[%luA\r", lines_printed+1UL );
1500 0 : } else {
1501 0 : PRINT( "\033[%luA\r", lines_printed );
1502 0 : }
1503 0 : write_summary( config, node_info, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ, tiles+(1UL-last_snap)*tile_cnt*FD_METRICS_TOTAL_SZ, links+last_snap*(cons_cnt*8UL*FD_METRICS_ALL_LINK_IN_TOTAL), links+(1UL-last_snap)*(cons_cnt*8UL*FD_METRICS_ALL_LINK_IN_TOTAL), interposing );
1504 0 : PRINT( "\033[0J" ); /* clear any leftover lines below */
1505 0 : PRINT( "\033[?25h" ); /* show cursor */
1506 0 : flush_frame();
1507 0 : next += (long)1e7;
1508 0 : }
1509 0 : }
1510 0 : }
1511 :
1512 : void
1513 : watch_cmd_args( int * pargc FD_PARAM_UNUSED,
1514 : char *** pargv FD_PARAM_UNUSED,
1515 0 : args_t * args ) {
1516 0 : args->watch.drain_output_fd = -1;
1517 0 : }
1518 :
1519 : void
1520 : watch_cmd_fn( args_t * args,
1521 0 : config_t * config ) {
1522 0 : int allow_fds[ 5 ];
1523 0 : ulong allow_fds_cnt = 0;
1524 0 : allow_fds[ allow_fds_cnt++ ] = 0; /* stdin */
1525 0 : allow_fds[ allow_fds_cnt++ ] = 1; /* stdout */
1526 0 : allow_fds[ allow_fds_cnt++ ] = 2; /* stderr */
1527 0 : if( FD_LIKELY( fd_log_private_logfile_fd()!=-1 ) )
1528 0 : allow_fds[ allow_fds_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
1529 0 : if( FD_UNLIKELY( args->watch.drain_output_fd!=-1 ) )
1530 0 : allow_fds[ allow_fds_cnt++ ] = args->watch.drain_output_fd; /* maybe we are interposing firedancer log output with the monitor */
1531 :
1532 0 : fd_topo_join_workspaces( &config->topo, FD_SHMEM_JOIN_MODE_READ_ONLY, FD_TOPO_CORE_DUMP_LEVEL_DISABLED );
1533 :
1534 0 : struct sock_filter seccomp_filter[ 128UL ];
1535 0 : uint drain_output_fd = args->watch.drain_output_fd >= 0 ? (uint)args->watch.drain_output_fd : (uint)-1;
1536 0 : populate_sock_filter_policy_watch( 128UL, seccomp_filter, (uint)fd_log_private_logfile_fd(), drain_output_fd );
1537 :
1538 0 : if( FD_LIKELY( config->development.sandbox ) ) {
1539 0 : fd_sandbox_enter( config->uid,
1540 0 : config->gid,
1541 0 : 0,
1542 0 : 0,
1543 0 : 0,
1544 0 : 1, /* Keep controlling terminal for main so it can receive Ctrl+C */
1545 0 : 0,
1546 0 : 0UL,
1547 0 : 0UL,
1548 0 : 0UL,
1549 0 : 0UL,
1550 0 : allow_fds_cnt,
1551 0 : allow_fds,
1552 0 : sock_filter_policy_watch_instr_cnt,
1553 0 : seccomp_filter );
1554 0 : } else {
1555 0 : fd_sandbox_switch_uid_gid( config->uid, config->gid );
1556 0 : }
1557 :
1558 0 : fd_topo_fill( &config->topo );
1559 :
1560 0 : run( config, args->watch.drain_output_fd );
1561 0 : }
1562 :
1563 : action_t fd_action_watch = {
1564 : .name = "watch",
1565 : .args = watch_cmd_args,
1566 : .fn = watch_cmd_fn,
1567 : .require_config = 1,
1568 : .perm = watch_cmd_perm,
1569 : .description = "Watch a locally running Firedancer instance with a terminal GUI",
1570 : .detail = "Connects to a running validator and renders a terminal dashboard of the\n"
1571 : "most important monitoring and operational metrics.",
1572 : };
|