@@@ tvec doc wip
[mLib] / test / tvec-bench.c
index 7086e14..c1d8cc0 100644 (file)
@@ -81,6 +81,110 @@ static void normalize(double *x_inout, const char **unit_out, double scale)
   *x_inout = x; *unit_out = *u;
 }
 
+/* --- @benchloop_...@ --- *
+ *
+ * Arguments:  @unsigned long n@ = iteration count
+ *             @void *ctx@ = benchmark running context
+ *
+ * Returns:    ---
+ *
+ * Use:                Run various kinds of benchmarking loops.
+ *
+ *               * The @..._outer_...@ functions call the underlying
+ *                 function @n@ times in a loop; by contrast, the
+ *                 @..._inner_...@ functions set a register value to the
+ *                 chosen iteration count and expect the underlying function
+ *                 to perform the loop itself.
+ *
+ *               * The @..._direct@ functions just call the underlying test
+ *                 function directly (though still through an `indirect
+ *                 jump' instruction); by contrast, the @..._indirect@
+ *                 functions invoke a subsidiary environment's @run@
+ *                 function, which adds additional overhead.
+ */
+
+static void benchloop_outer_direct(unsigned long n, void *ctx)
+{
+  struct benchrun *r = ctx;
+  tvec_testfn *fn = r->fn; void *tctx = r->ctx;
+  const struct tvec_reg *in = r->in; struct tvec_reg *out = r->out;
+
+  while (n--) fn(in, out, tctx);
+}
+
+static void benchloop_inner_direct(unsigned long n, void *ctx)
+  { struct benchrun *r = ctx; *r->n = n; r->fn(r->in, r->out, r->ctx); }
+
+static void benchloop_outer_indirect(unsigned long n, void *ctx)
+{
+  struct benchrun *r = ctx;
+  struct tvec_state *tv = r->tv;
+  void (*run)(struct tvec_state *, tvec_testfn, void *) = r->env->run;
+  tvec_testfn *fn = r->fn; void *tctx = r->ctx;
+
+  while (n--) run(tv, fn, tctx);
+}
+
+static void benchloop_inner_indirect(unsigned long n, void *ctx)
+  { struct benchrun *r = ctx; *r->n = n; r->env->run(r->tv, r->fn, r->ctx); }
+
+/*----- Output utilities --------------------------------------------------*/
+
+/* --- @tvec_benchreport@ --- *
+ *
+ * Arguments:  @const struct gprintf_ops *gops@ = print operations
+ *             @void *go@ = print destination
+ *             @unsigned unit@ = the unit being measured (~TVBU_...@)
+ *             @const struct bench_timing *tm@ = the benchmark result
+ *
+ * Returns:    ---
+ *
+ * Use:                Formats a report about the benchmark performance.  This
+ *             function is intended to be called on by an output
+ *             @ebench@ function.
+ */
+
+void tvec_benchreport(const struct gprintf_ops *gops, void *go,
+                     unsigned unit, const struct bench_timing *tm)
+{
+  double scale, x, n = tm->n;
+  const char *u, *what, *whats;
+
+  if (!tm) { gprintf(gops, go, "benchmark FAILED"); return; }
+
+  assert(tm->f&BTF_TIMEOK);
+
+  switch (unit) {
+    case TVBU_OP:
+      gprintf(gops, go, "%.0f iterations ", n);
+      what = "op"; whats = "ops"; scale = 1000;
+      break;
+    case TVBU_BYTE:
+      x = n; normalize(&x, &u, 1024); gprintf(gops, go, "%.3f %sB ", x, u);
+      what = whats = "B"; scale = 1024;
+      break;
+    default:
+      abort();
+  }
+
+  x = tm->t; normalize(&x, &u, 1000);
+  gprintf(gops, go, "in %.3f %ss", x, u);
+  if (tm->f&BTF_CYOK) {
+    x = tm->cy; normalize(&x, &u, 1000);
+    gprintf(gops, go, " (%.3f %scy)", x, u);
+  }
+  gprintf(gops, go, ": ");
+
+  x = n/tm->t; normalize(&x, &u, scale);
+  gprintf(gops, go, "%.3f %s%s/s", x, u, whats);
+  x = tm->t/n; normalize(&x, &u, 1000);
+  gprintf(gops, go, ", %.3f %ss/%s", x, u, what);
+  if (tm->f&BTF_CYOK) {
+    x = tm->cy/n; normalize(&x, &u, 1000);
+    gprintf(gops, go, " (%.3f %scy/%s)", x, u, what);
+  }
+}
+
 /*----- Benchmark environment scaffolding ---------------------------------*/
 
 /* --- @tvec_benchsetup@ --- *
@@ -145,7 +249,8 @@ fail_timer:
  *             @const char *var@ = variable name to set
  *             @void *ctx@ = context pointer
  *
- * Returns:    Zero on success, @-1@ on failure.
+ * Returns:    %$+1$% on success, %$0$% if the variable name was not
+ *             recognized, or %$-1$% on any other error.
  *
  * Use:                Set a special variable.  The following special variables are
  *             supported.
@@ -198,109 +303,6 @@ void tvec_benchbefore(struct tvec_state *tv, void *ctx)
   if (subenv && subenv->before) subenv->before(tv, bc->subctx);
 }
 
-/* --- @tvec_benchafter@ --- *
- *
- * Arguments:  @struct tvec_state *tv@ = test vector state
- *             @void *ctx@ = context pointer
- *
- * Returns:    ---
- *
- * Use:                Invoke the subordinate environment's @after@ function to
- *             clean up after the benchmark.
- */
-
-void tvec_benchafter(struct tvec_state *tv, void *ctx)
-{
-  struct tvec_benchctx *bc = ctx;
-  const struct tvec_benchenv *be = bc->be;
-  const struct tvec_env *subenv = be->env;
-
-  /* Restore the benchmark state's old target. */
-  bc->bst->target_s = bc->dflt_target;
-  bc->f &= ~TVBF_SETTRG;
-
-  /* Pass the call on to the subsidiary environment. */
-  if (subenv && subenv->after) subenv->after(tv, bc->subctx);
-}
-
-/* --- @tvec_benchteardown@ --- *
- *
- * Arguments:  @struct tvec_state *tv@ = test vector state
- *             @void *ctx@ = context pointer
- *
- * Returns:    ---
- *
- * Use:                Tear down the benchmark environment.
- */
-
-void tvec_benchteardown(struct tvec_state *tv, void *ctx)
-{
-  struct tvec_benchctx *bc = ctx;
-  const struct tvec_benchenv *be;
-  const struct tvec_env *subenv;
-
-  be = bc->be; subenv = be->env;
-
-  /* Tear down any subsidiary environment. */
-  if (subenv && subenv->teardown)
-    subenv->teardown(tv, bc->subctx);
-
-  /* If the benchmark state was temporary, then dispose of it. */
-  if (bc->bst) {
-    if (be->bst) bc->bst->target_s = bc->dflt_target;
-    else { bench_destroy(bc->bst); xfree(bc->bst); }
-  }
-}
-
-/*----- Measurement machinery ---------------------------------------------*/
-
-/* --- @benchloop_...@ --- *
- *
- * Arguments:  @unsigned long n@ = iteration count
- *             @void *ctx@ = benchmark running context
- *
- * Returns:    ---
- *
- * Use:                Run various kinds of benchmarking loops.
- *
- *               * The @..._outer_...@ functions call the underlying
- *                 function @n@ times in a loop; by contrast, the
- *                 @..._inner_...@ functions set a register value to the
- *                 chosen iteration count and expect the underlying function
- *                 to perform the loop itself.
- *
- *               * The @..._direct@ functions just call the underlying test
- *                 function directly (though still through an `indirect
- *                 jump' instruction); by contrast, the @..._indirect@
- *                 functions invoke a subsidiary environment's @run@
- *                 function, which adds additional overhead.
- */
-
-static void benchloop_outer_direct(unsigned long n, void *ctx)
-{
-  struct benchrun *r = ctx;
-  tvec_testfn *fn = r->fn; void *tctx = r->ctx;
-  const struct tvec_reg *in = r->in; struct tvec_reg *out = r->out;
-
-  while (n--) fn(in, out, tctx);
-}
-
-static void benchloop_inner_direct(unsigned long n, void *ctx)
-  { struct benchrun *r = ctx; *r->n = n; r->fn(r->in, r->out, r->ctx); }
-
-static void benchloop_outer_indirect(unsigned long n, void *ctx)
-{
-  struct benchrun *r = ctx;
-  struct tvec_state *tv = r->tv;
-  void (*run)(struct tvec_state *, tvec_testfn, void *) = r->env->run;
-  tvec_testfn *fn = r->fn; void *tctx = r->ctx;
-
-  while (n--) run(tv, fn, tctx);
-}
-
-static void benchloop_inner_indirect(unsigned long n, void *ctx)
-  { struct benchrun *r = ctx; *r->n = n; r->env->run(r->tv, r->fn, r->ctx); }
-
 /* --- @tvec_benchrun@ --- *
  *
  * Arguments:  @struct tvec_state *tv@ = test vector state
@@ -370,60 +372,57 @@ void tvec_benchrun(struct tvec_state *tv, tvec_testfn *fn, void *ctx)
 #undef f_any
 }
 
-/*----- Output utilities --------------------------------------------------*/
-
-/* --- @tvec_benchreport@ --- *
+/* --- @tvec_benchafter@ --- *
  *
- * Arguments:  @const struct gprintf_ops *gops@ = print operations
- *             @void *go@ = print destination
- *             @unsigned unit@ = the unit being measured (~TVBU_...@)
- *             @const struct bench_timing *tm@ = the benchmark result
+ * Arguments:  @struct tvec_state *tv@ = test vector state
+ *             @void *ctx@ = context pointer
  *
  * Returns:    ---
  *
- * Use:                Formats a report about the benchmark performance.  This
- *             function is intended to be called on by an output
- *             @ebench@ function.
+ * Use:                Invoke the subordinate environment's @after@ function to
+ *             clean up after the benchmark.
  */
 
-void tvec_benchreport(const struct gprintf_ops *gops, void *go,
-                     unsigned unit, const struct bench_timing *tm)
+void tvec_benchafter(struct tvec_state *tv, void *ctx)
 {
-  double scale, x, n = tm->n;
-  const char *u, *what, *whats;
+  struct tvec_benchctx *bc = ctx;
+  const struct tvec_benchenv *be = bc->be;
+  const struct tvec_env *subenv = be->env;
 
-  if (!tm) { gprintf(gops, go, "benchmark FAILED"); return; }
+  /* Restore the benchmark state's old target. */
+  bc->bst->target_s = bc->dflt_target;
+  bc->f &= ~TVBF_SETTRG;
 
-  assert(tm->f&BTF_TIMEOK);
+  /* Pass the call on to the subsidiary environment. */
+  if (subenv && subenv->after) subenv->after(tv, bc->subctx);
+}
 
-  switch (unit) {
-    case TVBU_OP:
-      gprintf(gops, go, "%.0f iterations ", n);
-      what = "op"; whats = "ops"; scale = 1000;
-      break;
-    case TVBU_BYTE:
-      x = n; normalize(&x, &u, 1024); gprintf(gops, go, "%.3f %sB ", x, u);
-      what = whats = "B"; scale = 1024;
-      break;
-    default:
-      abort();
-  }
+/* --- @tvec_benchteardown@ --- *
+ *
+ * Arguments:  @struct tvec_state *tv@ = test vector state
+ *             @void *ctx@ = context pointer
+ *
+ * Returns:    ---
+ *
+ * Use:                Tear down the benchmark environment.
+ */
 
-  x = tm->t; normalize(&x, &u, 1000);
-  gprintf(gops, go, "in %.3f %ss", x, u);
-  if (tm->f&BTF_CYOK) {
-    x = tm->cy; normalize(&x, &u, 1000);
-    gprintf(gops, go, " (%.3f %scy)", x, u);
-  }
-  gprintf(gops, go, ": ");
+void tvec_benchteardown(struct tvec_state *tv, void *ctx)
+{
+  struct tvec_benchctx *bc = ctx;
+  const struct tvec_benchenv *be;
+  const struct tvec_env *subenv;
 
-  x = n/tm->t; normalize(&x, &u, scale);
-  gprintf(gops, go, "%.3f %s%s/s", x, u, whats);
-  x = tm->t/n; normalize(&x, &u, 1000);
-  gprintf(gops, go, ", %.3f %ss/%s", x, u, what);
-  if (tm->f&BTF_CYOK) {
-    x = tm->cy/n; normalize(&x, &u, 1000);
-    gprintf(gops, go, " (%.3f %scy/%s)", x, u, what);
+  be = bc->be; subenv = be->env;
+
+  /* Tear down any subsidiary environment. */
+  if (subenv && subenv->teardown)
+    subenv->teardown(tv, bc->subctx);
+
+  /* If the benchmark state was temporary, then dispose of it. */
+  if (bc->bst) {
+    if (be->bst) bc->bst->target_s = bc->dflt_target;
+    else { bench_destroy(bc->bst); xfree(bc->bst); }
   }
 }