Line data Source code
1 : #include "fd_topo.h"
2 :
3 : #include "../metrics/fd_metrics.h"
4 : #include "../../util/pod/fd_pod_format.h"
5 : #include "../../util/wksp/fd_wksp_private.h"
6 : #include "../../util/shmem/fd_shmem_private.h"
7 :
8 : #include <stdio.h>
9 : #include <errno.h>
10 : #include <unistd.h>
11 : #include <sys/stat.h>
12 :
13 : void *
14 : fd_topo_obj_laddr( fd_topo_t const * topo,
15 30 : ulong obj_id ) {
16 30 : fd_topo_obj_t const * obj = &topo->objs[ obj_id ];
17 30 : if( FD_UNLIKELY( obj_id==ULONG_MAX ) ) FD_LOG_CRIT(( "invalid obj_id ULONG_MAX" ));
18 30 : if( FD_UNLIKELY( obj_id>=FD_TOPO_MAX_OBJS ) ) FD_LOG_CRIT(( "invalid obj_id %lu", obj_id ));
19 30 : FD_TEST( obj->id == obj_id );
20 30 : FD_TEST( obj->offset );
21 30 : return (void *)((ulong)topo->workspaces[ obj->wksp_id ].wksp + obj->offset);
22 30 : }
23 :
24 : void
25 : fd_topo_join_workspace( fd_topo_t * topo,
26 : fd_topo_wksp_t * wksp,
27 : int mode,
28 0 : int dump ) {
29 0 : char name[ PATH_MAX ];
30 0 : FD_TEST( fd_cstr_printf_check( name, PATH_MAX, NULL, "%s_%s.wksp", topo->app_name, wksp->name ) );
31 :
32 0 : wksp->wksp = fd_wksp_join( fd_shmem_join( name, mode, dump, NULL, NULL, NULL ) );
33 0 : if( FD_UNLIKELY( !wksp->wksp ) ) FD_LOG_ERR(( "fd_wksp_join failed" ));
34 0 : }
35 :
36 : FD_FN_PURE static int
37 0 : tile_needs_wksp( fd_topo_t const * topo, fd_topo_tile_t const * tile, ulong wksp_id ) {
38 0 : int mode = -1;
39 0 : for( ulong i=0UL; i<tile->uses_obj_cnt; i++ ) {
40 0 : if( FD_UNLIKELY( topo->objs[ tile->uses_obj_id[ i ] ].wksp_id==wksp_id ) ) {
41 0 : mode = fd_int_max( mode, tile->uses_obj_mode[ i ] );
42 0 : }
43 0 : }
44 0 : return mode;
45 0 : }
46 :
47 : void
48 : fd_topo_join_tile_workspaces( fd_topo_t * topo,
49 : fd_topo_tile_t * tile,
50 0 : int core_dump_level ) {
51 0 : for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
52 0 : int needs_wksp = tile_needs_wksp( topo, tile, i );
53 0 : if( FD_LIKELY( -1!=needs_wksp ) ) {
54 0 : int dump = core_dump_level >= topo->workspaces[ i ].core_dump_level ? 1 : 0;
55 0 : fd_topo_join_workspace( topo, &topo->workspaces[ i ], needs_wksp, dump );
56 0 : }
57 0 : }
58 0 : }
59 :
60 : void
61 : fd_topo_join_workspaces( fd_topo_t * topo,
62 : int mode,
63 0 : int core_dump_level ) {
64 0 : for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
65 0 : int dump = core_dump_level >= topo->workspaces[ i ].core_dump_level ? 1 : 0;
66 0 : fd_topo_join_workspace( topo, &topo->workspaces[ i ], mode, dump );
67 0 : }
68 0 : }
69 :
70 : void
71 : fd_topo_leave_workspace( fd_topo_t * topo FD_PARAM_UNUSED,
72 0 : fd_topo_wksp_t * wksp ) {
73 0 : if( FD_LIKELY( wksp->wksp ) ) {
74 0 : if( FD_UNLIKELY( fd_wksp_detach( wksp->wksp ) ) ) FD_LOG_ERR(( "fd_wksp_detach failed" ));
75 0 : wksp->wksp = NULL;
76 0 : wksp->known_footprint = 0UL;
77 0 : wksp->total_footprint = 0UL;
78 0 : }
79 0 : }
80 :
81 : void
82 0 : fd_topo_leave_workspaces( fd_topo_t * topo ) {
83 0 : for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
84 0 : fd_topo_leave_workspace( topo, &topo->workspaces[ i ] );
85 0 : }
86 0 : }
87 :
88 : extern char fd_shmem_private_base[ FD_SHMEM_PRIVATE_BASE_MAX ];
89 :
90 : int
91 : fd_topo_create_workspace( fd_topo_t * topo,
92 : fd_topo_wksp_t * wksp,
93 0 : int update_existing ) {
94 0 : char name[ PATH_MAX ];
95 0 : FD_TEST( fd_cstr_printf_check( name, PATH_MAX, NULL, "%s_%s.wksp", topo->app_name, wksp->name ) );
96 :
97 0 : ulong sub_page_cnt[ 1 ] = { wksp->page_cnt };
98 0 : ulong sub_cpu_idx [ 1 ] = { fd_shmem_cpu_idx( wksp->numa_idx ) };
99 :
100 0 : int err;
101 0 : if( FD_UNLIKELY( update_existing ) ) {
102 0 : err = fd_shmem_update_multi( name, wksp->page_sz, 1, sub_page_cnt, sub_cpu_idx, S_IRUSR | S_IWUSR ); /* logs details */
103 0 : } else {
104 0 : err = fd_shmem_create_multi( name, wksp->page_sz, 1, sub_page_cnt, sub_cpu_idx, S_IRUSR | S_IWUSR ); /* logs details */
105 0 : }
106 0 : if( FD_UNLIKELY( err && errno==ENOMEM ) ) return -1;
107 0 : else if( FD_UNLIKELY( err ) ) FD_LOG_ERR(( "fd_shmem_create_multi failed" ));
108 :
109 0 : void * shmem = fd_shmem_join( name, FD_SHMEM_JOIN_MODE_READ_WRITE, 0, NULL, NULL, NULL ); /* logs details */
110 :
111 0 : void * wkspmem = fd_wksp_new( shmem, name, 0U, wksp->part_max, wksp->total_footprint ); /* logs details */
112 0 : if( FD_UNLIKELY( !wkspmem ) ) FD_LOG_ERR(( "fd_wksp_new failed" ));
113 :
114 0 : fd_wksp_t * join = fd_wksp_join( wkspmem );
115 0 : if( FD_UNLIKELY( !join ) ) FD_LOG_ERR(( "fd_wksp_join failed" ));
116 :
117 : /* Footprint has been predetermined so that this alloc() call must
118 : succeed inside the data region. The difference between total_footprint
119 : and known_footprint is given to "loose" data, that may be dynamically
120 : allocated out of the workspace at runtime. */
121 0 : if( FD_LIKELY( wksp->known_footprint ) ) {
122 0 : ulong offset = fd_wksp_alloc( join, fd_topo_workspace_align(), wksp->known_footprint, 1UL );
123 0 : if( FD_UNLIKELY( !offset ) ) FD_LOG_ERR(( "fd_wksp_alloc failed" ));
124 :
125 : /* gaddr_lo is the start of the workspace data region that can be
126 : given out in response to wksp alloc requests. We rely on an
127 : implicit assumption everywhere that the bytes we are given by
128 : this single allocation will be at gaddr_lo, so that we can find
129 : them, so we verify this here for paranoia in case the workspace
130 : alloc implementation changes. */
131 0 : if( FD_UNLIKELY( fd_ulong_align_up( ((struct fd_wksp_private*)join)->gaddr_lo, fd_topo_workspace_align() ) != offset ) )
132 0 : FD_LOG_ERR(( "wksp gaddr_lo %lu != offset %lu", fd_ulong_align_up( ((struct fd_wksp_private*)join)->gaddr_lo, fd_topo_workspace_align() ), offset ));
133 0 : }
134 :
135 0 : fd_wksp_leave( join );
136 :
137 0 : if( FD_UNLIKELY( fd_shmem_leave( shmem, NULL, NULL ) ) ) /* logs details */
138 0 : FD_LOG_ERR(( "fd_shmem_leave failed" ));
139 :
140 0 : return 0;
141 0 : }
142 :
143 : void
144 : fd_topo_wksp_new( fd_topo_t const * topo,
145 : fd_topo_wksp_t const * wksp,
146 0 : fd_topo_obj_callbacks_t ** callbacks ) {
147 0 : for( ulong i=0UL; i<topo->obj_cnt; i++ ) {
148 0 : fd_topo_obj_t const * obj = &topo->objs[ i ];
149 0 : if( FD_LIKELY( obj->wksp_id!=wksp->id ) ) continue;
150 :
151 0 : for( ulong j=0UL; callbacks[ j ]; j++ ) {
152 0 : if( FD_LIKELY( strcmp( callbacks[ j ]->name, obj->name ) ) ) continue;
153 :
154 0 : long ts = -fd_log_wallclock();
155 0 : if( FD_LIKELY( callbacks[ j ]->new ) ) callbacks[ j ]->new( topo, obj );
156 0 : long elapsed = fd_log_wallclock() + ts;
157 0 : if( FD_UNLIKELY( elapsed>(1000L*1000L*100L ) ) ) FD_LOG_WARNING(( "fd_topo_wksp_new(%s) took %ld ms", obj->name, elapsed/(1000L*1000L) ));
158 0 : else if( FD_UNLIKELY( elapsed>(1000L*1000L*5L ) ) ) FD_LOG_INFO(( "fd_topo_wksp_new(%s) took %ld ms", obj->name, elapsed/(1000L*1000L) ));
159 0 : break;
160 0 : }
161 0 : }
162 0 : }
163 :
164 : void
165 : fd_topo_workspace_fill( fd_topo_t * topo,
166 0 : fd_topo_wksp_t * wksp ) {
167 0 : for( ulong i=0UL; i<topo->link_cnt; i++ ) {
168 0 : fd_topo_link_t * link = &topo->links[ i ];
169 :
170 0 : if( FD_UNLIKELY( topo->objs[ link->mcache_obj_id ].wksp_id!=wksp->id ) ) continue;
171 0 : link->mcache = fd_mcache_join( fd_topo_obj_laddr( topo, link->mcache_obj_id ) );
172 0 : FD_TEST( link->mcache );
173 :
174 0 : if( link->mtu ) {
175 0 : if( FD_UNLIKELY( topo->objs[ link->dcache_obj_id ].wksp_id!=wksp->id ) ) continue;
176 0 : link->dcache = fd_dcache_join( fd_topo_obj_laddr( topo, link->dcache_obj_id ) );
177 0 : FD_TEST( link->dcache );
178 0 : }
179 0 : }
180 :
181 0 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
182 0 : fd_topo_tile_t * tile = &topo->tiles[ i ];
183 :
184 0 : if( FD_LIKELY( topo->objs[ tile->metrics_obj_id ].wksp_id==wksp->id ) ) {
185 0 : tile->metrics = fd_metrics_join( fd_topo_obj_laddr( topo, tile->metrics_obj_id ) );
186 0 : FD_TEST( tile->metrics );
187 0 : }
188 :
189 0 : for( ulong j=0UL; j<tile->in_cnt; j++ ) {
190 0 : if( FD_UNLIKELY( topo->objs[ tile->in_link_fseq_obj_id[ j ] ].wksp_id!=wksp->id ) ) continue;
191 0 : tile->in_link_fseq[ j ] = fd_fseq_join( fd_topo_obj_laddr( topo, tile->in_link_fseq_obj_id[ j ] ) );
192 0 : FD_TEST( tile->in_link_fseq[ j ] );
193 0 : }
194 0 : }
195 0 : }
196 :
197 : void
198 : fd_topo_fill_tile( fd_topo_t * topo,
199 0 : fd_topo_tile_t * tile ) {
200 0 : for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
201 0 : if( FD_UNLIKELY( -1!=tile_needs_wksp( topo, tile, i ) ) )
202 0 : fd_topo_workspace_fill( topo, &topo->workspaces[ i ] );
203 0 : }
204 0 : }
205 :
206 : void
207 0 : fd_topo_fill( fd_topo_t * topo ) {
208 0 : for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
209 0 : fd_topo_workspace_fill( topo, &topo->workspaces[ i ] );
210 0 : }
211 0 : }
212 :
213 : FD_FN_CONST static ulong
214 0 : fd_topo_tile_extra_huge_pages( fd_topo_tile_t const * tile ) {
215 : /* Every tile maps an additional set of pages for the stack. */
216 0 : (void)tile;
217 0 : return (FD_TILE_PRIVATE_STACK_SZ/FD_SHMEM_HUGE_PAGE_SZ)+2UL;
218 0 : }
219 :
220 : FD_FN_PURE static ulong
221 0 : fd_topo_tile_extra_normal_pages( fd_topo_tile_t const * tile ) {
222 0 : ulong key_pages = 0UL;
223 0 : if( FD_UNLIKELY( tile->keyswitch_obj_id ) ) {
224 : /* Certain tiles using fd_keyload_load need normal pages to hold
225 : key material. */
226 0 : key_pages = 5UL;
227 0 : }
228 :
229 0 : if( !strcmp( tile->name, "net" ) ) {
230 : /* net tile uses normal pages to hold xsk rings */
231 :
232 : /* xdp_desc struct is in linux UAPI so its size can be
233 : safely assumed */
234 0 : ulong xdp_desc_sz_bytes = 16UL;
235 0 : ulong xsk_rings_sz_bytes = 0UL;
236 0 : ulong xdp_address_sz_bytes = sizeof(ulong);
237 :
238 : /* rx ring */
239 0 : xsk_rings_sz_bytes += tile->xdp.xdp_rx_queue_size * xdp_desc_sz_bytes;
240 : /* tx ring */
241 0 : xsk_rings_sz_bytes += tile->xdp.xdp_tx_queue_size * xdp_desc_sz_bytes;
242 :
243 : /* completion ring */
244 0 : xsk_rings_sz_bytes += tile->xdp.xdp_tx_queue_size * xdp_address_sz_bytes;
245 : /* free ring */
246 0 : xsk_rings_sz_bytes += tile->xdp.free_ring_depth * xdp_address_sz_bytes;
247 :
248 0 : key_pages += fd_ulong_align_up( xsk_rings_sz_bytes, FD_SHMEM_NORMAL_PAGE_SZ ) / FD_SHMEM_NORMAL_PAGE_SZ;
249 :
250 : /* All 4 rings must store a ring header. This is 320 bytes
251 : per ring as of linux v6.18.3, however could change in
252 : the future so allow up to a full 4KB page per ring to
253 : be safe. */
254 0 : key_pages += 4UL;
255 0 : }
256 :
257 : /* All tiles lock one normal page for the fd_log shared lock. */
258 0 : return key_pages+1UL;
259 0 : }
260 :
261 : FD_FN_PURE static ulong
262 : fd_topo_mlock_max_tile1( fd_topo_t const * topo,
263 0 : fd_topo_tile_t const * tile ) {
264 0 : ulong tile_mem = 0UL;
265 :
266 0 : for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
267 0 : if( FD_UNLIKELY( -1!=tile_needs_wksp( topo, tile, i ) ) )
268 0 : tile_mem += topo->workspaces[ i ].page_cnt * topo->workspaces[ i ].page_sz;
269 0 : }
270 :
271 0 : return tile_mem +
272 0 : fd_topo_tile_extra_huge_pages( tile ) * FD_SHMEM_HUGE_PAGE_SZ +
273 0 : fd_topo_tile_extra_normal_pages( tile ) * FD_SHMEM_NORMAL_PAGE_SZ;
274 0 : }
275 :
276 : FD_FN_PURE ulong
277 0 : fd_topo_mlock_max_tile( fd_topo_t const * topo ) {
278 0 : ulong highest_tile_mem = 0UL;
279 0 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
280 0 : fd_topo_tile_t const * tile = &topo->tiles[ i ];
281 0 : highest_tile_mem = fd_ulong_max( highest_tile_mem, fd_topo_mlock_max_tile1( topo, tile ) );
282 0 : }
283 :
284 0 : return highest_tile_mem;
285 0 : }
286 :
287 : FD_FN_PURE ulong
288 : fd_topo_gigantic_page_cnt( fd_topo_t const * topo,
289 0 : ulong numa_idx ) {
290 0 : ulong result = 0UL;
291 0 : for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
292 0 : fd_topo_wksp_t const * wksp = &topo->workspaces[ i ];
293 0 : if( FD_LIKELY( wksp->numa_idx!=numa_idx ) ) continue;
294 :
295 0 : if( FD_LIKELY( wksp->page_sz==FD_SHMEM_GIGANTIC_PAGE_SZ ) ) {
296 0 : result += wksp->page_cnt;
297 0 : }
298 0 : }
299 0 : return result;
300 0 : }
301 :
302 : FD_FN_PURE ulong
303 : fd_topo_huge_page_cnt( fd_topo_t const * topo,
304 : ulong numa_idx,
305 0 : int include_anonymous ) {
306 0 : ulong result = 0UL;
307 0 : for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
308 0 : fd_topo_wksp_t const * wksp = &topo->workspaces[ i ];
309 0 : if( FD_LIKELY( wksp->numa_idx!=numa_idx ) ) continue;
310 :
311 0 : if( FD_LIKELY( wksp->page_sz==FD_SHMEM_HUGE_PAGE_SZ ) ) {
312 0 : result += wksp->page_cnt;
313 0 : }
314 0 : }
315 :
316 : /* The stack huge pages are also placed in the hugetlbfs. */
317 0 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
318 0 : result += fd_topo_tile_extra_huge_pages( &topo->tiles[ i ] );
319 0 : }
320 :
321 : /* No anonymous huge pages in use yet. */
322 0 : (void)include_anonymous;
323 :
324 0 : return result;
325 0 : }
326 :
327 : FD_FN_PURE ulong
328 0 : fd_topo_normal_page_cnt( fd_topo_t * topo ) {
329 0 : ulong result = 0UL;
330 0 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
331 0 : result += fd_topo_tile_extra_normal_pages( &topo->tiles[ i ] );
332 0 : }
333 0 : return result;
334 0 : }
335 :
336 : FD_FN_PURE ulong
337 0 : fd_topo_mlock( fd_topo_t const * topo ) {
338 0 : ulong result = 0UL;
339 0 : for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
340 0 : result += topo->workspaces[ i ].page_cnt * topo->workspaces[ i ].page_sz;
341 0 : }
342 0 : return result;
343 0 : }
344 :
345 : static void
346 0 : fd_topo_mem_sz_string( ulong sz, char out[static 24] ) {
347 0 : if( FD_LIKELY( sz >= FD_SHMEM_GIGANTIC_PAGE_SZ ) ) {
348 0 : FD_TEST( fd_cstr_printf_check( out, 24, NULL, "%lu GiB", sz / (1 << 30) ) );
349 0 : } else if( FD_LIKELY( sz >= 1048576 ) ) {
350 0 : FD_TEST( fd_cstr_printf_check( out, 24, NULL, "%lu MiB", sz / (1 << 20) ) );
351 0 : } else if( FD_LIKELY( sz >= 1024 ) ) {
352 0 : FD_TEST( fd_cstr_printf_check( out, 24, NULL, "%lu KiB", sz / (1 << 10) ) );
353 0 : } else {
354 0 : FD_TEST( fd_cstr_printf_check( out, 24, NULL, "%lu B", sz ) );
355 0 : }
356 0 : }
357 :
358 : void
359 : fd_topo_print_log( int stdout,
360 0 : fd_topo_t * topo ) {
361 0 : char message[ 32UL*4096UL ] = {0}; /* Same as FD_LOG_BUF_SZ */
362 :
363 0 : char * cur = message;
364 0 : ulong remaining = sizeof(message) - 1; /* Leave one character at the end to ensure NUL terminated */
365 :
366 0 : #define PRINT( ... ) do { \
367 0 : int n = snprintf( cur, remaining, __VA_ARGS__ ); \
368 0 : if( FD_UNLIKELY( n < 0 ) ) FD_LOG_ERR(( "snprintf failed" )); \
369 0 : if( FD_UNLIKELY( (ulong)n >= remaining ) ) FD_LOG_ERR(( "snprintf overflow" )); \
370 0 : remaining -= (ulong)n; \
371 0 : cur += n; \
372 0 : } while( 0 )
373 :
374 0 : PRINT( "\nSUMMARY\n" );
375 :
376 : /* The logic to compute number of stack pages is taken from
377 : fd_tile_thread.cxx, in function fd_topo_tile_stack_join, and this
378 : should match that. */
379 0 : ulong stack_pages = topo->tile_cnt * FD_SHMEM_HUGE_PAGE_SZ * ((FD_TILE_PRIVATE_STACK_SZ/FD_SHMEM_HUGE_PAGE_SZ)+2UL);
380 :
381 : /* The logic to map these private pages into memory is in utility.c,
382 : under fd_keyload_load, and the amount of pages should be kept in
383 : sync. */
384 0 : ulong private_key_pages = 5UL * FD_SHMEM_NORMAL_PAGE_SZ;
385 0 : ulong total_bytes = fd_topo_mlock( topo ) + stack_pages + private_key_pages;
386 :
387 0 : PRINT(" %23s: %lu\n", "Total Tiles", topo->tile_cnt );
388 0 : PRINT(" %23s: %lu bytes (%lu GiB + %lu MiB + %lu KiB)\n",
389 0 : "Total Memory Locked",
390 0 : total_bytes,
391 0 : total_bytes / (1 << 30),
392 0 : (total_bytes % (1 << 30)) / (1 << 20),
393 0 : (total_bytes % (1 << 20)) / (1 << 10) );
394 :
395 0 : ulong required_gigantic_pages = 0UL;
396 0 : ulong required_huge_pages = 0UL;
397 :
398 0 : ulong numa_node_cnt = fd_shmem_numa_cnt();
399 0 : for( ulong i=0UL; i<numa_node_cnt; i++ ) {
400 0 : required_gigantic_pages += fd_topo_gigantic_page_cnt( topo, i );
401 0 : required_huge_pages += fd_topo_huge_page_cnt( topo, i, 0 );
402 0 : }
403 0 : PRINT(" %23s: %lu\n", "Required Gigantic Pages", required_gigantic_pages );
404 0 : PRINT(" %23s: %lu\n", "Required Huge Pages", required_huge_pages );
405 0 : PRINT(" %23s: %lu\n", "Required Normal Pages", fd_topo_normal_page_cnt( topo ) );
406 0 : for( ulong i=0UL; i<numa_node_cnt; i++ ) {
407 0 : PRINT(" %23s (NUMA node %lu): %lu\n", "Required Gigantic Pages", i, fd_topo_gigantic_page_cnt( topo, i ) );
408 0 : PRINT(" %23s (NUMA node %lu): %lu\n", "Required Huge Pages", i, fd_topo_huge_page_cnt( topo, i, 0 ) );
409 0 : }
410 :
411 0 : if( FD_UNLIKELY( topo->agave_affinity_cnt>0UL ) ) {
412 0 : char agave_affinity[4096];
413 0 : ulong offset = 0UL;
414 0 : for ( ulong i = 0UL; i < topo->agave_affinity_cnt; i++ ) {
415 0 : ulong sz;
416 0 : if( FD_LIKELY( i != 0UL )) FD_TEST( fd_cstr_printf_check( agave_affinity+offset, 4096-offset, &sz, ", %lu", topo->agave_affinity_cpu_idx[ i ] ) );
417 0 : else FD_TEST( fd_cstr_printf_check( agave_affinity+offset, 4096-offset, &sz, "%lu", topo->agave_affinity_cpu_idx[ i ] ) );
418 0 : offset += sz;
419 0 : }
420 0 : PRINT( " %23s: %s\n", "Agave Affinity", agave_affinity );
421 0 : }
422 :
423 0 : PRINT( "\nWORKSPACES\n");
424 0 : for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
425 0 : fd_topo_wksp_t * wksp = &topo->workspaces[ i ];
426 :
427 0 : char size[ 24 ];
428 0 : fd_topo_mem_sz_string( wksp->page_sz * wksp->page_cnt, size );
429 0 : PRINT( " %2lu (%7s): %12s page_cnt=%3lu page_sz=%-8s numa_idx=%-2lu footprint=%10lu loose=%10lu\n", i, size, wksp->name, wksp->page_cnt, fd_shmem_page_sz_to_cstr( wksp->page_sz ), wksp->numa_idx, wksp->known_footprint, wksp->total_footprint - wksp->known_footprint );
430 0 : }
431 :
432 0 : PRINT( "\nOBJECTS\n" );
433 0 : for( ulong i=0UL; i<topo->obj_cnt; i++ ) {
434 0 : fd_topo_obj_t * obj = &topo->objs[ i ];
435 :
436 0 : char size[ 24 ];
437 0 : fd_topo_mem_sz_string( obj->footprint, size );
438 0 : PRINT( " %3lu: %12s %12s wksp_id=%-2lu footprint=%7s offset=%lu",
439 0 : i, topo->workspaces[ obj->wksp_id ].name, obj->name,
440 0 : obj->wksp_id, size, obj->offset );
441 0 : for( fd_pod_iter_t iter=fd_pod_iter_init( fd_pod_queryf_subpod( topo->props, "obj.%lu", obj->id ) );
442 0 : !fd_pod_iter_done( iter );
443 0 : iter=fd_pod_iter_next( iter ) ) {
444 0 : fd_pod_info_t info = fd_pod_iter_info( iter );
445 0 : if( !strncmp( info.key, "seed", info.key_sz ) ) continue;
446 0 : PRINT( " %.*s", (int)info.key_sz, info.key );
447 0 : switch( info.val_type ) {
448 0 : case FD_POD_VAL_TYPE_CSTR:
449 0 : PRINT( "=%.*s", (int)info.val_sz, (char const *)info.val );
450 0 : break;
451 0 : case FD_POD_VAL_TYPE_ULONG: {
452 0 : ulong val; fd_ulong_svw_dec( info.val, &val );
453 0 : PRINT( "=%lu", val );
454 0 : break;
455 0 : }
456 0 : }
457 0 : }
458 0 : PRINT( "\n" );
459 0 : }
460 :
461 0 : PRINT( "\nLINKS\n" );
462 0 : for( ulong i=0UL; i<topo->link_cnt; i++ ) {
463 0 : fd_topo_link_t * link = &topo->links[ i ];
464 :
465 0 : char size[ 24 ];
466 0 : fd_topo_mem_sz_string( fd_dcache_req_data_sz( link->mtu, link->depth, link->burst, 1 ), size );
467 0 : PRINT( " %2lu (%7s): %12s kind_id=%-2lu wksp_id=%-2lu depth=%-5lu mtu=%-9lu burst=%lu\n", i, size, link->name, link->kind_id, topo->objs[ link->dcache_obj_id ].wksp_id, link->depth, link->mtu, link->burst );
468 0 : }
469 :
470 0 : #define PRINTIN( ... ) do { \
471 0 : int n = snprintf( cur_in, remaining_in, __VA_ARGS__ ); \
472 0 : if( FD_UNLIKELY( n < 0 ) ) FD_LOG_ERR(( "snprintf failed" )); \
473 0 : if( FD_UNLIKELY( (ulong)n >= remaining_in ) ) FD_LOG_ERR(( "snprintf overflow" )); \
474 0 : remaining_in -= (ulong)n; \
475 0 : cur_in += n; \
476 0 : } while( 0 )
477 :
478 0 : #define PRINTOUT( ... ) do { \
479 0 : int n = snprintf( cur_out, remaining_out, __VA_ARGS__ ); \
480 0 : if( FD_UNLIKELY( n < 0 ) ) FD_LOG_ERR(( "snprintf failed" )); \
481 0 : if( FD_UNLIKELY( (ulong)n >= remaining_out ) ) FD_LOG_ERR(( "snprintf overflow" )); \
482 0 : remaining_out -= (ulong)n; \
483 0 : cur_out += n; \
484 0 : } while( 0 )
485 :
486 0 : PRINT( "\nTILES\n" );
487 0 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
488 0 : fd_topo_tile_t * tile = &topo->tiles[ i ];
489 :
490 0 : char in[ 256 ] = {0};
491 0 : char * cur_in = in;
492 0 : ulong remaining_in = sizeof( in ) - 1;
493 :
494 0 : for( ulong j=0UL; j<tile->in_cnt; j++ ) {
495 0 : if( FD_LIKELY( j != 0 ) ) PRINTIN( ", " );
496 0 : if( FD_LIKELY( tile->in_link_reliable[ j ] ) ) PRINTIN( "%2lu", tile->in_link_id[ j ] );
497 0 : else PRINTIN( "%2ld", (long)-tile->in_link_id[ j ] );
498 0 : }
499 :
500 0 : char out[ 256 ] = {0};
501 0 : char * cur_out = out;
502 0 : ulong remaining_out = sizeof( out ) - 1;
503 :
504 0 : for( ulong j=0UL; j<tile->out_cnt; j++ ) {
505 0 : if( FD_LIKELY( j != 0 ) ) PRINTOUT( ", " );
506 0 : PRINTOUT( "%2lu", tile->out_link_id[ j ] );
507 0 : }
508 :
509 : /* Determine tile's NUMA node either based on CPU or wksp affinity */
510 0 : ulong tile_numa = 0UL;
511 0 : if( tile->cpu_idx!=ULONG_MAX ) {
512 0 : tile_numa = fd_shmem_numa_idx( tile->cpu_idx );
513 0 : } else {
514 0 : tile_numa = topo->workspaces[ topo->objs[ tile->tile_obj_id ].wksp_id ].numa_idx;
515 0 : }
516 :
517 0 : char size[ 24 ];
518 0 : fd_topo_mem_sz_string( fd_topo_mlock_max_tile1( topo, tile ), size );
519 0 : PRINT( " %2lu (%7s): %12s kind_id=%-2lu wksp_id=%-2lu cpu_idx=", i, size, tile->name, tile->kind_id, topo->objs[ tile->tile_obj_id ].wksp_id );
520 0 : if( tile->cpu_idx!=ULONG_MAX ) {
521 0 : PRINT( "%3lu", tile->cpu_idx );
522 0 : } else {
523 0 : PRINT( "any" );
524 0 : }
525 :
526 0 : PRINT( " numa_idx=%lu in=[%s] out=[%s] objs=[", tile_numa, in, out );
527 0 : for( ulong j=0UL; j<tile->uses_obj_cnt; j++ ) {
528 0 : if( FD_LIKELY( j!=0 ) ) PRINT( " " );
529 0 : int is_rw = tile->uses_obj_mode[ j ] == FD_SHMEM_JOIN_MODE_READ_WRITE;
530 0 : PRINT( "%lu:%s", tile->uses_obj_id[ j ], is_rw?"rw":"ro" );
531 0 : }
532 0 : PRINT( "]" );
533 :
534 : #if 0
535 : PRINT( " wksps=[" );
536 : for( ulong j=0UL; j<topo->wksp_cnt; j++ ) {
537 : int mode = tile_needs_wksp( topo, tile, j );
538 : if( FD_UNLIKELY( -1!=mode ) ) {
539 : if( FD_LIKELY( j!=0 ) ) PRINT( " " );
540 : PRINT( "%s:%s", topo->workspaces[ j ].name, mode==FD_SHMEM_JOIN_MODE_READ_WRITE?"rw":"ro" );
541 : }
542 : }
543 : PRINT( "]" );
544 : #endif
545 :
546 0 : if( FD_LIKELY( i != topo->tile_cnt-1 ) ) PRINT( "\n" );
547 0 : }
548 :
549 0 : if( FD_UNLIKELY( stdout ) ) FD_LOG_STDOUT(( "%s\n", message ));
550 0 : else FD_LOG_INFO(( "%s", message ));
551 0 : }
|