LCOV - code coverage report
Current view: top level - funk - fd_funk.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 235 335 70.1 %
Date: 2025-01-08 12:08:44 Functions: 10 12 83.3 %

          Line data    Source code
       1             : #include "fd_funk.h"
       2             : #include <stdio.h>
       3             : 
       4             : ulong
       5      816921 : fd_funk_align( void ) {
       6      816921 :   return alignof(fd_funk_t);
       7      816921 : }
       8             : 
       9             : ulong
      10      816921 : fd_funk_footprint( void ) {
      11      816921 :   return sizeof(fd_funk_t);
      12      816921 : }
      13             : 
      14             : /* TODO: Consider letter user just passing a join of alloc to use,
      15             :    inferring the backing wksp and cgroup_hint from that and then
      16             :    allocating exclusively from that? */
      17             : 
      18             : void *
      19             : fd_funk_new( void * shmem,
      20             :              ulong  wksp_tag,
      21             :              ulong  seed,
      22             :              ulong  txn_max,
      23      408501 :              ulong  rec_max ) {
      24      408501 :   fd_funk_t * funk = (fd_funk_t *)shmem;
      25             : 
      26      408501 :   if( FD_UNLIKELY( !funk ) ) {
      27           3 :     FD_LOG_WARNING(( "NULL funk" ));
      28           3 :     return NULL;
      29           3 :   }
      30             : 
      31      408498 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)funk, fd_funk_align() ) ) ) {
      32           3 :     FD_LOG_WARNING(( "misaligned funk" ));
      33           3 :     return NULL;
      34           3 :   }
      35             : 
      36      408495 :   if( FD_UNLIKELY( !wksp_tag ) ) {
      37           3 :     FD_LOG_WARNING(( "bad wksp_tag" ));
      38           3 :     return NULL;
      39           3 :   }
      40             : 
      41      408492 :   fd_wksp_t * wksp = fd_wksp_containing( funk );
      42      408492 :   if( FD_UNLIKELY( !wksp ) ) {
      43           3 :     FD_LOG_WARNING(( "shmem must be part of a workspace" ));
      44           3 :     return NULL;
      45           3 :   }
      46             : 
      47      408489 :   if( txn_max>FD_FUNK_TXN_IDX_NULL ) { /* See note in fd_funk.h about this limit */
      48           3 :     FD_LOG_WARNING(( "txn_max too large for index compression" ));
      49           3 :     return NULL;
      50           3 :   }
      51             : 
      52      408486 :   void * txn_shmem = fd_wksp_alloc_laddr( wksp, fd_funk_txn_map_align(), fd_funk_txn_map_footprint( txn_max ), wksp_tag );
      53      408486 :   if( FD_UNLIKELY( !txn_shmem ) ) {
      54           3 :     FD_LOG_WARNING(( "txn_max too large for workspace" ));
      55           3 :     return NULL;
      56           3 :   }
      57             : 
      58      408483 :   void * txn_shmap = fd_funk_txn_map_new( txn_shmem, txn_max, seed );
      59      408483 :   if( FD_UNLIKELY( !txn_shmap ) ) {
      60           0 :     FD_LOG_WARNING(( "fd_funk_txn_map_new failed" ));
      61           0 :     fd_wksp_free_laddr( txn_shmem );
      62           0 :     return NULL;
      63           0 :   }
      64             : 
      65      408483 :   fd_funk_txn_t * txn_map = fd_funk_txn_map_join( txn_shmap );
      66      408483 :   if( FD_UNLIKELY( !txn_map ) ) {
      67           0 :     FD_LOG_WARNING(( "fd_funk_txn_map_join failed" ));
      68           0 :     fd_wksp_free_laddr( fd_funk_txn_map_delete( txn_shmap ) );
      69           0 :     return NULL;
      70           0 :   }
      71             : 
      72      408483 :   void * rec_shmem = fd_wksp_alloc_laddr( wksp, fd_funk_rec_map_align(), fd_funk_rec_map_footprint( rec_max ), wksp_tag );
      73      408483 :   if( FD_UNLIKELY( !rec_shmem ) ) {
      74           3 :     FD_LOG_WARNING(( "rec_max too large for workspace" ));
      75           3 :     fd_wksp_free_laddr( fd_funk_txn_map_delete( fd_funk_txn_map_leave( txn_map ) ) );
      76           3 :     return NULL;
      77           3 :   }
      78             : 
      79      408480 :   void * rec_shmap = fd_funk_rec_map_new( rec_shmem, rec_max, seed );
      80      408480 :   if( FD_UNLIKELY( !rec_shmap ) ) {
      81           0 :     FD_LOG_WARNING(( "fd_funk_rec_map_new failed" ));
      82           0 :     fd_wksp_free_laddr( rec_shmem );
      83           0 :     fd_wksp_free_laddr( fd_funk_txn_map_delete( fd_funk_txn_map_leave( txn_map ) ) );
      84           0 :     return NULL;
      85           0 :   }
      86             : 
      87      408480 :   fd_funk_rec_t * rec_map = fd_funk_rec_map_join( rec_shmap );
      88      408480 :   if( FD_UNLIKELY( !rec_map ) ) {
      89           0 :     FD_LOG_WARNING(( "fd_funk_rec_map_join failed" ));
      90           0 :     fd_wksp_free_laddr( fd_funk_rec_map_delete( rec_shmap ) );
      91           0 :     fd_wksp_free_laddr( fd_funk_txn_map_delete( fd_funk_txn_map_leave( txn_map ) ) );
      92           0 :     return NULL;
      93           0 :   }
      94             : 
      95      408480 :   void * alloc_shmem = fd_wksp_alloc_laddr( wksp, fd_alloc_align(), fd_alloc_footprint(), wksp_tag );
      96      408480 :   if( FD_UNLIKELY( !alloc_shmem ) ) {
      97           0 :     FD_LOG_WARNING(( "fd_alloc too large for workspace" ));
      98           0 :     fd_wksp_free_laddr( fd_funk_rec_map_delete( fd_funk_rec_map_leave( rec_map ) ) );
      99           0 :     fd_wksp_free_laddr( fd_funk_txn_map_delete( fd_funk_txn_map_leave( txn_map ) ) );
     100           0 :     return NULL;
     101           0 :   }
     102             : 
     103      408480 :   void * alloc_shalloc = fd_alloc_new( alloc_shmem, wksp_tag );
     104      408480 :   if( FD_UNLIKELY( !alloc_shalloc ) ) {
     105           0 :     FD_LOG_WARNING(( "fd_alloc_new failed" ));
     106           0 :     fd_wksp_free_laddr( fd_funk_rec_map_delete( fd_funk_rec_map_leave( rec_map ) ) );
     107           0 :     fd_wksp_free_laddr( fd_funk_txn_map_delete( fd_funk_txn_map_leave( txn_map ) ) );
     108           0 :     return NULL;
     109           0 :   }
     110             : 
     111      408480 :   fd_alloc_t * alloc = fd_alloc_join( alloc_shalloc, 0UL ); /* TODO: Consider letting user pass the cgroup hint? */
     112      408480 :   if( FD_UNLIKELY( !alloc ) ) {
     113           0 :     FD_LOG_WARNING(( "fd_alloc_join failed" ));
     114           0 :     fd_wksp_free_laddr( fd_alloc_delete( alloc_shalloc ) );
     115           0 :     fd_wksp_free_laddr( fd_funk_rec_map_delete( fd_funk_rec_map_leave( rec_map ) ) );
     116           0 :     fd_wksp_free_laddr( fd_funk_txn_map_delete( fd_funk_txn_map_leave( txn_map ) ) );
     117           0 :     return NULL;
     118           0 :   }
     119             : 
     120      408480 :   fd_memset( funk, 0, fd_funk_footprint() );
     121             : 
     122      408480 :   funk->funk_gaddr = fd_wksp_gaddr_fast( wksp, funk );
     123      408480 :   funk->wksp_tag   = wksp_tag;
     124      408480 :   funk->seed       = seed;
     125      408480 :   funk->cycle_tag  = 3UL; /* various verify functions use tags 0-2 */
     126             : 
     127      408480 :   funk->txn_max         = txn_max;
     128      408480 :   funk->txn_map_gaddr   = fd_wksp_gaddr_fast( wksp, txn_map ); /* Note that this persists the join until delete */
     129      408480 :   funk->child_head_cidx = fd_funk_txn_cidx( FD_FUNK_TXN_IDX_NULL );
     130      408480 :   funk->child_tail_cidx = fd_funk_txn_cidx( FD_FUNK_TXN_IDX_NULL );
     131             : 
     132      408480 :   fd_funk_txn_xid_set_root( funk->root         );
     133      408480 :   fd_funk_txn_xid_set_root( funk->last_publish );
     134             : 
     135      408480 :   funk->rec_max       = rec_max;
     136      408480 :   funk->rec_map_gaddr = fd_wksp_gaddr_fast( wksp, rec_map ); /* Note that this persists the join until delete */
     137      408480 :   funk->rec_head_idx  = FD_FUNK_REC_IDX_NULL;
     138      408480 :   funk->rec_tail_idx  = FD_FUNK_REC_IDX_NULL;
     139             : 
     140      408480 :   funk->alloc_gaddr = fd_wksp_gaddr_fast( wksp, alloc ); /* Note that this persists the join until delete */
     141             : 
     142      408480 :   ulong tmp_max;
     143      408480 :   fd_funk_partvec_t * partvec = (fd_funk_partvec_t *)fd_alloc_malloc_at_least( alloc, fd_funk_partvec_align(), fd_funk_partvec_footprint(0U), &tmp_max );
     144      408480 :   if( FD_UNLIKELY( !partvec ) ) {
     145           0 :     FD_LOG_WARNING(( "partvec alloc failed" ));
     146           0 :     fd_wksp_free_laddr( fd_alloc_delete( alloc_shalloc ) );
     147           0 :     fd_wksp_free_laddr( fd_funk_rec_map_delete( fd_funk_rec_map_leave( rec_map ) ) );
     148           0 :     fd_wksp_free_laddr( fd_funk_txn_map_delete( fd_funk_txn_map_leave( txn_map ) ) );
     149           0 :     return NULL;
     150           0 :   }
     151      408480 :   partvec->num_part = 0U;
     152      408480 :   funk->partvec_gaddr = fd_wksp_gaddr_fast( wksp, partvec );
     153             : 
     154      408480 :   funk->write_lock = 0UL;
     155             : 
     156      408480 :   FD_COMPILER_MFENCE();
     157      408480 :   FD_VOLATILE( funk->magic ) = FD_FUNK_MAGIC;
     158      408480 :   FD_COMPILER_MFENCE();
     159             : 
     160      408480 :   return (void *)funk;
     161      408480 : }
     162             : 
     163             : fd_funk_t *
     164      408492 : fd_funk_join( void * shfunk ) {
     165      408492 :   fd_funk_t * funk = (fd_funk_t *)shfunk;
     166             : 
     167      408492 :   if( FD_UNLIKELY( !funk ) ) {
     168           3 :     FD_LOG_WARNING(( "NULL shfunk" ));
     169           3 :     return NULL;
     170           3 :   }
     171             : 
     172      408489 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)funk, fd_funk_align() ) ) ) {
     173           3 :     FD_LOG_WARNING(( "misaligned shfunk" ));
     174           3 :     return NULL;
     175           3 :   }
     176             : 
     177      408486 :   fd_wksp_t * wksp = fd_wksp_containing( funk );
     178      408486 :   if( FD_UNLIKELY( !wksp ) ) {
     179           3 :     FD_LOG_WARNING(( "shfunk must be part of a workspace" ));
     180           3 :     return NULL;
     181           3 :   }
     182             : 
     183      408483 :   if( FD_UNLIKELY( funk->magic!=FD_FUNK_MAGIC ) ) {
     184           3 :     FD_LOG_WARNING(( "bad magic" ));
     185           3 :     return NULL;
     186           3 :   }
     187             : 
     188             : #ifdef FD_FUNK_WKSP_PROTECT
     189             :   fd_wksp_mprotect( wksp, 1 );
     190             : #endif
     191             : 
     192      408480 :   return funk;
     193      408483 : }
     194             : 
     195             : void *
     196      408480 : fd_funk_leave( fd_funk_t * funk ) {
     197             : 
     198      408480 :   if( FD_UNLIKELY( !funk ) ) {
     199           3 :     FD_LOG_WARNING(( "NULL funk" ));
     200           3 :     return NULL;
     201           3 :   }
     202             : 
     203      408477 :   return (void *)funk;
     204      408480 : }
     205             : 
     206             : void *
     207      408489 : fd_funk_delete( void * shfunk ) {
     208      408489 :   fd_funk_t * funk = (fd_funk_t *)shfunk;
     209             : 
     210      408489 :   if( FD_UNLIKELY( !funk ) ) {
     211           3 :     FD_LOG_WARNING(( "NULL shfunk" ));
     212           3 :     return NULL;
     213           3 :   }
     214             : 
     215      408486 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)funk, fd_funk_align() ) ) ) {
     216           3 :     FD_LOG_WARNING(( "misaligned shfunk" ));
     217           3 :     return NULL;
     218           3 :   }
     219             : 
     220      408483 :   fd_wksp_t * wksp = fd_wksp_containing( funk );
     221      408483 :   if( FD_UNLIKELY( !wksp ) ) {
     222           3 :     FD_LOG_WARNING(( "shfunk must be part of a workspace" ));
     223           3 :     return NULL;
     224           3 :   }
     225             : 
     226      408480 :   if( FD_UNLIKELY( funk->magic!=FD_FUNK_MAGIC ) ) {
     227           3 :     FD_LOG_WARNING(( "bad magic" ));
     228           3 :     return NULL;
     229           3 :   }
     230             : 
     231             :   /* Free all value resources here */
     232             : 
     233      408477 :   fd_wksp_free_laddr( fd_alloc_delete       ( fd_alloc_leave       ( fd_funk_alloc  ( funk, wksp ) ) ) );
     234      408477 :   fd_wksp_free_laddr( fd_funk_rec_map_delete( fd_funk_rec_map_leave( fd_funk_rec_map( funk, wksp ) ) ) );
     235      408477 :   fd_wksp_free_laddr( fd_funk_txn_map_delete( fd_funk_txn_map_leave( fd_funk_txn_map( funk, wksp ) ) ) );
     236             : 
     237      408477 :   FD_COMPILER_MFENCE();
     238      408477 :   FD_VOLATILE( funk->magic ) = 0UL;
     239      408477 :   FD_COMPILER_MFENCE();
     240             : 
     241      408477 :   return funk;
     242      408480 : }
     243             : 
     244             : int
     245    22275108 : fd_funk_verify( fd_funk_t * funk ) {
     246             : 
     247   757353672 : # define TEST(c) do {                                                                           \
     248   757353672 :     if( FD_UNLIKELY( !(c) ) ) { FD_LOG_WARNING(( "FAIL: %s", #c )); return FD_FUNK_ERR_INVAL; } \
     249   757353672 :   } while(0)
     250             : 
     251    22275108 :   TEST( funk );
     252             : 
     253             :   /* Test metadata */
     254             : 
     255    22275108 :   TEST( funk->magic==FD_FUNK_MAGIC );
     256             : 
     257    22275108 :   ulong funk_gaddr = funk->funk_gaddr;
     258    22275108 :   TEST( funk_gaddr );
     259    22275108 :   fd_wksp_t * wksp = fd_funk_wksp( funk );
     260    22275108 :   TEST( wksp );
     261    22275108 :   TEST( fd_wksp_laddr_fast( wksp, funk_gaddr )==(void *)funk );
     262    22275108 :   TEST( fd_wksp_gaddr_fast( wksp, funk       )==funk_gaddr   );
     263             : 
     264    22275108 :   ulong wksp_tag = fd_funk_wksp_tag( funk );
     265    22275108 :   TEST( !!wksp_tag );
     266             : 
     267    22275108 :   ulong seed = funk->seed; /* seed can be anything */
     268             : 
     269    22275108 :   TEST( funk->cycle_tag>2UL );
     270             : 
     271             :   /* Test transaction map */
     272             : 
     273    22275108 :   ulong txn_max = funk->txn_max;
     274    22275108 :   TEST( txn_max<=FD_FUNK_TXN_IDX_NULL );
     275             : 
     276    22275108 :   ulong txn_map_gaddr = funk->txn_map_gaddr;
     277    22275108 :   TEST( txn_map_gaddr );
     278    22275108 :   TEST( fd_wksp_tag( wksp, txn_map_gaddr-1UL )==wksp_tag ); /* When txn_max is 0, txn_map_gaddr can be first byte after alloc */
     279    22275108 :   fd_funk_txn_t * txn_map = fd_funk_txn_map( funk, wksp );
     280    22275108 :   TEST( txn_map );
     281    22275108 :   TEST( txn_max==fd_funk_txn_map_key_max( txn_map ) );
     282    22275108 :   TEST( seed   ==fd_funk_txn_map_seed   ( txn_map ) );
     283             : 
     284    22275108 :   ulong child_head_idx = fd_funk_txn_idx( funk->child_head_cidx );
     285    22275108 :   ulong child_tail_idx = fd_funk_txn_idx( funk->child_tail_cidx );
     286             : 
     287    22275108 :   int null_child_head = fd_funk_txn_idx_is_null( child_head_idx );
     288    22275108 :   int null_child_tail = fd_funk_txn_idx_is_null( child_tail_idx );
     289             : 
     290    22275108 :   if( !txn_max ) TEST( null_child_head & null_child_tail );
     291    22275102 :   else {
     292    22275102 :     if( null_child_head ) TEST( null_child_tail );
     293    15474219 :     else                  TEST( child_head_idx<txn_max );
     294             : 
     295    22275102 :     if( null_child_tail ) TEST( null_child_head );
     296    15474219 :     else                  TEST( child_tail_idx<txn_max );
     297    22275102 :   }
     298             : 
     299    22275108 :   if( !txn_max ) TEST( fd_funk_txn_idx_is_null( child_tail_idx ) );
     300             : 
     301    22275108 :   fd_funk_txn_xid_t const * root = fd_funk_root( funk );
     302    22275108 :   TEST( root ); /* Practically guaranteed */
     303    22275108 :   TEST( fd_funk_txn_xid_eq_root( root ) );
     304             : 
     305    22275108 :   fd_funk_txn_xid_t * last_publish = funk->last_publish;
     306    22275108 :   TEST( last_publish ); /* Practically guaranteed */
     307             :   /* (*last_publish) only be root at creation and anything but root post
     308             :      creation.  But we don't know which situation applies here so this
     309             :      could be anything. */
     310             : 
     311    22275108 :   TEST( !fd_funk_txn_verify( funk ) );
     312             : 
     313             :   /* Test record map */
     314             : 
     315    22275108 :   ulong rec_max = funk->rec_max;
     316    22275108 :   TEST( rec_max<=FD_FUNK_TXN_IDX_NULL );
     317             : 
     318    22275108 :   ulong rec_map_gaddr = funk->rec_map_gaddr;
     319    22275108 :   TEST( rec_map_gaddr );
     320    22275108 :   TEST( fd_wksp_tag( wksp, rec_map_gaddr-1UL )==wksp_tag ); /* When rec_max is zero, rec_map_gaddr can be first byte after alloc */
     321    22275108 :   fd_funk_rec_t * rec_map = fd_funk_rec_map( funk, wksp );
     322    22275108 :   TEST( rec_map );
     323    22275108 :   TEST( rec_max==fd_funk_rec_map_key_max( rec_map ) );
     324    22275108 :   TEST( seed   ==fd_funk_rec_map_seed   ( rec_map ) );
     325             : 
     326    22275108 :   ulong rec_head_idx = funk->rec_head_idx;
     327    22275108 :   ulong rec_tail_idx = funk->rec_tail_idx;
     328             : 
     329    22275108 :   int null_rec_head = fd_funk_rec_idx_is_null( rec_head_idx );
     330    22275108 :   int null_rec_tail = fd_funk_rec_idx_is_null( rec_tail_idx );
     331             : 
     332    22275108 :   if( !rec_max ) TEST( null_rec_head & null_rec_tail );
     333    22275102 :   else {
     334    22275102 :     if( null_rec_head ) TEST( null_rec_tail );
     335    19129353 :     else                TEST( rec_head_idx<rec_max );
     336             : 
     337    22275102 :     if( null_rec_tail ) TEST( null_rec_head );
     338    19129353 :     else                TEST( rec_tail_idx<rec_max );
     339    22275102 :   }
     340             : 
     341    22275108 :   if( !rec_max ) TEST( fd_funk_rec_idx_is_null( rec_tail_idx ) );
     342             : 
     343    22275108 :   TEST( !fd_funk_rec_verify( funk ) );
     344    22275108 :   TEST( !fd_funk_part_verify( funk ) );
     345             : 
     346             :   /* Test values */
     347             : 
     348    22275108 :   ulong alloc_gaddr = funk->alloc_gaddr;
     349    22275108 :   TEST( alloc_gaddr );
     350    22275108 :   TEST( fd_wksp_tag( wksp, alloc_gaddr )==wksp_tag );
     351    22275108 :   fd_alloc_t * alloc = fd_funk_alloc( funk, wksp );
     352    22275108 :   TEST( alloc );
     353             : 
     354    22275108 :   TEST( !fd_funk_val_verify( funk ) );
     355             : 
     356    22275108 : # undef TEST
     357             : 
     358    22275108 :   return FD_FUNK_SUCCESS;
     359    22275108 : }
     360             : 
     361             : static char *
     362           0 : fd_smart_size( ulong sz, char * tmp, size_t tmpsz ) {
     363           0 :   if( sz <= (1UL<<7) )
     364           0 :     snprintf( tmp, tmpsz, "%lu B", sz );
     365           0 :   else if( sz <= (1UL<<17) )
     366           0 :     snprintf( tmp, tmpsz, "%.3f KB", ((double)sz/((double)(1UL<<10))) );
     367           0 :   else if( sz <= (1UL<<27) )
     368           0 :     snprintf( tmp, tmpsz, "%.3f MB", ((double)sz/((double)(1UL<<20))) );
     369           0 :   else
     370           0 :     snprintf( tmp, tmpsz, "%.3f GB", ((double)sz/((double)(1UL<<30))) );
     371           0 :   return tmp;
     372           0 : }
     373             : 
     374             : void
     375           0 : fd_funk_log_mem_usage( fd_funk_t * funk ) {
     376           0 :   char tmp1[100];
     377           0 :   char tmp2[100];
     378             : 
     379           0 :   FD_LOG_NOTICE(( "funk base footprint: %s",
     380           0 :                   fd_smart_size( fd_funk_footprint(), tmp1, sizeof(tmp1) ) ));
     381           0 :   fd_wksp_t * wksp = fd_funk_wksp( funk );
     382           0 :   fd_funk_txn_t const * txn_map = fd_funk_txn_map( funk, wksp );
     383           0 :   FD_LOG_NOTICE(( "txn table footprint: %s (%lu entries used out of %lu, %lu%%)",
     384           0 :                   fd_smart_size( fd_funk_txn_map_footprint( funk->txn_max ), tmp1, sizeof(tmp1) ),
     385           0 :                   fd_funk_txn_map_key_cnt( txn_map ),
     386           0 :                   fd_funk_txn_map_key_max( txn_map ),
     387           0 :                   (100U*fd_funk_txn_map_key_cnt( txn_map )) / fd_funk_txn_map_key_max( txn_map ) ));
     388           0 :   fd_funk_rec_t * rec_map = fd_funk_rec_map( funk, wksp );
     389           0 :   FD_LOG_NOTICE(( "rec table footprint: %s (%lu entries used out of %lu, %lu%%)",
     390           0 :                   fd_smart_size( fd_funk_rec_map_footprint( funk->rec_max ), tmp1, sizeof(tmp1) ),
     391           0 :                   fd_funk_rec_map_key_cnt( rec_map ),
     392           0 :                   fd_funk_rec_map_key_max( rec_map ),
     393           0 :                   (100U*fd_funk_rec_map_key_cnt( rec_map )) / fd_funk_rec_map_key_max( rec_map ) ));
     394           0 :   ulong val_cnt   = 0;
     395           0 :   ulong val_min   = ULONG_MAX;
     396           0 :   ulong val_max   = 0;
     397           0 :   ulong val_used  = 0;
     398           0 :   ulong val_alloc = 0;
     399           0 :   for( fd_funk_rec_map_iter_t iter = fd_funk_rec_map_iter_init( rec_map );
     400           0 :        !fd_funk_rec_map_iter_done( rec_map, iter );
     401           0 :        iter = fd_funk_rec_map_iter_next( rec_map, iter ) ) {
     402           0 :     fd_funk_rec_t * rec = fd_funk_rec_map_iter_ele( rec_map, iter );
     403           0 :     val_cnt ++;
     404           0 :     val_min = fd_ulong_min( val_min, rec->val_sz );
     405           0 :     val_max = fd_ulong_max( val_max, rec->val_sz );
     406           0 :     val_used += rec->val_sz;
     407           0 :     val_alloc += rec->val_max;
     408           0 :   }
     409           0 :   ulong avg_size = val_cnt ? (val_used / val_cnt) : 0;
     410           0 :   FD_LOG_NOTICE(( "  rec count: %lu, min size: %lu, avg_size: %lu, max_size: %lu, total_size: %s, total_allocated: %s",
     411           0 :                   val_cnt, val_min, avg_size, val_max,
     412           0 :                   fd_smart_size( val_used, tmp1, sizeof(tmp1) ),
     413           0 :                   fd_smart_size( val_alloc, tmp2, sizeof(tmp2) ) ));
     414           0 :   FD_LOG_NOTICE(( "part vec footprint: %s",
     415           0 :                   fd_smart_size( fd_funk_partvec_footprint(0U), tmp1, sizeof(tmp1) ) ));
     416           0 : }
     417             : 
     418             : #include "../flamenco/fd_rwlock.h"
     419             : static fd_rwlock_t lock[ 1 ] = {0};
     420             : 
     421             : void
     422     7116480 : fd_funk_start_write( fd_funk_t * funk ) {
     423     7116480 :   fd_rwlock_write( lock );
     424             : #ifdef FD_FUNK_WKSP_PROTECT
     425             :   fd_wksp_mprotect( fd_funk_wksp( funk ), 0 );
     426             : #endif
     427     7116480 : # if FD_HAS_THREADS
     428     7116480 :   register ulong oldval;
     429     7116480 :   for(;;) {
     430     7116480 :     oldval = funk->write_lock;
     431     7116480 :     if( FD_LIKELY( FD_ATOMIC_CAS( &funk->write_lock, oldval, oldval+1U) == oldval ) ) break;
     432           0 :     FD_SPIN_PAUSE();
     433           0 :   }
     434     7116480 :   if( FD_UNLIKELY(oldval&1UL) ) {
     435           0 :      FD_LOG_CRIT(( "attempt to lock funky when it is already locked" ));
     436           0 :   }
     437     7116480 :   FD_COMPILER_MFENCE();
     438             : # else
     439             :   (void)funk;
     440             : # endif
     441     7116480 : }
     442             : 
     443             : void
     444     7116480 : fd_funk_end_write( fd_funk_t * funk ) {
     445     7116480 : # if FD_HAS_THREADS
     446     7116480 :   FD_COMPILER_MFENCE();
     447     7116480 :   register ulong oldval;
     448     7116480 :   for(;;) {
     449     7116480 :     oldval = funk->write_lock;
     450     7116480 :     if( FD_LIKELY( FD_ATOMIC_CAS( &funk->write_lock, oldval, oldval+1U) == oldval ) ) break;
     451           0 :     FD_SPIN_PAUSE();
     452           0 :   }
     453     7116480 :   if( FD_UNLIKELY(!(oldval&1UL)) ) {
     454           0 :     FD_LOG_CRIT(( "attempt to unlock funky when it is already unlocked" ));
     455           0 :   }
     456             : # else
     457             :   (void)funk;
     458             : # endif
     459             : #ifdef FD_FUNK_WKSP_PROTECT
     460             :   fd_wksp_mprotect( fd_funk_wksp( funk ), 1 );
     461             : #endif
     462     7116480 :   fd_rwlock_unwrite( lock );
     463     7116480 : }
     464             : 
     465             : void
     466   568010892 : fd_funk_check_write( fd_funk_t * funk ) {
     467   568010892 :   ulong val = funk->write_lock;
     468   568010892 :   if( FD_UNLIKELY(!(val&1UL)) ) FD_LOG_CRIT(( "missing call to fd_funk_start_write" ));
     469   568010892 : }

Generated by: LCOV version 1.14