Blame common/b.c

nsz a520c1
#include <stdlib.h>
nsz a520c1
#include <stdio.h>
nsz a520c1
#include <string.h>
nsz a520c1
#include <errno.h>
nsz a520c1
#include <time.h>
nsz 9d224c
#include <sys/types.h>
nsz 9d224c
#include <sys/wait.h>
nsz 9d224c
#include <unistd.h>
nsz a520c1
#include "test.h"
nsz a520c1
nsz 7d87d3
#define T(f)
nsz 7d87d3
#define B(f) void f(int);
nsz 7d87d3
#include "tests.h"
nsz a520c1
#undef B
nsz a520c1
nsz 9d224c
static int verbose = 1;
nsz a520c1
nsz a520c1
void error__(const char *n, int l, const char *s, ...) {
nsz 1b83d1
	dprintf(1, "use error in tests only\n");
nsz a520c1
}
nsz a520c1
nsz 7d87d3
static int N;
nsz a520c1
static unsigned long long start;
nsz 2a3abc
static unsigned long long dt;
nsz a520c1
//static unsigned long long bytes;
nsz a520c1
nsz a520c1
#define SEC  1000000000ULL
nsz 9d224c
#define MAXN  500000000
nsz b6dbb9
#define MINT (SEC/5)
nsz a520c1
nsz 2a3abc
static unsigned long long tic() {
nsz a520c1
	struct timespec ts;
nsz a520c1
nsz 3a7270
	if (clock_gettime(CLOCK_REALTIME, &ts) < 0) {
nsz 1b83d1
		dprintf(1, "bench: clock_gettime failed: %s\n", strerror(errno));
nsz a520c1
		return 0;
nsz a520c1
	}
nsz a520c1
	return ts.tv_sec*SEC + ts.tv_nsec;
nsz a520c1
}
nsz a520c1
nsz a520c1
void start_timer() {
nsz a520c1
	if (!start)
nsz 2a3abc
		start = tic();
nsz a520c1
}
nsz a520c1
nsz a520c1
void stop_timer() {
nsz a520c1
	if (start)
nsz 2a3abc
		dt += tic() - start;
nsz a520c1
	start = 0;
nsz a520c1
}
nsz a520c1
nsz a520c1
void reset_timer() {
nsz a520c1
	if (start)
nsz 2a3abc
		start = tic();
nsz 2a3abc
	dt = 0;
nsz a520c1
}
nsz a520c1
nsz a520c1
static int nextN() {
nsz 2a3abc
	unsigned long long n = dt/N;
nsz 7d87d3
	unsigned long long i;
nsz 2a5fbe
nsz 2a5fbe
	if (n)
nsz b6dbb9
		n = MINT/n;
nsz 2a5fbe
	else
nsz b6dbb9
		n = MINT;
nsz 9d224c
	n += n/2;
nsz a520c1
	if (n > N*100ULL)
nsz a520c1
		n = N*100ULL;
nsz a520c1
	else if (n <= N)
nsz a520c1
		n = N+1;
nsz a520c1
	if (n > MAXN)
nsz a520c1
		n = MAXN;
nsz 7d87d3
nsz 7d87d3
	/* round up to a nice number */
nsz 7d87d3
	for (i = 1; i < n; i *= 10);
nsz 7d87d3
	if (i/2 >= n)
nsz 7d87d3
		i /= 2;
nsz 7d87d3
	if (i/2 >= n)
nsz 7d87d3
		i /= 2;
nsz 7d87d3
	return i;
nsz a520c1
}
nsz a520c1
nsz 9d224c
void vmstats() {
nsz 9d224c
	FILE *f;
nsz 9d224c
	char buf[256];
nsz 9d224c
	int maj, min, in_heap=0;
nsz 9d224c
	unsigned long l;
nsz 9d224c
	size_t vm_size=0, vm_rss=0, vm_priv_dirty=0;
nsz 9d224c
nsz 9d224c
	f = fopen("/proc/self/smaps", "rb");
nsz 9d224c
	if (f) while (fgets(buf, sizeof buf, f)) {
nsz 8f27a3
		if (sscanf(buf, "%*x-%*x %*s %*x %x:%x %*u %*s", &maj, &min)==2)
nsz 9d224c
			in_heap = (!maj && !min && !strstr(buf, "---p") && (strstr(buf, "[heap]") || !strchr(buf, '[')));
nsz 9d224c
		if (in_heap) {
nsz 9d224c
			if (sscanf(buf, "Size: %lu", &l)==1) vm_size += l;
nsz 9d224c
			else if (sscanf(buf, "Rss: %lu", &l)==1) vm_rss += l;
nsz 9d224c
			else if (sscanf(buf, "Private_Dirty: %lu", &l)==1) vm_priv_dirty += l;
nsz 9d224c
		}
nsz 9d224c
	}
nsz 9d224c
	if (f) fclose(f);
nsz 1b83d1
	dprintf(1, " %7zu virt %7zu res %7zu dirty", vm_size, vm_rss, vm_priv_dirty);
nsz 9d224c
}
nsz 9d224c
nsz 9d224c
void stats() {
nsz 1b83d1
	if (dt/N >= 100)
nsz 1b83d1
		dprintf(1, "%10d N %10llu ns/op   ", N, dt/N);
nsz 9d224c
	else
nsz 1b83d1
		dprintf(1, "%10d N %13.2f ns/op", N, (double)dt/N);
nsz 9d224c
	if (verbose)
nsz 9d224c
		vmstats();
nsz 1b83d1
	dprintf(1, "\n");
nsz 9d224c
}
nsz 9d224c
nsz 8561b0
static char *pattern;
nsz 8561b0
nsz 7d87d3
static void run(const char *name, void (*f)(int)) {
nsz 8561b0
	int p;
nsz 8561b0
nsz 8561b0
	if (pattern && !strstr(name, pattern))
nsz 8561b0
		return;
nsz 8561b0
	p = fork();
nsz 9d224c
	if (p) {
nsz 9d224c
		int s;
nsz 9d224c
		if (p<0 || wait(&s)<0 || !WIFEXITED(s) || WEXITSTATUS(s))
nsz 1b83d1
			dprintf(1, "benchmark %s failed\n", name);
nsz 9d224c
		return;
nsz 9d224c
	}
nsz 1b83d1
	dprintf(1, "%-32s", name);
nsz a520c1
	for (N=1; ; N=nextN()) {
nsz 7d87d3
		// TODO: fork at each iteration and pass N,dt..?
nsz a520c1
		reset_timer();
nsz a520c1
		start_timer();
nsz 7d87d3
		f(N);
nsz a520c1
		stop_timer();
nsz 1b83d1
//		dprintf(1, "%10d%12llu next: %d\n", N, dt, nextN());
nsz 9d224c
		if (dt >= SEC/2 || N >= MAXN) {
nsz 9d224c
			stats();
nsz 9d224c
			exit(0);
nsz 9d224c
		}
nsz a520c1
		if (N <= 0) {
nsz 1b83d1
			dprintf(1, "bench: fatal: N <= 0\n");
nsz 9d224c
			exit(1);
nsz a520c1
		}
nsz a520c1
	}
nsz a520c1
}
nsz a520c1
nsz 8561b0
static void usage() {
nsz 96dfbd
	fprintf(stderr, "usage: ./b [-vq] [pat]\n");
nsz 8561b0
	exit(1);
nsz 8561b0
}
nsz 8561b0
nsz 8561b0
int main(int argc, char *argv[]) {
nsz 8561b0
	int c;
nsz 8561b0
nsz 8561b0
	while((c = getopt(argc, argv, "vq")) != -1)
nsz 8561b0
		switch(c) {
nsz 8561b0
		case 'v':
nsz 8561b0
			verbose = 1;
nsz 8561b0
			break;
nsz 8561b0
		case 'q':
nsz 8561b0
			verbose = 0;
nsz 8561b0
			break;
nsz 8561b0
		default:
nsz 8561b0
			usage();
nsz 8561b0
		}
nsz 8561b0
	if (optind != argc)
nsz 8561b0
		pattern = argv[optind];
nsz a520c1
#define B(t) run(#t, t);
nsz 7d87d3
#include "tests.h"
nsz a520c1
	return 0;
nsz a520c1
}