Line data Source code
1 : #ifndef HEADER_fd_src_disco_gui_fd_gui_gossip_bw_h 2 : #define HEADER_fd_src_disco_gui_fd_gui_gossip_bw_h 3 : 4 : /* fd_gui_gossip_bw aggregates the per-peer gossip byte counts the gui 5 : shows. The gossip tile (egress, keyed by destination socket) and 6 : each gossvf tile (ingress, keyed by source socket) add every packet 7 : they already handle, keyed by (ip4, port, message tag), and publish 8 : the aggregates to the gui at most every FD_GUI_GOSSIP_BW_FLUSH_NS 9 : instead of the gui reading every raw packet. The gui attributes 10 : each record to a peer by socket when it applies it, the same lookup 11 : it did per packet. Records are only ever summed, so the byte 12 : counts match the per packet path exactly; they reach the gui's 13 : 150 ms rate windows at most one flush interval later. */ 14 : 15 : #include "../../util/bits/fd_bits.h" 16 : #include "../metrics/generated/fd_metrics_enums.h" 17 : 18 : struct fd_gui_gossip_bw_rec { 19 : uint ip4; /* net order */ 20 : ushort port; /* net order */ 21 : ushort tag; /* in [0,FD_METRICS_ENUM_GOSSIP_MESSAGE_TYPE_CNT) */ 22 : ulong sz; /* sum of gossip payload bytes */ 23 : }; 24 : 25 : typedef struct fd_gui_gossip_bw_rec fd_gui_gossip_bw_rec_t; 26 : 27 0 : #define FD_GUI_GOSSIP_BW_REC_MAX (256UL) 28 0 : #define FD_GUI_GOSSIP_BW_MTU (FD_GUI_GOSSIP_BW_REC_MAX*sizeof(fd_gui_gossip_bw_rec_t)) 29 0 : #define FD_GUI_GOSSIP_BW_LG_SLOT_CNT (9) 30 0 : #define FD_GUI_GOSSIP_BW_FLUSH_NS (10L*1000L*1000L) 31 : 32 0 : #define FD_GUI_GOSSIP_BW_ALIGN (128UL) 33 0 : #define FD_GUI_GOSSIP_BW_MAGIC (0xf17eda2c37b0b500UL) /* firedancer gui bw ver 0 */ 34 : 35 : /* Pending byte counts, keyed by ip4 | port<<32 | tag<<48 (tag is 36 : below FD_METRICS_ENUM_GOSSIP_MESSAGE_TYPE_CNT, so no key is ULONG_MAX). */ 37 : 38 : struct fd_gui_gossip_bw_ele { 39 : ulong key; 40 : ulong sz; 41 : }; 42 : 43 : typedef struct fd_gui_gossip_bw_ele fd_gui_gossip_bw_ele_t; 44 : 45 : #define MAP_NAME fd_gui_gossip_bw_map 46 0 : #define MAP_T fd_gui_gossip_bw_ele_t 47 0 : #define MAP_KEY_NULL ULONG_MAX 48 0 : #define MAP_KEY_INVAL(k) ((k)==ULONG_MAX) 49 : #define MAP_MEMOIZE 0 50 : #include "../../util/tmpl/fd_map_dynamic.c" 51 : 52 : struct __attribute__((aligned(FD_GUI_GOSSIP_BW_ALIGN))) fd_gui_gossip_bw_private { 53 : ulong magic; /* ==FD_GUI_GOSSIP_BW_MAGIC */ 54 : long flush_ticks; 55 : long deadline; /* tickcount the pending records are due, LONG_MAX if none */ 56 : fd_gui_gossip_bw_ele_t * map; 57 : }; 58 : 59 : typedef struct fd_gui_gossip_bw_private fd_gui_gossip_bw_t; 60 : 61 : FD_PROTOTYPES_BEGIN 62 : 63 : /* fd_gui_gossip_bw_{align,footprint} return the required alignment and 64 : footprint of a memory region suitable for use as a gui_gossip_bw. */ 65 : 66 : FD_FN_CONST ulong 67 : fd_gui_gossip_bw_align( void ); 68 : 69 : FD_FN_CONST ulong 70 : fd_gui_gossip_bw_footprint( void ); 71 : 72 : /* fd_gui_gossip_bw_new formats an unused memory region for use as a 73 : gui_gossip_bw with no pending records. seed seeds the key hash. 74 : Returns shmem on success and NULL on failure (logs details). */ 75 : 76 : void * 77 : fd_gui_gossip_bw_new( void * shmem, 78 : ulong seed ); 79 : 80 : fd_gui_gossip_bw_t * 81 : fd_gui_gossip_bw_join( void * shbw ); 82 : 83 : void * 84 : fd_gui_gossip_bw_leave( fd_gui_gossip_bw_t const * bw ); 85 : 86 : void * 87 : fd_gui_gossip_bw_delete( void * shbw ); 88 : 89 : /* fd_gui_gossip_bw_add counts a gossip payload sent to or received 90 : from ip4:port (net order) at tickcount now. Payloads the gui does 91 : not attribute (too short for a tag, unknown tag) are ignored. 92 : Returns 1 if the table is full and must be flushed before the next 93 : add. */ 94 : 95 : static inline int 96 : fd_gui_gossip_bw_add( fd_gui_gossip_bw_t * bw, 97 : uint ip4, 98 : ushort port, 99 : uchar const * payload, 100 : ulong payload_sz, 101 0 : long now ) { 102 0 : if( FD_UNLIKELY( payload_sz<sizeof(uint) ) ) return 0; 103 0 : uint tag = FD_LOAD( uint, payload ); 104 0 : if( FD_UNLIKELY( tag>=FD_METRICS_ENUM_GOSSIP_MESSAGE_TYPE_CNT ) ) return 0; 105 : 106 0 : ulong key = (ulong)ip4 | ((ulong)port<<32) | ((ulong)tag<<48); 107 0 : fd_gui_gossip_bw_ele_t * ele = fd_gui_gossip_bw_map_query( bw->map, key, NULL ); 108 0 : if( FD_LIKELY( ele ) ) { 109 0 : ele->sz += payload_sz; 110 0 : return 0; 111 0 : } 112 : 113 0 : if( FD_UNLIKELY( !fd_gui_gossip_bw_map_key_cnt( bw->map ) ) ) bw->deadline = now + bw->flush_ticks; 114 0 : fd_gui_gossip_bw_map_insert( bw->map, key )->sz = payload_sz; 115 0 : return fd_gui_gossip_bw_map_key_cnt( bw->map )==FD_GUI_GOSSIP_BW_REC_MAX; 116 0 : } 117 : 118 : /* fd_gui_gossip_bw_due returns 1 if there are records and they are due 119 : at tickcount now. */ 120 : 121 : static inline int 122 : fd_gui_gossip_bw_due( fd_gui_gossip_bw_t const * bw, 123 0 : long now ) { 124 0 : return fd_gui_gossip_bw_map_key_cnt( bw->map ) && now>=bw->deadline; 125 0 : } 126 : 127 : /* fd_gui_gossip_bw_next_deadline returns the tickcount the pending 128 : records are due, LONG_MAX if there are none. */ 129 : 130 : static inline long 131 0 : fd_gui_gossip_bw_next_deadline( fd_gui_gossip_bw_t const * bw ) { 132 0 : return fd_gui_gossip_bw_map_key_cnt( bw->map ) ? bw->deadline : LONG_MAX; 133 0 : } 134 : 135 : /* fd_gui_gossip_bw_flush copies the pending records to out (room for 136 : FD_GUI_GOSSIP_BW_REC_MAX) and empties the table. Returns the number 137 : of records copied. */ 138 : 139 : static inline ulong 140 : fd_gui_gossip_bw_flush( fd_gui_gossip_bw_t * bw, 141 0 : fd_gui_gossip_bw_rec_t * out ) { 142 0 : ulong cnt = 0UL; 143 0 : ulong slot_cnt = fd_gui_gossip_bw_map_slot_cnt( bw->map ); 144 0 : for( ulong i=0UL; i<slot_cnt; i++ ) { 145 0 : fd_gui_gossip_bw_ele_t const * ele = bw->map + i; 146 0 : if( fd_gui_gossip_bw_map_key_inval( ele->key ) ) continue; 147 0 : out[ cnt++ ] = (fd_gui_gossip_bw_rec_t){ .ip4 = (uint)ele->key, .port = (ushort)(ele->key>>32), .tag = (ushort)(ele->key>>48), .sz = ele->sz }; 148 0 : } 149 0 : fd_gui_gossip_bw_map_clear( bw->map ); 150 0 : bw->deadline = LONG_MAX; 151 0 : return cnt; 152 0 : } 153 : 154 : FD_PROTOTYPES_END 155 : 156 : #endif /* HEADER_fd_src_disco_gui_fd_gui_gossip_bw_h */