source: benchmark/readyQ/rq_bench.hpp @ 56e5b24

ADTast-experimentalenumforall-pointer-decaypthread-emulationqualifiedEnum
Last change on this file since 56e5b24 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.