source: benchmark/readyQ/rq_bench.hpp@ ce9f9d4

ADT ast-experimental enum forall-pointer-decay pthread-emulation qualifiedEnum
Last change on this file since ce9f9d4 was 56ac392, checked in by Thierry Delisle <tdelisle@…>, 4 years ago

Moved single_sem to rq_bench.hpp which was duplicated across multiple fibre benchmarks.

  • Property mode set to 100644
File size: 11.1 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, "no") == 0) {
146 value = false;
147 return true;
148 }
149
150 return false;
151}
152
153bool parse_truefalse(const char * arg, bool & value) {
154 if(strcmp(arg, "true") == 0) {
155 value = true;
156 return true;
157 }
158
159 if(strcmp(arg, "false") == 0) {
160 value = false;
161 return true;
162 }
163
164 return false;
165}
166
167bool parse_settrue (const char *, bool & value ) {
168 value = true;
169 return true;
170}
171
172bool parse_setfalse(const char *, bool & value ) {
173 value = false;
174 return true;
175}
176
177bool parse(const char * arg, const char * & value ) {
178 value = arg;
179 return true;
180}
181
182bool parse(const char * arg, int & value) {
183 char * end;
184 int r = strtoll(arg, &end, 10);
185 if(*end != '\0') return false;
186
187 value = r;
188 return true;
189}
190
191bool parse(const char * arg, unsigned & value) {
192 char * end;
193 unsigned long long int r = strtoull(arg, &end, 10);
194 if(*end != '\0') return false;
195 if(r > UINT_MAX) return false;
196
197 value = r;
198 return true;
199}
200
201bool parse(const char * arg, unsigned long & value) {
202 char * end;
203 unsigned long long int r = strtoull(arg, &end, 10);
204 if(*end != '\0') return false;
205 if(r > ULONG_MAX) return false;
206
207 value = r;
208 return true;
209}
210
211bool parse(const char * arg, unsigned long long & value) {
212 char * end;
213 unsigned long long int r = strtoull(arg, &end, 10);
214 if(*end != '\0') return false;
215 if(r > ULLONG_MAX) return false;
216
217 value = r;
218 return true;
219}
220
221bool parse(const char * arg, double & value) {
222 char * end;
223 double r = strtod(arg, &end);
224 if(*end != '\0') return false;
225
226 value = r;
227 return true;
228}
229
230//-----------------------------------------------------------------------------
231struct option_t {
232 char short_name;
233 const char * long_name;
234 const char * help;
235 void * variable;
236 bool (*parse_fun)(const char *, void * );
237
238 template<typename T>
239 inline option_t( char short_name, const char * long_name, const char * help, T & variable ) {
240 this->short_name = short_name;
241 this->long_name = long_name;
242 this->help = help;
243 this->variable = reinterpret_cast<void*>(&variable);
244 #pragma GCC diagnostic push
245 #pragma GCC diagnostic ignored "-Wcast-function-type"
246 this->parse_fun = reinterpret_cast<bool (*)(const char *, void * )>(static_cast<bool (*)(const char *, T & )>(parse));
247 #pragma GCC diagnostic pop
248 }
249
250 template<typename T>
251 inline option_t( char short_name, const char * long_name, const char * help, T & variable, bool (*parse)(const char *, T & )) {
252 this->short_name = short_name;
253 this->long_name = long_name;
254 this->help = help;
255 this->variable = reinterpret_cast<void*>(&variable);
256 #pragma GCC diagnostic push
257 #pragma GCC diagnostic ignored "-Wcast-function-type"
258 this->parse_fun = reinterpret_cast<bool (*)(const char *, void * )>(parse);
259 #pragma GCC diagnostic pop
260 }
261};
262
263extern option_t last_option;
264
265
266//-----------------------------------------------------------------------------
267#include <cstdint>
268#include <climits>
269#include <errno.h>
270#include <unistd.h>
271extern "C" {
272 #include <getopt.h>
273 #include <sys/ioctl.h>
274
275 extern FILE * stderr;
276 extern FILE * stdout;
277
278 extern int fileno(FILE *stream);
279
280 extern int fprintf ( FILE * stream, const char * format, ... );
281
282 extern long long int strtoll (const char* str, char** endptr, int base);
283 extern unsigned long long int strtoull(const char* str, char** endptr, int base);
284 extern double strtod (const char* str, char** endptr);
285}
286
287static void usage(char * cmd, option_t options[], size_t opt_count, const char * usage, FILE * out) __attribute__ ((noreturn));
288
289//-----------------------------------------------------------------------------
290// getopt_long wrapping
291void parse_args(
292 int argc,
293 char * argv[],
294 option_t options[],
295 size_t opt_count,
296 const char * usage_msg,
297 char ** * left
298) {
299 struct option optarr[opt_count + 2];
300 {
301 int idx = 0;
302 for(size_t i = 0; i < opt_count; i++) {
303 if(options[i].long_name) {
304 optarr[idx].name = options[i].long_name;
305 optarr[idx].flag = nullptr;
306 optarr[idx].val = options[i].short_name;
307 if( ((intptr_t)options[i].parse_fun) == ((intptr_t)parse_settrue)
308 || ((intptr_t)options[i].parse_fun) == ((intptr_t)parse_setfalse) ) {
309 optarr[idx].has_arg = no_argument;
310 } else {
311 optarr[idx].has_arg = required_argument;
312 }
313 idx++;
314 }
315 }
316 optarr[idx+0].name = "help";
317 optarr[idx+0].has_arg = no_argument;
318 optarr[idx+0].flag = 0;
319 optarr[idx+0].val = 'h';
320 optarr[idx+1].name = 0;
321 optarr[idx+1].has_arg = no_argument;
322 optarr[idx+1].flag = 0;
323 optarr[idx+1].val = 0;
324 }
325
326 char optstring[opt_count * 3];
327 for(auto & o : optstring) {
328 o = '\0';
329 }
330 {
331 int idx = 0;
332 for(size_t i = 0; i < opt_count; i++) {
333 optstring[idx] = options[i].short_name;
334 idx++;
335 if( ((intptr_t)options[i].parse_fun) != ((intptr_t)parse_settrue)
336 && ((intptr_t)options[i].parse_fun) != ((intptr_t)parse_setfalse) ) {
337 optstring[idx] = ':';
338 idx++;
339 }
340 }
341 optstring[idx+0] = 'h';
342 optstring[idx+1] = '\0';
343 }
344
345 FILE * out = stderr;
346 for(;;) {
347 int idx = 0;
348 int opt = getopt_long(argc, argv, optstring, optarr, &idx);
349 switch(opt) {
350 case -1:
351 if(left != nullptr) *left = argv + optind;
352 return;
353 case 'h':
354 out = stdout;
355 [[fallthrough]];
356 case '?':
357 usage(argv[0], options, opt_count, usage_msg, out);
358 default:
359 for(size_t i = 0; i < opt_count; i++) {
360 if(opt == options[i].short_name) {
361 const char * arg = optarg ? optarg : "";
362 if( arg[0] == '=' ) { arg++; }
363 bool success = options[i].parse_fun( arg, options[i].variable );
364 if(success) goto NEXT_ARG;
365
366 fprintf(out, "Argument '%s' for option %c could not be parsed\n\n", arg, (char)opt);
367 usage(argv[0], options, opt_count, usage_msg, out);
368 }
369 }
370 std::abort();
371 }
372 NEXT_ARG:;
373 }
374}
375
376//-----------------------------------------------------------------------------
377// Print usage
378static void printopt(FILE * out, int width, int max, char sn, const char * ln, const char * help) {
379 int hwidth = max - (11 + width);
380 if(hwidth <= 0) hwidth = max;
381
382 fprintf(out, " -%c, --%-*s %.*s\n", sn, width, ln, hwidth, help);
383 for(;;) {
384 help += std::min(strlen(help), (unsigned long)hwidth);
385 if('\0' == *help) break;
386 fprintf(out, "%*s%.*s\n", width + 11, "", hwidth, help);
387 }
388}
389
390__attribute__((noreturn)) void print_args_usage(int , char * argv[], option_t options[], size_t opt_count, const char * usage_msg, bool error) {
391 usage(argv[0], options, opt_count, usage_msg, error ? stderr : stdout);
392}
393
394static __attribute__((noreturn)) void usage(char * cmd, option_t options[], size_t opt_count, const char * help, FILE * out) {
395 int width = 0;
396 {
397 for(size_t i = 0; i < opt_count; i++) {
398 if(options[i].long_name) {
399 int w = strlen(options[i].long_name);
400 if(w > width) width = w;
401 }
402 }
403 }
404
405 int max_width = 1000000;
406 int outfd = fileno(out);
407 if(isatty(outfd)) {
408 struct winsize size;
409 int ret = ioctl(outfd, TIOCGWINSZ, &size);
410 if(ret < 0) abort(); // "ioctl error: (%d) %s\n", (int)errno, strerror(errno)
411 max_width = size.ws_col;
412 }
413
414 fprintf(out, "Usage:\n %s %s\n", cmd, help);
415
416 for(size_t i = 0; i < opt_count; i++) {
417 printopt(out, width, max_width, options[i].short_name, options[i].long_name, options[i].help);
418 }
419 fprintf(out, " -%c, --%-*s %s\n", 'h', width, "help", "print this help message");
420 exit(out == stdout ? 0 : 1);
421}
422
Note: See TracBrowser for help on using the repository browser.