Line data Source code
1 : #ifndef HEADER_fd_src_disco_shred_fd_shred_batch_h 2 : #define HEADER_fd_src_disco_shred_fd_shred_batch_h 3 : 4 : #include "../../util/fd_util_base.h" 5 : #include "../shred/fd_shredder.h" 6 : 7 : /* The shred tile partitions a block into batches of microblocks, and 8 : it partitions each batch into fixed-size FEC sets, with 32 data 9 : shreds and 32 parity shreds each. Each batch is made up of an 10 : integer number of microblocks, which means that no microblock can 11 : cross the batch boundary, and that the last FEC set may need to be 12 : padded with 0s. Since padding completes the payload of the last 13 : FEC set in the batch, and does not impact the batch itself, no FEC 14 : set can contain only padding. 15 : The number of FEC sets per batch is limited only by block-level 16 : limits, so the larger the value, the less relative padding overhead 17 : in every batch. However, the larger the value, the longer it takes 18 : before the tile can start generating and sending FEC sets, unless 19 : you use some strange speculative tricks, which we do not use. 20 : Assuming n batches in a given block, the (upper-limit) quantity of 21 : FEC sets is determined by FD_SHRED_BATCH_FEC_SETS_WMARK for the 22 : first n-1 batches, and by FD_SHRED_BATCH_FEC_SETS_MAX for the last 23 : batch. This is needed because when the microblock completing the 24 : block is received, we include it in the current batch irrespective 25 : of how full the batch might be. The diagrams below (not at scale) 26 : show 2 FEC sets before the watermark (W), which indicates where to 27 : close the current batch, as well as 2 extra FEC sets available for 28 : the last batch in the block. 29 : 30 : Normal: (to be deprecated) 31 : +------------+------------+~~~~~~~~~~~+~~~~~~~~~~~~+ 32 : | FEC_set | FEC_set (W) extra | extra | 33 : +------------+------------+~~~~~~~~~~~+~~~~~~~~~~~~+ 34 : 35 : Chained: (first n-1 batches) 36 : +-----------+-----------+~~~~~~~~~~+~~~~~~~~~~~+ 37 : | FEC_set | FEC_set (W) extra | extra | 38 : +-----------+-----------+~~~~~~~~~~+~~~~~~~~~~~+ 39 : 40 : Resigned: (last batch in block) 41 : +----------+----------+~~~~~~~~~~+~~~~~~~~~~+ 42 : | FEC_set | FEC_set (W) extra | extra | 43 : +----------+----------+~~~~~~~~~~+~~~~~~~~~~+ 44 : 45 : The first n-1 batches are chained, whereas the last one in the 46 : block is (chained+)resigned, which means that each shred (and thus 47 : each FEC set) in the last batch has a smaller payload capacity. 48 : In order to size the region labeled extra, we need to consider the 49 : worst case scenario: we have buffered W-1 bytes using the chained 50 : watermark, when a max-size microblock arrives indicating it is the 51 : last in the block. This situation can only happen when running in 52 : low-power mode, because otherwise the last microblock would be a 53 : tick, which is small, but it does not seem to be worth plumbing in 54 : that sort of logic just to save a little memory that would not 55 : pollute cache anyway. 56 : 57 : Note that this payload reduction does not affect normal FEC sets, 58 : which are scheduled to be deprecated at some point (TODO). */ 59 33 : #define FD_SHRED_BATCH_FEC_SETS_WMARK ( 2UL ) 60 0 : #define FD_SHRED_BATCH_FEC_SETS_EXTRA ( 2UL ) 61 : /* FD_SHRED_BATCH_FEC_SETS_MAX affects the value of STEM_BURST inside 62 : the shred tile (refer to its calculation for details). */ 63 0 : #define FD_SHRED_BATCH_FEC_SETS_MAX ( FD_SHRED_BATCH_FEC_SETS_WMARK + FD_SHRED_BATCH_FEC_SETS_EXTRA ) 64 : /* Validate extra payload capacity. Note that (chained+)resigned 65 : needs to take into considerations the watermark regression. */ 66 : #define FD_SHRED_BATCH_RESIGNED_WMARK_REGRESSION ( FD_SHRED_BATCH_FEC_SETS_WMARK * ( FD_SHREDDER_CHAINED_FEC_SET_PAYLOAD_SZ - FD_SHREDDER_RESIGNED_FEC_SET_PAYLOAD_SZ ) ) 67 : FD_STATIC_ASSERT( ( FD_SHRED_BATCH_FEC_SETS_EXTRA * FD_SHREDDER_NORMAL_FEC_SET_PAYLOAD_SZ ) >= ( FD_POH_SHRED_MTU ), FD_SHRED_BATCH_FEC_SETS_EXTRA ); 68 : FD_STATIC_ASSERT( ( FD_SHRED_BATCH_FEC_SETS_EXTRA * FD_SHREDDER_CHAINED_FEC_SET_PAYLOAD_SZ ) >= ( FD_POH_SHRED_MTU ), FD_SHRED_BATCH_FEC_SETS_EXTRA ); 69 : FD_STATIC_ASSERT( ( FD_SHRED_BATCH_FEC_SETS_EXTRA * FD_SHREDDER_RESIGNED_FEC_SET_PAYLOAD_SZ ) >= ( FD_POH_SHRED_MTU + FD_SHRED_BATCH_RESIGNED_WMARK_REGRESSION ), FD_SHRED_BATCH_FEC_SETS_EXTRA ); 70 : 71 : /* FD_SHRED_BATCH_WMARK: Following along the lines of dcache, batch 72 : microblocks until either the slot ends or the batch would exceed 73 : the corresponding watermark. Only when the received microblock 74 : completes the block is the batch allowed to go beyond the given 75 : watermark, since all remaining FEC sets need to be generated and 76 : forwarded at once. The watermark is relative to the beginning 77 : of the payload in the pending batch buffer (i.e. excluding the 78 : 8 bytes needed for microblock_cnt in the batch header). */ 79 : #define FD_SHRED_BATCH_WMARK_NORMAL ( FD_SHRED_BATCH_FEC_SETS_WMARK * FD_SHREDDER_NORMAL_FEC_SET_PAYLOAD_SZ - 8UL ) 80 33 : #define FD_SHRED_BATCH_WMARK_CHAINED ( FD_SHRED_BATCH_FEC_SETS_WMARK * FD_SHREDDER_CHAINED_FEC_SET_PAYLOAD_SZ - 8UL ) 81 0 : #define FD_SHRED_BATCH_WMARK_RESIGNED ( FD_SHRED_BATCH_FEC_SETS_WMARK * FD_SHREDDER_RESIGNED_FEC_SET_PAYLOAD_SZ - 8UL ) 82 : /* Validate watermark payload capacity. It must support at least 83 : FD_POH_SHRED_MTU bytes. Prefer > to >= as a safety margin, to 84 : avoid any dependency on how we determine later on if the batch 85 : would exceed the watermark. */ 86 : FD_STATIC_ASSERT( ( FD_SHRED_BATCH_WMARK_NORMAL ) > ( FD_POH_SHRED_MTU ), FD_SHRED_BATCH_WMARK_NORMAL ); 87 : FD_STATIC_ASSERT( ( FD_SHRED_BATCH_WMARK_CHAINED ) > ( FD_POH_SHRED_MTU ), FD_SHRED_BATCH_WMARK_CHAINED ); 88 : FD_STATIC_ASSERT( ( FD_SHRED_BATCH_WMARK_RESIGNED ) > ( FD_POH_SHRED_MTU ), FD_SHRED_BATCH_WMARK_RESIGNED ); 89 : FD_STATIC_ASSERT( ( FD_SHRED_BATCH_WMARK_RESIGNED + FD_SHRED_BATCH_RESIGNED_WMARK_REGRESSION ) == ( FD_SHRED_BATCH_WMARK_CHAINED ), FD_SHRED_BATCH_RESIGNED_WMARK_REGRESSION ); 90 : 91 : /* There are three different raw buffer sizes depending on the FEC 92 : set type: normal, chained, and resigned (see fd_shredder.h for 93 : further details). In order to support all three, we allocate the 94 : largest of them (i.e. normal). TODO once normal FEC sets have 95 : been deprecated, replace NORMAL with CHAINED payload size in the 96 : calculation of FD_SHRED_BATCH_RAW_BUF_SZ below. */ 97 : #define FD_SHRED_BATCH_RAW_BUF_SZ ( FD_SHRED_BATCH_FEC_SETS_MAX * FD_SHREDDER_NORMAL_FEC_SET_PAYLOAD_SZ ) 98 : /* Validate batch raw buffer size. Note that (chained+)resigned 99 : needs to take into considerations the watermark regression. */ 100 : FD_STATIC_ASSERT( ( FD_SHRED_BATCH_RAW_BUF_SZ ) >= ( FD_SHRED_BATCH_WMARK_NORMAL + FD_POH_SHRED_MTU ), FD_SHRED_BATCH_RAW_BUF_SZ ); 101 : FD_STATIC_ASSERT( ( FD_SHRED_BATCH_RAW_BUF_SZ ) >= ( FD_SHRED_BATCH_WMARK_CHAINED + FD_POH_SHRED_MTU ), FD_SHRED_BATCH_RAW_BUF_SZ ); 102 : FD_STATIC_ASSERT( ( FD_SHRED_BATCH_RAW_BUF_SZ ) >= ( FD_SHRED_BATCH_WMARK_RESIGNED + FD_POH_SHRED_MTU + FD_SHRED_BATCH_RESIGNED_WMARK_REGRESSION ), FD_SHRED_BATCH_RAW_BUF_SZ ); 103 : 104 : /* FD_SHRED_BATCH_BLOCK_DATA_SZ_MAX is a conservative compile-time 105 : bound on entry bytes in a 32k-shred block (1024 chained FEC sets). 106 : It subtracts worst-case padding of about half the payload, plus 107 : last-batch resigned-size regression and 8-byte batch headers. 108 : Pack does not use this as its per-slot cap; that is 109 : fd_shred_batch_pack_data_max at become-leader. This macro is the 110 : pre-leader default (FD_PACK_MAX_DATA_PER_BLOCK) and sizes skipped- 111 : tick buffers. */ 112 : FD_STATIC_ASSERT( ( FD_SHRED_BATCH_FEC_SETS_MAX ) == ( 4UL ), FD_SHRED_BATCH_FEC_SETS_MAX ); 113 0 : #define FD_SHRED_BATCH_BLOCK_DATA_OHEAD ( 512UL * FD_SHREDDER_CHAINED_FEC_SET_PAYLOAD_SZ + 8192UL + 8192UL ) 114 : FD_STATIC_ASSERT( ( FD_SHRED_BATCH_BLOCK_DATA_OHEAD ) < ( 1024UL * FD_SHREDDER_CHAINED_FEC_SET_PAYLOAD_SZ ), FD_SHRED_BATCH_BLOCK_DATA_OHEAD ); 115 0 : #define FD_SHRED_BATCH_BLOCK_DATA_SZ_MAX ( (1024UL-2UL) * FD_SHREDDER_CHAINED_FEC_SET_PAYLOAD_SZ - FD_SHRED_BATCH_BLOCK_DATA_OHEAD ) 116 : 117 : /* fd_shred_batch_pack_data_max: how many entry bytes (microblock 118 : headers + txn payloads, excluding empty ticks) pack can emit in a 119 : slot without producing more than slot_max_data_shreds. 120 : 121 : max_microblock_sz is the largest pack-produced entry: the 48-byte 122 : entry header plus (max txns per microblock)*FD_TPU_MTU. 123 : 124 : We shred by filling a batch until the next microblock would not 125 : fit in two chained FEC sets (WMARK_CHAINED = 2*C-8 payload bytes), 126 : then padding out that batch: 127 : - The first microblock of a slot is flushed immediately, using 128 : ceil( (8+max_microblock_sz)/C ) FEC sets. 129 : - Each later closed batch holds at least 130 : WMARK_CHAINED-max_microblock_sz entry bytes and uses 2 FEC sets. 131 : - The last batch is the leftover (at most wmark) plus the 132 : completing microblock, padded to resigned FEC sets: 133 : ceil( (wmark + 8 + max_microblock_sz) / R ). Production 134 : finishes on an empty tick; low-power can finish on a 135 : max-size microblock. 136 : 137 : Empty ticks are not included; the caller should subtract 138 : 48*(ticks_per_slot+skipped_ticks). Returns 0 if the shred budget 139 : cannot cover the reserved FEC sets. */ 140 : FD_FN_CONST static inline ulong 141 : fd_shred_batch_pack_data_max( ulong slot_max_data_shreds, 142 33 : ulong max_microblock_sz ) { 143 33 : ulong const C = FD_SHREDDER_CHAINED_FEC_SET_PAYLOAD_SZ; 144 33 : ulong const R = FD_SHREDDER_RESIGNED_FEC_SET_PAYLOAD_SZ; 145 33 : ulong const wmark = FD_SHRED_BATCH_WMARK_CHAINED; /* 2*C - 8 */ 146 : 147 33 : if( FD_UNLIKELY( max_microblock_sz>=wmark ) ) return 0UL; 148 : 149 30 : ulong fec_set_cnt = slot_max_data_shreds / 32UL; 150 30 : ulong first_batch_fec_cnt = ( 8UL + max_microblock_sz + C - 1UL ) / C; 151 30 : ulong last_batch_fec_cnt = ( wmark + 8UL + max_microblock_sz + R - 1UL ) / R; 152 30 : if( FD_UNLIKELY( fec_set_cnt<first_batch_fec_cnt+last_batch_fec_cnt ) ) return 0UL; 153 : 154 21 : ulong middle_batch_fec_cnt = ( fec_set_cnt - first_batch_fec_cnt - last_batch_fec_cnt ) & ~1UL; /* even, 2 FEC per batch */ 155 21 : ulong min_batch = wmark - max_microblock_sz; 156 21 : return ( middle_batch_fec_cnt / 2UL ) * min_batch; 157 30 : } 158 : 159 : #endif /* HEADER_fd_src_disco_shred_fd_shred_batch_h */