LCOV - code coverage report
Current view: top level - tango - fd_tango_base.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 49 75 65.3 %
Date: 2026-08-14 04:54:57 Functions: 70 16378 0.4 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_tango_fd_tango_base_h
       2             : #define HEADER_fd_src_tango_fd_tango_base_h
       3             : 
       4             : /* Tango messaging concepts:
       5             : 
       6             :    - Each message comes from a single local origin.  Each origin has a
       7             :      13-bit id that uniquely identifies it within a set of message
       8             :      producers and consumers for the lifetime of the set.  Origins
       9             :      typically include a mixture of network receiving devices, local
      10             :      message publishers, etc.  Applications might restrict the set of
      11             :      origins / add additional context / structure to origins id as
      12             :      need.
      13             : 
      14             :    - Messages are partitioned into one or more disjoint fragments.  The
      15             :      number of message payload bytes in a message fragment is in
      16             :      [0,2^16).  That is, message fragment size is any 16-bit unsigned
      17             :      int (thus bounded and variable).  Zero sized fragments are
      18             :      legitimate (e.g. one use case for this is heartbeating a stalled
      19             :      send of a large multi-fragment message).  Note that this is large
      20             :      enough to allow a maximum size UDP payload to be published in a
      21             :      single message fragment.  Applications might choose to impose
      22             :      additional limitations on message fragmentation.
      23             : 
      24             :    - Each fragment has a 64-bit sequence number that is unique over a
      25             :      (potentially dynamic) set of communicating message producers and
      26             :      consumers for the lifetime of that set.  Note that the use of a
      27             :      64-bit sequence number means that sequence number reuse is not an
      28             :      issue practically (would take hundreds of years even at highly
      29             :      local unrealistic messaging rates from producers to consumers).
      30             :      Note also that it is possible to use a smaller sequence number and
      31             :      deal with the implications of sequence number reuse via a number of
      32             :      standard techniques (epochs, TCP timestamp style, etc ... possibly
      33             :      with some minor additional constraints).  This is not done here for
      34             :      code simplicity / robustness / flexibility.
      35             : 
      36             :    - Message fragment sequence numbers increase sequentially with no
      37             :      gaps over the set of all producers for the set's lifetime.  As
      38             :      such, if a consumer encounters a gap in fragment sequence numbers,
      39             :      it knows it was overrun and has lost a message fragment (but
      40             :      typically that consumer does not know the origin of the lost
      41             :      fragment and needs to react accordingly).
      42             : 
      43             :    - The message fragment sequence numbers increase monotonically but
      44             :      not necessarily sequentially as the fragments from messages from
      45             :      different origins may be interleaved in fragment sequence number.
      46             : 
      47             :    - Each fragment is timestamped accordingly to when its origin first
      48             :      started producing it (tsorig) and when it was made first available
      49             :      for consumers (tspub).  As these are used mostly for monitoring and
      50             :      diagnostic purposes, they are stored in a temporally and/or
      51             :      precision compressed representation to free up room for other
      52             :      metadata.
      53             : 
      54             :   -  tsorig is measured on the origin's wallclock and the tspub is
      55             :      measured on the consumer facing publisher's wallclock (these are
      56             :      often the same wallclock).  As such, tsorig from the same origin
      57             :      will be monotonically increasing and tspub will be monotonically
      58             :      increasing across all fragments from all origins.
      59             : 
      60             :    - The wallclocks used for the timestamping should be reasonably well
      61             :      synchronized in the sense described in util/log.  As such
      62             :      timestamps measured by the same wallclocks will be exactly
      63             :      spatially comparable and approximately temporally comparable and
      64             :      timestamps measured by different wallclocks are both approximately
      65             :      spatially and temporally comparable.  Applications might chose to
      66             :      use things like preexisting host globally synchronized hardware
      67             :      tickcounters (e.g. RDTSC) for these instead of the system wallclock
      68             :      to reduce overheads.
      69             : 
      70             :    - Message fragments are distributed strictly in order.  There is no
      71             :      inherent limit to the number of fragments in a message.
      72             :      Applications might impose additional restrictions as appropriate
      73             :      for their needs.
      74             : 
      75             :    - To facilitate message reassembly, each fragment has a set of
      76             :      control bits that specify message boundaries and other conditions
      77             :      that might occur during message distribution.
      78             : 
      79             :      * SOM ("start-of-message"): This indicates this fragment starts a
      80             :        message from the fragment's origin.
      81             : 
      82             :      * EOM ("end-of-message"): This indicates this fragment ends a
      83             :        message from the fragment's origin.  If a consumer sees all the
      84             :        fragment sequence numbers between the sequence number of an SOM
      85             :        fragment from an origin to the sequence number of an EOM fragment
      86             :        from that origin inclusive, it knows that it has received all
      87             :        fragments for that message without loss from that origin.
      88             : 
      89             :      * ERR ("error"): This indicates that the _entire_ message to which
      90             :        the fragment belongs should be considered as corrupt (e.g. CRC
      91             :        checks that happen at the very end of network packet reception
      92             :        are the typical reason for this and these inherent cannot be
      93             :        checked until the last fragment).
      94             : 
      95             :    - To facilitate high performance message distribution, each fragment
      96             :      has a 64-bit message signature.  How the signature is used is
      97             :      application defined.  A typical use case is to have the first
      98             :      fragment of a message signify (in an application dependent way)
      99             :      which consumers are definitely known a priori to be uninterested in
     100             :      the message (such that those consumer doesn't have to spend any
     101             :      bandwidth or compute to reassemble or parse message payloads while
     102             :      still preserving common sequencing and ordering of all messages
     103             :      between all consumers).
     104             : 
     105             :    - For similar reasons, recent message fragments are typically stored
     106             :      in two separate caches:  A fragment metadata cache ("mcache", which
     107             :      behaves like a hybrid of a ring and a direct mapped cache ... it
     108             :      maps recently published fragment sequence numbers to fragment
     109             :      metadata) and a fragment payload cache (which is more flexibly
     110             :      allocated at "chunk" granularity as per the capabilities and needs
     111             :      of the individual origins). */
     112             : 
     113             : #include "../util/fd_util.h"
     114             : 
     115             : #if FD_HAS_SSE /* also covers FD_HAS_AVX */
     116             : #include <smmintrin.h>
     117             : #endif
     118             : 
     119             : #if FD_HAS_AVX
     120             : /* Layout compatible with __m256i without pulling in all of immintrin.h */
     121             : typedef long long fd_frag_meta_v256_t __attribute__((__vector_size__(32),__may_alias__));
     122             : #endif
     123             : 
     124             : /* FD_CHUNK_{LG_SZ,ALIGN,FOOTPRINT,SZ} describe the granularity of
     125             :    message fragment payload allocations.  ALIGN==FOOTPRINT==SZ==2^LG_SZ
     126             :    and recommend this to be something like a cache line practically. */
     127             : 
     128   532408242 : #define FD_CHUNK_LG_SZ     (6)
     129         102 : #define FD_CHUNK_ALIGN     (64UL) /* == 2^FD_CHUNK_LG_SZ, explicit to workaround compiler limitations */
     130          27 : #define FD_CHUNK_FOOTPRINT (64UL) /* " */
     131    30142358 : #define FD_CHUNK_SZ        (64UL) /* " */
     132             : 
     133             : /* FD_CHUNK_{LG_SZ,ALIGN,FOOTPRINT,SZ} describe the coarse layout of
     134             :    message fragment structures.
     135             :    sizeof(fd_frag_meta_t)==ALIGN==FOOTPRINT==SZ==2^LG_SZ.  Recommend
     136             :    this to be something like a positive integer multiple or an integer
     137             :    power of two divisor of a cache line size. */
     138             : 
     139             : #define FD_FRAG_META_LG_SZ     (5)
     140             : #define FD_FRAG_META_ALIGN     (32UL) /* == 2^FD_FRAG_META_LG_SZ, explicit to workaround compiler limitations */
     141             : #define FD_FRAG_META_FOOTPRINT (32UL) /* " */
     142             : #define FD_FRAG_META_SZ        (32UL) /* " */
     143             : 
     144             : /* FD_FRAG_META_ORIG_MAX specifies the maximum number of message origins
     145             :    that are supported.  Origins ids are in [0,FD_FRAG_META_ORIG_MAX). */
     146             : 
     147             : #define FD_FRAG_META_ORIG_MAX (8192UL)
     148             : 
     149             : /* fd_frag_meta_t specifies the message fragment metadata. */
     150             : 
     151             : union __attribute__((aligned(FD_FRAG_META_ALIGN))) fd_frag_meta {
     152             : 
     153             :   struct {
     154             : 
     155             :     /* First aligned SSE word ... these are strictly updated atomically */
     156             : 
     157             :     ulong  seq; /* naturally atomic r/w, frag sequence number. */
     158             :     ulong  sig; /* naturally atomic r/w, application defined message signature for fast consumer side filtering
     159             :                    performance is best if this is updated atomically with seq */
     160             : 
     161             :     /* Second aligned SSE word ... these are typically updated
     162             :        atomically but there is no guarantee both SSE words are jointly
     163             :        updated atomically. */
     164             : 
     165             :     uint   chunk;  /* naturally atomic r/w, compressed relative location of first byte of the frag in data region. */
     166             :     ushort sz;     /* naturally atomic r/w, Frag size in bytes. */
     167             :     ushort ctl;    /* naturally atomic r/w, Message reassembly control bits (origin/clock domain, SOM/EOM/ERR flags) */
     168             :     uint   tsorig; /* naturally atomic r/w, Message diagnostic compressed timestamps */
     169             :     uint   tspub;  /* naturally atomic r/w, " */
     170             : 
     171             :   };
     172             : 
     173             : 
     174             :   /* Intel architecture manual 3A section 8.1.1 (April 2022):
     175             : 
     176             :        Processors that enumerate support for Intel AVX (by setting the
     177             :        feature flag CPUID.01H:ECX.AVX[bit 28]) guarantee that the
     178             :        16-byte memory operations performed by the following instructions
     179             :        will always be carried out atomically:
     180             : 
     181             :        - MOVAPD, MOVAPS, and MOVDQA.
     182             :        - VMOVAPD, VMOVAPS, and VMOVDQA when encoded with VEX.128.
     183             :        - VMOVAPD, VMOVAPS, VMOVDQA32, and VMOVDQA64 when encoded with
     184             :          EVEX.128 and k0 (masking disabled).
     185             : 
     186             :        (Note that these instructions require the linear addresses of
     187             :        their memory operands to be 16-byte aligned.)
     188             : 
     189             :      That is accesses to "sse0" and "sse1" below are atomic when AVX
     190             :      support is available given the overall structure alignment,
     191             :      appropriate intrinsics and what not.  Accesses to avx are likely
     192             :      atomic on many x86 platforms but this is not guaranteed and such
     193             :      should not be assumed. */
     194             : 
     195             : # if FD_HAS_SSE
     196             :   struct {
     197             :     __m128i sse0; /* naturally atomic r/w, covers seq and sig */
     198             :     __m128i sse1; /* naturally atomic r/w, covers chunk, sz, ctl, tsorig and tspub */
     199             :   };
     200             : # endif
     201             : 
     202             : # if FD_HAS_AVX
     203             :   fd_frag_meta_v256_t avx; /* Possibly non-atomic but can hold the metadata in a single register */
     204             : # endif
     205             : 
     206             : # if FD_HAS_ARM
     207             :   ulong ul[4];
     208             : # endif
     209             : 
     210             : };
     211             : 
     212             : typedef union fd_frag_meta fd_frag_meta_t;
     213             : 
     214             : FD_PROTOTYPES_BEGIN
     215             : 
     216             : /* fd_seq_{lt,le,eq,ne,ge,gt} compare 64-bit sequence numbers with
     217             :    proper handling of sequence number wrapping (e.g. if, for example, we
     218             :    decide to randomize the initial sequence numbers used by an
     219             :    application for security reasons and by chance pick a sequence number
     220             :    near 2^64 such that wrapping sequence numbers 0 occurs.  That is,
     221             :    sequence number reuse is not an issue practically in a real world
     222             :    application but sequence number wrapping is if we want to support
     223             :    things like initial sequence number randomization for security.
     224             : 
     225             :    fd_seq_{inc,dec} returns the result of incrementing/decrementing
     226             :    sequence number a delta times.
     227             : 
     228             :    fd_seq_diff returns the how many sequence numbers a is ahead of b.
     229             :    Positive/negative values means a is in the future/past of b.  Zero
     230             :    indicates a and b are the same.
     231             : 
     232             :    In general operations on sequence numbers are strongly encouraged to
     233             :    use this macros as such facilitates updating code to accommodate
     234             :    things like changing the width of a sequence number. */
     235             : 
     236  3076520799 : FD_FN_CONST static inline int fd_seq_lt( ulong a, ulong b ) { return ((long)(a-b))< 0L; }
     237           0 : FD_FN_CONST static inline int fd_seq_le( ulong a, ulong b ) { return ((long)(a-b))<=0L; }
     238  3073425600 : FD_FN_CONST static inline int fd_seq_eq( ulong a, ulong b ) { return a==b;              }
     239  9691363136 : FD_FN_CONST static inline int fd_seq_ne( ulong a, ulong b ) { return a!=b;              }
     240     3000000 : FD_FN_CONST static inline int fd_seq_ge( ulong a, ulong b ) { return ((long)(a-b))>=0L; }
     241  3071759514 : FD_FN_CONST static inline int fd_seq_gt( ulong a, ulong b ) { return ((long)(a-b))> 0L; }
     242             : 
     243 15959021750 : FD_FN_CONST static inline ulong fd_seq_inc( ulong a, ulong delta ) { return a+delta; }
     244   410188267 : FD_FN_CONST static inline ulong fd_seq_dec( ulong a, ulong delta ) { return a-delta; }
     245             : 
     246 25307281486 : FD_FN_CONST static inline long fd_seq_diff( ulong a, ulong b ) { return (long)(a-b); }
     247             : 
     248             : /* fd_chunk_to_laddr: returns a pointer in the local address space to
     249             :    the first byte of the chunk with the given compressed relative
     250             :    address chunk given the pointer in the local address space of the
     251             :    chunk whose index is 0 (chunk0).  fd_chunk_to_laddr_const is for
     252             :    const-correctness.
     253             : 
     254             :    fd_laddr_to_chunk: vice versa. */
     255             : 
     256             : FD_FN_CONST static inline void *    /* Will be aligned FD_CHUNK_ALIGN and in [ chunk0, chunk0 + FD_CHUNK_SZ*(UINT_MAX+1) ) */
     257             : fd_chunk_to_laddr( void * chunk0,   /* Assumed aligned FD_CHUNK_ALIGN */
     258    29541494 :                    ulong  chunk ) { /* Assumed in [0,UINT_MAX] */
     259    29541494 :   return (void *)(((ulong)chunk0) + (chunk << FD_CHUNK_LG_SZ));
     260    29541494 : }
     261             : 
     262             : FD_FN_CONST static inline void const *
     263             : fd_chunk_to_laddr_const( void const * chunk0,
     264   472657769 :                          ulong        chunk ) {
     265   472657769 :   return (void const *)(((ulong)chunk0) + (chunk << FD_CHUNK_LG_SZ));
     266   472657769 : }
     267             : 
     268             : FD_FN_CONST static inline ulong           /* Will be in [0,UINT_MAX] */
     269             : fd_laddr_to_chunk( void const * chunk0,   /* Assumed aligned FD_CHUNK_ALIGN */
     270       65841 :                    void const * laddr ) { /* Assumed aligned FD_CHUNK_ALIGN and in [ chunk0, chunk0 + FD_CHUNK_SZ*(UINT_MAX+1) ) */
     271       65841 :   return (((ulong)laddr)-((ulong)chunk0)) >> FD_CHUNK_LG_SZ;
     272       65841 : }
     273             : 
     274             : /* fd_frag_meta_seq_query returns the sequence number pointed to by meta
     275             :    as atomically observed at some point of time between when the call
     276             :    was made and the call returns.  Assumes meta is valid.  This acts as
     277             :    a compiler memory fence. */
     278             : 
     279             : static inline ulong
     280   481657664 : fd_frag_meta_seq_query( fd_frag_meta_t const * meta ) { /* Assumed non-NULL */
     281   481657664 :   FD_COMPILER_MFENCE();
     282   481657664 :   ulong seq = FD_VOLATILE_CONST( meta->seq );
     283   481657664 :   FD_COMPILER_MFENCE();
     284   481657664 :   return seq;
     285   481657664 : }
     286             : 
     287             : #if FD_HAS_SSE
     288             : 
     289             : /* fd_frag_meta_seq_sig_query returns the sequence number and signature
     290             :    pointed to by meta in one atomic read, same semantics as
     291             :    fd_frag_meta_seq_query. */
     292             : static inline __m128i
     293           0 : fd_frag_meta_seq_sig_query( fd_frag_meta_t const * meta ) { /* Assumed non-NULL */
     294           0 :   FD_COMPILER_MFENCE();
     295           0 :   __m128i sse0 = FD_VOLATILE_CONST( meta->sse0 );
     296           0 :   FD_COMPILER_MFENCE();
     297           0 :   return sse0;
     298           0 : }
     299             : 
     300             : #endif
     301             : 
     302             : /* fd_frag_meta_ctl, fd_frag_meta_ctl_{som,eom,err} pack and unpack the
     303             :    fd_frag message reassembly control bits. */
     304             : 
     305             : FD_FN_CONST static inline ulong  /* In [0,2^16) */
     306             : fd_frag_meta_ctl( ulong orig,    /* Assumed in [0,FD_FRAG_META_ORIG_MAX) */
     307             :                   int   som,     /* 0 for false, non-zero for true */
     308             :                   int   eom,     /* 0 for false, non-zero for true */
     309   396751312 :                   int   err ) {  /* 0 for false, non-zero for true */
     310   396751312 :   return ((ulong)!!som) | (((ulong)!!eom)<<1) | (((ulong)!!err)<<2) | (orig<<3);
     311   396751312 : }
     312             : 
     313           0 : FD_FN_CONST static inline ulong fd_frag_meta_ctl_orig( ulong ctl ) { return        ctl>>3;         }
     314     3000000 : FD_FN_CONST static inline int   fd_frag_meta_ctl_som ( ulong ctl ) { return (int)( ctl     & 1UL); }
     315     3000000 : FD_FN_CONST static inline int   fd_frag_meta_ctl_eom ( ulong ctl ) { return (int)((ctl>>1) & 1UL); }
     316     3000000 : FD_FN_CONST static inline int   fd_frag_meta_ctl_err ( ulong ctl ) { return (int)((ctl>>2) & 1UL); }
     317             : 
     318             : #if FD_HAS_SSE
     319             : 
     320             : FD_FN_CONST static inline __m128i
     321             : fd_frag_meta_sse0( ulong seq,
     322          15 :                    ulong sig ) {
     323          15 :   return _mm_set_epi64x( (long)sig, (long)seq ); /* Backward Intel ... sigh */
     324          15 : }
     325             : 
     326           0 : FD_FN_CONST static inline ulong fd_frag_meta_sse0_seq( __m128i sse0 ) { return (ulong)_mm_extract_epi64( sse0, 0 ); }
     327           0 : FD_FN_CONST static inline ulong fd_frag_meta_sse0_sig( __m128i sse0 ) { return (ulong)_mm_extract_epi64( sse0, 1 ); }
     328             : 
     329             : FD_FN_CONST static inline __m128i
     330             : fd_frag_meta_sse1( ulong chunk,    /* Assumed 32-bit */
     331             :                    ulong sz,       /* Assumed 16 bit */
     332             :                    ulong ctl,      /* Assumed 16-bit */
     333             :                    ulong tsorig,   /* Assumed 32-bit */
     334          15 :                    ulong tspub ) { /* Assumed 32-bit */
     335          15 :   return _mm_set_epi64x( (long)(tsorig | (tspub<<32)),
     336          15 :                          (long)(chunk | (sz<<32) | (ctl<<48)) ); /* Backward Intel ... sigh */
     337          15 : }
     338             : 
     339           0 : FD_FN_CONST static inline ulong fd_frag_meta_sse1_chunk ( __m128i sse1 ) { return (ulong)(uint  )_mm_extract_epi32( sse1, 0 ); }
     340           0 : FD_FN_CONST static inline ulong fd_frag_meta_sse1_sz    ( __m128i sse1 ) { return (ulong)(ushort)_mm_extract_epi16( sse1, 2 ); }
     341           0 : FD_FN_CONST static inline ulong fd_frag_meta_sse1_ctl   ( __m128i sse1 ) { return (ulong)(ushort)_mm_extract_epi16( sse1, 3 ); }
     342           0 : FD_FN_CONST static inline ulong fd_frag_meta_sse1_tsorig( __m128i sse1 ) { return (ulong)(uint  )_mm_extract_epi32( sse1, 2 ); }
     343           0 : FD_FN_CONST static inline ulong fd_frag_meta_sse1_tspub ( __m128i sse1 ) { return (ulong)(uint  )_mm_extract_epi32( sse1, 3 ); }
     344             : 
     345             : #endif
     346             : #if FD_HAS_AVX
     347             : 
     348             : FD_FN_CONST static inline fd_frag_meta_v256_t
     349             : fd_frag_meta_avx( ulong seq,
     350             :                   ulong sig,
     351             :                   ulong chunk,    /* Assumed 32-bit */
     352             :                   ulong sz,       /* Assumed 16 bit */
     353             :                   ulong ctl,      /* Assumed 16-bit */
     354             :                   ulong tsorig,   /* Assumed 32-bit */
     355       65922 :                   ulong tspub ) { /* Assumed 32-bit */
     356       65922 :   return (fd_frag_meta_v256_t){ (long)seq,
     357       65922 :                                 (long)sig,
     358       65922 :                                 (long)(chunk | (sz<<32) | (ctl<<48)),
     359       65922 :                                 (long)(tsorig | (tspub<<32)) };
     360       65922 : }
     361             : 
     362           0 : FD_FN_CONST static inline ulong fd_frag_meta_avx_seq   ( fd_frag_meta_v256_t avx ) { return (ulong)         avx[0];       }
     363           0 : FD_FN_CONST static inline ulong fd_frag_meta_avx_sig   ( fd_frag_meta_v256_t avx ) { return (ulong)         avx[1];       }
     364           0 : FD_FN_CONST static inline ulong fd_frag_meta_avx_chunk ( fd_frag_meta_v256_t avx ) { return (ulong)(uint  ) avx[2];       }
     365           0 : FD_FN_CONST static inline ulong fd_frag_meta_avx_sz    ( fd_frag_meta_v256_t avx ) { return (ulong)(ushort)(avx[2]>>32);  }
     366           0 : FD_FN_CONST static inline ulong fd_frag_meta_avx_ctl   ( fd_frag_meta_v256_t avx ) { return (ulong)(ushort)(avx[2]>>48);  }
     367           0 : FD_FN_CONST static inline ulong fd_frag_meta_avx_tsorig( fd_frag_meta_v256_t avx ) { return (ulong)(uint  ) avx[3];       }
     368           0 : FD_FN_CONST static inline ulong fd_frag_meta_avx_tspub ( fd_frag_meta_v256_t avx ) { return (ulong)(uint  )(avx[3]>>32);  }
     369             : 
     370             : #endif
     371             : 
     372             : #if FD_HAS_ARM
     373             : 
     374             : FD_FN_CONST static inline ulong
     375             : fd_frag_meta_ul2( ulong chunk,
     376             :                   ulong sz,
     377             :                   ulong ctl ) {
     378             :   return chunk | (sz<<32) | (ctl<<48);
     379             : }
     380             : 
     381             : FD_FN_CONST static inline ulong
     382             : fd_frag_meta_ul3( ulong tsorig,
     383             :                   ulong tspub ) {
     384             :   return tsorig | (tspub<<32);
     385             : }
     386             : 
     387             : FD_FN_CONST static inline ulong fd_frag_meta_ul2_chunk ( ulong ul2 ) { return (ulong)(uint  )( ul2      & 0xFFFFFFFFUL); }
     388             : FD_FN_CONST static inline ulong fd_frag_meta_ul2_sz    ( ulong ul2 ) { return (ulong)(ushort)((ul2>>32) &     0xFFFFUL); }
     389             : FD_FN_CONST static inline ulong fd_frag_meta_ul2_ctl   ( ulong ul2 ) { return (ulong)(ushort)((ul2>>48) &     0xFFFFUL); }
     390             : FD_FN_CONST static inline ulong fd_frag_meta_ul3_tsorig( ulong ul3 ) { return (ulong)(uint  )( ul3      & 0xFFFFFFFFUL); }
     391             : FD_FN_CONST static inline ulong fd_frag_meta_ul3_tspub ( ulong ul3 ) { return (ulong)(uint  )( ul3>>32 );                }
     392             : 
     393             : #endif /* FD_HAS_ARM */
     394             : 
     395             : /* fd_frag_meta_ts_{comp,decomp}:  Given the longs ts and tsref that
     396             :    are reasonably close to each other (|ts-tsref| < 2^31 ... about
     397             :    +/-2.1 seconds if ts and tsref are reasonably well synchronized
     398             :    fd_log_wallclock measurements), this pair of functions can quickly
     399             :    and losslessly compress / decompress ts by a factor of 2 exactly
     400             :    using tsref as the compressor / decompressor "state". */
     401             : 
     402             : FD_FN_CONST static inline ulong   /* In [0,UINT_MAX] */
     403   415383203 : fd_frag_meta_ts_comp( long ts ) {
     404   415383203 :   return (ulong)(uint)ts;
     405   415383203 : }
     406             : 
     407             : FD_FN_CONST static inline long
     408             : fd_frag_meta_ts_decomp( ulong tscomp,   /* In [0,UINT_MAX] */
     409           0 :                         long  tsref ) {
     410           0 :   ulong msb = ((ulong)tsref) + fd_ulong_mask_lsb(31) - tscomp;
     411           0 :   return (long)((msb & ~fd_ulong_mask_lsb(32)) | tscomp);
     412           0 : }
     413             : 
     414             : FD_PROTOTYPES_END
     415             : 
     416             : #endif /* HEADER_fd_src_tango_fd_tango_base_h */
     417             : 

Generated by: LCOV version 1.14