Charles.Forsyth20060303644188019 years agoHistory
1165 lines · 19.5 KB · C
RawDownload
#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include <interp.h>#include "io.h"#include "../port/error.h"#include <isa.h>#include "kernel.h" /* Builtin module support */#include "bench.h"#include "benchmod.h" typedef enum { None, Calibrate, Base, Op, Intr, Dis, Gc, MS2T, xTest};static struct {	int		inuse;	/* reference count */	int		test;	void*	scratch;	char*	buf;	int		bufsz;	char*	wpos;	void		(*op)(void);	vlong	tickstart;} bench; static voidlog(char *msg, ...){	va_list ap; 	va_start(ap, msg);	bench.wpos = vseprint(bench.wpos, bench.buf+bench.bufsz, msg, ap);	va_end(ap);} voidelog(char *msg, ...){	va_list ap; 	if(bench.buf == 0)		return;	va_start(ap, msg);	bench.wpos = vseprint(bench.wpos, bench.buf+bench.bufsz, msg, ap);	va_end(ap);} static voidclear(void){	bench.wpos = bench.buf;} static longrep(void *to, long n, ulong offset){	long left = bench.wpos - bench.buf - offset;	if(left < 0)		left = 0;	if(n > left)		n = left;	memmove(to, bench.buf+offset, n);	return n;} static longnotest(int report, void *va, long n, ulong offset){	USED(report, va, n, offset);	if(report)		return rep(va, n, offset);	return 0;} // Calibrationstatic long MS2TS = 0;	// time stamps per millisecstatic long US2TS = 0;	// time stamps per microsecond static longcal(int report, void *va, long n, ulong offset){	int tot, i, lim, low, max, pl, mdelay;	ulong t;	if(report)		return rep(va, n, offset);	clear();	setpri(PriRealtime);	lim = 1000;	low = 64000000;	max = 0;	tot = 0;	mdelay = 1000;	for(i=0; i<lim; i++){		do{			pl = splhi();			t = archrdtsc32();			microdelay(mdelay);			t = archrdtsc32() - t;			splx(pl);		} while(t < 0);		if(t < low)			low = t;		if(t > max)			max = t;		tot += t;	}	MS2TS = tot/lim;	US2TS = MS2TS/1000;	if(va)		log("mdelay=%lud lim=%lud tot=%lud low=%lud max=%lud\n", mdelay, lim, tot, low, max);	setpri(PriNormal);	return n;} /* * ticks to format string *//*static*/ char *ts2str(vlong ticks){#define Nbuf 5	static char b[Nbuf][40];	static int n=Nbuf-1;	char *fmt, *unit;	double d; 	if(0){		print("ticks=%lld MS2TS=%ld\n", ticks, MS2TS);		d = (double)ticks;		print("1:%f\n", d);		d = (double)ticks*1000;		//print("2:%f\n", d);		d = ((double)ticks)/MS2TS;		//print("3:%f\n", d);	}	n = (n+1)%Nbuf;	if(ticks > MS2TS*1000) {		fmt = "%.2f %s";		unit = "s";		d = ((double)ticks/MS2TS) * 1000.0;	} else if(ticks > MS2TS) {		fmt = "%.2f %s";		unit = "ms";		d = (double)ticks/MS2TS;	} else if(ticks > MS2TS/1000) {		fmt = "%.2f %s";		unit = "us";		d = ((double)ticks*1000)/MS2TS;	} else {		fmt = "%.2f %s";		unit = "ns";		d = ((double)ticks*1000*1000)/MS2TS;	}	sprint(b[n], fmt, d, unit);	return b[n];} /* * ticks to microseconds */static doublets2us(vlong ticks){	return ((double)ticks*1000)/MS2TS;} /* * microseconds timestamp */static vlongbus(int reset){	vlong now;	if(US2TS == 0)		return 0;	if(reset) {		bench.tickstart = archrdtsc();		return 0;	}	now = archrdtsc();	return ((now-bench.tickstart))/US2TS;} // Basestatic longbase(int report, void *va, long n, ulong offset){	int tot, i, lim, low, max, pl;	ulong t;	char *bm; 	if(report)		return rep(va, n, offset);	clear();	setpri(PriRealtime);	lim = 1000;	low = 64000000;	max = 0;	tot = 0;	for(i=0; i<lim; i++){		do {			pl = splhi();			t = archrdtsc32();			// do nothing			t = archrdtsc32() - t;			splx(pl);		} while(t < 0);		if(t < low)			low = t;		if(t > max)			max = t;		tot += t;	}	bm = ts2str(tot/lim);	log("%d %lud %lud %lud %lud (%s)\n", up->pid, lim, tot, low, max, bm);	setpri(PriNormal);	return n;} // Timeop typedef struct Psync Psync; enum {	Maxprocs=3,}; struct Psync {	Rendez	r;	int	flag;	int	id;	int	awaken;};static Psync timesync[Maxprocs];static Ref nactive;static Ref nbusy;static RWlock sync; static voidnilop(void){} static inttimev(void *a){	return *(int*)a;} static voidtimeop0(void *ap){	int tot, i, lim, low, max;	ulong t;	Psync *ps;	char *bm; 	ps = ap;	setpri(PriRealtime);	incref(&nactive);	sleep(&ps->r, timev, &ps->flag);	rlock(&sync);	lim = 1000;	low = 64000000;	max = 0;	tot = 0;	for(i=0; i<lim; i++){		do{			t = archrdtsc32();			(*bench.op)();			t = archrdtsc32() - t;		}while(t < 0);		if(t < low)			low = t;		if(t > max)			max = t;		tot += t;	}	bm = ts2str(tot/lim);	log("%d %lud %lud %lud %lud (%s)\n", up->pid, lim, tot, low, max, bm);	runlock(&sync);	pexit("", 0);} static longtimeop(int report, void *va, long n, ulong offset){	int i, np, pl; 	if(report)		return rep(va, n, offset);	clear();	bench.op = 0;	if(strncmp(va, "nil", 3) == 0)		bench.op = nilop;	else if(strncmp(va, "sched", 5) == 0)		bench.op = sched;	else		return 0;	for(np=1; np<=Maxprocs; np++) {		nactive.ref = 0;		wlock(&sync);		log("%d procs\n", np);		setpri(PriRealtime);		for(i=0; i<np; i++) {			timesync[i].id = i;			kproc("timeop", timeop0, &timesync[i], 0);		}		while(nactive.ref < np)			tsleep(&up->sleep, return0, 0, 20);		for(i=0; i<np; i++){			timesync[i].flag = 1;			wakeup(&timesync[i].r);		}		sched();		pl = splhi();		setpri(PriNormal);		wunlock(&sync);		// now they run		wlock(&sync);		// wait for last reader		wunlock(&sync);		splx(pl);	}	return n;} typedef struct Ictr Ictr;struct Ictr {	ulong	base;	ulong	sleep;	ulong	spllo;	ulong	intr;	ulong	isave;	ulong	arrive;	ulong	wakeup;	ulong	awake;};static Ictr counters[5/*100*/], *curct;static int intrwant;static Rendez vous;int	spltbl;	/* set by spllo */int	intrtbl;	/* set by intrvec() */int	isavetbl;	/* set by intrvec() */ static int ienable;  static voidintrwake(void){	if(ienable == 0)		return;	ienable = 0;	if(spltbl == 0)		// not used here		curct->spllo = curct->intr = curct->isave = archrdtsc32();	else {		curct->spllo = spltbl;		curct->intr = intrtbl;		curct->isave = isavetbl;	}	curct->arrive = archrdtsc32();	intrwant = 0;	wakeup(&vous);	curct->wakeup = archrdtsc32();} /* * sleep calls intrtest with splhi (under lock): * provoke the interrupt now, so that it is guaranteed * not to happen until sleep has queued the process, * forcing wakeup to do something. */static intintrtest(void*){	ienable = 1;		/* enable recording on interrupt */	curct->sleep = archrdtsc32();	return intrwant==0;} static longintrtime(int report, void *va, long n, ulong offset){	Ictr *ic;	long t;	int i;	char *bm;	if(report)		return rep(va, n, offset);	clear(); 	setpri(PriRealtime);	sched();	curct = counters;	ienable = 0;	addclock0link(intrwake, MS2HZ);	for(i=0; i<nelem(counters); i++){		curct = &counters[i];		intrwant = 1;		curct->base = archrdtsc32();		sleep(&vous, intrtest, nil);		curct->awake = archrdtsc32();		sched();	/* just to slow it down between trials */	}	log("interrupt\n");	for(i=0; i<nelem(counters); i++){		ic = &counters[i];		t = ic->awake - ic->base;		bm = ts2str(ic->awake - ic->arrive);		ic->awake -= ic->wakeup;		ic->wakeup -= ic->arrive;		ic->arrive -= ic->isave;		ic->isave -= ic->intr;		ic->intr -= ic->spllo;		ic->spllo -= ic->sleep;		ic->sleep -= ic->base;		log("%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t%ld\t%ld (%s)\n", ic->sleep, ic->spllo, ic->intr, ic->isave, ic->arrive, ic->wakeup, ic->awake, t, bm);	}	setpri(PriNormal);	return n;}  /* DIS operation timing */ typedef struct  {	vlong	n;		/* count */	vlong	min;	vlong 	max;	vlong	sum;	vlong	sumsq;	/* sum of squares */} Stat; static voidstat(enum { Reset, Inc } op, Stat *c, vlong val){	switch(op) {	case	Reset:		c->n = 0;		c->sum = 0;		c->sumsq = 0;		c->min = 0;		c->max = 0;		break;	case Inc:		c->n++;		c->sum += val;		c->sumsq += val*val;		break;	}	if(val < c->min || c->n == 1)		c->min = val;	if(val > c->max || c->n == 1)		c->max = val;} static voidstatinc(Stat *d, Stat *s){	d->n += s->n;	d->sum += s->sum;	d->sumsq += s->sumsq;	if(s->min < d->min || d->n == s->n)		d->min = s->min;	if(s->max > d->max || d->n == s->n)		d->max = s->max;} enum{	HSIZE	= 31,	MAXCOUNT	= 100000000L,}; typedef struct {	int		op;	int		pc;	long		count;	Stat	t;		/* combined dec and execution time */} Istat; typedef struct Mstat Mstat;struct Mstat {	char*	name;	char*	path;	int		ninst;	Istat*	inst;	Inst*		base;	Mstat*	hash;	Mstat*	link;}; struct{	Mstat*	hash[HSIZE];	Mstat*	list;} vmstat; 

Lines 1–500 of 1165.