X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/31d0247cc58abc0b0720aa7e9972011c5a66995c..c81c35dfd10050ffef85d57dc2ad73f52f38a3f2:/test/bench.c diff --git a/test/bench.c b/test/bench.c index 345944b..1643e55 100644 --- a/test/bench.c +++ b/test/bench.c @@ -648,12 +648,23 @@ int bench_measure(struct bench_timing *t_out, struct bench_state *b, { struct bench_timer *tm = b->tm; struct bench_time t0, t1; - unsigned long n; + unsigned long n, nn; /* Make sure the state is calibrated. */ if (bench_calibrate(b)) return (-1); - /* Main adaptive measurement loop. */ + /* Main adaptive measurement loop. + * + * Suppose the timer loop %$n$% iterations in %$t$% seconds. Our ideal + * time is %$T$% seconds. If %$t \ge T/\sqrt{2}$%, we're happy. + * Otherwise, we need to scale up the iteration count. The obvious next + * choice is %$n' = n T/t$%. Alas, rounding is a problem: if + * %$T/t < 1 + 1/n$% then %$\floor{n T/t} = n$% and we will make no + * progress. We know that %$T/t > \sqrt{2}%, so this can only happen when + * %$1 + 1/n > \sqrt{2}$%, i.e., when %$n < \sqrt{2} + 1$%. On the other + * hand, if %$T/t < 1 + 1/n$% then %$t (n + 1)/n > T$%, so just trying + * again with %$n' = n + 1$% iterations will very likely work. + */ debug("measuring..."); n = 1; for (;;) { tm->ops->now(tm, &t0); fn(n, ctx); tm->ops->now(tm, &t1); @@ -661,8 +672,10 @@ int bench_measure(struct bench_timing *t_out, struct bench_state *b, if (!(t_out->f&BTF_TIMEOK)) return (-1); if (!(t_out->f&BTF_CYOK)) debug(" n = %10lu; t = %12g", n, t_out->t); else debug(" n = %10lu; t = %12g, cy = %10.0f", n, t_out->t, t_out->cy); - if (t_out->t >= 0.72*b->target_s) break; - n *= 1.44*b->target_s/t_out->t; + if (t_out->t >= 0.707*b->target_s) break; + nn = n*b->target_s/t_out->t; + if (nn > n) n = nn; + else n++; } /* Adjust according to the calibration. */