Skip to content

Instantly share code, notes, and snippets.

@a2800276
Created March 8, 2012 10:16
Show Gist options
  • Save a2800276/2000148 to your computer and use it in GitHub Desktop.
Save a2800276/2000148 to your computer and use it in GitHub Desktop.
straightforward C port of Go (golang) Benchmark facility.
/*
* 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