LCOV - code coverage report
Current view: top level - flamenco/progcache - fd_progcache.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 17 26 65.4 %
Date: 2026-09-17 04:28:31 Functions: 8 216 3.7 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_progcache_fd_progcache_h
       2             : #define HEADER_fd_src_flamenco_progcache_fd_progcache_h
       3             : 
       4             : /* fd_progcache.h provides program cache data structures.
       5             : 
       6             :    Records and value slots are one and the same: the record array is
       7             :    partitioned by size class (rec_base[c] .. rec_base[c]+class_max[c]), and a
       8             :    record's value storage is the arena slot at its own index.  Acquiring a
       9             :    record from a class's free list is acquiring its value slot.
      10             : 
      11             :    Lock ordering: spill.lock (outermost, held across a spilled frame's
      12             :    execution), global txn lock, txn lock, recm chain_lock, rec.lock.  An
      13             :    in-flight record's read lock is outside the ordering.  None of these locks
      14             :    prefer writers, so a writer can in principle be starved by readers. */
      15             : 
      16             : #include "fd_progcache_rec.h" /* includes fd_progcache_base.h */
      17             : #include "fd_progcache_cache.h"
      18             : #include "fd_progcache_xid.h"
      19             : #include "../fd_rwlock.h"
      20             : #include "../runtime/fd_runtime_const.h"
      21             : 
      22             : /* Eviction may claim records still attached to a live fork (unlinked under the
      23             :    fork lock); 0 restricts it to rooted records. */
      24             : 
      25             : #ifndef FD_PROGCACHE_EVICT_UNROOTED
      26             : #define FD_PROGCACHE_EVICT_UNROOTED 1
      27             : #endif
      28             : 
      29             : /* fd_progcache_shmem_t is the top-level shared memory data structure
      30             :    of the progcache. */
      31             : 
      32         204 : #define FD_PROGCACHE_SHMEM_MAGIC (0xf17eda2ce7fc2c03UL)
      33             : 
      34             : /* spill.lock serializes spilling, so the spad holds at most one CPI stack:
      35             :    FD_MAX_INSTRUCTION_STACK_DEPTH frames of FD_PROGCACHE_CACHE_SLOT_TOP_SZ. */
      36             : 
      37             : #define FD_PROGCACHE_SPAD_MAX (FD_MAX_INSTRUCTION_STACK_DEPTH * FD_PROGCACHE_CACHE_SLOT_TOP_SZ)
      38             : 
      39             : struct fd_progcache_shmem {
      40             : 
      41             :   ulong magic;
      42             :   ulong wksp_tag;
      43             :   ulong seed;
      44             : 
      45             :   struct {
      46             :     uint  max;        /* == sum of class_max */
      47             :     ulong map_gaddr;
      48             :     ulong ele_gaddr;
      49             :   } rec;
      50             : 
      51             :   struct __attribute__((aligned(64))) {
      52             :     fd_rwlock_t rwlock;
      53             :     ulong       max;
      54             :     ulong       map_gaddr;
      55             :     ulong       pool_gaddr;
      56             :     ulong       ele_gaddr;
      57             :     uint        child_head_idx;
      58             :     uint        child_tail_idx;
      59             :     fd_progcache_fork_id_t root;
      60             :     fd_progcache_fork_id_t seq;
      61             :   } txn;
      62             : 
      63             :   struct {
      64             :     fd_rwlock_t        lock;
      65             :     fd_progcache_rec_t rec[ FD_MAX_INSTRUCTION_STACK_DEPTH ];
      66             :     uint               rec_used;
      67             :     uint               spad_used;
      68             :     uint               spad_off[ FD_MAX_INSTRUCTION_STACK_DEPTH ];
      69             :     uchar              spad[ FD_PROGCACHE_SPAD_MAX ] __attribute__((aligned(64UL)));
      70             :   } spill;
      71             : 
      72             :   /* Size-class cache.  The record array is partitioned by class: class c
      73             :      owns records [rec_base[c], rec_base[c]+class_max[c]), and record idx's value
      74             :      storage is the fixed-size arena slot at (idx - rec_base[c]).  A value is
      75             :      stored in the smallest class whose slot holds it */
      76             :   struct {
      77             :     ulong       class_max  [ FD_PROGCACHE_CACHE_CLASS_CNT ]; /* records per class */
      78             :     ulong       rec_base   [ FD_PROGCACHE_CACHE_CLASS_CNT ]; /* first rec idx of class c */
      79             :     ulong       arena_gaddr[ FD_PROGCACHE_CACHE_CLASS_CNT ]; /* value arena base */
      80             : 
      81             :     /* Per-class free list of records */
      82             :     struct __attribute__((aligned(64))) { ulong ver_top; } free_top[ FD_PROGCACHE_CACHE_CLASS_CNT ];
      83             : 
      84             :     /* Per-class approximate depth of the free list */
      85             :     struct __attribute__((aligned(64))) { ulong val; } free_cnt[ FD_PROGCACHE_CACHE_CLASS_CNT ];
      86             : 
      87             :     /* Per-class CLOCK position */
      88             :     struct __attribute__((aligned(64))) { ulong val; } clock_hand[ FD_PROGCACHE_CACHE_CLASS_CNT ];
      89             : 
      90             :     /* Round-robin cursor for fd_progcache_housekeeping */
      91             :     struct __attribute__((aligned(64))) { ulong val; } housekeep_hand;
      92             :   } cache;
      93             : 
      94             : };
      95             : 
      96             : FD_STATIC_ASSERT( FD_PROGCACHE_SPAD_MAX<=UINT_MAX, "layout" );
      97             : 
      98             : /* Declare a separately-chained concurrent hash map for cache entries */
      99             : 
     100             : #define MAP_NAME              fd_prog_recm
     101        1020 : #define MAP_ELE_T             fd_progcache_rec_t
     102             : #define MAP_KEY_T             fd_progcache_rec_key_t
     103             : #define MAP_KEY               pair
     104     2661849 : #define MAP_KEY_EQ(k0,k1)     fd_progcache_rec_key_eq((k0),(k1))
     105     5497130 : #define MAP_KEY_HASH(k0,seed) fd_progcache_rec_key_hash( &(k0)->prog, (seed) )
     106             : #define MAP_IDX_T             uint
     107        1020 : #define MAP_NEXT              map_next
     108             : #define MAP_MAGIC             (0xf173da2ce77ecdb8UL)
     109             : #define MAP_IMPL_STYLE        1
     110             : #include "../../util/tmpl/fd_map_chain_para.c"
     111             : 
     112             : /* fd_progcache_class_free_cnt returns the number of free records in class c (its
     113             :    free-list depth).  Approximate: a separate atomic from the list head, so it can
     114             :    momentarily disagree with it.  It feeds occupancy gauges. */
     115             : static inline ulong
     116             : fd_progcache_class_free_cnt( fd_progcache_shmem_t * pc,
     117         159 :                              ulong                  c ) {
     118         159 :   return __atomic_load_n( &pc->cache.free_cnt[ c ].val, __ATOMIC_RELAXED );
     119         159 : }
     120             : 
     121             : /* fd_progcache_rec_class returns the size class owning record rec_idx
     122             :    (record ranges are contiguous and ascending by class). */
     123             : 
     124             : static inline ulong
     125             : fd_progcache_rec_class( fd_progcache_shmem_t const * pc,
     126        2052 :                         ulong                        rec_idx ) {
     127        2052 :   ulong c = 0UL;
     128        2052 :   while( c+1UL<FD_PROGCACHE_CACHE_CLASS_CNT && rec_idx >= pc->cache.rec_base[ c+1UL ] ) c++;
     129        2052 :   return c;
     130        2052 : }
     131             : 
     132             : /* Declare a tree / hash map hybrid of fork graph nodes (externally
     133             :    synchronized) */
     134             : 
     135             : struct __attribute__((aligned(64))) fd_progcache_txn {
     136             :   fd_progcache_fork_id_t xid;
     137             :   uint                   map_next;
     138             :   fd_rwlock_t            lock;
     139             :   ushort                 tag : 2;
     140             : 
     141             :   uint   parent_idx;
     142             :   uint   child_head_idx;
     143             :   uint   child_tail_idx;
     144             :   uint   sibling_prev_idx;
     145             :   uint   sibling_next_idx;
     146             : 
     147             :   uint   rec_head_idx;
     148             :   uint   rec_tail_idx;
     149             : };
     150             : 
     151             : #define POOL_NAME       fd_prog_txnp
     152             : #define POOL_T          fd_progcache_txn_t
     153             : #define POOL_IDX_T      uint
     154        9093 : #define POOL_NEXT       map_next
     155             : #define POOL_IMPL_STYLE 1
     156             : #include "../../util/tmpl/fd_pool.c"
     157             : 
     158             : #define  MAP_NAME              fd_prog_txnm
     159             : #define  MAP_ELE_T             fd_progcache_txn_t
     160             : #define  MAP_KEY               xid
     161             : #define  MAP_IDX_T             uint
     162             : #define  MAP_NEXT              map_next
     163             : #define  MAP_MAGIC             (0xf173da2ce77ecdb9UL)
     164             : #define  MAP_IMPL_STYLE        1
     165             : #include "../../util/tmpl/fd_map_chain.c"
     166             : 
     167             : /* Declare fd_progcache_join_t now that we have all dependencies */
     168             : 
     169             : struct fd_progcache_join {
     170             : 
     171             :   fd_progcache_shmem_t * shmem;
     172             : 
     173             :   struct {
     174             :     fd_prog_recm_t       map[1];
     175             :     fd_progcache_rec_t * ele;   /* record array (partitioned by size class) */
     176             :     ulong                max;
     177             :   } rec;
     178             : 
     179             :   struct {
     180             :     fd_prog_txnm_t *     map;
     181             :     fd_progcache_txn_t * pool;
     182             :   } txn;
     183             : 
     184             :   void * data_base;
     185             : 
     186             : };
     187             : 
     188             : /* Snapshots per-class occupancy for metrics.  Both arrays are
     189             :    FD_PROGCACHE_CACHE_CLASS_CNT long. */
     190             : static inline void
     191             : fd_progcache_cache_class_occupancy( fd_progcache_join_t * join,
     192             :                                     ulong *               used,
     193           0 :                                     ulong *               max ) {
     194           0 :   fd_progcache_shmem_t * pc = join->shmem;
     195           0 :   for( ulong c=0UL; c<FD_PROGCACHE_CACHE_CLASS_CNT; c++ ) {
     196           0 :     ulong n = pc->cache.class_max[ c ];
     197             :     /* free_cnt is maintained separately from the free-list head, so a
     198             :        concurrent pop can transiently overshoot it; clamp before deriving. */
     199           0 :     ulong free_cnt = fd_progcache_class_free_cnt( pc, c );
     200           0 :     max [ c ] = n;
     201           0 :     used[ c ] = n - fd_ulong_min( free_cnt, n );
     202           0 :   }
     203           0 : }
     204             : 
     205             : FD_PROTOTYPES_BEGIN
     206             : 
     207             : FD_FN_CONST ulong
     208             : fd_progcache_shmem_align( void );
     209             : 
     210             : /* fd_progcache_shmem_min_sz returns the smallest progcache_sz that provisions
     211             :    txn_max, rounded up to the next MiB boundary: every class at
     212             :    fd_progcache_cache_class_min. */
     213             : 
     214             : ulong
     215             : fd_progcache_shmem_min_sz( ulong txn_max );
     216             : 
     217             : /* fd_progcache_shmem_{footprint,new} size and construct a program cache.
     218             :    txn_max bounds concurrent fork-graph nodes and progcache_sz is the shared memory
     219             :    budget, which covers everything: this shmem, the fork graph, the record array
     220             :    and the per-class value arenas.  footprint returns progcache_sz, or 0 if that
     221             :    budget is below fd_progcache_shmem_min_sz.
     222             :    shmem_new derives the split internally, provisioning every byte it can into
     223             :    value slots, and allocates nothing beyond the region it is given. */
     224             : 
     225             : ulong
     226             : fd_progcache_shmem_footprint( ulong txn_max,
     227             :                               ulong progcache_sz );
     228             : 
     229             : fd_progcache_shmem_t *
     230             : fd_progcache_shmem_new( void * shmem,
     231             :                         ulong  wksp_tag,
     232             :                         ulong  seed,
     233             :                         ulong  txn_max,
     234             :                         ulong  progcache_sz );
     235             : 
     236             : fd_progcache_join_t *
     237             : fd_progcache_shmem_join( fd_progcache_join_t *  ljoin,
     238             :                          fd_progcache_shmem_t * shmem );
     239             : 
     240             : void *
     241             : fd_progcache_shmem_leave( fd_progcache_join_t *   ljoin,
     242             :                           fd_progcache_shmem_t ** opt_shmem );
     243             : 
     244             : void *
     245             : fd_progcache_shmem_delete( fd_progcache_shmem_t * shmem );
     246             : 
     247             : void *
     248             : fd_progcache_shmem_delete_fast( fd_progcache_shmem_t * shmem );
     249             : 
     250             : FD_FN_CONST static inline fd_progcache_fork_id_t
     251       12603 : fd_progcache_fork_id_initial( void ) {
     252       12603 :   return 0UL;
     253       12603 : }
     254             : 
     255             : FD_PROTOTYPES_END
     256             : 
     257             : #endif /* HEADER_fd_src_flamenco_progcache_fd_progcache_h */

Generated by: LCOV version 1.14