|
#ifndef RBENCH_H
|
|
#define RBENCH_H
|
|
|
|
#include "rprint.h"
|
|
#include "rtime.h"
|
|
#include <errno.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
|
|
#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 |