LCOV - code coverage report
Current view: top level - flamenco/accdb - bench_accdb.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 301 0.0 %
Date: 2026-06-30 05:50:37 Functions: 0 9 0.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : 
       3             : #include "fd_accdb.h"
       4             : #include "../../util/fd_util.h"
       5             : 
       6             : #include <stdlib.h>
       7             : #include <string.h>
       8             : #include <unistd.h>
       9             : #include <sys/mman.h>
      10             : 
      11             : /* Account size distribution modeled from Solana mainnet snapshot data.
      12             :    ~996M accounts, ~285.5 GiB total.  The cumulative distribution
      13             :    function (CDF) is encoded as a table of (threshold, avg_size) pairs
      14             :    so we can sample sizes that match real-world distribution.
      15             : 
      16             :    Key characteristics:
      17             :      - 65% of accounts are 128-256 bytes (token accounts, 165 B)
      18             :      - 91% of accounts are <= 256 bytes
      19             :      - 99% of accounts are <= 1024 bytes
      20             :      - Tail goes up to 10 MiB
      21             : 
      22             :    Weights below are parts-per-thousand (permille).  They sum to
      23             :    1000 and are derived from the bin_cnt column of the histogram. */
      24             : 
      25             : struct size_bucket {
      26             :   uint weight;   /* permille (parts per 1000) */
      27             :   uint avg_size; /* representative size for this bucket */
      28             : };
      29             : 
      30             : static struct size_bucket const SIZE_DIST[] = {
      31             :   {  76,      0 },  /*   0 <= sz <=    0 :  7.6% */
      32             :   {  33,      1 },  /*   0 <  sz <=    1 :  0.3% (cumul  7.9%) — grouped small */
      33             :   {   5,      2 },  /*   1 <  sz <=    2 */
      34             :   {   4,      3 },  /*   2 <  sz <=    4 */
      35             :   {   2,      7 },  /*   4 <  sz <=    8 */
      36             :   {   8,     12 },  /*   8 <  sz <=   16 */
      37             :   {  31,     22 },  /*  16 <  sz <=   32 */
      38             :   {  27,     51 },  /*  32 <  sz <=   64 */
      39             :   { 113,     88 },  /*  64 <  sz <=  128 */
      40             :   { 653,    165 },  /* 128 <  sz <=  256 : 65.3% — token accounts */
      41             :   {  20,    347 },  /* 256 <  sz <=  512 */
      42             :   {  14,    638 },  /* 512 <  sz <= 1024 — kept small so bench runs fast */
      43             :   /*  remaining ~1.2% grouped into larger buckets, but omitted for
      44             :       benchmark speed.  We add the remaining weight to the 638 bucket
      45             :       above so weights sum to ~1000. */
      46             : };
      47             : 
      48           0 : #define SIZE_DIST_CNT (sizeof(SIZE_DIST)/sizeof(SIZE_DIST[0]))
      49             : 
      50             : static ulong
      51           0 : sample_account_size( fd_rng_t * rng ) {
      52           0 :   uint r = fd_rng_uint( rng ) % 1000U;
      53           0 :   uint cumul = 0U;
      54           0 :   for( ulong i=0UL; i<SIZE_DIST_CNT; i++ ) {
      55           0 :     cumul += SIZE_DIST[ i ].weight;
      56           0 :     if( r<cumul ) return (ulong)SIZE_DIST[ i ].avg_size;
      57           0 :   }
      58           0 :   return 165UL; /* fallback: token account */
      59           0 : }
      60             : 
      61             : /* Generate a random pubkey from an index.  The index is encoded into
      62             :    the first 8 bytes so that each index produces a unique pubkey, while
      63             :    the rest is zeroed for reproducibility. */
      64             : static void
      65             : make_pubkey( uchar pubkey[ static 32 ],
      66           0 :              ulong idx ) {
      67           0 :   fd_memset( pubkey, 0, 32UL );
      68           0 :   fd_memcpy( pubkey, &idx, sizeof(ulong) );
      69           0 : }
      70             : 
      71             : static uchar dummy_owner[ 32 ] = { 0xEE };
      72             : 
      73             : /* Maximum account data size used in the benchmark.  We cap at 1024
      74             :    to keep I/O reasonable; the long tail is rare on mainnet anyway. */
      75           0 : #define BENCH_MAX_DATA_SZ (1024UL)
      76             : 
      77             : static uchar data_buf[ BENCH_MAX_DATA_SZ ];
      78             : 
      79             : /* Cache footprint for benchmarks: must cover BENCH_CACHE_MIN_RESERVED
      80             :    slots per class (class 7 is 10 MiB each). */
      81           0 : #define BENCH_CACHE_FOOTPRINT  (16UL<<30UL)
      82           0 : #define BENCH_CACHE_MIN_RESERVED (640UL)
      83             : 
      84             : static fd_accdb_t *
      85             : bench_setup( int * out_fd,
      86             :              ulong max_accounts,
      87             :              ulong max_live_slots,
      88             :              ulong max_account_writes_per_slot,
      89             :              ulong partition_cnt,
      90           0 :              ulong partition_sz ) {
      91           0 :   int fd = memfd_create( "accdb_bench", 0 );
      92           0 :   if( FD_UNLIKELY( fd<0 ) ) FD_LOG_ERR(( "memfd_create failed" ));
      93           0 :   *out_fd = fd;
      94             : 
      95           0 :   ulong cache_fp = BENCH_CACHE_FOOTPRINT;
      96           0 :   ulong shmem_fp = fd_accdb_shmem_footprint( max_accounts, max_live_slots, max_account_writes_per_slot, partition_cnt, cache_fp, BENCH_CACHE_MIN_RESERVED, 1UL );
      97           0 :   FD_TEST( shmem_fp );
      98           0 :   void * shmem_mem = aligned_alloc( fd_accdb_shmem_align(), shmem_fp );
      99           0 :   FD_TEST( shmem_mem );
     100           0 :   fd_accdb_shmem_t * shmem = fd_accdb_shmem_join(
     101           0 :       fd_accdb_shmem_new( shmem_mem, max_accounts, max_live_slots,
     102           0 :                           max_account_writes_per_slot, partition_cnt,
     103           0 :                           partition_sz, cache_fp, BENCH_CACHE_MIN_RESERVED, 0, 42UL, 1UL ) );
     104           0 :   FD_TEST( shmem );
     105             : 
     106           0 :   ulong accdb_fp = fd_accdb_footprint( max_live_slots );
     107           0 :   FD_TEST( accdb_fp );
     108           0 :   void * accdb_mem = aligned_alloc( fd_accdb_align(), accdb_fp );
     109           0 :   FD_TEST( accdb_mem );
     110           0 :   fd_accdb_t * accdb = fd_accdb_join( fd_accdb_new( accdb_mem, shmem, fd, 0UL, NULL ) );
     111           0 :   FD_TEST( accdb );
     112           0 :   return accdb;
     113           0 : }
     114             : 
     115             : /* Helper: write a single account via acquire/release. */
     116             : static void
     117             : bench_write_one( fd_accdb_t *       accdb,
     118             :                  fd_accdb_fork_id_t fork_id,
     119             :                  uchar const *      pubkey,
     120             :                  ulong              lamports,
     121             :                  uchar const *      data,
     122             :                  ulong              data_len,
     123           0 :                  uchar const *      owner ) {
     124           0 :   uchar const * pks[1] = { pubkey };
     125           0 :   int wr[1] = { 1 };
     126           0 :   fd_acc_t acc[1];
     127           0 :   memset( acc, 0, sizeof(acc) );
     128           0 :   fd_accdb_acquire( accdb, fork_id, 1UL, pks, wr, acc );
     129           0 :   acc[0].lamports = lamports;
     130           0 :   acc[0].data_len = data_len;
     131           0 :   memcpy( acc[0].owner, owner, 32UL );
     132           0 :   if( data_len && data ) memcpy( acc[0].data, data, data_len );
     133           0 :   acc[0].commit = 1;
     134           0 :   fd_accdb_release( accdb, 1UL, acc );
     135           0 : }
     136             : 
     137             : /* Helper: read a single account via acquire/release.  Returns 1 if
     138             :    found. */
     139             : static int
     140             : bench_read_one( fd_accdb_t *       accdb,
     141             :                 fd_accdb_fork_id_t fork_id,
     142             :                 uchar const *      pubkey,
     143             :                 ulong *            out_lamports,
     144             :                 uchar *            out_data,
     145             :                 ulong *            out_data_len,
     146           0 :                 uchar *            out_owner ) {
     147           0 :   uchar const * pks[1] = { pubkey };
     148           0 :   int wr[1] = { 0 };
     149           0 :   fd_acc_t acc[1];
     150           0 :   memset( acc, 0, sizeof(acc) );
     151           0 :   fd_accdb_acquire( accdb, fork_id, 1UL, pks, wr, acc );
     152           0 :   int found = acc[0].lamports!=0UL;
     153           0 :   if( found ) {
     154           0 :     if( out_lamports ) *out_lamports = acc[0].lamports;
     155           0 :     if( out_data_len ) *out_data_len = acc[0].data_len;
     156           0 :     if( out_owner )    memcpy( out_owner, acc[0].owner, 32UL );
     157           0 :     if( out_data && acc[0].data && acc[0].data_len )
     158           0 :       memcpy( out_data, acc[0].data, acc[0].data_len );
     159           0 :   }
     160           0 :   fd_accdb_release( accdb, 1UL, acc );
     161           0 :   return found;
     162           0 : }
     163             : 
     164             : /* ------------------------------------------------------------------ */
     165             : 
     166             : /* bench_write: Populate N accounts on a single fork, measuring write
     167             :    throughput.  Account sizes are sampled from the mainnet distribution
     168             :    so the I/O pattern is realistic. */
     169             : static void
     170             : bench_write( ulong   account_cnt,
     171           0 :              fd_rng_t * rng ) {
     172           0 :   int fd;
     173           0 :   ulong partition_sz = 1UL<<30UL;
     174           0 :   ulong partition_cnt = 1024UL;
     175           0 :   fd_accdb_t * accdb = bench_setup( &fd,
     176           0 :                                     account_cnt + 1024UL,
     177           0 :                                     64UL,
     178           0 :                                     (uint)account_cnt + 1024U,
     179           0 :                                     partition_cnt,
     180           0 :                                     partition_sz );
     181             : 
     182           0 :   fd_accdb_fork_id_t root  = fd_accdb_attach_child( accdb, (fd_accdb_fork_id_t){ .val = USHORT_MAX } );
     183           0 :   fd_accdb_fork_id_t fork  = fd_accdb_attach_child( accdb, root );
     184             : 
     185           0 :   uchar pubkey[ 32 ];
     186           0 :   ulong total_bytes = 0UL;
     187             : 
     188           0 :   long dt = -fd_log_wallclock();
     189           0 :   for( ulong i=0UL; i<account_cnt; i++ ) {
     190           0 :     make_pubkey( pubkey, i );
     191           0 :     ulong sz = sample_account_size( rng );
     192           0 :     if( sz>BENCH_MAX_DATA_SZ ) sz = BENCH_MAX_DATA_SZ;
     193           0 :     bench_write_one( accdb, fork, pubkey, i+1UL,
     194           0 :                      sz ? data_buf : NULL, sz, dummy_owner );
     195           0 :     total_bytes += sz;
     196           0 :   }
     197           0 :   dt += fd_log_wallclock();
     198             : 
     199           0 :   double secs = (double)dt / 1e9;
     200           0 :   FD_LOG_NOTICE(( "bench_write: %lu accounts, %.2f MiB data in %.3f s "
     201           0 :                   "(%.0f accts/s, %.2f MiB/s, %.0f ns/write)",
     202           0 :                   account_cnt,
     203           0 :                   (double)total_bytes / (double)(1UL<<20UL),
     204           0 :                   secs,
     205           0 :                   (double)account_cnt / secs,
     206           0 :                   (double)total_bytes / (double)(1UL<<20UL) / secs,
     207           0 :                   (double)dt / (double)account_cnt ));
     208             : 
     209           0 :   close( fd );
     210           0 : }
     211             : 
     212             : /* ------------------------------------------------------------------ */
     213             : 
     214             : /* bench_read: Populate N accounts, then read them all back in random
     215             :    order, measuring read throughput. */
     216             : static void
     217             : bench_read( ulong   account_cnt,
     218           0 :             fd_rng_t * rng ) {
     219           0 :   int fd;
     220           0 :   ulong partition_sz = 1UL<<30UL;
     221           0 :   ulong partition_cnt = 1024UL;
     222           0 :   fd_accdb_t * accdb = bench_setup( &fd,
     223           0 :                                     account_cnt + 1024UL,
     224           0 :                                     64UL,
     225           0 :                                     (uint)account_cnt + 1024U,
     226           0 :                                     partition_cnt,
     227           0 :                                     partition_sz );
     228             : 
     229           0 :   fd_accdb_fork_id_t root  = fd_accdb_attach_child( accdb, (fd_accdb_fork_id_t){ .val = USHORT_MAX } );
     230           0 :   fd_accdb_fork_id_t fork  = fd_accdb_attach_child( accdb, root );
     231             : 
     232             :   /* Populate */
     233           0 :   uchar pubkey[ 32 ];
     234           0 :   for( ulong i=0UL; i<account_cnt; i++ ) {
     235           0 :     make_pubkey( pubkey, i );
     236           0 :     ulong sz = sample_account_size( rng );
     237           0 :     if( sz>BENCH_MAX_DATA_SZ ) sz = BENCH_MAX_DATA_SZ;
     238           0 :     bench_write_one( accdb, fork, pubkey, i+1UL,
     239           0 :                      sz ? data_buf : NULL, sz, dummy_owner );
     240           0 :   }
     241             : 
     242             :   /* Read in random order */
     243           0 :   ulong  lamports;
     244           0 :   uchar  rdata[ BENCH_MAX_DATA_SZ ];
     245           0 :   ulong  data_len;
     246           0 :   uchar  owner[ 32 ];
     247           0 :   ulong  total_bytes = 0UL;
     248           0 :   ulong  found = 0UL;
     249             : 
     250           0 :   long dt = -fd_log_wallclock();
     251           0 :   for( ulong i=0UL; i<account_cnt; i++ ) {
     252           0 :     ulong idx = fd_rng_ulong( rng ) % account_cnt;
     253           0 :     make_pubkey( pubkey, idx );
     254           0 :     if( bench_read_one( accdb, fork, pubkey, &lamports,
     255           0 :                         rdata, &data_len, owner ) ) {
     256           0 :       total_bytes += data_len;
     257           0 :       found++;
     258           0 :     }
     259           0 :   }
     260           0 :   dt += fd_log_wallclock();
     261             : 
     262           0 :   double secs = (double)dt / 1e9;
     263           0 :   FD_LOG_NOTICE(( "bench_read:  %lu reads (%lu hit), %.2f MiB in %.3f s "
     264           0 :                   "(%.0f reads/s, %.2f MiB/s, %.0f ns/read)",
     265           0 :                   account_cnt, found,
     266           0 :                   (double)total_bytes / (double)(1UL<<20UL),
     267           0 :                   secs,
     268           0 :                   (double)account_cnt / secs,
     269           0 :                   (double)total_bytes / (double)(1UL<<20UL) / secs,
     270           0 :                   (double)dt / (double)account_cnt ));
     271             : 
     272           0 :   close( fd );
     273           0 : }
     274             : 
     275             : /* ------------------------------------------------------------------ */
     276             : 
     277             : /* bench_replay: Simulate a realistic replay workload.  Each slot
     278             :    consists of ~reads_per_slot read queries followed by
     279             :    ~writes_per_slot account updates, then the previous slot is
     280             :    rooted.  This mirrors actual replay where each transaction reads
     281             :    several accounts (programs, signers, state) before writing back
     282             :    a smaller set.
     283             : 
     284             :    On mainnet a typical slot has ~1200 transactions, each touching
     285             :    ~5-10 accounts for reads and ~2-4 for writes.  The default
     286             :    parameterization captures this: 1200 writes/slot with 4x as
     287             :    many reads.
     288             : 
     289             :    Timing is tracked separately for reads, writes, and rooting to
     290             :    identify bottlenecks. */
     291             : static void
     292             : bench_replay( ulong   slot_cnt,
     293             :               ulong   writes_per_slot,
     294             :               ulong   reads_per_slot,
     295           0 :               fd_rng_t * rng ) {
     296           0 :   int fd;
     297           0 :   ulong total_accounts = slot_cnt * writes_per_slot + 1024UL;
     298           0 :   ulong partition_sz  = 1UL<<30UL;
     299           0 :   ulong partition_cnt = 1024UL;
     300           0 :   ulong max_live      = 64UL;
     301           0 :   fd_accdb_t * accdb = bench_setup( &fd,
     302           0 :                                     total_accounts,
     303           0 :                                     max_live,
     304           0 :                                     writes_per_slot + 16UL,
     305           0 :                                     partition_cnt,
     306           0 :                                     partition_sz );
     307             : 
     308           0 :   fd_accdb_fork_id_t root = fd_accdb_attach_child( accdb, (fd_accdb_fork_id_t){ .val = USHORT_MAX } );
     309             : 
     310           0 :   uchar pubkey[ 32 ];
     311             : 
     312             :   /* We re-use a pool of pubkeys so that rooting has old versions to
     313             :      tombstone (realistic for hot accounts like token program,
     314             :      system program, fee payers, etc.). */
     315           0 :   ulong pubkey_pool_sz = writes_per_slot * 4UL;
     316             : 
     317           0 :   ulong total_reads       = 0UL;
     318           0 :   ulong total_read_hits   = 0UL;
     319           0 :   ulong total_writes      = 0UL;
     320           0 :   ulong total_write_bytes = 0UL;
     321           0 :   long  dt_read           = 0;
     322           0 :   long  dt_write          = 0;
     323           0 :   long  dt_root           = 0;
     324             : 
     325           0 :   uchar  rdata[ BENCH_MAX_DATA_SZ ];
     326           0 :   ulong  lamports;
     327           0 :   ulong  data_len;
     328           0 :   uchar  owner[ 32 ];
     329             : 
     330           0 :   long dt_total = -fd_log_wallclock();
     331           0 :   fd_accdb_fork_id_t prev = root;
     332           0 :   for( ulong s=0UL; s<slot_cnt; s++ ) {
     333           0 :     fd_accdb_fork_id_t cur = fd_accdb_attach_child( accdb, prev );
     334             : 
     335             :     /* --- reads (simulate transaction account loading) --- */
     336           0 :     long t0 = fd_log_wallclock();
     337           0 :     for( ulong r=0UL; r<reads_per_slot; r++ ) {
     338           0 :       ulong idx = fd_rng_ulong( rng ) % pubkey_pool_sz;
     339           0 :       make_pubkey( pubkey, idx );
     340           0 :       if( bench_read_one( accdb, cur, pubkey, &lamports,
     341           0 :                           rdata, &data_len, owner ) ) {
     342           0 :         total_read_hits++;
     343           0 :       }
     344           0 :       total_reads++;
     345           0 :     }
     346           0 :     long t1 = fd_log_wallclock();
     347           0 :     dt_read += (t1 - t0);
     348             : 
     349             :     /* --- writes (simulate transaction execution results) --- */
     350           0 :     for( ulong w=0UL; w<writes_per_slot; w++ ) {
     351           0 :       ulong idx = fd_rng_ulong( rng ) % pubkey_pool_sz;
     352           0 :       make_pubkey( pubkey, idx );
     353           0 :       ulong sz = sample_account_size( rng );
     354           0 :       if( sz>BENCH_MAX_DATA_SZ ) sz = BENCH_MAX_DATA_SZ;
     355           0 :       bench_write_one( accdb, cur, pubkey, (s*writes_per_slot + w)+1UL,
     356           0 :                        sz ? data_buf : NULL, sz, dummy_owner );
     357           0 :       total_write_bytes += sz;
     358           0 :       total_writes++;
     359           0 :     }
     360           0 :     long t2 = fd_log_wallclock();
     361           0 :     dt_write += (t2 - t1);
     362             : 
     363             :     /* --- root previous slot --- */
     364           0 :     if( FD_LIKELY( s>0UL ) ) {
     365           0 :       fd_accdb_advance_root( accdb, prev );
     366           0 :       { int b = 0; fd_accdb_background( accdb, &b ); }
     367           0 :     }
     368           0 :     long t3 = fd_log_wallclock();
     369           0 :     dt_root += (t3 - t2);
     370             : 
     371           0 :     prev = cur;
     372           0 :   }
     373           0 :   dt_total += fd_log_wallclock();
     374             : 
     375           0 :   fd_accdb_shmem_metrics_t const * m = fd_accdb_shmetrics( accdb );
     376             : 
     377           0 :   double total_secs = (double)dt_total / 1e9;
     378           0 :   FD_LOG_NOTICE(( "bench_replay: %lu slots, %lu reads/slot, "
     379           0 :                   "%lu writes/slot, %.3f s total",
     380           0 :                   slot_cnt, reads_per_slot, writes_per_slot,
     381           0 :                   total_secs ));
     382           0 :   FD_LOG_NOTICE(( "  read:    %lu queries (%lu hits, %.1f%% hit rate), "
     383           0 :                   "%.0f reads/s, %.0f ns/read",
     384           0 :                   total_reads, total_read_hits,
     385           0 :                   total_reads ? 100.0*(double)total_read_hits/(double)total_reads : 0.0,
     386           0 :                   (double)total_reads / ((double)dt_read/1e9),
     387           0 :                   dt_read ? (double)dt_read/(double)total_reads : 0.0 ));
     388           0 :   FD_LOG_NOTICE(( "  write:   %lu writes, %.2f MiB, "
     389           0 :                   "%.0f writes/s, %.0f ns/write",
     390           0 :                   total_writes,
     391           0 :                   (double)total_write_bytes / (double)(1UL<<20UL),
     392           0 :                   (double)total_writes / ((double)dt_write/1e9),
     393           0 :                   dt_write ? (double)dt_write/(double)total_writes : 0.0 ));
     394           0 :   FD_LOG_NOTICE(( "  root:    %.0f ns/root, %.3f s total "
     395           0 :                   "(%lu slots rooted)",
     396           0 :                   slot_cnt>1UL ? (double)dt_root/(double)(slot_cnt-1UL) : 0.0,
     397           0 :                   (double)dt_root / 1e9,
     398           0 :                   slot_cnt>1UL ? slot_cnt-1UL : 0UL ));
     399           0 :   FD_LOG_NOTICE(( "  slot:    %.0f ns/slot (%.0f slots/s)",
     400           0 :                   (double)dt_total / (double)slot_cnt,
     401           0 :                   (double)slot_cnt / total_secs ));
     402           0 :   FD_LOG_NOTICE(( "  metrics: accounts_total=%lu disk_used=%.2f MiB "
     403           0 :                   "disk_alloc=%.2f MiB",
     404           0 :                   m->accounts_total,
     405           0 :                   (double)m->disk_used_bytes / (double)(1UL<<20UL),
     406           0 :                   (double)m->disk_allocated_bytes / (double)(1UL<<20UL) ));
     407             : 
     408           0 :   close( fd );
     409           0 : }
     410             : 
     411             : /* ------------------------------------------------------------------ */
     412             : 
     413             : /* bench_mixed: Mixed read-write workload.  Populate a base set of
     414             :    accounts, then run a workload that is read_pct% reads and the rest
     415             :    writes, simulating transaction execution that reads many accounts
     416             :    but updates fewer. */
     417             : static void
     418             : bench_mixed( ulong   base_cnt,
     419             :              ulong   op_cnt,
     420             :              uint    read_pct,
     421           0 :              fd_rng_t * rng ) {
     422           0 :   int fd;
     423           0 :   ulong partition_sz  = 1UL<<30UL;
     424           0 :   ulong partition_cnt = 1024UL;
     425           0 :   fd_accdb_t * accdb = bench_setup( &fd,
     426           0 :                                     base_cnt + op_cnt + 1024UL,
     427           0 :                                     64UL,
     428           0 :                                     (uint)(base_cnt + op_cnt) + 1024U,
     429           0 :                                     partition_cnt,
     430           0 :                                     partition_sz );
     431             : 
     432           0 :   fd_accdb_fork_id_t root = fd_accdb_attach_child( accdb, (fd_accdb_fork_id_t){ .val = USHORT_MAX } );
     433           0 :   fd_accdb_fork_id_t fork = fd_accdb_attach_child( accdb, root );
     434             : 
     435             :   /* Populate base set */
     436           0 :   uchar pubkey[ 32 ];
     437           0 :   for( ulong i=0UL; i<base_cnt; i++ ) {
     438           0 :     make_pubkey( pubkey, i );
     439           0 :     ulong sz = sample_account_size( rng );
     440           0 :     if( sz>BENCH_MAX_DATA_SZ ) sz = BENCH_MAX_DATA_SZ;
     441           0 :     bench_write_one( accdb, fork, pubkey, i+1UL,
     442           0 :                      sz ? data_buf : NULL, sz, dummy_owner );
     443           0 :   }
     444             : 
     445           0 :   uchar  rdata[ BENCH_MAX_DATA_SZ ];
     446           0 :   ulong  lamports;
     447           0 :   ulong  data_len;
     448           0 :   uchar  owner[ 32 ];
     449           0 :   ulong  reads = 0UL;
     450           0 :   ulong  writes = 0UL;
     451             : 
     452           0 :   long dt = -fd_log_wallclock();
     453           0 :   for( ulong i=0UL; i<op_cnt; i++ ) {
     454           0 :     uint coin = fd_rng_uint( rng ) % 100U;
     455           0 :     ulong idx = fd_rng_ulong( rng ) % base_cnt;
     456           0 :     make_pubkey( pubkey, idx );
     457           0 :     if( coin < read_pct ) {
     458           0 :       bench_read_one( accdb, fork, pubkey, &lamports,
     459           0 :                       rdata, &data_len, owner );
     460           0 :       reads++;
     461           0 :     } else {
     462           0 :       ulong sz = sample_account_size( rng );
     463           0 :       if( sz>BENCH_MAX_DATA_SZ ) sz = BENCH_MAX_DATA_SZ;
     464           0 :       bench_write_one( accdb, fork, pubkey, i+1UL,
     465           0 :                        sz ? data_buf : NULL, sz, dummy_owner );
     466           0 :       writes++;
     467           0 :     }
     468           0 :   }
     469           0 :   dt += fd_log_wallclock();
     470             : 
     471           0 :   double secs = (double)dt / 1e9;
     472           0 :   FD_LOG_NOTICE(( "bench_mixed: %lu ops (%lu reads, %lu writes) in %.3f s "
     473           0 :                   "(%.0f ops/s, %.0f ns/op, read_pct=%u%%)",
     474           0 :                   op_cnt, reads, writes, secs,
     475           0 :                   (double)op_cnt / secs,
     476           0 :                   (double)dt / (double)op_cnt,
     477           0 :                   (uint)read_pct ));
     478             : 
     479           0 :   close( fd );
     480           0 : }
     481             : 
     482             : /* ------------------------------------------------------------------ */
     483             : 
     484             : int
     485             : main( int     argc,
     486             :       char ** argv ) {
     487             :   fd_boot( &argc, &argv );
     488             : 
     489             :   ulong account_cnt     = fd_env_strip_cmdline_ulong( &argc, &argv, "--accounts",        NULL, 100000UL  );
     490             :   ulong slot_cnt        = fd_env_strip_cmdline_ulong( &argc, &argv, "--slots",           NULL,    100UL  );
     491             :   ulong writes_per_slot = fd_env_strip_cmdline_ulong( &argc, &argv, "--writes-per-slot", NULL,   1200UL  );
     492             :   ulong reads_per_slot  = fd_env_strip_cmdline_ulong( &argc, &argv, "--reads-per-slot",  NULL,   4800UL  );
     493             :   ulong mixed_ops       = fd_env_strip_cmdline_ulong( &argc, &argv, "--mixed-ops",       NULL, 200000UL  );
     494             :   uint  read_pct        = fd_env_strip_cmdline_uint ( &argc, &argv, "--read-pct",        NULL,      80U  );
     495             :   uint  seed            = fd_env_strip_cmdline_uint ( &argc, &argv, "--seed",            NULL,      42U  );
     496             : 
     497             :   FD_LOG_NOTICE(( "accdb benchmark (accounts=%lu slots=%lu wpslot=%lu "
     498             :                   "rpslot=%lu mixed_ops=%lu read_pct=%u seed=%u)",
     499             :                   account_cnt, slot_cnt, writes_per_slot, reads_per_slot,
     500             :                   mixed_ops, read_pct, seed ));
     501             : 
     502             :   fd_rng_t _rng[1];
     503             :   fd_rng_t * rng = fd_rng_join( fd_rng_new( _rng, seed, 0UL ) );
     504             :   FD_TEST( rng );
     505             : 
     506             :   FD_LOG_NOTICE(( "--- write throughput ---" ));
     507             :   bench_write( account_cnt, rng );
     508             : 
     509             :   FD_LOG_NOTICE(( "--- read throughput ---" ));
     510             :   bench_read( account_cnt, rng );
     511             : 
     512             :   FD_LOG_NOTICE(( "--- replay simulation ---" ));
     513             :   bench_replay( slot_cnt, writes_per_slot, reads_per_slot, rng );
     514             : 
     515             :   FD_LOG_NOTICE(( "--- mixed read/write (%u%% reads) ---", read_pct ));
     516             :   bench_mixed( account_cnt, mixed_ops, read_pct, rng );
     517             : 
     518             :   fd_rng_delete( fd_rng_leave( rng ) );
     519             : 
     520             :   FD_LOG_NOTICE(( "pass" ));
     521             :   fd_halt();
     522             :   return 0;
     523             : }

Generated by: LCOV version 1.14