| #include "stdinc.h" | 
 | #include "dat.h" | 
 | #include "fns.h" | 
 |  | 
 | int collectstats = 1; | 
 |  | 
 | /* keep in sync with dat.h:/NStat */ | 
 | Statdesc statdesc[NStat] = | 
 | { | 
 | 	{ "rpc total", }, | 
 | 	{ "rpc reads", }, | 
 | 	{ "rpc reads ok", }, | 
 | 	{ "rpc reads failed", }, | 
 | 	{ "rpc read bytes", }, | 
 | 	{ "rpc read time", }, | 
 | 	{ "rpc read cached", }, | 
 | 	{ "rpc read cached time", }, | 
 | 	{ "rpc read uncached", }, | 
 | 	{ "rpc read uncached time "}, | 
 | 	 | 
 | 	{ "rpc writes", }, | 
 | 	{ "rpc writes new", }, | 
 | 	{ "rpc writes old", }, | 
 | 	{ "rpc writes failed", }, | 
 | 	{ "rpc write bytes", }, | 
 | 	{ "rpc write time", }, | 
 | 	{ "rpc write new time", }, | 
 | 	{ "rpc write old time", }, | 
 |  | 
 | 	{ "lump cache hits", }, | 
 | 	{ "lump cache misses", }, | 
 | 	{ "lump cache reads", }, | 
 | 	{ "lump cache writes", }, | 
 | 	{ "lump cache size", }, | 
 | 	{ "lump cache stall", }, | 
 | 	{ "lump cache read time", }, | 
 |  | 
 | 	{ "disk cache hits", }, | 
 | 	{ "disk cache misses", }, | 
 | 	{ "disk cache lookups", }, | 
 | 	{ "disk cache reads", }, | 
 | 	{ "disk cache writes", }, | 
 | 	{ "disk cache dirty", }, | 
 | 	{ "disk cache size", }, | 
 | 	{ "disk cache flushes", }, | 
 | 	{ "disk cache stalls", }, | 
 | 	{ "disk cache lookup time", }, | 
 |  | 
 | 	{ "disk block stalls", }, | 
 | 	{ "lump stalls", }, | 
 |  | 
 | 	{ "index cache hits", }, | 
 | 	{ "index cache misses", }, | 
 | 	{ "index cache reads", }, | 
 | 	{ "index cache writes", }, | 
 | 	{ "index cache fills", }, | 
 | 	{ "index cache prefetches", }, | 
 | 	{ "index cache dirty", }, | 
 | 	{ "index cache size", }, | 
 | 	{ "index cache flushes", }, | 
 | 	{ "index cache stalls", }, | 
 | 	{ "index cache read time", }, | 
 | 	{ "index cache lookups" }, | 
 | 	{ "index cache summary hits" }, | 
 | 	{ "index cache summary prefetches" }, | 
 |  | 
 | 	{ "bloom filter hits", }, | 
 | 	{ "bloom filter misses", }, | 
 | 	{ "bloom filter false misses", }, | 
 | 	{ "bloom filter lookups", }, | 
 | 	{ "bloom filter ones", }, | 
 | 	{ "bloom filter bits", }, | 
 |  | 
 | 	{ "arena block reads", }, | 
 | 	{ "arena block read bytes", }, | 
 | 	{ "arena block writes", }, | 
 | 	{ "arena block write bytes", }, | 
 |  | 
 | 	{ "isect block reads", }, | 
 | 	{ "isect block read bytes", }, | 
 | 	{ "isect block writes", }, | 
 | 	{ "isect block write bytes", }, | 
 |  | 
 | 	{ "sum reads", }, | 
 | 	{ "sum read bytes", }, | 
 | 	 | 
 | 	{ "cig loads" }, | 
 | 	{ "cig load time" }, | 
 | }; | 
 |  | 
 | QLock statslock; | 
 | Stats stats; | 
 | Stats *stathist; | 
 | int nstathist; | 
 | ulong statind; | 
 | ulong stattime; | 
 |  | 
 | void | 
 | statsproc(void *v) | 
 | { | 
 | 	USED(v); | 
 |  | 
 | 	for(;;){ | 
 | 		stats.now = time(0); | 
 | 		stathist[stattime%nstathist] = stats; | 
 | 		stattime++; | 
 | 		sleep(1000); | 
 | 	} | 
 | } | 
 |  | 
 | void | 
 | statsinit(void) | 
 | { | 
 | 	nstathist = 90000; | 
 | 	stathist = MKNZ(Stats, nstathist); | 
 | 	vtproc(statsproc, nil); | 
 | } | 
 |  | 
 | void | 
 | setstat(int index, long val) | 
 | { | 
 | 	qlock(&statslock); | 
 | 	stats.n[index] = val; | 
 | 	qunlock(&statslock); | 
 | } | 
 |  | 
 | void | 
 | addstat(int index, int inc) | 
 | { | 
 | 	if(!collectstats) | 
 | 		return; | 
 | 	qlock(&statslock); | 
 | 	stats.n[index] += inc; | 
 | 	qunlock(&statslock); | 
 | } | 
 |  | 
 | void | 
 | addstat2(int index, int inc, int index1, int inc1) | 
 | { | 
 | 	if(!collectstats) | 
 | 		return; | 
 | 	qlock(&statslock); | 
 | 	stats.n[index] += inc; | 
 | 	stats.n[index1] += inc1; | 
 | 	qunlock(&statslock); | 
 | } | 
 |  | 
 | void | 
 | printstats(void) | 
 | { | 
 | } | 
 |  | 
 | void | 
 | binstats(long (*fn)(Stats *s0, Stats *s1, void *arg), void *arg, | 
 | 	long t0, long t1, Statbin *bin, int nbin) | 
 | { | 
 | 	long xt0, t, te, v; | 
 | 	int i, j, lo, hi, m; | 
 | 	vlong tot; | 
 | 	Statbin *b; | 
 | 	 | 
 | 	t = stats.now; | 
 | 	 | 
 | 	/* negative times mean relative to now. */ | 
 | 	if(t0 <= 0) | 
 | 		t0 += t; | 
 | 	if(t1 <= 0) | 
 | 		t1 += t; | 
 | 	/* ten minute range if none given */ | 
 | 	if(t1 <= t0) | 
 | 		t0 = t1 - 60*10; | 
 | 	if(0) fprint(2, "stats %ld-%ld\n", t0, t1); | 
 | 	 | 
 | 	/* binary search to find t0-1 or close */ | 
 | 	lo = stattime; | 
 | 	hi = stattime+nstathist; | 
 | 	while(lo+1 < hi){ | 
 | 		m = (lo+hi)/2; | 
 | 		if(stathist[m%nstathist].now >= t0) | 
 | 			hi = m; | 
 | 		else | 
 | 			lo = m; | 
 | 	} | 
 | 	xt0 = stathist[lo%nstathist].now; | 
 | 	if(xt0 >= t1){ | 
 | 		/* no samples */ | 
 | 		memset(bin, 0, nbin*sizeof bin[0]); | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	hi = stattime+nstathist; | 
 | 	j = lo+1; | 
 | 	for(i=0; i<nbin; i++){ | 
 | 		te = t0 + (t1-t0)*i/nbin; | 
 | 		b = &bin[i]; | 
 | 		memset(b, 0, sizeof *b); | 
 | 		tot = 0; | 
 | 		for(; j<hi && stathist[j%nstathist].now<te; j++){ | 
 | 			v = fn(&stathist[(j-1)%nstathist], &stathist[j%nstathist], arg); | 
 | 			if(b->nsamp==0 || v < b->min) | 
 | 				b->min = v; | 
 | 			if(b->nsamp==0 || v > b->max) | 
 | 				b->max = v; | 
 | 			tot += v; | 
 | 			b->nsamp++; | 
 | 		} | 
 | 		if(b->nsamp) | 
 | 			b->avg = tot / b->nsamp; | 
 | 		if(b->nsamp==0 && i>0) | 
 | 			*b = bin[i-1]; | 
 | 	}	 | 
 | } |