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 "../../../../disco/topo/fd_topob.h"
8 : #include "../../../../disco/topo/fd_cpu_topo.h"
9 : #include "../../../../disco/net/fd_net_tile.h"
10 :
11 : #include <errno.h>
12 : #include <unistd.h>
13 : #include <sched.h>
14 : #include <fcntl.h>
15 : #include <pthread.h>
16 : #include <linux/capability.h>
17 : #include <linux/futex.h>
18 : #include <sys/syscall.h>
19 : #include <sys/wait.h>
20 : #include <sys/socket.h>
21 : #include <arpa/inet.h>
22 :
23 : extern fd_topo_obj_callbacks_t * CALLBACKS[];
24 :
25 : fd_topo_run_tile_t
26 : fdctl_tile_run( fd_topo_tile_t const * tile );
27 :
28 : void
29 : update_config_for_dev( config_t * config );
30 :
31 : void
32 : bench_cmd_args( int * pargc,
33 : char *** pargv,
34 0 : args_t * args ) {
35 0 : args->load.no_quic = fd_env_strip_cmdline_contains( pargc, pargv, "--no-quic" );
36 0 : args->load.no_watch = fd_env_strip_cmdline_contains( pargc, pargv, "--no-watch" );
37 0 : }
38 :
39 : void
40 : add_bench_topo( fd_topo_t * topo,
41 : char const * affinity,
42 : ulong benchg_tile_cnt,
43 : ulong benchs_tile_cnt,
44 : ulong accounts_cnt,
45 : int transaction_mode,
46 : float contending_fraction,
47 : float cu_price_spread,
48 : ulong conn_cnt,
49 : ushort send_to_port,
50 : uint send_to_ip_addr,
51 : ushort rpc_port,
52 : uint rpc_ip_addr,
53 0 : int reserve_agave_cores ) {
54 :
55 0 : fd_topob_wksp( topo, "bench" );
56 0 : fd_topob_link( topo, "bencho_out", "bench", 128UL, 64UL, 1UL );
57 0 : for( ulong i=0UL; i<benchg_tile_cnt; i++ ) fd_topob_link( topo, "benchg_s", "bench", 65536UL, FD_TXN_MTU, 1UL );
58 :
59 0 : int is_bench_auto_affinity = !strcmp( affinity, "auto" );
60 :
61 0 : ushort parsed_tile_to_cpu[ FD_TILE_MAX ];
62 0 : for( ulong i=0UL; i<FD_TILE_MAX; i++ ) parsed_tile_to_cpu[ i ] = USHORT_MAX;
63 :
64 0 : fd_topo_cpus_t cpus[1];
65 0 : fd_topo_cpus_init( cpus );
66 :
67 0 : ulong affinity_tile_cnt = 0UL;
68 0 : if( FD_LIKELY( !is_bench_auto_affinity ) ) affinity_tile_cnt = fd_topob_parse_affinity_cstr( affinity, parsed_tile_to_cpu, 0 );
69 :
70 0 : ulong tile_to_cpu[ FD_TILE_MAX ] = {0};
71 0 : for( ulong i=0UL; i<affinity_tile_cnt; i++ ) {
72 0 : if( FD_UNLIKELY( parsed_tile_to_cpu[ i ]!=USHORT_MAX && parsed_tile_to_cpu[ i ]>=cpus->cpu_cnt ) )
73 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 "
74 0 : "only has %lu CPUs. You should either change the CPU allocations in the affinity string, or increase the number of CPUs "
75 0 : "in the system.",
76 0 : parsed_tile_to_cpu[ i ], cpus->cpu_cnt ));
77 0 : tile_to_cpu[ i ] = fd_ulong_if( parsed_tile_to_cpu[ i ]==USHORT_MAX, ULONG_MAX, (ulong)parsed_tile_to_cpu[ i ] );
78 0 : }
79 0 : if( FD_LIKELY( !is_bench_auto_affinity ) ) {
80 0 : if( FD_UNLIKELY( affinity_tile_cnt<benchg_tile_cnt+1UL+benchs_tile_cnt ) )
81 0 : FD_LOG_ERR(( "The benchmark topology you are using has %lu bench tiles, but the CPU affinity specified "
82 0 : "in the [development.bench.affinity] only provides for %lu cores. ",
83 0 : benchg_tile_cnt+1UL+benchs_tile_cnt, affinity_tile_cnt ));
84 0 : else if( FD_UNLIKELY( affinity_tile_cnt>benchg_tile_cnt+1UL+benchs_tile_cnt ) )
85 0 : FD_LOG_WARNING(( "The benchmark topology you are using has %lu bench tiles, but the CPU affinity specified "
86 0 : "in the [development.bench.affinity] provides for %lu cores. The extra cores will be unused.",
87 0 : benchg_tile_cnt+1UL+benchs_tile_cnt, affinity_tile_cnt ));
88 0 : }
89 0 : fd_topo_tile_t * bencho = fd_topob_tile( topo, "bencho", "bench", "bench", tile_to_cpu[ 0 ], 0, 0, 0 );
90 0 : bencho->bencho.rpc_port = rpc_port;
91 0 : bencho->bencho.rpc_ip_addr = rpc_ip_addr;
92 0 : for( ulong i=0UL; i<benchg_tile_cnt; i++ ) {
93 0 : fd_topo_tile_t * benchg = fd_topob_tile( topo, "benchg", "bench", "bench", tile_to_cpu[ i+1UL ], 0, 0, 0 );
94 0 : benchg->benchg.accounts_cnt = accounts_cnt;
95 0 : benchg->benchg.mode = transaction_mode;
96 0 : benchg->benchg.contending_fraction = contending_fraction;
97 0 : benchg->benchg.cu_price_spread = cu_price_spread;
98 0 : }
99 0 : for( ulong i=0UL; i<benchs_tile_cnt; i++ ) {
100 0 : fd_topo_tile_t * benchs = fd_topob_tile( topo, "benchs", "bench", "bench", tile_to_cpu[ benchg_tile_cnt+1UL+i ], 0, 0, 0 );
101 0 : benchs->benchs.send_to_ip_addr = send_to_ip_addr;
102 0 : benchs->benchs.send_to_port = send_to_port;
103 0 : benchs->benchs.conn_cnt = conn_cnt;
104 0 : }
105 :
106 0 : fd_topob_tile_out( topo, "bencho", 0UL, "bencho_out", 0UL );
107 0 : for( ulong i=0UL; i<benchg_tile_cnt; i++ ) {
108 0 : fd_topob_tile_in( topo, "benchg", i, "bench", "bencho_out", 0, 1, 1 );
109 0 : fd_topob_tile_out( topo, "benchg", i, "benchg_s", i );
110 0 : }
111 0 : for( ulong i=0UL; i<benchg_tile_cnt; i++ ) {
112 0 : for( ulong j=0UL; j<benchs_tile_cnt; j++ ) {
113 0 : fd_topob_tile_in( topo, "benchs", j, "bench", "benchg_s", i, 1, 1 );
114 0 : }
115 0 : }
116 :
117 : /* This will blow away previous auto topology layouts and recompute an auto topology. */
118 0 : if( FD_UNLIKELY( is_bench_auto_affinity ) ) fd_topob_auto_layout( topo, reserve_agave_cores );
119 0 : fd_topob_finish( topo, CALLBACKS );
120 0 : }
121 :
122 : void
123 : fd_topo_initialize( config_t * config );
124 :
125 : void
126 0 : bench_topo( config_t * config ) {
127 0 : config->tiles.rpc.delay_startup = 0;
128 :
129 0 : fd_topo_initialize( config );
130 :
131 0 : ushort rpc_port;
132 0 : uint rpc_ip_addr;
133 0 : if( FD_UNLIKELY( !config->is_firedancer ) ) {
134 0 : config->frankendancer.rpc.port = fd_ushort_if( config->frankendancer.rpc.port, config->frankendancer.rpc.port, 8899 );
135 0 : config->frankendancer.rpc.full_api = 1;
136 0 : rpc_port = config->frankendancer.rpc.port;
137 0 : rpc_ip_addr = config->net.ip_addr;
138 0 : } else {
139 0 : if( FD_UNLIKELY( !config->tiles.rpc.enabled ) ) FD_LOG_ERR(( "RPC tile must be enabled to run bench" ));
140 0 : rpc_port = config->tiles.rpc.rpc_listen_port;
141 0 : if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( config->tiles.rpc.rpc_listen_address, &rpc_ip_addr ) ) )
142 0 : FD_LOG_ERR(( "failed to parse rpc listen address `%s`", config->tiles.rpc.rpc_listen_address ));
143 0 : }
144 :
145 0 : int is_auto_affinity = !strcmp( config->layout.affinity, "auto" );
146 0 : int is_agave_auto_affinity;
147 0 : if( FD_UNLIKELY( config->is_firedancer ) ) {
148 0 : is_agave_auto_affinity = is_auto_affinity;
149 0 : } else {
150 0 : is_agave_auto_affinity = !strcmp( config->frankendancer.layout.agave_affinity, "auto" );
151 0 : }
152 0 : int is_bench_auto_affinity = !strcmp( config->development.bench.affinity, "auto" );
153 :
154 0 : if( FD_UNLIKELY( is_auto_affinity != is_agave_auto_affinity ||
155 0 : is_auto_affinity != is_bench_auto_affinity ) ) {
156 0 : FD_LOG_ERR(( "The CPU affinity string in the configuration file under [layout.affinity], [layout.agave_affinity], and [development.bench.affinity] must all be set to 'auto' or all be set to a specific CPU affinity string." ));
157 0 : }
158 :
159 0 : add_bench_topo( &config->topo,
160 0 : config->development.bench.affinity,
161 0 : config->development.bench.benchg_tile_count,
162 0 : config->development.bench.benchs_tile_count,
163 0 : config->development.genesis.fund_initial_accounts,
164 0 : 0, 0.0f, 0.0f,
165 0 : config->layout.quic_tile_count,
166 0 : config->tiles.quic.quic_transaction_listen_port,
167 0 : config->net.ip_addr,
168 0 : rpc_port,
169 0 : rpc_ip_addr,
170 0 : !config->is_firedancer );
171 0 : }
172 :
173 : void
174 : bench_cmd_fn( args_t * args,
175 0 : config_t * config ) {
176 :
177 0 : if( args->load.no_quic ) {
178 0 : ushort port = config->tiles.quic.regular_transaction_listen_port;
179 0 : ulong benchs_tile_cnt = fd_topo_tile_name_cnt( &config->topo, "benchs" );
180 0 : for( ulong i=0UL; i<benchs_tile_cnt; i++ ) {
181 0 : fd_topo_tile_t * benchs = &config->topo.tiles[ fd_topo_find_tile( &config->topo, "benchs", i ) ];
182 0 : benchs->benchs.no_quic = 1;
183 0 : benchs->benchs.send_to_port = port;
184 0 : }
185 0 : }
186 :
187 0 : args_t configure_args = {
188 0 : .configure.command = CONFIGURE_CMD_INIT,
189 0 : };
190 :
191 0 : for( ulong i=0UL; STAGES[ i ]; i++ )
192 0 : configure_args.configure.stages[ i ] = STAGES[ i ];
193 0 : configure_cmd_fn( &configure_args, config );
194 :
195 0 : update_config_for_dev( config );
196 :
197 0 : run_firedancer_init( config, 1, 1 );
198 :
199 0 : if( 0==strcmp( config->net.provider, "xdp" ) ) {
200 0 : fd_topo_install_xdp_simple( &config->topo, config->net.bind_address_parsed );
201 0 : }
202 :
203 0 : initialize_accdb_fd( config );
204 :
205 0 : fd_topo_join_workspaces( &config->topo, FD_SHMEM_JOIN_MODE_READ_WRITE, FD_TOPO_CORE_DUMP_LEVEL_DISABLED );
206 :
207 0 : if( !args->load.no_watch ) {
208 : /* watch incompatible with sandbox */
209 0 : config->development.sandbox = 0;
210 0 : config->development.no_clone = 1;
211 :
212 0 : int pipefd[2];
213 0 : if( FD_UNLIKELY( pipe2( pipefd, O_NONBLOCK ) ) ) FD_LOG_ERR(( "pipe2() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
214 :
215 0 : args_t watch_args;
216 0 : watch_args.watch.drain_output_fd = pipefd[0];
217 0 : watch_args.watch.full = 1;
218 0 : if( FD_UNLIKELY( -1==dup2( pipefd[ 1 ], STDERR_FILENO ) ) ) FD_LOG_ERR(( "dup2() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
219 :
220 : /* FIXME allow running sandboxed/multiprocess */
221 0 : fd_topo_run_single_process( &config->topo, 2, config->uid, config->gid, fdctl_tile_run );
222 0 : watch_cmd_fn( &watch_args, config );
223 0 : } else {
224 : /* FIXME allow running sandboxed/multiprocess */
225 0 : fd_topo_run_single_process( &config->topo, 2, config->uid, config->gid, fdctl_tile_run );
226 0 : }
227 0 : }
|