{
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);
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. */