source: benchmark/readyQ/rq_bench.hpp@ 509ec82

Last change on this file since 509ec82 was 8faa6612, checked in by Thierry Delisle <tdelisle@…>, 3 years ago

Minor fixes to how benchmarks handle yes/no arguments

  • Property mode set to 100644
File size: 11.4 KB
Line 
1#include <cassert>
2#include <climits>
3#include <cstdint>
4#include <cstdio>
5
6#include <time.h> // timespec
7#include <sys/time.h> // timeval
8
9typedef __uint128_t __lehmer64_state_t;
10static inline uint64_t __lehmer64( __lehmer64_state_t & state ) {
11 state *= 0xda942042e4dd58b5;
12 return state >> 64;
13}
14
15enum { TIMEGRAN = 1000000000LL }; // nanosecond granularity, except for timeval
16
17
18volatile bool stop = false;
19bool clock_mode;
20double duration = -1;
21unsigned long long stop_count = 0;
22unsigned nprocs = 1;
23unsigned nthreads = 1;
24
25volatile unsigned long long threads_left;
26
27#define BENCH_OPT \
28 {'d', "duration", "Duration of the experiments in seconds", duration }, \
29 {'i', "iterations", "Number of iterations of the experiments", stop_count }, \
30 {'t', "nthreads", "Number of threads to use", nthreads }, \
31 {'p', "nprocs", "Number of processors to use", nprocs }
32
33#define BENCH_OPT_PARSE(name) \
34 { \
35 int opt_cnt = sizeof(opt) / sizeof(option_t); \
36 char **left; \
37 parse_args( argc, argv, opt, opt_cnt, "[OPTIONS]...\n" name, &left ); \
38 if(duration > 0 && stop_count > 0) { \
39 fprintf(stderr, "--duration and --iterations cannot be used together\n"); \
40 print_args_usage(argc, argv, opt, opt_cnt, "[OPTIONS]...\n" name, true); \
41 } else if(duration > 0) { \
42 clock_mode = true; \
43 stop_count = 0xFFFFFFFFFFFFFFFF; \
44 printf("Running for %lf seconds\n", duration); \
45 } else if(stop_count > 0) { \
46 clock_mode = false; \
47 printf("Running for %llu iterations\n", stop_count); \
48 } else { \
49 duration = 5; clock_mode = true;\
50 printf("Running for %lf seconds\n", duration); \
51 } \
52 }
53
54uint64_t timeHiRes() {
55 timespec curr;
56 clock_gettime( CLOCK_REALTIME, &curr );
57 return (int64_t)curr.tv_sec * TIMEGRAN + curr.tv_nsec;
58}
59
60uint64_t to_miliseconds( uint64_t durtn ) { return durtn / (TIMEGRAN / 1000LL); }
61double to_fseconds(uint64_t durtn ) { return durtn / (double)TIMEGRAN; }
62uint64_t from_fseconds(double sec) { return sec * TIMEGRAN; }
63
64template<typename Sleeper>
65void wait(const uint64_t & start, bool is_tty) {
66 for(;;) {
67 Sleeper::usleep(100000);
68 uint64_t end = timeHiRes();
69 uint64_t delta = end - start;
70 if(is_tty) {
71 printf(" %.1f\r", to_fseconds(delta));
72 fflush(stdout);
73 }
74 if( clock_mode && delta >= from_fseconds(duration) ) {
75 break;
76 }
77 else if( !clock_mode && threads_left == 0 ) {
78 break;
79 }
80 }
81}
82
83class Fibre;
84int fibre_park();
85int fibre_unpark( Fibre * );
86Fibre * fibre_self();
87
88class __attribute__((aligned(128))) bench_sem {
89 Fibre * volatile ptr = nullptr;
90public:
91 inline bool wait() {
92 static Fibre * const ready = reinterpret_cast<Fibre *>(1ull);
93 for(;;) {
94 Fibre * expected = this->ptr;
95 if(expected == ready) {
96 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
97 return false;
98 }
99 }
100 else {
101 /* paranoid */ assert( expected == nullptr );
102 if(__atomic_compare_exchange_n(&this->ptr, &expected, fibre_self(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
103 fibre_park();
104 return true;
105 }
106 }
107
108 }
109 }
110
111 inline bool post() {
112 static Fibre * const ready = reinterpret_cast<Fibre *>(1ull);
113 for(;;) {
114 Fibre * expected = this->ptr;
115 if(expected == ready) return false;
116 if(expected == nullptr) {
117 if(__atomic_compare_exchange_n(&this->ptr, &expected, ready, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
118 return false;
119 }
120 }
121 else {
122 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
123 fibre_unpark( expected );
124 return true;
125 }
126 }
127 }
128 }
129};
130
131// ==========================================================================================
132#include <cstdlib>
133#include <cstring>
134
135#include <algorithm>
136
137//-----------------------------------------------------------------------------
138// Typed argument parsing
139bool parse_yesno(const char * arg, bool & value ) {
140 if(strcmp(arg, "yes") == 0) {
141 value = true;
142 return true;
143 }
144
145 if(strcmp(arg, "Y") == 0) {
146 value = true;
147 return true;
148 }
149
150 if(strcmp(arg, "y") == 0) {
151 value = true;
152 return true;
153 }
154
155 if(strcmp(arg, "no") == 0) {
156 value = false;
157 return true;
158 }
159
160 if(strcmp(arg, "N") == 0) {
161 value = false;
162 return true;
163 }
164
165 if(strcmp(arg, "n") == 0) {
166 value = false;
167 return true;
168 }
169
170 return false;
171}
172
173bool parse_truefalse(const char * arg, bool & value) {
174 if(strcmp(arg, "true") == 0) {
175 value = true;
176 return true;
177 }
178
179 if(strcmp(arg, "false") == 0) {
180 value = false;
181 return true;
182 }
183
184 return false;
185}
186
187bool parse_settrue (const char *, bool & value ) {
188 value = true;
189 return true;
190}
191
192bool parse_setfalse(const char *, bool & value ) {
193 value = false;
194 return true;
195}
196
197bool parse(const char * arg, const char * & value ) {
198 value = arg;
199 return true;
200}
201
202bool parse(const char * arg, int & value) {
203 char * end;
204 int r = strtoll(arg, &end, 10);
205 if(*end != '\0') return false;
206
207 value = r;
208 return true;
209}
210
211bool parse(const char * arg, unsigned & value) {
212 char * end;
213 unsigned long long int r = strtoull(arg, &end, 10);
214 if(*end != '\0') return false;
215 if(r > UINT_MAX) return false;
216
217 value = r;
218 return true;
219}
220
221bool parse(const char * arg, unsigned long & value) {
222 char * end;
223 unsigned long long int r = strtoull(arg, &end, 10);
224 if(*end != '\0') return false;
225 if(r > ULONG_MAX) return false;
226
227 value = r;
228 return true;
229}
230
231bool parse(const char * arg, unsigned long long & value) {
232 char * end;
233 unsigned long long int r = strtoull(arg, &end, 10);
234 if(*end != '\0') return false;
235 if(r > ULLONG_MAX) return false;
236
237 value = r;
238 return true;
239}
240
241bool parse(const char * arg, double & value) {
242 char * end;
243 double r = strtod(arg, &end);
244 if(*end != '\0') return false;
245
246 value = r;
247 return true;
248}
249
250//-----------------------------------------------------------------------------
251struct option_t {
252 char short_name;
253 const char * long_name;
254 const char * help;
255 void * variable;
256 bool (*parse_fun)(const char *, void * );
257
258 template<typename T>
259 inline option_t( char short_name, const char * long_name, const char * help, T & variable ) {
260 this->short_name = short_name;
261 this->long_name = long_name;
262 this->help = help;
263 this->variable = reinterpret_cast<void*>(&variable);
264 #pragma GCC diagnostic push
265 #pragma GCC diagnostic ignored "-Wcast-function-type"
266 this->parse_fun = reinterpret_cast<bool (*)(const char *, void * )>(static_cast<bool (*)(const char *, T & )>(parse));
267 #pragma GCC diagnostic pop
268 }
269
270 template<typename T>
271 inline option_t( char short_name, const char * long_name, const char * help, T & variable, bool (*parse)(const char *, T & )) {
272 this->short_name = short_name;
273 this->long_name = long_name;
274 this->help = help;
275 this->variable = reinterpret_cast<void*>(&variable);
276 #pragma GCC diagnostic push
277 #pragma GCC diagnostic ignored "-Wcast-function-type"
278 this->parse_fun = reinterpret_cast<bool (*)(const char *, void * )>(parse);
279 #pragma GCC diagnostic pop
280 }
281};
282
283extern option_t last_option;
284
285
286//-----------------------------------------------------------------------------
287#include <cstdint>
288#include <climits>
289#include <errno.h>
290#include <unistd.h>
291extern "C" {
292 #include <getopt.h>
293 #include <sys/ioctl.h>
294
295 extern FILE * stderr;
296 extern FILE * stdout;
297
298 extern int fileno(FILE *stream);
299
300 extern int fprintf ( FILE * stream, const char * format, ... );
301
302 extern long long int strtoll (const char* str, char** endptr, int base);
303 extern unsigned long long int strtoull(const char* str, char** endptr, int base);
304 extern double strtod (const char* str, char** endptr);
305}
306
307static void usage(char * cmd, option_t options[], size_t opt_count, const char * usage, FILE * out) __attribute__ ((noreturn));
308
309//-----------------------------------------------------------------------------
310// getopt_long wrapping
311void parse_args(
312 int argc,
313 char * argv[],
314 option_t options[],
315 size_t opt_count,
316 const char * usage_msg,
317 char ** * left
318) {
319 struct option optarr[opt_count + 2];
320 {
321 int idx = 0;
322 for(size_t i = 0; i < opt_count; i++) {
323 if(options[i].long_name) {
324 optarr[idx].name = options[i].long_name;
325 optarr[idx].flag = nullptr;
326 optarr[idx].val = options[i].short_name;
327 if( ((intptr_t)options[i].parse_fun) == ((intptr_t)parse_settrue)
328 || ((intptr_t)options[i].parse_fun) == ((intptr_t)parse_setfalse) ) {
329 optarr[idx].has_arg = no_argument;
330 } else {
331 optarr[idx].has_arg = required_argument;
332 }
333 idx++;
334 }
335 }
336 optarr[idx+0].name = "help";
337 optarr[idx+0].has_arg = no_argument;
338 optarr[idx+0].flag = 0;
339 optarr[idx+0].val = 'h';
340 optarr[idx+1].name = 0;
341 optarr[idx+1].has_arg = no_argument;
342 optarr[idx+1].flag = 0;
343 optarr[idx+1].val = 0;
344 }
345
346 char optstring[opt_count * 3];
347 for(auto & o : optstring) {
348 o = '\0';
349 }
350 {
351 int idx = 0;
352 for(size_t i = 0; i < opt_count; i++) {
353 optstring[idx] = options[i].short_name;
354 idx++;
355 if( ((intptr_t)options[i].parse_fun) != ((intptr_t)parse_settrue)
356 && ((intptr_t)options[i].parse_fun) != ((intptr_t)parse_setfalse) ) {
357 optstring[idx] = ':';
358 idx++;
359 }
360 }
361 optstring[idx+0] = 'h';
362 optstring[idx+1] = '\0';
363 }
364
365 FILE * out = stderr;
366 for(;;) {
367 int idx = 0;
368 int opt = getopt_long(argc, argv, optstring, optarr, &idx);
369 switch(opt) {
370 case -1:
371 if(left != nullptr) *left = argv + optind;
372 return;
373 case 'h':
374 out = stdout;
375 [[fallthrough]];
376 case '?':
377 usage(argv[0], options, opt_count, usage_msg, out);
378 default:
379 for(size_t i = 0; i < opt_count; i++) {
380 if(opt == options[i].short_name) {
381 const char * arg = optarg ? optarg : "";
382 if( arg[0] == '=' ) { arg++; }
383 bool success = options[i].parse_fun( arg, options[i].variable );
384 if(success) goto NEXT_ARG;
385
386 fprintf(out, "Argument '%s' for option %c could not be parsed\n\n", arg, (char)opt);
387 usage(argv[0], options, opt_count, usage_msg, out);
388 }
389 }
390 std::abort();
391 }
392 NEXT_ARG:;
393 }
394}
395
396//-----------------------------------------------------------------------------
397// Print usage
398static void printopt(FILE * out, int width, int max, char sn, const char * ln, const char * help) {
399 int hwidth = max - (11 + width);
400 if(hwidth <= 0) hwidth = max;
401
402 fprintf(out, " -%c, --%-*s %.*s\n", sn, width, ln, hwidth, help);
403 for(;;) {
404 help += std::min(strlen(help), (unsigned long)hwidth);
405 if('\0' == *help) break;
406 fprintf(out, "%*s%.*s\n", width + 11, "", hwidth, help);
407 }
408}
409
410__attribute__((noreturn)) void print_args_usage(int , char * argv[], option_t options[], size_t opt_count, const char * usage_msg, bool error) {
411 usage(argv[0], options, opt_count, usage_msg, error ? stderr : stdout);
412}
413
414static __attribute__((noreturn)) void usage(char * cmd, option_t options[], size_t opt_count, const char * help, FILE * out) {
415 int width = 0;
416 {
417 for(size_t i = 0; i < opt_count; i++) {
418 if(options[i].long_name) {
419 int w = strlen(options[i].long_name);
420 if(w > width) width = w;
421 }
422 }
423 }
424
425 int max_width = 1000000;
426 int outfd = fileno(out);
427 if(isatty(outfd)) {
428 struct winsize size;
429 int ret = ioctl(outfd, TIOCGWINSZ, &size);
430 if(ret < 0) abort(); // "ioctl error: (%d) %s\n", (int)errno, strerror(errno)
431 max_width = size.ws_col;
432 }
433
434 fprintf(out, "Usage:\n %s %s\n", cmd, help);
435
436 for(size_t i = 0; i < opt_count; i++) {
437 printopt(out, width, max_width, options[i].short_name, options[i].long_name, options[i].help);
438 }
439 fprintf(out, " -%c, --%-*s %s\n", 'h', width, "help", "print this help message");
440 exit(out == stdout ? 0 : 1);
441}
442
Note: See TracBrowser for help on using the repository browser.