@@@ fltfmt mess
[mLib] / test / tvec-bench.h
diff --git a/test/tvec-bench.h b/test/tvec-bench.h
new file mode 100644 (file)
index 0000000..4125e11
--- /dev/null
@@ -0,0 +1,243 @@
+/* -*-c-*-
+ *
+ * Test-vector framework benchmark extension
+ *
+ * (c) 2024 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the mLib utilities library.
+ *
+ * mLib is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * mLib is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with mLib.  If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#ifndef MLIB_TVEC_BENCH_H
+#define MLIB_TVEC_BENCH_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#ifndef MLIB_BENCH_H
+#  include "bench.h"
+#endif
+
+#ifndef MLIB_CONTROL_H
+#  include "control.h"
+#endif
+
+#ifndef MLIB_GPRINTF_H
+#  include "gprintf.h"
+#endif
+
+#ifndef MLIB_TVEC_H
+#  include "tvec.h"
+#endif
+
+#ifndef MLIB_TVEC_OUTPUT_H
+#  include "tvec-output.h"
+#endif
+
+/*----- Test environment --------------------------------------------------*/
+
+struct tvec_benchenv {
+  /* Benchmark environment definition. */
+
+  struct tvec_env _env;                        /* benchmarking is an environment */
+  struct bench_state **bst;            /* benchmark state anchor or null */
+  unsigned long niter;                 /* iterations done per unit */
+  int riter, rbuf;                     /* iterations and buffer registers */
+  const struct tvec_env *env;          /* subordinate environment */
+};
+
+struct tvec_benchctx {
+  /* Benchmark environment context; private. */
+
+  const struct tvec_benchenv *be;      /* environment configuration */
+  struct bench_state *bst;             /* benchmark state */
+  double dflt_target;                  /* default time in seconds */
+  unsigned f;                          /* flags */
+#define TVBF_SETTRG 1u                 /*   set `@target' */
+#define TVBF_SETMASK (TVBF_SETTRG))    /*   mask of @TVBF_SET...@ */
+  void *subctx;                                /* subordinate environment context */
+};
+
+/* --- Environment implementation --- *
+ *
+ * The following special variables are supported.
+ *
+ *   * %|@target|% is the (approximate) number of seconds to run the
+ *     benchmark.
+ *
+ * Unrecognized variables are passed to the subordinate environment, if there
+ * is one.  Other events are passed through to the subordinate environment.
+ */
+
+extern tvec_envsetupfn tvec_benchsetup;
+extern tvec_envfindvarfn tvec_benchfindvar;
+extern tvec_envbeforefn tvec_benchbefore;
+extern tvec_envrunfn tvec_benchrun;
+extern tvec_envafterfn tvec_benchafter;
+extern tvec_envteardownfn tvec_benchteardown;
+
+#define TVEC_BENCHENV                                                  \
+  { sizeof(struct tvec_benchctx),                                      \
+    tvec_benchsetup,                                                   \
+    tvec_benchfindvar,                                                 \
+    tvec_benchbefore,                                                  \
+    tvec_benchrun,                                                     \
+    tvec_benchafter,                                                   \
+    tvec_benchteardown }
+#define TVEC_BENCHINIT TVEC_BENCHENV, &tvec_benchstate
+
+/*----- Benchmark output extension ----------------------------------------*/
+
+#define TVEC_BENCHOUTEXT "tvec-bench"
+
+struct tvec_benchoutops {
+  /* Output extension for benchmarking.  The name for this extension is
+   * %|tvec-bench|%.
+   */
+
+  void (*bbench)(struct tvec_output */*o*/,
+                const char */*desc*/, unsigned /*unit*/);
+    /* Begin a benchmark.  If the description @desc@ is null -- which it will
+     * be unless we're doing adhoc testing, then the output driver should
+     * label its benchmark output, e.g., by dumping the values of the input
+     * registers marked @TVRF_ID@.  The @unit@ is one of the @BTU_...@
+     * constants explaining what sort of thing is being measured.
+     */
+
+  void (*ebench)(struct tvec_output */*o*/,
+                const char */*desc*/, unsigned /*unit*/,
+                const struct bench_timing */*t*/);
+    /* End a benchmark.  The @unit@ argument is as for @bbench@.  If @tm@ is
+     * zero then the measurement failed; otherwise @tm->n@ counts total
+     * number of things (operations or bytes, as indicated by @unit@)
+     * processed in the indicated time.
+     */
+};
+
+extern const struct tvec_benchoutops tvec_benchoutputfallback;
+  /* Fallback operations for benchmark output.  The @o@ argument is a pointer
+   * to a @struct tvec_fallbackoutput@.
+   */
+
+/*----- Global variables --------------------------------------------------*/
+
+extern struct bench_state *tvec_benchstate; /* default benchmark state */
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @TVEC_BENCHMARK@, @TVEC_BENCHMARK_TAG@ --- *
+ *
+ * Arguments:  @const char *desc@ = a description of the benchmark
+ *             @struct bench_state **bst_inout@ = benchmark state (updated)
+ *             @unsigned unit@ = unit being measured (@BTU_...@ code)
+ *             @double base@ = number of units per external iteration
+ *
+ * Returns:    ---
+ *
+ * Use:
+ */
+
+#define TVEC_BENCHMARK_DECLS                                           \
+  struct tvec_state *_tvbench_tv;                                      \
+  struct tvec_fallbackoutput _tvbench_fo;                              \
+  const struct tvec_benchoutops *_tvbench_bo;                          \
+  struct tvec_output *_tvbench_o;                                      \
+  const char *_tvbench_desc;                                           \
+  unsigned _tvbench_unit;                                              \
+  struct bench_timing _tvbench_tm;                                     \
+  int _tvbench_rc;                                                     \
+  BENCH_MEASURE_DECLS
+
+#define TVEC_BENCHMARK_TAG(tag, desc, tv, bst, unit, base)             \
+  MC_BEFORE(tag##__tvbench_setup, {                                    \
+    _tvbench_tv = (tv);                                                        \
+    _tvbench_bo = tvec_outputext(_tvbench_tv, &_tvbench_o, &_tvbench_fo, \
+                                TVEC_BENCHOUTEXT,                      \
+                                &tvec_benchoutputfallback);            \
+    _tvbench_desc = (desc); _tvbench_unit = (unit);                    \
+    TVEC_BEGINTEST(_tvbench_tv);                                       \
+    _tvbench_bo->bbench(_tvbench_o, _tvbench_desc, _tvbench_unit);     \
+  })                                                                   \
+  MC_AFTER(tag##__tvbench_report, {                                    \
+    _tvbench_bo->ebench(_tvbench_o, _tvbench_desc, _tvbench_unit,      \
+                       _tvbench_rc ? 0 : &_tvbench_tm);                \
+    tvec_endtest(_tvbench_tv);                                         \
+  })                                                                   \
+  BENCH_MEASURE_TAG(tag##__tvbench_measure, (bst),                     \
+                   _tvbench_rc, &_tvbench_tm, (base))
+
+#define TVEC_BENCHMARK(desc, tv, bst, unit, base)                      \
+  TVEC_BENCHMARK_TAG(tvec_bench, desc, tv, bst, unit, base)
+
+/* --- @tvec_benchprep@ --- *
+ *
+ * Arguments:  @struct tvec_state *tv@ = test vector state
+ *             @struct bench_state **bst_inout@ = benchmark state (updated)
+ *             @unsigned f@ = calibration flags
+ *
+ * Returns:    Zero on success, %$-1$% on failure.
+ *
+ * Use:                If @*bst_inout@ is null then allocate and initialize a fresh
+ *             benchmark state with a default timer, and @*bst_inout@ is
+ *             updated to point to the fresh state.  The storage for the
+ *             state was allocated using the test vector state's arena.
+ *
+ *             If the benchmark state hasn't been calibrated, then this is
+ *             done, passing @f@ to @bench_calibrate@.
+ *
+ *             On failure, the test group is skipped, reporting a suitable
+ *             message, and %$-1$% is returned.  If a fresh benchmark state
+ *             was allocated, but calibration failed, the state is
+ *             %%\emph{not}%% released.
+ */
+
+extern int tvec_benchprep(struct tvec_state */*tv*/,
+                         struct bench_state **/*bst_inout*/,
+                         unsigned /*f*/);
+
+/* --- @tvec_benchreport@ --- *
+ *
+ * Arguments:  @const struct gprintf_ops *gops@ = print operations
+ *             @void *go@ = print destination
+ *             @unsigned unit@ = the unit being measured (@BTU_...@)
+ *             @unsigned style@ = output style (@TVSF_...@)
+ *             @const struct bench_timing *t@ = 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.
+ */
+
+extern void tvec_benchreport
+  (const struct gprintf_ops */*gops*/, void */*go*/,
+   unsigned /*unit*/, unsigned /*style*/, const struct bench_timing */*tm*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif