@@@ tvec doc wip
[mLib] / test / bench.c
index 345944b..1643e55 100644 (file)
@@ -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. */