LCOV - code coverage report
Current view: top level - disco/quic - fd_tpu_reasm.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 158 224 70.5 %
Date: 2026-07-15 05:23:55 Functions: 11 12 91.7 %

          Line data    Source code
       1             : #include "fd_tpu.h"
       2             : #include "fd_tpu_reasm_private.h"
       3             : #include "../../tango/dcache/fd_dcache.h"
       4             : #include "../../tango/mcache/fd_mcache.h"
       5             : 
       6             : FD_FN_CONST ulong
       7          81 : fd_tpu_reasm_align( void ) {
       8          81 :   return alignof(fd_tpu_reasm_t);
       9          81 : }
      10             : 
      11             : FD_FN_CONST ulong
      12             : fd_tpu_reasm_footprint( ulong depth,
      13          30 :                         ulong burst ) {
      14             : 
      15          30 :   if( FD_UNLIKELY(
      16          30 :       ( fd_ulong_popcnt( depth )!=1 ) |
      17          30 :       ( depth>0x7fffffffUL          ) |
      18          30 :       ( burst<2                     ) |
      19          30 :       ( burst>0x7fffffffUL          ) ) )
      20          15 :     return 0UL;
      21             : 
      22          15 :   ulong slot_cnt  = depth+burst;
      23          15 :   ulong chain_cnt = fd_tpu_reasm_map_chain_cnt_est( slot_cnt );
      24          15 :   return FD_LAYOUT_FINI( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_INIT,
      25          30 :       fd_tpu_reasm_align(),         sizeof(fd_tpu_reasm_t)                  ), /* hdr       */
      26          30 :       alignof(uint),                depth   *sizeof(uint)                   ), /* pub_slots */
      27          30 :       alignof(fd_tpu_reasm_slot_t), slot_cnt*sizeof(fd_tpu_reasm_slot_t)    ), /* slots     */
      28          30 :       fd_tpu_reasm_map_align(),     fd_tpu_reasm_map_footprint( chain_cnt ) ), /* map       */
      29          30 :       fd_tpu_reasm_align() );
      30             : 
      31          30 : }
      32             : 
      33             : void *
      34             : fd_tpu_reasm_new( void * shmem,
      35             :                   ulong  depth,
      36             :                   ulong  burst,
      37             :                   ulong  orig,
      38           6 :                   void * dcache ) {
      39             : 
      40           6 :   if( FD_UNLIKELY( !shmem ) ) return NULL;
      41           6 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, alignof(fd_tpu_reasm_t) ) ) ) return NULL;
      42           6 :   if( FD_UNLIKELY( !fd_tpu_reasm_footprint( depth, burst ) ) ) return NULL;
      43           6 :   if( FD_UNLIKELY( orig > FD_FRAG_META_ORIG_MAX ) ) return NULL;
      44             : 
      45           6 :   ulong req_data_sz = fd_tpu_reasm_req_data_sz( depth, burst );
      46           6 :   if( FD_UNLIKELY( fd_dcache_data_sz( dcache )<req_data_sz ) ) {
      47           0 :     FD_LOG_WARNING(( "dcache data_sz is too small (need %lu, have %lu)", req_data_sz, fd_dcache_data_sz( dcache ) ));
      48           0 :     return NULL;
      49           0 :   }
      50             : 
      51             :   /* Memory layout */
      52             : 
      53           6 :   ulong slot_cnt = depth+burst;
      54           6 :   if( FD_UNLIKELY( !slot_cnt ) ) return NULL;
      55           6 :   ulong chain_cnt = fd_tpu_reasm_map_chain_cnt_est( slot_cnt );
      56             : 
      57           6 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      58           6 :   fd_tpu_reasm_t *      reasm     = FD_SCRATCH_ALLOC_APPEND( l, fd_tpu_reasm_align(),         sizeof(fd_tpu_reasm_t)                  );
      59           6 :   uint *                pub_slots = FD_SCRATCH_ALLOC_APPEND( l, alignof(uint),                depth*sizeof(uint)                      );
      60           6 :   fd_tpu_reasm_slot_t * slots     = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_tpu_reasm_slot_t), slot_cnt*sizeof(fd_tpu_reasm_slot_t)    );
      61           6 :   void *                map_mem   = FD_SCRATCH_ALLOC_APPEND( l, fd_tpu_reasm_map_align(),     fd_tpu_reasm_map_footprint( chain_cnt ) );
      62           6 :   FD_SCRATCH_ALLOC_FINI( l, fd_tpu_reasm_align() );
      63             : 
      64           6 :   fd_memset( reasm, 0, sizeof(fd_tpu_reasm_t) );
      65           6 :   fd_memset( slots, 0, burst*sizeof(fd_tpu_reasm_slot_t) );
      66             : 
      67           6 :   fd_tpu_reasm_map_t * map = fd_tpu_reasm_map_join( fd_tpu_reasm_map_new( map_mem, chain_cnt, 0UL ) );
      68           6 :   if( FD_UNLIKELY( !map ) ) {
      69           0 :     FD_LOG_WARNING(( "fd_tpu_reasm_map_new failed" ));
      70           0 :     return NULL;
      71           0 :   }
      72             : 
      73             :   /* Initialize reasm object */
      74             : 
      75           6 :   reasm->slots_off     = (ulong)( (uchar *)slots     - (uchar *)reasm );
      76           6 :   reasm->pub_slots_off = (ulong)( (uchar *)pub_slots - (uchar *)reasm );
      77           6 :   reasm->map_off       = (ulong)( (uchar *)map       - (uchar *)reasm );
      78           6 :   reasm->dcache        = dcache;
      79             : 
      80           6 :   reasm->depth    = (uint)depth;
      81           6 :   reasm->burst    = (uint)burst;
      82           6 :   reasm->head     = (uint)slot_cnt-1U;
      83           6 :   reasm->tail     = (uint)depth;
      84           6 :   reasm->slot_cnt = (uint)slot_cnt;
      85           6 :   reasm->orig     = (ushort)orig;
      86             : 
      87             :   /* The initial state moves the first 'depth' slots to the mcache (PUB)
      88             :      and leaves the rest as FREE. */
      89             : 
      90         774 :   for( uint j=0U; j<depth; j++ ) {
      91         768 :     fd_tpu_reasm_slot_t * slot = slots + j;
      92         768 :     slot->k.state     = FD_TPU_REASM_STATE_PUB;
      93         768 :     slot->k.conn_uid  = ULONG_MAX;
      94         768 :     slot->k.stream_id = 0xffffffffffff;
      95         768 :     slot->k.sz        = 0;
      96         768 :     slot->chain_next = UINT_MAX;
      97         768 :     pub_slots[ j ]   = j;
      98         768 :   }
      99         774 :   for( uint j=(uint)depth; j<slot_cnt; j++ ) {
     100         768 :     fd_tpu_reasm_slot_t * slot = slots + j;
     101         768 :     slot->k.state     = FD_TPU_REASM_STATE_FREE;
     102         768 :     slot->k.conn_uid  = ULONG_MAX;
     103         768 :     slot->k.stream_id = 0xffffffffffff;
     104         768 :     slot->k.sz        = 0;
     105         768 :     slot->lru_prev    = fd_uint_if( j<slot_cnt-1U, j+1U, UINT_MAX );
     106         768 :     slot->lru_next    = fd_uint_if( j>depth,       j-1U, UINT_MAX );
     107         768 :     slot->chain_next  = UINT_MAX;
     108         768 :   }
     109             : 
     110             :   /* Clear the entire hash map */
     111             : 
     112           6 :   uint * chains    = fd_tpu_reasm_map_private_chain( map );
     113         774 :   for( uint j=0U; j<chain_cnt; j++ ) {
     114         768 :     chains[ j ] = UINT_MAX;
     115         768 :   }
     116             : 
     117           6 :   FD_COMPILER_MFENCE();
     118           6 :   reasm->magic = FD_TPU_REASM_MAGIC;
     119           6 :   FD_COMPILER_MFENCE();
     120             : 
     121           6 :   return reasm;
     122           6 : }
     123             : 
     124             : fd_tpu_reasm_t *
     125           6 : fd_tpu_reasm_join( void * shreasm ) {
     126           6 :   fd_tpu_reasm_t * reasm = shreasm;
     127           6 :   if( FD_UNLIKELY( reasm->magic != FD_TPU_REASM_MAGIC ) ) {
     128           0 :     FD_LOG_WARNING(( "bad magic" ));
     129           0 :     return NULL;
     130           0 :   }
     131           6 :   return reasm;
     132           6 : }
     133             : 
     134             : void *
     135           3 : fd_tpu_reasm_leave( fd_tpu_reasm_t * reasm ) {
     136           3 :   return reasm;
     137           3 : }
     138             : 
     139             : void *
     140           3 : fd_tpu_reasm_delete( void * shreasm ) {
     141           3 :   fd_tpu_reasm_t * reasm = shreasm;
     142           3 :   if( FD_UNLIKELY( !reasm ) ) return NULL;
     143           3 :   reasm->magic = 0UL;
     144           3 :   return shreasm;
     145           3 : }
     146             : 
     147             : fd_tpu_reasm_slot_t *
     148             : fd_tpu_reasm_query( fd_tpu_reasm_t * reasm,
     149             :                     ulong            conn_uid,
     150       76509 :                     ulong            stream_id ) {
     151       76509 :   return smap_query( reasm, conn_uid, stream_id );
     152       76509 : }
     153             : 
     154             : fd_tpu_reasm_slot_t *
     155             : fd_tpu_reasm_prepare( fd_tpu_reasm_t * reasm,
     156             :                       ulong            conn_uid,
     157             :                       ulong            stream_id,
     158       76125 :                       long             tsorig ) {
     159       76125 :   fd_tpu_reasm_slot_t * slot = slotq_pop_tail( reasm );
     160       76125 :   smap_remove( reasm, slot );
     161       76125 :   slot_begin( slot );
     162       76125 :   slotq_push_head( reasm, slot );
     163       76125 :   slot->k.conn_uid  = conn_uid;
     164       76125 :   slot->k.stream_id = stream_id & FD_TPU_REASM_SID_MASK;
     165       76125 :   smap_insert( reasm, slot );
     166       76125 :   slot->tsorig_comp = (uint)fd_frag_meta_ts_comp( tsorig );
     167       76125 :   return slot;
     168       76125 : }
     169             : 
     170             : int
     171             : fd_tpu_reasm_frag( fd_tpu_reasm_t *      reasm,
     172             :                    fd_tpu_reasm_slot_t * slot,
     173             :                    uchar const *         data,
     174             :                    ulong                 data_sz,
     175       65841 :                    ulong                 data_off ) {
     176             : 
     177       65841 :   if( FD_UNLIKELY( slot->k.state != FD_TPU_REASM_STATE_BUSY ) )
     178           0 :     return FD_TPU_REASM_ERR_STATE;
     179             : 
     180       65841 :   ulong slot_idx = slot_get_idx( reasm, slot );
     181       65841 :   ulong sz0      = slot->k.sz;
     182             : 
     183       65841 :   if( FD_UNLIKELY( data_off>sz0 ) ) {
     184           0 :     return FD_TPU_REASM_ERR_SKIP;
     185           0 :   }
     186             : 
     187       65841 :   if( FD_UNLIKELY( data_off<sz0 ) ) {
     188             :     /* Fragment partially known ... should not happen */
     189           0 :     ulong skip = sz0 - data_off;
     190           0 :     if( skip>data_sz ) return FD_TPU_REASM_SUCCESS;
     191           0 :     data_off  += skip;
     192           0 :     data_sz   -= skip;
     193           0 :     data      += skip;
     194           0 :   }
     195             : 
     196       65841 :   ulong sz1 = sz0 + data_sz;
     197       65841 :   if( FD_UNLIKELY( (sz1<sz0)|(sz1>FD_TPU_MTU) ) ) {
     198           0 :     fd_tpu_reasm_cancel( reasm, slot );
     199           0 :     return FD_TPU_REASM_ERR_SZ;
     200           0 :   }
     201             : 
     202       65841 :   fd_memcpy( reasm->dcache[ slot_idx ].payload + sz0, data, data_sz );
     203             : 
     204       65841 :   slot->k.sz = (ushort)( sz1 & FD_TPU_REASM_SZ_MASK );
     205       65841 :   return FD_TPU_REASM_SUCCESS;
     206       65841 : }
     207             : 
     208             : int
     209             : fd_tpu_reasm_publish( fd_tpu_reasm_t *      reasm,
     210             :                       fd_tpu_reasm_slot_t * slot,
     211             :                       fd_frag_meta_t *      mcache,
     212             :                       void *                base,  /* Assumed aligned FD_CHUNK_ALIGN */
     213             :                       ulong                 seq,
     214             :                       long                  tspub,
     215             :                       uint                  source_ipv4,
     216       65841 :                       uchar                 source_tpu ) {
     217             : 
     218       65841 :   ulong depth = reasm->depth;
     219             : 
     220       65841 :   if( FD_UNLIKELY( slot->k.state != FD_TPU_REASM_STATE_BUSY ) )
     221           0 :     return FD_TPU_REASM_ERR_STATE;
     222             : 
     223             :   /* Derive chunk index */
     224       65841 :   uint           slot_idx = slot_get_idx( reasm, slot );
     225       65841 :   fd_tpu_msg_t * buf      = &reasm->dcache[ slot_idx ];
     226       65841 :   ulong          chunk    = fd_laddr_to_chunk( base, buf );
     227       65841 :   if( FD_UNLIKELY( ( (ulong)buf<(ulong)base ) |
     228       65841 :                    ( chunk>UINT_MAX          ) ) ) {
     229           0 :     FD_LOG_CRIT(( "invalid base %p for slot %p in tpu_reasm %p",
     230           0 :                   base, (void *)slot, (void *)reasm ));
     231           0 :   }
     232             : 
     233             :   /* Find least recently published slot.  This is our "freed slot".
     234             :      (Every time a new slot is published, another slot is simultaneously
     235             :      freed) */
     236       65841 :   uint * pub_slot       = fd_tpu_reasm_pub_slots_laddr( reasm ) + fd_mcache_line_idx( seq, depth );
     237       65841 :   uint   freed_slot_idx = *pub_slot;
     238       65841 :   FD_CHECK_CRIT( freed_slot_idx < reasm->slot_cnt, "corruption detected" );
     239             : 
     240             :   /* Publish to mcache */
     241       65841 :   ulong sz  = slot->k.sz;
     242       65841 :   ulong ctl         = fd_frag_meta_ctl( reasm->orig, 1, 1, 0 );
     243       65841 :   ulong tsorig_comp = slot->tsorig_comp;
     244       65841 :   ulong tspub_comp  = fd_frag_meta_ts_comp( tspub );
     245             : 
     246       65841 :   fd_txn_m_t * txnm = &buf->hdr;
     247       65841 :   *txnm = (fd_txn_m_t){0};
     248       65841 :   txnm->payload_sz = (ushort)sz;
     249       65841 :   txnm->source_ipv4 = source_ipv4;
     250       65841 :   txnm->source_tpu  = source_tpu;
     251             : 
     252       65841 : # if FD_HAS_AVX
     253       65841 :   fd_mcache_publish_avx( mcache, depth, seq, 0UL, chunk, fd_txn_m_realized_footprint( txnm, 0, 0 ), ctl, tsorig_comp, tspub_comp );
     254             : # elif FD_HAS_SSE
     255             :   fd_mcache_publish_sse( mcache, depth, seq, 0UL, chunk, fd_txn_m_realized_footprint( txnm, 0, 0 ), ctl, tsorig_comp, tspub_comp );
     256             : # else
     257             :   fd_mcache_publish    ( mcache, depth, seq, 0UL, chunk, fd_txn_m_realized_footprint( txnm, 0, 0 ), ctl, tsorig_comp, tspub_comp );
     258             : # endif
     259             : 
     260             :   /* Mark new slot as published */
     261       65841 :   slotq_remove( reasm, slot );
     262       65841 :   slot->k.state = FD_TPU_REASM_STATE_PUB;
     263       65841 :   *pub_slot = slot_idx;
     264             : 
     265             :   /* Free oldest published slot */
     266       65841 :   fd_tpu_reasm_slot_t * free_slot = fd_tpu_reasm_slots_laddr( reasm ) + freed_slot_idx;
     267       65841 :   uint free_slot_state = free_slot->k.state;
     268       65841 :   FD_CHECK_CRIT( free_slot_state == FD_TPU_REASM_STATE_PUB, "corruption detected" );
     269       65841 :   free_slot->k.state = FD_TPU_REASM_STATE_FREE;
     270       65841 :   slotq_push_tail( reasm, free_slot );
     271             : 
     272       65841 :   return FD_TPU_REASM_SUCCESS;
     273       65841 : }
     274             : 
     275             : void
     276             : fd_tpu_reasm_cancel( fd_tpu_reasm_t *      reasm,
     277        9348 :                      fd_tpu_reasm_slot_t * slot ) {
     278        9348 :   if( FD_UNLIKELY( slot->k.state != FD_TPU_REASM_STATE_BUSY ) ) return;
     279        9348 :   slotq_remove( reasm, slot );
     280        9348 :   smap_remove( reasm, slot );
     281        9348 :   slot->k.state     = FD_TPU_REASM_STATE_FREE;
     282        9348 :   slot->k.conn_uid  = ULONG_MAX;
     283        9348 :   slot->k.stream_id = 0UL;
     284        9348 :   slotq_push_tail( reasm, slot );
     285        9348 : }
     286             : 
     287             : int
     288             : fd_tpu_reasm_publish_fast( fd_tpu_reasm_t * reasm,
     289             :                            uchar const *    data,
     290             :                            ulong            sz,
     291             :                            fd_frag_meta_t * mcache,
     292             :                            void *           base,  /* Assumed aligned FD_CHUNK_ALIGN */
     293             :                            ulong            seq,
     294             :                            long             tspub,
     295             :                            uint             source_ipv4,
     296           0 :                            uchar            source_tpu ) {
     297             : 
     298           0 :   ulong depth = reasm->depth;
     299           0 :   if( FD_UNLIKELY( sz>FD_TPU_MTU ) ) return FD_TPU_REASM_ERR_SZ;
     300             : 
     301             :   /* Acquire least recent slot.  This is our "new slot" */
     302           0 :   fd_tpu_reasm_slot_t * slot = slotq_pop_tail( reasm );
     303           0 :   smap_remove( reasm, slot );
     304           0 :   slot_begin( slot );
     305             : 
     306             :   /* Derive buffer address of new slot */
     307           0 :   uint           slot_idx = slot_get_idx( reasm, slot );
     308           0 :   fd_tpu_msg_t * buf      = &reasm->dcache[ slot_idx ];
     309           0 :   ulong          chunk    = fd_laddr_to_chunk( base, buf );
     310           0 :   if( FD_UNLIKELY( ( (ulong)buf<(ulong)base ) |
     311           0 :                    ( chunk>UINT_MAX         ) ) ) {
     312           0 :     FD_LOG_ERR(( "Computed invalid chunk index (base=%p buf=%p chunk=%lx)",
     313           0 :                  base, (void *)buf, chunk ));
     314           0 :   }
     315             : 
     316             :   /* Find least recently published slot.  This is our "freed slot".
     317             :      (Every time a new slot is published, another slot is simultaneously
     318             :      freed) */
     319           0 :   uint * pub_slot       = fd_tpu_reasm_pub_slots_laddr( reasm ) + fd_mcache_line_idx( seq, depth );
     320           0 :   uint   freed_slot_idx = *pub_slot;
     321           0 :   FD_CHECK_CRIT( freed_slot_idx < reasm->slot_cnt, "corruption detected" );
     322             : 
     323             :   /* Copy data into new slot */
     324           0 :   FD_COMPILER_MFENCE();
     325           0 :   slot->k.sz = sz & FD_TPU_REASM_SZ_MASK;
     326           0 :   fd_txn_m_t * txnm = &buf->hdr;
     327           0 :   *txnm = (fd_txn_m_t){0};
     328           0 :   txnm->payload_sz = (ushort)slot->k.sz,
     329           0 :   txnm->source_ipv4 = source_ipv4;
     330           0 :   txnm->source_tpu  = source_tpu;
     331           0 :   fd_memcpy( buf->payload, data, sz );
     332           0 :   FD_COMPILER_MFENCE();
     333           0 :   slot->k.state = FD_TPU_REASM_STATE_PUB;
     334           0 :   FD_COMPILER_MFENCE();
     335             : 
     336             :   /* Publish new slot, while simultaneously removing all references to
     337             :      the old slot */
     338           0 :   *pub_slot = slot_idx;
     339           0 :   ulong ctl         = fd_frag_meta_ctl( reasm->orig, 1, 1, 0 );
     340           0 :   uint  tsorig_comp = slot->tsorig_comp;
     341           0 :   uint  tspub_comp  = (uint)fd_frag_meta_ts_comp( tspub );
     342           0 : # if FD_HAS_AVX
     343           0 :   fd_mcache_publish_avx( mcache, depth, seq, 0UL, chunk, fd_txn_m_realized_footprint( txnm, 0, 0 ), ctl, tsorig_comp, tspub_comp );
     344             : # elif FD_HAS_SSE
     345             :   fd_mcache_publish_sse( mcache, depth, seq, 0UL, chunk, fd_txn_m_realized_footprint( txnm, 0, 0 ), ctl, tsorig_comp, tspub_comp );
     346             : # else
     347             :   fd_mcache_publish    ( mcache, depth, seq, 0UL, chunk, fd_txn_m_realized_footprint( txnm, 0, 0 ), ctl, tsorig_comp, tspub_comp );
     348             : # endif
     349             : 
     350             :   /* Free old slot */
     351           0 :   fd_tpu_reasm_slot_t * free_slot = fd_tpu_reasm_slots_laddr( reasm ) + freed_slot_idx;
     352           0 :   uint free_slot_state = free_slot->k.state;
     353           0 :   FD_CHECK_CRIT( free_slot_state == FD_TPU_REASM_STATE_PUB, "corruption detected" );
     354           0 :   free_slot->k.state = FD_TPU_REASM_STATE_FREE;
     355           0 :   slotq_push_tail( reasm, free_slot );
     356           0 :   return FD_TPU_REASM_SUCCESS;
     357           0 : }

Generated by: LCOV version 1.14