LCOV - code coverage report
Current view: top level - flamenco/progcache - fd_progcache_clock.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 24 24 100.0 %
Date: 2026-04-06 06:22:41 Functions: 20 273 7.3 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_progcache_fd_progcache_clock_h
       2             : #define HEADER_fd_src_flamenco_progcache_fd_progcache_clock_h
       3             : 
       4             : /* fd_progcache_clock.h provides the cache eviction policy for the
       5             :    program cache (CLOCK).
       6             : 
       7             :    CLOCK is a cache replacement algorithm:
       8             :    Entries get evicted when the cache is full.
       9             : 
      10             :    There are two "cache is full" conditions:
      11             :    - No more progcache_rec descriptors available
      12             :    - Insufficient heap space to allocate a val
      13             : 
      14             :    The CLOCK algorithm works as follows:
      15             :    - There exists a "visited" bit for each progcache_rec
      16             :    - Whenever a user accesses a record, the visited bit is set
      17             :    - When cache replacement kicks in, the bit set is scanned
      18             :      (low-to-high cyclic).  For each record:
      19             :      - If the "visited" bit is set, unset it
      20             :      - Else ("visited" bit unset), evict the record
      21             : 
      22             :    Some implementation details:
      23             :    - The "visited" bits are stored in a dense bit array ("cbits")
      24             :      (Optimize for fast scans)
      25             :    - This bit array shadows the progcache_rec pool (including free
      26             :      entries)
      27             :    - An additional "exists" bit is interleaved with the "visited" bit,
      28             :      to disambiguate an existing idle entry from a free entry */
      29             : 
      30             : #include "fd_progcache_base.h"
      31             : #include <stdatomic.h>
      32             : 
      33             : FD_PROTOTYPES_BEGIN
      34             : 
      35             : /* Helper APIs for the CLOCK bit array */
      36             : 
      37             : /* fd_prog_cbits_slot returns the 64-bit slot that contains the bit pair
      38             :    for the record with pool index rec_idx. */
      39             : 
      40             : FD_FN_CONST static inline atomic_ulong *
      41             : fd_prog_cbits_slot( atomic_ulong * bits,
      42         489 :                     ulong          rec_idx ) {
      43         489 :   return &bits[ rec_idx>>5 ];
      44         489 : }
      45             : 
      46             : /* fd_prog_{visited,exists}_bit return the bit index of the {visited,
      47             :    exists} flag for a record within its slot (see fd_prog_cbits_slot).
      48             : 
      49             :    Full example:
      50             : 
      51             :      slot_p = fd_prog_cbits_slot( bits, idx )
      52             :      slot = atomic_load_explicit( slot, memory_order_relaxed )
      53             :      rec_exists = fd_ulong_extract_bit( slot, fd_prog_visited_bit( idx ) ) */
      54             : 
      55             : FD_FN_CONST static inline int
      56         834 : fd_prog_visited_bit( ulong rec_idx ) {
      57         834 :   return 2*(rec_idx & 31UL);
      58         834 : }
      59             : 
      60             : FD_FN_CONST static inline int
      61         336 : fd_prog_exists_bit( ulong rec_idx ) {
      62         336 :   return fd_prog_visited_bit( rec_idx )+1;
      63         336 : }
      64             : 
      65             : /* fd_prog_cbits_{align,footprint} return the alignment/size requirement
      66             :    for the cbits array. */
      67             : 
      68             : static inline ulong
      69        1878 : fd_prog_cbits_align( void ) {
      70        1878 :   return 64UL;
      71        1878 : }
      72             : 
      73             : static inline ulong
      74         489 : fd_prog_cbits_footprint( ulong rec_max ) {
      75         489 :   return fd_ulong_align_up( rec_max*2, 512UL ) / 8UL;
      76         489 : }
      77             : 
      78             : /* fd_prog_clock_init initializes CLOCK cache replacement algo state. */
      79             : 
      80             : void
      81             : fd_prog_clock_init( atomic_ulong * cbits,
      82             :                     ulong          rec_max );
      83             : 
      84             : /* fd_prog_clock_touch marks the record at the given index as recently
      85             :    touched which makes it less likely to get evicted. */
      86             : 
      87             : static inline void
      88             : fd_prog_clock_touch( atomic_ulong * cbits,
      89          90 :                      ulong          rec_idx ) {
      90          90 :   atomic_ulong * slot_p = fd_prog_cbits_slot( cbits, rec_idx );
      91             :   /* Set the "exists" and "visited" bits */
      92          90 :   ulong mask = 3UL<<(fd_prog_visited_bit( rec_idx ));
      93          90 :   atomic_fetch_or_explicit( slot_p, mask, memory_order_relaxed );
      94          90 : }
      95             : 
      96             : /* fd_prog_clock_remove indicates that the record at the given index is
      97             :    about to be deleted.  Should be run before a deletion, not after. */
      98             : 
      99             : static inline void
     100             : fd_prog_clock_remove( atomic_ulong * cbits,
     101          54 :                       ulong          rec_idx ) {
     102          54 :   atomic_ulong * slot_p = fd_prog_cbits_slot( cbits, rec_idx );
     103             :   /* Clear the "exists" and "visited" bits */
     104          54 :   ulong mask = ~( (3UL<<fd_prog_visited_bit( rec_idx )) );
     105             :   atomic_fetch_and_explicit( slot_p, mask, memory_order_relaxed );
     106          54 : }
     107             : 
     108             : /* fd_prog_clock_evict evicts records until at least rec_min records
     109             :    and heap_min bytes of heap space are queued for reclamation. */
     110             : 
     111             : void
     112             : fd_prog_clock_evict( fd_progcache_t * progcache,
     113             :                      ulong            rec_min,
     114             :                      ulong            heap_min );
     115             : 
     116             : FD_PROTOTYPES_END
     117             : 
     118             : #endif /* HEADER_fd_src_flamenco_progcache_fd_progcache_clock_h */

Generated by: LCOV version 1.14