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 : }
|