LCOV - code coverage report
Current view: top level - app/shared/commands - mem.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 104 0.0 %
Date: 2026-06-29 05:51:35 Functions: 0 5 0.0 %

          Line data    Source code
       1             : #include "../fd_config.h"
       2             : #include "../fd_action.h"
       3             : 
       4             : #include <unistd.h>
       5             : 
       6             : struct mem_obj_entry {
       7             :   ulong footprint;
       8             :   char  wksp[ 13 ];
       9             :   char  obj[ 13 ];
      10             : };
      11             : typedef struct mem_obj_entry mem_obj_entry_t;
      12             : 
      13             : #define SORT_NAME        sort_obj_by_footprint
      14           0 : #define SORT_KEY_T       mem_obj_entry_t
      15           0 : #define SORT_BEFORE(a,b) ((a).footprint>(b).footprint)
      16             : #include "../../../util/tmpl/fd_sort.c"
      17             : 
      18             : extern action_t * ACTIONS[];
      19             : 
      20             : static void
      21           0 : fmt_size( char * buf, ulong sz ) {
      22           0 :   if( FD_LIKELY( sz >= (1UL<<30) ) )      FD_TEST( fd_cstr_printf_check( buf, 24, NULL, "%lu GiB", sz / (1UL<<30) ) );
      23           0 :   else if( FD_LIKELY( sz >= (1UL<<20) ) ) FD_TEST( fd_cstr_printf_check( buf, 24, NULL, "%lu MiB", sz / (1UL<<20) ) );
      24           0 :   else if( FD_LIKELY( sz >= (1UL<<10) ) ) FD_TEST( fd_cstr_printf_check( buf, 24, NULL, "%lu KiB", sz / (1UL<<10) ) );
      25           0 :   else                                    FD_TEST( fd_cstr_printf_check( buf, 24, NULL, "%lu B",   sz             ) );
      26           0 : }
      27             : 
      28             : static void
      29             : mem_cmd_args( int *    pargc,
      30             :               char *** pargv,
      31           0 :               args_t * args ) {
      32           0 :   char const * topo_name = fd_env_strip_cmdline_cstr( pargc, pargv, "--topo", NULL, "" );
      33           0 :   args->mem.sort = fd_env_strip_cmdline_contains( pargc, pargv, "--sort" );
      34             : 
      35           0 :   ulong topo_name_len = strlen( topo_name );
      36           0 :   if( FD_UNLIKELY( topo_name_len > sizeof(args->mem.topo)-1 ) ) FD_LOG_ERR(( "Unknown --topo %s", topo_name ));
      37           0 :   fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( args->mem.topo ), topo_name, topo_name_len ) );
      38           0 : }
      39             : 
      40             : static void
      41             : reconstruct_topo( config_t *   config,
      42           0 :                   char const * topo_name ) {
      43           0 :   if( !topo_name[0] ) return; /* keep default action topo */
      44             : 
      45           0 :   action_t const * selected = NULL;
      46           0 :   for( action_t ** a=ACTIONS; *a; a++ ) {
      47           0 :     action_t const * action = *a;
      48           0 :     if( 0==strcmp( action->name, topo_name ) ) {
      49           0 :       selected = action;
      50           0 :       break;
      51           0 :     }
      52           0 :   }
      53             : 
      54           0 :   if( !selected       ) FD_LOG_ERR(( "Unknown --topo %s", topo_name ));
      55           0 :   if( !selected->topo ) FD_LOG_ERR(( "Cannot recover topology for --topo %s", topo_name ));
      56             : 
      57           0 :   selected->topo( config );
      58           0 : }
      59             : 
      60             : void
      61             : mem_cmd_fn( args_t *   args,
      62           0 :             config_t * config ) {
      63           0 :   reconstruct_topo( config, args->mem.topo );
      64             : 
      65           0 :   if( FD_UNLIKELY( args->mem.sort ) ) {
      66           0 :     fd_topo_t * topo = &config->topo;
      67             : 
      68             :     /* Max entries: objects + per-wksp loose + per-wksp overhead + extra pages */
      69           0 :     mem_obj_entry_t entries[ FD_TOPO_MAX_OBJS + 2UL*FD_TOPO_MAX_WKSPS + 2UL ];
      70           0 :     ulong cnt = 0UL;
      71             : 
      72             :     /* Real topology objects */
      73           0 :     for( ulong i=0UL; i<topo->obj_cnt; i++ ) {
      74           0 :       fd_topo_obj_t * obj = &topo->objs[ i ];
      75           0 :       entries[ cnt ].footprint = obj->footprint;
      76           0 :       fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( entries[ cnt ].wksp ), topo->workspaces[ obj->wksp_id ].name, sizeof(entries[ cnt ].wksp)-1 ) );
      77           0 :       fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( entries[ cnt ].obj ), obj->name, sizeof(entries[ cnt ].obj)-1 ) );
      78           0 :       cnt++;
      79           0 :     }
      80             : 
      81             :     /* Per-workspace loose memory and page rounding overhead */
      82           0 :     for( ulong i=0UL; i<topo->wksp_cnt; i++ ) {
      83           0 :       fd_topo_wksp_t * wksp = &topo->workspaces[ i ];
      84           0 :       ulong loose = wksp->total_footprint - wksp->known_footprint;
      85           0 :       if( loose ) {
      86           0 :         entries[ cnt ].footprint = loose;
      87           0 :         fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( entries[ cnt ].wksp ), wksp->name, sizeof(entries[ cnt ].wksp)-1 ) );
      88           0 :         fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( entries[ cnt ].obj ), "loose", 5 ) );
      89           0 :         cnt++;
      90           0 :       }
      91           0 :       ulong pages_sz = wksp->page_cnt * wksp->page_sz;
      92           0 :       ulong overhead = pages_sz - wksp->total_footprint;
      93           0 :       if( overhead ) {
      94           0 :         entries[ cnt ].footprint = overhead;
      95           0 :         fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( entries[ cnt ].wksp ), wksp->name, sizeof(entries[ cnt ].wksp)-1 ) );
      96           0 :         fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( entries[ cnt ].obj ), "padding", 7 ) );
      97           0 :         cnt++;
      98           0 :       }
      99           0 :     }
     100             : 
     101             :     /* Tile stacks: each tile maps (FD_TILE_PRIVATE_STACK_SZ/FD_SHMEM_HUGE_PAGE_SZ)+2
     102             :        huge pages for its stack (see fd_topo_tile_extra_huge_pages). */
     103           0 :     ulong stack_huge_pages = topo->tile_cnt * ((FD_TILE_PRIVATE_STACK_SZ/FD_SHMEM_HUGE_PAGE_SZ)+2UL);
     104           0 :     if( stack_huge_pages ) {
     105           0 :       entries[ cnt ].footprint = stack_huge_pages * FD_SHMEM_HUGE_PAGE_SZ;
     106           0 :       fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( entries[ cnt ].wksp ), "", 0 ) );
     107           0 :       fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( entries[ cnt ].obj ), "tile_stacks", 11 ) );
     108           0 :       cnt++;
     109           0 :     }
     110             : 
     111             :     /* Extra normal pages (private keys, XSK rings, log locks, etc.) */
     112           0 :     ulong extra_normal = fd_topo_normal_page_cnt( topo );
     113           0 :     if( extra_normal ) {
     114           0 :       entries[ cnt ].footprint = extra_normal * FD_SHMEM_NORMAL_PAGE_SZ;
     115           0 :       fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( entries[ cnt ].wksp ), "", 0 ) );
     116           0 :       fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( entries[ cnt ].obj ), "normal_pages", 12 ) );
     117           0 :       cnt++;
     118           0 :     }
     119             : 
     120           0 :     sort_obj_by_footprint_inplace( entries, cnt );
     121             : 
     122           0 :     ulong total = 0UL;
     123           0 :     for( ulong i=0UL; i<cnt; i++ ) total += entries[ i ].footprint;
     124             : 
     125           0 :     FD_LOG_STDOUT(( "%7s  %6s  %15s  %10s  %7s  %15s  %12s  %12s\n", "SIZE", "PCT", "BYTES", "CUM SIZE", "CUM PCT", "CUM BYTES", "WORKSPACE", "OBJECT" ));
     126           0 :     FD_LOG_STDOUT(( "-------  ------  ---------------  ----------  -------  ---------------  ------------  ------------\n" ));
     127           0 :     ulong cum = 0UL;
     128           0 :     for( ulong i=0UL; i<cnt; i++ ) {
     129           0 :       ulong sz = entries[ i ].footprint;
     130           0 :       cum += sz;
     131           0 :       char sz_str[ 24 ], cum_str[ 24 ];
     132           0 :       fmt_size( sz_str,  sz  );
     133           0 :       fmt_size( cum_str, cum );
     134           0 :       double pct     = total ? 100.0 * (double)sz  / (double)total : 0.0;
     135           0 :       double cum_pct = total ? 100.0 * (double)cum / (double)total : 0.0;
     136           0 :       FD_LOG_STDOUT(( "%7s  %5.1f%%  %15lu  %10s  %6.1f%%  %15lu  %12s  %12s\n", sz_str, pct, sz, cum_str, cum_pct, cum, entries[ i ].wksp, entries[ i ].obj ));
     137           0 :     }
     138             : 
     139           0 :     char total_str[ 24 ];
     140           0 :     fmt_size( total_str, total );
     141           0 :     FD_LOG_STDOUT(( "-------  ------  ---------------  ----------  -------  ---------------  ------------  ------------\n" ));
     142           0 :     FD_LOG_STDOUT(( "%7s  %5.1f%%  %15lu  %10s  %6.1f%%  %15lu  %12s  %12s\n", total_str, 100.0, total, total_str, 100.0, total, "TOTAL", "" ));
     143           0 :     return;
     144           0 :   }
     145             : 
     146           0 :   fd_topo_print_log( 1, &config->topo );
     147           0 : }
     148             : 
     149             : static void
     150           0 : mem_args_help( fd_action_help_t * help ) {
     151           0 :   fd_action_help_arg( help, "--topo", "<command>", "Build the topology from another subcommand (e.g. `gossip`) instead of\n"
     152           0 :                                                    "the default validator topology.  <command> is the name of a subcommand\n"
     153           0 :                                                    "that builds its own topology" );
     154             :   fd_action_help_arg( help, "--sort", NULL,        "List objects largest first, with per object and cumulative memory\n"
     155           0 :                                                    "footprint, instead of the default per memory region layout" );
     156           0 : }
     157             : 
     158             : action_t fd_action_mem = {
     159             :   .name           = "mem",
     160             :   .args           = mem_cmd_args,
     161             :   .fn             = mem_cmd_fn,
     162             :   .require_config = 1,
     163             :   .perm           = NULL,
     164             :   .description    = "Print the validator's memory regions and tile layout",
     165             :   .detail         = "Prints the shared memory regions and tiles that the validator topology\n"
     166             :                     "allocates, including how much memory each object reserves.  A tile is a\n"
     167             :                     "single thread pinned to a CPU core that performs one part of the validator's\n"
     168             :                     "work.  This is computed from the configuration without attaching to a\n"
     169             :                     "running validator.",
     170             :   .usage          = "mem [OPTIONS]",
     171             :   .args_help      = mem_args_help,
     172             : };

Generated by: LCOV version 1.14