/*----- Data structures ---------------------------------------------------*/
struct bench_time {
- unsigned f;
-#define BTF_TIMEOK 1u
-#define BTF_CYOK 2u
-#define BTF_ANY (BTF_TIMEOK | BTF_CYOK)
- kludge64 s; uint32 ns;
- kludge64 cy;
+ unsigned f; /* flags */
+#define BTF_TIMEOK 1u /* @s@ ad @ns@ slots are value */
+#define BTF_CYOK 2u /* @cy@ slot is valid */
+#define BTF_ANY (BTF_TIMEOK | BTF_CYOK) /* some part is useful */
+ kludge64 s; uint32 ns; /* real time in seconds and nanos */
+ kludge64 cy; /* count of CPU cycles */
};
struct bench_timing {
- unsigned f;
- double n, t, cy;
+ unsigned f; /* flags (as in @struct bench_time@) */
+ double n, t, cy; /* count, time, and cycles */
};
struct bench_timer { const struct bench_timerops *ops; };
struct bench_timerops {
void (*now)(struct bench_timer */*bt*/, struct bench_time */*t_out*/);
+ /* Fill in @*t_out@ with the current time. v*/
+
void (*destroy)(struct bench_timer */*bt*/);
+ /* Release the timer and any resources it holds. */
};
struct bench_state {
- struct bench_timer *tm;
- double target_s;
- unsigned f;
- struct { double m, c; } clk, cy;
+ struct bench_timer *tm; /* a timer */
+ double target_s; /* target time to run benchmarks */
+ unsigned f; /* flags (@BTF_...@) for calibrations */
+ struct { double m, c; } clk, cy; /* calculated overheads */
};
-typedef void bench_fn(unsigned long /*n*/, void */*p*/);
+typedef void bench_fn(unsigned long /*n*/, void */*ctx*/);
+/* Run the benchmark @n@ times, given a context pointer @ctx@. */
/*----- Functions provided ------------------------------------------------*/
+/* --- @bench_createtimer@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: A freshly constructed standard timer object.
+ *
+ * Use: Allocate a timer. Dispose of it by calling
+ * @tm->ops->destroy(tm)@ when you're done.
+ */
+
extern struct bench_timer *bench_createtimer(void);
+/* --- @bench_init@ --- *
+ *
+ * Arguments: @struct bench_state *b@ = bench state to initialize
+ * @struct bench_timer *tm@ = timer to attach
+ *
+ * Returns: ---
+ *
+ * Use: Initialize the benchmark state. It still needs to be
+ * calibrated (use @bench_calibrate@) before it can be used, but
+ * this will be done automatically by @bench_measure@ if it's
+ * not done by hand earlier. The timer is now owned by the
+ * benchmark state and will be destroyed by @bench_destroy@.
+ */
+
extern void bench_init(struct bench_state */*b*/,
struct bench_timer */*tm*/);
+/* --- @bench_destroy@ --- *
+ *
+ * Arguments: @struct bench_state *b@ = bench state
+ *
+ * Returns: ---
+ *
+ * Use: Destroy the benchmark state, releasing the resources that it
+ * holds.
+ */
+
extern void bench_destroy(struct bench_state */*b*/);
+/* --- @bench_calibrate@ --- *
+ *
+ * Arguments: @struct bench_state *b@ = bench state
+ *
+ * Returns: Zero on success, @-1@ if calibration failed.
+ *
+ * Use: Calibrate the benchmark state, so that it can be used to
+ * measure performance reasonably accurately.
+ */
+
extern int bench_calibrate(struct bench_state */*b*/);
+/* --- @bench_measure@ --- *
+ *
+ * Arguments: @struct bench_timing *t_out@ = where to leave the timing
+ * @struct bench_state *b@ = benchmark state
+ * @double base@ = number of internal units per call
+ * @bench_fn *fn@, @void *ctx@ = benchmark function to run
+ *
+ * Returns: Zero on success, @-1@ if timing failed.
+ *
+ * Use: Measure a function. The function @fn@ is called adaptively
+ * with an iteration count @n@ set so as to run for
+ * approximately @b->target_s@ seconds.
+ *
+ * The result is left in @*t_out@, with @t_out->n@ counting the
+ * final product of the iteration count and @base@ (which might,
+ * e.g., reflect the number of inner iterations the function
+ * performs, or the number of bytes it processes per iteration).
+ */
+
extern int bench_measure(struct bench_timing */*t_out*/,
struct bench_state */*b*/,
- double /*base*/, bench_fn */*fn*/, void */*p*/);
+ double /*base*/, bench_fn */*fn*/, void */*ctx*/);
/*----- That's all, folks -------------------------------------------------*/