LCOV - code coverage report
Current view: top level - disco/events - fd_event_report.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 47 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 156 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_disco_events_fd_event_report_h
       2             : #define HEADER_fd_src_disco_events_fd_event_report_h
       3             : 
       4             : /* fd_event_report.h provides a thread-local, fire-and-forget path for a
       5             :    tile to report a telemetry event to the event tile, mirroring how the
       6             :    metrics thread-local (fd_metrics_tl / FD_MCNT_*) works.
       7             : 
       8             :    A tile opts in by setting fd_topo_run_tile_t.max_event_sz; the topology
       9             :    then auto-wires a dedicated unreliable link from the tile to the event
      10             :    tile (see topology construction).  At tile boot, fd_event_register()
      11             :    sets up the thread-local reporter from that link.  Generated code emits
      12             :    one fd_event_report_<name>( msg ) macro per event schema (see
      13             :    generated/fd_event_gen.h) which forwards to fd_event_report_().
      14             : 
      15             :    The link is written directly via fd_mcache_publish (outside fd_stem); it
      16             :    is unreliable, so events are dropped if the event tile falls behind.
      17             :    When a tile has no event link (telemetry off / max_event_sz==0),
      18             :    fd_event_tl is NULL and reporting is a no-op. */
      19             : 
      20             : #include "../topo/fd_topo.h"
      21             : #include "../sleep/fd_sleep.h"
      22             : #include "../../tango/mcache/fd_mcache.h"
      23             : #include "../../tango/dcache/fd_dcache.h"
      24             : 
      25             : struct fd_event_reporter {
      26             :   fd_frag_meta_t * mcache;  /* mcache of the event link (joined) */
      27             :   ulong            depth;   /* mcache depth */
      28             :   ulong            seq;     /* next sequence number to publish */
      29             :   ulong *          seq_store; /* mcache header seq */
      30             : 
      31             :   fd_wksp_t *      mem;     /* workspace containing the dcache (chunk base) */
      32             :   ulong            chunk;   /* current write chunk */
      33             :   ulong            chunk0;  /* first chunk */
      34             :   ulong            wmark;   /* wrap watermark */
      35             :   ulong            mtu;     /* link mtu (== max_event_sz) */
      36             : 
      37             :   fd_sleep_t *     sleep;
      38             :   ulong            link_id;
      39             :   fd_sleep_wake_t  wake[ FD_SLEEP_BITS_CNT ];
      40             :   ulong            wake_cnt;
      41             : };
      42             : 
      43             : typedef struct fd_event_reporter fd_event_reporter_t;
      44             : 
      45             : /* The thread-local reporter for the currently running tile, or NULL if the
      46             :    tile has no event link. */
      47             : 
      48             : extern FD_TL fd_event_reporter_t * fd_event_tl;
      49             : 
      50             : FD_PROTOTYPES_BEGIN
      51             : 
      52             : /* fd_event_register sets up fd_event_tl for the calling tile.  If the tile
      53             :    has an event link (tile->event_link_id != ULONG_MAX) it joins the link's
      54             :    mcache/dcache; otherwise fd_event_tl is left NULL and reporting is a
      55             :    no-op.  Must be called once, after the tile's tango objects are joined
      56             :    (i.e. after fd_topo_fill_tile), before the run loop. */
      57             : 
      58             : void
      59             : fd_event_register( fd_topo_t const *      topo,
      60             :                    fd_topo_tile_t const * tile );
      61             : 
      62           0 : #define FD_EVENT_SIG( type, sz ) ( ((ulong)(sz)<<8) | ((ulong)(type)&0xFFUL) )
      63           0 : #define FD_EVENT_SIG_TYPE( sig ) ( (ulong)(sig)&0xFFUL )
      64           0 : #define FD_EVENT_SIG_SZ( sig )   ( (ulong)(sig)>>8 )
      65             : 
      66             : struct fd_event_report_iov {
      67             :   void const * base;
      68             :   ulong        sz;
      69             : };
      70             : 
      71             : typedef struct fd_event_report_iov fd_event_report_iov_t;
      72             : 
      73             : /* fd_event_report_ publishes a single event of sz bytes (the serialized
      74             :    fd_event_<name>_t struct) to the event link.  type is the event schema
      75             :    id, carried with the byte size in the frag sig (see FD_EVENT_SIG) so the
      76             :    event tile can dispatch and size-validate; the frag sz field is too
      77             :    narrow for large events and is published as 0.  No-op when
      78             :    fd_event_tl is NULL.  The generated fd_event_report_<name>() helpers call
      79             :    this with the right type and size. */
      80             : 
      81             : static inline void
      82           0 : fd_event_report_ring_( fd_event_reporter_t * r ) {
      83           0 :   if( FD_LIKELY( !r->sleep ) ) return;
      84           0 :   __atomic_store_n( &r->sleep->seq_mirror[ r->link_id ], r->seq, __ATOMIC_RELEASE );
      85           0 :   fd_sleep_wake_check( r->sleep, r->wake, r->wake_cnt );
      86           0 : }
      87             : 
      88             : static inline void
      89             : fd_event_report_( ulong        type,
      90             :                   void const * event,
      91           0 :                   ulong        sz ) {
      92           0 :   fd_event_reporter_t * r = fd_event_tl;
      93           0 :   if( FD_UNLIKELY( !r ) ) return; /* no event link / telemetry off */
      94             : 
      95           0 :   FD_TEST( type<=0xFFUL );
      96           0 :   FD_TEST( sz<=r->mtu );
      97             : 
      98           0 :   ulong tspub = fd_frag_meta_ts_comp( fd_tickcount() );
      99             : 
     100           0 :   fd_memcpy( fd_chunk_to_laddr( r->mem, r->chunk ), event, sz );
     101           0 :   fd_mcache_publish( r->mcache, r->depth, r->seq, FD_EVENT_SIG( type, sz ), r->chunk, 0UL, 0UL, 0UL, tspub );
     102           0 :   r->seq   = fd_seq_inc( r->seq, 1UL );
     103           0 :   r->chunk = fd_dcache_compact_next( r->chunk, sz, r->chunk0, r->wmark );
     104           0 :   fd_mcache_seq_update( r->seq_store, r->seq );
     105           0 :   fd_event_report_ring_( r );
     106           0 : }
     107             : 
     108             : static inline void
     109             : fd_event_report_gather_( ulong                         type,
     110             :                          fd_event_report_iov_t const * iov,
     111           0 :                          ulong                         iov_cnt ) {
     112           0 :   fd_event_reporter_t * r = fd_event_tl;
     113           0 :   if( FD_UNLIKELY( !r ) ) return; /* no event link / telemetry off */
     114             : 
     115           0 :   FD_TEST( type<=0xFFUL );
     116           0 :   ulong sz = 0UL;
     117           0 :   for( ulong i=0UL; i<iov_cnt; i++ ) {
     118           0 :     FD_TEST( iov[ i ].sz<=r->mtu-sz );
     119           0 :     sz += iov[ i ].sz;
     120           0 :   }
     121             : 
     122           0 :   ulong tspub = fd_frag_meta_ts_comp( fd_tickcount() );
     123             : 
     124           0 :   uchar * dst = fd_chunk_to_laddr( r->mem, r->chunk );
     125           0 :   for( ulong i=0UL; i<iov_cnt; i++ ) {
     126           0 :     fd_memcpy( dst, iov[ i ].base, iov[ i ].sz );
     127           0 :     dst += iov[ i ].sz;
     128           0 :   }
     129           0 :   fd_mcache_publish( r->mcache, r->depth, r->seq, FD_EVENT_SIG( type, sz ), r->chunk, 0UL, 0UL, 0UL, tspub );
     130           0 :   r->seq   = fd_seq_inc( r->seq, 1UL );
     131           0 :   r->chunk = fd_dcache_compact_next( r->chunk, sz, r->chunk0, r->wmark );
     132           0 :   fd_mcache_seq_update( r->seq_store, r->seq );
     133           0 :   fd_event_report_ring_( r );
     134           0 : }
     135             : 
     136           0 : #define FD_EVENT_TYPE_METRICS_TRIGGER (255UL)
     137             : 
     138             : struct fd_event_metrics_trigger {
     139             :   uint  reason;
     140             :   ulong slot;
     141             :   ulong snapct_state;
     142             : };
     143             : 
     144             : typedef struct fd_event_metrics_trigger fd_event_metrics_trigger_t;
     145             : 
     146             : static inline void
     147             : fd_event_metrics_trigger( uint  reason,
     148             :                           ulong slot,
     149           0 :                           ulong snapct_state ) {
     150           0 :   fd_event_metrics_trigger_t t = { .reason = reason, .slot = slot, .snapct_state = snapct_state };
     151           0 :   fd_event_report_( FD_EVENT_TYPE_METRICS_TRIGGER, &t, sizeof(t) );
     152           0 : }
     153             : 
     154             : FD_PROTOTYPES_END
     155             : 
     156             : #endif /* HEADER_fd_src_disco_events_fd_event_report_h */

Generated by: LCOV version 1.14