#ifndef RBENCH_H #define RBENCH_H #include "rprint.h" #include "rtime.h" #include #include #include #include #include #include #include #include #include "rstring.h" #include "rterminal.h" #define RBENCH(times, action) \ { \ unsigned long utimes = (unsigned long)times; \ nsecs_t start = nsecs(); \ for (unsigned long i = 0; i < utimes; i++) { \ { \ action; \ } \ } \ nsecs_t end = nsecs(); \ printf("%s\n", format_time(end - start)); \ } #define RBENCHP(times, action) \ { \ printf("\n"); \ nsecs_t start = nsecs(); \ unsigned int prev_percentage = 0; \ unsigned long utimes = (unsigned long)times; \ for (unsigned long i = 0; i < utimes; i++) { \ unsigned int percentage = ((long double)i / (long double)times) * 100; \ int percentage_changed = percentage != prev_percentage; \ __attribute__((unused)) int first = i == 0; \ __attribute__((unused)) int last = i == utimes - 1; \ { action; }; \ if (percentage_changed) { \ printf("\r%d%%", percentage); \ fflush(stdout); \ \ prev_percentage = percentage; \ } \ } \ nsecs_t end = nsecs(); \ printf("\r%s\n", format_time(end - start)); \ } struct rbench_t; typedef struct rbench_function_t { #ifdef __cplusplus void (*call)(); #else void(*call); #endif char name[256]; char group[256]; void *arg; void *data; bool first; bool last; int argc; unsigned long times_executed; nsecs_t average_execution_time; nsecs_t total_execution_time; } rbench_function_t; typedef struct rbench_t { unsigned int function_count; rbench_function_t functions[100]; rbench_function_t *current; rprogressbar_t *progress_bar; bool show_progress; int winner; bool stdout; unsigned long times; bool silent; nsecs_t execution_time; #ifdef __cplusplus void (*add_function)(struct rbench_t *r, const char *name, const char *group, void (*)()); #else void (*add_function)(struct rbench_t *r, const char *name, const char *group, void *); #endif void (*rbench_reset)(struct rbench_t *r); struct rbench_t *(*execute)(struct rbench_t *r, long times); struct rbench_t *(*execute1)(struct rbench_t *r, long times, void *arg1); struct rbench_t *(*execute2)(struct rbench_t *r, long times, void *arg1, void *arg2); struct rbench_t *(*execute3)(struct rbench_t *r, long times, void *arg1, void *arg2, void *arg3); } rbench_t; FILE *_rbench_stdout = NULL; FILE *_rbench_stdnull = NULL; void rbench_toggle_stdout(rbench_t *r) { if (!r->stdout) { if (_rbench_stdout == NULL) { _rbench_stdout = stdout; } if (_rbench_stdnull == NULL) { _rbench_stdnull = fopen("/dev/null", "wb"); } if (stdout == _rbench_stdout) { stdout = _rbench_stdnull; } else { stdout = _rbench_stdout; } } } void rbench_restore_stdout(rbench_t *r) { if (r->stdout) return; if (_rbench_stdout) { stdout = _rbench_stdout; } if (_rbench_stdnull) { fclose(_rbench_stdnull); _rbench_stdnull = NULL; } } rbench_t *rbench_new(); rbench_t *_rbench = NULL; rbench_function_t *rbf; rbench_t *rbench() { if (_rbench == NULL) { _rbench = rbench_new(); } return _rbench; } typedef void *(*rbench_call)(); typedef void *(*rbench_call1)(void *); typedef void *(*rbench_call2)(void *, void *); typedef void *(*rbench_call3)(void *, void *, void *); #ifdef __cplusplus void rbench_add_function(rbench_t *rp, const char *name, const char *group, void (*call)()) { #else void rbench_add_function(rbench_t *rp, const char *name, const char *group, void *call) { #endif rbench_function_t *f = &rp->functions[rp->function_count]; rp->function_count++; f->average_execution_time = 0; f->total_execution_time = 0; f->times_executed = 0; f->call = call; strcpy(f->name, name); strcpy(f->group, group); } void rbench_reset_function(rbench_function_t *f) { f->average_execution_time = 0; f->times_executed = 0; f->total_execution_time = 0; } void rbench_reset(rbench_t *rp) { for (unsigned int i = 0; i < rp->function_count; i++) { rbench_reset_function(&rp->functions[i]); } } int rbench_get_winner_index(rbench_t *r) { int winner = 0; nsecs_t time = 0; for (unsigned int i = 0; i < r->function_count; i++) { if (time == 0 || r->functions[i].total_execution_time < time) { winner = i; time = r->functions[i].total_execution_time; } } return winner; } bool rbench_was_last_function(rbench_t *r) { for (unsigned int i = 0; i < r->function_count; i++) { if (i == r->function_count - 1 && r->current == &r->functions[i]) return true; } return false; } rbench_function_t *rbench_execute_prepare(rbench_t *r, int findex, long times, int argc) { rbench_toggle_stdout(r); if (findex == 0) { r->execution_time = 0; } rbench_function_t *rf = &r->functions[findex]; rf->argc = argc; rbf = rf; r->current = rf; if (r->show_progress) r->progress_bar = rprogressbar_new(0, times, 20, stderr); r->times = times; // printf(" %s:%s gets executed for %ld times with %d // arguments.\n",rf->group, rf->name, times,argc); rbench_reset_function(rf); return rf; } void rbench_execute_finish(rbench_t *r) { rbench_toggle_stdout(r); if (r->progress_bar) { free(r->progress_bar); r->progress_bar = NULL; } r->current->average_execution_time = r->current->total_execution_time / r->current->times_executed; ; // printf(" %s:%s finished executing in // %s\n",r->current->group,r->current->name, // format_time(r->current->total_execution_time)); // rbench_show_results_function(r->current); if (rbench_was_last_function(r)) { rbench_restore_stdout(r); unsigned int winner_index = rbench_get_winner_index(r); r->winner = winner_index + 1; if (!r->silent) rprintgf(stderr, "Benchmark results:\n"); nsecs_t total_time = 0; for (unsigned int i = 0; i < r->function_count; i++) { rbf = &r->functions[i]; total_time += rbf->total_execution_time; bool is_winner = winner_index == i; if (is_winner) { if (!r->silent) rprintyf(stderr, " > %s:%s:%s\n", format_time(rbf->total_execution_time), rbf->group, rbf->name); } else { if (!r->silent) rprintbf(stderr, " %s:%s:%s\n", format_time(rbf->total_execution_time), rbf->group, rbf->name); } } if (!r->silent) rprintgf(stderr, "Total execution time: %s\n", format_time(total_time)); } rbench_restore_stdout(r); rbf = NULL; r->current = NULL; } struct rbench_t *rbench_execute(rbench_t *r, long times) { for (unsigned int i = 0; i < r->function_count; i++) { rbench_function_t *f = rbench_execute_prepare(r, i, times, 0); rbench_call c = (rbench_call)f->call; nsecs_t start = nsecs(); f->first = true; c(); f->first = false; f->last = false; f->times_executed++; for (int j = 1; j < times; j++) { c(); f->times_executed++; f->last = f->times_executed == r->times - 1; if (r->progress_bar) { rprogressbar_update(r->progress_bar, f->times_executed); } } f->total_execution_time = nsecs() - start; r->execution_time += f->total_execution_time; rbench_execute_finish(r); } return r; } struct rbench_t *rbench_execute1(rbench_t *r, long times, void *arg1) { for (unsigned int i = 0; i < r->function_count; i++) { rbench_function_t *f = rbench_execute_prepare(r, i, times, 1); rbench_call1 c = (rbench_call1)f->call; nsecs_t start = nsecs(); f->first = true; c(arg1); f->first = false; f->last = false; f->times_executed++; for (int j = 1; j < times; j++) { c(arg1); f->times_executed++; f->last = f->times_executed == r->times - 1; if (r->progress_bar) { rprogressbar_update(r->progress_bar, f->times_executed); } } f->total_execution_time = nsecs() - start; r->execution_time += f->total_execution_time; rbench_execute_finish(r); } return r; } struct rbench_t *rbench_execute2(rbench_t *r, long times, void *arg1, void *arg2) { for (unsigned int i = 0; i < r->function_count; i++) { rbench_function_t *f = rbench_execute_prepare(r, i, times, 2); rbench_call2 c = (rbench_call2)f->call; nsecs_t start = nsecs(); f->first = true; c(arg1, arg2); f->first = false; f->last = false; f->times_executed++; for (int j = 1; j < times; j++) { c(arg1, arg2); f->times_executed++; f->last = f->times_executed == r->times - 1; if (r->progress_bar) { rprogressbar_update(r->progress_bar, f->times_executed); } } f->total_execution_time = nsecs() - start; r->execution_time += f->total_execution_time; rbench_execute_finish(r); } return r; } struct rbench_t *rbench_execute3(rbench_t *r, long times, void *arg1, void *arg2, void *arg3) { for (unsigned int i = 0; i < r->function_count; i++) { rbench_function_t *f = rbench_execute_prepare(r, i, times, 3); rbench_call3 c = (rbench_call3)f->call; nsecs_t start = nsecs(); f->first = true; c(arg1, arg2, arg3); f->first = false; f->last = false; f->times_executed++; for (int j = 1; j < times; j++) { c(arg1, arg2, arg3); f->times_executed++; f->last = f->times_executed == r->times - 1; if (r->progress_bar) { rprogressbar_update(r->progress_bar, f->times_executed); } } f->total_execution_time = nsecs() - start; rbench_execute_finish(r); } return r; } rbench_t *rbench_new() { rbench_t *r = (rbench_t *)malloc(sizeof(rbench_t)); memset(r, 0, sizeof(rbench_t)); r->add_function = rbench_add_function; r->rbench_reset = rbench_reset; r->execute1 = rbench_execute1; r->execute2 = rbench_execute2; r->execute3 = rbench_execute3; r->execute = rbench_execute; r->stdout = true; r->silent = false; r->winner = 0; r->show_progress = true; return r; } void rbench_free(rbench_t *r) { free(r); } #endif