source: benchmark/readyQ/rq_bench.hpp @ 2c7eee0

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 2c7eee0 was 2c7eee0, checked in by Thierry Delisle <tdelisle@…>, 3 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.