Line data Source code
1 : #include "fd_topob.h"
2 :
3 : #include "fd_pod_format.h"
4 : #include "../../util/shmem/fd_shmem_private.h"
5 :
6 : fd_topo_t *
7 : fd_topob_new( void * mem,
8 3 : char const * app_name ) {
9 3 : fd_topo_t * topo = (fd_topo_t *)mem;
10 :
11 3 : if( FD_UNLIKELY( !topo ) ) {
12 0 : FD_LOG_WARNING( ( "NULL topo" ) );
13 0 : return NULL;
14 0 : }
15 :
16 3 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)topo, alignof(fd_topo_t) ) ) ) {
17 0 : FD_LOG_WARNING( ( "misaligned topo" ) );
18 0 : return NULL;
19 0 : }
20 :
21 3 : fd_memset( topo, 0, sizeof(fd_topo_t) );
22 :
23 3 : FD_TEST( fd_pod_new( topo->props, sizeof(topo->props) ) );
24 :
25 3 : if( FD_UNLIKELY( strlen( app_name )>=sizeof(topo->app_name) ) ) FD_LOG_ERR(( "app_name too long: %s", app_name ));
26 3 : strncpy( topo->app_name, app_name, sizeof(topo->app_name) );
27 :
28 3 : return topo;
29 3 : }
30 :
31 : void
32 : fd_topob_wksp( fd_topo_t * topo,
33 99 : char const * name ) {
34 99 : if( FD_UNLIKELY( !topo || !name || !strlen( name ) ) ) FD_LOG_ERR(( "NULL args" ));
35 99 : if( FD_UNLIKELY( strlen( name )>=sizeof(topo->workspaces[ topo->wksp_cnt ].name ) ) ) FD_LOG_ERR(( "wksp name too long: %s", name ));
36 99 : if( FD_UNLIKELY( topo->wksp_cnt>=FD_TOPO_MAX_WKSPS ) ) FD_LOG_ERR(( "too many workspaces" ));
37 :
38 99 : fd_topo_wksp_t * wksp = &topo->workspaces[ topo->wksp_cnt ];
39 99 : strncpy( wksp->name, name, sizeof(wksp->name) );
40 99 : wksp->id = topo->wksp_cnt;
41 99 : topo->wksp_cnt++;
42 99 : }
43 :
44 : fd_topo_obj_t *
45 : fd_topob_obj( fd_topo_t * topo,
46 : char const * obj_name,
47 495 : char const * wksp_name ) {
48 495 : if( FD_UNLIKELY( !topo || !obj_name || !wksp_name ) ) FD_LOG_ERR(( "NULL args" ));
49 495 : if( FD_UNLIKELY( strlen( obj_name )>=sizeof(topo->objs[ topo->obj_cnt ].name ) ) ) FD_LOG_ERR(( "obj name too long: %s", obj_name ));
50 495 : if( FD_UNLIKELY( topo->obj_cnt>=FD_TOPO_MAX_OBJS ) ) FD_LOG_ERR(( "too many objects" ));
51 :
52 495 : ulong wksp_id = fd_topo_find_wksp( topo, wksp_name );
53 495 : if( FD_UNLIKELY( wksp_id==ULONG_MAX ) ) FD_LOG_ERR(( "workspace not found: %s", wksp_name ));
54 :
55 495 : fd_topo_obj_t * obj = &topo->objs[ topo->obj_cnt ];
56 495 : strncpy( obj->name, obj_name, sizeof(obj->name) );
57 495 : obj->id = topo->obj_cnt;
58 495 : obj->wksp_id = wksp_id;
59 495 : topo->obj_cnt++;
60 :
61 495 : return obj;
62 495 : }
63 :
64 : void
65 : fd_topob_link( fd_topo_t * topo,
66 : char const * link_name,
67 : char const * wksp_name,
68 : ulong depth,
69 : ulong mtu,
70 99 : ulong burst ) {
71 99 : if( FD_UNLIKELY( !topo || !link_name || !wksp_name ) ) FD_LOG_ERR(( "NULL args" ));
72 99 : if( FD_UNLIKELY( strlen( link_name )>=sizeof(topo->links[ topo->link_cnt ].name ) ) ) FD_LOG_ERR(( "link name too long: %s", link_name ));
73 99 : if( FD_UNLIKELY( topo->link_cnt>=FD_TOPO_MAX_LINKS ) ) FD_LOG_ERR(( "too many links" ));
74 :
75 99 : ulong kind_id = 0UL;
76 1683 : for( ulong i=0UL; i<topo->link_cnt; i++ ) {
77 1584 : if( !strcmp( topo->links[ i ].name, link_name ) ) kind_id++;
78 1584 : }
79 :
80 99 : fd_topo_link_t * link = &topo->links[ topo->link_cnt ];
81 99 : strncpy( link->name, link_name, sizeof(link->name) );
82 99 : link->id = topo->link_cnt;
83 99 : link->kind_id = kind_id;
84 99 : link->depth = depth;
85 99 : link->mtu = mtu;
86 99 : link->burst = burst;
87 :
88 99 : fd_topo_obj_t * obj = fd_topob_obj( topo, "mcache", wksp_name );
89 99 : link->mcache_obj_id = obj->id;
90 99 : FD_TEST( fd_pod_insertf_ulong( topo->props, depth, "obj.%lu.depth", obj->id ) );
91 :
92 99 : obj = fd_topob_obj( topo, "dcache", wksp_name );
93 99 : link->dcache_obj_id = obj->id;
94 99 : FD_TEST( fd_pod_insertf_ulong( topo->props, depth, "obj.%lu.depth", obj->id ) );
95 99 : FD_TEST( fd_pod_insertf_ulong( topo->props, burst, "obj.%lu.burst", obj->id ) );
96 99 : FD_TEST( fd_pod_insertf_ulong( topo->props, mtu, "obj.%lu.mtu", obj->id ) );
97 99 : topo->link_cnt++;
98 99 : }
99 :
100 : void
101 : fd_topob_tile_uses( fd_topo_t * topo,
102 : fd_topo_tile_t * tile,
103 : fd_topo_obj_t * obj,
104 798 : int mode ) {
105 798 : (void)topo;
106 :
107 798 : if( FD_UNLIKELY( tile->uses_obj_cnt>=FD_TOPO_MAX_TILE_OBJS ) ) FD_LOG_ERR(( "tile `%s` uses too many objects", tile->name ));
108 :
109 798 : tile->uses_obj_id[ tile->uses_obj_cnt ] = obj->id;
110 798 : tile->uses_obj_mode[ tile->uses_obj_cnt ] = mode;
111 798 : tile->uses_obj_cnt++;
112 798 : }
113 :
114 : fd_topo_tile_t *
115 : fd_topob_tile( fd_topo_t * topo,
116 : char const * tile_name,
117 : char const * tile_wksp,
118 : char const * metrics_wksp,
119 : ulong cpu_idx,
120 69 : int is_agave ) {
121 :
122 69 : if( FD_UNLIKELY( !topo || !tile_name || !tile_wksp || !metrics_wksp ) ) FD_LOG_ERR(( "NULL args" ));
123 69 : if( FD_UNLIKELY( strlen( tile_name )>=sizeof(topo->tiles[ topo->tile_cnt ].name ) ) ) FD_LOG_ERR(( "tile name too long: %s", tile_name ));
124 69 : if( FD_UNLIKELY( topo->tile_cnt>=FD_TOPO_MAX_TILES ) ) FD_LOG_ERR(( "too many tiles" ));
125 :
126 69 : ulong kind_id = 0UL;
127 828 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
128 759 : if( !strcmp( topo->tiles[ i ].name, tile_name ) ) kind_id++;
129 759 : }
130 :
131 69 : fd_topo_tile_t * tile = &topo->tiles[ topo->tile_cnt ];
132 69 : strncpy( tile->name, tile_name, sizeof(tile->name) );
133 69 : tile->id = topo->tile_cnt;
134 69 : tile->kind_id = kind_id;
135 69 : tile->is_agave = is_agave;
136 69 : tile->cpu_idx = cpu_idx;
137 69 : tile->in_cnt = 0UL;
138 69 : tile->out_cnt = 0UL;
139 69 : tile->uses_obj_cnt = 0UL;
140 :
141 69 : fd_topo_obj_t * tile_obj = fd_topob_obj( topo, "tile", tile_wksp );
142 69 : tile->tile_obj_id = tile_obj->id;
143 69 : fd_topob_tile_uses( topo, tile, tile_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
144 :
145 69 : fd_topo_obj_t * obj = fd_topob_obj( topo, "metrics", metrics_wksp );
146 69 : tile->metrics_obj_id = obj->id;
147 69 : fd_topob_tile_uses( topo, tile, obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
148 :
149 69 : topo->tile_cnt++;
150 69 : return tile;
151 69 : }
152 :
153 : void
154 : fd_topob_tile_in( fd_topo_t * topo,
155 : char const * tile_name,
156 : ulong tile_kind_id,
157 : char const * fseq_wksp,
158 : char const * link_name,
159 : ulong link_kind_id,
160 : int reliable,
161 144 : int polled ) {
162 144 : if( FD_UNLIKELY( !topo || !tile_name || !fseq_wksp || !link_name ) ) FD_LOG_ERR(( "NULL args" ));
163 :
164 144 : ulong tile_id = fd_topo_find_tile( topo, tile_name, tile_kind_id );
165 144 : if( FD_UNLIKELY( tile_id==ULONG_MAX ) ) FD_LOG_ERR(( "tile not found: %s:%lu", tile_name, tile_kind_id ));
166 144 : fd_topo_tile_t * tile = &topo->tiles[ tile_id ];
167 :
168 144 : ulong link_id = fd_topo_find_link( topo, link_name, link_kind_id );
169 144 : if( FD_UNLIKELY( link_id==ULONG_MAX ) ) FD_LOG_ERR(( "link not found: %s:%lu", link_name, link_kind_id ));
170 144 : fd_topo_link_t * link = &topo->links[ link_id ];
171 :
172 144 : if( FD_UNLIKELY( tile->in_cnt>=FD_TOPO_MAX_TILE_IN_LINKS ) ) FD_LOG_ERR(( "too many in links: %s:%lu", tile_name, tile_kind_id ) );
173 144 : tile->in_link_id[ tile->in_cnt ] = link->id;
174 144 : tile->in_link_reliable[ tile->in_cnt ] = reliable;
175 144 : tile->in_link_poll[ tile->in_cnt ] = polled;
176 144 : fd_topo_obj_t * obj = fd_topob_obj( topo, "fseq", fseq_wksp );
177 144 : fd_topob_tile_uses( topo, tile, obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
178 144 : tile->in_link_fseq_obj_id[ tile->in_cnt ] = obj->id;
179 144 : tile->in_cnt++;
180 :
181 144 : fd_topob_tile_uses( topo, tile, &topo->objs[ link->mcache_obj_id ], FD_SHMEM_JOIN_MODE_READ_ONLY );
182 144 : if( FD_LIKELY( link->mtu ) ) {
183 144 : fd_topob_tile_uses( topo, tile, &topo->objs[ link->dcache_obj_id ], FD_SHMEM_JOIN_MODE_READ_ONLY );
184 144 : }
185 144 : }
186 :
187 : void
188 : fd_topob_tile_out( fd_topo_t * topo,
189 : char const * tile_name,
190 : ulong tile_kind_id,
191 : char const * link_name,
192 99 : ulong link_kind_id ) {
193 99 : ulong tile_id = fd_topo_find_tile( topo, tile_name, tile_kind_id );
194 99 : if( FD_UNLIKELY( tile_id==ULONG_MAX ) ) FD_LOG_ERR(( "tile not found: %s:%lu", tile_name, tile_kind_id ));
195 99 : fd_topo_tile_t * tile = &topo->tiles[ tile_id ];
196 :
197 99 : ulong link_id = fd_topo_find_link( topo, link_name, link_kind_id );
198 99 : if( FD_UNLIKELY( link_id==ULONG_MAX ) ) FD_LOG_ERR(( "link not found: %s:%lu", link_name, link_kind_id ));
199 99 : fd_topo_link_t * link = &topo->links[ link_id ];
200 :
201 99 : if( FD_UNLIKELY( tile->out_cnt>=FD_TOPO_MAX_TILE_OUT_LINKS ) ) FD_LOG_ERR(( "too many out links: %s", tile_name ));
202 99 : tile->out_link_id[ tile->out_cnt ] = link->id;
203 99 : tile->out_cnt++;
204 :
205 99 : fd_topob_tile_uses( topo, tile, &topo->objs[ link->mcache_obj_id ], FD_SHMEM_JOIN_MODE_READ_WRITE );
206 99 : if( FD_LIKELY( link->mtu ) ) {
207 99 : fd_topob_tile_uses( topo, tile, &topo->objs[ link->dcache_obj_id ], FD_SHMEM_JOIN_MODE_READ_WRITE );
208 99 : }
209 99 : }
210 :
211 : static void
212 3 : validate( fd_topo_t const * topo ) {
213 : /* Objects have valid wksp_ids */
214 498 : for( ulong i=0UL; i<topo->obj_cnt; i++ ) {
215 495 : if( FD_UNLIKELY( topo->objs[ i ].wksp_id>=topo->wksp_cnt ) )
216 0 : FD_LOG_ERR(( "invalid workspace id %lu", topo->objs[ i ].wksp_id ));
217 495 : }
218 :
219 : /* Tile ins are valid */
220 72 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
221 213 : for( ulong j=0UL; j<topo->tiles[ i ].in_cnt; j++ ) {
222 144 : if( FD_UNLIKELY( topo->tiles[ i ].in_link_id[ j ]>=topo->link_cnt ) )
223 0 : FD_LOG_ERR(( "tile %lu (%s) has invalid in link %lu", i, topo->tiles[ i ].name, topo->tiles[ i ].in_link_id[ j ] ));
224 144 : }
225 69 : }
226 :
227 : /* Tile does not have duplicated ins */
228 72 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
229 213 : for( ulong j=0UL; j<topo->tiles[ i ].in_cnt; j++ ) {
230 756 : for( ulong k=0UL; k<topo->tiles[ i ].in_cnt; k++ ) {
231 612 : if( FD_UNLIKELY( j==k ) ) continue;
232 468 : if( FD_UNLIKELY( topo->tiles[ i ].in_link_id[ j ] == topo->tiles[ i ].in_link_id[ k ] ) )
233 0 : FD_LOG_ERR(( "tile %lu (%s) has duplicated in link %lu (%s)", i, topo->tiles[ i ].name,
234 468 : topo->tiles[ i ].in_link_id[ j ], topo->links[ topo->tiles[ i ].in_link_id[ j ] ].name ));
235 468 : }
236 144 : }
237 69 : }
238 :
239 : /* Tile does not have duplicated outs */
240 72 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
241 168 : for( ulong j=0UL; j<topo->tiles[ i ].out_cnt; j++ ) {
242 558 : for( ulong k=0UL; k<topo->tiles[ i ].out_cnt; k++ ) {
243 459 : if( FD_UNLIKELY( j==k ) ) continue;
244 360 : if( FD_UNLIKELY( topo->tiles[ i ].out_link_id[ j ] == topo->tiles[ i ].out_link_id[ k ] ) )
245 0 : FD_LOG_ERR(( "tile %lu (%s) has duplicated out link %lu (%s)", i, topo->tiles[ i ].name,
246 360 : topo->tiles[ i ].out_link_id[ j ], topo->links[ topo->tiles[ i ].out_link_id[ j ] ].name ));
247 360 : }
248 99 : }
249 69 : }
250 :
251 : /* Tile outs are different than ins */
252 72 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
253 168 : for( ulong j=0UL; j<topo->tiles[ i ].out_cnt; j++ ) {
254 456 : for( ulong k=0UL; k<topo->tiles[ i ].in_cnt; k++ ) {
255 357 : char const * link_name = topo->links[ topo->tiles[ i ].out_link_id[ j ] ].name;
256 : /* PoH tile "publishes" this on behalf of Agave, so it's not
257 : a real circular link. */
258 357 : if( FD_UNLIKELY( !strcmp( link_name, "stake_out" ) ||
259 357 : !strcmp( link_name, "crds_shred" ) ) ) continue;
260 :
261 321 : if( FD_UNLIKELY( topo->tiles[ i ].out_link_id[ j ] == topo->tiles[ i ].in_link_id[ k ] ) )
262 0 : FD_LOG_ERR(( "tile %lu has out link %lu same as in", i, topo->tiles[ i ].out_link_id[ j ] ));
263 321 : }
264 99 : }
265 69 : }
266 :
267 : /* Non polling tile ins are also not reliable */
268 72 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
269 213 : for( ulong j=0UL; j<topo->tiles[ i ].in_cnt; j++ ) {
270 144 : if( FD_UNLIKELY( !topo->tiles[ i ].in_link_poll[ j ] && topo->tiles[ i ].in_link_reliable[ j ] ) )
271 0 : FD_LOG_ERR(( "tile %lu has in link %lu which is not polled but reliable", i, topo->tiles[ i ].in_link_id[ j ] ));
272 144 : }
273 69 : }
274 :
275 : /* Tile outs are valid */
276 72 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
277 168 : for( ulong j=0UL; j<topo->tiles[ i ].out_cnt; j++ ) {
278 99 : if( FD_UNLIKELY( topo->tiles[ i ].out_link_id[ j ] >= topo->link_cnt ) )
279 0 : FD_LOG_ERR(( "tile %lu has invalid out link %lu", i, topo->tiles[ i ].out_link_id[ j ] ));
280 99 : }
281 69 : }
282 :
283 : /* Workspace names are unique */
284 102 : for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
285 3366 : for( ulong j=0UL; j<topo->wksp_cnt; j++ ) {
286 3267 : if( FD_UNLIKELY( i==j ) ) continue;
287 3168 : if( FD_UNLIKELY( !strcmp( topo->workspaces[ i ].name, topo->workspaces[ j ].name ) ) )
288 0 : FD_LOG_ERR(( "duplicate workspace name %s", topo->workspaces[ i ].name ));
289 3168 : }
290 99 : }
291 :
292 : /* Each workspace is identified correctly */
293 102 : for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
294 99 : if( FD_UNLIKELY( topo->workspaces[ i ].id != i ) )
295 0 : FD_LOG_ERR(( "workspace %lu has id %lu", i, topo->workspaces[ i ].id ));
296 99 : }
297 :
298 : /* Each link has exactly one producer */
299 102 : for( ulong i=0UL; i<topo->link_cnt; i++ ) {
300 99 : ulong producer_cnt = 0;
301 2376 : for( ulong j=0UL; j<topo->tile_cnt; j++ ) {
302 5544 : for( ulong k=0UL; k<topo->tiles[ j ].out_cnt; k++ ) {
303 3267 : if( topo->tiles[ j ].out_link_id[ k ]==i ) producer_cnt++;
304 3267 : }
305 2277 : }
306 99 : if( FD_UNLIKELY( producer_cnt!=1UL ) )
307 0 : FD_LOG_ERR(( "link %lu (%s:%lu) has %lu producers", i, topo->links[ i ].name, topo->links[ i ].kind_id, producer_cnt ));
308 99 : }
309 :
310 : /* Each link has at least one consumer */
311 102 : for( ulong i=0UL; i<topo->link_cnt; i++ ) {
312 99 : ulong cnt = fd_topo_link_consumer_cnt( topo, &topo->links[ i ] );
313 99 : if( FD_UNLIKELY( cnt < 1 ) )
314 0 : FD_LOG_ERR(( "link %lu (%s:%lu) has %lu consumers", i, topo->links[ i ].name, topo->links[ i ].kind_id, cnt ));
315 99 : }
316 3 : }
317 :
318 : void
319 3 : fd_topob_auto_layout( fd_topo_t * topo ) {
320 : /* Incredibly simple automatic layout system for now ... just assign
321 : tiles to CPU cores in NUMA sequential order, except for a few tiles
322 : which should be floating. */
323 :
324 3 : char const * FLOATING[] = {
325 3 : "metric",
326 3 : "cswtch",
327 3 : "bencho",
328 3 : "bhole", /* FIREDANCER only */
329 3 : };
330 :
331 3 : char const * ORDERED[] = {
332 3 : "benchg",
333 3 : "benchs",
334 3 : "net",
335 3 : "quic",
336 3 : "verify",
337 3 : "dedup",
338 3 : "resolv",
339 3 : "pack",
340 3 : "bank",
341 3 : "poh",
342 : #ifdef FD_HAS_NO_AGAVE
343 : "pohi", /* FIREDANCER only */
344 : #endif
345 3 : "shred",
346 3 : "store",
347 : #ifdef FD_HAS_NO_AGAVE
348 : "storei", /* FIREDANCER only */
349 : #endif
350 3 : "sign",
351 3 : "plugin",
352 3 : "gui",
353 : #ifdef FD_HAS_NO_AGAVE
354 : "gossip", /* FIREDANCER only */
355 : "repair", /* FIREDANCER only */
356 : "replay", /* FIREDANCER only */
357 : "rtpool", /* FIREDANCER only */
358 : "sender", /* FIREDANCER only */
359 : "eqvoc", /* FIREDANCER only */
360 : "rpcsrv", /* FIREDANCER only */
361 : "snaps", /* FIREDANCER only */
362 : "stpool", /* FIREDANCER only */
363 : #endif
364 3 : };
365 :
366 72 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
367 69 : fd_topo_tile_t * tile = &topo->tiles[ i ];
368 69 : tile->cpu_idx = ULONG_MAX;
369 69 : }
370 :
371 3 : ulong cpu_ordering[ FD_TILE_MAX ] = { 0UL };
372 3 : ulong num_cpus = fd_numa_cpu_cnt();
373 :
374 3 : ulong next_cpu_idx = 0UL;
375 3 : ulong num_numa_nodes = fd_numa_node_cnt();
376 6 : for( ulong i=0UL; i<num_numa_nodes; i++ ) {
377 195 : for( ulong j=0UL; j<num_cpus; j++ ) {
378 192 : ulong numa_node = fd_numa_node_idx( j );
379 192 : if( FD_UNLIKELY( numa_node!=i ) ) continue;
380 192 : FD_TEST( next_cpu_idx<FD_TILE_MAX );
381 192 : cpu_ordering[ next_cpu_idx++ ] = j;
382 192 : }
383 3 : }
384 :
385 3 : FD_TEST( next_cpu_idx==num_cpus );
386 :
387 3 : ulong cpu_idx = 0UL;
388 48 : for( ulong i=0UL; i<sizeof(ORDERED)/sizeof(ORDERED[0]); i++ ) {
389 1080 : for( ulong j=0UL; j<topo->tile_cnt; j++ ) {
390 1035 : fd_topo_tile_t * tile = &topo->tiles[ j ];
391 1035 : if( !strcmp( tile->name, ORDERED[ i ] ) ) {
392 63 : if( FD_UNLIKELY( cpu_idx>=num_cpus ) ) {
393 0 : FD_LOG_ERR(( "auto layout cannot set affinity for tile `%s:%lu` because all the CPUs are already assigned", tile->name, tile->kind_id ));
394 63 : } else {
395 63 : tile->cpu_idx = cpu_ordering[ cpu_idx++ ];
396 63 : }
397 63 : }
398 1035 : }
399 45 : }
400 :
401 : /* Make sure all the tiles we haven't set are supposed to be floating. */
402 72 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
403 69 : fd_topo_tile_t * tile = &topo->tiles[ i ];
404 69 : if( tile->cpu_idx!=ULONG_MAX ) continue;
405 :
406 6 : int found = 0;
407 9 : for( ulong j=0UL; j<sizeof(FLOATING)/sizeof(FLOATING[0]); j++ ) {
408 9 : if( !strcmp( tile->name, FLOATING[ j ] ) ) {
409 6 : found = 1;
410 6 : break;
411 6 : }
412 9 : }
413 :
414 6 : if( FD_UNLIKELY( !found ) ) FD_LOG_WARNING(( "auto layout cannot affine tile `%s:%lu` because it is unknown. Leaving it floating", tile->name, tile->kind_id ));
415 6 : }
416 :
417 132 : for( ulong i=cpu_idx; i<num_cpus; i++ ) {
418 129 : if( FD_LIKELY( topo->agave_affinity_cnt<sizeof(topo->agave_affinity_cpu_idx)/sizeof(topo->agave_affinity_cpu_idx[0]) ) ) {
419 129 : topo->agave_affinity_cpu_idx[ topo->agave_affinity_cnt++ ] = cpu_ordering[ i ];
420 129 : }
421 129 : }
422 3 : }
423 :
424 : void
425 : fd_topob_finish( fd_topo_t * topo,
426 : ulong (* align )( fd_topo_t const * topo, fd_topo_obj_t const * obj ),
427 : ulong (* footprint)( fd_topo_t const * topo, fd_topo_obj_t const * obj ),
428 3 : ulong (* loose )( fd_topo_t const * topo, fd_topo_obj_t const * obj) ) {
429 72 : for( ulong z=0UL; z<topo->tile_cnt; z++ ) {
430 69 : fd_topo_tile_t * tile = &topo->tiles[ z ];
431 :
432 69 : ulong in_cnt = 0UL;
433 213 : for( ulong i=0UL; i<tile->in_cnt; i++ ) {
434 144 : if( FD_UNLIKELY( !tile->in_link_poll[ i ] ) ) continue;
435 141 : in_cnt++;
436 141 : }
437 :
438 69 : ulong cons_cnt = 0UL;
439 1656 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
440 1587 : fd_topo_tile_t * consumer_tile = &topo->tiles[ i ];
441 4899 : for( ulong j=0UL; j<consumer_tile->in_cnt; j++ ) {
442 8064 : for( ulong k=0UL; k<tile->out_cnt; k++ ) {
443 4752 : if( FD_UNLIKELY( consumer_tile->in_link_id[ j ]==tile->out_link_id[ k ] && consumer_tile->in_link_reliable[ j ] ) ) {
444 93 : cons_cnt++;
445 93 : }
446 4752 : }
447 3312 : }
448 1587 : }
449 :
450 69 : FD_TEST( !fd_pod_replacef_ulong( topo->props, in_cnt, "obj.%lu.in_cnt", tile->metrics_obj_id ) );
451 69 : FD_TEST( !fd_pod_replacef_ulong( topo->props, cons_cnt, "obj.%lu.cons_cnt", tile->metrics_obj_id ) );
452 69 : }
453 :
454 102 : for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
455 99 : fd_topo_wksp_t * wksp = &topo->workspaces[ i ];
456 :
457 99 : ulong loose_sz = 0UL;
458 16434 : for( ulong j=0UL; j<topo->obj_cnt; j++ ) {
459 16335 : fd_topo_obj_t * obj = &topo->objs[ j ];
460 16335 : if( FD_UNLIKELY( obj->wksp_id!=wksp->id ) ) continue;
461 495 : loose_sz += loose( topo, obj );
462 495 : }
463 :
464 99 : ulong part_max = 3UL + (loose_sz / (64UL << 10)); /* 3 for initial alignment + actual alloc + residual padding */
465 99 : ulong offset = fd_ulong_align_up( fd_wksp_private_data_off( part_max ), fd_topo_workspace_align() );
466 :
467 16434 : for( ulong j=0UL; j<topo->obj_cnt; j++ ) {
468 16335 : fd_topo_obj_t * obj = &topo->objs[ j ];
469 16335 : if( FD_UNLIKELY( obj->wksp_id!=wksp->id ) ) continue;
470 :
471 495 : offset = fd_ulong_align_up( offset, align( topo, obj ) );
472 495 : obj->offset = offset;
473 495 : obj->footprint = footprint( topo, obj );
474 495 : offset += obj->footprint;
475 495 : }
476 :
477 99 : ulong footprint = fd_ulong_align_up( offset, fd_topo_workspace_align() );
478 :
479 : /* Compute footprint for a workspace that can store our footprint,
480 : with an extra align of padding incase gaddr_lo is not aligned. */
481 99 : ulong total_wksp_footprint = fd_wksp_footprint( part_max, footprint + fd_topo_workspace_align() + loose_sz );
482 :
483 99 : ulong page_sz = FD_SHMEM_GIGANTIC_PAGE_SZ;
484 99 : if( FD_UNLIKELY( total_wksp_footprint < 4 * FD_SHMEM_HUGE_PAGE_SZ ) ) page_sz = FD_SHMEM_HUGE_PAGE_SZ;
485 :
486 99 : ulong wksp_aligned_footprint = fd_ulong_align_up( total_wksp_footprint, page_sz );
487 :
488 : /* Give any leftover space in the underlying shared memory to the
489 : data region of the workspace, since we might as well use it. */
490 99 : wksp->part_max = part_max;
491 99 : wksp->known_footprint = footprint;
492 99 : wksp->total_footprint = wksp_aligned_footprint - fd_ulong_align_up( fd_wksp_private_data_off( part_max ), fd_topo_workspace_align() );
493 99 : wksp->page_sz = page_sz;
494 99 : wksp->page_cnt = wksp_aligned_footprint / page_sz;
495 99 : }
496 :
497 3 : validate( topo );
498 3 : }
|