Commit | Line | Data |
---|---|---|
b1a20bee MW |
1 | /* -*-c-*- |
2 | * | |
3 | * Test-vector framework benchmark extension | |
4 | * | |
5 | * (c) 2024 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_TVEC_BENCH_H | |
29 | #define MLIB_TVEC_BENCH_H | |
30 | ||
31 | #ifdef __cplusplus | |
32 | extern "C" { | |
33 | #endif | |
34 | ||
35 | /*----- Header files ------------------------------------------------------*/ | |
36 | ||
37 | #ifndef MLIB_BENCH_H | |
38 | # include "bench.h" | |
39 | #endif | |
40 | ||
41 | #ifndef MLIB_CONTROL_H | |
42 | # include "control.h" | |
43 | #endif | |
44 | ||
45 | #ifndef MLIB_GPRINTF_H | |
46 | # include "gprintf.h" | |
47 | #endif | |
48 | ||
49 | #ifndef MLIB_TVEC_H | |
50 | # include "tvec.h" | |
51 | #endif | |
52 | ||
53 | #ifndef MLIB_TVEC_OUTPUT_H | |
54 | # include "tvec-output.h" | |
55 | #endif | |
56 | ||
57 | /*----- Test environment --------------------------------------------------*/ | |
58 | ||
59 | struct tvec_benchenv { | |
60 | /* Benchmark environment definition. */ | |
61 | ||
62 | struct tvec_env _env; /* benchmarking is an environment */ | |
63 | struct bench_state **bst; /* benchmark state anchor or null */ | |
64 | unsigned long niter; /* iterations done per unit */ | |
65 | int riter, rbuf; /* iterations and buffer registers */ | |
66 | const struct tvec_env *env; /* subordinate environment */ | |
67 | }; | |
68 | ||
69 | struct tvec_benchctx { | |
70 | /* Benchmark environment context; private. */ | |
71 | ||
72 | const struct tvec_benchenv *be; /* environment configuration */ | |
73 | struct bench_state *bst; /* benchmark state */ | |
74 | double dflt_target; /* default time in seconds */ | |
75 | unsigned f; /* flags */ | |
76 | #define TVBF_SETTRG 1u /* set `@target' */ | |
77 | #define TVBF_SETMASK (TVBF_SETTRG)) /* mask of @TVBF_SET...@ */ | |
78 | void *subctx; /* subordinate environment context */ | |
79 | }; | |
80 | ||
81 | /* --- Environment implementation --- * | |
82 | * | |
83 | * The following special variables are supported. | |
84 | * | |
85 | * * %|@target|% is the (approximate) number of seconds to run the | |
86 | * benchmark. | |
87 | * | |
88 | * Unrecognized variables are passed to the subordinate environment, if there | |
89 | * is one. Other events are passed through to the subordinate environment. | |
90 | */ | |
91 | ||
92 | extern tvec_envsetupfn tvec_benchsetup; | |
93 | extern tvec_envfindvarfn tvec_benchfindvar; | |
94 | extern tvec_envbeforefn tvec_benchbefore; | |
95 | extern tvec_envrunfn tvec_benchrun; | |
96 | extern tvec_envafterfn tvec_benchafter; | |
97 | extern tvec_envteardownfn tvec_benchteardown; | |
98 | ||
99 | #define TVEC_BENCHENV \ | |
100 | { sizeof(struct tvec_benchctx), \ | |
101 | tvec_benchsetup, \ | |
102 | tvec_benchfindvar, \ | |
103 | tvec_benchbefore, \ | |
104 | tvec_benchrun, \ | |
105 | tvec_benchafter, \ | |
106 | tvec_benchteardown } | |
107 | #define TVEC_BENCHINIT TVEC_BENCHENV, &tvec_benchstate | |
108 | ||
109 | /*----- Benchmark output extension ----------------------------------------*/ | |
110 | ||
111 | #define TVEC_BENCHOUTEXT "tvec-bench" | |
112 | ||
113 | struct tvec_benchoutops { | |
114 | /* Output extension for benchmarking. The name for this extension is | |
115 | * %|tvec-bench|%. | |
116 | */ | |
117 | ||
118 | void (*bbench)(struct tvec_output */*o*/, | |
119 | const char */*desc*/, unsigned /*unit*/); | |
120 | /* Begin a benchmark. If the description @desc@ is null -- which it will | |
121 | * be unless we're doing adhoc testing, then the output driver should | |
122 | * label its benchmark output, e.g., by dumping the values of the input | |
123 | * registers marked @TVRF_ID@. The @unit@ is one of the @BTU_...@ | |
124 | * constants explaining what sort of thing is being measured. | |
125 | */ | |
126 | ||
127 | void (*ebench)(struct tvec_output */*o*/, | |
128 | const char */*desc*/, unsigned /*unit*/, | |
129 | const struct bench_timing */*t*/); | |
130 | /* End a benchmark. The @unit@ argument is as for @bbench@. If @tm@ is | |
131 | * zero then the measurement failed; otherwise @tm->n@ counts total | |
132 | * number of things (operations or bytes, as indicated by @unit@) | |
133 | * processed in the indicated time. | |
134 | */ | |
135 | }; | |
136 | ||
137 | extern const struct tvec_benchoutops tvec_benchoutputfallback; | |
138 | /* Fallback operations for benchmark output. The @o@ argument is a pointer | |
139 | * to a @struct tvec_fallbackoutput@. | |
140 | */ | |
141 | ||
142 | /*----- Global variables --------------------------------------------------*/ | |
143 | ||
144 | extern struct bench_state *tvec_benchstate; /* default benchmark state */ | |
145 | ||
146 | /*----- Functions provided ------------------------------------------------*/ | |
147 | ||
148 | /* --- @TVEC_BENCHMARK@, @TVEC_BENCHMARK_TAG@ --- * | |
149 | * | |
150 | * Arguments: @const char *desc@ = a description of the benchmark | |
151 | * @struct bench_state **bst_inout@ = benchmark state (updated) | |
152 | * @unsigned unit@ = unit being measured (@BTU_...@ code) | |
153 | * @double base@ = number of units per external iteration | |
154 | * | |
155 | * Returns: --- | |
156 | * | |
157 | * Use: | |
158 | */ | |
159 | ||
160 | #define TVEC_BENCHMARK_DECLS \ | |
161 | struct tvec_state *_tvbench_tv; \ | |
162 | struct tvec_fallbackoutput _tvbench_fo; \ | |
163 | const struct tvec_benchoutops *_tvbench_bo; \ | |
164 | struct tvec_output *_tvbench_o; \ | |
165 | const char *_tvbench_desc; \ | |
166 | unsigned _tvbench_unit; \ | |
167 | struct bench_timing _tvbench_tm; \ | |
168 | int _tvbench_rc; \ | |
169 | BENCH_MEASURE_DECLS | |
170 | ||
171 | #define TVEC_BENCHMARK_TAG(tag, desc, tv, bst, unit, base) \ | |
172 | MC_BEFORE(tag##__tvbench_setup, { \ | |
173 | _tvbench_tv = (tv); \ | |
174 | _tvbench_bo = tvec_outputext(_tvbench_tv, &_tvbench_o, &_tvbench_fo, \ | |
175 | TVEC_BENCHOUTEXT, \ | |
176 | &tvec_benchoutputfallback); \ | |
177 | _tvbench_desc = (desc); _tvbench_unit = (unit); \ | |
178 | TVEC_BEGINTEST(_tvbench_tv); \ | |
179 | _tvbench_bo->bbench(_tvbench_o, _tvbench_desc, _tvbench_unit); \ | |
180 | }) \ | |
181 | MC_AFTER(tag##__tvbench_report, { \ | |
182 | _tvbench_bo->ebench(_tvbench_o, _tvbench_desc, _tvbench_unit, \ | |
183 | _tvbench_rc ? 0 : &_tvbench_tm); \ | |
184 | tvec_endtest(_tvbench_tv); \ | |
185 | }) \ | |
186 | BENCH_MEASURE_TAG(tag##__tvbench_measure, (bst), \ | |
187 | _tvbench_rc, &_tvbench_tm, (base)) | |
188 | ||
189 | #define TVEC_BENCHMARK(desc, tv, bst, unit, base) \ | |
190 | TVEC_BENCHMARK_TAG(tvec_bench, desc, tv, bst, unit, base) | |
191 | ||
192 | /* --- @tvec_benchprep@ --- * | |
193 | * | |
194 | * Arguments: @struct tvec_state *tv@ = test vector state | |
195 | * @struct bench_state **bst_inout@ = benchmark state (updated) | |
196 | * @unsigned f@ = calibration flags | |
197 | * | |
198 | * Returns: Zero on success, %$-1$% on failure. | |
199 | * | |
200 | * Use: If @*bst_inout@ is null then allocate and initialize a fresh | |
201 | * benchmark state with a default timer, and @*bst_inout@ is | |
202 | * updated to point to the fresh state. The storage for the | |
203 | * state was allocated using the test vector state's arena. | |
204 | * | |
205 | * If the benchmark state hasn't been calibrated, then this is | |
206 | * done, passing @f@ to @bench_calibrate@. | |
207 | * | |
208 | * On failure, the test group is skipped, reporting a suitable | |
209 | * message, and %$-1$% is returned. If a fresh benchmark state | |
210 | * was allocated, but calibration failed, the state is | |
211 | * %%\emph{not}%% released. | |
212 | */ | |
213 | ||
214 | extern int tvec_benchprep(struct tvec_state */*tv*/, | |
215 | struct bench_state **/*bst_inout*/, | |
216 | unsigned /*f*/); | |
217 | ||
218 | /* --- @tvec_benchreport@ --- * | |
219 | * | |
220 | * Arguments: @const struct gprintf_ops *gops@ = print operations | |
221 | * @void *go@ = print destination | |
222 | * @unsigned unit@ = the unit being measured (@BTU_...@) | |
223 | * @unsigned style@ = output style (@TVSF_...@) | |
224 | * @const struct bench_timing *t@ = the benchmark result | |
225 | * | |
226 | * Returns: --- | |
227 | * | |
228 | * Use: Formats a report about the benchmark performance. This | |
229 | * function is intended to be called on by an output @ebench@ | |
230 | * function. | |
231 | */ | |
232 | ||
233 | extern void tvec_benchreport | |
234 | (const struct gprintf_ops */*gops*/, void */*go*/, | |
235 | unsigned /*unit*/, unsigned /*style*/, const struct bench_timing */*tm*/); | |
236 | ||
237 | /*----- That's all, folks -------------------------------------------------*/ | |
238 | ||
239 | #ifdef __cplusplus | |
240 | } | |
241 | #endif | |
242 | ||
243 | #endif |