Line data Source code
1 : #ifndef HEADER_fd_src_waltz_quic_log_fd_quic_log_tx_h 2 : #define HEADER_fd_src_waltz_quic_log_fd_quic_log_tx_h 3 : 4 : /* fd_quic_log_tx.h provides internal APIs for high performance 5 : logging of events. Programs that wish to read logs should use 6 : fd_quic_log_user.h instead. 7 : 8 : These are designed to handle millions of events per second in a 9 : production environment without significantly impacting application 10 : performance. That said, the below inlines still contribute to code 11 : bloat so they should be used sparingly in the hot path. 12 : 13 : Currently uses an unstable custom binary log format, could be made 14 : compatible with qlog in the future. 15 : 16 : ### Architecture 17 : 18 : fd_quic_log is split into an internal API (initialization, producing 19 : logs) and a public API (reading logs). This allows for changes to 20 : log producers without having to recompile consumers. 21 : 22 : Public APIs (fd_quic_log_user.h): 23 : - quic_log_abi: Stable ABI for a quic_log shared memory object 24 : - quic_log_rx: Log consumer join to a quic_log (via quic_log_abi) 25 : 26 : Internal APIs (fd_quic_log_tx.h which is this file): 27 : - quic_log_buf: SPMC queue for log messages (implements quic_log_abi) 28 : - quic_log_tx: Log producer join to a quic_log_buf */ 29 : 30 : #include "fd_quic_log_user.h" 31 : #include "../../../tango/mcache/fd_mcache.h" 32 : #include "../../../tango/dcache/fd_dcache.h" 33 : 34 : /* FD_QUIC_LOG_MTU is the max message size of a quic_log_buf. 35 : This parameter can be modified without changes to quic_log_abi. */ 36 : 37 17325 : #define FD_QUIC_LOG_MTU FD_CHUNK_SZ 38 : 39 : /* A quic_log_buf object is an SPMC queue for log messages suitable for 40 : use over shared memory. fd_quic_log_buf_t is the header of a 41 : quic_log_buf object. 42 : 43 : A quic_log_buf is joined by at most one producer (via quic_log_tx) and 44 : an arbitrary number of consumers (via quic_log_rx). A producer and 45 : the consumers do not need to be in the same address space. Consumers 46 : do not need to write to quic_log_buf memory. */ 47 : 48 : struct __attribute__((aligned(64))) fd_quic_log_buf { 49 : /* Public ABI for consumers */ 50 : fd_quic_log_abi_t abi; 51 : 52 : /* Private params follow ... */ 53 : ulong magic; 54 : uint dcache_off; 55 : uint chunk0; 56 : uint wmark; 57 : }; 58 : 59 : typedef struct fd_quic_log_buf fd_quic_log_buf_t; 60 : 61 : /* FD_QUIC_LOG_BUF_MAGIC is used to signal the layout of shared memory 62 : region of a quic_log_buf. */ 63 : 64 2130 : #define FD_QUIC_LOG_BUF_MAGIC (0x11df9ddf66ea2912) 65 : 66 : /* FD_QUIC_LOG_BUF_{ALIGN,FOOTPRINT} specify parameters for the memory 67 : region backing a quic_log_buf. U.B. if depth is invalid. */ 68 : 69 10935 : #define FD_QUIC_LOG_BUF_ALIGN FD_QUIC_LOG_ALIGN 70 : #define FD_QUIC_LOG_BUF_FOOTPRINT(depth) \ 71 : FD_LAYOUT_FINI( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_INIT, \ 72 : FD_QUIC_LOG_BUF_ALIGN, sizeof(fd_quic_log_buf_t) ), \ 73 : FD_MCACHE_ALIGN, FD_MCACHE_FOOTPRINT( depth, 0 ) ), \ 74 : FD_DCACHE_ALIGN, FD_DCACHE_FOOTPRINT( FD_DCACHE_REQ_DATA_SZ( FD_QUIC_LOG_MTU, depth, 1, 1 ), 0 ) ), \ 75 : FD_QUIC_LOG_BUF_ALIGN ) 76 : 77 : FD_PROTOTYPES_BEGIN 78 : 79 : /* fd_quic_log_buf_align returns FD_QUIC_LOG_BUF_ALIGN. */ 80 : 81 : FD_FN_CONST ulong 82 : fd_quic_log_buf_align( void ); 83 : 84 : /* fd_quic_log_buf_footprint returns the required size of a memory region 85 : backing a quic_log_buf. Silently returns 0 if depth is invalid (thus 86 : can be used as a quick way to check if depth is valid). */ 87 : 88 : FD_FN_CONST ulong 89 : fd_quic_log_buf_footprint( ulong depth ); 90 : 91 : /* fd_quic_log_buf_new formats a memory region as a quic_log_buf. Returns 92 : NULL and logs warning on failure (e.g. invalid depth). On success, 93 : returns shmlog which now ready for producer joins 94 : (fd_quic_log_buf_join) and consumer joins (fd_quic_log_rx_join). */ 95 : 96 : void * 97 : fd_quic_log_buf_new( void * shmlog, 98 : ulong depth ); 99 : 100 : /* fd_quic_log_buf_delete releases the memory region backing a 101 : quic_log_buf back to the caller. Assumes that there are no active 102 : joins to quic_log_buf. */ 103 : 104 : void * 105 : fd_quic_log_buf_delete( void * shmlog ); 106 : 107 : FD_PROTOTYPES_END 108 : 109 : /* fd_quic_log_tx describes a producer-side join to a fd_quic_log_buf. */ 110 : 111 : struct fd_quic_log_tx { 112 : fd_frag_meta_t * mcache; 113 : ulong * mcache_seq; 114 : void * base; 115 : ulong depth; 116 : ulong seq; 117 : uint chunk; 118 : uint chunk0; 119 : uint wmark; 120 : }; 121 : 122 : typedef struct fd_quic_log_tx fd_quic_log_tx_t; 123 : 124 : FD_PROTOTYPES_BEGIN 125 : 126 : /* fd_quic_log_tx_join joins the caller thread to a quic_log_buf as a 127 : producer. shmlog points to a quic_log_buf object in the local 128 : address space. On success, fills tx with join info and returns tx. 129 : On failure, returns NULL. Reasons for failure include shmlog is a 130 : NULL pointer or does obviously not point to a quic_log_buf object. 131 : It is U.B. to join multiple producers to the same shmlog. */ 132 : 133 : fd_quic_log_tx_t * 134 : fd_quic_log_tx_join( fd_quic_log_tx_t * tx, 135 : void * shmlog ); 136 : 137 : /* fd_quic_log_tx_leave releases the caller thread from the 138 : quic_log_buf. It is safe to call this function when consumers are 139 : still attached. */ 140 : 141 : void * 142 : fd_quic_log_tx_leave( fd_quic_log_tx_t * logger ); 143 : 144 : /* fd_quic_log_seq_update updates the seq[0] parameter. 145 : (See fd_mcache.h) */ 146 : 147 : static inline void 148 79319448 : fd_quic_log_tx_seq_update( fd_quic_log_tx_t * log ) { 149 79319448 : fd_mcache_seq_update( log->mcache_seq, log->seq ); 150 79319448 : } 151 : 152 : /* fd_quic_log_tx_prepare starts a new log message write. Any other 153 : in-flight write by this producer is dropped. Returns a pointer to 154 : the log message buffer (in memory owned by quic_log_buf). Up to 155 : FD_QUIC_LOG_BUF_MTU bytes may be written to this pointer. */ 156 : 157 : static inline void * 158 81 : fd_quic_log_tx_prepare( fd_quic_log_tx_t * log ) { 159 81 : return fd_chunk_to_laddr( log->base, log->chunk ); 160 81 : } 161 : 162 : /* fd_quic_log_tx_submit submits an in-flight log message write. */ 163 : 164 : static inline void 165 : fd_quic_log_tx_submit( fd_quic_log_tx_t * tx, 166 : ulong sz, /* in [0,FD_QUIC_LOG_BUF_MTU) */ 167 : ulong sig, /* see fd_quic_log_sig() */ 168 81 : long ts ) { /* usually fd_tickcount() */ 169 81 : fd_frag_meta_t * mcache = tx->mcache; 170 81 : ulong chunk = tx->chunk; 171 81 : ulong depth = tx->depth; 172 81 : ulong seq = tx->seq; 173 81 : ulong ctl = fd_frag_meta_ctl( 0, 1, 1, 0 ); 174 81 : uint ts_comp = (uint)fd_frag_meta_ts_comp( ts ); 175 81 : ulong chunk0 = tx->chunk0; 176 81 : uint wmark = tx->wmark; 177 : 178 81 : #if FD_HAS_SSE 179 81 : #define fd_quic_log_publish fd_mcache_publish_sse 180 : #else 181 : #define fd_quic_log_publish fd_mcache_publish 182 : #endif 183 81 : fd_quic_log_publish( mcache, depth, seq, sig, chunk, sz, ctl, 0, ts_comp ); 184 81 : #undef fd_quic_log_publish 185 : 186 81 : tx->seq = fd_seq_inc( seq, 1UL ); 187 81 : tx->chunk = (uint)fd_dcache_compact_next( chunk, sz, chunk0, wmark ); 188 81 : } 189 : 190 : static inline ulong 191 81 : fd_quic_log_sig( uint event ) { 192 81 : return (ulong)event; 193 81 : } 194 : 195 : FD_PROTOTYPES_END 196 : 197 : #endif /* HEADER_fd_src_waltz_quic_log_fd_quic_log_tx_h */