LCOV - code coverage report
Current view: top level - disco/sleep - fd_sleep.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 15 15 100.0 %
Date: 2026-09-17 04:28:31 Functions: 2 6 33.3 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_disco_sleep_fd_sleep_h
       2             : #define HEADER_fd_src_disco_sleep_fd_sleep_h
       3             : 
       4             : /* Idle tiles park in futex_wait instead of spinning and are woken
       5             :    when work arrives.  Three roles share one shmem region:
       6             : 
       7             :      sleeper   a stem tile with no work: flushes its link state, sets
       8             :                its bit in parked_bits, re-checks its ins once under the
       9             :                RMW fence, then FUTEX_WAIT_BITSETs on its word with an
      10             :                absolute deadline.
      11             : 
      12             :      producer  on publish: load parked_bits[w] & a mask precomputed at
      13             :                boot; if nonzero, locked OR into doorbell[w].
      14             : 
      15             :      mwaitx    naps in hardware on the doorbell line (umwait/mwaitx),
      16             :                turns rung bits into FUTEX_WAKEs, and runs the verifying
      17             :                sweep (seq_mirror vs seq_snap) that bounds a lost
      18             :                doorbell to one nap.  The only FUTEX_WAKE issuer.
      19             : 
      20             :    word 0 = parked, nonzero = running.  The doorbell is a hint: truth
      21             :    is level triggered (seqs, deadline) and re-checked on every wake,
      22             :    so spurious wakes are absorbed and a lost hint costs only bounded
      23             :    latency (the sweep, then the tile's own deadline). */
      24             : 
      25             : #include "../../util/fd_util_base.h"
      26             : 
      27          15 : #define FD_SLEEP_ALIGN     (128UL)
      28           3 : #define FD_SLEEP_MAGIC     (0xf17eda2c3751ee90UL) /* firedancer sleep ver 0 */
      29             : 
      30        3159 : #define FD_SLEEP_TILE_MAX  (512UL)
      31          81 : #define FD_SLEEP_BITS_CNT  (FD_SLEEP_TILE_MAX/64UL)
      32             : #define FD_SLEEP_LINK_MAX  (256UL) /* ==FD_TOPO_MAX_LINKS  */
      33             : #define FD_SLEEP_IN_MAX    (128UL) /* ==FD_TOPO_MAX_TILE_IN_LINKS */
      34             : 
      35             : #define FD_SLEEP_LINGER_NS   (0L)        /* park as soon as caught up */
      36             : #define FD_SLEEP_PARK_CAP_NS (20000000L) /* longest park */
      37             : #define FD_SLEEP_PARK_MIN_NS (5000L)     /* shorter than this and the futex round trip costs more than the spin */
      38             : 
      39             : struct __attribute__((aligned(FD_SLEEP_ALIGN))) fd_sleep_private {
      40             :   /* Loaded on every publish, written only at park/unpark */
      41             :   ulong parked_bits[ FD_SLEEP_BITS_CNT ];
      42             :   ulong  magic;       /* ==FD_SLEEP_MAGIC, off the parked_bits line */
      43             :   double tick_per_ns; /* fd_tickcount ticks per ns, for futex deadlines */
      44             :   ulong  pad0[ 6 ];
      45             : 
      46             :   /* Locked OR on wake edges; the line mwaitx monitors.  Own line. */
      47             :   ulong doorbell[ FD_SLEEP_BITS_CNT ];
      48             :   ulong pad1[ 8 ];
      49             : 
      50             :   /* Indexed by tile->id; written by the owner and mwaitx only */
      51             :   struct __attribute__((aligned(64UL))) {
      52             :     ulong word;      /* futex word: 0 parked, 1 running */
      53             :     ulong gen;       /* park count, diagnostics */
      54             :     ulong deadline;  /* abs fd_tickcount of the next timed obligation */
      55             :     ulong pad[ 5 ];
      56             :   } tile[ FD_SLEEP_TILE_MAX ];
      57             : 
      58             :   /* Sweep state: producers mirror out seqs at housekeeping, a parking
      59             :      tile snapshots the next seq it expects per polled in.
      60             :      mirror[link]>snap means a frag is pending. */
      61             :   ulong seq_mirror[ FD_SLEEP_LINK_MAX ];
      62             :   ulong seq_snap[ FD_SLEEP_TILE_MAX ][ FD_SLEEP_IN_MAX ];
      63             : };
      64             : 
      65             : typedef struct fd_sleep_private fd_sleep_t;
      66             : 
      67             : /* Wake table entry: the consumers of one out link as a (bitmap word,
      68             :    mask) pair.  One pair per link in practice. */
      69             : 
      70             : struct fd_sleep_wake {
      71             :   ulong w;
      72             :   ulong mask;
      73             : };
      74             : 
      75             : typedef struct fd_sleep_wake fd_sleep_wake_t;
      76             : 
      77             : struct fd_topo;
      78             : 
      79             : FD_PROTOTYPES_BEGIN
      80             : 
      81             : FD_FN_CONST ulong fd_sleep_align    ( void );
      82             : FD_FN_CONST ulong fd_sleep_footprint( void );
      83             : 
      84             : /* fd_sleep_new formats shmem (fd_sleep_align aligned, fd_sleep_footprint
      85             :    bytes) as a sleep region with every tile running.  tick_per_ns is
      86             :    the fd_tickcount rate used to turn park deadlines into futex
      87             :    timeouts.  Returns shmem on success, NULL on failure (logs
      88             :    details). */
      89             : 
      90             : void * fd_sleep_new( void * shmem,
      91             :                      double tick_per_ns );
      92             : 
      93             : fd_sleep_t * fd_sleep_join( void * shsleep );
      94             : 
      95             : /* fd_sleep_wake_table fills wake (FD_SLEEP_BITS_CNT entries) with the
      96             :    (word,mask) pairs covering every tile that polls link_id, and
      97             :    returns the pair count (0 if none, or in performance mode).  A
      98             :    consumer that never parks never has its bit set, so rings to it are
      99             :    free. */
     100             : 
     101             : ulong
     102             : fd_sleep_wake_table( fd_sleep_wake_t *       wake,
     103             :                      struct fd_topo const *  topo,
     104             :                      ulong                   link_id );
     105             : 
     106             : /* fd_sleep_ring marks tile_id as having work.  Safe from any thread;
     107             :    ringing a running tile is harmless. */
     108             : 
     109             : static inline void
     110             : fd_sleep_ring( fd_sleep_t * sleep,
     111      300000 :                ulong        tile_id ) {
     112      300000 :   __atomic_fetch_or( &sleep->doorbell[ tile_id>>6 ], 1UL<<(tile_id&63UL), __ATOMIC_RELEASE );
     113      300000 : }
     114             : 
     115             : /* fd_sleep_wake_check rings the parked consumers of one out link.
     116             :    One load per pair; the locked OR only on a hit. */
     117             : 
     118             : static inline void
     119             : fd_sleep_wake_check( fd_sleep_t *      sleep,
     120             :                      fd_sleep_wake_t const * wake,
     121           6 :                      ulong                   wake_cnt ) {
     122          18 :   for( ulong k=0UL; k<wake_cnt; k++ ) {
     123          12 :     ulong rung = FD_VOLATILE_CONST( sleep->parked_bits[ wake[ k ].w ] ) & wake[ k ].mask;
     124          12 :     if( FD_UNLIKELY( rung ) ) __atomic_fetch_or( &sleep->doorbell[ wake[ k ].w ], rung, __ATOMIC_RELEASE );
     125          12 :   }
     126           6 : }
     127             : 
     128             : /* Unpark causes, in ParkWake metrics enum order */
     129             : 
     130      300003 : #define FD_SLEEP_UNPARK_RING     (0)
     131          33 : #define FD_SLEEP_UNPARK_DEADLINE (1)
     132             : #define FD_SLEEP_UNPARK_PENDING  (2)
     133             : 
     134             : /* fd_sleep_park_wait blocks on word (caller set it to 0) until woken
     135             :    or deadline_ticks (abs fd_tickcount) passes.  Returns the cause.
     136             :    fd_sleep_wake_one sets word to 1 and wakes one waiter; called by
     137             :    the mwaitx tile only. */
     138             : 
     139             : int  fd_sleep_park_wait( fd_sleep_t const * sleep,
     140             :                          ulong *            word,
     141             :                          long               deadline_ticks );
     142             : 
     143             : void fd_sleep_wake_one( ulong * word );
     144             : 
     145             : FD_PROTOTYPES_END
     146             : 
     147             : #endif /* HEADER_fd_src_disco_sleep_fd_sleep_h */

Generated by: LCOV version 1.14