Line data Source code
1 : #ifndef HEADER_fd_src_disco_fd_clock_tile_h 2 : #define HEADER_fd_src_disco_fd_clock_tile_h 3 : 4 : /* fd_clock_tile.h provides fd_clock convenience APIs for tiles */ 5 : 6 : #include "../tango/tempo/fd_tempo.h" 7 : #include "../util/clock/fd_clock.h" 8 : 9 : /* fd_clock_tile_t is a fast nanosecond clock source for Firedancer 10 : tiles (single-threaded usage). */ 11 : 12 : struct fd_clock_tile { 13 : fd_clock_shmem_t shmem[1]; 14 : fd_clock_t clock[1]; 15 : fd_clock_epoch_t epoch[1]; 16 : double inv_m; 17 : }; 18 : 19 : typedef struct fd_clock_tile fd_clock_tile_t; 20 : 21 : FD_PROTOTYPES_BEGIN 22 : 23 : /* fd_clock_tile_init creates a new fd_clock_tile_t. Assumes that the 24 : calling thread has pre-calibrated fd_tempo tick_per_ns value. */ 25 : 26 : static inline void 27 1473 : fd_clock_tile_init( fd_clock_tile_t * clock ) { 28 : /* fdctl calibrates tick_per_ns on startup, no need to calibrate here */ 29 1473 : double init_w = (double)fd_tempo_tick_per_ns( NULL ); 30 : 31 1473 : long init_x0, init_y0; 32 1473 : int clock_err = fd_clock_joint_read( _fd_tickcount, NULL, fd_log_wallclock_host, NULL, &init_x0, &init_y0, NULL ); 33 1473 : if( FD_UNLIKELY( clock_err ) ) FD_LOG_ERR(( "fd_clock_joint_read failed (%i-%s)", clock_err, fd_clock_strerror( clock_err ) )); 34 : 35 1473 : long recal_avg = 10e6L; /* 10ms */ 36 1473 : void * shclock = fd_clock_new( clock->shmem, recal_avg, 0L, 0., 0., init_x0, init_y0, init_w ); 37 1473 : if( FD_UNLIKELY( !shclock ) ) FD_LOG_ERR(( "fd_clock_new failed" )); 38 : 39 1473 : fd_clock_t * clock_ptr = fd_clock_join( clock->clock, shclock, _fd_tickcount, NULL ); 40 1473 : if( FD_UNLIKELY( !clock_ptr ) ) FD_LOG_ERR(( "fd_clock_join failed" )); 41 : 42 1473 : fd_clock_epoch_init( clock->epoch, clock->shmem ); 43 1473 : clock->inv_m = 1.0/clock->epoch->m; 44 1473 : } 45 : 46 : /* fd_clock_tile_recal_next returns the wallclock deadline after which 47 : the next recal should be done. */ 48 : 49 : static inline long 50 78 : fd_clock_tile_recal_next( fd_clock_tile_t const * clock ) { 51 78 : return fd_clock_recal_next( clock->clock ); 52 78 : } 53 : 54 : /* fd_clock_tile_recal is called periodically to synchronize tickcount 55 : to log_wallclock. Returns the wallclock deadline after which the 56 : next recal should be done. */ 57 : 58 : static inline long 59 4 : fd_clock_tile_recal( fd_clock_tile_t * clock ) { 60 4 : long x; long y; 61 4 : int err = fd_clock_joint_read( _fd_tickcount, NULL, fd_log_wallclock_host, NULL, &x, &y, NULL ); 62 4 : if( FD_UNLIKELY( err ) ) { 63 : /* on recal fail, retry in 1ms */ 64 0 : FD_LOG_WARNING(( "fd_clock_joint_read failed (%i-%s)", err, fd_clock_strerror( err ) )); 65 0 : return ( clock->shmem->recal_next = fd_clock_epoch_y( clock->epoch, fd_tickcount() ) + 1000000L ); 66 0 : } 67 4 : long recal_next = fd_clock_recal( clock->clock, x, y ); 68 4 : fd_clock_epoch_refresh( clock->epoch, clock->shmem ); 69 4 : clock->inv_m = 1.0/clock->epoch->m; 70 4 : return recal_next; 71 4 : } 72 : 73 : /* fd_clock_tile_set re-anchors the clock to a caller-supplied 74 : wallclock. For harnesses driving a virtual timeline. */ 75 : 76 : static inline void 77 : fd_clock_tile_set( fd_clock_tile_t * clock, 78 57 : long now ) { 79 57 : fd_clock_step( clock->clock, fd_tickcount(), now, clock->epoch->w ); 80 57 : fd_clock_epoch_refresh( clock->epoch, clock->shmem ); 81 57 : clock->inv_m = 1.0/clock->epoch->m; 82 57 : } 83 : 84 : /* fd_clock_tile_now returns an approximation of fd_log_wallclock. */ 85 : 86 : static inline long 87 290206235 : fd_clock_tile_now( fd_clock_tile_t const * clock ) { 88 290206235 : return fd_clock_epoch_y( clock->epoch, fd_tickcount() ); 89 290206235 : } 90 : 91 : /* fd_clock_tile_recal_due returns 1 if a recalibration is due, else 0. */ 92 : 93 : static inline int 94 78 : fd_clock_tile_recal_due( fd_clock_tile_t * clock ) { 95 78 : return fd_clock_tile_now( clock ) >= fd_clock_tile_recal_next( clock ); 96 78 : } 97 : 98 : /* fd_clock_tile_tickcount_to_wallclock converts an fd_tickcount() 99 : sample to a fd_log_wallclock() estimate. */ 100 : 101 : static inline long 102 : fd_clock_tile_tickcount_to_wallclock( fd_clock_tile_t const * clock, 103 0 : long tickcount ) { 104 0 : return fd_clock_epoch_y( clock->epoch, tickcount ); 105 0 : } 106 : 107 : /* fd_clock_tile_wallclock_to_tickcount converts a fd_log_wallclock() 108 : value to the fd_tickcount() at which the clock would read it. */ 109 : 110 : static inline long 111 : fd_clock_tile_wallclock_to_tickcount( fd_clock_tile_t const * clock, 112 36 : long wallclock ) { 113 36 : fd_clock_epoch_t const * epoch = clock->epoch; 114 36 : return fd_clock_epoch_x0( epoch ) + (long)( (double)( wallclock-fd_clock_epoch_y0_eff( epoch ) )*clock->inv_m ); 115 36 : } 116 : 117 : /* fd_clock_tile_tickcomp_to_wallclock converts a compressed 118 : fd_tickcount() sample to a fd_log_wallclock() estimate. */ 119 : 120 : static inline long 121 : fd_clock_tile_tickcomp_to_wallclock( fd_clock_tile_t const * clock, 122 0 : ulong ts_comp ) { 123 0 : long ts = fd_frag_meta_ts_decomp( ts_comp, clock->epoch->x0 ); 124 0 : return fd_clock_tile_tickcount_to_wallclock( clock, ts ); 125 0 : } 126 : 127 : FD_PROTOTYPES_END 128 : 129 : #endif /* HEADER_fd_src_disco_fd_clock_tile_h */