Created
November 21, 2012 11:54
-
-
Save Mons/4124526 to your computer and use it in GitHub Desktop.
Small benchmark utility
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Usage: | |
#include "benchmark.h" | |
int test1 (va_list ap) { | |
char *str1 = va_arg( ap, char * ); | |
char *str2 = va_arg( ap, char * ); | |
... | |
return ...; | |
} | |
int test2 (va_list ap) { | |
char *str1 = va_arg( ap, char * ); | |
char *str2 = va_arg( ap, char * ); | |
... | |
return ...; | |
} | |
int main () { | |
bench_item tests[2] = { | |
{ "test1", test1, 0}, | |
{ "test2", test2, 0} | |
// ^ name of test | |
// ^ function | |
// ^ here will be stored result (double) | |
}; | |
benchmark(1E8, 2, tests, arg1, arg2); | |
// ^ time to run at least, microseconds (1s = 1E9 us) | |
// ^ number of items in tests | |
// ^ arguments to test function | |
} | |
//compile with: -lrt | |
*/ | |
#include <stdlib.h> | |
#include <stdarg.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <time.h> | |
typedef int (*testfunc)( va_list ap ); | |
typedef struct { | |
time_t sec; | |
long int nsec; | |
intmax_t delta; | |
} mytimediff; | |
typedef struct { | |
char *name; | |
testfunc func; | |
long double ops; | |
} bench_item; | |
static inline mytimediff timedelta( struct timespec t1, struct timespec t2 ) { | |
mytimediff d; | |
intmax_t delta_nsec = ( (intmax_t)t2.tv_nsec - (intmax_t)t1.tv_nsec ); | |
intmax_t delta_sec = (intmax_t)t2.tv_sec - (intmax_t)t1.tv_sec; | |
if (delta_nsec < 0) { delta_nsec += 1E9; delta_sec -=1; } | |
if (delta_sec < 0) { delta_nsec = 1E9 - delta_nsec; } | |
intmax_t delta = delta_sec*1E9 + delta_nsec; | |
d.sec = delta_sec; | |
d.nsec = delta_nsec; | |
d.delta = delta; | |
return d; | |
} | |
static long double vtimeit( intmax_t maxtime, char *name, testfunc test, va_list ap ) { | |
struct timeval tv; | |
struct timespec t0,t1,t2; | |
mytimediff d; | |
intmax_t i,k, total; | |
uint64_t time1, time2; | |
uint64_t tx1, tx2; | |
va_list an; | |
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t0); | |
long double ops; | |
for ( i = 1; i < 0xfffffff ; i <<= 1 ) { | |
gettimeofday(&tv, NULL); time1 = tv.tv_sec * 1000000 + tv.tv_usec; | |
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t1); | |
for ( k=0; k < i; k++) { | |
va_copy(an,ap); | |
test(an); | |
} | |
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t2); | |
gettimeofday(&tv, NULL); time2 = tv.tv_sec * 1000000 + tv.tv_usec; | |
total += i; | |
d = timedelta( t1,t2 ); | |
ops = i*1E9/d.delta; | |
d = timedelta( t0,t2 ); | |
if ( d.delta > maxtime ) { | |
printf("%-20s: delta = %jd.%09jds (%jd us); (ops = %.0Lf/s)\n", name, d.sec, d.nsec, d.delta, ops ); | |
return ops; | |
break; | |
} | |
} | |
return -1; | |
} | |
static long double timeit( intmax_t maxtime, char * name, testfunc test, ... ) { | |
va_list ap; | |
va_start(ap, test); | |
vtimeit(maxtime, name, test, ap); | |
} | |
static int compare_bench_items(const void *a, const void *b) { | |
long double ad = ((bench_item *)a)->ops; | |
long double bd = ((bench_item *)b)->ops; | |
return ad == bd ? 0 : ad > bd ? 1 : -1; | |
} | |
static void benchmark( intmax_t maxtime, int count, bench_item items[], ... ) { | |
int i,k; | |
va_list ap; | |
va_list an; | |
va_start(ap, items); | |
char tmp[256]; | |
va_copy(an,ap); | |
int rv = items[0].func( an ); | |
printf("RV = %d\n",rv); | |
for (i=1; i< count; i++) { | |
va_copy(an,ap); | |
int cv = items[i].func( an ); | |
if ( cv != rv ) { | |
fprintf(stderr, "%s return value (%d) differs from %s (%d)\n", items[i].name, cv, items[0].name, rv); | |
} | |
} | |
for (i=0; i< count; i++) { | |
items[i].ops = vtimeit( maxtime, items[i].name, items[i].func, ap ); | |
} | |
qsort( items, count, sizeof( bench_item ), compare_bench_items ); | |
for (k=-2; k < count; k++) { | |
if (k == -2) { | |
printf("%21s|",""); | |
for (i=0; i< count; i++) { | |
int lp = (20 - strlen(items[i].name) )/2+1; | |
int rp = 20 - strlen(items[i].name) - lp; | |
printf("%*s%s%*s |", lp, "",items[i].name, rp,""); | |
//printf("| %-20.20s", items[i].name); | |
} | |
printf("\n"); | |
} | |
else if (k == -1) { | |
printf("---------------------|"); | |
for (i=0; i< count; i++) { | |
printf("---------------------|"); | |
} | |
printf("\n"); | |
} | |
else { | |
printf("%-20.20s |", items[k].name); | |
for (i=0; i< count; i++) { | |
if (i == k) { | |
printf("%10s%s%10s|", "","-",""); | |
} else { | |
snprintf(tmp, 255, "%+0.2Lf%% (x%0.1Lf)", 100.0 * (items[k].ops - items[i].ops) / items[i].ops, (double)items[k].ops/items[i].ops); | |
int lp = (20 - strlen(tmp) )/2+1; | |
int rp = 20 - strlen(tmp) - lp; | |
printf("%*s%s%*s |", lp, "",tmp, rp,""); | |
//printf(" %-20.20s|", tmp); | |
} | |
} | |
printf("\n"); | |
} | |
} | |
printf("\n"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment