Created
March 8, 2012 10:16
-
-
Save a2800276/2000148 to your computer and use it in GitHub Desktop.
straightforward C port of Go (golang) Benchmark facility.
This file contains hidden or 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
/* | |
* this is a fairly straightforward port of go-langs bench utility | |
* to C ... | |
* usage: | |
* see sample `main` at bottom | |
* original code see: | |
* http://golang.org/src/pkg/testing/benchmark.go | |
* | |
* Thanks to https://github.com/jbenet for "portable" c nanosec timer: | |
* https://gist.github.com/1087739 | |
* | |
* Javascript version of bench: | |
* https://gist.github.com/1892127 | |
* | |
* Java version | |
* https://gist.github.com/2000141 | |
*/ | |
#include <stddef.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <strings.h> | |
typedef struct B { | |
int n; | |
uint64_t ns; | |
size_t bytes; | |
uint64_t start; | |
/* public */ | |
void (*benchmark)(struct B *); | |
char * name; | |
} B; | |
#include <time.h> | |
#include <sys/time.h> | |
#ifdef __MACH__ | |
#include <mach/clock.h> | |
#include <mach/mach.h> | |
#endif | |
uint64_t nanoseconds () { | |
/* ugh */ | |
/* forced to use cludgy ns time code based on : | |
* https://gist.github.com/1087739 | |
* b/c osx is borked. | |
*/ | |
uint64_t result = 0; | |
#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time | |
clock_serv_t cclock; | |
mach_timespec_t mts; | |
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); | |
clock_get_time(cclock, &mts); | |
mach_port_deallocate(mach_task_self(), cclock); | |
result = mts.tv_sec * 1e9; | |
result += mts.tv_nsec; | |
#else | |
struct timespec ts; | |
clock_gettime(CLOCK_REALTIME, &ts); | |
result = ts.tv_sec * 1e9; | |
result += ts.tv_nsec; | |
#endif | |
return result; | |
} | |
void start_timer( B * b) { | |
if (b->start == 0) { | |
b->start = nanoseconds(); | |
} | |
} | |
void stop_timer( B * b) { | |
if (b->start > 0) { | |
b->ns += nanoseconds() - b->start; | |
} | |
b->start = 0; | |
} | |
void reset_timer( B * b) { | |
if (b->start > 0) { | |
b->start = nanoseconds(); | |
} | |
b->ns = 0; | |
} | |
void set_bytes(B * b, size_t n){ | |
b->bytes = n; | |
} | |
uint64_t ns_per_op(B * b) { | |
if (b->n <= 0) { | |
return 0; | |
} | |
return b->ns / (uint64_t)b->n; | |
} | |
void run_n(B * b, int n) { | |
b->n = n; | |
reset_timer(b); | |
start_timer(b); | |
b->benchmark(b); | |
stop_timer(b); | |
} | |
#define min(x,y) ((x > y)?(y):(x)) | |
#define max(x,y) ((x < y)?(y):(x)) | |
int round_down_ten(int n){ | |
int tens, result, i = 0; | |
for (;n>10;) { | |
n/=10; | |
tens++; | |
} | |
result = 1; | |
for(i=0; i< tens; i++) { | |
result *= 10; | |
} | |
return result; | |
} | |
int round_up(int n) { | |
int base = round_down_ten(n); | |
if (n < (2*base)) { | |
return 2*base; | |
} | |
if (n < (5 * base)) { | |
return 5 * base; | |
} | |
return 10*base; | |
} | |
void run (B * b){ | |
int n = 1, last; | |
uint64_t time; | |
run_n(b, n); | |
time = 1e9; | |
for (;b->ns < time && n < 1e9;) { | |
last = n; | |
if (ns_per_op(b) == 0) { | |
n = 1e9; | |
} else { | |
n = (int)(time/ns_per_op(b)); | |
} | |
n = max(min(n+n/2, 100*last), last+1); | |
n = round_up(n); | |
run_n(b,n); | |
} | |
} | |
//void launch (B * bench){} | |
double mb_per_sec(B * b) { | |
if (b->bytes <=0 || b->ns <= 0 || b->n <=0) { | |
return 0; | |
} | |
return ((double)b->bytes * (double)b->n) / (double)b->ns * 1e3; | |
} | |
void print_results(B*b) { | |
double mbs; | |
uint64_t nsop; | |
printf("%8d\t", b->n); | |
nsop = ns_per_op(b); | |
if (b->n > 0 && nsop < 100) { | |
if (nsop < 10) { | |
printf("%13.2f ns/op", (double)b->ns/(double)b->n); | |
} else { | |
printf("%12.1f ns/op", (double)b->ns/(double)b->n); | |
} | |
} else { | |
printf("%10llu ns/op", nsop); | |
} | |
mbs = mb_per_sec(b); | |
if (mbs != 0) { | |
printf("\t%7.2f MB/s", mbs); | |
} | |
printf("\t(%s)\n", b->name); | |
} | |
#define MAIN 0 | |
#if MAIN | |
void bench (B * b) { | |
int i; | |
void * t, * t2; | |
for (i=0; i!=b->n; ++i) { | |
t = malloc(1000); | |
t2 = malloc(4000); | |
memcpy(t2, t, 1000); | |
free(t); | |
free(t2); | |
b->bytes += 5000; | |
} | |
} | |
void bench2 (B * b) { | |
int i; | |
void * t; | |
for (i=0; i!=b->n; ++i) { | |
t = malloc(1000); | |
t = realloc(t, 4000); | |
free(t); | |
b->bytes += 5000; | |
} | |
} | |
int main () { | |
B b; | |
bzero(&b, sizeof(b)); | |
b.name = "malloc"; | |
b.benchmark = &bench; | |
run(&b); | |
print_results(&b); | |
bzero(&b, sizeof(b)); | |
b.name = "realloc"; | |
b.benchmark = &bench2; | |
run(&b); | |
print_results(&b); | |
return 0; | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment