LCOV - code coverage report
Current view: top level - app/firedancer-dev/commands - snapshot_load.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 542 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 16 0.0 %

          Line data    Source code
       1             : #include "../../firedancer/topology.h"
       2             : #include "../../platform/fd_sys_util.h"
       3             : #include "../../shared/commands/configure/configure.h"
       4             : #include "../../shared/commands/run/run.h"
       5             : #include "../../shared_dev/commands/dev.h"
       6             : #include "../../../disco/metrics/fd_metrics.h"
       7             : #include "../../../disco/topo/fd_topob.h"
       8             : #include "../../../disco/pack/fd_pack_cost.h"
       9             : #include "../../../util/pod/fd_pod_format.h"
      10             : #include "../../../discof/restore/utils/fd_ssctrl.h"
      11             : #include "../../../discof/restore/utils/fd_ssmsg.h"
      12             : #include "../../../flamenco/runtime/fd_cost_tracker.h"
      13             : #include "../../../flamenco/accdb/fd_accdb_private.h"
      14             : 
      15             : #include <fcntl.h> /* open */
      16             : #include <sys/resource.h>
      17             : #include <linux/capability.h>
      18             : #include <unistd.h> /* close, sleep */
      19             : #include <stdlib.h>
      20             : #include <stdio.h>
      21             : 
      22             : #define NAME "snapshot-load"
      23             : 
      24           0 : #define SL_RESET  "\033[0m"
      25           0 : #define SL_BOLD   "\033[1m"
      26           0 : #define SL_DIM    "\033[2m"
      27           0 : #define SL_RED    "\033[31m"
      28             : #define SL_GREEN  "\033[32m"
      29           0 : #define SL_YELLOW "\033[33m"
      30             : 
      31             : static char const *
      32             : sev_color( int    color,
      33           0 :            double pct ) {
      34           0 :   if( FD_UNLIKELY( !color ) ) return "";
      35           0 :   if( FD_UNLIKELY( pct>=85.0 ) ) return SL_RED;
      36           0 :   if( FD_UNLIKELY( pct>=50.0 ) ) return SL_YELLOW;
      37           0 :   return "";
      38           0 : }
      39             : 
      40             : static double
      41           0 : clamp_pct( double pct ) {
      42           0 :   return fd_double_if( pct<0.0, 0.0, fd_double_if( pct>100.0, 100.0, pct ) );
      43           0 : }
      44             : 
      45             : static char *
      46             : fmt_bar( char * buf,
      47             :          ulong  buf_sz,
      48             :          int    color,
      49             :          double pct,
      50           0 :          ulong  width ) {
      51           0 :   ulong filled = (ulong)( clamp_pct( pct )*(double)width/100.0+0.5 );
      52           0 :   ulong len = 0UL, l;
      53           0 :   FD_TEST( fd_cstr_printf_check( buf, buf_sz, &len, "%s", color ? SL_GREEN : "" ) );
      54           0 :   for( ulong i=0UL;    i<filled; i++ ) { FD_TEST( fd_cstr_printf_check( buf+len, buf_sz-len, &l, "█" ) ); len += l; }
      55           0 :   FD_TEST( fd_cstr_printf_check( buf+len, buf_sz-len, &l, "%s", color ? SL_DIM : "" ) ); len += l;
      56           0 :   for( ulong i=filled; i<width;  i++ ) { FD_TEST( fd_cstr_printf_check( buf+len, buf_sz-len, &l, "░" ) ); len += l; }
      57           0 :   FD_TEST( fd_cstr_printf_check( buf+len, buf_sz-len, &l, "%s", color ? SL_RESET : "" ) );
      58           0 :   return buf;
      59           0 : }
      60             : 
      61             : static char const *
      62           0 : phase_cstr( ulong state ) {
      63           0 :   if( FD_LIKELY( ( state>= 5UL && state<= 8UL ) || ( state>=13UL && state<=16UL ) ) ) return "full";
      64           0 :   if( FD_LIKELY( ( state>= 9UL && state<=12UL ) || ( state>=17UL && state<=20UL ) ) ) return "incr";
      65           0 :   if( FD_UNLIKELY( state==21UL ) ) return "done";
      66           0 :   return "wait";
      67           0 : }
      68             : 
      69             : extern fd_topo_obj_callbacks_t * CALLBACKS[];
      70             : 
      71             : fd_topo_run_tile_t
      72             : fdctl_tile_run( fd_topo_tile_t const * tile );
      73             : 
      74             : static void
      75             : snapshot_load_layout( config_t *  config,
      76           0 :                       fd_topo_t * topo ) {
      77           0 :   if( FD_LIKELY( !strcmp( config->layout.affinity, "auto" ) ) ) {
      78           0 :     fd_topob_auto_layout( topo );
      79           0 :     return;
      80           0 :   }
      81             : 
      82           0 :   ushort tile_to_cpu[ FD_TILE_MAX ];
      83           0 :   ulong affinity_tile_cnt = fd_topob_parse_affinity_cstr( config->layout.affinity, tile_to_cpu, 1, 1 );
      84           0 :   if( FD_UNLIKELY( affinity_tile_cnt<topo->tile_cnt ) ) {
      85           0 :     FD_LOG_ERR(( "snapshot-load topology has %lu tiles, but [layout.affinity] only provides %lu entries",
      86           0 :                  topo->tile_cnt, affinity_tile_cnt ));
      87           0 :   }
      88           0 :   if( FD_UNLIKELY( affinity_tile_cnt>topo->tile_cnt ) ) {
      89           0 :     FD_LOG_WARNING(( "snapshot-load topology has %lu tiles, but [layout.affinity] provides %lu entries; ignoring extras",
      90           0 :                      topo->tile_cnt, affinity_tile_cnt ));
      91           0 :   }
      92             : 
      93           0 :   fd_topo_cpus_t cpus[1];
      94           0 :   fd_topo_cpus_init( cpus );
      95           0 :   for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
      96           0 :     ushort encoded = tile_to_cpu[ i ];
      97           0 :     ushort cpu_idx = (ushort)(encoded & ~FD_TOPOB_CPU_SHARED);
      98           0 :     if( FD_UNLIKELY( encoded!=USHORT_MAX && cpu_idx>=cpus->cpu_cnt ) ) {
      99           0 :       FD_LOG_ERR(( "[layout.affinity] assigns snapshot-load tile %lu to CPU %hu, but the system has %lu CPUs",
     100           0 :                    i, cpu_idx, cpus->cpu_cnt ));
     101           0 :     }
     102           0 :     topo->tiles[ i ].cpu_idx = fd_ulong_if( encoded==USHORT_MAX,
     103           0 :                                             ULONG_MAX,
     104           0 :                                             (ulong)cpu_idx );
     105           0 :     topo->tiles[ i ].floats = encoded!=USHORT_MAX && !!(encoded & FD_TOPOB_CPU_SHARED);
     106           0 :   }
     107           0 : }
     108             : 
     109             : static void
     110           0 : snapshot_load_topo( config_t * config ) {
     111           0 :   config->firedancer.layout.resolv_tile_count = 0;
     112           0 :   fd_topo_t * topo = &config->topo;
     113           0 :   fd_topob_new( &config->topo, config->name );
     114           0 :   topo->max_page_size = fd_cstr_to_shmem_page_sz( config->hugetlbfs.max_page_size );
     115             : 
     116           0 :   fd_topob_wksp( topo, "txncache" );
     117           0 :   fd_topo_obj_t * txncache_obj = setup_topo_txncache( topo, "txncache",
     118           0 :       config->firedancer.runtime.max_live_slots,
     119           0 :       2UL*config->limits.max_txn_per_slot );
     120           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, txncache_obj->id, "txncache" ) );
     121             : 
     122           0 :   fd_topob_wksp( topo, "accdb" );
     123           0 :   fd_topo_obj_t * accdb_obj = setup_topo_accdb( topo, "accdb",
     124           0 :       config->firedancer.accounts.max_accounts,
     125           0 :       config->firedancer.runtime.max_live_slots,
     126           0 :       FD_RUNTIME_MAX_ACC_WRITES_PER_SLOT,
     127           0 :       8192UL,
     128           0 :       1UL<<35UL,
     129           0 :       config->firedancer.accounts.cache_size_gib*(1UL<<30UL),
     130           0 :       config->tiles.bundle.enabled,
     131           0 :       1UL+config->firedancer.layout.snapin_tile_count,
     132           0 :       0UL );
     133           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, accdb_obj->id, "accdb" ) );
     134             : 
     135           0 :   fd_topob_wksp( topo, "banks" );
     136           0 :   fd_topo_obj_t * banks_obj = setup_topo_banks( topo, "banks",
     137           0 :       config->firedancer.runtime.max_live_slots,
     138           0 :       config->firedancer.runtime.bank_cache_cnt,
     139           0 :       config->firedancer.runtime.stake_delegation_cache_cnt,
     140           0 :       config->development.bench.max_cost_per_block );
     141           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, banks_obj->id, "banks" ) );
     142             : 
     143           0 : #define FOR(cnt) for( ulong i=0UL; i<cnt; i++ )
     144             : 
     145             :   /* metrics tile *****************************************************/
     146           0 :   fd_topob_wksp( topo, "metric_in" );
     147           0 :   fd_topob_wksp( topo, "metric" );
     148           0 :   fd_topob_tile( topo, "metric",  "metric", "metric_in", ULONG_MAX, 0, 0, 1 );
     149             : 
     150             :   /* read() tile */
     151           0 :   fd_topob_wksp( topo, "snapct" );
     152           0 :   fd_topo_tile_t * snapct_tile = fd_topob_tile( topo, "snapct", "snapct", "metric_in", ULONG_MAX, 0, 0, 1 );
     153           0 :   snapct_tile->allow_shutdown = 1;
     154             : 
     155             :   /* load tile */
     156           0 :   fd_topob_wksp( topo, "snapld" );
     157           0 :   fd_topo_tile_t * snapld_tile = fd_topob_tile( topo, "snapld", "snapld", "metric_in", ULONG_MAX, 0, 0, 1 );
     158           0 :   snapld_tile->allow_shutdown = 1;
     159             : 
     160             :   /* "snapdc": Zstandard decompress tile */
     161           0 :   fd_topob_wksp( topo, "snapdc" );
     162           0 :   ulong snapdc_tile_cnt = config->firedancer.layout.snapdc_tile_count;
     163           0 :   FOR(snapdc_tile_cnt) fd_topob_tile( topo, "snapdc", "snapdc", "metric_in", ULONG_MAX, 0, 0, 0 )->allow_shutdown = 1;
     164             : 
     165             :   /* Parallel snapshot loader tiles. */
     166           0 :   fd_topob_wksp( topo, "snapin" );
     167           0 :   ulong snapin_tile_cnt = config->firedancer.layout.snapin_tile_count;
     168           0 :   FOR(snapin_tile_cnt) {
     169           0 :     fd_topo_tile_t * tile = fd_topob_tile( topo, "snapin", "snapin", "metric_in", ULONG_MAX, 0, 0, 0 );
     170           0 :     tile->allow_shutdown = 1;
     171           0 :   }
     172             : 
     173           0 :   fd_topob_wksp( topo, "snapin_shmem" );
     174           0 :   fd_topo_obj_t * shmem_obj = fd_topob_obj( topo, "snapin_shmem", "snapin_shmem" );
     175           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, shmem_obj->id, "snapin_shmem" ) );
     176             : 
     177           0 :   fd_topo_obj_t * dc_ticket_obj = fd_topob_obj_named( topo, "fseq", "snapdc", "frame_ticket" );
     178           0 :   FOR(snapdc_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapdc", i ) ], dc_ticket_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     179             : 
     180           0 :   fd_topob_wksp( topo, "diag" );
     181           0 :   fd_topob_tile( topo, "diag", "diag", "metric_in", ULONG_MAX, 0, 0, 0 );
     182           0 :   fd_topo_tile_t * accdb_tile = fd_topob_tile( topo, "accdb", "accdb", "metric_in", ULONG_MAX, 0, 0, 0 );
     183             : 
     184           0 :   fd_topob_wksp( topo, "snapct_ld"    );
     185           0 :   fd_topob_wksp( topo, "snapld_dc"    );
     186           0 :   fd_topob_wksp( topo, "snapdc_in"    );
     187             : 
     188           0 :   fd_topob_wksp( topo, "snapin_manif" );
     189           0 :   fd_topob_wksp( topo, "snapct_repr"  );
     190             : 
     191           0 :   fd_topob_wksp( topo, "snapin_ct"    );
     192             : 
     193           0 :   fd_topob_link( topo, "snapct_ld",    "snapct_ld",    128UL,                  sizeof(fd_ssctrl_msg_t),        1UL );
     194           0 :   fd_topob_link( topo, "snapld_dc",    "snapld_dc",    FD_SNAPSHOT_DATA_DEPTH, FD_SNAPSHOT_DATA_MTU,           1UL );
     195           0 :   FOR(snapdc_tile_cnt) fd_topob_link( topo, "snapdc_in", "snapdc_in", FD_SNAPSHOT_DC_IN_DEPTH, FD_SNAPSHOT_DATA_MTU, 1UL );
     196           0 :   fd_topob_link( topo, "snapin_manif", "snapin_manif", 4UL,     sizeof(fd_snapshot_manifest_t), 1UL )->permit_no_consumers = 1;
     197           0 :   fd_topob_link( topo, "snapct_repr",  "snapct_repr",  128UL,   0UL,                            1UL )->permit_no_consumers = 1;
     198             : 
     199           0 :   FOR(snapin_tile_cnt) fd_topob_link( topo, "snapin_ct", "snapin_ct", 128UL, 0UL, 1UL );
     200           0 :   FOR(snapin_tile_cnt) fd_topob_tile_in( topo, "snapct", 0UL, "metric_in", "snapin_ct", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     201             : 
     202           0 :   fd_topob_tile_in ( topo, "snapct",  0UL, "metric_in", "snapld_dc",    0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     203           0 :   fd_topob_tile_out( topo, "snapct",  0UL,              "snapct_ld",    0UL                                       );
     204           0 :   fd_topob_tile_out( topo, "snapct",  0UL,              "snapct_repr",  0UL                                       );
     205           0 :   fd_topob_tile_in ( topo, "snapld",  0UL, "metric_in", "snapct_ld",    0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     206           0 :   fd_topob_tile_out( topo, "snapld",  0UL,              "snapld_dc",    0UL                                       );
     207           0 :   FOR(snapdc_tile_cnt) fd_topob_tile_in ( topo, "snapdc", i,   "metric_in", "snapld_dc", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     208           0 :   FOR(snapdc_tile_cnt) fd_topob_tile_out( topo, "snapdc", i,               "snapdc_in", i                                         );
     209           0 :   for( ulong t=0UL; t<snapin_tile_cnt; t++ ) {
     210           0 :     FOR(snapdc_tile_cnt) fd_topob_tile_in( topo, "snapin", t, "metric_in", "snapdc_in", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     211           0 :     fd_topob_tile_out( topo, "snapin", t, "snapin_ct", t );
     212           0 :   }
     213           0 :   fd_topob_tile_out( topo, "snapin",  0UL,              "snapin_manif", 0UL                                       );
     214             : 
     215           0 :   fd_topo_tile_t * snapin_tile = &topo->tiles[ fd_topo_find_tile( topo, "snapin", 0UL ) ];
     216           0 :   fd_topob_tile_uses( topo, snapin_tile, txncache_obj,   FD_SHMEM_JOIN_MODE_READ_WRITE );
     217           0 :   fd_topob_tile_uses( topo, accdb_tile,  accdb_obj,      FD_SHMEM_JOIN_MODE_READ_WRITE );
     218           0 :   FOR(snapin_tile_cnt) {
     219           0 :     fd_topo_tile_t * tile = &topo->tiles[ fd_topo_find_tile( topo, "snapin", i ) ];
     220           0 :     fd_topob_tile_uses( topo, tile, accdb_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     221           0 :     fd_topob_tile_uses( topo, tile, shmem_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     222           0 :     fd_topob_tile_uses( topo, tile, banks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     223           0 :     tile->snapin.accdb_obj_id    = accdb_obj->id;
     224           0 :     tile->snapin.txncache_obj_id = txncache_obj->id;
     225           0 :     tile->snapin.banks_obj_id    = banks_obj->id;
     226           0 :     tile->snapin.shmem_obj_id    = shmem_obj->id;
     227           0 :     tile->snapin.max_live_slots  = config->firedancer.runtime.max_live_slots;
     228           0 :   }
     229             : 
     230           0 :   for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
     231           0 :     fd_topo_tile_t * tile = &topo->tiles[ i ];
     232           0 :     fd_topo_configure_tile( tile, config );
     233           0 :   }
     234             : 
     235           0 :   snapshot_load_layout( config, topo );
     236           0 :   fd_topob_waker( topo );
     237           0 :   fd_topob_finish( topo, CALLBACKS );
     238           0 : }
     239             : 
     240             : static void
     241           0 : snapshot_load_topo1( config_t * config ) {
     242           0 :   snapshot_load_topo( config );
     243           0 : }
     244             : 
     245             : static void
     246             : snapshot_load_args( int *    pargc,
     247             :                     char *** pargv,
     248           0 :                     args_t * args ) {
     249           0 :   if( FD_UNLIKELY( fd_env_strip_cmdline_contains( pargc, pargv, "--help" ) ) ) {
     250           0 :     fputs(
     251           0 :       "\nUsage: firedancer-dev snapshot-load [GLOBAL FLAGS] [FLAGS]\n"
     252           0 :       "\n"
     253           0 :       "Global Flags:\n"
     254           0 :       "  --mainnet            Use Solana mainnet-beta defaults\n"
     255           0 :       "  --testnet            Use Solana testnet defaults\n"
     256           0 :       "  --devnet             Use Solana devnet defaults\n"
     257           0 :       "\n"
     258           0 :       "Flags:\n"
     259           0 :       "  --snapshot-dir PATH  Load/save snapshots from this directory\n"
     260           0 :       "  --offline            Do not attempt to download snapshots\n"
     261           0 :       "  --no-incremental     Disable incremental snapshot loading\n"
     262           0 :       "  --no-watch           Do not print periodic progress updates\n"
     263           0 :       "  --db-rec-max <num>   Database max record/account count (e.g. 10e6 -> 10M accounts)\n"
     264           0 :       "  --accounts-hist      After loading, analyze account size distribution\n"
     265           0 :       "\n",
     266           0 :       stderr );
     267           0 :     exit( 0 );
     268           0 :   }
     269           0 :   memset( &args->snapshot_load, 0, sizeof(args->snapshot_load) );
     270             : 
     271           0 :   char const * snapshot_dir  = fd_env_strip_cmdline_cstr    ( pargc, pargv, "--snapshot-dir", NULL, NULL   );
     272           0 :   int          offline       = fd_env_strip_cmdline_contains( pargc, pargv, "--offline"                    )!=0;
     273           0 :   int          no_incremental= fd_env_strip_cmdline_contains( pargc, pargv, "--no-incremental"             )!=0;
     274           0 :   int          no_watch      = fd_env_strip_cmdline_contains( pargc, pargv, "--no-watch"                   )!=0;
     275           0 :   int          accounts_hist = fd_env_strip_cmdline_contains( pargc, pargv, "--accounts-hist"              )!=0;
     276           0 :   double       db_sz         = fd_env_strip_cmdline_double  ( pargc, pargv, "--db-sz",        NULL, 0.0    );
     277           0 :   double       db_rec_max    = fd_env_strip_cmdline_double  ( pargc, pargv, "--db-rec-max",   NULL, 0.0    );
     278           0 :   if( FD_UNLIKELY( !(db_sz>=0.0 && db_sz<1.8e19) ) )           FD_LOG_ERR(( "--db-sz out of range" ));      /* also rejects NaN */
     279           0 :   if( FD_UNLIKELY( !(db_rec_max>=0.0 && db_rec_max<1.8e19) ) ) FD_LOG_ERR(( "--db-rec-max out of range" ));
     280             : 
     281           0 :   fd_cstr_ncpy( args->snapshot_load.snapshot_dir, snapshot_dir, sizeof(args->snapshot_load.snapshot_dir) );
     282           0 :   args->snapshot_load.accounts_hist  = accounts_hist;
     283           0 :   args->snapshot_load.offline        = offline;
     284           0 :   args->snapshot_load.no_incremental = no_incremental;
     285           0 :   args->snapshot_load.no_watch       = no_watch;
     286           0 :   args->snapshot_load.db_rec_max     = (ulong)db_rec_max;
     287           0 :   args->snapshot_load.cache_sz       = (ulong)db_sz;
     288           0 : }
     289             : 
     290             : /* ACCOUNTS_HIST_N (32) is chosen to make the histogram lightweight.
     291             :    And because accounts can have a data size in the range [0, 10MiB],
     292             :    the width of the bins increments in powers of 2.  In the future, it
     293             :    should be possible to pass this as a configuration parameter. */
     294           0 : #define ACCOUNTS_HIST_N (32)
     295             : 
     296             : struct accounts_hist {
     297             :   ulong total_cnt;
     298             :   ulong total_acc;
     299             :   ulong bin_thi[ ACCOUNTS_HIST_N ];
     300             :   ulong bin_cnt[ ACCOUNTS_HIST_N ];
     301             :   ulong bin_acc[ ACCOUNTS_HIST_N ];
     302             :   ulong bin_min[ ACCOUNTS_HIST_N ];
     303             :   ulong bin_max[ ACCOUNTS_HIST_N ];
     304             :   ulong token_cnt;
     305             : };
     306             : typedef struct accounts_hist accounts_hist_t;
     307             : 
     308             : static inline void
     309           0 : accounts_hist_reset( accounts_hist_t * hist ) {
     310           0 :   hist->total_cnt = 0UL;
     311           0 :   hist->total_acc = 0UL;
     312           0 :   for( int i=0; i < ACCOUNTS_HIST_N; i++ ) {
     313           0 :     hist->bin_thi[ i ] = fd_ulong_if( i > 0, fd_pow2( ulong, i-1 ), 0UL );
     314           0 :     hist->bin_cnt[ i ] = 0UL;
     315           0 :     hist->bin_acc[ i ] = 0UL;
     316           0 :     hist->bin_min[ i ] = ULONG_MAX;
     317           0 :     hist->bin_max[ i ] = 0UL;
     318           0 :   }
     319           0 :   hist->token_cnt = 0UL;
     320           0 : }
     321             : 
     322             : static inline void FD_FN_UNUSED
     323             : accounts_hist_update( accounts_hist_t * hist,
     324           0 :                       ulong             account_sz ) {
     325           0 :   hist->total_cnt += 1UL;
     326           0 :   hist->total_acc += account_sz;
     327           0 :   int i=0;
     328             :   /* This allows for arbitrary thresholds - not optimized for pow2
     329             :      bins. */
     330           0 :   for( ; i < ACCOUNTS_HIST_N; i++ ) {
     331           0 :     if( FD_UNLIKELY( account_sz <= hist->bin_thi[ i ] )) {
     332           0 :       hist->bin_cnt[ i ] += 1;
     333           0 :       hist->bin_acc[ i ] += account_sz;
     334           0 :       hist->bin_min[ i ] = fd_ulong_min( hist->bin_min[ i ], account_sz );
     335           0 :       hist->bin_max[ i ] = fd_ulong_max( hist->bin_max[ i ], account_sz );
     336           0 :       break;
     337           0 :     }
     338           0 :   }
     339           0 :   FD_TEST( i < ACCOUNTS_HIST_N );
     340           0 : }
     341             : 
     342             : static inline int
     343           0 : accounts_hist_check( accounts_hist_t const * hist ) {
     344           0 :   ulong cnt = 0UL;
     345           0 :   ulong acc = 0UL;
     346           0 :   for( int i=0; i < ACCOUNTS_HIST_N; i++ ) {
     347           0 :     cnt += hist->bin_cnt[ i ];
     348           0 :     acc += hist->bin_acc[ i ];
     349           0 :   }
     350           0 :   if( cnt != hist->total_cnt ) return -1;
     351           0 :   if( acc != hist->total_acc ) return -2;
     352           0 :   return 0;
     353           0 : }
     354             : 
     355             : static void
     356           0 : accounts_hist_print( accounts_hist_t const * hist ) {
     357           0 :   double hist_total_cnt_M   = (double)hist->total_cnt / (double)1.0e6;
     358           0 :   double hist_total_cnt_GiB = (double)hist->total_acc / (double)1073741824;
     359           0 :   printf( "\n" );
     360           0 :   printf( "hist_total_cnt %16lu ( %6.1f M   )\n", hist->total_cnt, hist_total_cnt_M   );
     361           0 :   printf( "hist_total_acc %16lu ( %6.1f GiB )\n", hist->total_acc, hist_total_cnt_GiB );
     362           0 :   printf( "   bin_th_lo <  sz <=    bin_th_hi |    bin_cnt (run_sum%%) |      bin_acc (run_sum%%) |    bin_min B |    bin_max B |    bin_avg B |\n" );
     363           0 :   ulong sum_cnt = 0UL;
     364           0 :   ulong sum_acc = 0UL;
     365           0 :   for( int i=0; i < ACCOUNTS_HIST_N; i++ ) {
     366             :     /* bin thresholds */
     367           0 :     ulong hist_bin_tlo      = hist->bin_thi[ fd_int_if( i>0, i-1, i ) ];
     368           0 :     ulong hist_bin_thi      = hist->bin_thi[ i ];
     369             :     /* bin cnt */
     370           0 :     ulong hist_bin_cnt      = hist->bin_cnt[ i ];
     371           0 :     sum_cnt                += hist->bin_cnt[ i ];
     372           0 :     double sum_cnt_p        = (double)(sum_cnt * 100) / (double)hist->total_cnt;
     373           0 :     double hist_bin_cnt_K   = (double)(hist_bin_cnt) / (double)1.0e3;
     374             :     /* bin acc */
     375           0 :     ulong hist_bin_acc      = hist->bin_acc[ i ];
     376           0 :     sum_acc                += hist->bin_acc[ i ];
     377           0 :     double sum_acc_p        = (double)(sum_acc * 100) / (double)hist->total_acc;
     378           0 :     double hist_bin_acc_MiB = (double)(hist_bin_acc) / (double)1048576.0f;
     379             :     /* bin min, max, avg */
     380           0 :     ulong hist_bin_min      = fd_ulong_if( hist->bin_cnt[ i ] > 0, hist->bin_min[ i ], 0UL );
     381           0 :     ulong hist_bin_max      = hist->bin_max[ i ];
     382           0 :     ulong hist_bin_avg      = hist->bin_cnt[ i ] > 0 ? hist->bin_acc[ i ] / hist->bin_cnt[ i ] : 0UL;
     383             :     /* log */
     384           0 :     char buf[256];
     385           0 :     FD_TEST( fd_cstr_printf_check( buf, sizeof(buf), NULL,
     386           0 :                                   "%12lu %s sz <= %12lu | %8.1f K (%6.1f %%) | %8.1f MiB (%6.1f %%) | %12lu | %12lu | %12lu |\n",
     387           0 :                                   hist_bin_tlo, i==0? "<=" : "< ", hist_bin_thi,
     388           0 :                                   hist_bin_cnt_K, sum_cnt_p,
     389           0 :                                   hist_bin_acc_MiB, sum_acc_p,
     390           0 :                                   hist_bin_min, hist_bin_max, hist_bin_avg ) );
     391           0 :     printf( "%s", buf );
     392           0 :   }
     393           0 :   printf( "\n" );
     394           0 : }
     395             : 
     396             : static void
     397             : accounts_hist( accounts_hist_t * hist,
     398           0 :                config_t *        config ) {
     399           0 :   fd_topo_t * topo = &config->topo;
     400           0 :   ulong accdb_obj_id = fd_pod_query_ulong( topo->props, "accdb", ULONG_MAX );
     401           0 :   FD_TEST( accdb_obj_id!=ULONG_MAX );
     402           0 :   void * _accdb_shmem = fd_topo_obj_laddr( topo, accdb_obj_id );
     403           0 :   fd_accdb_shmem_t * shmem = fd_accdb_shmem_join( _accdb_shmem );
     404           0 :   FD_TEST( shmem );
     405             : 
     406             :   /* Recompute the shmem layout to locate acc_map and acc_pool element
     407             :      storage without taking a writer joiner slot.  This mirrors the
     408             :      layout in fd_accdb_shmem_new and fd_accdb_join_readonly. */
     409             : 
     410           0 :   ulong max_live_slots              = shmem->max_live_slots;
     411           0 :   ulong max_accounts                = shmem->max_accounts;
     412           0 :   ulong chain_cnt                   = shmem->chain_cnt;
     413             : 
     414           0 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
     415           0 :                                   FD_SCRATCH_ALLOC_APPEND( l, FD_ACCDB_SHMEM_ALIGN,           sizeof(fd_accdb_shmem_t)                                );
     416           0 :                                   FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_accdb_fork_shmem_t), max_live_slots*sizeof(fd_accdb_fork_shmem_t)            );
     417           0 :                                   FD_SCRATCH_ALLOC_APPEND( l, descends_set_align(),           max_live_slots*descends_set_footprint( max_live_slots ) );
     418           0 :   uint *               acc_map  = FD_SCRATCH_ALLOC_APPEND( l, alignof(uint),                  chain_cnt*sizeof(uint)                                  );
     419           0 :   fd_accdb_accmeta_t * acc_pool = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_accdb_accmeta_t),    max_accounts*sizeof(fd_accdb_accmeta_t)                 );
     420             : 
     421             :   /* Walk every hash chain.  Each non-UINT_MAX head index yields a
     422             :      linked list of live acc_pool elements via map.next. */
     423             : 
     424           0 :   for( ulong chain_i=0UL; chain_i<chain_cnt; chain_i++ ) {
     425           0 :     uint acc_idx = acc_map[ chain_i ];
     426           0 :     while( acc_idx!=UINT_MAX ) {
     427           0 :       fd_accdb_accmeta_t const * accmeta = &acc_pool[ acc_idx ];
     428           0 :       ulong data_sz = (ulong)FD_ACCDB_SIZE_DATA( accmeta->executable_size );
     429           0 :       accounts_hist_update( hist, sizeof(fd_accdb_disk_meta_t) + data_sz );
     430           0 :       acc_idx = accmeta->map.next;
     431           0 :     }
     432           0 :   }
     433           0 : }
     434             : 
     435             : /* fixup_config applies command-line arguments to config, overriding
     436             :    defaults / config file */
     437             : 
     438             : static void
     439             : fixup_config( config_t *     config,
     440           0 :               args_t const * args ) {
     441           0 :   if( args->snapshot_load.snapshot_dir[0] ) {
     442           0 :     fd_cstr_ncpy( config->paths.snapshots, args->snapshot_load.snapshot_dir, sizeof(config->paths.snapshots) );
     443           0 :   }
     444             : 
     445           0 :   if( args->snapshot_load.db_rec_max ) {
     446           0 :     config->firedancer.accounts.max_accounts = args->snapshot_load.db_rec_max;
     447           0 :   }
     448             : 
     449           0 :   if( args->snapshot_load.cache_sz ) {
     450           0 :     config->firedancer.accounts.cache_size_gib = fd_ulong_align_up( args->snapshot_load.cache_sz, (1UL<<30) )>>30;
     451           0 :   }
     452             : 
     453           0 :   if( args->snapshot_load.offline ) {
     454           0 :     config->firedancer.snapshots.sources.gossip.allow_any      = 0;
     455           0 :     config->firedancer.snapshots.sources.gossip.allow_list_cnt = 0;
     456           0 :     config->firedancer.snapshots.sources.servers_cnt           = 0;
     457           0 :   }
     458             : 
     459           0 :   if( args->snapshot_load.no_incremental ) {
     460           0 :     config->firedancer.snapshots.incremental_snapshots = 0;
     461           0 :   }
     462             : 
     463           0 :   if( FD_UNLIKELY( config->firedancer.snapshots.sources.gossip.allow_any || config->firedancer.snapshots.sources.gossip.allow_list_cnt ) ) {
     464           0 :     FD_LOG_WARNING(( "snapshot-load command is incompatible with gossip snapshot sources; disabling gossip snapshot sources" ));
     465           0 :     config->firedancer.snapshots.sources.gossip.allow_any      = 0;
     466           0 :     config->firedancer.snapshots.sources.gossip.allow_list_cnt = 0;
     467           0 :   }
     468             : 
     469             :   /* FIXME Unfortunately, the fdctl boot procedure constructs the
     470             :            topology before parsing command-line arguments.  So, here,
     471             :            we construct the topology again (a third time ... sigh). */
     472           0 :   snapshot_load_topo( config );
     473           0 : }
     474             : 
     475             : static void
     476             : snapshot_load_cmd_fn( args_t *   args,
     477           0 :                       config_t * config ) {
     478           0 :   fixup_config( config, args );
     479             : 
     480           0 :   int watch = !args->snapshot_load.no_watch;
     481             : 
     482           0 :   fd_topo_t * topo = &config->topo;
     483             : 
     484           0 :   args_t configure_args = {
     485           0 :     .configure.command = CONFIGURE_CMD_INIT,
     486           0 :   };
     487             : 
     488           0 :   for( ulong i=0UL; STAGES[ i ]; i++ )
     489           0 :     configure_args.configure.stages[ i ] = STAGES[ i ];
     490           0 :   configure_cmd_fn( &configure_args, config );
     491             : 
     492           0 :   run_firedancer_init( config, 1, 0 );
     493             : 
     494           0 :   initialize_accdb_fd( config );
     495           0 :   initialize_epoch_credits_fd( config );
     496           0 :   initialize_cost_tracker_fd( config );
     497           0 :   initialize_vote_stakes_fd( config );
     498           0 :   initialize_stake_delegations_fd( config );
     499           0 :   initialize_store_fds( config );
     500           0 :   initialize_snapshot_fds( config );
     501             : 
     502           0 :   fd_topo_join_workspaces( topo, FD_SHMEM_JOIN_MODE_READ_WRITE, FD_TOPO_CORE_DUMP_LEVEL_DISABLED );
     503           0 :   fd_topo_fill( topo );
     504             : 
     505           0 :   fd_topo_tile_t * snapct_tile = &topo->tiles[ fd_topo_find_tile( topo, "snapct", 0UL ) ];
     506           0 :   fd_topo_tile_t * snapld_tile = &topo->tiles[ fd_topo_find_tile( topo, "snapld", 0UL ) ];
     507           0 :   ulong snapdc_tile_cnt = config->firedancer.layout.snapdc_tile_count;
     508           0 :   ulong snapin_tile_cnt = config->firedancer.layout.snapin_tile_count;
     509           0 :   FD_TEST( snapin_tile_cnt<=FD_TOPO_MAX_TILE_IN_LINKS );
     510             : 
     511           0 :   double tick_per_ns = fd_tempo_tick_per_ns( NULL );
     512           0 :   double ns_per_tick = 1.0/tick_per_ns;
     513             : 
     514           0 :   long start = fd_log_wallclock();
     515           0 :   fd_topo_run_single_process( topo, config->uid, config->gid, fdctl_tile_run );
     516             : 
     517           0 :   ulong volatile * const snapct_metrics = fd_metrics_tile( snapct_tile->metrics );
     518           0 :   ulong volatile * const snapld_metrics = fd_metrics_tile( snapld_tile->metrics );
     519           0 :   ulong volatile *       snapin_all_metrics[ FD_TOPO_MAX_TILE_IN_LINKS ];
     520           0 :   for( ulong i=0UL; i<snapin_tile_cnt; i++ ) {
     521           0 :     fd_topo_tile_t * tile = &topo->tiles[ fd_topo_find_tile( topo, "snapin", i ) ];
     522           0 :     snapin_all_metrics[ i ] = fd_metrics_tile( tile->metrics );
     523           0 :   }
     524           0 :   ulong volatile *       snapdc_metrics[ FD_TOPO_MAX_TILE_IN_LINKS ];
     525           0 :   for( ulong i=0UL; i<snapdc_tile_cnt; i++ ) {
     526           0 :     fd_topo_tile_t * snapdc_tile = &topo->tiles[ fd_topo_find_tile( topo, "snapdc", i ) ];
     527           0 :     snapdc_metrics[ i ] = fd_metrics_tile( snapdc_tile->metrics );
     528           0 :   }
     529             : 
     530           0 :   ulong total_off_old    = 0UL;
     531           0 :   ulong decomp_off_old   = 0UL;
     532           0 :   ulong snapld_wait_old  = 0UL;
     533           0 :   ulong snapdc_wait_old[ FD_TOPO_MAX_TILE_IN_LINKS ] = {0};
     534           0 :   ulong snapin_wait_old[ FD_TOPO_MAX_TILE_IN_LINKS ] = {0};
     535           0 :   ulong acc_cnt_old      = 0UL;
     536             : 
     537           0 :   int color = fd_log_colorize() && isatty( STDOUT_FILENO );
     538           0 :   char const * c_bold = color ? SL_BOLD : "";
     539           0 :   char const * c_dim  = color ? SL_DIM  : "";
     540           0 :   char const * c_norm = color ? SL_RESET : "";
     541             : 
     542           0 :   sleep( 1 );
     543           0 :   if( watch ) {
     544           0 :     printf( "%scomp%s compressed %s·%s %sraw%s uncompressed %s·%s %sacc%s accounts %s·%s "
     545           0 :             "%sbusy%s %%%s of load·decompress·insert·write, yellow when the bottleneck%s\n",
     546           0 :             c_dim, c_norm, c_dim, c_norm,
     547           0 :             c_dim, c_norm, c_dim, c_norm,
     548           0 :             c_dim, c_norm, c_dim, c_norm,
     549           0 :             c_dim, c_norm, c_dim, c_norm );
     550           0 :     fflush( stdout );
     551           0 :   }
     552             : 
     553           0 :   long next = start+1000L*1000L*1000L;
     554           0 :   for(;;) {
     555           0 :     ulong snapct_status = FD_VOLATILE_CONST( snapct_metrics[ MIDX( GAUGE, TILE, STATE ) ] );
     556           0 :     ulong snapld_status = FD_VOLATILE_CONST( snapld_metrics[ MIDX( GAUGE, TILE, STATE ) ] );
     557           0 :     int snapin_shutdown = 1;
     558           0 :     for( ulong i=0UL; i<snapin_tile_cnt; i++ ) {
     559           0 :       snapin_shutdown &= FD_VOLATILE_CONST( snapin_all_metrics[ i ][ MIDX( GAUGE, TILE, STATE ) ] )==2UL;
     560           0 :     }
     561           0 :     int snapdc_shutdown = 1;
     562           0 :     for( ulong i=0UL; i<snapdc_tile_cnt; i++ ) {
     563           0 :       snapdc_shutdown &= FD_VOLATILE_CONST( snapdc_metrics[ i ][ MIDX( GAUGE, TILE, STATE ) ] )==2UL;
     564           0 :     }
     565             : 
     566           0 :     if( FD_UNLIKELY( snapct_status==2UL && snapld_status==2UL && snapdc_shutdown && snapin_shutdown ) ) break;
     567             : 
     568           0 :     long cur = fd_log_wallclock();
     569           0 :     if( FD_UNLIKELY( cur<next ) ) {
     570           0 :       long sleep_nanos = fd_long_min( 1000L*1000L, next-cur );
     571           0 :       FD_TEST( !fd_sys_util_nanosleep(  (uint)(sleep_nanos/(1000L*1000L*1000L)), (uint)(sleep_nanos%(1000L*1000L*1000L)) ) );
     572           0 :       continue;
     573           0 :     }
     574             : 
     575           0 :     ulong total_off    = snapct_metrics[ MIDX( GAUGE, SNAPCT, READ_PROGRESS_BYTES_FULL ) ] +
     576           0 :                          snapct_metrics[ MIDX( GAUGE, SNAPCT, READ_PROGRESS_BYTES_INCREMENTAL ) ];
     577           0 :     ulong decomp_off   = 0UL;
     578           0 :     ulong snapdc_wait[ FD_TOPO_MAX_TILE_IN_LINKS ];
     579           0 :     for( ulong i=0UL; i<snapdc_tile_cnt; i++ ) {
     580           0 :       decomp_off += snapdc_metrics[ i ][ MIDX( GAUGE, SNAPDC, DECOMPRESSED_PROGRESS_BYTES_FULL ) ] +
     581           0 :                     snapdc_metrics[ i ][ MIDX( GAUGE, SNAPDC, DECOMPRESSED_PROGRESS_BYTES_INCREMENTAL ) ];
     582           0 :       snapdc_wait[ i ] = snapdc_metrics[ i ][ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG ) ]
     583           0 :                        + snapdc_metrics[ i ][ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_SLEEPING ) ]
     584           0 :                        + snapdc_metrics[ i ][ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) ]
     585           0 :                        + snapdc_metrics[ i ][ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_SLEEPING ) ];
     586           0 :     }
     587             :     /* Waiting on either neighbor counts as not busy */
     588           0 :     ulong snapld_wait  = snapld_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG ) ]
     589           0 :                        + snapld_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_SLEEPING ) ]
     590           0 :                        + snapld_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) ]
     591           0 :                        + snapld_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_SLEEPING ) ];
     592           0 :     ulong snapin_wait[ FD_TOPO_MAX_TILE_IN_LINKS ];
     593           0 :     ulong acc_cnt     = 0UL;
     594           0 :     for( ulong i=0UL; i<snapin_tile_cnt; i++ ) {
     595           0 :       ulong volatile * metrics = snapin_all_metrics[ i ];
     596           0 :       snapin_wait[ i ] = metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG ) ]
     597           0 :                        + metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_SLEEPING ) ]
     598           0 :                        + metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) ]
     599           0 :                        + metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_SLEEPING ) ];
     600           0 :       acc_cnt += metrics[ MIDX( GAUGE, SNAPIN, ACCOUNT_PROGRESS_NEW ) ];
     601           0 :     }
     602             : 
     603           0 :     char const * phase = phase_cstr( snapct_metrics[ MIDX( GAUGE, SNAPCT, LOAD_STATE ) ] );
     604           0 :     ulong consumed, dc_in, dc_out, size_bytes;
     605           0 :     if( FD_UNLIKELY( !strcmp( phase, "incr" ) ) ) {
     606           0 :       consumed   = ULONG_MAX;
     607           0 :       for( ulong i=0UL; i<snapin_tile_cnt; i++ ) consumed = fd_ulong_min( consumed, snapin_all_metrics[ i ][ MIDX( GAUGE, SNAPIN, PARSE_PROGRESS_BYTES_INCREMENTAL ) ] );
     608           0 :       dc_in      = 0UL;
     609           0 :       dc_out     = 0UL;
     610           0 :       for( ulong i=0UL; i<snapdc_tile_cnt; i++ ) {
     611           0 :         dc_in  += snapdc_metrics[ i ][ MIDX( GAUGE, SNAPDC, COMPRESSED_PROGRESS_BYTES_INCREMENTAL ) ];
     612           0 :         dc_out += snapdc_metrics[ i ][ MIDX( GAUGE, SNAPDC, DECOMPRESSED_PROGRESS_BYTES_INCREMENTAL ) ];
     613           0 :       }
     614           0 :       size_bytes = snapct_metrics[ MIDX( GAUGE, SNAPCT, READ_EXPECTED_BYTES_INCREMENTAL ) ];
     615           0 :     } else {
     616           0 :       consumed   = ULONG_MAX;
     617           0 :       for( ulong i=0UL; i<snapin_tile_cnt; i++ ) consumed = fd_ulong_min( consumed, snapin_all_metrics[ i ][ MIDX( GAUGE, SNAPIN, PARSE_PROGRESS_BYTES_FULL ) ] );
     618           0 :       dc_in      = 0UL;
     619           0 :       dc_out     = 0UL;
     620           0 :       for( ulong i=0UL; i<snapdc_tile_cnt; i++ ) {
     621           0 :         dc_in  += snapdc_metrics[ i ][ MIDX( GAUGE, SNAPDC, COMPRESSED_PROGRESS_BYTES_FULL ) ];
     622           0 :         dc_out += snapdc_metrics[ i ][ MIDX( GAUGE, SNAPDC, DECOMPRESSED_PROGRESS_BYTES_FULL ) ];
     623           0 :       }
     624           0 :       size_bytes = snapct_metrics[ MIDX( GAUGE, SNAPCT, READ_EXPECTED_BYTES_FULL ) ];
     625           0 :     }
     626           0 :     double done_comp = dc_out ? (double)dc_in*( (double)consumed/(double)dc_out ) : 0.0;
     627           0 :     double progress  = size_bytes ? clamp_pct( 100.0*done_comp/(double)size_bytes ) : 0.0;
     628             : 
     629           0 :     if( watch ) {
     630           0 :       double snapdc_busy[ FD_TOPO_MAX_TILE_IN_LINKS ];
     631           0 :       double snapdc_busy_avg = 0.0;
     632           0 :       for( ulong i=0UL; i<snapdc_tile_cnt; i++ ) {
     633           0 :         snapdc_busy[ i ] = clamp_pct( 100.0-( ( (double)( snapdc_wait[ i ]-snapdc_wait_old[ i ] )*ns_per_tick )/1e7 ) );
     634           0 :         snapdc_busy_avg += snapdc_busy[ i ];
     635           0 :       }
     636           0 :       snapdc_busy_avg /= (double)snapdc_tile_cnt;
     637             : 
     638           0 :       double snapin_busy[ FD_TOPO_MAX_TILE_IN_LINKS ];
     639           0 :       double snapin_busy_avg = 0.0;
     640           0 :       for( ulong i=0UL; i<snapin_tile_cnt; i++ ) {
     641           0 :         snapin_busy[ i ] = clamp_pct( 100.0-( ( (double)( snapin_wait[ i ]-snapin_wait_old[ i ] )*ns_per_tick )/1e7 ) );
     642           0 :         snapin_busy_avg += snapin_busy[ i ];
     643           0 :       }
     644           0 :       snapin_busy_avg /= (double)snapin_tile_cnt;
     645             : 
     646           0 :       double busy[ 3 ] = {
     647           0 :         clamp_pct( 100.0-( ( (double)( snapld_wait-snapld_wait_old )*ns_per_tick )/1e7 ) ),
     648           0 :         snapdc_busy_avg,
     649           0 :         snapin_busy_avg,
     650           0 :       };
     651             : 
     652           0 :       char bar[ 256 ];
     653           0 :       printf( " %s%4s%s %s %s%5.1f%%%s"
     654           0 :               "  %scomp%s %5.2f %sGB/s%s"
     655           0 :               "  %sraw%s %5.2f %sGB/s%s"
     656           0 :               "  %sacc%s %4.1f %sM/s%s",
     657           0 :               c_dim, phase, c_norm,
     658           0 :               fmt_bar( bar, sizeof(bar), color, progress, 20UL ),
     659           0 :               c_bold, progress, c_norm,
     660           0 :               c_dim, c_norm, (double)( total_off -total_off_old  )/1e9, c_dim, c_norm,
     661           0 :               c_dim, c_norm, (double)( decomp_off-decomp_off_old )/1e9, c_dim, c_norm,
     662           0 :               c_dim, c_norm, (double)fd_ulong_sat_sub( acc_cnt, acc_cnt_old )/1e6, c_dim, c_norm );
     663             : 
     664           0 :       static char const * tile_key[ 3 ] = { "ld", "dc(avg)", "in(avg)" };
     665           0 :       printf( "  %sbusy%s", c_dim, c_norm );
     666           0 :       for( ulong i=0UL; i<3UL; i++ ) {
     667           0 :         printf( " %s%s%s %s%3.0f%s%%%s",
     668           0 :                 c_dim, tile_key[ i ], c_norm,
     669           0 :                 sev_color( color, busy[ i ] ), busy[ i ], c_dim, c_norm );
     670           0 :       }
     671           0 :       for( ulong i=0UL; i<snapdc_tile_cnt; i++ ) {
     672           0 :         printf( " %sdc%lu%s %s%3.0f%s%%%s",
     673           0 :                 c_dim, i, c_norm,
     674           0 :                 sev_color( color, snapdc_busy[ i ] ), snapdc_busy[ i ], c_dim, c_norm );
     675           0 :       }
     676           0 :       for( ulong i=0UL; i<snapin_tile_cnt; i++ ) {
     677           0 :         printf( " %sin%lu%s %s%3.0f%s%%%s",
     678           0 :                 c_dim, i, c_norm,
     679           0 :                 sev_color( color, snapin_busy[ i ] ), snapin_busy[ i ], c_dim, c_norm );
     680           0 :       }
     681           0 :       printf( "\n" );
     682           0 :       fflush( stdout );
     683           0 :     }
     684           0 :     total_off_old    = total_off;
     685           0 :     decomp_off_old   = decomp_off;
     686           0 :     snapld_wait_old  = snapld_wait;
     687           0 :     for( ulong i=0UL; i<snapdc_tile_cnt; i++ ) {
     688           0 :       snapdc_wait_old[ i ] = snapdc_wait[ i ];
     689           0 :     }
     690           0 :     for( ulong i=0UL; i<snapin_tile_cnt; i++ ) {
     691           0 :       snapin_wait_old[ i ] = snapin_wait[ i ];
     692           0 :     }
     693           0 :     acc_cnt_old      = acc_cnt;
     694             : 
     695           0 :     next+=1000L*1000L*1000L;
     696           0 :   }
     697             : 
     698           0 :   if( args->snapshot_load.accounts_hist ) {
     699           0 :     accounts_hist_t hist[1];
     700           0 :     accounts_hist_reset( hist );
     701           0 :     FD_LOG_NOTICE(( "Accounts histogram: starting" ));
     702           0 :     accounts_hist( hist, config );
     703           0 :     FD_TEST( !accounts_hist_check( hist ) );
     704           0 :     accounts_hist_print( hist );
     705           0 :   }
     706           0 : }
     707             : 
     708             : static void
     709           0 : snapshot_load_args_help( fd_action_help_t * help ) {
     710           0 :   fd_action_help_arg( help, "--snapshot-dir",   "<path>",  "Load/save snapshots from this directory" );
     711           0 :   fd_action_help_arg( help, "--offline",        NULL,      "Do not attempt to download snapshots" );
     712           0 :   fd_action_help_arg( help, "--no-incremental", NULL,      "Disable incremental snapshot loading" );
     713           0 :   fd_action_help_arg( help, "--no-watch",       NULL,      "Do not print periodic progress updates" );
     714           0 :   fd_action_help_arg( help, "--db-sz",          "<bytes>", "Accounts cache size in bytes (e.g. 10e9 -> 10 GB)" );
     715           0 :   fd_action_help_arg( help, "--db-rec-max",     "<num>",   "Database max record/account count (e.g. 10e6 -> 10M accounts)" );
     716           0 :   fd_action_help_arg( help, "--fsck",           NULL,      "After loading, run database integrity checks" );
     717           0 :   fd_action_help_arg( help, "--accounts-hist",  NULL,      "After loading, analyze account size distribution" );
     718           0 : }
     719             : 
     720             : action_t fd_action_snapshot_load = {
     721             :   .name        = NAME,
     722             :   .topo        = snapshot_load_topo1,
     723             :   .perm        = dev_cmd_perm,
     724             :   .args        = snapshot_load_args,
     725             :   .fn          = snapshot_load_cmd_fn,
     726             :   .description = "Load a snapshot into a database and optionally inspect it",
     727             :   .detail      = "Boots a reduced topology that downloads (or reads from disk) a full and\n"
     728             :                  "optional incremental snapshot, loads the accounts into a database, and\n"
     729             :                  "can then run integrity checks or analyze the account size distribution.",
     730             :   .usage       = NAME " [OPTIONS]",
     731             :   .args_help   = snapshot_load_args_help,
     732             : };

Generated by: LCOV version 1.14