Commit | Line | Data |
---|---|---|
b64eb60f MW |
1 | /* -*-c-*- |
2 | * | |
3 | * Benchmarking support | |
4 | * | |
5 | * (c) 2023 Straylight/Edgeware | |
6 | */ | |
7 | ||
8 | /*----- Licensing notice --------------------------------------------------* | |
9 | * | |
10 | * This file is part of the mLib utilities library. | |
11 | * | |
12 | * mLib is free software: you can redistribute it and/or modify it under | |
13 | * the terms of the GNU Library General Public License as published by | |
14 | * the Free Software Foundation; either version 2 of the License, or (at | |
15 | * your option) any later version. | |
16 | * | |
17 | * mLib is distributed in the hope that it will be useful, but WITHOUT | |
18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
19 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | |
20 | * License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU Library General Public | |
23 | * License along with mLib. If not, write to the Free Software | |
24 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |
25 | * USA. | |
26 | */ | |
27 | ||
28 | #ifndef MLIB_BENCH_H | |
29 | #define MLIB_BENCH_H | |
30 | ||
31 | #ifdef __cplusplus | |
32 | extern "C" { | |
33 | #endif | |
34 | ||
35 | /*----- Header files ------------------------------------------------------*/ | |
36 | ||
6e683a79 MW |
37 | #include <time.h> |
38 | ||
b64eb60f MW |
39 | #ifndef MLIB_BITS_H |
40 | # include "bits.h" | |
41 | #endif | |
42 | ||
13ee7406 MW |
43 | #ifndef MLIB_DSTR_H |
44 | # include "dstr.h" | |
45 | #endif | |
46 | ||
b64eb60f MW |
47 | /*----- Data structures ---------------------------------------------------*/ |
48 | ||
49 | struct bench_time { | |
67b5031e MW |
50 | unsigned f; /* flags */ |
51 | #define BTF_TIMEOK 1u /* @s@ ad @ns@ slots are value */ | |
52 | #define BTF_CYOK 2u /* @cy@ slot is valid */ | |
53 | #define BTF_ANY (BTF_TIMEOK | BTF_CYOK) /* some part is useful */ | |
6e683a79 MW |
54 | union { |
55 | struct { kludge64 s; uint32 ns; } ts; /* @struct timespec@-ish */ | |
56 | clock_t clk; /* @clock@ */ | |
57 | kludge64 rawns; /* raw nanosecond count */ | |
58 | } t; /* time */ | |
c91413e6 | 59 | kludge64 cy; /* count of CPU cycles */ |
b64eb60f MW |
60 | }; |
61 | ||
62 | struct bench_timing { | |
c91413e6 | 63 | unsigned f; /* flags (@BTF_...@) */ |
67b5031e | 64 | double n, t, cy; /* count, time, and cycles */ |
b64eb60f MW |
65 | }; |
66 | ||
67 | struct bench_timer { const struct bench_timerops *ops; }; | |
68 | ||
69 | struct bench_timerops { | |
13ee7406 MW |
70 | void (*describe)(struct bench_timer */*bt*/, dstr */*d*/); |
71 | /* Write a description of the timer to @d@. */ | |
72 | ||
6e683a79 MW |
73 | int (*now)(struct bench_timer */*bt*/, struct bench_time */*t_out*/, |
74 | unsigned /*f*/); | |
75 | #define BTF_T0 0u /* fetching first time of a pair */ | |
76 | #define BTF_T1 1u /* fetching second time of a pair */ | |
77 | /* Fill in @*t_out@ with the current time. Return zero on success | |
78 | * %%\emph{or} permanent failure; return %$-1$% on temporary failure. | |
79 | */ | |
80 | ||
81 | void (*diff)(struct bench_timer */*bt*/, | |
82 | struct bench_timing */*delta_out*/, | |
83 | const struct bench_time */*t0*/, | |
84 | const struct bench_time */*t1*/); | |
85 | /* Subtract the time @t0@ from the time @t1@, leaving the result in | |
86 | * @*delta_out@, setting flags as appropriate. | |
87 | */ | |
67b5031e | 88 | |
b64eb60f | 89 | void (*destroy)(struct bench_timer */*bt*/); |
67b5031e | 90 | /* Release the timer and any resources it holds. */ |
b64eb60f MW |
91 | }; |
92 | ||
93 | struct bench_state { | |
67b5031e MW |
94 | struct bench_timer *tm; /* a timer */ |
95 | double target_s; /* target time to run benchmarks */ | |
c91413e6 | 96 | unsigned f; /* calibration flags (@BTF_...@) */ |
13ee7406 | 97 | #define BTF_CLB 0x0100 /* tried calibrating */ |
67b5031e | 98 | struct { double m, c; } clk, cy; /* calculated overheads */ |
b64eb60f MW |
99 | }; |
100 | ||
67b5031e | 101 | typedef void bench_fn(unsigned long /*n*/, void */*ctx*/); |
c91413e6 | 102 | /* Run the benchmark @n@ times, given a context pointer @ctx@. */ |
b64eb60f MW |
103 | |
104 | /*----- Functions provided ------------------------------------------------*/ | |
105 | ||
67b5031e MW |
106 | /* --- @bench_createtimer@ --- * |
107 | * | |
13ee7406 | 108 | * Arguments: @const char *config@ = user-supplied configuration string |
67b5031e | 109 | * |
13ee7406 MW |
110 | * Returns: A freshly constructed standard timer object, or null on |
111 | * failure. | |
67b5031e MW |
112 | * |
113 | * Use: Allocate a timer. Dispose of it by calling | |
114 | * @tm->ops->destroy(tm)@ when you're done. | |
13ee7406 MW |
115 | * |
116 | * Applications should not set configuration strings except as | |
117 | * established by user action, e.g., from a command-line option, | |
118 | * environment variable, or configuration file. | |
67b5031e MW |
119 | */ |
120 | ||
13ee7406 | 121 | extern struct bench_timer *bench_createtimer(const char *config); |
b64eb60f | 122 | |
67b5031e MW |
123 | /* --- @bench_init@ --- * |
124 | * | |
125 | * Arguments: @struct bench_state *b@ = bench state to initialize | |
13ee7406 | 126 | * @struct bench_timer *tm@ = timer to attach, or null |
67b5031e | 127 | * |
13ee7406 MW |
128 | * Returns: Zero on success, %$-1$% on failure. |
129 | * | |
130 | * Use: Initialize the benchmark state. On success, the timer state | |
131 | * still needs to be calibrated (use @bench_calibrate@) before | |
132 | * it can be used, but this will be done automatically by | |
133 | * @bench_measure@ if it's not done by hand earlier. The timer | |
134 | * is now owned by the benchmark state and will be destroyed by | |
135 | * @bench_destroy@. | |
67b5031e | 136 | * |
13ee7406 MW |
137 | * The only reason for failure is if @tm@ was null on entry, |
138 | * and automatic construction of a timer failed. The state is | |
139 | * safe to discard, but calling @bench_destroy@ is safe too. | |
67b5031e MW |
140 | */ |
141 | ||
13ee7406 | 142 | extern int bench_init(struct bench_state */*b*/, struct bench_timer */*tm*/); |
b64eb60f | 143 | |
67b5031e MW |
144 | /* --- @bench_destroy@ --- * |
145 | * | |
146 | * Arguments: @struct bench_state *b@ = bench state | |
147 | * | |
148 | * Returns: --- | |
149 | * | |
150 | * Use: Destroy the benchmark state, releasing the resources that it | |
151 | * holds. | |
152 | */ | |
153 | ||
e63124bc | 154 | extern void bench_destroy(struct bench_state */*b*/); |
b64eb60f | 155 | |
67b5031e MW |
156 | /* --- @bench_calibrate@ --- * |
157 | * | |
158 | * Arguments: @struct bench_state *b@ = bench state | |
159 | * | |
13ee7406 | 160 | * Returns: Zero on success, %$-1$% if calibration failed. |
67b5031e MW |
161 | * |
162 | * Use: Calibrate the benchmark state, so that it can be used to | |
163 | * measure performance reasonably accurately. | |
164 | */ | |
165 | ||
b64eb60f MW |
166 | extern int bench_calibrate(struct bench_state */*b*/); |
167 | ||
67b5031e MW |
168 | /* --- @bench_measure@ --- * |
169 | * | |
8d372122 MW |
170 | * Arguments: @struct bench_state *b@ = benchmark state |
171 | * @struct bench_timing *t_out@ = where to leave the timing | |
67b5031e MW |
172 | * @double base@ = number of internal units per call |
173 | * @bench_fn *fn@, @void *ctx@ = benchmark function to run | |
174 | * | |
13ee7406 | 175 | * Returns: Zero on success, %$-1$% if timing failed. |
67b5031e MW |
176 | * |
177 | * Use: Measure a function. The function @fn@ is called adaptively | |
178 | * with an iteration count @n@ set so as to run for | |
179 | * approximately @b->target_s@ seconds. | |
180 | * | |
181 | * The result is left in @*t_out@, with @t_out->n@ counting the | |
182 | * final product of the iteration count and @base@ (which might, | |
183 | * e.g., reflect the number of inner iterations the function | |
184 | * performs, or the number of bytes it processes per iteration). | |
185 | */ | |
186 | ||
8d372122 MW |
187 | extern int bench_measure(struct bench_state */*b*/, |
188 | struct bench_timing */*t_out*/, | |
67b5031e | 189 | double /*base*/, bench_fn */*fn*/, void */*ctx*/); |
b64eb60f MW |
190 | |
191 | /*----- That's all, folks -------------------------------------------------*/ | |
192 | ||
193 | #ifdef __cplusplus | |
194 | } | |
195 | #endif | |
196 | ||
197 | #endif |