Line data Source code
1 : /* bench_tempo_calib measures the accuracy and wall-clock cost of the
2 : tick_per_ns calibration loop in fd_tempo_tick_per_ns for different
3 : (trial_cnt, trim_cnt, sleep_ns) parameterizations. Because the real
4 : fd_tempo_tick_per_ns is FD_ONCE-guarded (only samples once per
5 : process), this harness re-implements the identical sampling logic so
6 : it can be run many times and compared against a high-precision
7 : reference. Used to validate that the "Tier 1" parameter reduction
8 : (fewer/shorter trials) does not degrade the rate estimate. */
9 :
10 : #include "../fd_tango.h"
11 : #include "../../util/math/fd_stat.h"
12 : #include <math.h>
13 :
14 : #if FD_HAS_DOUBLE
15 :
16 : /* calib runs ONE calibration with the given parameters and returns
17 : mu (tick_per_ns) in *opt_mu and sigma in *opt_sigma. Identical
18 : algorithm to fd_tempo_tick_per_ns. */
19 :
20 : static int
21 : calib( double * opt_mu,
22 : double * opt_sigma,
23 : ulong trial_cnt,
24 : ulong trim_cnt,
25 0 : long sleep_ns ) {
26 0 : double mu, sigma;
27 0 : int retries = 0;
28 0 : ulong iter = 0UL;
29 0 : for(;;) {
30 0 : double trial[ 4096 ];
31 0 : if( trial_cnt>4096UL ) trial_cnt = 4096UL;
32 0 : for( ulong trial_idx=0UL; trial_idx<trial_cnt; trial_idx++ ) {
33 0 : long then; long toc; fd_tempo_observe_pair( &then, &toc );
34 0 : fd_log_sleep( sleep_ns );
35 0 : long now; long tic; fd_tempo_observe_pair( &now, &tic );
36 0 : trial[ trial_idx ] = (double)(tic-toc) / (double)(now-then);
37 0 : }
38 0 : double * sample = trial + trim_cnt;
39 0 : ulong sample_cnt = trial_cnt - 2UL*trim_cnt;
40 0 : ulong thresh = sample_cnt >> 1;
41 0 : if( FD_LIKELY( fd_stat_robust_norm_fit_double( &mu, &sigma, sample, sample_cnt, sample )>thresh ) && FD_LIKELY( mu>0. ) ) break;
42 0 : iter++;
43 0 : retries++;
44 0 : if( iter==3UL ) { mu = 3.; sigma = 1e-7; break; }
45 0 : }
46 0 : if( opt_mu ) *opt_mu = mu;
47 0 : if( opt_sigma ) *opt_sigma = sigma;
48 0 : return retries;
49 0 : }
50 :
51 : /* run_config repeats calib() rep_cnt times, printing the spread of mu
52 : (relative to ref) and the wall-clock cost per calibration. */
53 :
54 : static void
55 : run_config( char const * label,
56 : ulong trial_cnt,
57 : ulong trim_cnt,
58 : long sleep_ns,
59 : ulong rep_cnt,
60 0 : double ref ) {
61 0 : if( rep_cnt>256UL ) rep_cnt = 256UL;
62 0 : if( rep_cnt<1UL ) rep_cnt = 1UL;
63 0 : double mus[ 256 ];
64 0 : double sigmas[ 256 ];
65 0 : long t_total = 0L;
66 0 : int retry_total = 0;
67 :
68 0 : for( ulong r=0UL; r<rep_cnt; r++ ) {
69 0 : long t0 = fd_log_wallclock();
70 0 : retry_total += calib( &mus[r], &sigmas[r], trial_cnt, trim_cnt, sleep_ns );
71 0 : t_total += fd_log_wallclock() - t0;
72 0 : }
73 :
74 : /* mean / stddev / min / max of mu */
75 0 : double sum=0., sum2=0., lo=mus[0], hi=mus[0];
76 0 : double maxabserr=0.;
77 0 : for( ulong r=0UL; r<rep_cnt; r++ ) {
78 0 : double m = mus[r];
79 0 : sum += m;
80 0 : sum2 += m*m;
81 0 : if( m<lo ) lo=m;
82 0 : if( m>hi ) hi=m;
83 0 : double e = (m-ref)/ref;
84 0 : if( e<0. ) e=-e;
85 0 : if( e>maxabserr ) maxabserr = e;
86 0 : }
87 0 : double mean = sum/(double)rep_cnt;
88 0 : double var = sum2/(double)rep_cnt - mean*mean;
89 0 : if( var<0. ) var=0.;
90 0 : double sd = sqrt( var );
91 0 : double bias = (mean-ref)/ref;
92 0 : double spread = (hi-lo)/ref;
93 :
94 0 : double sig_sum=0.; for( ulong r=0UL; r<rep_cnt; r++ ) sig_sum += sigmas[r];
95 0 : double sig_mean = sig_sum/(double)rep_cnt;
96 :
97 0 : FD_LOG_NOTICE(( "%-26s wall/calib %7.1f ms | mu mean %10.6f ghz bias %+9.2e jitter(sd) %8.2e (%.2f ppm) spread %8.2e maxerr %8.2e sigma_out %8.2e retries %d",
98 0 : label,
99 0 : (double)t_total/(double)rep_cnt/1e6,
100 0 : mean, bias, sd/mean, sd/mean*1e6, spread, maxabserr, sig_mean, retry_total ));
101 0 : }
102 :
103 : #endif
104 :
105 : int
106 : main( int argc,
107 : char ** argv ) {
108 : fd_boot( &argc, &argv );
109 :
110 : # if FD_HAS_DOUBLE
111 : ulong rep_cnt = fd_env_strip_cmdline_ulong( &argc, &argv, "--reps", NULL, 30UL );
112 :
113 : FD_LOG_NOTICE(( "building high-precision reference (large trial_cnt, long sleep)..." ));
114 :
115 : /* Reference: a single very long, high-trial calibration. Average a
116 : few of these to pin down "truth" as well as we can on this host. */
117 : double ref_sum = 0.;
118 : ulong ref_cnt = 5UL;
119 : for( ulong r=0UL; r<ref_cnt; r++ ) {
120 : double m;
121 : calib( &m, NULL, 64UL, 8UL, 33554432L /* ~33.6 ms */ );
122 : ref_sum += m;
123 : }
124 : double ref = ref_sum/(double)ref_cnt;
125 : FD_LOG_NOTICE(( "reference mu = %.6f ghz (%lu reps of 64 x 33.6ms)", ref, ref_cnt ));
126 : FD_LOG_NOTICE(( "comparing %lu reps per config:", rep_cnt ));
127 :
128 : /* The two configs that actually landed:
129 : - "prod" : fd_tempo_tick_per_ns (32 x 16.8ms)
130 : - "dev" : fd_tempo_tick_per_ns_dev (4 x 0.25ms)
131 : "candidate (16 x 8.4ms)" is an intermediate parameterization that was
132 : evaluated but NOT deployed (production kept the conservative 32-trial
133 : config); it is kept here for comparison only. */
134 : run_config( "prod (32 x 16.8ms)", 32UL, 4UL, 16777216L, rep_cnt, ref );
135 : run_config( "candidate (16 x 8.4ms)", 16UL, 2UL, 8388608L, rep_cnt, ref );
136 : run_config( "dev (4 x 0.25ms)", 4UL, 0UL, 262144L, rep_cnt, ref );
137 :
138 : /* A few neighbours around the dev floor, for reference / re-tuning.
139 : The robust fit needs > sample_cnt/2 valid points where
140 : sample_cnt = trial-2*trim, so trim must stay small at low trials.
141 : At trial_cnt==1 sigma collapses to 0, so >=2 trials is the floor
142 : if a meaningful sigma is required. */
143 : run_config( "dev-alt (8 x 0.25ms)", 8UL, 1UL, 262144L, rep_cnt, ref );
144 : run_config( "dev-alt (4 x 0.5ms)", 4UL, 0UL, 524288L, rep_cnt, ref );
145 : run_config( "dev-alt (2 x 0.5ms)", 2UL, 0UL, 524288L, rep_cnt, ref );
146 :
147 : # else
148 : FD_LOG_WARNING(( "skip: no double" ));
149 : # endif
150 :
151 : FD_LOG_NOTICE(( "done" ));
152 : fd_halt();
153 : return 0;
154 : }
|