--- /dev/null
+/* -*-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