LCOV - code coverage report
Current view: top level - app/shared/commands/watch - watch.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 695 0.0 %
Date: 2026-03-19 18:19:27 Functions: 0 25 0.0 %

          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             : };

Generated by: LCOV version 1.14