source: benchmark/readyQ/rq_bench.hpp@ be73f30

ADT arm-eh ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since be73f30 was 2c7eee0, checked in by Thierry Delisle <tdelisle@…>, 5 years ago

Fixed cycle benchmark to avoid extra unmatched unpark.
Added libfibre implementation.
Split out go common code into bench.go

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