LCOV - code coverage report
Current view: top level - disco/topo - fd_topo.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 8 576 1.4 %
Date: 2026-07-22 05:23:51 Functions: 1 24 4.2 %

          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          24 :                    ulong             obj_id ) {
      16          24 :   fd_topo_obj_t const * obj = &topo->objs[ obj_id ];
      17          24 :   if( FD_UNLIKELY( obj_id==ULONG_MAX ) ) FD_LOG_CRIT(( "invalid obj_id ULONG_MAX" ));
      18          24 :   if( FD_UNLIKELY( obj_id>=FD_TOPO_MAX_OBJS ) ) FD_LOG_CRIT(( "invalid obj_id %lu", obj_id ));
      19          24 :   FD_TEST( obj->id == obj_id );
      20          24 :   FD_TEST( obj->offset );
      21          24 :   return (void *)((ulong)topo->workspaces[ obj->wksp_id ].wksp + obj->offset);
      22          24 : }
      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*150L ) ) ) 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->id_keyswitch_obj_id!=ULONG_MAX ) ) {
     224             :     /* Certain tiles using fd_keyload_load need normal pages to hold
     225             :        key material. */
     226           0 :     key_pages += 5UL;
     227           0 :   }
     228           0 :   if( FD_UNLIKELY( tile->av_keyswitch_obj_id!=ULONG_MAX ) ) {
     229             :     /* Certain tiles using fd_keyload_load need normal pages to hold
     230             :        key material. */
     231           0 :     key_pages += 5UL;
     232           0 :   }
     233             : 
     234           0 :   if( !strcmp( tile->name, "net" ) ) {
     235             :       /* net tile uses normal pages to hold xsk rings */
     236             : 
     237             :       /* xdp_desc struct is in linux UAPI so its size can be
     238             :          safely assumed */
     239           0 :       ulong xdp_desc_sz_bytes    = 16UL;
     240           0 :       ulong xsk_rings_sz_bytes   = 0UL;
     241           0 :       ulong xdp_address_sz_bytes = sizeof(ulong);
     242             : 
     243             :       /* rx ring */
     244           0 :       xsk_rings_sz_bytes += tile->xdp.xdp_rx_queue_size * xdp_desc_sz_bytes;
     245             :       /* tx ring */
     246           0 :       xsk_rings_sz_bytes += tile->xdp.xdp_tx_queue_size * xdp_desc_sz_bytes;
     247             : 
     248             :       /* completion ring */
     249           0 :       xsk_rings_sz_bytes += tile->xdp.xdp_tx_queue_size * xdp_address_sz_bytes;
     250             :       /* free ring */
     251           0 :       xsk_rings_sz_bytes += tile->xdp.free_ring_depth   * xdp_address_sz_bytes;
     252             : 
     253           0 :       key_pages += fd_ulong_align_up( xsk_rings_sz_bytes, FD_SHMEM_NORMAL_PAGE_SZ ) / FD_SHMEM_NORMAL_PAGE_SZ;
     254             : 
     255             :       /* All 4 rings must store a ring header. This is 320 bytes
     256             :          per ring as of linux v6.18.3, however could change in
     257             :          the future so allow up to a full 4KB page per ring to
     258             :          be safe. */
     259           0 :       key_pages += 4UL;
     260           0 :   }
     261             : 
     262           0 :   return key_pages;
     263           0 : }
     264             : 
     265             : FD_FN_PURE static ulong
     266             : fd_topo_mlock_max_tile1( fd_topo_t const *      topo,
     267           0 :                          fd_topo_tile_t const * tile ) {
     268           0 :   ulong tile_mem = 0UL;
     269             : 
     270           0 :   for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
     271           0 :     if( FD_UNLIKELY( -1!=tile_needs_wksp( topo, tile, i ) ) )
     272           0 :       tile_mem += topo->workspaces[ i ].page_cnt * topo->workspaces[ i ].page_sz;
     273           0 :   }
     274             : 
     275           0 :   return tile_mem +
     276           0 :       fd_topo_tile_extra_huge_pages( tile ) * FD_SHMEM_HUGE_PAGE_SZ +
     277           0 :       fd_topo_tile_extra_normal_pages( tile ) * FD_SHMEM_NORMAL_PAGE_SZ;
     278           0 : }
     279             : 
     280             : FD_FN_PURE ulong
     281           0 : fd_topo_mlock_max_tile( fd_topo_t const * topo ) {
     282           0 :   ulong highest_tile_mem = 0UL;
     283           0 :   for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
     284           0 :     fd_topo_tile_t const * tile = &topo->tiles[ i ];
     285           0 :     highest_tile_mem = fd_ulong_max( highest_tile_mem, fd_topo_mlock_max_tile1( topo, tile ) );
     286           0 :   }
     287             : 
     288           0 :   return highest_tile_mem;
     289           0 : }
     290             : 
     291             : FD_FN_PURE ulong
     292             : fd_topo_gigantic_page_cnt( fd_topo_t const * topo,
     293           0 :                            ulong             numa_idx ) {
     294           0 :   ulong result = 0UL;
     295           0 :   for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
     296           0 :     fd_topo_wksp_t const * wksp = &topo->workspaces[ i ];
     297           0 :     if( FD_LIKELY( wksp->numa_idx!=numa_idx ) ) continue;
     298             : 
     299           0 :     if( FD_LIKELY( wksp->page_sz==FD_SHMEM_GIGANTIC_PAGE_SZ ) ) {
     300           0 :       result += wksp->page_cnt;
     301           0 :     }
     302           0 :   }
     303           0 :   return result;
     304           0 : }
     305             : 
     306             : FD_FN_PURE ulong
     307             : fd_topo_huge_page_cnt( fd_topo_t const * topo,
     308             :                        ulong             numa_idx,
     309           0 :                        int               include_anonymous ) {
     310           0 :   ulong result = 0UL;
     311           0 :   for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
     312           0 :     fd_topo_wksp_t const * wksp = &topo->workspaces[ i ];
     313           0 :     if( FD_LIKELY( wksp->numa_idx!=numa_idx ) ) continue;
     314             : 
     315           0 :     if( FD_LIKELY( wksp->page_sz==FD_SHMEM_HUGE_PAGE_SZ ) ) {
     316           0 :       result += wksp->page_cnt;
     317           0 :     }
     318           0 :   }
     319             : 
     320             :   /* The stack huge pages are also placed in the hugetlbfs. */
     321           0 :   for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
     322           0 :     result += fd_topo_tile_extra_huge_pages( &topo->tiles[ i ] );
     323           0 :   }
     324             : 
     325             :   /* No anonymous huge pages in use yet. */
     326           0 :   (void)include_anonymous;
     327             : 
     328           0 :   return result;
     329           0 : }
     330             : 
     331             : FD_FN_PURE ulong
     332           0 : fd_topo_normal_page_cnt( fd_topo_t const * topo ) {
     333           0 :   ulong result = 0UL;
     334           0 :   for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
     335           0 :     result += fd_topo_tile_extra_normal_pages( &topo->tiles[ i ] );
     336           0 :   }
     337           0 :   return result;
     338           0 : }
     339             : 
     340             : FD_FN_PURE ulong
     341           0 : fd_topo_mlock( fd_topo_t const * topo ) {
     342           0 :   ulong result = 0UL;
     343           0 :   for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
     344           0 :     result += topo->workspaces[ i ].page_cnt * topo->workspaces[ i ].page_sz;
     345           0 :   }
     346           0 :   return result;
     347           0 : }
     348             : 
     349             : static void
     350           0 : fd_topo_mem_sz_string( ulong sz, char out[static 24] ) {
     351           0 :   if( FD_LIKELY( sz >= FD_SHMEM_GIGANTIC_PAGE_SZ ) ) {
     352           0 :     FD_TEST( fd_cstr_printf_check( out, 24, NULL, "%.1f GiB", (double)sz / (double)(1UL << 30) ) );
     353           0 :   } else if( FD_LIKELY( sz >= 1048576 ) ) {
     354           0 :     FD_TEST( fd_cstr_printf_check( out, 24, NULL, "%.1f MiB", (double)sz / (double)(1UL << 20) ) );
     355           0 :   } else if( FD_LIKELY( sz >= 1024 ) ) {
     356           0 :     FD_TEST( fd_cstr_printf_check( out, 24, NULL, "%.1f KiB", (double)sz / (double)(1UL << 10) ) );
     357           0 :   } else {
     358           0 :     FD_TEST( fd_cstr_printf_check( out, 24, NULL, "%lu B", sz ) );
     359           0 :   }
     360           0 : }
     361             : 
     362             : /* Style sizes by magnitude so the big numbers pop */
     363             : 
     364             : static char const *
     365             : fd_topo_mem_sz_style( ulong        sz,
     366             :                       char const * bold,
     367           0 :                       char const * dim ) {
     368           0 :   if( sz>=(1UL<<30) ) return bold;
     369           0 :   if( sz< (1UL<<20) ) return dim;
     370           0 :   return "";
     371           0 : }
     372             : 
     373             : void
     374             : fd_topo_print_log( int         stdout,
     375           0 :                    fd_topo_t * topo ) {
     376           0 :   char message[ 32UL*4096UL ] = {0}; /* Same as FD_LOG_BUF_SZ */
     377             : 
     378           0 :   char * cur = message;
     379           0 :   ulong remaining = sizeof(message) - 1; /* Leave one character at the end to ensure NUL terminated */
     380             : 
     381           0 : #define PRINT( ... ) do {                                                             \
     382           0 :     int n = snprintf( cur, remaining, __VA_ARGS__ );                                  \
     383           0 :     if( FD_UNLIKELY( n < 0 ) ) FD_LOG_ERR(( "snprintf failed" ));                     \
     384           0 :     if( FD_UNLIKELY( (ulong)n >= remaining ) ) {                                      \
     385             :       /* stdout mode flushes and retries, log mode keeps one message */               \
     386           0 :       if( FD_UNLIKELY( !stdout ) ) FD_LOG_ERR(( "snprintf overflow" ));               \
     387           0 :       *cur = '\0';                                                                    \
     388           0 :       FD_LOG_STDOUT(( "%s", message ));                                               \
     389           0 :       cur = message; remaining = sizeof(message) - 1;                                 \
     390           0 :       n = snprintf( cur, remaining, __VA_ARGS__ );                                    \
     391           0 :       if( FD_UNLIKELY( n < 0 ) ) FD_LOG_ERR(( "snprintf failed" ));                   \
     392           0 :       if( FD_UNLIKELY( (ulong)n >= remaining ) ) FD_LOG_ERR(( "snprintf overflow" )); \
     393           0 :     }                                                                                 \
     394           0 :     remaining -= (ulong)n;                                                            \
     395           0 :     cur += n;                                                                         \
     396           0 :   } while( 0 )
     397             : 
     398           0 :   int color = stdout && fd_log_colorize() && isatty( STDOUT_FILENO );
     399           0 :   char const * c_bold   = color ? "\033[1m" : "";
     400           0 :   char const * c_dim    = color ? "\033[2m" : "";
     401           0 :   char const * c_normal = color ? "\033[0m" : "";
     402             : 
     403           0 :   char const * sep = "";
     404             : 
     405           0 : #define SECTION( ... ) do {                                                            \
     406           0 :     char _title[ 64 ];                                                                \
     407           0 :     FD_TEST( fd_cstr_printf_check( _title, sizeof(_title), NULL, __VA_ARGS__ ) );     \
     408           0 :     PRINT( "%s%s──%s %s%s%s %s", sep, c_dim, c_normal, c_bold, _title, c_normal, c_dim ); \
     409           0 :     for( ulong _i=strlen( _title ); _i<76UL; _i++ ) PRINT( "─" );                     \
     410           0 :     PRINT( "%s\n", c_normal );                                                        \
     411           0 :     sep = "\n";                                                                       \
     412           0 :   } while( 0 )
     413             : 
     414           0 :   SECTION( "Summary" );
     415             : 
     416             :   /* The logic to compute number of stack pages is taken from
     417             :      fd_tile_thread.cxx, in function fd_topo_tile_stack_join, and this
     418             :      should match that. */
     419           0 :   ulong stack_pages = topo->tile_cnt * FD_SHMEM_HUGE_PAGE_SZ * ((FD_TILE_PRIVATE_STACK_SZ/FD_SHMEM_HUGE_PAGE_SZ)+2UL);
     420             : 
     421           0 :   ulong normal_page_bytes = fd_topo_normal_page_cnt( topo ) * FD_SHMEM_NORMAL_PAGE_SZ;
     422           0 :   ulong total_bytes = fd_topo_mlock( topo ) + stack_pages + normal_page_bytes;
     423             : 
     424           0 :   PRINT("  %s%-23s%s  %lu\n", c_dim, "Total Tiles", c_normal, topo->tile_cnt );
     425           0 :   PRINT("  %s%-23s%s  %s%lu GiB + %lu MiB + %lu KiB%s  %s(%lu bytes)%s\n",
     426           0 :     c_dim, "Total Memory Locked", c_normal,
     427           0 :     c_bold,
     428           0 :     total_bytes / (1 << 30),
     429           0 :     (total_bytes % (1 << 30)) / (1 << 20),
     430           0 :     (total_bytes % (1 << 20)) / (1 << 10),
     431           0 :     c_normal,
     432           0 :     c_dim, total_bytes, c_normal );
     433             : 
     434           0 :   ulong required_gigantic_pages = 0UL;
     435           0 :   ulong required_huge_pages = 0UL;
     436             : 
     437           0 :   ulong numa_node_cnt = fd_shmem_numa_cnt();
     438           0 :   for( ulong i=0UL; i<numa_node_cnt; i++ ) {
     439           0 :     required_gigantic_pages += fd_topo_gigantic_page_cnt( topo, i );
     440           0 :     required_huge_pages += fd_topo_huge_page_cnt( topo, i, 0 );
     441           0 :   }
     442           0 :   PRINT("  %s%-23s%s  %lu\n", c_dim, "Required Gigantic Pages", c_normal, required_gigantic_pages );
     443           0 :   PRINT("  %s%-23s%s  %lu\n", c_dim, "Required Huge Pages", c_normal, required_huge_pages );
     444           0 :   PRINT("  %s%-23s%s  %lu\n", c_dim, "Required Normal Pages", c_normal, fd_topo_normal_page_cnt( topo ) );
     445           0 :   if( FD_UNLIKELY( numa_node_cnt>1UL ) ) {
     446           0 :     for( ulong i=0UL; i<numa_node_cnt; i++ ) {
     447           0 :       char label[ 40 ];
     448           0 :       FD_TEST( fd_cstr_printf_check( label, sizeof(label), NULL, "NUMA node %lu", i ) );
     449           0 :       PRINT("  %s%-23s%s  %lu gigantic, %lu huge\n", c_dim, label, c_normal, fd_topo_gigantic_page_cnt( topo, i ), fd_topo_huge_page_cnt( topo, i, 0 ) );
     450           0 :     }
     451           0 :   }
     452             : 
     453           0 :   if( FD_UNLIKELY( topo->agave_affinity_cnt>0UL ) ) {
     454           0 :     char agave_affinity[4096];
     455           0 :     ulong offset = 0UL;
     456           0 :     for ( ulong i = 0UL; i < topo->agave_affinity_cnt; i++ ) {
     457           0 :       ulong sz;
     458           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 ] ) );
     459           0 :       else                       FD_TEST( fd_cstr_printf_check( agave_affinity+offset, 4096-offset, &sz, "%lu", topo->agave_affinity_cpu_idx[ i ] ) );
     460           0 :       offset += sz;
     461           0 :     }
     462           0 :     PRINT( "  %s%-23s%s  %s\n", c_dim, "Agave Affinity", c_normal, agave_affinity );
     463           0 :   }
     464             : 
     465           0 :   SECTION( "Workspaces (%lu)", topo->wksp_cnt );
     466           0 :   PRINT( "  %s%3s  %10s  %-13s  %5s  %-8s  %4s  %12s  %12s%s\n", c_dim, "ID", "SIZE", "NAME", "PAGES", "PAGE SZ", "NUMA", "FOOTPRINT", "LOOSE", c_normal );
     467           0 :   for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
     468           0 :     fd_topo_wksp_t * wksp = &topo->workspaces[ i ];
     469             : 
     470           0 :     ulong sz = wksp->page_sz * wksp->page_cnt;
     471           0 :     char size[ 24 ];
     472           0 :     fd_topo_mem_sz_string( sz, size );
     473           0 :     PRINT( "  %3lu  %s%10s%s  %-13s  %5lu  %-8s  %4lu  %12lu  %s%12lu%s\n",
     474           0 :            i, fd_topo_mem_sz_style( sz, c_bold, c_dim ), size, c_normal,
     475           0 :            wksp->name, wksp->page_cnt, fd_shmem_page_sz_to_cstr( wksp->page_sz ), wksp->numa_idx,
     476           0 :            wksp->known_footprint, c_dim, wksp->total_footprint - wksp->known_footprint, c_normal );
     477           0 :   }
     478             : 
     479           0 :   SECTION( "Objects (%lu)", topo->obj_cnt );
     480           0 :   PRINT( "  %s%4s  %10s  %-13s  %-13s  %4s  %12s  %s%s\n", c_dim, "ID", "SIZE", "WORKSPACE", "OBJECT", "WKSP", "OFFSET", "PROPERTIES", c_normal );
     481           0 :   for( ulong i=0UL; i<topo->obj_cnt; i++ ) {
     482           0 :     fd_topo_obj_t * obj = &topo->objs[ i ];
     483             : 
     484           0 :     char size[ 24 ];
     485           0 :     fd_topo_mem_sz_string( obj->footprint, size );
     486           0 :     PRINT( "  %4lu  %s%10s%s  %-13s  %-13s  %4lu  %12lu ",
     487           0 :            i, fd_topo_mem_sz_style( obj->footprint, c_bold, c_dim ), size, c_normal,
     488           0 :            topo->workspaces[ obj->wksp_id ].name, obj->name,
     489           0 :            obj->wksp_id, obj->offset );
     490           0 :     for( fd_pod_iter_t iter=fd_pod_iter_init( fd_pod_queryf_subpod( topo->props, "obj.%lu", obj->id ) );
     491           0 :          !fd_pod_iter_done( iter );
     492           0 :          iter=fd_pod_iter_next( iter ) ) {
     493           0 :       fd_pod_info_t info = fd_pod_iter_info( iter );
     494           0 :       if( !strcmp( info.key, "seed" ) ) continue; /* key is a cstr (key_sz includes NUL) */
     495           0 :       PRINT( " %s%.*s=%s", c_dim, (int)info.key_sz, info.key, c_normal );
     496           0 :       switch( info.val_type ) {
     497           0 :       case FD_POD_VAL_TYPE_CSTR:
     498           0 :         PRINT( "%.*s", (int)info.val_sz, (char const *)info.val );
     499           0 :         break;
     500           0 :       case FD_POD_VAL_TYPE_ULONG: {
     501           0 :         ulong val; fd_ulong_svw_dec( info.val, &val );
     502           0 :         PRINT( "%lu", val );
     503           0 :         break;
     504           0 :       }
     505           0 :       case FD_POD_VAL_TYPE_INT: {
     506           0 :         ulong u; fd_ulong_svw_dec( info.val, &u );
     507           0 :         PRINT( "%i", (int)fd_long_zz_dec( u ) );
     508           0 :         break;
     509           0 :       }
     510           0 :       }
     511           0 :     }
     512           0 :     PRINT( "\n" );
     513           0 :   }
     514             : 
     515           0 :   SECTION( "Links (%lu)", topo->link_cnt );
     516           0 :   PRINT( "  %s%3s  %10s  %-13s  %4s  %4s  %8s  %9s  %5s%s\n", c_dim, "ID", "SIZE", "NAME", "KIND", "WKSP", "DEPTH", "MTU", "BURST", c_normal );
     517           0 :   for( ulong i=0UL; i<topo->link_cnt; i++ ) {
     518           0 :     fd_topo_link_t * link = &topo->links[ i ];
     519             : 
     520           0 :     ulong sz = fd_dcache_req_data_sz( link->mtu, link->depth, link->burst, 1 );
     521           0 :     char size[ 24 ];
     522           0 :     fd_topo_mem_sz_string( sz, size );
     523           0 :     PRINT( "  %3lu  %s%10s%s  %-13s  %4lu  %4lu  %8lu  %9lu  %5lu\n",
     524           0 :            i, fd_topo_mem_sz_style( sz, c_bold, c_dim ), size, c_normal,
     525           0 :            link->name, link->kind_id, topo->objs[ link->mcache_obj_id ].wksp_id, link->depth, link->mtu, link->burst );
     526           0 :   }
     527             : 
     528           0 : #define PRINTIN( ... ) do {                                                            \
     529           0 :     int n = snprintf( cur_in, remaining_in, __VA_ARGS__ );                             \
     530           0 :     if( FD_UNLIKELY( n < 0 ) ) FD_LOG_ERR(( "snprintf failed" ));                      \
     531           0 :     if( FD_UNLIKELY( (ulong)n >= remaining_in ) ) FD_LOG_ERR(( "snprintf overflow" )); \
     532           0 :     remaining_in -= (ulong)n;                                                          \
     533           0 :     cur_in += n;                                                                       \
     534           0 :   } while( 0 )
     535             : 
     536           0 : #define PRINTOUT( ... ) do {                                                            \
     537           0 :     int n = snprintf( cur_out, remaining_out, __VA_ARGS__ );                            \
     538           0 :     if( FD_UNLIKELY( n < 0 ) ) FD_LOG_ERR(( "snprintf failed" ));                       \
     539           0 :     if( FD_UNLIKELY( (ulong)n >= remaining_out ) ) FD_LOG_ERR(( "snprintf overflow" )); \
     540           0 :     remaining_out -= (ulong)n;                                                          \
     541           0 :     cur_out += n;                                                                       \
     542           0 :   } while( 0 )
     543             : 
     544           0 :   SECTION( "Tiles (%lu)", topo->tile_cnt );
     545           0 :   PRINT( "  %s%3s  %10s  %-13s  %4s  %4s  %4s  %4s  %s%s\n", c_dim, "ID", "MLOCK", "NAME", "KIND", "WKSP", "CPU", "NUMA", "LINKS / OBJECTS", c_normal );
     546           0 :   for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
     547           0 :     fd_topo_tile_t * tile = &topo->tiles[ i ];
     548             : 
     549           0 :     char in[ 256 ] = {0};
     550           0 :     char * cur_in = in;
     551           0 :     ulong remaining_in = sizeof( in ) - 1;
     552             : 
     553           0 :     for( ulong j=0UL; j<tile->in_cnt; j++ ) {
     554           0 :       if( FD_LIKELY( j != 0 ) ) PRINTIN( ", " );
     555           0 :       if( FD_LIKELY( tile->in_link_reliable[ j ] ) ) PRINTIN( "%2lu", tile->in_link_id[ j ] );
     556           0 :       else PRINTIN( "%2ld", (long)-tile->in_link_id[ j ] );
     557           0 :     }
     558             : 
     559           0 :     char out[ 256 ] = {0};
     560           0 :     char * cur_out = out;
     561           0 :     ulong remaining_out = sizeof( out ) - 1;
     562             : 
     563           0 :     for( ulong j=0UL; j<tile->out_cnt; j++ ) {
     564           0 :       if( FD_LIKELY( j != 0 ) ) PRINTOUT( ", " );
     565           0 :       PRINTOUT( "%2lu", tile->out_link_id[ j ] );
     566           0 :     }
     567             : 
     568             :     /* Determine tile's NUMA node either based on CPU or wksp affinity */
     569           0 :     ulong tile_numa = 0UL;
     570           0 :     if( tile->cpu_idx!=ULONG_MAX ) {
     571           0 :       tile_numa = fd_shmem_numa_idx( tile->cpu_idx );
     572           0 :     } else {
     573           0 :       tile_numa = topo->workspaces[ topo->objs[ tile->tile_obj_id ].wksp_id ].numa_idx;
     574           0 :     }
     575             : 
     576           0 :     ulong mlock = fd_topo_mlock_max_tile1( topo, tile );
     577           0 :     char size[ 24 ];
     578           0 :     fd_topo_mem_sz_string( mlock, size );
     579           0 :     PRINT( "  %3lu  %s%10s%s  %-13s  %4lu  %4lu  ",
     580           0 :            i, fd_topo_mem_sz_style( mlock, c_bold, c_dim ), size, c_normal,
     581           0 :            tile->name, tile->kind_id, topo->objs[ tile->tile_obj_id ].wksp_id );
     582           0 :     if( tile->cpu_idx!=ULONG_MAX ) {
     583           0 :       PRINT( "%4lu", tile->cpu_idx );
     584           0 :     } else {
     585           0 :       PRINT( "%s%4s%s", c_dim, "any", c_normal );
     586           0 :     }
     587             : 
     588           0 :     PRINT( "  %4lu  %sin=%s[%s]  %sout=%s[%s]  %sobjs=[", tile_numa, c_dim, c_normal, in, c_dim, c_normal, out, c_dim );
     589           0 :     for( ulong j=0UL; j<tile->uses_obj_cnt; j++ ) {
     590           0 :       if( FD_LIKELY( j!=0 ) ) PRINT( " " );
     591           0 :       int is_rw = tile->uses_obj_mode[ j ] == FD_SHMEM_JOIN_MODE_READ_WRITE;
     592           0 :       PRINT( "%lu:%s", tile->uses_obj_id[ j ], is_rw?"rw":"ro" );
     593           0 :     }
     594           0 :     PRINT( "]%s", c_normal );
     595             : 
     596             : #if 0
     597             :     PRINT( "  wksps=[" );
     598             :     for( ulong j=0UL; j<topo->wksp_cnt; j++ ) {
     599             :       int mode = tile_needs_wksp( topo, tile, j );
     600             :       if( FD_UNLIKELY( -1!=mode ) ) {
     601             :         if( FD_LIKELY( j!=0 ) ) PRINT( " " );
     602             :         PRINT( "%s:%s", topo->workspaces[ j ].name, mode==FD_SHMEM_JOIN_MODE_READ_WRITE?"rw":"ro" );
     603             :       }
     604             :     }
     605             :     PRINT( "]" );
     606             : #endif
     607             : 
     608           0 :     if( FD_LIKELY( i != topo->tile_cnt-1 ) ) PRINT( "\n" );
     609           0 :   }
     610             : 
     611           0 :   if( FD_UNLIKELY( stdout ) ) FD_LOG_STDOUT(( "%s\n", message ));
     612           0 :   else                        FD_LOG_INFO(( "%s", message ));
     613             : 
     614           0 : #undef PRINT
     615           0 : #undef PRINTIN
     616           0 : #undef PRINTOUT
     617           0 : #undef SECTION
     618           0 : }
     619             : 
     620             : /* PRINT_JSON_CSTR streams src (sz bytes, embedded NULs stop early)
     621             :    as a JSON string literal, escaping quotes, backslashes and control
     622             :    characters.  No fixed intermediate buffer: expansion cannot
     623             :    truncate regardless of src length or content. */
     624             : 
     625           0 : #define PRINT_JSON_CSTR( src, sz ) do {                                               \
     626           0 :     char const * _s  = (src);                                                         \
     627           0 :     ulong        _sz = (sz);                                                          \
     628           0 :     PRINT( "\"" );                                                                    \
     629           0 :     for( ulong _i=0UL; _i<_sz && _s[ _i ]; _i++ ) {                                   \
     630           0 :       uchar _c = (uchar)_s[ _i ];                                                     \
     631           0 :       if(      FD_UNLIKELY( _c=='"' || _c=='\\' ) ) PRINT( "\\%c", (char)_c );        \
     632           0 :       else if( FD_UNLIKELY( _c<0x20 ) )             PRINT( "\\u%04x", (uint)_c );     \
     633           0 :       else                                          PRINT( "%c", (char)_c );          \
     634           0 :     }                                                                                 \
     635           0 :     PRINT( "\"" );                                                                    \
     636           0 :   } while( 0 )
     637             : 
     638             : void
     639           0 : fd_topo_print_json( fd_topo_t * topo ) {
     640           0 :   char message[ 32UL*4096UL ] = {0};
     641             : 
     642           0 :   char * cur = message;
     643           0 :   ulong remaining = sizeof(message) - 1;
     644             : 
     645           0 : #define PRINT( ... ) do {                                                             \
     646           0 :     int n = snprintf( cur, remaining, __VA_ARGS__ );                                  \
     647           0 :     if( FD_UNLIKELY( n < 0 ) ) FD_LOG_ERR(( "snprintf failed" ));                     \
     648           0 :     if( FD_UNLIKELY( (ulong)n >= remaining ) ) {                                      \
     649           0 :       *cur = '\0';                                                                    \
     650           0 :       FD_LOG_STDOUT(( "%s", message ));                                               \
     651           0 :       cur = message; remaining = sizeof(message) - 1;                                 \
     652           0 :       n = snprintf( cur, remaining, __VA_ARGS__ );                                    \
     653           0 :       if( FD_UNLIKELY( n < 0 ) ) FD_LOG_ERR(( "snprintf failed" ));                   \
     654           0 :       if( FD_UNLIKELY( (ulong)n >= remaining ) ) FD_LOG_ERR(( "snprintf overflow" )); \
     655           0 :     }                                                                                 \
     656           0 :     remaining -= (ulong)n;                                                            \
     657           0 :     cur += n;                                                                         \
     658           0 :   } while( 0 )
     659             : 
     660           0 :   ulong stack_pages = topo->tile_cnt * FD_SHMEM_HUGE_PAGE_SZ * ((FD_TILE_PRIVATE_STACK_SZ/FD_SHMEM_HUGE_PAGE_SZ)+2UL);
     661           0 :   ulong normal_page_bytes = fd_topo_normal_page_cnt( topo ) * FD_SHMEM_NORMAL_PAGE_SZ;
     662           0 :   ulong total_bytes = fd_topo_mlock( topo ) + stack_pages + normal_page_bytes;
     663             : 
     664           0 :   ulong required_gigantic_pages = 0UL;
     665           0 :   ulong required_huge_pages = 0UL;
     666           0 :   ulong numa_node_cnt = fd_shmem_numa_cnt();
     667           0 :   for( ulong i=0UL; i<numa_node_cnt; i++ ) {
     668           0 :     required_gigantic_pages += fd_topo_gigantic_page_cnt( topo, i );
     669           0 :     required_huge_pages += fd_topo_huge_page_cnt( topo, i, 0 );
     670           0 :   }
     671             : 
     672           0 :   PRINT( "{\n  \"summary\": {\n" );
     673           0 :   PRINT( "    \"tile_cnt\": %lu,\n", topo->tile_cnt );
     674           0 :   PRINT( "    \"total_memory_locked_bytes\": %lu,\n", total_bytes );
     675           0 :   PRINT( "    \"required_gigantic_pages\": %lu,\n", required_gigantic_pages );
     676           0 :   PRINT( "    \"required_huge_pages\": %lu,\n", required_huge_pages );
     677           0 :   PRINT( "    \"required_normal_pages\": %lu,\n", fd_topo_normal_page_cnt( topo ) );
     678           0 :   PRINT( "    \"numa_nodes\": [" );
     679           0 :   for( ulong i=0UL; i<numa_node_cnt; i++ ) {
     680           0 :     PRINT( "%s\n      { \"node\": %lu, \"gigantic_pages\": %lu, \"huge_pages\": %lu }", i ? "," : "", i, fd_topo_gigantic_page_cnt( topo, i ), fd_topo_huge_page_cnt( topo, i, 0 ) );
     681           0 :   }
     682           0 :   PRINT( "\n    ],\n" );
     683           0 :   PRINT( "    \"agave_affinity\": [" );
     684           0 :   for( ulong i=0UL; i<topo->agave_affinity_cnt; i++ ) PRINT( "%s%lu", i ? ", " : "", topo->agave_affinity_cpu_idx[ i ] );
     685           0 :   PRINT( "]\n  },\n" );
     686             : 
     687           0 :   PRINT( "  \"workspaces\": [\n" );
     688           0 :   for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
     689           0 :     fd_topo_wksp_t * wksp = &topo->workspaces[ i ];
     690           0 :     PRINT( "    { \"id\": %lu, \"name\": ", i );
     691           0 :     PRINT_JSON_CSTR( wksp->name, sizeof(wksp->name) );
     692           0 :     PRINT( ", \"page_cnt\": %lu, \"page_sz\": \"%s\", \"numa_idx\": %lu, \"total_bytes\": %lu, \"footprint\": %lu, \"loose\": %lu }%s\n",
     693           0 :            wksp->page_cnt, fd_shmem_page_sz_to_cstr( wksp->page_sz ), wksp->numa_idx,
     694           0 :            wksp->page_cnt * wksp->page_sz, wksp->known_footprint, wksp->total_footprint - wksp->known_footprint,
     695           0 :            i==topo->wksp_cnt-1UL ? "" : "," );
     696           0 :   }
     697           0 :   PRINT( "  ],\n" );
     698             : 
     699           0 :   PRINT( "  \"objects\": [\n" );
     700           0 :   for( ulong i=0UL; i<topo->obj_cnt; i++ ) {
     701           0 :     fd_topo_obj_t * obj = &topo->objs[ i ];
     702           0 :     PRINT( "    { \"id\": %lu, \"name\": ", i );
     703           0 :     PRINT_JSON_CSTR( obj->name, sizeof(obj->name) );
     704           0 :     PRINT( ", \"wksp\": " );
     705           0 :     PRINT_JSON_CSTR( topo->workspaces[ obj->wksp_id ].name, sizeof(topo->workspaces[ obj->wksp_id ].name) );
     706           0 :     PRINT( ", \"wksp_id\": %lu, \"footprint\": %lu, \"offset\": %lu, \"props\": {",
     707           0 :            obj->wksp_id, obj->footprint, obj->offset );
     708           0 :     int first = 1;
     709           0 :     for( fd_pod_iter_t iter=fd_pod_iter_init( fd_pod_queryf_subpod( topo->props, "obj.%lu", obj->id ) );
     710           0 :          !fd_pod_iter_done( iter );
     711           0 :          iter=fd_pod_iter_next( iter ) ) {
     712           0 :       fd_pod_info_t info = fd_pod_iter_info( iter );
     713           0 :       if( !strcmp( info.key, "seed" ) ) continue; /* key is a cstr (key_sz includes NUL) */
     714           0 :       switch( info.val_type ) {
     715           0 :       case FD_POD_VAL_TYPE_CSTR: {
     716           0 :         PRINT( "%s ", first ? "" : "," );
     717           0 :         PRINT_JSON_CSTR( info.key, info.key_sz );
     718           0 :         PRINT( ": " );
     719           0 :         PRINT_JSON_CSTR( (char const *)info.val, info.val_sz );
     720           0 :         first = 0;
     721           0 :         break;
     722           0 :       }
     723           0 :       case FD_POD_VAL_TYPE_ULONG: {
     724           0 :         ulong val; fd_ulong_svw_dec( info.val, &val );
     725           0 :         PRINT( "%s ", first ? "" : "," );
     726           0 :         PRINT_JSON_CSTR( info.key, info.key_sz );
     727           0 :         PRINT( ": %lu", val );
     728           0 :         first = 0;
     729           0 :         break;
     730           0 :       }
     731           0 :       case FD_POD_VAL_TYPE_INT: {
     732           0 :         ulong u; fd_ulong_svw_dec( info.val, &u );
     733           0 :         PRINT( "%s ", first ? "" : "," );
     734           0 :         PRINT_JSON_CSTR( info.key, info.key_sz );
     735           0 :         PRINT( ": %i", (int)fd_long_zz_dec( u ) );
     736           0 :         first = 0;
     737           0 :         break;
     738           0 :       }
     739           0 :       }
     740           0 :     }
     741           0 :     PRINT( "%s} }%s\n", first ? "" : " ", i==topo->obj_cnt-1UL ? "" : "," );
     742           0 :   }
     743           0 :   PRINT( "  ],\n" );
     744             : 
     745           0 :   PRINT( "  \"links\": [\n" );
     746           0 :   for( ulong i=0UL; i<topo->link_cnt; i++ ) {
     747           0 :     fd_topo_link_t * link = &topo->links[ i ];
     748           0 :     PRINT( "    { \"id\": %lu, \"name\": ", i );
     749           0 :     PRINT_JSON_CSTR( link->name, sizeof(link->name) );
     750           0 :     PRINT( ", \"kind_id\": %lu, \"wksp_id\": %lu, \"depth\": %lu, \"mtu\": %lu, \"burst\": %lu, \"dcache_bytes\": %lu }%s\n",
     751           0 :            link->kind_id, topo->objs[ link->mcache_obj_id ].wksp_id, link->depth, link->mtu, link->burst,
     752           0 :            fd_dcache_req_data_sz( link->mtu, link->depth, link->burst, 1 ),
     753           0 :            i==topo->link_cnt-1UL ? "" : "," );
     754           0 :   }
     755           0 :   PRINT( "  ],\n" );
     756             : 
     757           0 :   PRINT( "  \"tiles\": [\n" );
     758           0 :   for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
     759           0 :     fd_topo_tile_t * tile = &topo->tiles[ i ];
     760             : 
     761           0 :     ulong tile_numa = 0UL;
     762           0 :     if( tile->cpu_idx!=ULONG_MAX ) tile_numa = fd_shmem_numa_idx( tile->cpu_idx );
     763           0 :     else                           tile_numa = topo->workspaces[ topo->objs[ tile->tile_obj_id ].wksp_id ].numa_idx;
     764             : 
     765           0 :     PRINT( "    { \"id\": %lu, \"name\": ", i );
     766           0 :     PRINT_JSON_CSTR( tile->name, sizeof(tile->name) );
     767           0 :     PRINT( ", \"kind_id\": %lu, \"wksp_id\": %lu, ",
     768           0 :            tile->kind_id, topo->objs[ tile->tile_obj_id ].wksp_id );
     769           0 :     if( tile->cpu_idx!=ULONG_MAX ) PRINT( "\"cpu_idx\": %lu, ", tile->cpu_idx );
     770           0 :     else                           PRINT( "\"cpu_idx\": null, " );
     771           0 :     PRINT( "\"numa_idx\": %lu, \"mlock_bytes\": %lu, \"in_links\": [", tile_numa, fd_topo_mlock_max_tile1( topo, tile ) );
     772           0 :     for( ulong j=0UL; j<tile->in_cnt; j++ ) {
     773           0 :       PRINT( "%s{ \"link_id\": %lu, \"reliable\": %s }", j ? ", " : "", tile->in_link_id[ j ], tile->in_link_reliable[ j ] ? "true" : "false" );
     774           0 :     }
     775           0 :     PRINT( "], \"out_links\": [" );
     776           0 :     for( ulong j=0UL; j<tile->out_cnt; j++ ) PRINT( "%s%lu", j ? ", " : "", tile->out_link_id[ j ] );
     777           0 :     PRINT( "], \"objects\": [" );
     778           0 :     for( ulong j=0UL; j<tile->uses_obj_cnt; j++ ) {
     779           0 :       int is_rw = tile->uses_obj_mode[ j ] == FD_SHMEM_JOIN_MODE_READ_WRITE;
     780           0 :       PRINT( "%s{ \"obj_id\": %lu, \"mode\": \"%s\" }", j ? ", " : "", tile->uses_obj_id[ j ], is_rw ? "rw" : "ro" );
     781           0 :     }
     782           0 :     PRINT( "] }%s\n", i==topo->tile_cnt-1UL ? "" : "," );
     783           0 :   }
     784           0 :   PRINT( "  ]\n}" );
     785             : 
     786           0 : #undef PRINT
     787             : 
     788           0 :   FD_LOG_STDOUT(( "%s\n", message ));
     789           0 : }

Generated by: LCOV version 1.14