Line data Source code
1 : #include "../../fdctl.h"
2 :
3 : #include "../../../../disco/tiles.h"
4 : #include "../../../../disco/topo/fd_topob.h"
5 : #include "../../../../disco/topo/fd_pod_format.h"
6 : #include "../../../../util/tile/fd_tile_private.h"
7 : #include "../../../../util/shmem/fd_shmem_private.h"
8 :
9 : void
10 3 : fd_topo_initialize( config_t * config ) {
11 3 : ulong net_tile_cnt = config->layout.net_tile_count;
12 3 : ulong quic_tile_cnt = config->layout.quic_tile_count;
13 3 : ulong verify_tile_cnt = config->layout.verify_tile_count;
14 3 : ulong resolv_tile_cnt = config->layout.resolv_tile_count;
15 3 : ulong bank_tile_cnt = config->layout.bank_tile_count;
16 3 : ulong shred_tile_cnt = config->layout.shred_tile_count;
17 :
18 3 : fd_topo_t * topo = { fd_topob_new( &config->topo, config->name ) };
19 :
20 : /* topo, name */
21 3 : fd_topob_wksp( topo, "net_quic" );
22 3 : fd_topob_wksp( topo, "net_shred" );
23 3 : fd_topob_wksp( topo, "quic_verify" );
24 3 : fd_topob_wksp( topo, "verify_dedup" );
25 3 : fd_topob_wksp( topo, "dedup_resolv" );
26 3 : fd_topob_wksp( topo, "resolv_pack" );
27 3 : fd_topob_wksp( topo, "pack_bank" );
28 3 : fd_topob_wksp( topo, "bank_poh" );
29 3 : fd_topob_wksp( topo, "bank_busy" );
30 3 : fd_topob_wksp( topo, "poh_shred" );
31 3 : fd_topob_wksp( topo, "gossip_dedup" );
32 3 : fd_topob_wksp( topo, "shred_store" );
33 3 : fd_topob_wksp( topo, "stake_out" );
34 3 : fd_topob_wksp( topo, "metric_in" );
35 :
36 3 : fd_topob_wksp( topo, "shred_sign" );
37 3 : fd_topob_wksp( topo, "sign_shred" );
38 :
39 3 : fd_topob_wksp( topo, "net" );
40 3 : fd_topob_wksp( topo, "quic" );
41 3 : fd_topob_wksp( topo, "verify" );
42 3 : fd_topob_wksp( topo, "dedup" );
43 3 : fd_topob_wksp( topo, "resolv" );
44 3 : fd_topob_wksp( topo, "pack" );
45 3 : fd_topob_wksp( topo, "bank" );
46 3 : fd_topob_wksp( topo, "poh" );
47 3 : fd_topob_wksp( topo, "shred" );
48 3 : fd_topob_wksp( topo, "store" );
49 3 : fd_topob_wksp( topo, "sign" );
50 3 : fd_topob_wksp( topo, "metric" );
51 3 : fd_topob_wksp( topo, "cswtch" );
52 :
53 309 : #define FOR(cnt) for( ulong i=0UL; i<cnt; i++ )
54 :
55 : /* topo, link_name, wksp_name, is_reasm, depth, mtu, burst */
56 3 : FOR(net_tile_cnt) fd_topob_link( topo, "net_quic", "net_quic", 0, config->tiles.net.send_buffer_size, FD_NET_MTU, 1UL );
57 3 : FOR(net_tile_cnt) fd_topob_link( topo, "net_shred", "net_shred", 0, config->tiles.net.send_buffer_size, FD_NET_MTU, 1UL );
58 3 : FOR(quic_tile_cnt) fd_topob_link( topo, "quic_net", "net_quic", 0, config->tiles.net.send_buffer_size, FD_NET_MTU, 1UL );
59 3 : FOR(shred_tile_cnt) fd_topob_link( topo, "shred_net", "net_shred", 0, config->tiles.net.send_buffer_size, FD_NET_MTU, 1UL );
60 3 : FOR(quic_tile_cnt) fd_topob_link( topo, "quic_verify", "quic_verify", 1, config->tiles.verify.receive_buffer_size, 0UL, config->tiles.quic.txn_reassembly_count );
61 12 : FOR(verify_tile_cnt) fd_topob_link( topo, "verify_dedup", "verify_dedup", 0, config->tiles.verify.receive_buffer_size, FD_TPU_DCACHE_MTU, 1UL );
62 : /* gossip_dedup could be FD_TPU_MTU, since txns are not parsed, but better to just share one size for all the ins of dedup */
63 3 : /**/ fd_topob_link( topo, "gossip_dedup", "gossip_dedup", 0, 2048UL, FD_TPU_DCACHE_MTU, 1UL );
64 : /* dedup_pack is large currently because pack can encounter stalls when running at very high throughput rates that would
65 : otherwise cause drops. */
66 3 : /**/ fd_topob_link( topo, "dedup_resolv", "dedup_resolv", 0, 65536UL, FD_TPU_DCACHE_MTU, 1UL );
67 3 : FOR(resolv_tile_cnt) fd_topob_link( topo, "resolv_pack", "resolv_pack", 0, 65536UL, FD_TPU_RESOLVED_DCACHE_MTU, 1UL );
68 3 : /**/ fd_topob_link( topo, "stake_out", "stake_out", 0, 128UL, 40UL + 40200UL * 40UL, 1UL );
69 : /* pack_bank is shared across all banks, so if one bank stalls due to complex transactions, the buffer neeeds to be large so that
70 : other banks can keep proceeding. */
71 3 : /**/ fd_topob_link( topo, "pack_bank", "pack_bank", 0, 65536UL, USHORT_MAX, 1UL );
72 6 : FOR(bank_tile_cnt) fd_topob_link( topo, "bank_poh", "bank_poh", 0, 128UL, USHORT_MAX, 1UL );
73 3 : /**/ fd_topob_link( topo, "poh_pack", "bank_poh", 0, 128UL, sizeof(fd_became_leader_t), 1UL );
74 3 : /**/ fd_topob_link( topo, "poh_shred", "poh_shred", 0, 16384UL, USHORT_MAX, 1UL );
75 3 : /**/ fd_topob_link( topo, "crds_shred", "poh_shred", 0, 128UL, 8UL + 40200UL * 38UL, 1UL );
76 3 : /**/ fd_topob_link( topo, "replay_resol", "bank_poh", 0, 128UL, sizeof(fd_completed_bank_t), 1UL );
77 : /* See long comment in fd_shred.c for an explanation about the size of this dcache. */
78 3 : FOR(shred_tile_cnt) fd_topob_link( topo, "shred_store", "shred_store", 0, 16384UL, 4UL*FD_SHRED_STORE_MTU, 4UL+config->tiles.shred.max_pending_shred_sets );
79 :
80 3 : FOR(shred_tile_cnt) fd_topob_link( topo, "shred_sign", "shred_sign", 0, 128UL, 32UL, 1UL );
81 3 : FOR(shred_tile_cnt) fd_topob_link( topo, "sign_shred", "sign_shred", 0, 128UL, 64UL, 1UL );
82 :
83 3 : ushort parsed_tile_to_cpu[ FD_TILE_MAX ];
84 : /* Unassigned tiles will be floating, unless auto topology is enabled. */
85 3075 : for( ulong i=0UL; i<FD_TILE_MAX; i++ ) parsed_tile_to_cpu[ i ] = USHORT_MAX;
86 :
87 3 : int is_auto_affinity = !strcmp( config->layout.affinity, "auto" );
88 3 : int is_agave_auto_affinity = !strcmp( config->layout.agave_affinity, "auto" );
89 3 : int is_bench_auto_affinity = !strcmp( config->development.bench.affinity, "auto" );
90 :
91 3 : if( FD_UNLIKELY( is_auto_affinity != is_agave_auto_affinity ||
92 3 : is_auto_affinity != is_bench_auto_affinity ) ) {
93 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." ));
94 0 : }
95 :
96 3 : ulong affinity_tile_cnt = 0UL;
97 3 : if( FD_LIKELY( !is_auto_affinity ) ) affinity_tile_cnt = fd_tile_private_cpus_parse( config->layout.affinity, parsed_tile_to_cpu );
98 :
99 3 : ulong tile_to_cpu[ FD_TILE_MAX ] = {0};
100 3 : for( ulong i=0UL; i<affinity_tile_cnt; i++ ) {
101 0 : if( FD_UNLIKELY( parsed_tile_to_cpu[ i ]!=USHORT_MAX && parsed_tile_to_cpu[ i ]>=fd_numa_cpu_cnt() ) )
102 0 : FD_LOG_ERR(( "The CPU affinity string in the configuration file under [layout.affinity] specifies a CPU index of %hu, but the system "
103 0 : "only has %lu CPUs. You should either change the CPU allocations in the affinity string, or increase the number of CPUs "
104 0 : "in the system.",
105 0 : parsed_tile_to_cpu[ i ], fd_numa_cpu_cnt() ));
106 0 : tile_to_cpu[ i ] = fd_ulong_if( parsed_tile_to_cpu[ i ]==USHORT_MAX, ULONG_MAX, (ulong)parsed_tile_to_cpu[ i ] );
107 0 : }
108 :
109 : /* topo, tile_name, tile_wksp, metrics_wksp, cpu_idx, is_agave */
110 3 : FOR(net_tile_cnt) fd_topob_tile( topo, "net", "net", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0 );
111 3 : FOR(quic_tile_cnt) fd_topob_tile( topo, "quic", "quic", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0 );
112 12 : FOR(verify_tile_cnt) fd_topob_tile( topo, "verify", "verify", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0 );
113 3 : /**/ fd_topob_tile( topo, "dedup", "dedup", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0 );
114 3 : FOR(resolv_tile_cnt) fd_topob_tile( topo, "resolv", "resolv", "metric_in", tile_to_cpu[ topo->tile_cnt ], 1 );
115 3 : /**/ fd_topob_tile( topo, "pack", "pack", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0 );
116 6 : FOR(bank_tile_cnt) fd_topob_tile( topo, "bank", "bank", "metric_in", tile_to_cpu[ topo->tile_cnt ], 1 );
117 3 : /**/ fd_topob_tile( topo, "poh", "poh", "metric_in", tile_to_cpu[ topo->tile_cnt ], 1 );
118 3 : FOR(shred_tile_cnt) fd_topob_tile( topo, "shred", "shred", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0 );
119 3 : /**/ fd_topob_tile( topo, "store", "store", "metric_in", tile_to_cpu[ topo->tile_cnt ], 1 );
120 3 : /**/ fd_topob_tile( topo, "sign", "sign", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0 );
121 3 : /**/ fd_topob_tile( topo, "metric", "metric", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0 );
122 3 : /**/ fd_topob_tile( topo, "cswtch", "cswtch", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0 );
123 :
124 3 : if( FD_LIKELY( !is_auto_affinity ) ) {
125 0 : if( FD_UNLIKELY( affinity_tile_cnt<topo->tile_cnt ) )
126 0 : FD_LOG_ERR(( "The topology you are using has %lu tiles, but the CPU affinity specified in the config tile as [layout.affinity] only provides for %lu cores. "
127 0 : "You should either increase the number of cores dedicated to Firedancer in the affinity string, or decrease the number of cores needed by reducing "
128 0 : "the total tile count. You can reduce the tile count by decreasing individual tile counts in the [layout] section of the configuration file.",
129 0 : topo->tile_cnt, affinity_tile_cnt ));
130 0 : if( FD_UNLIKELY( affinity_tile_cnt>topo->tile_cnt ) )
131 0 : FD_LOG_WARNING(( "The topology you are using has %lu tiles, but the CPU affinity specified in the config tile as [layout.affinity] provides for %lu cores. "
132 0 : "Not all cores in the affinity will be used by Firedancer. You may wish to increase the number of tiles in the system by increasing "
133 0 : "individual tile counts in the [layout] section of the configuration file.",
134 0 : topo->tile_cnt, affinity_tile_cnt ));
135 :
136 0 : if( FD_LIKELY( strcmp( "", config->layout.agave_affinity ) ) ) {
137 0 : ushort agave_cpu[ FD_TILE_MAX ];
138 0 : ulong agave_cpu_cnt = fd_tile_private_cpus_parse( config->layout.agave_affinity, agave_cpu );
139 :
140 0 : for( ulong i=0UL; i<agave_cpu_cnt; i++ ) {
141 0 : if( FD_UNLIKELY( agave_cpu[ i ]>=fd_numa_cpu_cnt() ) )
142 0 : FD_LOG_ERR(( "The CPU affinity string in the configuration file under [layout.agave_affinity] specifies a CPU index of %hu, but the system "
143 0 : "only has %lu CPUs. You should either change the CPU allocations in the affinity string, or increase the number of CPUs "
144 0 : "in the system.",
145 0 : agave_cpu[ i ], fd_numa_cpu_cnt() ));
146 :
147 0 : for( ulong j=0UL; j<topo->tile_cnt; j++ ) {
148 0 : fd_topo_tile_t * tile = &topo->tiles[ j ];
149 0 : if( tile->cpu_idx==agave_cpu[ i ] ) FD_LOG_WARNING(( "Tile `%s:%lu` is already assigned to CPU %hu, but the CPU is also assigned to Agave. "
150 0 : "This may cause contention between the two tiles.", tile->name, tile->kind_id, agave_cpu[ i ] ));
151 0 : }
152 :
153 0 : if( FD_UNLIKELY( topo->agave_affinity_cnt>FD_TILE_MAX ) ) {
154 0 : FD_LOG_ERR(( "The CPU affinity string in the configuration file under [layout.agave_affinity] specifies more CPUs than Firedancer can use. "
155 0 : "You should either reduce the number of CPUs in the affinity string." ));
156 0 : }
157 0 : topo->agave_affinity_cpu_idx[ topo->agave_affinity_cnt++ ] = agave_cpu[ i ];
158 0 : }
159 0 : }
160 0 : }
161 :
162 : /* topo, tile_name, tile_kind_id, fseq_wksp, link_name, link_kind_id, reliable, polled */
163 6 : FOR(net_tile_cnt) for( ulong j=0UL; j<quic_tile_cnt; j++ )
164 3 : fd_topob_tile_in( topo, "net", i, "metric_in", "quic_net", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
165 6 : FOR(net_tile_cnt) for( ulong j=0UL; j<shred_tile_cnt; j++ )
166 3 : fd_topob_tile_in( topo, "net", i, "metric_in", "shred_net", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
167 3 : FOR(net_tile_cnt) fd_topob_tile_out( topo, "net", i, "net_quic", i );
168 3 : FOR(net_tile_cnt) fd_topob_tile_out( topo, "net", i, "net_shred", i );
169 :
170 6 : FOR(quic_tile_cnt) for( ulong j=0UL; j<net_tile_cnt; j++ )
171 3 : fd_topob_tile_in( topo, "quic", i, "metric_in", "net_quic", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
172 3 : FOR(quic_tile_cnt) fd_topob_tile_out( topo, "quic", i, "quic_verify", i );
173 3 : FOR(quic_tile_cnt) fd_topob_tile_out( topo, "quic", i, "quic_net", i );
174 : /* All verify tiles read from all QUIC tiles, packets are round robin. */
175 24 : FOR(verify_tile_cnt) for( ulong j=0UL; j<quic_tile_cnt; j++ )
176 12 : fd_topob_tile_in( topo, "verify", i, "metric_in", "quic_verify", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers, verify tiles may be overrun */
177 12 : FOR(verify_tile_cnt) fd_topob_tile_out( topo, "verify", i, "verify_dedup", i );
178 : /* Declare the single gossip link before the variable length verify-dedup links so we could have a compile-time index to the gossip link. */
179 3 : /**/ fd_topob_tile_in( topo, "dedup", 0UL, "metric_in", "gossip_dedup", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
180 12 : FOR(verify_tile_cnt) fd_topob_tile_in( topo, "dedup", 0UL, "metric_in", "verify_dedup", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
181 3 : /**/ fd_topob_tile_out( topo, "dedup", 0UL, "dedup_resolv", 0UL );
182 3 : FOR(resolv_tile_cnt) fd_topob_tile_in( topo, "resolv", i, "metric_in", "dedup_resolv", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
183 3 : FOR(resolv_tile_cnt) fd_topob_tile_in( topo, "resolv", i, "metric_in", "replay_resol", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
184 3 : FOR(resolv_tile_cnt) fd_topob_tile_out( topo, "resolv", i, "resolv_pack", i );
185 3 : /**/ fd_topob_tile_in( topo, "pack", 0UL, "metric_in", "resolv_pack", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
186 : /* The PoH to pack link is reliable, and must be. The fragments going
187 : across here are "you became leader" which pack must respond to
188 : by publishing microblocks, otherwise the leader TPU will hang
189 : forever.
190 :
191 : It's marked as unreliable since otherwise we have a reliable credit
192 : loop which will also starve the pack tile. This is OK because we
193 : will never send more than one leader message until the pack tile
194 : must acknowledge it with a packing done frag, so there will be at
195 : most one in flight at any time. */
196 3 : /**/ fd_topob_tile_in( topo, "pack", 0UL, "metric_in", "poh_pack", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
197 3 : fd_topob_tile_out( topo, "pack", 0UL, "pack_bank", 0UL );
198 6 : FOR(bank_tile_cnt) fd_topob_tile_in( topo, "bank", i, "metric_in", "pack_bank", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
199 6 : FOR(bank_tile_cnt) fd_topob_tile_out( topo, "bank", i, "bank_poh", i );
200 6 : FOR(bank_tile_cnt) fd_topob_tile_in( topo, "poh", 0UL, "metric_in", "bank_poh", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
201 3 : if( FD_LIKELY( config->tiles.pack.use_consumed_cus ) )
202 6 : FOR(bank_tile_cnt) fd_topob_tile_in( topo, "pack", 0UL, "metric_in", "bank_poh", i, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
203 3 : /**/ fd_topob_tile_in( topo, "poh", 0UL, "metric_in", "stake_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
204 3 : /**/ fd_topob_tile_in( topo, "poh", 0UL, "metric_in", "pack_bank", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
205 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "poh_shred", 0UL );
206 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "poh_pack", 0UL );
207 6 : FOR(shred_tile_cnt) for( ulong j=0UL; j<net_tile_cnt; j++ )
208 3 : fd_topob_tile_in( topo, "shred", i, "metric_in", "net_shred", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
209 3 : FOR(shred_tile_cnt) fd_topob_tile_in( topo, "shred", i, "metric_in", "poh_shred", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
210 3 : FOR(shred_tile_cnt) fd_topob_tile_in( topo, "shred", i, "metric_in", "stake_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
211 3 : FOR(shred_tile_cnt) fd_topob_tile_in( topo, "shred", i, "metric_in", "crds_shred", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
212 3 : FOR(shred_tile_cnt) fd_topob_tile_out( topo, "shred", i, "shred_store", i );
213 3 : FOR(shred_tile_cnt) fd_topob_tile_out( topo, "shred", i, "shred_net", i );
214 3 : FOR(shred_tile_cnt) fd_topob_tile_in( topo, "store", 0UL, "metric_in", "shred_store", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
215 :
216 : /* Sign links don't need to be reliable because they are synchronous,
217 : so there's at most one fragment in flight at a time anyway. The
218 : sign links are also not polled by the mux, instead the tiles will
219 : read the sign responses out of band in a dedicated spin loop. */
220 :
221 6 : for( ulong i=0UL; i<shred_tile_cnt; i++ ) {
222 3 : /**/ fd_topob_tile_in( topo, "sign", 0UL, "metric_in", "shred_sign", i, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
223 3 : /**/ fd_topob_tile_out( topo, "shred", i, "shred_sign", i );
224 3 : /**/ fd_topob_tile_in( topo, "shred", i, "metric_in", "sign_shred", i, FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
225 3 : /**/ fd_topob_tile_out( topo, "sign", 0UL, "sign_shred", i );
226 3 : }
227 :
228 : /* PoH tile represents the Agave address space, so it's
229 : responsible for publishing Agave provided data to
230 : these links. */
231 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "gossip_dedup", 0UL );
232 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "stake_out", 0UL );
233 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "crds_shred", 0UL );
234 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "replay_resol", 0UL );
235 :
236 : /* For now the only plugin consumer is the GUI */
237 3 : int plugins_enabled = config->tiles.gui.enabled;
238 3 : if( FD_LIKELY( plugins_enabled ) ) {
239 0 : fd_topob_wksp( topo, "plugin_in" );
240 0 : fd_topob_wksp( topo, "plugin_out" );
241 0 : fd_topob_wksp( topo, "plugin" );
242 :
243 : /**/ fd_topob_link( topo, "plugin_out", "plugin_out", 0, 128UL, 8UL+40200UL*(58UL+12UL*34UL), 1UL );
244 0 : /**/ fd_topob_link( topo, "replay_plugi", "plugin_in", 0, 128UL, 4098*8UL, 1UL );
245 0 : /**/ fd_topob_link( topo, "gossip_plugi", "plugin_in", 0, 128UL, 8UL+40200UL*(58UL+12UL*34UL), 1UL );
246 0 : /**/ fd_topob_link( topo, "poh_plugin", "plugin_in", 0, 128UL, 16UL, 1UL );
247 0 : /**/ fd_topob_link( topo, "startp_plugi", "plugin_in", 0, 128UL, 56UL, 1UL );
248 0 : /**/ fd_topob_link( topo, "votel_plugin", "plugin_in", 0, 128UL, 8UL, 1UL );
249 :
250 : /**/ fd_topob_tile( topo, "plugin", "plugin", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0 );
251 :
252 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "replay_plugi", 0UL );
253 0 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "gossip_plugi", 0UL );
254 0 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "poh_plugin", 0UL );
255 0 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "startp_plugi", 0UL );
256 0 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "votel_plugin", 0UL );
257 0 : /**/ fd_topob_tile_out( topo, "plugin", 0UL, "plugin_out", 0UL );
258 :
259 0 : /**/ fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "replay_plugi", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
260 0 : /**/ fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "gossip_plugi", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
261 0 : /**/ fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "stake_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
262 0 : /**/ fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "poh_plugin", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
263 0 : /**/ fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "startp_plugi", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
264 0 : /**/ fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "votel_plugin", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
265 0 : }
266 :
267 3 : if( FD_LIKELY( config->tiles.gui.enabled ) ) {
268 0 : fd_topob_wksp( topo, "gui" );
269 0 : /**/ fd_topob_tile( topo, "gui", "gui", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0 );
270 0 : /**/ fd_topob_tile_in( topo, "gui", 0UL, "metric_in", "plugin_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
271 0 : }
272 :
273 3 : if( FD_LIKELY( !is_auto_affinity ) ) {
274 0 : if( FD_UNLIKELY( affinity_tile_cnt<topo->tile_cnt ) )
275 0 : FD_LOG_ERR(( "The topology you are using has %lu tiles, but the CPU affinity specified in the config tile as [layout.affinity] only provides for %lu cores. "
276 0 : "You should either increase the number of cores dedicated to Firedancer in the affinity string, or decrease the number of cores needed by reducing "
277 0 : "the total tile count. You can reduce the tile count by decreasing individual tile counts in the [layout] section of the configuration file.",
278 0 : topo->tile_cnt, affinity_tile_cnt ));
279 0 : if( FD_UNLIKELY( affinity_tile_cnt>topo->tile_cnt ) )
280 0 : FD_LOG_WARNING(( "The topology you are using has %lu tiles, but the CPU affinity specified in the config tile as [layout.affinity] provides for %lu cores. "
281 0 : "Not all cores in the affinity will be used by Firedancer. You may wish to increase the number of tiles in the system by increasing "
282 0 : "individual tile counts in the [layout] section of the configuration file.",
283 0 : topo->tile_cnt, affinity_tile_cnt ));
284 :
285 0 : if( FD_LIKELY( strcmp( "", config->layout.agave_affinity ) ) ) {
286 0 : ushort agave_cpu[ FD_TILE_MAX ];
287 0 : ulong agave_cpu_cnt = fd_tile_private_cpus_parse( config->layout.agave_affinity, agave_cpu );
288 :
289 0 : for( ulong i=0UL; i<agave_cpu_cnt; i++ ) {
290 0 : if( FD_UNLIKELY( agave_cpu[ i ]>=fd_numa_cpu_cnt() ) )
291 0 : FD_LOG_ERR(( "The CPU affinity string in the configuration file under [layout.agave_affinity] specifies a CPU index of %hu, but the system "
292 0 : "only has %lu CPUs. You should either change the CPU allocations in the affinity string, or increase the number of CPUs "
293 0 : "in the system.",
294 0 : agave_cpu[ i ], fd_numa_cpu_cnt() ));
295 :
296 0 : for( ulong j=0UL; j<topo->tile_cnt; j++ ) {
297 0 : fd_topo_tile_t * tile = &topo->tiles[ j ];
298 0 : if( tile->cpu_idx==agave_cpu[ i ] ) FD_LOG_WARNING(( "Tile `%s:%lu` is already assigned to CPU %hu, but the CPU is also assigned to Agave. "
299 0 : "This may cause contention between the two tiles.", tile->name, tile->kind_id, agave_cpu[ i ] ));
300 0 : }
301 :
302 0 : if( FD_UNLIKELY( topo->agave_affinity_cnt>FD_TILE_MAX ) ) {
303 0 : FD_LOG_ERR(( "The CPU affinity string in the configuration file under [layout.agave_affinity] specifies more CPUs than Firedancer can use. "
304 0 : "You should either reduce the number of CPUs in the affinity string." ));
305 0 : }
306 0 : topo->agave_affinity_cpu_idx[ topo->agave_affinity_cnt++ ] = agave_cpu[ i ];
307 0 : }
308 0 : }
309 0 : }
310 :
311 : /* There is a special fseq that sits between the pack, bank, and poh
312 : tiles to indicate when the bank/poh tiles are done processing a
313 : microblock. Pack uses this to determine when to "unlock" accounts
314 : that it marked as locked because they were being used. */
315 :
316 9 : for( ulong i=0UL; i<bank_tile_cnt; i++ ) {
317 6 : fd_topo_obj_t * busy_obj = fd_topob_obj( topo, "fseq", "bank_busy" );
318 :
319 6 : fd_topo_tile_t * poh_tile = &topo->tiles[ fd_topo_find_tile( topo, "poh", 0UL ) ];
320 6 : fd_topo_tile_t * pack_tile = &topo->tiles[ fd_topo_find_tile( topo, "pack", 0UL ) ];
321 6 : fd_topob_tile_uses( topo, poh_tile, busy_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
322 6 : fd_topob_tile_uses( topo, pack_tile, busy_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
323 6 : FD_TEST( fd_pod_insertf_ulong( topo->props, busy_obj->id, "bank_busy.%lu", i ) );
324 6 : }
325 :
326 : /* There's another special fseq that's used to communicate the shred
327 : version from the Agave boot path to the shred tile. */
328 3 : fd_topo_obj_t * poh_shred_obj = fd_topob_obj( topo, "fseq", "poh_shred" );
329 3 : fd_topo_tile_t * poh_tile = &topo->tiles[ fd_topo_find_tile( topo, "poh", 0UL ) ];
330 3 : fd_topob_tile_uses( topo, poh_tile, poh_shred_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
331 6 : for( ulong i=0UL; i<shred_tile_cnt; i++ ) {
332 3 : fd_topo_tile_t * shred_tile = &topo->tiles[ fd_topo_find_tile( topo, "shred", i ) ];
333 3 : fd_topob_tile_uses( topo, shred_tile, poh_shred_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
334 3 : }
335 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, poh_shred_obj->id, "poh_shred" ) );
336 :
337 54 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
338 51 : fd_topo_tile_t * tile = &topo->tiles[ i ];
339 :
340 51 : if( FD_UNLIKELY( !strcmp( tile->name, "net" ) ) ) {
341 3 : strncpy( tile->net.interface, config->tiles.net.interface, sizeof(tile->net.interface) );
342 3 : memcpy( tile->net.src_mac_addr, config->tiles.net.mac_addr, 6UL );
343 :
344 3 : tile->net.xdp_aio_depth = config->tiles.net.xdp_aio_depth;
345 3 : tile->net.xdp_rx_queue_size = config->tiles.net.xdp_rx_queue_size;
346 3 : tile->net.xdp_tx_queue_size = config->tiles.net.xdp_tx_queue_size;
347 3 : tile->net.src_ip_addr = config->tiles.net.ip_addr;
348 3 : tile->net.zero_copy = !!strcmp( config->tiles.net.xdp_mode, "skb" ); /* disable zc for skb */
349 3 : fd_memset( tile->net.xdp_mode, 0, 4 );
350 3 : fd_memcpy( tile->net.xdp_mode, config->tiles.net.xdp_mode, strnlen( config->tiles.net.xdp_mode, 3 ) ); /* GCC complains about strncpy */
351 :
352 3 : tile->net.shred_listen_port = config->tiles.shred.shred_listen_port;
353 3 : tile->net.quic_transaction_listen_port = config->tiles.quic.quic_transaction_listen_port;
354 3 : tile->net.legacy_transaction_listen_port = config->tiles.quic.regular_transaction_listen_port;
355 :
356 : /* multihome support */
357 3 : ulong multi_cnt = tile->net.multihome_ip_addrs_cnt = config->tiles.net.multihome_ip_addrs_cnt;
358 3 : for( ulong j = 0; j < multi_cnt; ++j ) {
359 0 : tile->net.multihome_ip_addrs[j] = config->tiles.net.multihome_ip4_addrs[j];
360 0 : }
361 48 : } else if( FD_UNLIKELY( !strcmp( tile->name, "quic" ) ) ) {
362 3 : fd_memcpy( tile->quic.src_mac_addr, config->tiles.net.mac_addr, 6 );
363 3 : strncpy( tile->quic.identity_key_path, config->consensus.identity_path, sizeof(tile->quic.identity_key_path) );
364 :
365 3 : tile->quic.depth = topo->links[ tile->out_link_id[ 0 ] ].depth;
366 3 : tile->quic.reasm_cnt = config->tiles.quic.txn_reassembly_count;
367 3 : tile->quic.max_concurrent_connections = config->tiles.quic.max_concurrent_connections;
368 3 : tile->quic.max_concurrent_handshakes = config->tiles.quic.max_concurrent_handshakes;
369 3 : tile->quic.max_inflight_quic_packets = config->tiles.quic.max_inflight_quic_packets;
370 3 : tile->quic.ip_addr = config->tiles.net.ip_addr;
371 3 : tile->quic.quic_transaction_listen_port = config->tiles.quic.quic_transaction_listen_port;
372 3 : tile->quic.idle_timeout_millis = config->tiles.quic.idle_timeout_millis;
373 3 : tile->quic.ack_delay_millis = config->tiles.quic.ack_delay_millis;
374 3 : tile->quic.retry = config->tiles.quic.retry;
375 3 : tile->quic.max_concurrent_streams_per_connection = config->tiles.quic.max_concurrent_streams_per_connection;
376 :
377 45 : } else if( FD_UNLIKELY( !strcmp( tile->name, "verify" ) ) ) {
378 :
379 33 : } else if( FD_UNLIKELY( !strcmp( tile->name, "dedup" ) ) ) {
380 3 : tile->dedup.tcache_depth = config->tiles.dedup.signature_cache_size;
381 :
382 30 : } else if( FD_UNLIKELY( !strcmp( tile->name, "resolv" ) ) ) {
383 :
384 27 : } else if( FD_UNLIKELY( !strcmp( tile->name, "pack" ) ) ) {
385 3 : strncpy( tile->pack.identity_key_path, config->consensus.identity_path, sizeof(tile->pack.identity_key_path) );
386 :
387 3 : tile->pack.max_pending_transactions = config->tiles.pack.max_pending_transactions;
388 3 : tile->pack.bank_tile_count = config->layout.bank_tile_count;
389 3 : tile->pack.larger_max_cost_per_block = config->development.bench.larger_max_cost_per_block;
390 3 : tile->pack.larger_shred_limits_per_block = config->development.bench.larger_shred_limits_per_block;
391 3 : tile->pack.use_consumed_cus = config->tiles.pack.use_consumed_cus;
392 :
393 24 : } else if( FD_UNLIKELY( !strcmp( tile->name, "bank" ) ) ) {
394 :
395 18 : } else if( FD_UNLIKELY( !strcmp( tile->name, "poh" ) ) ) {
396 3 : strncpy( tile->poh.identity_key_path, config->consensus.identity_path, sizeof(tile->poh.identity_key_path) );
397 :
398 3 : tile->poh.plugins_enabled = plugins_enabled;
399 3 : tile->poh.bank_cnt = config->layout.bank_tile_count;
400 :
401 15 : } else if( FD_UNLIKELY( !strcmp( tile->name, "shred" ) ) ) {
402 3 : fd_memcpy( tile->shred.src_mac_addr, config->tiles.net.mac_addr, 6 );
403 3 : strncpy( tile->shred.identity_key_path, config->consensus.identity_path, sizeof(tile->shred.identity_key_path) );
404 :
405 3 : tile->shred.depth = topo->links[ tile->out_link_id[ 0 ] ].depth;
406 3 : tile->shred.ip_addr = config->tiles.net.ip_addr;
407 3 : tile->shred.fec_resolver_depth = config->tiles.shred.max_pending_shred_sets;
408 3 : tile->shred.expected_shred_version = config->consensus.expected_shred_version;
409 3 : tile->shred.shred_listen_port = config->tiles.shred.shred_listen_port;
410 3 : tile->shred.larger_shred_limits_per_block = config->development.bench.larger_shred_limits_per_block;
411 :
412 12 : } else if( FD_UNLIKELY( !strcmp( tile->name, "store" ) ) ) {
413 3 : tile->store.disable_blockstore_from_slot = config->development.bench.disable_blockstore_from_slot;
414 :
415 9 : } else if( FD_UNLIKELY( !strcmp( tile->name, "sign" ) ) ) {
416 3 : strncpy( tile->sign.identity_key_path, config->consensus.identity_path, sizeof(tile->sign.identity_key_path) );
417 :
418 6 : } else if( FD_UNLIKELY( !strcmp( tile->name, "metric" ) ) ) {
419 3 : if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( config->tiles.metric.prometheus_listen_address, &tile->metric.prometheus_listen_addr ) ) )
420 0 : FD_LOG_ERR(( "failed to parse prometheus listen address `%s`", config->tiles.metric.prometheus_listen_address ));
421 3 : tile->metric.prometheus_listen_port = config->tiles.metric.prometheus_listen_port;
422 :
423 3 : } else if( FD_UNLIKELY( !strcmp( tile->name, "cswtch" ) ) ) {
424 :
425 3 : } else if( FD_UNLIKELY( !strcmp( tile->name, "gui" ) ) ) {
426 0 : if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( config->tiles.gui.gui_listen_address, &tile->gui.listen_addr ) ) )
427 0 : FD_LOG_ERR(( "failed to parse gui listen address `%s`", config->tiles.gui.gui_listen_address ));
428 0 : tile->gui.listen_port = config->tiles.gui.gui_listen_port;
429 0 : tile->gui.is_voting = strcmp( config->consensus.vote_account_path, "" );
430 0 : strncpy( tile->gui.cluster, config->cluster, sizeof(tile->gui.cluster) );
431 0 : strncpy( tile->gui.identity_key_path, config->consensus.identity_path, sizeof(tile->gui.identity_key_path) );
432 :
433 0 : } else if( FD_UNLIKELY( !strcmp( tile->name, "plugin" ) ) ) {
434 :
435 0 : } else {
436 0 : FD_LOG_ERR(( "unknown tile name %lu `%s`", i, tile->name ));
437 0 : }
438 51 : }
439 :
440 3 : if( FD_UNLIKELY( is_auto_affinity ) ) fd_topob_auto_layout( topo );
441 :
442 3 : fd_topob_finish( topo, fdctl_obj_align, fdctl_obj_footprint, fdctl_obj_loose );
443 3 : config->topo = *topo;
444 3 : }
|