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 : }; 17 : 18 : typedef struct fd_clock_tile fd_clock_tile_t; 19 : 20 : FD_PROTOTYPES_BEGIN 21 : 22 : /* fd_clock_tile_init creates a new fd_clock_tile_t. Assumes that the 23 : calling thread has pre-calibrated fd_tempo tick_per_ns value. */ 24 : 25 : static inline void 26 60 : fd_clock_tile_init( fd_clock_tile_t * clock ) { 27 : /* fdctl calibrates tick_per_ns on startup, no need to calibrate here */ 28 60 : double init_w = (double)fd_tempo_tick_per_ns( NULL ); 29 : 30 60 : long init_x0, init_y0; 31 60 : int clock_err = fd_clock_joint_read( _fd_tickcount, NULL, fd_log_wallclock_host, NULL, &init_x0, &init_y0, NULL ); 32 60 : if( FD_UNLIKELY( clock_err ) ) FD_LOG_ERR(( "fd_clock_joint_read failed (%i-%s)", clock_err, fd_clock_strerror( clock_err ) )); 33 : 34 60 : long recal_avg = 10e6L; /* 10ms */ 35 60 : void * shclock = fd_clock_new( clock->shmem, recal_avg, 0L, 0., 0., init_x0, init_y0, init_w ); 36 60 : if( FD_UNLIKELY( !shclock ) ) FD_LOG_ERR(( "fd_clock_new failed" )); 37 : 38 60 : fd_clock_t * clock_ptr = fd_clock_join( clock->clock, shclock, _fd_tickcount, NULL ); 39 60 : if( FD_UNLIKELY( !clock_ptr ) ) FD_LOG_ERR(( "fd_clock_join failed" )); 40 : 41 60 : fd_clock_epoch_init( clock->epoch, clock->shmem ); 42 60 : } 43 : 44 : /* fd_clock_tile_recal_next returns the wallclock deadline after which 45 : the next recal should be done. */ 46 : 47 : static inline long 48 0 : fd_clock_tile_recal_next( fd_clock_tile_t const * clock ) { 49 0 : return fd_clock_recal_next( clock->clock ); 50 0 : } 51 : 52 : /* fd_clock_tile_recal is called periodically to synchronize tickcount 53 : to log_wallclock. Returns the wallclock deadline after which the 54 : next recal should be done. */ 55 : 56 : static inline long 57 0 : fd_clock_tile_recal( fd_clock_tile_t * clock ) { 58 0 : long x; long y; 59 0 : int err = fd_clock_joint_read( _fd_tickcount, NULL, fd_log_wallclock_host, NULL, &x, &y, NULL ); 60 0 : if( FD_UNLIKELY( err ) ) { 61 : /* on recal fail, retry in 1ms */ 62 0 : FD_LOG_WARNING(( "fd_clock_joint_read failed (%i-%s)", err, fd_clock_strerror( err ) )); 63 0 : return ( clock->shmem->recal_next = fd_clock_epoch_y( clock->epoch, fd_tickcount() ) + 1000000L ); 64 0 : } 65 0 : long recal_next = fd_clock_recal( clock->clock, x, y ); 66 0 : fd_clock_epoch_refresh( clock->epoch, clock->shmem ); 67 0 : return recal_next; 68 0 : } 69 : 70 : /* fd_clock_tile_set re-anchors the clock to a caller-supplied 71 : wallclock. For harnesses driving a virtual timeline. */ 72 : 73 : static inline void 74 : fd_clock_tile_set( fd_clock_tile_t * clock, 75 0 : long now ) { 76 0 : fd_clock_step( clock->clock, fd_tickcount(), now, clock->epoch->w ); 77 0 : fd_clock_epoch_refresh( clock->epoch, clock->shmem ); 78 0 : } 79 : 80 : /* fd_clock_tile_now returns an approximation of fd_log_wallclock. */ 81 : 82 : static inline long 83 262404437 : fd_clock_tile_now( fd_clock_tile_t const * clock ) { 84 262404437 : return fd_clock_epoch_y( clock->epoch, fd_tickcount() ); 85 262404437 : } 86 : 87 : /* fd_clock_tile_recal_due returns 1 if a recalibration is due, else 0. */ 88 : 89 : static inline int 90 0 : fd_clock_tile_recal_due( fd_clock_tile_t * clock ) { 91 0 : return fd_clock_tile_now( clock ) >= fd_clock_tile_recal_next( clock ); 92 0 : } 93 : 94 : /* fd_clock_tile_tickcount_to_wallclock converts an fd_tickcount() 95 : sample to a fd_log_wallclock() estimate. */ 96 : 97 : static inline long 98 : fd_clock_tile_tickcount_to_wallclock( fd_clock_tile_t const * clock, 99 0 : long tickcount ) { 100 0 : return fd_clock_epoch_y( clock->epoch, tickcount ); 101 0 : } 102 : 103 : /* fd_clock_tile_tickcomp_to_wallclock converts a compressed 104 : fd_tickcount() sample to a fd_log_wallclock() estimate. */ 105 : 106 : static inline long 107 : fd_clock_tile_tickcomp_to_wallclock( fd_clock_tile_t const * clock, 108 0 : ulong ts_comp ) { 109 0 : long ts = fd_frag_meta_ts_decomp( ts_comp, clock->epoch->x0 ); 110 0 : return fd_clock_tile_tickcount_to_wallclock( clock, ts ); 111 0 : } 112 : 113 : FD_PROTOTYPES_END 114 : 115 : #endif /* HEADER_fd_src_disco_fd_clock_tile_h */