LCOV - code coverage report
Current view: top level - flamenco/progcache - fd_progcache_user.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 2 23 8.7 %
Date: 2026-09-17 04:28:31 Functions: 0 0 -

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_progcache_fd_progcache_user_h
       2             : #define HEADER_fd_src_flamenco_progcache_fd_progcache_user_h
       3             : 
       4             : /* fd_progcache_user.h provides an API for managing a cache of loaded
       5             :    Solana on-chain program.
       6             : 
       7             :    ### Background
       8             : 
       9             :    Solana on-chain programs are rarely updated but frequently executed.
      10             :    Before a program can be executed, it must be loaded and verified,
      11             :    which is costly.
      12             : 
      13             :    ### Fork management
      14             : 
      15             :    The program cache is fork-aware (using transactions).  Txn-level
      16             :    operations (attach/publish/cancel) take the fork graph's exclusive
      17             :    lock; a read on the cached lineage never touches it, while switching
      18             :    fork, publishing and the eviction sweep take it shared.
      19             : 
      20             :    ### Cache entry
      21             : 
      22             :    Each Solana program can have a number of program cache entries
      23             :    (typically only zero or one, in rare cases where the program content
      24             :    differs across forks multiple).
      25             : 
      26             :    A cache entry is a progcache_rec object.  Records are partitioned by
      27             :    size class and double as value slots: an executable entry's program
      28             :    data lives in its own class's arena slot (see fd_progcache.h).
      29             : 
      30             :    ### Cache fill policy
      31             : 
      32             :    fd_progcache is lazily filled on reads.  Writes do not invalidate
      33             :    the cache; coherence comes from keying records on deploy_slot plus
      34             :    fork cancel, and from the BPF loader's pd_write gate failing an
      35             :    invoke before fd_progcache_pull if the programdata was superseded
      36             :    this slot.
      37             : 
      38             :    ### Cache evict policy
      39             : 
      40             :    Cache eviction (i.e. force removal of potentially useful records)
      41             :    happens on fill: when a fill finds its size class full, it evicts
      42             :    within that class (per-class CLOCK), and falls back to the spill
      43             :    scratch if no record frees up.  The replay tile's housekeeping runs
      44             :    the same sweep to keep a few slots free per class.
      45             : 
      46             :    ### Garbage collect policy
      47             : 
      48             :    When a database fork is cancelled (a competing history dies, or the
      49             :    consensus layer prunes a fork), its records are unmapped at once and
      50             :    their slots recovered by the next sweep.  A superseded revision stays
      51             :    mapped until CLOCK evicts it. */
      52             : 
      53             : #include "fd_progcache.h"
      54             : #include "fd_prog_load.h"
      55             : #include "fd_progcache_lineage.h"
      56             : #include "../runtime/fd_runtime_const.h"
      57             : 
      58             : struct fd_progcache_metrics {
      59             :   ulong lookup_cnt;
      60             :   ulong hit_cnt;
      61             :   ulong miss_cnt;
      62             :   ulong hit_loading_cnt;
      63             :   ulong class_full_cnt;
      64             :   ulong fill_cnt;
      65             :   ulong fill_tot_sz;
      66             :   ulong spill_cnt;
      67             :   ulong spill_tot_sz;
      68             :   ulong evict_cnt;
      69             :   ulong evict_tot_sz;
      70             :   ulong cum_pull_ticks;
      71             :   ulong load_cnt;
      72             :   ulong cum_load_ticks;
      73             :   /* Per-size-class breakdowns. */
      74             :   ulong hit_per_class  [ FD_PROGCACHE_CACHE_CLASS_CNT ];
      75             :   ulong fill_per_class [ FD_PROGCACHE_CACHE_CLASS_CNT ];
      76             :   ulong evict_per_class[ FD_PROGCACHE_CACHE_CLASS_CNT ];
      77             :   ulong spill_per_class[ FD_PROGCACHE_CACHE_CLASS_CNT ];
      78             : };
      79             : 
      80             : 
      81             : /* fd_progcache_t is a thread-local client to a program cache instance.
      82             :    This struct is quite large and therefore not local/stack
      83             :    declaration-friendly. */
      84             : 
      85             : struct fd_progcache {
      86             :   fd_progcache_join_t join[1];
      87             :   fd_progcache_lineage_t lineage[1];
      88             : 
      89             :   fd_progcache_metrics_t * metrics;
      90             : 
      91             :   uchar * scratch;
      92             :   ulong   scratch_sz;
      93             : 
      94             :   uint spill_active;
      95             : };
      96             : 
      97             : /* Writes every progcache counter for a tile. */
      98             : 
      99           0 : #define FD_PROGCACHE_METRICS_WRITE( TILE, m ) do {                                        \
     100           0 :     fd_progcache_metrics_t const * _m = (m);                                              \
     101           0 :     FD_MCNT_SET( TILE, PROGCACHE_LOOKUP,                _m->lookup_cnt     );             \
     102           0 :     FD_MCNT_SET( TILE, PROGCACHE_HIT,                   _m->hit_cnt        );             \
     103           0 :     FD_MCNT_SET( TILE, PROGCACHE_MISS,                  _m->miss_cnt       );             \
     104           0 :     FD_MCNT_SET( TILE, PROGCACHE_HIT_LOADING,           _m->hit_loading_cnt );            \
     105           0 :     FD_MCNT_SET( TILE, PROGCACHE_CLASS_FULL,            _m->class_full_cnt );             \
     106           0 :     FD_MCNT_SET( TILE, PROGCACHE_FILL,                  _m->fill_cnt       );             \
     107           0 :     FD_MCNT_SET( TILE, PROGCACHE_FILL_BYTES,            _m->fill_tot_sz    );             \
     108           0 :     FD_MCNT_SET( TILE, PROGCACHE_SPILL,                 _m->spill_cnt      );             \
     109           0 :     FD_MCNT_SET( TILE, PROGCACHE_SPILL_BYTES,           _m->spill_tot_sz   );             \
     110           0 :     FD_MCNT_SET( TILE, PROGCACHE_EVICTION,              _m->evict_cnt      );             \
     111           0 :     FD_MCNT_SET( TILE, PROGCACHE_EVICTION_BYTES,        _m->evict_tot_sz   );             \
     112           0 :     FD_MCNT_SET( TILE, PROGCACHE_DURATION_SECONDS,      _m->cum_pull_ticks );             \
     113           0 :     FD_MCNT_SET( TILE, PROGCACHE_LOAD,                  _m->load_cnt       );             \
     114           0 :     FD_MCNT_SET( TILE, PROGCACHE_LOAD_DURATION_SECONDS, _m->cum_load_ticks );             \
     115           0 :     FD_MCNT_ENUM_COPY( TILE, PROGCACHE_CLASS_HIT,      _m->hit_per_class   );             \
     116           0 :     FD_MCNT_ENUM_COPY( TILE, PROGCACHE_CLASS_FILL,     _m->fill_per_class  );             \
     117           0 :     FD_MCNT_ENUM_COPY( TILE, PROGCACHE_CLASS_EVICTION, _m->evict_per_class );             \
     118           0 :     FD_MCNT_ENUM_COPY( TILE, PROGCACHE_CLASS_SPILL,    _m->spill_per_class );             \
     119           0 :   } while(0)
     120             : 
     121             : FD_PROTOTYPES_BEGIN
     122             : 
     123             : extern FD_TL fd_progcache_metrics_t fd_progcache_metrics_default;
     124             : 
     125             : /* Constructor */
     126             : 
     127             : /* fd_progcache_join joins the caller to a program cache shmem instance.
     128             :    scratch points to a FD_PROGCACHE_SCRATCH_ALIGN aligned scratch buffer
     129             :    and scratch_sz is the size of the largest program/ELF binary that is
     130             :    going to be loaded (typically max account data sz). */
     131             : 
     132             : fd_progcache_t *
     133             : fd_progcache_join( fd_progcache_t *       ljoin,
     134             :                    fd_progcache_shmem_t * shmem,
     135             :                    uchar *                scratch,
     136             :                    ulong                  scratch_sz );
     137             : 
     138          60 : #define FD_PROGCACHE_SCRATCH_ALIGN     (64UL)
     139          60 : #define FD_PROGCACHE_SCRATCH_FOOTPRINT FD_RUNTIME_ACC_SZ_MAX
     140             : 
     141             : /* fd_progcache_leave detaches the caller from a program cache. */
     142             : 
     143             : void *
     144             : fd_progcache_leave( fd_progcache_t *        cache,
     145             :                     fd_progcache_shmem_t ** opt_shmem );
     146             : 
     147             : /* fd_progcache_pull loads a program from cache, filling the cache if
     148             :    necessary.  The load operation can have a number of outcomes:
     149             :    - Returns a pointer to an existing cache entry (cache hit, state
     150             :      either "Loaded" or "FailedVerification")
     151             :    - Returns a pointer to a newly created cache entry (cache fill,
     152             :      state either "Loaded" or "FailedVerification")
     153             :    - Returns NULL if fd_prog_info rejects the account (not a deployed
     154             :      program of a known loader)
     155             :    In other words, this method guarantees to return a cache entry if a
     156             :    deployed program was found in the account database, and the program
     157             :    either loaded successfully, or failed ELF/bytecode verification.
     158             :    It is the caller's responsibility to release the returned record with
     159             :    fd_progcache_rec_close. */
     160             : 
     161             : fd_progcache_rec_t * /* read locked */
     162             : fd_progcache_pull( fd_progcache_t *           cache,
     163             :                    fd_progcache_fork_id_t     fork_id,
     164             :                    fd_pubkey_t const *        prog_addr,
     165             :                    fd_prog_load_env_t const * env,
     166             :                    fd_acc_t const *           progdata_ro );
     167             : 
     168             : /* fd_progcache_rec_close releases a cache record handle returned by
     169             :    fd_progcache_pull. */
     170             : 
     171             : void
     172             : fd_progcache_rec_close( fd_progcache_t *     cache,
     173             :                         fd_progcache_rec_t * rec );
     174             : 
     175             : FD_PROTOTYPES_END
     176             : 
     177             : #endif /* HEADER_fd_src_flamenco_progcache_fd_progcache_user_h */

Generated by: LCOV version 1.14