LCOV - code coverage report
Current view: top level - app/firedancer-dev/commands - backtest.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 406 0.0 %
Date: 2026-01-23 05:02:40 Functions: 0 7 0.0 %

          Line data    Source code
       1             : /* The backtest command spawns a smaller topology for replaying shreds from
       2             :    rocksdb (or other sources TBD) and reproduce the behavior of replay tile.
       3             : 
       4             :    The smaller topology is:
       5             :            shred_out             replay_exec
       6             :    backtest-------------->replay------------->exec
       7             :      ^                    |^ | ^                |
       8             :      |____________________|| | |________________|
       9             :           replay_out       | |   exec_replay
      10             :                            | |------------------------------>no consumer
      11             :     no producer-------------  stake_out, send_out, poh_out
      12             :                 store_replay
      13             : 
      14             : */
      15             : #define _GNU_SOURCE
      16             : #include "../../firedancer/topology.h"
      17             : #include "../../shared/commands/configure/configure.h"
      18             : #include "../../shared/commands/run/run.h" /* initialize_workspaces */
      19             : #include "../../shared/commands/watch/watch.h"
      20             : #include "../../shared/fd_config.h" /* config_t */
      21             : #include "../../../disco/tiles.h"
      22             : #include "../../../disco/topo/fd_topob.h"
      23             : #include "../../../disco/topo/fd_topob_vinyl.h"
      24             : #include "../../../util/pod/fd_pod_format.h"
      25             : #include "../../../discof/replay/fd_replay_tile.h"
      26             : #include "../../../discof/restore/fd_snapin_tile_private.h"
      27             : #include "../../../discof/restore/fd_snaplv_tile_private.h"
      28             : #include "../../../discof/restore/fd_snapwm_tile_private.h"
      29             : #include "../../../discof/restore/utils/fd_slot_delta_parser.h"
      30             : #include "../../../discof/restore/utils/fd_ssctrl.h"
      31             : #include "../../../discof/restore/utils/fd_ssmsg.h"
      32             : #include "../../../discof/tower/fd_tower_tile.h"
      33             : #include "../../../discof/replay/fd_exec.h"
      34             : #include "../../../ballet/lthash/fd_lthash.h"
      35             : #include "../../../flamenco/capture/fd_capture_ctx.h"
      36             : #include "../../../disco/pack/fd_pack_cost.h"
      37             : #include "../../../flamenco/progcache/fd_progcache_admin.h"
      38             : 
      39             : #include "../main.h"
      40             : 
      41             : #include <errno.h>
      42             : #include <unistd.h>
      43             : #include <fcntl.h>
      44             : 
      45             : extern fd_topo_obj_callbacks_t * CALLBACKS[];
      46             : fd_topo_run_tile_t fdctl_tile_run( fd_topo_tile_t const * tile );
      47             : 
      48             : static void
      49           0 : backtest_topo( config_t * config ) {
      50             : 
      51           0 :   config->development.sandbox  = 0;
      52           0 :   config->development.no_clone = 1;
      53             : 
      54           0 :   ulong exec_tile_cnt   = config->firedancer.layout.exec_tile_count;
      55           0 :   ulong lta_tile_cnt    = config->firedancer.layout.snapshot_hash_tile_count;
      56           0 :   ulong snapwr_tile_cnt = config->firedancer.layout.snapwr_tile_count;
      57           0 :   ulong snaplh_tile_cnt = config->firedancer.layout.snapshot_hash_tile_count;
      58             : 
      59           0 :   int disable_snap_loader      = !config->gossip.entrypoints_cnt;
      60           0 :   int vinyl_enabled            = !!config->firedancer.vinyl.enabled;
      61           0 :   int solcap_enabled           = strlen( config->capture.solcap_capture )>0;
      62           0 :   int snapshot_lthash_disabled = config->development.snapshots.disable_lthash_verification;
      63             : 
      64           0 :   fd_topo_t * topo = { fd_topob_new( &config->topo, config->name ) };
      65           0 :   topo->max_page_size = fd_cstr_to_shmem_page_sz( config->hugetlbfs.max_page_size );
      66           0 :   topo->gigantic_page_threshold = config->hugetlbfs.gigantic_page_threshold_mib << 20;
      67             : 
      68           0 :   ulong cpu_idx = 0;
      69             : 
      70           0 :   fd_topob_wksp( topo, "metric" );
      71           0 :   fd_topob_wksp( topo, "metric_in" );
      72           0 :   fd_topob_tile( topo, "metric", "metric", "metric_in", ULONG_MAX, 0, 0 );
      73             : 
      74           0 :   fd_topob_wksp( topo, "backt" );
      75           0 :   fd_topo_tile_t * backt_tile = fd_topob_tile( topo, "backt", "backt", "metric_in", cpu_idx++, 0, 0 );
      76             : 
      77           0 :   fd_topob_wksp( topo, "replay" );
      78           0 :   fd_topo_tile_t * replay_tile = fd_topob_tile( topo, "replay", "replay", "metric_in", cpu_idx++, 0, 0 );
      79             : 
      80             :   /* specified by [tiles.replay] */
      81             : 
      82           0 :   fd_topob_wksp( topo, "funk" );
      83           0 :   fd_topo_obj_t * funk_obj = setup_topo_funk( topo, "funk",
      84           0 :       config->firedancer.funk.max_account_records,
      85           0 :       config->firedancer.funk.max_database_transactions,
      86           0 :       config->firedancer.funk.heap_size_gib );
      87           0 :   fd_topob_tile_uses( topo, replay_tile, funk_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
      88             : 
      89           0 :   fd_topob_wksp( topo, "progcache" );
      90           0 :   fd_topo_obj_t * progcache_obj = setup_topo_progcache( topo, "progcache",
      91           0 :       fd_progcache_est_rec_max( config->firedancer.runtime.program_cache.heap_size_mib<<20,
      92           0 :                                 config->firedancer.runtime.program_cache.mean_cache_entry_size ),
      93           0 :       config->firedancer.funk.max_database_transactions,
      94           0 :       config->firedancer.runtime.program_cache.heap_size_mib<<20 );
      95           0 :   fd_topob_tile_uses( topo, replay_tile, progcache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
      96             : 
      97             :   /**********************************************************************/
      98             :   /* Add the executor tiles to topo                                     */
      99             :   /**********************************************************************/
     100           0 :   fd_topob_wksp( topo, "exec" );
     101           0 :   #define FOR(cnt) for( ulong i=0UL; i<cnt; i++ )
     102           0 :   FOR(exec_tile_cnt) fd_topob_tile( topo, "exec", "exec", "metric_in", cpu_idx++, 0, 0 );
     103             : 
     104             :   /**********************************************************************/
     105             :   /* Add the capture tile to topo                                       */
     106             :   /**********************************************************************/
     107           0 :   if( solcap_enabled ) {
     108           0 :     fd_topob_wksp( topo, "solcap" );
     109           0 :     fd_topob_tile( topo, "solcap", "solcap", "metric_in", cpu_idx++, 0, 0 );
     110           0 :   }
     111             : 
     112             :   /**********************************************************************/
     113             :   /* Add the snapshot tiles to topo                                       */
     114             :   /**********************************************************************/
     115           0 :   fd_topo_tile_t * snapin_tile = NULL;
     116           0 :   if( FD_UNLIKELY( !disable_snap_loader ) ) {
     117           0 :     fd_topob_wksp( topo, "snapct" );
     118           0 :     fd_topob_wksp( topo, "snapld" );
     119           0 :     fd_topob_wksp( topo, "snapdc" );
     120           0 :     fd_topob_wksp( topo, "snapin" );
     121             : 
     122           0 :     fd_topo_tile_t * snapct_tile = fd_topob_tile( topo, "snapct",  "snapct",  "metric_in",  cpu_idx++, 0, 0 );
     123           0 :     fd_topo_tile_t * snapld_tile = fd_topob_tile( topo, "snapld",  "snapld",  "metric_in",  cpu_idx++, 0, 0 );
     124           0 :     fd_topo_tile_t * snapdc_tile = fd_topob_tile( topo, "snapdc",  "snapdc",  "metric_in",  cpu_idx++, 0, 0 );
     125           0 :                      snapin_tile = fd_topob_tile( topo, "snapin",  "snapin",  "metric_in",  cpu_idx++, 0, 0 );
     126             : 
     127           0 :     snapct_tile->allow_shutdown = 1;
     128           0 :     snapld_tile->allow_shutdown = 1;
     129           0 :     snapdc_tile->allow_shutdown = 1;
     130           0 :     snapin_tile->allow_shutdown = 1;
     131             : 
     132           0 :     if( vinyl_enabled ) {
     133           0 :       fd_topob_wksp( topo, "snapwm" );
     134           0 :       fd_topo_tile_t * snapwm_tile = fd_topob_tile( topo, "snapwm", "snapwm", "metric_in", cpu_idx++, 0, 0 );
     135           0 :       snapwm_tile->allow_shutdown = 1;
     136             : 
     137           0 :       fd_topob_wksp( topo, "snapwh" );
     138           0 :       fd_topo_tile_t * snapwh_tile = fd_topob_tile( topo, "snapwh", "snapwh", "metric_in", cpu_idx++, 0, 0 );
     139           0 :       snapwh_tile->allow_shutdown = 1;
     140             : 
     141           0 :       fd_topob_wksp( topo, "snapwr" );
     142           0 :       FOR(snapwr_tile_cnt) fd_topob_tile( topo, "snapwr", "snapwr", "metric_in", cpu_idx++, 0, 0 )->allow_shutdown = 1;
     143           0 :     }
     144             : 
     145           0 :     if( snapshot_lthash_disabled ) {
     146             :       /* nothing to do here */
     147           0 :     } else {
     148           0 :       if( vinyl_enabled ) {
     149           0 :         fd_topob_wksp( topo, "snaplh"    );
     150           0 :         fd_topob_wksp( topo, "snaplv"    );
     151           0 :         FOR(snaplh_tile_cnt) fd_topob_tile( topo, "snaplh", "snaplh", "metric_in", ULONG_MAX, 0, 0 )->allow_shutdown = 1;
     152           0 :         /**/                 fd_topob_tile( topo, "snaplv", "snaplv", "metric_in", ULONG_MAX, 0, 0 )->allow_shutdown = 1;
     153           0 :       } else {
     154           0 :         fd_topob_wksp( topo, "snapla" );
     155           0 :         fd_topob_wksp( topo, "snapls" );
     156           0 :         FOR(lta_tile_cnt)  fd_topob_tile( topo, "snapla", "snapla", "metric_in", cpu_idx++,  0, 0 )->allow_shutdown = 1;
     157           0 :         /**/               fd_topob_tile( topo, "snapls", "snapls", "metric_in", cpu_idx++,  0, 0 )->allow_shutdown = 1;
     158           0 :       }
     159           0 :     }
     160             : 
     161           0 :   } else {
     162           0 :     fd_topob_wksp( topo, "genesi" );
     163           0 :     fd_topob_tile( topo, "genesi",  "genesi",  "metric_in",  cpu_idx++, 0, 0 )->allow_shutdown = 1;
     164           0 :   }
     165             : 
     166             :   /**********************************************************************/
     167             :   /* Setup backtest->replay link (shred_out) in topo                 */
     168             :   /**********************************************************************/
     169             : 
     170             :   /* The repair tile is replaced by the backtest tile for the repair to
     171             :      replay link.  The frag interface is a "slice", ie. entry batch,
     172             :      which is provided by the backtest tile, which reads in the entry
     173             :      batches from the CLI-specified source (eg. RocksDB). */
     174             : 
     175           0 :   fd_topob_wksp( topo, "shred_out" );
     176           0 :   fd_topob_link( topo, "shred_out", "shred_out", 65536UL, FD_SHRED_OUT_MTU, 1UL );
     177           0 :   fd_topob_tile_in( topo, "replay", 0UL, "metric_in", "shred_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     178           0 :   fd_topob_tile_out( topo, "backt", 0UL, "shred_out", 0UL );
     179             : 
     180             :   /**********************************************************************/
     181             :   /* Setup snapshot links in topo                                       */
     182             :   /**********************************************************************/
     183           0 :   if( FD_LIKELY( !disable_snap_loader ) ) {
     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 :     if( vinyl_enabled ) {
     192           0 :       fd_topob_wksp( topo, "snapin_txn");
     193           0 :       fd_topob_wksp( topo, "snapin_wm" );
     194           0 :       fd_topob_wksp( topo, "snapwm_wr" );
     195           0 :     }
     196           0 :     if( snapshot_lthash_disabled ) {
     197           0 :       if( vinyl_enabled ) {
     198           0 :         fd_topob_wksp( topo, "snapwm_ct" );
     199           0 :       } else {
     200           0 :         fd_topob_wksp( topo, "snapin_ct" );
     201           0 :       }
     202           0 :     } else {
     203           0 :       if( vinyl_enabled ) {
     204           0 :         fd_topob_wksp( topo, "snaplv_lh" );
     205           0 :         fd_topob_wksp( topo, "snaplh_lv" );
     206           0 :         fd_topob_wksp( topo, "snapwm_lv" );
     207           0 :         fd_topob_wksp( topo, "snaplv_ct" );
     208           0 :         fd_topob_wksp( topo, "snaplv_wr" );
     209           0 :       } else {
     210           0 :         fd_topob_wksp( topo, "snapla_ls" );
     211           0 :         fd_topob_wksp( topo, "snapin_ls" );
     212           0 :         fd_topob_wksp( topo, "snapls_ct" );
     213           0 :       }
     214           0 :     }
     215             : 
     216           0 :     fd_topob_link( topo, "snapct_ld",    "snapct_ld",    128UL,   sizeof(fd_ssctrl_init_t),       1UL );
     217           0 :     fd_topob_link( topo, "snapld_dc",    "snapld_dc",    16384UL, USHORT_MAX,                     1UL );
     218           0 :     fd_topob_link( topo, "snapdc_in",    "snapdc_in",    16384UL, USHORT_MAX,                     1UL );
     219             : 
     220           0 :     fd_topob_link( topo, "snapin_manif", "snapin_manif", 4UL,     sizeof(fd_snapshot_manifest_t), 1UL ); /* TODO: Should be depth 1 or 2 but replay backpressures */
     221           0 :     fd_topob_link( topo, "snapct_repr",  "snapct_repr",  128UL,   0UL,                            1UL )->permit_no_consumers = 1;
     222             : 
     223           0 :     if( vinyl_enabled ) {
     224             :       /* snapwm needs all txn_cache data in order to verify the slot
     225             :        deltas with the slot history.  To make this possible, snapin
     226             :        uses the dcache of the snapin_txn link as the scratch memory.
     227             :        The depth of the link should match that of snapin_wm, just to
     228             :        guarantee enough mcache credits.  The mtu needs to be adjusted
     229             :        so that the total dcache size matches what snapin requires.
     230             :        Round up the mtu (ulong) size using: (...+(depth-1))/depth. */
     231           0 :       fd_topob_link( topo, "snapin_txn", "snapin_txn",   16UL, (sizeof(fd_sstxncache_entry_t)*FD_SNAPIN_TXNCACHE_MAX_ENTRIES+15UL/*depth-1*/)/16UL/*depth*/, 1UL );
     232           0 :       fd_topob_link( topo, "snapin_wm", "snapin_wm",     16UL, FD_SNAPWM_PAIR_BATCH_SZ_MAX,       1UL );
     233             :       /* snapwh and snapwr both use snapwm_wh's dcache.  snapwh sends
     234             :          control messages to snapwr, using snapwh_wr link, instructing
     235             :          which chunks in the dcache are ready to be consumed by snapwr. */
     236           0 :       fd_topo_link_t * snapwm_wh =
     237           0 :       fd_topob_link( topo, "snapwm_wh", "snapwm_wr",     64UL, FD_SNAPWM_WR_MTU,                  1UL );
     238           0 :       fd_topob_link( topo, "snapwh_wr", "snapwm_wr",     64UL, 0UL,                               1UL );
     239           0 :       fd_pod_insertf_ulong( topo->props, 8UL, "obj.%lu.app_sz",  snapwm_wh->dcache_obj_id );
     240           0 :     }
     241           0 :     if( snapshot_lthash_disabled ) {
     242           0 :       if( vinyl_enabled ) {
     243           0 :         fd_topob_link( topo, "snapwm_ct", "snapwm_ct",   128UL,   0UL,                            1UL );
     244           0 :       } else {
     245           0 :         fd_topob_link( topo, "snapin_ct", "snapin_ct",   128UL,  0UL,                             1UL );
     246           0 :       }
     247           0 :     } else {
     248           0 :       if( vinyl_enabled ) {
     249           0 :         FOR(snaplh_tile_cnt) fd_topob_link( topo, "snaplh_lv",  "snaplh_lv",    128UL,   sizeof(fd_lthash_value_t),     1UL );
     250           0 :         /**/                 fd_topob_link( topo, "snapwm_lv",  "snapwm_lv",  32768UL, FD_SNAPWM_DUP_META_BATCH_SZ,     1UL );
     251           0 :         /**/                 fd_topob_link( topo, "snaplv_lh",  "snaplv_lh", 262144UL,       FD_SNAPLV_DUP_META_SZ, FD_SNAPLV_STEM_BURST ); /* FD_SNAPWM_DUP_META_BATCH_CNT_MAX times the depth of snapwm_lv */
     252           0 :         /**/                 fd_topob_link( topo, "snaplv_ct",  "snaplv_ct",    128UL,                         0UL,     1UL );
     253           0 :         /**/                 fd_topob_link( topo, "snaplv_wr",  "snaplv_wr",    128UL,                         0UL,     1UL ); /* no dcache, only mcache fseq is used on this link. */
     254           0 :       } else {
     255           0 :         FOR(lta_tile_cnt) fd_topob_link( topo, "snapla_ls",  "snapla_ls",   128UL,  sizeof(fd_lthash_value_t),          1UL );
     256           0 :         /**/              fd_topob_link( topo, "snapin_ls",  "snapin_ls",   256UL,  sizeof(fd_snapshot_full_account_t), 1UL );
     257           0 :         /**/              fd_topob_link( topo, "snapls_ct",  "snapls_ct",   128UL,  0UL,                                1UL );
     258           0 :       }
     259           0 :     }
     260             : 
     261           0 :     if( snapshot_lthash_disabled ) {
     262           0 :       if( vinyl_enabled ) {
     263           0 :         fd_topob_tile_in ( topo, "snapct",  0UL, "metric_in", "snapwm_ct",  0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     264           0 :       } else {
     265           0 :         fd_topob_tile_in ( topo, "snapct",  0UL, "metric_in", "snapin_ct",  0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     266           0 :       }
     267           0 :     } else {
     268           0 :       if( vinyl_enabled ) {
     269           0 :         fd_topob_tile_in ( topo, "snapct",  0UL, "metric_in", "snaplv_ct",  0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     270           0 :       } else {
     271           0 :         fd_topob_tile_in ( topo, "snapct",  0UL, "metric_in", "snapls_ct", 0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED  );
     272           0 :       }
     273           0 :     }
     274             : 
     275           0 :     fd_topob_tile_in ( topo, "snapct",  0UL, "metric_in", "snapld_dc",    0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     276           0 :     fd_topob_tile_out( topo, "snapct",  0UL,              "snapct_ld",    0UL                                       );
     277           0 :     fd_topob_tile_out( topo, "snapct",  0UL,              "snapct_repr",  0UL                                       );
     278           0 :     fd_topob_tile_in ( topo, "snapld",  0UL, "metric_in", "snapct_ld",    0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     279           0 :     fd_topob_tile_out( topo, "snapld",  0UL,              "snapld_dc",    0UL                                       );
     280           0 :     fd_topob_tile_in ( topo, "snapdc",  0UL, "metric_in", "snapld_dc",    0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     281           0 :     fd_topob_tile_out( topo, "snapdc",  0UL,              "snapdc_in",    0UL                                       );
     282           0 :     fd_topob_tile_in ( topo, "snapin",  0UL, "metric_in", "snapdc_in",    0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     283             : 
     284           0 :     fd_topob_tile_out( topo, "snapin",  0UL,              "snapin_manif", 0UL                                       );
     285           0 :     fd_topob_tile_in ( topo, "replay",  0UL, "metric_in", "snapin_manif", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED   );
     286             : 
     287           0 :     if( vinyl_enabled ) {
     288           0 :       fd_topob_tile_out( topo, "snapin", 0UL,              "snapin_wm", 0UL );
     289           0 :       fd_topob_tile_in ( topo, "snapwm", 0UL, "metric_in", "snapin_wm", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     290           0 :       fd_topob_tile_out( topo, "snapin", 0UL,              "snapin_txn",0UL );
     291           0 :       fd_topob_tile_in ( topo, "snapwm", 0UL, "metric_in", "snapin_txn",0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     292           0 :       fd_topob_tile_out( topo, "snapwm", 0UL,              "snapwm_wh", 0UL );
     293           0 :       fd_topob_tile_in ( topo, "snapwh", 0UL, "metric_in", "snapwm_wh", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     294           0 :       fd_topob_tile_out( topo, "snapwh", 0UL,              "snapwh_wr", 0UL );
     295             :       /* snapwh and snapwr both access snapwm_wh's dcache, avoiding a
     296             :          memcpy for every account (vinyl pair) that is being processed
     297             :          (loaded) from the snapshot. */
     298           0 :       FOR(snapwr_tile_cnt) fd_topob_tile_in ( topo, "snapwr", i, "metric_in", "snapwh_wr", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     299           0 :       FOR(snapwr_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapwr", i ) ], &topo->objs[ topo->links[ fd_topo_find_link( topo, "snapwm_wh", 0UL ) ].dcache_obj_id ], FD_SHMEM_JOIN_MODE_READ_ONLY );
     300           0 :     }
     301           0 :     if( snapshot_lthash_disabled ) {
     302           0 :       if( vinyl_enabled ) {
     303           0 :         /**/                fd_topob_tile_out( topo, "snapwm",  0UL,              "snapwm_ct",  0UL                                       );
     304           0 :       } else {
     305           0 :         /**/                fd_topob_tile_out( topo, "snapin", 0UL,               "snapin_ct",  0UL                                       );
     306           0 :       }
     307           0 :     } else {
     308           0 :       if( vinyl_enabled ) {
     309           0 :         FOR(snaplh_tile_cnt) fd_topob_tile_in ( topo, "snaplh", i,   "metric_in", "snapwh_wr",  0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     310           0 :         FOR(snaplh_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snaplh", i ) ], &topo->objs[ topo->links[ fd_topo_find_link( topo, "snapwm_wh", 0UL ) ].dcache_obj_id ], FD_SHMEM_JOIN_MODE_READ_ONLY );
     311           0 :         FOR(snaplh_tile_cnt) fd_topob_tile_in ( topo, "snaplh", i,   "metric_in", "snaplv_lh",  0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     312           0 :         /**/                 fd_topob_tile_out( topo, "snaplv", 0UL,              "snaplv_lh",  0UL                                       );
     313           0 :         FOR(snaplh_tile_cnt) fd_topob_tile_out( topo, "snaplh", i,                "snaplh_lv",  i                                         );
     314           0 :         /**/                 fd_topob_tile_in ( topo, "snaplv", 0UL, "metric_in", "snapwm_lv",  0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     315           0 :         FOR(snaplh_tile_cnt) fd_topob_tile_in ( topo, "snaplv", 0UL, "metric_in", "snaplh_lv",  i,   FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     316           0 :         /**/                 fd_topob_tile_out( topo, "snaplv", 0UL,              "snaplv_wr",  0UL                                       );
     317           0 :         FOR(snapwr_tile_cnt) fd_topob_tile_in ( topo, "snapwr", i,   "metric_in", "snaplv_wr",  0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     318           0 :         /**/                 fd_topob_tile_out( topo, "snaplv", 0UL,              "snaplv_ct",  0UL                                       );
     319           0 :         /**/                 fd_topob_tile_out( topo, "snapwm", 0UL,              "snapwm_lv",  0UL                                       );
     320           0 :         FOR(snapwr_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapwr", i ) ], &topo->objs[ topo->links[ fd_topo_find_link( topo, "snaplv_wr", 0UL ) ].mcache_obj_id ], FD_SHMEM_JOIN_MODE_READ_WRITE );
     321           0 :       } else {
     322           0 :         FOR(lta_tile_cnt)    fd_topob_tile_in ( topo, "snapla", i,   "metric_in", "snapdc_in",  0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     323           0 :         FOR(lta_tile_cnt)    fd_topob_tile_out( topo, "snapla", i,                "snapla_ls",  i                                         );
     324           0 :         /**/                 fd_topob_tile_in ( topo, "snapls", 0UL, "metric_in", "snapin_ls",  0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     325           0 :         FOR(lta_tile_cnt)    fd_topob_tile_in ( topo, "snapls", 0UL, "metric_in", "snapla_ls",  i,   FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     326           0 :         /**/                 fd_topob_tile_out( topo, "snapls", 0UL,              "snapls_ct",  0UL                                       );
     327           0 :         /**/                 fd_topob_tile_out( topo, "snapin", 0UL,              "snapin_ls",  0UL                                       );
     328           0 :       }
     329           0 :     }
     330           0 :   } else {
     331           0 :     fd_topob_wksp( topo, "genesi_out" );
     332           0 :     fd_topob_link( topo, "genesi_out", "genesi_out", 2UL, 10UL*1024UL*1024UL+32UL+sizeof(fd_lthash_value_t), 1UL );
     333           0 :     fd_topob_tile_out( topo, "genesi", 0UL, "genesi_out", 0UL );
     334           0 :     fd_topob_tile_in ( topo, "replay", 0UL, "metric_in", "genesi_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     335           0 :   }
     336             : 
     337           0 :   if( vinyl_enabled ) {
     338           0 :     setup_topo_accdb_meta( topo, &config->firedancer );
     339             : 
     340           0 :     fd_topo_obj_t * accdb_data = setup_topo_accdb_cache( topo, &config->firedancer );
     341             : 
     342           0 :     fd_topob_wksp( topo, "accdb_exec" );
     343           0 :     fd_topo_tile_t * accdb_tile = fd_topob_tile( topo, "accdb", "accdb_exec", "metric_in", cpu_idx++, 0, 0 );
     344           0 :     fd_topob_tile_uses( topo, accdb_tile,  accdb_data, FD_SHMEM_JOIN_MODE_READ_WRITE );
     345           0 :     fd_topob_tile_uses( topo, replay_tile, accdb_data, FD_SHMEM_JOIN_MODE_READ_WRITE );
     346           0 :     for( ulong i=0UL; i<exec_tile_cnt; i++ ) {
     347           0 :       fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "exec", i ) ], accdb_data, FD_SHMEM_JOIN_MODE_READ_WRITE );
     348           0 :     }
     349             : 
     350           0 :     fd_topob_wksp( topo, "accdb_replay" );
     351           0 :   }
     352             : 
     353             :   /**********************************************************************/
     354             :   /* More backtest->replay links in topo                                */
     355             :   /**********************************************************************/
     356             : 
     357             :   /* The tower tile is replaced by the backtest tile for the tower to
     358             :      replay link.  The backtest tile simply sends monotonically
     359             :      increasing rooted slot numbers to the replay tile, once after each
     360             :      "replayed a full slot" notification received from the replay tile.
     361             :      This allows the replay tile to advance its watermark, and publish
     362             :      various data structures.  This is an oversimplified barebones mock
     363             :      of the tower tile. */
     364           0 :   fd_topob_wksp( topo, "tower_out" );
     365           0 :   fd_topob_link( topo, "tower_out", "tower_out", 1024UL, sizeof(fd_tower_slot_done_t), 1UL );
     366           0 :   fd_topob_tile_in( topo, "replay", 0UL, "metric_in", "tower_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     367           0 :   fd_topob_tile_out( topo, "backt", 0UL, "tower_out", 0UL );
     368             : 
     369             :   /**********************************************************************/
     370             :   /* Setup replay->stake/send/poh links in topo w/o consumers         */
     371             :   /**********************************************************************/
     372           0 :   fd_topob_wksp( topo, "replay_epoch"    );
     373           0 :   fd_topob_wksp( topo, "replay_poh"   );
     374             : 
     375           0 :   fd_topob_link( topo, "replay_epoch", "replay_epoch", 128UL, FD_EPOCH_OUT_MTU, 1UL );
     376           0 :   ulong bank_tile_cnt   = config->layout.bank_tile_count;
     377           0 :   FOR(bank_tile_cnt) fd_topob_link( topo, "replay_poh", "replay_poh", 128UL, (4096UL*sizeof(fd_txn_p_t))+sizeof(fd_microblock_trailer_t), 1UL );
     378             : 
     379           0 :   fd_topob_tile_out( topo, "replay", 0UL, "replay_epoch",   0UL );
     380           0 :   FOR(bank_tile_cnt) fd_topob_tile_out( topo, "replay", 0UL, "replay_poh", i );
     381             : 
     382           0 :   topo->links[ replay_tile->out_link_id[ fd_topo_find_tile_out_link( topo, replay_tile, "replay_epoch",   0 ) ] ].permit_no_consumers = 1;
     383           0 :   FOR(bank_tile_cnt) topo->links[ replay_tile->out_link_id[ fd_topo_find_tile_out_link( topo, replay_tile, "replay_poh", i ) ] ].permit_no_consumers = 1;
     384             : 
     385             :   /**********************************************************************/
     386             :   /* Setup replay->backtest link (replay_notif) in topo                 */
     387             :   /**********************************************************************/
     388             : 
     389           0 :   fd_topob_wksp( topo, "replay_out" );
     390           0 :   fd_topob_link( topo, "replay_out", "replay_out", 8192UL, sizeof( fd_replay_message_t ), 1UL );
     391           0 :   fd_topob_tile_out( topo, "replay", 0UL, "replay_out", 0UL );
     392           0 :   fd_topob_tile_in ( topo, "backt", 0UL, "metric_in", "replay_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     393           0 :   if( FD_LIKELY( !disable_snap_loader ) ) {
     394           0 :     fd_topob_tile_in ( topo, "backt", 0UL, "metric_in", "snapin_manif", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     395           0 :   } else {
     396           0 :     fd_topob_tile_in ( topo, "backt", 0UL, "metric_in", "genesi_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     397           0 :   }
     398             : 
     399             :   /**********************************************************************/
     400             :   /* Setup replay->exec link in topo                                    */
     401             :   /**********************************************************************/
     402           0 :   fd_topob_wksp( topo, "replay_exec" );
     403           0 :   fd_topob_link( topo, "replay_exec", "replay_exec", 16384UL, 2240UL, 1UL );
     404           0 :   fd_topob_tile_out( topo, "replay", 0UL, "replay_exec", 0UL );
     405           0 :   for( ulong i=0UL; i<exec_tile_cnt; i++ ) {
     406           0 :     fd_topob_tile_in( topo, "exec", i, "metric_in", "replay_exec", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     407           0 :   }
     408             : 
     409             :   /**********************************************************************/
     410             :   /* Setup exec->replay links in topo, to send solcap account updates
     411             :      so that they are serialized, and to notify replay tile that a txn
     412             :      has been finalized by the exec tile. */
     413             :   /**********************************************************************/
     414           0 :   fd_topob_wksp( topo, "exec_replay" );
     415             : 
     416           0 :   FOR(exec_tile_cnt) fd_topob_link( topo, "exec_replay", "exec_replay", 16384UL, sizeof(fd_exec_task_done_msg_t), 1UL );
     417             : 
     418           0 :   FOR(exec_tile_cnt) fd_topob_tile_out( topo, "exec", i, "exec_replay", i );
     419           0 :   FOR(exec_tile_cnt) fd_topob_tile_in( topo, "replay", 0UL, "metric_in", "exec_replay", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     420             : 
     421             :   /**********************************************************************/
     422             :   /* Setup the shared objs used by replay and exec tiles                */
     423             :   /**********************************************************************/
     424             : 
     425           0 :   if( FD_UNLIKELY( solcap_enabled ) ) {
     426             :     /* 32 sections of SOLCAP_WRITE_ACCOUNT_DATA_MTU bytes each ≈ 4MB.
     427             :        This is done to ideally avoid cache thrashing and allow for all
     428             :        the links to sit on L3 cache. */
     429           0 :     fd_topob_link( topo, "cap_repl", "solcap", 32UL, SOLCAP_WRITE_ACCOUNT_DATA_MTU, 1UL );
     430           0 :     fd_topob_tile_out( topo, "replay", 0UL, "cap_repl", 0UL );
     431           0 :     fd_topob_tile_in( topo, "solcap", 0UL, "metric_in", "cap_repl", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     432           0 :     FOR(exec_tile_cnt) fd_topob_link( topo, "cap_exec", "solcap", 32UL, SOLCAP_WRITE_ACCOUNT_DATA_MTU, 1UL );
     433           0 :     FOR(exec_tile_cnt) fd_topob_tile_out( topo, "exec", i, "cap_exec", i );
     434           0 :     FOR(exec_tile_cnt) fd_topob_tile_in( topo, "solcap", 0UL, "metric_in", "cap_exec", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     435           0 :   }
     436             : 
     437           0 :   fd_topob_wksp( topo, "store" );
     438           0 :   fd_topo_obj_t * store_obj = setup_topo_store( topo, "store", config->firedancer.runtime.max_live_slots * FD_SHRED_BLK_MAX, 1 );
     439           0 :   fd_topob_tile_uses( topo, backt_tile, store_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     440           0 :   fd_topob_tile_uses( topo, replay_tile, store_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     441           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, store_obj->id, "store" ) );
     442             : 
     443           0 :   fd_topo_obj_t * acc_pool_obj = setup_topo_acc_pool( topo, config->firedancer.runtime.max_account_cnt );
     444           0 :   fd_topob_tile_uses( topo, replay_tile, acc_pool_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     445           0 :   FOR(exec_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "exec", i ) ], acc_pool_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     446           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, acc_pool_obj->id, "acc_pool" ) );
     447             : 
     448             :   /* banks_obj shared by replay and exec tiles */
     449           0 :   fd_topob_wksp( topo, "banks" );
     450           0 :   fd_topo_obj_t * banks_obj = setup_topo_banks( topo, "banks", config->firedancer.runtime.max_live_slots, config->firedancer.runtime.max_fork_width, 0 );
     451           0 :   fd_topob_tile_uses( topo, replay_tile, banks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     452           0 :   FOR(exec_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "exec", i ) ], banks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     453           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, banks_obj->id, "banks" ) );
     454             : 
     455             :   /* banks_locks_obj shared by replay and exec tiles */
     456           0 :   fd_topob_wksp( topo, "banks_locks" );
     457           0 :   fd_topo_obj_t * banks_locks_obj = setup_topo_banks_locks( topo, "banks_locks" );
     458           0 :   fd_topob_tile_uses( topo, replay_tile, banks_locks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     459           0 :   FOR(exec_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "exec", i ) ], banks_locks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     460           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, banks_locks_obj->id, "banks_locks" ) );
     461             : 
     462             :   /* txncache_obj, busy_obj and poh_slot_obj only by replay tile */
     463           0 :   fd_topob_wksp( topo, "txncache"    );
     464           0 :   fd_topob_wksp( topo, "bank_busy"   );
     465           0 :   fd_topo_obj_t * txncache_obj = setup_topo_txncache( topo, "txncache",
     466           0 :       config->firedancer.runtime.max_live_slots,
     467           0 :       fd_ulong_pow2_up( FD_PACK_MAX_TXNCACHE_TXN_PER_SLOT ) );
     468           0 :   fd_topob_tile_uses( topo, replay_tile, txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     469           0 :   if( FD_LIKELY( !disable_snap_loader ) ) {
     470           0 :     fd_topob_tile_uses( topo, snapin_tile, txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     471           0 :     if( vinyl_enabled ) {
     472           0 :       ulong vinyl_map_obj_id  = fd_pod_query_ulong( topo->props, "accdb.meta_map",  ULONG_MAX ); FD_TEST( vinyl_map_obj_id !=ULONG_MAX );
     473           0 :       ulong vinyl_pool_obj_id = fd_pod_query_ulong( topo->props, "accdb.meta_pool", ULONG_MAX ); FD_TEST( vinyl_pool_obj_id!=ULONG_MAX );
     474           0 :       fd_topo_obj_t * vinyl_map_obj  = &topo->objs[ vinyl_map_obj_id ];
     475           0 :       fd_topo_obj_t * vinyl_pool_obj = &topo->objs[ vinyl_pool_obj_id ];
     476           0 :       fd_topob_tile_uses( topo, snapin_tile, vinyl_map_obj,  FD_SHMEM_JOIN_MODE_READ_WRITE );
     477           0 :       fd_topob_tile_uses( topo, snapin_tile, vinyl_pool_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     478           0 :     }
     479           0 :   }
     480           0 :   for( ulong i=0UL; i<exec_tile_cnt; i++ ) {
     481           0 :     fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "exec", i ) ], txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     482           0 :   }
     483             : 
     484           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, txncache_obj->id, "txncache" ) );
     485           0 :   for( ulong i=0UL; i<bank_tile_cnt; i++ ) {
     486           0 :     fd_topo_obj_t * busy_obj = fd_topob_obj( topo, "fseq", "bank_busy" );
     487           0 :     fd_topob_tile_uses( topo, replay_tile, busy_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     488           0 :     FD_TEST( fd_pod_insertf_ulong( topo->props, busy_obj->id, "bank_busy.%lu", i ) );
     489           0 :   }
     490             : 
     491           0 :   if( FD_LIKELY( !disable_snap_loader ) ) {
     492           0 :     fd_topob_tile_uses( topo, snapin_tile, funk_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     493           0 :   }
     494             : 
     495           0 :   if( vinyl_enabled ) {
     496           0 :     fd_topob_vinyl_rq( topo, "replay", 0UL, "accdb_replay", "replay", 4UL, 1024UL, 1024UL );
     497           0 :     for( ulong i=0UL; i<exec_tile_cnt; i++ ) {
     498           0 :       fd_topob_vinyl_rq( topo, "exec", i, "accdb_exec", "exec", 4UL, 1024UL, 1024UL );
     499           0 :     }
     500           0 :   }
     501             : 
     502           0 :   for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
     503           0 :     fd_topo_tile_t * tile = &topo->tiles[ i ];
     504           0 :     fd_topo_configure_tile( tile, config );
     505             : 
     506           0 :     if( !strcmp( tile->name, "replay" ) ) {
     507           0 :       tile->replay.enable_features_cnt = config->tiles.replay.enable_features_cnt;
     508           0 :       for( ulong i = 0; i < tile->replay.enable_features_cnt; i++ ) {
     509           0 :         strncpy( tile->replay.enable_features[i], config->tiles.replay.enable_features[i], sizeof(tile->replay.enable_features[i]) );
     510           0 :       }
     511           0 :     }
     512           0 :   }
     513             : 
     514             :   // fd_topob_auto_layout( topo, 0 );
     515           0 :   fd_topob_finish( topo, CALLBACKS );
     516           0 : }
     517             : 
     518             : extern int * fd_log_private_shared_lock;
     519             : 
     520             : static void
     521           0 : backtest_cmd_topo( config_t * config ) {
     522           0 :   backtest_topo( config );
     523           0 : }
     524             : 
     525             : extern configure_stage_t fd_cfg_stage_accdb;
     526             : 
     527             : static args_t
     528           0 : configure_args( void ) {
     529           0 :   args_t args = {
     530           0 :     .configure.command = CONFIGURE_CMD_INIT,
     531           0 :   };
     532             : 
     533           0 :   ulong stage_idx = 0UL;
     534           0 :   args.configure.stages[ stage_idx++ ] = &fd_cfg_stage_hugetlbfs;
     535           0 :   args.configure.stages[ stage_idx++ ] = &fd_cfg_stage_snapshots;
     536           0 :   args.configure.stages[ stage_idx++ ] = &fd_cfg_stage_accdb;
     537           0 :   args.configure.stages[ stage_idx++ ] = NULL;
     538             : 
     539           0 :   return args;
     540           0 : }
     541             : 
     542             : void
     543             : backtest_cmd_args( int *    pargc,
     544             :                    char *** pargv,
     545           0 :                    args_t * args ) {
     546           0 :   char const * db         = fd_env_strip_cmdline_cstr( pargc, pargv, "--db", NULL,   "funk"     );
     547           0 :   char const * vinyl_path = fd_env_strip_cmdline_cstr( pargc, pargv, "--vinyl-path", NULL, NULL );
     548           0 :   char const * vinyl_io   = fd_env_strip_cmdline_cstr( pargc, pargv, "--vinyl-io",   NULL, "bd" );
     549             : 
     550           0 :   args->backtest.no_watch = fd_env_strip_cmdline_contains( pargc, pargv, "--no-watch" );
     551             : 
     552           0 :   if(      0==strcmp( db, "funk"  ) ) args->backtest.is_vinyl = 0;
     553           0 :   else if( 0==strcmp( db, "vinyl" ) ) args->backtest.is_vinyl = 1;
     554           0 :   else FD_LOG_ERR(( "invalid --db '%s' (must be 'funk' or 'vinyl')", db ));
     555             : 
     556           0 :   fd_cstr_ncpy( args->backtest.vinyl_path, vinyl_path, sizeof(args->backtest.vinyl_path) );
     557             : 
     558           0 :   if( FD_UNLIKELY( strlen( vinyl_io )!=2UL ) ) FD_LOG_ERR(( "invalid --vinyl-io '%s'", vinyl_io ));
     559           0 :   fd_cstr_ncpy( args->backtest.vinyl_io, vinyl_io, sizeof(args->backtest.vinyl_io) );
     560           0 : }
     561             : 
     562             : void
     563             : backtest_cmd_perm( args_t *         args FD_PARAM_UNUSED,
     564             :                    fd_cap_chk_t *   chk,
     565           0 :                    config_t const * config ) {
     566           0 :   args_t c_args = configure_args();
     567           0 :   configure_cmd_perm( &c_args, chk, config );
     568           0 :   run_cmd_perm( NULL, chk, config );
     569           0 : }
     570             : 
     571             : static void
     572             : fixup_config( config_t *     config,
     573           0 :               args_t const * args ) {
     574           0 :   if( args->backtest.vinyl_path[0] ) {
     575           0 :     fd_cstr_ncpy( config->paths.accounts, args->backtest.vinyl_path, sizeof(config->paths.accounts) );
     576           0 :   }
     577             : 
     578           0 :   if( args->backtest.is_vinyl ) {
     579           0 :     config->firedancer.vinyl.enabled = 1;
     580             : 
     581           0 :     config->firedancer.vinyl.file_size_gib       = config->firedancer.funk.heap_size_gib;
     582           0 :     config->firedancer.vinyl.max_account_records = config->firedancer.funk.max_account_records;
     583             : 
     584           0 :     char const * io_mode = args->backtest.vinyl_io;
     585           0 :     if(      0==strcmp( io_mode, "ur" ) ) config->firedancer.vinyl.io_uring.enabled = 1;
     586           0 :     else if( 0==strcmp( io_mode, "bd" ) ) {}
     587           0 :     else FD_LOG_ERR(( "unsupported --vinyl-io '%s' (valid options are 'bd' and 'ur')", io_mode ));
     588           0 :   }
     589             : 
     590             :   /* FIXME Unfortunately, the fdctl boot procedure constructs the
     591             :            topology before parsing command-line arguments.  So, here,
     592             :            we construct the topology again (a third time ... sigh). */
     593           0 :   backtest_topo( config );
     594           0 : }
     595             : 
     596             : static void
     597             : backtest_cmd_fn( args_t *   args,
     598           0 :                  config_t * config ) {
     599           0 :   fixup_config( config, args );
     600           0 :   args_t c_args = configure_args();
     601           0 :   configure_cmd_fn( &c_args, config );
     602             : 
     603           0 :   initialize_workspaces( config );
     604           0 :   initialize_stacks( config );
     605             : 
     606           0 :   fd_log_private_shared_lock[ 1 ] = 0;
     607           0 :   fd_topo_join_workspaces( &config->topo, FD_SHMEM_JOIN_MODE_READ_WRITE, FD_TOPO_CORE_DUMP_LEVEL_DISABLED );
     608           0 :   fd_topo_fill( &config->topo );
     609             : 
     610           0 :   args_t watch_args;
     611           0 :   int pipefd[2];
     612           0 :   if( !args->backtest.no_watch ) {
     613           0 :     if( FD_UNLIKELY( pipe2( pipefd, O_NONBLOCK ) ) ) FD_LOG_ERR(( "pipe2() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     614             : 
     615           0 :     watch_args.watch.drain_output_fd = pipefd[0];
     616           0 :     if( FD_UNLIKELY( -1==dup2( pipefd[ 1 ], STDERR_FILENO ) ) ) FD_LOG_ERR(( "dup2() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     617           0 :   }
     618             : 
     619           0 :   fd_topo_run_single_process( &config->topo, 2, config->uid, config->gid, fdctl_tile_run );
     620           0 :   if( args->backtest.no_watch ) {
     621           0 :     for(;;) pause();
     622           0 :   } else {
     623           0 :     watch_cmd_fn( &watch_args, config );
     624           0 :   }
     625           0 : }
     626             : 
     627             : action_t fd_action_backtest = {
     628             :   .name = "backtest",
     629             :   .args = backtest_cmd_args,
     630             :   .fn   = backtest_cmd_fn,
     631             :   .perm = backtest_cmd_perm,
     632             :   .topo = backtest_cmd_topo,
     633             : };

Generated by: LCOV version 1.14