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 "../../../../util/tile/fd_tile.h"
8 :
9 : #include <errno.h>
10 : #include <unistd.h>
11 : #include <sys/resource.h>
12 : #include <linux/capability.h>
13 :
14 : void
15 : watch_cmd_perm( args_t * args FD_PARAM_UNUSED,
16 : fd_cap_chk_t * chk,
17 0 : config_t const * config ) {
18 0 : ulong mlock_limit = fd_topo_mlock( &config->topo );
19 :
20 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)`" );
21 :
22 0 : if( fd_sandbox_requires_cap_sys_admin( config->uid, config->gid ) )
23 0 : fd_cap_chk_cap( chk, "watch", CAP_SYS_ADMIN, "call `unshare(2)` with `CLONE_NEWUSER` to sandbox the process in a user namespace" );
24 0 : if( FD_LIKELY( getuid() != config->uid ) )
25 0 : fd_cap_chk_cap( chk, "watch", CAP_SETUID, "call `setresuid(2)` to switch uid to the sanbox user" );
26 0 : if( FD_LIKELY( getgid() != config->gid ) )
27 0 : fd_cap_chk_cap( chk, "watch", CAP_SETGID, "call `setresgid(2)` to switch gid to the sandbox user" );
28 0 : }
29 :
30 :
31 : static ulong lines_printed;
32 : static int ended_on_newline = 1;
33 :
34 : static char frame_buf[ 65536UL ];
35 : static ulong frame_len;
36 :
37 : static void
38 0 : flush_frame( void ) {
39 0 : ulong written = 0UL;
40 0 : while( written<frame_len ) {
41 0 : long w = write( STDOUT_FILENO, frame_buf+written, frame_len-written );
42 0 : if( FD_UNLIKELY( -1==w && errno==EAGAIN ) ) continue;
43 0 : else if( FD_UNLIKELY( -1==w ) ) FD_LOG_ERR(( "write() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
44 0 : else if( FD_UNLIKELY( 0==w ) ) break;
45 0 : written += (ulong)w;
46 0 : }
47 0 : frame_len = 0UL;
48 0 : }
49 :
50 : static int
51 0 : drain( int fd ) {
52 0 : int needs_reprint = 0;
53 :
54 0 : while( 1 ) {
55 0 : uchar buf[ 16384UL ];
56 0 : long result = read( fd, buf, sizeof(buf) );
57 0 : if( FD_UNLIKELY( -1==result && errno==EAGAIN ) ) break;
58 0 : else if( FD_UNLIKELY( -1==result ) ) FD_LOG_ERR(( "read() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
59 :
60 0 : if( FD_LIKELY( !needs_reprint ) ) {
61 : /* Buffer the erase sequence and first log chunk together so the
62 : terminal never renders a blank frame between erase and content. */
63 0 : frame_len = 0UL;
64 0 : if( FD_UNLIKELY( !ended_on_newline ) ) {
65 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 ) );
66 0 : } else {
67 0 : FD_TEST( fd_cstr_printf_check( frame_buf, sizeof(frame_buf), &frame_len, "\033[%luA\033[%luM\033[0J", lines_printed, lines_printed ) );
68 0 : }
69 0 : }
70 0 : FD_TEST( frame_len+(ulong)result<=sizeof(frame_buf) );
71 0 : fd_memcpy( frame_buf+frame_len, buf, (ulong)result );
72 0 : frame_len += (ulong)result;
73 0 : flush_frame();
74 0 : needs_reprint = 1;
75 :
76 0 : ended_on_newline = buf[ (ulong)result-1UL ]=='\n';
77 0 : }
78 :
79 0 : return needs_reprint;
80 0 : }
81 :
82 : static char *
83 : fmt_bytes( char * buf,
84 : ulong buf_sz,
85 0 : long bytes ) {
86 0 : char * tmp = fd_alloca_check( 1UL, buf_sz );
87 0 : if( FD_LIKELY( 8L*bytes<1000L ) ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%ld bits", 8L*bytes ) );
88 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 ) );
89 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 ) );
90 0 : else FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1f Gbit", (double)(8L*bytes)/1000000000.0 ) );
91 :
92 0 : FD_TEST( fd_cstr_printf_check( buf, buf_sz, NULL, "%10s", tmp ) );
93 0 : return buf;
94 0 : }
95 :
96 : static char *
97 : fmt_count( char * buf,
98 : ulong buf_sz,
99 0 : ulong count ) {
100 0 : char * tmp = fd_alloca_check( 1UL, buf_sz );
101 0 : if( FD_LIKELY( count<1000UL ) ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%lu", count ) );
102 0 : else if( FD_LIKELY( count<1000000UL ) ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1f K", (double)count/1000.0 ) );
103 0 : else if( FD_LIKELY( count<1000000000UL ) ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1f M", (double)count/1000000.0 ) );
104 :
105 0 : FD_TEST( fd_cstr_printf_check( buf, buf_sz, NULL, "%10s", tmp ) );
106 0 : return buf;
107 0 : }
108 :
109 : static char *
110 : fmt_countf( char * buf,
111 : ulong buf_sz,
112 0 : double count ) {
113 0 : char * tmp = fd_alloca_check( 1UL, buf_sz );
114 0 : if( FD_LIKELY( count<1000UL ) ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1f", count ) );
115 0 : else if( FD_LIKELY( count<1000000UL ) ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1f K", (double)count/1000.0 ) );
116 0 : else if( FD_LIKELY( count<1000000000UL ) ) FD_TEST( fd_cstr_printf_check( tmp, buf_sz, NULL, "%.1f M", (double)count/1000000.0 ) );
117 0 : else memcpy( tmp, "-", 2UL );
118 :
119 0 : FD_TEST( fd_cstr_printf_check( buf, buf_sz, NULL, "%10s", tmp ) );
120 0 : return buf;
121 0 : }
122 :
123 : static long
124 : diff_link( config_t const * config,
125 : char const * link_name,
126 : ulong const * prev_link,
127 : ulong const * cur_link,
128 0 : ulong idx ) {
129 0 : long result = 0L;
130 :
131 0 : ulong overall_polled_idx = 0UL;
132 0 : for( ulong i=0UL; i<config->topo.tile_cnt; i++ ) {
133 0 : fd_topo_tile_t const * tile = &config->topo.tiles[ i ];
134 0 : for( ulong j=0UL; j<config->topo.tiles[ i ].in_cnt; j++ ) {
135 0 : fd_topo_link_t const * link = &config->topo.links[ tile->in_link_id[ j ] ];
136 0 : if( FD_UNLIKELY( !tile->in_link_poll[ j ] ) ) continue;
137 :
138 0 : if( FD_LIKELY( !strcmp( link->name, link_name ) ) ) {
139 0 : result += (long)cur_link[ overall_polled_idx*8UL+idx ]-(long)prev_link[ overall_polled_idx*8UL+idx ];
140 0 : }
141 :
142 0 : overall_polled_idx++;
143 0 : }
144 0 : }
145 0 : return result;
146 0 : }
147 :
148 : static long
149 : diff_tile( config_t const * config,
150 : char const * tile_name,
151 : ulong const * prev_tile,
152 : ulong const * cur_tile,
153 0 : ulong idx ) {
154 0 : long result = 0L;
155 :
156 0 : for( ulong i=0UL; i<config->topo.tile_cnt; i++ ) {
157 0 : fd_topo_tile_t const * tile = &config->topo.tiles[ i ];
158 0 : if( FD_UNLIKELY( strcmp( tile->name, tile_name ) ) ) continue;
159 0 : result += (long)cur_tile[ i*FD_METRICS_TOTAL_SZ+idx ]-(long)prev_tile[ i*FD_METRICS_TOTAL_SZ+idx ];
160 0 : }
161 0 : return result;
162 0 : }
163 :
164 : static ulong
165 0 : total_crds( ulong const * metrics ) {
166 0 : ulong sum = 0UL;
167 0 : for( ulong i=0UL; i<FD_METRICS_ENUM_CRDS_VALUE_CNT; i++ ) {
168 0 : sum += metrics[ MIDX( GAUGE, GOSSIP, CRDS_COUNT_CONTACT_INFO_V1 )+i ];
169 0 : }
170 0 : return sum;
171 0 : }
172 :
173 : static ulong
174 0 : total_regime( ulong const * metrics ) {
175 0 : ulong sum = 0UL;
176 0 : for( ulong i=0UL; i<FD_METRICS_ENUM_TILE_REGIME_CNT; i++ ) {
177 0 : sum += metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS )+i ];
178 0 : }
179 0 : return sum;
180 0 : }
181 :
182 : static ulong tps_sent_samples_idx = 0UL;
183 : static ulong tps_sent_samples[ 200UL ];
184 : static ulong cups_samples_idx = 0UL;
185 : static ulong cups_samples[ 100UL ];
186 : static ulong sps_samples_idx = 0UL;
187 : static ulong sps_samples[ 200UL ];
188 : static ulong tps_samples_idx = 0UL;
189 : static ulong tps_samples[ 200UL ];
190 : static ulong snapshot_rx_idx = 0UL;
191 : static ulong snapshot_rx_samples[ 100UL ];
192 : static ulong snapshot_acc_idx = 0UL;
193 : static ulong snapshot_acc_samples[ 100UL ];
194 : static ulong events_sent_samples_idx = 0UL;
195 : static ulong events_sent_samples[ 100UL ];
196 : static ulong events_acked_samples_idx = 0UL;
197 : static ulong events_acked_samples[ 100UL ];
198 : static ulong event_bytes_written_samples_idx = 0UL;
199 : static ulong event_bytes_written_samples[ 100UL ];
200 : static ulong event_bytes_read_samples_idx = 0UL;
201 : static ulong event_bytes_read_samples[ 100UL ];
202 : static ulong rps_samples_idx = 0UL;
203 : static ulong rps_samples[ 100UL ];
204 :
205 : #define RESET "\033[0m"
206 : #define BOLD "\033[1m"
207 : #define UNBOLD "\033[22m"
208 :
209 : #define RED "\033[31m"
210 : #define GREEN "\033[32m"
211 : #define YELLOW "\033[33m"
212 : #define BLUE "\033[34m"
213 : #define MAGENTA "\033[35m"
214 : #define CYAN "\033[36m"
215 :
216 : #define BGREEN "\033[92m"
217 : #define BYELLOW "\033[93m"
218 :
219 : #define CLEARLN "\033[K"
220 :
221 0 : #define PRINT(...) do { \
222 0 : ulong _len; \
223 0 : FD_TEST( fd_cstr_printf_check( frame_buf+frame_len, sizeof(frame_buf)-frame_len, &_len, __VA_ARGS__ ) ); \
224 0 : frame_len += _len; \
225 0 : } while(0)
226 :
227 : #define DIFF_LINK_BYTES( link_name, metric_type, metric_subtype, metric ) (__extension__({ \
228 : long bytes = diff_link( config, link_name, prev_link, cur_link, MIDX( metric_type, metric_subtype, metric ) ); \
229 : fmt_bytes( fd_alloca_check( 1UL, 64UL ), 64UL, bytes ); \
230 : }))
231 :
232 : #define DIFF_BYTES( tile_name, metric_type, metric_subtype, metric ) (__extension__({ \
233 : long bytes = diff_tile( config, tile_name, prev_tile, cur_tile, MIDX( metric_type, metric_subtype, metric ) ); \
234 : fmt_bytes( fd_alloca_check( 1UL, 64UL ), 64UL, bytes ); \
235 : }))
236 :
237 0 : #define COUNT( count ) (__extension__({ \
238 0 : fmt_count( fd_alloca_check( 1UL, 64UL ), 64UL, count ); \
239 0 : }))
240 :
241 0 : #define COUNTF( count ) (__extension__({ \
242 0 : fmt_countf( fd_alloca_check( 1UL, 64UL ), 64UL, count ); \
243 0 : }))
244 :
245 : static int
246 : write_bench( config_t const * config,
247 : ulong const * cur_tile,
248 0 : ulong const * prev_tile ) {
249 0 : if( FD_UNLIKELY( fd_topo_find_tile( &config->topo, "benchs", 0UL )==ULONG_MAX ) ) return 0;
250 :
251 0 : ulong tps_sum = 0UL;
252 0 : ulong num_tps_samples = fd_ulong_min( tps_sent_samples_idx, sizeof(tps_sent_samples)/sizeof(tps_sent_samples[0]));
253 0 : for( ulong i=0UL; i<num_tps_samples; i++ ) tps_sum += tps_sent_samples[ i ];
254 0 : char * tps_str = COUNTF( 100.0*(double)tps_sum/(double)num_tps_samples );
255 :
256 0 : PRINT( "๐ถ " BOLD BGREEN "BENCH......." RESET UNBOLD
257 0 : " " BOLD "GENERATED TPS" UNBOLD " %s"
258 0 : " " BOLD "BENCHG BUSY" UNBOLD, tps_str );
259 0 : for( ulong i=0UL; i<config->topo.tile_cnt; i++ ) {
260 0 : if( FD_LIKELY( strcmp( config->topo.tiles[ i ].name, "benchg" ) ) ) continue;
261 :
262 0 : ulong total_ticks = total_regime( &cur_tile[ i*FD_METRICS_TOTAL_SZ ] )-total_regime( &prev_tile[ i*FD_METRICS_TOTAL_SZ ] );
263 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;
264 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;
265 0 : double busy_pct = 100.0 - idle_pct - backp_pct;
266 :
267 0 : PRINT( " %.1f %%", busy_pct );
268 0 : }
269 :
270 0 : PRINT( " " BOLD "BENCHS BUSY" UNBOLD );
271 0 : for( ulong i=0UL; i<config->topo.tile_cnt; i++ ) {
272 0 : if( FD_LIKELY( strcmp( config->topo.tiles[ i ].name, "benchs" ) ) ) continue;
273 :
274 0 : ulong total_ticks = total_regime( &cur_tile[ i*FD_METRICS_TOTAL_SZ ] )-total_regime( &prev_tile[ i*FD_METRICS_TOTAL_SZ ] );
275 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;
276 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;
277 0 : double busy_pct = 100.0 - idle_pct - backp_pct;
278 :
279 0 : PRINT( " %.1f %%", busy_pct );
280 0 : }
281 :
282 0 : PRINT( CLEARLN "\n" );
283 0 : return 1;
284 0 : }
285 :
286 : static void
287 : write_backtest( config_t const * config,
288 0 : ulong const * cur_tile ) {
289 0 : ulong backt_idx = fd_topo_find_tile( &config->topo, "backt", 0UL );
290 0 : ulong start_slot = cur_tile[ backt_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, BACKT, START_SLOT ) ];
291 0 : ulong final_slot = cur_tile[ backt_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, BACKT, FINAL_SLOT ) ];
292 :
293 0 : ulong replay_idx = fd_topo_find_tile( &config->topo, "replay", 0UL );
294 0 : ulong current_slot = cur_tile[ replay_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, REPLAY, ROOT_SLOT ) ];
295 0 : current_slot = current_slot ? current_slot : start_slot;
296 :
297 0 : ulong total_slots = final_slot-start_slot;
298 0 : ulong completed_slots = current_slot-start_slot;
299 :
300 0 : double progress = 0.0;
301 0 : if( FD_LIKELY( total_slots>0UL ) ) progress = 100.0 * (double)completed_slots / (double)total_slots;
302 0 : else progress = 100.0;
303 :
304 0 : PRINT( "๐งช " BOLD BGREEN "BACKTEST...." RESET UNBOLD
305 0 : " " BOLD "PCT" UNBOLD " %.1f %% (%lu/%lu)" CLEARLN "\n",
306 0 : progress, completed_slots, total_slots );
307 0 : }
308 :
309 : static void
310 : write_snapshots( config_t const * config,
311 : ulong const * cur_tile,
312 0 : ulong const * prev_tile ) {
313 0 : ulong snapct_idx = fd_topo_find_tile( &config->topo, "snapct", 0UL );
314 0 : ulong state = cur_tile[ snapct_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, SNAPCT, STATE ) ];
315 :
316 0 : ulong bytes_read = cur_tile[ snapct_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, SNAPCT, FULL_BYTES_READ ) ];
317 0 : ulong bytes_total = cur_tile[ snapct_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, SNAPCT, FULL_BYTES_TOTAL ) ];
318 :
319 0 : double progress = 0.0;
320 0 : switch( state ) {
321 0 : case FD_SNAPCT_STATE_WAITING_FOR_PEERS:
322 0 : case FD_SNAPCT_STATE_WAITING_FOR_PEERS_INCREMENTAL:
323 0 : case FD_SNAPCT_STATE_COLLECTING_PEERS:
324 0 : case FD_SNAPCT_STATE_COLLECTING_PEERS_INCREMENTAL:
325 0 : break;
326 0 : case FD_SNAPCT_STATE_READING_FULL_FILE:
327 0 : case FD_SNAPCT_STATE_FLUSHING_FULL_FILE_FINI:
328 0 : case FD_SNAPCT_STATE_FLUSHING_FULL_FILE_DONE:
329 0 : case FD_SNAPCT_STATE_READING_INCREMENTAL_FILE:
330 0 : case FD_SNAPCT_STATE_FLUSHING_INCREMENTAL_FILE_FINI:
331 0 : case FD_SNAPCT_STATE_FLUSHING_INCREMENTAL_FILE_DONE:
332 0 : case FD_SNAPCT_STATE_READING_FULL_HTTP:
333 0 : case FD_SNAPCT_STATE_FLUSHING_FULL_HTTP_FINI:
334 0 : case FD_SNAPCT_STATE_FLUSHING_FULL_HTTP_DONE:
335 0 : case FD_SNAPCT_STATE_READING_INCREMENTAL_HTTP:
336 0 : case FD_SNAPCT_STATE_FLUSHING_INCREMENTAL_HTTP_FINI:
337 0 : case FD_SNAPCT_STATE_FLUSHING_INCREMENTAL_HTTP_DONE:
338 0 : if( FD_LIKELY( bytes_total>0UL ) ) progress = 100.0 * (double)bytes_read / (double)bytes_total;
339 0 : break;
340 0 : case FD_SNAPCT_STATE_SHUTDOWN:
341 0 : progress = 100.0;
342 0 : break;
343 0 : }
344 :
345 0 : ulong snap_rx_sum = 0UL;
346 0 : ulong num_snap_rx_samples = fd_ulong_min( snapshot_rx_idx, sizeof(snapshot_rx_samples)/sizeof(snapshot_rx_samples[0]) );
347 0 : for( ulong i=0UL; i<num_snap_rx_samples; i++ ) snap_rx_sum += snapshot_rx_samples[ i ];
348 0 : double megabytes_per_second = 0.0;
349 0 : if( FD_LIKELY( num_snap_rx_samples ) ) megabytes_per_second = 100.0*(double)snap_rx_sum/(double)num_snap_rx_samples/1e6;
350 :
351 0 : ulong accounts_sum = 0UL;
352 0 : ulong num_accounts_samples = fd_ulong_min( snapshot_acc_idx, sizeof(snapshot_acc_samples)/sizeof(snapshot_acc_samples[0]) );
353 0 : for( ulong i=0UL; i<num_accounts_samples; i++ ) accounts_sum += snapshot_acc_samples[ i ];
354 0 : double million_accounts_per_second = 0.0;
355 0 : if( FD_LIKELY( num_accounts_samples ) ) million_accounts_per_second = 100.0*(double)accounts_sum/(double)num_accounts_samples/1e6;
356 :
357 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 ] );
358 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 ] );
359 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 ] );
360 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 ] );
361 0 : ulong snapls_tile_idx = fd_topo_find_tile( &config->topo, "snapls", 0UL );
362 0 : ulong snapls_total_ticks = snapls_tile_idx!=ULONG_MAX ? total_regime( &cur_tile[ snapls_tile_idx*FD_METRICS_TOTAL_SZ ] )-total_regime( &prev_tile[ snapls_tile_idx*FD_METRICS_TOTAL_SZ ] ) : 0UL;
363 0 : snapct_total_ticks = fd_ulong_max( snapct_total_ticks, 1UL );
364 0 : snapld_total_ticks = fd_ulong_max( snapld_total_ticks, 1UL );
365 0 : snapdc_total_ticks = fd_ulong_max( snapdc_total_ticks, 1UL );
366 0 : snapin_total_ticks = fd_ulong_max( snapin_total_ticks, 1UL );
367 0 : snapls_total_ticks = fd_ulong_max( snapls_total_ticks, 1UL );
368 :
369 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;
370 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;
371 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;
372 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;
373 0 : double snapls_backp_pct = snapls_tile_idx!=ULONG_MAX ? 100.0*(double)diff_tile( config, "snapls", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) )/(double)snapls_total_ticks : 0.0;
374 :
375 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;
376 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;
377 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;
378 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;
379 0 : double snapls_idle_pct = snapls_tile_idx!=ULONG_MAX ? 100.0*(double)diff_tile( config, "snapls", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG ) )/(double)snapls_total_ticks : 0.0;
380 :
381 0 : if( FD_UNLIKELY( snapls_tile_idx!=ULONG_MAX ) ) {
382 0 : PRINT( "โก " BOLD BYELLOW "SNAPSHOTS..." RESET UNBOLD
383 0 : " " BOLD "STATE" UNBOLD " %s"
384 0 : " " BOLD "PCT" UNBOLD " %.1f %%"
385 0 : " " BOLD "RX" UNBOLD " %3.f MB/s"
386 0 : " " BOLD "ACC" UNBOLD " %3.1f M/s"
387 0 : " " BOLD "BACKP" UNBOLD " %3.0f%%,%3.0f%%,%3.0f%%,%3.0f%%,%3.0f%%"
388 0 : " " BOLD "BUSY" UNBOLD " %3.0f%%,%3.0f%%,%3.0f%%,%3.0f%%,%3.0f%%" CLEARLN "\n",
389 0 : fd_snapct_state_str( state ),
390 0 : progress,
391 0 : megabytes_per_second,
392 0 : million_accounts_per_second,
393 0 : snapct_backp_pct,
394 0 : snapld_backp_pct,
395 0 : snapdc_backp_pct,
396 0 : snapin_backp_pct,
397 0 : snapls_backp_pct,
398 0 : 100.0-snapct_idle_pct-snapct_backp_pct,
399 0 : 100.0-snapld_idle_pct-snapld_backp_pct,
400 0 : 100.0-snapdc_idle_pct-snapdc_backp_pct,
401 0 : 100.0-snapin_idle_pct-snapin_backp_pct,
402 0 : 100.0-snapls_idle_pct );
403 0 : } else {
404 0 : PRINT( "โก " BOLD BYELLOW "SNAPSHOTS..." RESET UNBOLD
405 0 : " " BOLD "STATE" UNBOLD " %s"
406 0 : " " BOLD "PCT" UNBOLD " %.1f %%"
407 0 : " " BOLD "RX" UNBOLD " %3.f MB/s"
408 0 : " " BOLD "ACC" UNBOLD " %3.1f M/s"
409 0 : " " BOLD "BACKP" UNBOLD " %3.0f%%,%3.0f%%,%3.0f%%,%3.0f%%"
410 0 : " " BOLD "BUSY" UNBOLD " %3.0f%%,%3.0f%%,%3.0f%%,%3.0f%%" CLEARLN "\n",
411 0 : fd_snapct_state_str( state ),
412 0 : progress,
413 0 : megabytes_per_second,
414 0 : million_accounts_per_second,
415 0 : snapct_backp_pct,
416 0 : snapld_backp_pct,
417 0 : snapdc_backp_pct,
418 0 : snapin_backp_pct,
419 0 : 100.0-snapct_idle_pct-snapct_backp_pct,
420 0 : 100.0-snapld_idle_pct-snapld_backp_pct,
421 0 : 100.0-snapdc_idle_pct-snapdc_backp_pct,
422 0 : 100.0-snapin_idle_pct-snapin_backp_pct );
423 0 : }
424 0 : }
425 :
426 : static uint
427 : write_accdb( config_t const * config,
428 0 : ulong const * cur_tile ) {
429 0 : ulong accdb_tile_idx = fd_topo_find_tile( &config->topo, "accdb", 0UL );
430 0 : ulong snapwm_tile_idx = fd_topo_find_tile( &config->topo, "snapwm", 0UL );
431 0 : ulong snapwr_tile_idx = fd_topo_find_tile( &config->topo, "snapwr", 0UL );
432 0 : if( accdb_tile_idx ==ULONG_MAX ) return 0U;
433 0 : if( snapwm_tile_idx==ULONG_MAX ) return 0U;
434 0 : if( snapwr_tile_idx==ULONG_MAX ) return 0U;
435 :
436 0 : ulong snapwr_state = cur_tile[ snapwr_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, SNAPWR, STATE ) ];
437 0 : ulong used_bytes = cur_tile[ snapwr_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, SNAPWR, FILE_USED_BYTES ) ];
438 0 : ulong cap_bytes = cur_tile[ snapwr_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, SNAPWR, FILE_CAPACITY_BYTES ) ];
439 0 : ulong acct_cnt = cur_tile[ snapwm_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, SNAPWM, ACCOUNTS_ACTIVE ) ];
440 0 : if( snapwr_state==4 ) {
441 0 : used_bytes = cur_tile[ accdb_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, ACCDB, FILE_USED_BYTES ) ];
442 0 : cap_bytes = cur_tile[ accdb_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, ACCDB, FILE_CAPACITY_BYTES ) ];
443 0 : acct_cnt = cur_tile[ accdb_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, ACCDB, ACCOUNTS ) ];
444 0 : }
445 :
446 0 : double data_pct = 100.0*(double)used_bytes/(double)cap_bytes;
447 0 : double used_gb = (double)used_bytes/1e9;
448 0 : double index_pct = 100.0*(double)acct_cnt/(double)config->firedancer.accounts.max_accounts;
449 :
450 0 : ulong rps_sum = 0UL;
451 0 : ulong num_rps_samples = fd_ulong_min( rps_samples_idx, sizeof(rps_samples)/sizeof(rps_samples[0]) );
452 0 : for( ulong i=0UL; i<num_rps_samples; i++ ) rps_sum += rps_samples[ i ];
453 0 : char * rps_str = COUNTF( 100.0*(double)rps_sum/(double)num_rps_samples );
454 :
455 0 : PRINT( "๐พ " BOLD GREEN "ACCOUNTS...." RESET UNBOLD
456 0 : " " BOLD "DATA" UNBOLD " %4.1f%% (%.1f GB) "
457 0 : " " BOLD "INDEX" UNBOLD " %4.1f%% (%.1fM) "
458 0 : " " BOLD "RPS" UNBOLD " %s" CLEARLN "\n",
459 0 : data_pct, used_gb, index_pct, (double)acct_cnt/1e6, rps_str );
460 0 : return 1;
461 0 : }
462 :
463 : static uint
464 : write_wfs( config_t const * config,
465 0 : ulong const * cur_tile ) {
466 0 : ulong gossip_tile_idx = fd_topo_find_tile( &config->topo, "gossip", 0UL );
467 0 : if( FD_UNLIKELY( gossip_tile_idx==ULONG_MAX ) ) return 0U;
468 :
469 0 : int wfs_state = (int)cur_tile[ gossip_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, GOSSIP, WFS_STATE ) ];
470 0 : if( FD_LIKELY( wfs_state==FD_GOSSIP_WFS_STATE_DONE ) ) return 0U;
471 :
472 0 : char const * state_str;
473 0 : switch( wfs_state ) {
474 0 : case FD_GOSSIP_WFS_STATE_INIT: state_str = "loading snapshot"; break;
475 0 : case FD_GOSSIP_WFS_STATE_WAIT: state_str = "waiting"; break;
476 0 : case FD_GOSSIP_WFS_STATE_PUBLISH: state_str = "starting"; break;
477 0 : default: return 0U;
478 0 : }
479 :
480 0 : ulong _stake_online = cur_tile[ gossip_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, GOSSIP, WFS_STAKE_ONLINE ) ];
481 0 : ulong _stake_total = cur_tile[ gossip_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, GOSSIP, WFS_STAKE_TOTAL ) ];
482 0 : ulong peers_online = cur_tile[ gossip_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, GOSSIP, WFS_STAKED_PEERS_ONLINE ) ];
483 0 : ulong peers_total = cur_tile[ gossip_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, GOSSIP, WFS_STAKED_PEERS_TOTAL ) ];
484 :
485 0 : ulong ipecho_tile_idx = fd_topo_find_tile( &config->topo, "ipecho", 0UL );
486 0 : ulong shred_ver = 0UL;
487 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 ) ];
488 :
489 0 : double stake_pct = _stake_total>0UL ? 100.0*(double)_stake_online/(double)_stake_total : 0.0;
490 0 : double stake_div = (_stake_total<(ulong)1e14) ? 1e9 : 1e15;
491 0 : char const * stake_unit = (_stake_total<(ulong)1e14) ? " SOL" : "M";
492 0 : double stake_online = (double)_stake_online / stake_div;
493 0 : double stake_total = (double)_stake_total / stake_div;
494 :
495 0 : PRINT( "โณ " BOLD YELLOW "CLUSTER BOOT" RESET UNBOLD
496 0 : " " BOLD "STATE" UNBOLD " %s"
497 0 : " " BOLD "STAKE" UNBOLD " %3.0f%% (%.1f%s / %.1f%s)"
498 0 : " " BOLD "SHRED VERSION" UNBOLD " %lu"
499 0 : " " BOLD "PEERS" UNBOLD " %lu online %lu offline"
500 0 : " " BOLD "BANK HASH" UNBOLD " %s" CLEARLN "\n",
501 0 : state_str,
502 0 : stake_pct,
503 0 : stake_online,
504 0 : stake_unit,
505 0 : stake_total,
506 0 : stake_unit,
507 0 : shred_ver,
508 0 : peers_online,
509 0 : peers_total>peers_online ? peers_total-peers_online : 0UL,
510 0 : config->firedancer.consensus.wait_for_supermajority_with_bank_hash );
511 0 : return 1U;
512 0 : }
513 :
514 : static uint
515 : write_gossip( config_t const * config,
516 : ulong const * cur_tile,
517 : ulong const * prev_tile,
518 : ulong const * cur_link,
519 0 : ulong const * prev_link ) {
520 0 : ulong gossip_tile_idx = fd_topo_find_tile( &config->topo, "gossip", 0UL );
521 0 : if( gossip_tile_idx==ULONG_MAX ) return 0U;
522 0 : char * contact_info = COUNT( cur_tile[ gossip_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, GOSSIP, CRDS_COUNT_CONTACT_INFO_V2 ) ] );
523 :
524 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 ] );
525 0 : gossip_total_ticks = fd_ulong_max( gossip_total_ticks, 1UL );
526 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;
527 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;
528 0 : double gossip_busy_pct = 100.0 - gossip_backp_pct - gossip_idle_pct;
529 :
530 0 : PRINT( "๐ฌ " BOLD BLUE "GOSSIP......" RESET UNBOLD
531 0 : " " BOLD "RX" UNBOLD " %s"
532 0 : " " BOLD "TX" UNBOLD " %s"
533 0 : " " BOLD "CRDS" UNBOLD " %s"
534 0 : " " BOLD "PEERS" UNBOLD " %s"
535 0 : " " BOLD "BUSY" UNBOLD " %3.0f%%"
536 0 : " " BOLD "BACKP" UNBOLD " %3.0f%%" CLEARLN "\n",
537 0 : DIFF_LINK_BYTES( "net_gossvf", COUNTER, LINK, CONSUMED_SIZE_BYTES ),
538 0 : DIFF_LINK_BYTES( "gossip_net", COUNTER, LINK, CONSUMED_SIZE_BYTES ),
539 0 : COUNT( total_crds( &cur_tile[ fd_topo_find_tile( &config->topo, "gossip", 0UL )*FD_METRICS_TOTAL_SZ ] ) ),
540 0 : contact_info,
541 0 : gossip_busy_pct,
542 0 : gossip_backp_pct );
543 0 : return 1U;
544 0 : }
545 :
546 : static uint
547 : write_repair( config_t const * config,
548 : ulong const * cur_tile,
549 : ulong const * cur_link,
550 0 : ulong const * prev_link ) {
551 0 : ulong repair_tile_idx = fd_topo_find_tile( &config->topo, "repair", 0UL );
552 0 : if( repair_tile_idx==ULONG_MAX ) return 0U;
553 0 : ulong repair_slot = cur_tile[ repair_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( COUNTER, REPAIR, REPAIRED_SLOTS ) ];
554 0 : ulong turbine_slot = cur_tile[ repair_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( COUNTER, REPAIR, CURRENT_SLOT ) ];
555 0 : PRINT( "๐งฑ " BOLD RED "REPAIR......" RESET UNBOLD
556 0 : " " BOLD "RX" UNBOLD " %s"
557 0 : " " BOLD "TX" UNBOLD " %s"
558 0 : " " BOLD "REPAIR SLOT" UNBOLD " %lu (%02ld)"
559 0 : " " BOLD "TURBINE SLOT" UNBOLD " %lu" CLEARLN "\n",
560 0 : DIFF_LINK_BYTES( "net_repair", COUNTER, LINK, CONSUMED_SIZE_BYTES ),
561 0 : DIFF_LINK_BYTES( "repair_net", COUNTER, LINK, CONSUMED_SIZE_BYTES ),
562 0 : repair_slot,
563 0 : (long)repair_slot-(long)turbine_slot,
564 0 : turbine_slot );
565 0 : return 1U;
566 0 : }
567 :
568 : static uint
569 : write_replay( config_t const * config,
570 0 : ulong const * cur_tile ) {
571 0 : ulong repair_tile_idx = fd_topo_find_tile( &config->topo, "repair", 0UL );
572 0 : ulong replay_tile_idx = fd_topo_find_tile( &config->topo, "replay", 0UL );
573 0 : if( replay_tile_idx==ULONG_MAX ) return 0U;
574 :
575 0 : ulong reset_slot = cur_tile[ replay_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, REPLAY, RESET_SLOT ) ];
576 0 : ulong next_leader_slot = cur_tile[ replay_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, REPLAY, NEXT_LEADER_SLOT ) ];
577 0 : ulong leader_slot = cur_tile[ replay_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, REPLAY, LEADER_SLOT ) ];
578 0 : char * next_leader_slot_str = fd_alloca_check( 1UL, 64UL );
579 :
580 0 : ulong turbine_slot;
581 0 : if( repair_tile_idx!=ULONG_MAX ) {
582 0 : turbine_slot = cur_tile[ repair_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( COUNTER, REPAIR, CURRENT_SLOT ) ];
583 0 : } else {
584 0 : turbine_slot = reset_slot;
585 0 : }
586 :
587 0 : ulong slot_in_seconds = (ulong)((double)(next_leader_slot-reset_slot)*0.4);
588 0 : if( FD_UNLIKELY( leader_slot ) ) FD_TEST( fd_cstr_printf_check( next_leader_slot_str, 64UL, NULL, "now" ) );
589 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 ) );
590 0 : else FD_TEST( fd_cstr_printf_check( next_leader_slot_str, 64UL, NULL, "never" ) );
591 :
592 0 : ulong root_distance = cur_tile[ replay_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, REPLAY, ROOT_DISTANCE ) ];
593 0 : ulong live_banks = cur_tile[ replay_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, REPLAY, LIVE_BANKS ) ];
594 :
595 0 : ulong sps_sum = 0UL;
596 0 : ulong num_sps_samples = fd_ulong_min( sps_samples_idx, sizeof(sps_samples)/sizeof(sps_samples[0]));
597 0 : for( ulong i=0UL; i<num_sps_samples; i++ ) sps_sum += sps_samples[ i ];
598 0 : char * sps_str = COUNTF( 100.0*(double)sps_sum/(double)num_sps_samples );
599 :
600 0 : ulong tps_sum = 0UL;
601 0 : ulong num_tps_samples = fd_ulong_min( tps_samples_idx, sizeof(tps_samples)/sizeof(tps_samples[0]));
602 0 : for( ulong i=0UL; i<num_tps_samples; i++ ) tps_sum += tps_samples[ i ];
603 0 : char * tps_str = COUNTF( 100.0*(double)tps_sum/(double)num_tps_samples );
604 :
605 0 : ulong cups_sum = 0UL;
606 0 : ulong num_cups_samples = fd_ulong_min( cups_samples_idx, sizeof(cups_samples)/sizeof(cups_samples[0]));
607 0 : for( ulong i=0UL; i<num_cups_samples; i++ ) cups_sum += cups_samples[ i ];
608 0 : char * mcups_str = COUNTF( 100.0*(double)cups_sum/(double)num_cups_samples );
609 :
610 0 : PRINT( "๐ฅ " BOLD MAGENTA "REPLAY......" RESET UNBOLD
611 0 : " " BOLD "SLOT" UNBOLD " %lu (%02ld)"
612 0 : " " BOLD "CU/s" UNBOLD " %s"
613 0 : " " BOLD "TPS" UNBOLD " %s"
614 0 : " " BOLD "SPS" UNBOLD " %s"
615 0 : " " BOLD "LEADER IN" UNBOLD " %s"
616 0 : " " BOLD "ROOT DIST" UNBOLD " %lu"
617 0 : " " BOLD "BANKS" UNBOLD " %2lu" CLEARLN "\n",
618 0 : reset_slot,
619 0 : (long)reset_slot-(long)turbine_slot,
620 0 : mcups_str,
621 0 : tps_str,
622 0 : sps_str,
623 0 : next_leader_slot_str,
624 0 : root_distance,
625 0 : live_banks );
626 0 : return 1U;
627 0 : }
628 :
629 : static uint
630 : write_gui( config_t const * config,
631 : ulong const * cur_tile,
632 0 : ulong const * prev_tile ) {
633 0 : (void)cur_tile;
634 :
635 0 : ulong gui_tile_idx = fd_topo_find_tile( &config->topo, "gui", 0UL );
636 0 : if( gui_tile_idx==ULONG_MAX ) return 0U;
637 :
638 0 : ulong connection_count = cur_tile[ gui_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, GUI, CONNECTION_COUNT ) ]+
639 0 : cur_tile[ gui_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, GUI, WEBSOCKET_CONNECTION_COUNT ) ];
640 :
641 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 ] );
642 0 : gui_total_ticks = fd_ulong_max( gui_total_ticks, 1UL );
643 0 : double gui_backp_pct = 100.0*(double)diff_tile( config, "gui", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) )/(double)gui_total_ticks;
644 0 : double gui_idle_pct = 100.0*(double)diff_tile( config, "gui", prev_tile, cur_tile, MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG ) )/(double)gui_total_ticks;
645 0 : double gui_busy_pct = 100.0 - gui_backp_pct - gui_idle_pct;
646 :
647 0 : long sent_frame_count = diff_tile( config, "gui", prev_tile, cur_tile, MIDX( COUNTER, GUI, WEBSOCKET_FRAMES_SENT ) );
648 0 : char * sent_frame_count_s = COUNT( (ulong)sent_frame_count );
649 0 : long received_frame_count = diff_tile( config, "gui", prev_tile, cur_tile, MIDX( COUNTER, GUI, WEBSOCKET_FRAMES_RECEIVED ) );
650 :
651 0 : PRINT( "๐ " BOLD CYAN "GUI........." RESET UNBOLD
652 0 : " " BOLD "CONNS" UNBOLD " %lu"
653 0 : " " BOLD "FRAMES" UNBOLD " %s in %s out"
654 0 : " " BOLD "BW" UNBOLD " %s in %s out"
655 0 : " " BOLD "BUSY" UNBOLD " %3.0f%% " CLEARLN "\n",
656 0 : connection_count,
657 0 : COUNT( (ulong)received_frame_count ),
658 0 : sent_frame_count_s,
659 0 : DIFF_BYTES( "gui", COUNTER, GUI, BYTES_READ ),
660 0 : DIFF_BYTES( "gui", COUNTER, GUI, BYTES_WRITTEN ),
661 0 : gui_busy_pct );
662 0 : return 1U;
663 0 : }
664 :
665 : static uint
666 : write_event( config_t const * config,
667 0 : ulong const * cur_tile ) {
668 0 : ulong event_tile_idx = fd_topo_find_tile( &config->topo, "event", 0UL );
669 0 : if( event_tile_idx==ULONG_MAX ) return 0U;
670 :
671 0 : ulong connection_state = cur_tile[ event_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, EVENT, CONNECTION_STATE ) ];
672 0 : char const * connection_state_str;
673 0 : switch( connection_state ) {
674 0 : case 0UL: connection_state_str = "disconnected"; break;
675 0 : case 1UL: connection_state_str = "connecting"; break;
676 0 : case 2UL: connection_state_str = "authenticating"; break;
677 0 : case 3UL: connection_state_str = "confirming_auth"; break;
678 0 : case 4UL: connection_state_str = "connected"; break;
679 0 : default: connection_state_str = "unknown"; break;
680 0 : }
681 :
682 0 : ulong event_queue_count = cur_tile[ event_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, EVENT, EVENT_QUEUE_COUNT ) ];
683 0 : ulong event_queue_drops = cur_tile[ event_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( COUNTER, EVENT, EVENT_QUEUE_DROPS ) ];
684 0 : ulong event_queue_bytes_used = cur_tile[ event_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, EVENT, EVENT_QUEUE_BYTES_USED ) ];
685 0 : ulong event_queue_bytes_capacity = cur_tile[ event_tile_idx*FD_METRICS_TOTAL_SZ+MIDX( GAUGE, EVENT, EVENT_QUEUE_BYTES_CAPACITY ) ];
686 :
687 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;
688 :
689 0 : ulong events_sent_sum = 0UL;
690 0 : ulong num_events_sent_samples = fd_ulong_min( events_sent_samples_idx, sizeof(events_sent_samples)/sizeof(events_sent_samples[0]));
691 0 : for( ulong i=0UL; i<num_events_sent_samples; i++ ) events_sent_sum += events_sent_samples[ i ];
692 0 : char * events_sent_str = COUNTF( 100.0*(double)events_sent_sum/(double)num_events_sent_samples );
693 :
694 0 : ulong events_acked_sum = 0UL;
695 0 : ulong num_events_acked_samples = fd_ulong_min( events_acked_samples_idx, sizeof(events_acked_samples)/sizeof(events_acked_samples[0]));
696 0 : for( ulong i=0UL; i<num_events_acked_samples; i++ ) events_acked_sum += events_acked_samples[ i ];
697 0 : char * events_acked_str = COUNTF( 100.0*(double)events_acked_sum/(double)num_events_acked_samples );
698 :
699 0 : ulong bytes_written_sum = 0UL;
700 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]));
701 0 : for( ulong i=0UL; i<num_bytes_written_samples; i++ ) bytes_written_sum += event_bytes_written_samples[ i ];
702 0 : long bytes_written_per_sec = (long)(100.0*(double)bytes_written_sum/(double)num_bytes_written_samples);
703 0 : char * bytes_written_str = fmt_bytes( fd_alloca_check( 1UL, 64UL ), 64UL, bytes_written_per_sec );
704 :
705 0 : ulong bytes_read_sum = 0UL;
706 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]));
707 0 : for( ulong i=0UL; i<num_bytes_read_samples; i++ ) bytes_read_sum += event_bytes_read_samples[ i ];
708 0 : long bytes_read_per_sec = (long)(100.0*(double)bytes_read_sum/(double)num_bytes_read_samples);
709 0 : char * bytes_read_str = fmt_bytes( fd_alloca_check( 1UL, 64UL ), 64UL, bytes_read_per_sec );
710 :
711 0 : char * event_queue_count_s = COUNT( event_queue_count );
712 :
713 0 : PRINT( "๐ก " BOLD YELLOW "EVENT......." RESET UNBOLD
714 0 : " " BOLD "STATE" UNBOLD " %12s"
715 0 : " " BOLD "QUEUE" UNBOLD " %s"
716 0 : " " BOLD "SENT" UNBOLD " %s /s"
717 0 : " " BOLD "ACKED" UNBOLD " %s /s"
718 0 : " " BOLD "BW" UNBOLD " %s in %s out"
719 0 : " " BOLD "DROPS" UNBOLD " %s"
720 0 : " " BOLD "FULL" UNBOLD " %3.0f%%" CLEARLN "\n",
721 0 : connection_state_str,
722 0 : event_queue_count_s,
723 0 : events_sent_str,
724 0 : events_acked_str,
725 0 : bytes_read_str,
726 0 : bytes_written_str,
727 0 : COUNT( event_queue_drops ),
728 0 : event_queue_pct_full );
729 0 : return 1U;
730 0 : }
731 :
732 : static void
733 : write_summary( config_t const * config,
734 : ulong const * cur_tile,
735 : ulong const * prev_tile,
736 : ulong const * cur_link,
737 0 : ulong const * prev_link ) {
738 0 : (void)config;
739 0 : (void)prev_tile;
740 0 : (void)cur_tile;
741 :
742 0 : if( FD_UNLIKELY( !ended_on_newline ) ) PRINT( "\n" );
743 0 : PRINT( "\033[?7l" ); /* disable autowrap mode */
744 0 : PRINT( "โโโโโโโโโโโโโโโ" CLEARLN "\n" );
745 :
746 0 : ulong snapct_idx = fd_topo_find_tile( &config->topo, "snapct", 0UL );
747 0 : int shutdown = 1;
748 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;
749 :
750 0 : static long snap_shutdown_time = 0L;
751 0 : if( FD_UNLIKELY( !snap_shutdown_time && !shutdown ) ) snap_shutdown_time = 1L; /* Was not shutdown on boot */
752 0 : if( FD_UNLIKELY( !snap_shutdown_time && shutdown ) ) snap_shutdown_time = 2L; /* Was shutdown on boot */
753 0 : if( FD_UNLIKELY( snap_shutdown_time==1L && shutdown ) ) snap_shutdown_time = fd_log_wallclock();
754 :
755 0 : lines_printed = 1UL;
756 :
757 0 : if( FD_UNLIKELY( write_bench( config, cur_tile, prev_tile ) ) ) lines_printed++;
758 :
759 0 : ulong backt_idx = fd_topo_find_tile( &config->topo, "backt", 0UL );
760 0 : if( FD_UNLIKELY( backt_idx!=ULONG_MAX ) ) {
761 0 : lines_printed++;
762 0 : write_backtest( config, cur_tile );
763 0 : }
764 :
765 0 : long now = fd_log_wallclock();
766 0 : if( FD_UNLIKELY( snap_shutdown_time==1L || now<snap_shutdown_time+(long)2e9 ) ) {
767 0 : lines_printed++;
768 0 : write_snapshots( config, cur_tile, prev_tile );
769 0 : }
770 :
771 0 : lines_printed += write_accdb( config, cur_tile );
772 0 : lines_printed += write_wfs( config, cur_tile );
773 0 : lines_printed += write_gossip( config, cur_tile, prev_tile, cur_link, prev_link );
774 0 : lines_printed += write_repair( config, cur_tile, cur_link, prev_link );
775 0 : lines_printed += write_replay( config, cur_tile );
776 0 : lines_printed += write_gui( config, cur_tile, prev_tile );
777 0 : lines_printed += write_event( config, cur_tile );
778 :
779 0 : PRINT( "\033[?7h" ); /* enable autowrap mode */
780 0 : }
781 :
782 : static void
783 : snap_tiles( fd_topo_t const * topo,
784 0 : ulong * tiles ) {
785 0 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
786 0 : fd_topo_tile_t const * tile = &topo->tiles[ i ];
787 0 : volatile ulong const * metrics = fd_metrics_tile( tile->metrics );
788 0 : FD_TEST( metrics );
789 0 : for( ulong j=0UL; j<FD_METRICS_TOTAL_SZ/8UL; j++ ) tiles[ i*FD_METRICS_TOTAL_SZ+j ] = metrics[ j ];
790 0 : }
791 0 : }
792 :
793 : static void
794 : snap_links( fd_topo_t const * topo,
795 0 : ulong * links ) {
796 0 : ulong overall_polled_idx = 0UL;
797 :
798 0 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
799 0 : fd_topo_tile_t const * tile = &topo->tiles[ i ];
800 :
801 0 : ulong polled_in_idx = 0UL;
802 0 : for( ulong j=0UL; j<topo->tiles[ i ].in_cnt; j++ ) {
803 0 : if( FD_UNLIKELY( !tile->in_link_poll[ j ] ) ) continue;
804 :
805 0 : volatile ulong const * metrics = fd_metrics_link_in( tile->metrics, polled_in_idx );
806 0 : FD_TEST( metrics );
807 0 : for( ulong k=0UL; k<FD_METRICS_ALL_LINK_IN_TOTAL; k++ ) links[ overall_polled_idx*8UL+k ] = metrics[ k ];
808 0 : polled_in_idx++;
809 0 : overall_polled_idx++;
810 0 : }
811 0 : }
812 0 : }
813 :
814 : static ulong tiles[ 2UL*FD_TILE_MAX*FD_METRICS_TOTAL_SZ ];
815 : static ulong links[ 2UL*4096UL*8UL*FD_METRICS_ALL_LINK_IN_TOTAL ];
816 :
817 : static void
818 : run( config_t const * config,
819 0 : int drain_output_fd ) {
820 0 : (void)config;
821 0 : (void)drain_output_fd;
822 :
823 0 : ulong tile_cnt = config->topo.tile_cnt;
824 :
825 0 : ulong cons_cnt = 0UL;
826 0 : for( ulong i=0UL; i<config->topo.tile_cnt; i++ ) {
827 0 : for( ulong j=0UL; j<config->topo.tiles[ i ].in_cnt; j++ ) {
828 0 : if( FD_UNLIKELY( config->topo.tiles[ i ].in_link_poll[ j ] ) ) cons_cnt++;
829 0 : }
830 0 : }
831 :
832 0 : FD_TEST( tile_cnt<=FD_TILE_MAX );
833 0 : FD_TEST( cons_cnt<=4096UL );
834 :
835 0 : snap_tiles( &config->topo, tiles );
836 0 : fd_memcpy( tiles+tile_cnt*FD_METRICS_TOTAL_SZ, tiles, tile_cnt*FD_METRICS_TOTAL_SZ );
837 :
838 0 : snap_links( &config->topo, links );
839 0 : fd_memcpy( links+(cons_cnt*8UL*FD_METRICS_ALL_LINK_IN_TOTAL), links, cons_cnt*8UL*FD_METRICS_ALL_LINK_IN_TOTAL );
840 :
841 0 : ulong last_snap = 1UL;
842 :
843 0 : frame_len = 0UL;
844 0 : write_summary( config, 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) );
845 0 : flush_frame();
846 :
847 0 : long next = fd_log_wallclock()+(long)1e9;
848 0 : for(;;) {
849 0 : if( FD_UNLIKELY( drain_output_fd>=0 ) ) {
850 0 : if( FD_UNLIKELY( drain( drain_output_fd ) ) ) {
851 0 : frame_len = 0UL;
852 0 : write_summary( config, 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) );
853 0 : flush_frame();
854 0 : }
855 0 : }
856 :
857 0 : long now = fd_log_wallclock();
858 0 : if( FD_UNLIKELY( now>=next ) ) {
859 0 : last_snap = 1UL-last_snap;
860 0 : snap_tiles( &config->topo, tiles+last_snap*tile_cnt*FD_METRICS_TOTAL_SZ );
861 0 : snap_links( &config->topo, links+last_snap*(cons_cnt*8UL*FD_METRICS_ALL_LINK_IN_TOTAL) );
862 :
863 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, TRANSACTIONS_SENT ) );
864 0 : tps_sent_samples_idx++;
865 :
866 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, SLOTS_TOTAL ) );
867 0 : sps_samples_idx++;
868 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, TRANSACTIONS_TOTAL ) );
869 0 : tps_samples_idx++;
870 0 : cups_samples[ cups_samples_idx%(sizeof(cups_samples)/sizeof(cups_samples[0])) ] =
871 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, COMPUTE_UNITS_TOTAL ) ) +
872 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, COMPUTE_UNITS_TOTAL ) );
873 0 : cups_samples_idx++;
874 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 ) ) +
875 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 ) );
876 0 : snapshot_rx_idx++;
877 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, ACCOUNTS_LOADED ) );
878 0 : snapshot_acc_idx++;
879 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, EVENTS_SENT ) );
880 0 : events_sent_samples_idx++;
881 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, EVENTS_ACKED ) );
882 0 : events_acked_samples_idx++;
883 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 ) );
884 0 : event_bytes_written_samples_idx++;
885 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 ) );
886 0 : event_bytes_read_samples_idx++;
887 0 : rps_samples[ rps_samples_idx%(sizeof(rps_samples)/sizeof(rps_samples[0])) ] = (ulong)(
888 0 : 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, TXN_ACCOUNT_CHANGES_UNCHANGED_NONEXIST ) ) +
889 0 : 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, TXN_ACCOUNT_CHANGES_CREATED ) ) +
890 0 : 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, TXN_ACCOUNT_CHANGES_DELETE ) ) +
891 0 : 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, TXN_ACCOUNT_CHANGES_MODIFY ) ) +
892 0 : 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, TXN_ACCOUNT_CHANGES_UNCHANGED ) ) +
893 0 : 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, ACCDB_CREATED ) ) +
894 0 : 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, ACCDB_ROOTED ) ) +
895 0 : 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, ACCDB_REVERTED ) ) +
896 0 : 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, ACCDB_GC_ROOT ) ) +
897 0 : 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, ACCDB_RECLAIMED ) ) );
898 0 : rps_samples_idx++;
899 :
900 : /* Move cursor to top of dashboard and overwrite in place.
901 : All output is buffered and flushed in a single write() so
902 : the terminal never renders a partially drawn frame. */
903 0 : frame_len = 0UL;
904 0 : PRINT( "\033[?25l" ); /* hide cursor during redraw */
905 0 : if( FD_UNLIKELY( !ended_on_newline ) ) {
906 0 : PRINT( "\033[%luA\r", lines_printed+1UL );
907 0 : } else {
908 0 : PRINT( "\033[%luA\r", lines_printed );
909 0 : }
910 0 : write_summary( config, 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) );
911 0 : PRINT( "\033[0J" ); /* clear any leftover lines below */
912 0 : PRINT( "\033[?25h" ); /* show cursor */
913 0 : flush_frame();
914 0 : next += (long)1e7;
915 0 : }
916 0 : }
917 0 : }
918 :
919 : void
920 : watch_cmd_fn( args_t * args,
921 0 : config_t * config ) {
922 0 : int allow_fds[ 5 ];
923 0 : ulong allow_fds_cnt = 0;
924 0 : allow_fds[ allow_fds_cnt++ ] = 0; /* stdin */
925 0 : allow_fds[ allow_fds_cnt++ ] = 1; /* stdout */
926 0 : allow_fds[ allow_fds_cnt++ ] = 2; /* stderr */
927 0 : if( FD_LIKELY( fd_log_private_logfile_fd()!=-1 ) )
928 0 : allow_fds[ allow_fds_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
929 0 : if( FD_UNLIKELY( args->watch.drain_output_fd!=-1 ) )
930 0 : allow_fds[ allow_fds_cnt++ ] = args->watch.drain_output_fd; /* maybe we are interposing firedancer log output with the monitor */
931 :
932 0 : fd_topo_join_workspaces( &config->topo, FD_SHMEM_JOIN_MODE_READ_ONLY, FD_TOPO_CORE_DUMP_LEVEL_DISABLED );
933 :
934 0 : struct sock_filter seccomp_filter[ 128UL ];
935 0 : uint drain_output_fd = args->watch.drain_output_fd >= 0 ? (uint)args->watch.drain_output_fd : (uint)-1;
936 0 : populate_sock_filter_policy_watch( 128UL, seccomp_filter, (uint)fd_log_private_logfile_fd(), drain_output_fd );
937 :
938 0 : if( FD_LIKELY( config->development.sandbox ) ) {
939 0 : if( FD_UNLIKELY( close( config->log.lock_fd ) ) ) FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
940 :
941 0 : fd_sandbox_enter( config->uid,
942 0 : config->gid,
943 0 : 0,
944 0 : 0,
945 0 : 0,
946 0 : 1, /* Keep controlling terminal for main so it can receive Ctrl+C */
947 0 : 0,
948 0 : 0UL,
949 0 : 0UL,
950 0 : 0UL,
951 0 : 0UL,
952 0 : allow_fds_cnt,
953 0 : allow_fds,
954 0 : sock_filter_policy_watch_instr_cnt,
955 0 : seccomp_filter );
956 0 : } else {
957 0 : fd_sandbox_switch_uid_gid( config->uid, config->gid );
958 0 : }
959 :
960 0 : fd_topo_fill( &config->topo );
961 :
962 0 : run( config, args->watch.drain_output_fd );
963 0 : }
964 :
965 : action_t fd_action_watch = {
966 : .name = "watch",
967 : .args = NULL,
968 : .fn = watch_cmd_fn,
969 : .require_config = 1,
970 : .perm = watch_cmd_perm,
971 : .description = "Watch a locally running Firedancer instance with a terminal GUI",
972 : };
|