LCOV - code coverage report
Current view: top level - app/shared_dev/commands/bench - bench.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 170 0.0 %
Date: 2026-10-21 18:58:43 Functions: 0 6 0.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : #include "bench.h"
       3             : #include "../../../shared/commands/configure/configure.h"
       4             : #include "../../../shared/commands/run/run.h"
       5             : 
       6             : #include "../../../shared/commands/watch/watch.h"
       7             : #include "../../../platform/fd_sys_util.h"
       8             : #include "../../../../disco/topo/fd_topob.h"
       9             : #include "../../../../disco/topo/fd_cpu_topo.h"
      10             : #include "../../../../disco/net/fd_net_tile.h"
      11             : 
      12             : #include <errno.h>
      13             : #include <unistd.h>
      14             : #include <sched.h>
      15             : #include <fcntl.h>
      16             : #include <pthread.h>
      17             : #include <signal.h>
      18             : #include <linux/capability.h>
      19             : #include <linux/futex.h>
      20             : #include <sys/syscall.h>
      21             : #include <sys/wait.h>
      22             : #include <sys/socket.h>
      23             : #include <arpa/inet.h>
      24             : 
      25             : extern fd_topo_obj_callbacks_t * CALLBACKS[];
      26             : 
      27             : fd_topo_run_tile_t
      28             : fdctl_tile_run( fd_topo_tile_t const * tile );
      29             : 
      30             : void
      31             : update_config_for_dev( config_t * config );
      32             : 
      33             : int
      34           0 : bench_transaction_mode( char const * name ) {
      35           0 :   if( !strcmp( name, ""                ) ) return BENCHG_TRANSACTION_MODE_NOOP;
      36           0 :   if( !strcmp( name, "noop"            ) ) return BENCHG_TRANSACTION_MODE_NOOP;
      37           0 :   if( !strcmp( name, "sol-transfer"    ) ) return BENCHG_TRANSACTION_MODE_SOL_TRANSFER;
      38           0 :   if( !strcmp( name, "ptoken-transfer" ) ) return BENCHG_TRANSACTION_MODE_PTOKEN_TRANSFER;
      39           0 :   return -1;
      40           0 : }
      41             : 
      42             : void
      43             : bench_cmd_args( int *    pargc,
      44             :                 char *** pargv,
      45           0 :                 args_t * args ) {
      46           0 :   args->load.no_quic  = fd_env_strip_cmdline_contains( pargc, pargv, "--no-quic" );
      47           0 :   args->load.no_watch = fd_env_strip_cmdline_contains( pargc, pargv, "--no-watch" );
      48           0 :   args->load.duration = fd_env_strip_cmdline_ulong( pargc, pargv, "--duration", NULL, 0UL );
      49           0 : }
      50             : 
      51             : void
      52             : add_bench_topo( fd_topo_t  * topo,
      53             :                 char const * affinity,
      54             :                 ulong        benchg_tile_cnt,
      55             :                 ulong        benchs_tile_cnt,
      56             :                 ulong        accounts_cnt,
      57             :                 int          transaction_mode,
      58             :                 float        contending_fraction,
      59             :                 float        cu_price_spread,
      60             :                 ulong        conn_cnt,
      61             :                 ushort       send_to_port,
      62             :                 uint         send_to_ip_addr,
      63             :                 ushort       rpc_port,
      64           0 :                 uint         rpc_ip_addr ) {
      65             : 
      66           0 :   fd_topob_wksp( topo, "bench" );
      67           0 :   fd_topob_link( topo, "bencho_out", "bench", 128UL, 64UL, 1UL );
      68           0 :   for( ulong i=0UL; i<benchg_tile_cnt; i++ ) fd_topob_link( topo, "benchg_s", "bench", 65536UL, FD_TXN_MTU, 1UL );
      69             : 
      70           0 :   int is_bench_auto_affinity = !strcmp( affinity, "auto" );
      71             : 
      72           0 :   ushort parsed_tile_to_cpu[ FD_TILE_MAX ];
      73           0 :   for( ulong i=0UL; i<FD_TILE_MAX; i++ ) parsed_tile_to_cpu[ i ] = USHORT_MAX;
      74             : 
      75           0 :   fd_topo_cpus_t cpus[1];
      76           0 :   fd_topo_cpus_init( cpus );
      77             : 
      78           0 :   ulong affinity_tile_cnt = 0UL;
      79           0 :   if( FD_LIKELY( !is_bench_auto_affinity ) ) affinity_tile_cnt = fd_topob_parse_affinity_cstr( affinity, parsed_tile_to_cpu, 0, 1 );
      80             : 
      81           0 :   ulong tile_to_cpu[ FD_TILE_MAX ] = {0};
      82           0 :   for( ulong i=0UL; i<affinity_tile_cnt; i++ ) {
      83           0 :     ushort cpu_idx = (ushort)( parsed_tile_to_cpu[ i ] & ~FD_TOPOB_CPU_SHARED );
      84           0 :     if( FD_UNLIKELY( parsed_tile_to_cpu[ i ]!=USHORT_MAX && cpu_idx>=cpus->cpu_cnt ) )
      85           0 :       FD_LOG_ERR(( "The CPU affinity string in the configuration file under [development.bench.affinity] specifies a CPU index of %hu, but the system "
      86           0 :                    "only has %lu CPUs. You should either change the CPU allocations in the affinity string, or increase the number of CPUs "
      87           0 :                    "in the system.",
      88           0 :                    cpu_idx, cpus->cpu_cnt ));
      89           0 :     tile_to_cpu[ i ] = fd_ulong_if( parsed_tile_to_cpu[ i ]==USHORT_MAX, ULONG_MAX, (ulong)parsed_tile_to_cpu[ i ] );
      90           0 :   }
      91           0 :   if( FD_LIKELY( !is_bench_auto_affinity ) ) {
      92           0 :     if( FD_UNLIKELY( affinity_tile_cnt<benchg_tile_cnt+1UL+benchs_tile_cnt ) )
      93           0 :       FD_LOG_ERR(( "The benchmark topology you are using has %lu bench tiles, but the CPU affinity specified "
      94           0 :                    "in the [development.bench.affinity] only provides for %lu cores. ",
      95           0 :                    benchg_tile_cnt+1UL+benchs_tile_cnt, affinity_tile_cnt ));
      96           0 :     else if( FD_UNLIKELY( affinity_tile_cnt>benchg_tile_cnt+1UL+benchs_tile_cnt ) )
      97           0 :       FD_LOG_WARNING(( "The benchmark topology you are using has %lu bench tiles, but the CPU affinity specified "
      98           0 :                        "in the [development.bench.affinity] provides for %lu cores. The extra cores will be unused.",
      99           0 :                        benchg_tile_cnt+1UL+benchs_tile_cnt, affinity_tile_cnt ));
     100           0 :   }
     101           0 :   fd_topo_tile_t * bencho = fd_topob_tile( topo, "bencho", "bench", "bench", tile_to_cpu[ 0 ], 0, 0, 0 );
     102           0 :   bencho->bencho.rpc_port    = rpc_port;
     103           0 :   bencho->bencho.rpc_ip_addr = rpc_ip_addr;
     104           0 :   for( ulong i=0UL; i<benchg_tile_cnt; i++ ) {
     105           0 :     fd_topo_tile_t * benchg = fd_topob_tile( topo, "benchg", "bench", "bench", tile_to_cpu[ i+1UL ], 0, 0, 0 );
     106           0 :     benchg->benchg.accounts_cnt        = accounts_cnt;
     107           0 :     benchg->benchg.mode                = transaction_mode;
     108           0 :     benchg->benchg.contending_fraction = contending_fraction;
     109           0 :     benchg->benchg.cu_price_spread     = cu_price_spread;
     110           0 :   }
     111           0 :   for( ulong i=0UL; i<benchs_tile_cnt; i++ ) {
     112           0 :     fd_topo_tile_t * benchs = fd_topob_tile( topo, "benchs", "bench", "bench", tile_to_cpu[ benchg_tile_cnt+1UL+i ], 0, 0, 0 );
     113           0 :     benchs->benchs.send_to_ip_addr = send_to_ip_addr;
     114           0 :     benchs->benchs.send_to_port    = send_to_port;
     115           0 :     benchs->benchs.conn_cnt        = conn_cnt;
     116           0 :   }
     117             : 
     118           0 :   fd_topob_tile_out( topo, "bencho", 0UL, "bencho_out", 0UL );
     119           0 :   if( FD_LIKELY( fd_topo_find_link( topo, "replay_slot", 0UL )!=ULONG_MAX ) ) {
     120           0 :     fd_topob_tile_in( topo, "bencho", 0UL, "metric_in", "replay_slot", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED ); /* fseq in a wksp replay maps */
     121           0 :   }
     122           0 :   for( ulong i=0UL; i<benchg_tile_cnt; i++ ) {
     123           0 :     fd_topob_tile_in( topo, "benchg", i, "bench", "bencho_out", 0, 1, 1 );
     124           0 :     fd_topob_tile_out( topo, "benchg", i, "benchg_s", i );
     125           0 :   }
     126           0 :   for( ulong i=0UL; i<benchg_tile_cnt; i++ ) {
     127           0 :     for( ulong j=0UL; j<benchs_tile_cnt; j++ ) {
     128           0 :       fd_topob_tile_in( topo, "benchs", j, "bench", "benchg_s", i, 1, 1 );
     129           0 :     }
     130           0 :   }
     131             : 
     132             :   /* This will blow away previous auto topology layouts and recompute an auto topology. */
     133           0 :   if( FD_UNLIKELY( is_bench_auto_affinity ) ) fd_topob_auto_layout( topo );
     134           0 :   fd_topob_sleep_finish( topo );
     135           0 :   fd_topob_finish( topo, CALLBACKS );
     136           0 : }
     137             : 
     138             : void
     139             : fd_topo_initialize( config_t * config );
     140             : 
     141             : void
     142           0 : bench_topo( config_t * config ) {
     143           0 :   config->tiles.rpc.delay_startup = 0;
     144             : 
     145           0 :   fd_topo_initialize( config );
     146             : 
     147           0 :   ushort rpc_port;
     148           0 :   uint rpc_ip_addr;
     149           0 :   if( FD_UNLIKELY( !config->tiles.rpc.enabled ) ) FD_LOG_ERR(( "RPC tile must be enabled to run bench" ));
     150           0 :   rpc_port = config->tiles.rpc.rpc_listen_port;
     151           0 :   if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( config->tiles.rpc.rpc_listen_address, &rpc_ip_addr ) ) )
     152           0 :     FD_LOG_ERR(( "failed to parse rpc listen address `%s`", config->tiles.rpc.rpc_listen_address ));
     153             : 
     154           0 :   int is_auto_affinity = !strcmp( config->layout.affinity, "auto" );
     155           0 :   int is_bench_auto_affinity = !strcmp( config->development.bench.affinity, "auto" );
     156             : 
     157           0 :   if( FD_UNLIKELY( is_auto_affinity != is_bench_auto_affinity ) ) {
     158           0 :     FD_LOG_ERR(( "The CPU affinity string in the configuration file under [layout.affinity] and [development.bench.affinity] must all be set to 'auto' or all be set to a specific CPU affinity string." ));
     159           0 :   }
     160             : 
     161           0 :   int transaction_mode = bench_transaction_mode( config->development.bench.transaction_mode );
     162           0 :   if( FD_UNLIKELY( transaction_mode<0 ) )
     163           0 :     FD_LOG_ERR(( "unknown [development.bench.transaction_mode] `%s`", config->development.bench.transaction_mode ));
     164             : 
     165           0 :   add_bench_topo( &config->topo,
     166           0 :                   config->development.bench.affinity,
     167           0 :                   config->development.bench.benchg_tile_count,
     168           0 :                   config->development.bench.benchs_tile_count,
     169           0 :                   config->development.genesis.fund_initial_accounts,
     170           0 :                   transaction_mode, 0.0f, 0.0f,
     171           0 :                   config->layout.quic_tile_count,
     172           0 :                   config->tiles.quic.quic_transaction_listen_port,
     173           0 :                   config->net.ip_addr,
     174           0 :                   rpc_port,
     175           0 :                   rpc_ip_addr );
     176           0 : }
     177             : 
     178             : static pid_t bench_pid;
     179             : 
     180             : static void
     181           0 : bench_signal( int sig ) {
     182           0 :   kill( bench_pid, sig );
     183           0 : }
     184             : 
     185             : void
     186             : bench_cmd_fn( args_t *   args,
     187           0 :               config_t * config ) {
     188             : 
     189           0 :   if( args->load.no_quic ) {
     190           0 :     ushort port = config->tiles.quic.regular_transaction_listen_port;
     191           0 :     ulong benchs_tile_cnt = fd_topo_tile_name_cnt( &config->topo, "benchs" );
     192           0 :     for( ulong i=0UL; i<benchs_tile_cnt; i++ ) {
     193           0 :       fd_topo_tile_t * benchs = &config->topo.tiles[ fd_topo_find_tile( &config->topo, "benchs", i ) ];
     194           0 :       benchs->benchs.no_quic      = 1;
     195           0 :       benchs->benchs.send_to_port = port;
     196           0 :     }
     197           0 :   }
     198             : 
     199           0 :   config->topo.tiles[ fd_topo_find_tile( &config->topo, "bencho", 0UL ) ].bencho.duration_s = args->load.duration;
     200             : 
     201           0 :   args_t configure_args = {
     202           0 :     .configure.command = CONFIGURE_CMD_INIT,
     203           0 :   };
     204             : 
     205           0 :   for( ulong i=0UL; STAGES[ i ]; i++ )
     206           0 :     configure_args.configure.stages[ i ] = STAGES[ i ];
     207           0 :   configure_cmd_fn( &configure_args, config );
     208             : 
     209             :   /* Everything past configure runs in a child: the tiles join the
     210             :      cpuset cgroup and drop privileges, so only a root parent outside
     211             :      it can dissolve the partition once they exit (or fail to boot) */
     212           0 :   bench_pid = fork();
     213           0 :   if( FD_UNLIKELY( bench_pid<0 ) ) FD_LOG_ERR(( "fork() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     214           0 :   if( FD_LIKELY( bench_pid ) ) {
     215           0 :     struct sigaction sa = { .sa_handler = bench_signal };
     216           0 :     if( FD_UNLIKELY( sigaction( SIGINT, &sa, NULL ) || sigaction( SIGTERM, &sa, NULL ) ) )
     217           0 :       FD_LOG_ERR(( "sigaction() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     218             : 
     219           0 :     int wstatus;
     220           0 :     while( FD_UNLIKELY( -1==waitpid( bench_pid, &wstatus, 0 ) ) ) {
     221           0 :       if( FD_UNLIKELY( errno!=EINTR ) ) FD_LOG_ERR(( "waitpid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     222           0 :     }
     223             : 
     224           0 :     configure_args = (args_t){ .configure.command = CONFIGURE_CMD_FINI, .configure.stages = { &fd_cfg_stage_cpuset } };
     225           0 :     configure_cmd_fn( &configure_args, config );
     226           0 :     fd_sys_util_exit_group( WIFSIGNALED( wstatus ) ? 128+WTERMSIG( wstatus ) : WEXITSTATUS( wstatus ) );
     227           0 :   }
     228             : 
     229           0 :   update_config_for_dev( config );
     230             : 
     231           0 :   run_firedancer_init( config, 1, 1 );
     232             : 
     233           0 :   if( 0==strcmp( config->net.provider, "xdp" ) ) {
     234           0 :     fd_topo_install_xdp_simple( &config->topo, config->net.bind_address_parsed );
     235           0 :   }
     236             : 
     237           0 :   initialize_accdb_fd( config );
     238           0 :   initialize_epoch_credits_fd( config );
     239           0 :   initialize_cost_tracker_fd( config );
     240           0 :   initialize_vote_stakes_fd( config );
     241           0 :   initialize_stake_delegations_fd( config );
     242           0 :   initialize_store_fds( config );
     243           0 :   initialize_snapshot_fds( config );
     244             : 
     245           0 :   fd_topo_join_workspaces( &config->topo, FD_SHMEM_JOIN_MODE_READ_WRITE, FD_TOPO_CORE_DUMP_LEVEL_DISABLED );
     246           0 :   if( 0==strcmp( config->net.provider, "mlx5" ) ) {
     247           0 :     fd_topo_install_mlx5( &config->topo, NULL );
     248           0 :   }
     249             : 
     250           0 :   if( !args->load.no_watch ) {
     251             :     /* watch incompatible with sandbox */
     252           0 :     config->development.sandbox  = 0;
     253           0 :     config->development.no_clone = 1;
     254             : 
     255           0 :     int pipefd[2];
     256           0 :     if( FD_UNLIKELY( pipe2( pipefd, O_NONBLOCK ) ) ) FD_LOG_ERR(( "pipe2() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     257             : 
     258           0 :     args_t watch_args;
     259           0 :     watch_args.watch.drain_output_fd = pipefd[0];
     260           0 :     watch_args.watch.full = 1;
     261           0 :     if( FD_UNLIKELY( -1==dup2( pipefd[ 1 ], STDERR_FILENO ) ) ) FD_LOG_ERR(( "dup2() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     262             : 
     263             :     /* FIXME allow running sandboxed/multiprocess */
     264           0 :     fd_topo_run_single_process( &config->topo, config->uid, config->gid, fdctl_tile_run );
     265           0 :     watch_cmd_fn( &watch_args, config );
     266           0 :   } else {
     267             :     /* FIXME allow running sandboxed/multiprocess */
     268           0 :     fd_topo_run_single_process( &config->topo, config->uid, config->gid, fdctl_tile_run );
     269           0 :   }
     270           0 : }

Generated by: LCOV version 1.14