LCOV - code coverage report
Current view: top level - app/shared_dev/commands/bench - fd_benchg.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 186 0.0 %
Date: 2026-09-17 04:28:31 Functions: 0 5 0.0 %

          Line data    Source code
       1             : #include "bench.h"
       2             : 
       3             : #include "../../../../disco/topo/fd_topo.h"
       4             : #include "../../../../flamenco/genesis/fd_genesis_create.h"
       5             : #include "../../../../flamenco/runtime/fd_system_ids_pp.h"
       6             : 
       7             : typedef struct {
       8             :   fd_rng_t rng[ 1 ];
       9             :   fd_sha512_t sha[ 1 ];
      10             : 
      11             :   ulong sender_idx;
      12             :   ulong lamport_idx;
      13             :   int   changed_blockhash;
      14             : 
      15             :   int   has_recent_blockhash;
      16             :   uchar recent_blockhash[ 32 ];
      17             :   uchar staged_blockhash[ 32 ];
      18             : 
      19             :   int   transaction_mode;
      20             :   float contending_fraction;
      21             :   float cu_price_spread;
      22             : 
      23             :   ulong acct_cnt;
      24             :   fd_pubkey_t * acct_public_keys;
      25             :   fd_pubkey_t * acct_private_keys;
      26             :   fd_pubkey_t * token_accounts;
      27             : 
      28             :   ulong benchg_cnt;
      29             :   ulong benchg_idx;
      30             : 
      31             :   fd_wksp_t * mem;
      32             :   ulong       out_chunk0;
      33             :   ulong       out_wmark;
      34             :   ulong       out_chunk;
      35             : } fd_benchg_ctx_t;
      36             : 
      37             : FD_STATIC_ASSERT( FD_GENESIS_TOKEN_ACCOUNTS_PER_ACCOUNT>=2UL, token_accounts );
      38             : 
      39             : FD_FN_CONST static inline ulong
      40           0 : scratch_align( void ) {
      41           0 :   return alignof( fd_benchg_ctx_t );
      42           0 : }
      43             : 
      44             : FD_FN_PURE static inline ulong
      45           0 : scratch_footprint( fd_topo_tile_t const * tile ) {
      46           0 :   (void)tile;
      47           0 :   ulong l = FD_LAYOUT_INIT;
      48           0 :   l = FD_LAYOUT_APPEND( l, alignof( fd_benchg_ctx_t ), sizeof( fd_benchg_ctx_t ) );
      49           0 :   l = FD_LAYOUT_APPEND( l, alignof( fd_pubkey_t ), sizeof( fd_pubkey_t ) * tile->benchg.accounts_cnt );
      50           0 :   l = FD_LAYOUT_APPEND( l, alignof( fd_pubkey_t ), sizeof( fd_pubkey_t ) * tile->benchg.accounts_cnt );
      51           0 :   l = FD_LAYOUT_APPEND( l, alignof( fd_pubkey_t ), sizeof( fd_pubkey_t ) * 2UL * tile->benchg.accounts_cnt );
      52           0 :   return FD_LAYOUT_FINI( l, scratch_align() );
      53           0 : }
      54             : 
      55             : typedef struct __attribute__((packed)) {
      56             :         uchar sig_cnt; /* = 1 */
      57             :         uchar signature[64];
      58             :         uchar _sig_cnt; /* also 1 */
      59             :         uchar ro_signed_cnt; /* ??? */
      60             :         uchar ro_unsigned_cnt; /* ??? */
      61             :         uchar acct_addr_cnt; /* = ??? */
      62             :         uchar fee_payer[32];
      63             : } single_signer_hdr_t;
      64             : 
      65             : typedef struct __attribute__((packed)) {
      66             :         uchar sig_cnt; /* = 1 */
      67             :         uchar signature[64];
      68             :         uchar _sig_cnt; /* also 1 */
      69             :         uchar ro_signed_cnt; /* = 0 */
      70             :         uchar ro_unsigned_cnt; /* = 1 . Compute Budget Program */
      71             :         uchar acct_addr_cnt; /* = 2 */
      72             :         uchar fee_payer[32];
      73             :         uchar compute_budget_program[32]; /* = {COMPUTE_BUDGET_PROG_ID} */
      74             :         uchar recent_blockhash[32];
      75             :         uchar instr_cnt; /* = 2 */
      76             :   /* Start of instruction */
      77             :   struct __attribute__((packed)) {
      78             :     uchar prog_id; /* = 1 */
      79             :     uchar acct_cnt; /* = 0 */
      80             :     uchar data_sz; /* = 9 */
      81             :     uchar set_cu_price; /* = 3 */
      82             :     ulong micro_lamports_per_cu; /* Preferably less than 10k or so */
      83             :   } _1;
      84             :   /* Start of second instruction */
      85             :   struct __attribute__((packed)) {
      86             :     uchar prog_id; /* = 1 */
      87             :     uchar acct_cnt; /* = 0 */
      88             :     uchar data_sz; /* = 5 */
      89             :     uchar set_cu_limit; /* = 2 */
      90             :     uint cus; /* = 300 */
      91             :   } _2;
      92             : } noop_t;
      93             : 
      94             : typedef struct __attribute__((packed)) {
      95             :   uchar sig_cnt; /* = 1 */
      96             :   uchar signature[64];
      97             :   uchar _sig_cnt; /* also 1 */
      98             :   uchar ro_signed_cnt; /* = 0 */
      99             :   uchar ro_unsigned_cnt; /* = 1 . System program */
     100             :   uchar acct_addr_cnt; /* = 3 */
     101             :   uchar fee_payer[32];
     102             :   uchar transfer_dest[32];
     103             :   uchar system_program[32]; /* = { 0 0 ...} */
     104             :   uchar recent_blockhash[32];
     105             :   uchar instr_cnt; /* = 1 */
     106             :   /* Start of instruction */
     107             :   struct __attribute__((packed)) {
     108             :     uchar prog_id; /* = 2 */
     109             :     uchar acct_cnt; /* = 2 */
     110             :     uchar from_acct; /* = 0 */
     111             :     uchar to_acct; /* = 1 */
     112             :     uchar data_sz; /* = 12 */
     113             :     uint  transfer; /* = 2 . SystemInstruction is bincode encoded, so the
     114             :                             discriminant is a u32, not a u8 */
     115             :     ulong lamports; /* variable */
     116             :   } _1;
     117             : } sol_transfer_t;
     118             : 
     119             : /* SOL_TRANSFER_LAMPORTS is the base amount of a system transfer.  The
     120             :    destination account does not exist yet, so the transfer has to leave
     121             :    it rent exempt (890,880 lamports for an empty account under the
     122             :    genesis rent parameters) or the transaction fails. */
     123             : 
     124           0 : #define SOL_TRANSFER_LAMPORTS (10000000UL)
     125             : 
     126             : typedef struct __attribute__((packed)) {
     127             :   uchar sig_cnt; /* = 1 */
     128             :   uchar signature[64];
     129             :   uchar _sig_cnt; /* also 1 */
     130             :   uchar ro_signed_cnt; /* = 0 */
     131             :   uchar ro_unsigned_cnt; /* = 2 . Compute Budget Program, SPL Token Program */
     132             :   uchar acct_addr_cnt; /* = 5 */
     133             :   uchar authority[32]; /* fee payer, also the token account owner */
     134             :   uchar transfer_src[32];
     135             :   uchar transfer_dest[32];
     136             :   uchar compute_budget_program[32]; /* = {COMPUTE_BUDGET_PROG_ID} */
     137             :   uchar token_program[32]; /* = {TOKEN_PROG_ID} */
     138             :   uchar recent_blockhash[32];
     139             :   uchar instr_cnt; /* = 2 */
     140             :   /* Start of instruction */
     141             :   struct __attribute__((packed)) {
     142             :     uchar prog_id; /* = 3 */
     143             :     uchar acct_cnt; /* = 0 */
     144             :     uchar data_sz; /* = 5 */
     145             :     uchar set_cu_limit; /* = 2 */
     146             :     uint  cus;
     147             :   } _1;
     148             :   /* Start of second instruction */
     149             :   struct __attribute__((packed)) {
     150             :     uchar prog_id; /* = 4 */
     151             :     uchar acct_cnt; /* = 3 */
     152             :     uchar src_acct; /* = 1 */
     153             :     uchar dest_acct; /* = 2 */
     154             :     uchar authority_acct; /* = 0 */
     155             :     uchar data_sz; /* = 9 */
     156             :     uchar transfer; /* = 3 . SPL Token Instruction::Transfer */
     157             :     ulong amount; /* variable */
     158             :   } _2;
     159             : } ptoken_transfer_t;
     160             : 
     161             : /* PTOKEN_TRANSFER_CUS bounds the compute cost of a p-token transfer.
     162             :    Without an explicit limit every transaction would be charged the
     163             :    200k CU per instruction default, which caps a block at a few hundred
     164             :    transactions and makes the benchmark measure nothing.  A transfer
     165             :    measures out at just over 200 CUs, so this leaves roughly a factor of
     166             :    two of headroom. */
     167             : 
     168           0 : #define PTOKEN_TRANSFER_CUS (500U)
     169             : 
     170             : static inline void
     171             : after_credit( fd_benchg_ctx_t *   ctx,
     172             :               fd_stem_context_t * stem,
     173             :               int *               opt_poll_in,
     174           0 :               int *               charge_busy ) {
     175           0 :   (void)opt_poll_in;
     176             : 
     177           0 :   if( FD_UNLIKELY( !ctx->has_recent_blockhash ) ) return;
     178             : 
     179           0 :   *charge_busy = 1;
     180             : 
     181           0 :   int is_contending = fd_rng_float_c( ctx->rng ) < ctx->contending_fraction;
     182           0 :   ulong sender_idx = fd_ulong_if( is_contending, 0UL, ctx->sender_idx );
     183             : 
     184           0 :   float norm = 4.0f + fd_rng_float_norm( ctx->rng );
     185           0 :   if( FD_UNLIKELY( norm<0.0f ) ) norm = 0.0f;
     186           0 :   ulong cu_price_spread = (ulong)(ctx->cu_price_spread * norm);
     187             : 
     188           0 :   void * _txn = fd_chunk_to_laddr( ctx->mem, ctx->out_chunk );
     189             : 
     190           0 :   ulong   transaction_size = 0UL;
     191           0 :   uchar * recent_blockhash = NULL;
     192             : 
     193           0 :   switch( ctx->transaction_mode ) {
     194           0 :     case BENCHG_TRANSACTION_MODE_NOOP:
     195           0 :       {
     196           0 :         noop_t * txn = (noop_t *)_txn;
     197             : 
     198           0 :         txn->sig_cnt         = 1;
     199           0 :         txn->_sig_cnt        = 1;
     200           0 :         txn->ro_signed_cnt   = 0;
     201           0 :         txn->ro_unsigned_cnt = 1;
     202           0 :         txn->acct_addr_cnt   = 2;
     203           0 :         memcpy( txn->compute_budget_program, (uchar const[32]) { COMPUTE_BUDGET_PROG_ID }, 32UL );
     204           0 :         txn->instr_cnt       = 2;
     205           0 :         txn->_1.prog_id      = 1;
     206           0 :         txn->_1.acct_cnt     = 0;
     207           0 :         txn->_1.data_sz      = 9;
     208           0 :         txn->_1.set_cu_price = 3;
     209           0 :         txn->_2.prog_id      = 1;
     210           0 :         txn->_2.acct_cnt     = 0;
     211           0 :         txn->_2.data_sz      = 5;
     212           0 :         txn->_2.set_cu_limit = 2;
     213           0 :         txn->_2.cus          = 300;
     214             : 
     215             :         /* Variable */
     216           0 :         txn->_1.micro_lamports_per_cu = ctx->lamport_idx; /* Unique per transaction so they aren't duplicates */
     217           0 :         txn->_1.micro_lamports_per_cu += fd_ulong_if( is_contending, 1000000UL, 0UL ); /* +300 lamports */
     218           0 :         txn->_1.micro_lamports_per_cu += cu_price_spread;
     219             : 
     220           0 :         transaction_size = sizeof(noop_t);
     221           0 :         recent_blockhash = txn->recent_blockhash;
     222           0 :       }
     223           0 :       break;
     224             : 
     225           0 :     case BENCHG_TRANSACTION_MODE_SOL_TRANSFER:
     226           0 :       {
     227           0 :         sol_transfer_t * txn = (sol_transfer_t *)_txn;
     228             : 
     229           0 :         txn->sig_cnt         = 1;
     230           0 :         txn->_sig_cnt        = 1;
     231           0 :         txn->ro_signed_cnt   = 0;
     232           0 :         txn->ro_unsigned_cnt = 1;
     233           0 :         txn->acct_addr_cnt   = 3;
     234           0 :         memcpy( txn->transfer_dest, ctx->acct_public_keys[ sender_idx ].uc, 32UL );
     235           0 :         for( ulong j=0UL; j<32UL; j++ ) txn->transfer_dest[ j ] ^= 0xFF;
     236           0 :         memcpy( txn->system_program, (uchar const[32]) { SYS_PROG_ID }, 32UL );
     237           0 :         txn->instr_cnt       = 1;
     238             : 
     239           0 :         txn->_1.prog_id      = 2;
     240           0 :         txn->_1.acct_cnt     = 2;
     241           0 :         txn->_1.from_acct    = 0;
     242           0 :         txn->_1.to_acct      = 1;
     243           0 :         txn->_1.data_sz      = 12;
     244           0 :         txn->_1.transfer     = 2;
     245             : 
     246           0 :         txn->_1.lamports     = SOL_TRANSFER_LAMPORTS + ctx->lamport_idx;
     247             : 
     248           0 :         transaction_size = sizeof(sol_transfer_t);
     249           0 :         recent_blockhash = txn->recent_blockhash;
     250           0 :       }
     251           0 :       break;
     252             : 
     253           0 :     case BENCHG_TRANSACTION_MODE_PTOKEN_TRANSFER:
     254           0 :       {
     255           0 :         ptoken_transfer_t * txn = (ptoken_transfer_t *)_txn;
     256             : 
     257           0 :         txn->sig_cnt         = 1;
     258           0 :         txn->_sig_cnt        = 1;
     259           0 :         txn->ro_signed_cnt   = 0;
     260           0 :         txn->ro_unsigned_cnt = 2;
     261           0 :         txn->acct_addr_cnt   = 5;
     262           0 :         memcpy( txn->transfer_src,           ctx->token_accounts[ 2UL*sender_idx      ].uc, 32UL );
     263           0 :         memcpy( txn->transfer_dest,          ctx->token_accounts[ 2UL*sender_idx+1UL  ].uc, 32UL );
     264           0 :         memcpy( txn->compute_budget_program, (uchar const[32]) { COMPUTE_BUDGET_PROG_ID }, 32UL );
     265           0 :         memcpy( txn->token_program,          (uchar const[32]) { TOKEN_PROG_ID          }, 32UL );
     266           0 :         txn->instr_cnt       = 2;
     267             : 
     268           0 :         txn->_1.prog_id        = 3;
     269           0 :         txn->_1.acct_cnt       = 0;
     270           0 :         txn->_1.data_sz        = 5;
     271           0 :         txn->_1.set_cu_limit   = 2;
     272           0 :         txn->_1.cus            = PTOKEN_TRANSFER_CUS;
     273             : 
     274           0 :         txn->_2.prog_id        = 4;
     275           0 :         txn->_2.acct_cnt       = 3;
     276           0 :         txn->_2.src_acct       = 1;
     277           0 :         txn->_2.dest_acct      = 2;
     278           0 :         txn->_2.authority_acct = 0;
     279           0 :         txn->_2.data_sz        = 9;
     280           0 :         txn->_2.transfer       = 3;
     281             : 
     282             :         /* Unique per transaction so they aren't duplicates */
     283           0 :         txn->_2.amount         = ctx->lamport_idx;
     284             : 
     285           0 :         transaction_size = sizeof(ptoken_transfer_t);
     286           0 :         recent_blockhash = txn->recent_blockhash;
     287           0 :       }
     288           0 :       break;
     289             : 
     290           0 :     default:
     291           0 :       FD_LOG_ERR(( "Unknown transaction mode %i", ctx->transaction_mode ));
     292           0 :       break;
     293           0 :   }
     294             : 
     295           0 :   single_signer_hdr_t * txnh = (single_signer_hdr_t *)_txn;
     296           0 :   fd_memcpy( txnh->fee_payer,  ctx->acct_public_keys[ sender_idx ].uc, 32UL );
     297           0 :   fd_memcpy( recent_blockhash, ctx->recent_blockhash,                  32UL );
     298             : 
     299           0 :   fd_ed25519_sign( txnh->signature,
     300           0 :                    &(txnh->_sig_cnt),
     301           0 :                    transaction_size-65UL,
     302           0 :                    ctx->acct_public_keys[ sender_idx ].uc,
     303           0 :                    ctx->acct_private_keys[ sender_idx ].uc,
     304           0 :                    ctx->sha );
     305             : 
     306           0 :   fd_stem_publish( stem, 0UL, 0UL, ctx->out_chunk, transaction_size, 0UL, 0UL, 0UL );
     307           0 :   ctx->out_chunk = fd_dcache_compact_next( ctx->out_chunk, transaction_size, ctx->out_chunk0, ctx->out_wmark );
     308             : 
     309           0 :   ctx->sender_idx = (ctx->sender_idx + 1UL) % ctx->acct_cnt;
     310           0 :   if( FD_UNLIKELY( !ctx->sender_idx ) ) {
     311           0 :     if( FD_UNLIKELY( ctx->changed_blockhash ) ) {
     312           0 :       ctx->lamport_idx = 1UL+ctx->benchg_idx;
     313           0 :       ctx->changed_blockhash = 0;
     314           0 :       fd_memcpy( ctx->recent_blockhash, ctx->staged_blockhash, 32UL );
     315           0 :     } else {
     316             :       /* Increments of the number of generators so there are never
     317             :          duplicate transactions generated. */
     318           0 :       ctx->lamport_idx += ctx->benchg_cnt;
     319           0 :     }
     320           0 :   }
     321           0 : }
     322             : 
     323             : static inline void
     324             : during_frag( fd_benchg_ctx_t * ctx,
     325             :              ulong             in_idx FD_PARAM_UNUSED,
     326             :              ulong             seq    FD_PARAM_UNUSED,
     327             :              ulong             sig    FD_PARAM_UNUSED,
     328             :              ulong             chunk,
     329             :              ulong             sz     FD_PARAM_UNUSED,
     330           0 :              ulong             ctl    FD_PARAM_UNUSED ) {
     331           0 :   if( FD_UNLIKELY( !ctx->has_recent_blockhash ) ) {
     332           0 :     fd_memcpy( ctx->recent_blockhash, fd_chunk_to_laddr( ctx->mem, chunk ), 32UL );
     333           0 :     ctx->has_recent_blockhash = 1;
     334           0 :     ctx->changed_blockhash    = 0;
     335           0 :   } else {
     336           0 :     if( FD_UNLIKELY( !memcmp( ctx->recent_blockhash, fd_chunk_to_laddr( ctx->mem, chunk ), 32UL ) ) ) return;
     337             : 
     338           0 :     fd_memcpy( ctx->staged_blockhash, fd_chunk_to_laddr( ctx->mem, chunk ), 32UL );
     339           0 :     ctx->changed_blockhash    = 1;
     340           0 :   }
     341           0 : }
     342             : 
     343             : static void
     344             : unprivileged_init( fd_topo_t const *      topo,
     345           0 :                    fd_topo_tile_t const * tile ) {
     346           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     347             : 
     348           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     349           0 :   fd_benchg_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_benchg_ctx_t ), sizeof( fd_benchg_ctx_t ) );
     350           0 :   ctx->acct_public_keys = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_pubkey_t ), sizeof( fd_pubkey_t ) * tile->benchg.accounts_cnt );
     351           0 :   ctx->acct_private_keys = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_pubkey_t ), sizeof( fd_pubkey_t ) * tile->benchg.accounts_cnt );
     352           0 :   ctx->token_accounts    = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_pubkey_t ), sizeof( fd_pubkey_t ) * 2UL * tile->benchg.accounts_cnt );
     353             : 
     354           0 :   FD_TEST( fd_rng_join( fd_rng_new( ctx->rng, (uint)tile->kind_id, 0UL ) ) );
     355           0 :   FD_TEST( fd_sha512_join( fd_sha512_new( ctx->sha ) ) );
     356             : 
     357           0 :   ctx->acct_cnt            = tile->benchg.accounts_cnt;
     358           0 :   ctx->transaction_mode    = tile->benchg.mode;
     359           0 :   ctx->contending_fraction = tile->benchg.contending_fraction;
     360           0 :   ctx->cu_price_spread     = tile->benchg.cu_price_spread;
     361             : 
     362           0 :   for( ulong i=0UL; i<ctx->acct_cnt; i++ ) {
     363           0 :     fd_memset( ctx->acct_private_keys[ i ].uc, 0, 32UL );
     364           0 :     FD_STORE( ulong, ctx->acct_private_keys[ i ].uc, i );
     365           0 :     fd_ed25519_public_from_private( ctx->acct_public_keys[ i ].uc, ctx->acct_private_keys[ i ].uc , ctx->sha );
     366           0 :   }
     367             : 
     368           0 :   if( FD_UNLIKELY( ctx->transaction_mode==BENCHG_TRANSACTION_MODE_PTOKEN_TRANSFER ) ) {
     369           0 :     for( ulong i=0UL; i<ctx->acct_cnt; i++ ) {
     370           0 :       fd_genesis_token_account_address( &ctx->token_accounts[ 2UL*i     ], i, 0UL );
     371           0 :       fd_genesis_token_account_address( &ctx->token_accounts[ 2UL*i+1UL ], i, 1UL );
     372           0 :     }
     373           0 :   }
     374             : 
     375           0 :   ctx->has_recent_blockhash = 0;
     376             : 
     377           0 :   ctx->sender_idx        = 0UL;
     378           0 :   ctx->lamport_idx       = 1UL+tile->kind_id;
     379           0 :   ctx->changed_blockhash = 0;
     380             : 
     381           0 :   ctx->benchg_cnt = fd_topo_tile_name_cnt( topo, "benchg" );
     382           0 :   ctx->benchg_idx = tile->kind_id;
     383             : 
     384           0 :   ctx->mem        = topo->workspaces[ topo->objs[ topo->links[ tile->out_link_id[ 0 ] ].dcache_obj_id ].wksp_id ].wksp;
     385           0 :   ctx->out_chunk0 = fd_dcache_compact_chunk0( ctx->mem, topo->links[ tile->out_link_id[ 0 ] ].dcache );
     386           0 :   ctx->out_wmark  = fd_dcache_compact_wmark ( ctx->mem, topo->links[ tile->out_link_id[ 0 ] ].dcache, topo->links[ tile->out_link_id[ 0 ] ].mtu );
     387           0 :   ctx->out_chunk  = ctx->out_chunk0;
     388             : 
     389           0 :   ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, 1UL );
     390           0 :   if( FD_UNLIKELY( scratch_top > (ulong)scratch + scratch_footprint( tile ) ) )
     391           0 :     FD_LOG_ERR(( "scratch overflow %lu %lu %lu", scratch_top - (ulong)scratch - scratch_footprint( tile ), scratch_top, (ulong)scratch + scratch_footprint( tile ) ));
     392           0 : }
     393             : 
     394           0 : #define STEM_BURST (1UL)
     395             : 
     396           0 : #define STEM_CALLBACK_CONTEXT_TYPE  fd_benchg_ctx_t
     397           0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_benchg_ctx_t)
     398             : 
     399           0 : #define STEM_CALLBACK_AFTER_CREDIT after_credit
     400           0 : #define STEM_CALLBACK_DURING_FRAG  during_frag
     401             : 
     402             : #include "../../../../disco/stem/fd_stem.c"
     403             : 
     404             : fd_topo_run_tile_t fd_tile_benchg = {
     405             :   .name              = "benchg",
     406             :   .scratch_align     = scratch_align,
     407             :   .scratch_footprint = scratch_footprint,
     408             :   .unprivileged_init = unprivileged_init,
     409             :   .run               = stem_run,
     410             : };

Generated by: LCOV version 1.14