xref: /plan9/sys/src/cmd/stats.c (revision 3f69512988c55e1bb3bc10cc4fa9825ba0b07fec)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <ctype.h>
47dd7cddfSDavid du Colombier #include <auth.h>
57dd7cddfSDavid du Colombier #include <fcall.h>
67dd7cddfSDavid du Colombier #include <draw.h>
77dd7cddfSDavid du Colombier #include <event.h>
83e12c5d1SDavid du Colombier 
97dd7cddfSDavid du Colombier #define	MAXNUM	8	/* maximum number of numbers on data line */
103e12c5d1SDavid du Colombier 
117dd7cddfSDavid du Colombier typedef struct Graph		Graph;
127dd7cddfSDavid du Colombier typedef struct Machine	Machine;
137dd7cddfSDavid du Colombier 
147dd7cddfSDavid du Colombier struct Graph
157dd7cddfSDavid du Colombier {
167dd7cddfSDavid du Colombier 	int		colindex;
177dd7cddfSDavid du Colombier 	Rectangle	r;
187dd7cddfSDavid du Colombier 	int		*data;
197dd7cddfSDavid du Colombier 	int		ndata;
207dd7cddfSDavid du Colombier 	char		*label;
2180ee5cbfSDavid du Colombier 	void		(*newvalue)(Machine*, long*, long*, int);
227dd7cddfSDavid du Colombier 	void		(*update)(Graph*, long, long);
237dd7cddfSDavid du Colombier 	Machine	*mach;
247dd7cddfSDavid du Colombier 	int		overflow;
257dd7cddfSDavid du Colombier 	Image	*overtmp;
267dd7cddfSDavid du Colombier };
273e12c5d1SDavid du Colombier 
283e12c5d1SDavid du Colombier enum
293e12c5d1SDavid du Colombier {
307dd7cddfSDavid du Colombier 	/* /dev/swap */
317dd7cddfSDavid du Colombier 	Mem		= 0,
327dd7cddfSDavid du Colombier 	Maxmem,
333e12c5d1SDavid du Colombier 	Swap,
347dd7cddfSDavid du Colombier 	Maxswap,
357dd7cddfSDavid du Colombier 	/* /dev/sysstats */
367dd7cddfSDavid du Colombier 	Procno	= 0,
377dd7cddfSDavid du Colombier 	Context,
387dd7cddfSDavid du Colombier 	Interrupt,
393e12c5d1SDavid du Colombier 	Syscall,
403e12c5d1SDavid du Colombier 	Fault,
417dd7cddfSDavid du Colombier 	TLBfault,
427dd7cddfSDavid du Colombier 	TLBpurge,
433e12c5d1SDavid du Colombier 	Load,
447dd7cddfSDavid du Colombier 	/* /net/ether0/0/stats */
457dd7cddfSDavid du Colombier 	In		= 0,
467dd7cddfSDavid du Colombier 	Out,
477dd7cddfSDavid du Colombier 	Err0,
483e12c5d1SDavid du Colombier };
493e12c5d1SDavid du Colombier 
507dd7cddfSDavid du Colombier struct Machine
513e12c5d1SDavid du Colombier {
527dd7cddfSDavid du Colombier 	char		*name;
537dd7cddfSDavid du Colombier 	int		remote;
547dd7cddfSDavid du Colombier 	int		statsfd;
557dd7cddfSDavid du Colombier 	int		swapfd;
567dd7cddfSDavid du Colombier 	int		etherfd;
579a747e4fSDavid du Colombier 	int		ifstatsfd;
5880ee5cbfSDavid du Colombier 	int		batteryfd;
599a747e4fSDavid du Colombier 	int		bitsybatfd;
607dd7cddfSDavid du Colombier 	int		disable;
613e12c5d1SDavid du Colombier 
627dd7cddfSDavid du Colombier 	long		devswap[4];
637dd7cddfSDavid du Colombier 	long		devsysstat[8];
647dd7cddfSDavid du Colombier 	long		prevsysstat[8];
657dd7cddfSDavid du Colombier 	int		nproc;
667dd7cddfSDavid du Colombier 	long		netetherstats[8];
677dd7cddfSDavid du Colombier 	long		prevetherstats[8];
6880ee5cbfSDavid du Colombier 	long		batterystats[2];
699a747e4fSDavid du Colombier 	long		netetherifstats[2];
703e12c5d1SDavid du Colombier 
717dd7cddfSDavid du Colombier 	char		buf[1024];
727dd7cddfSDavid du Colombier 	char		*bufp;
737dd7cddfSDavid du Colombier 	char		*ebufp;
743e12c5d1SDavid du Colombier };
757dd7cddfSDavid du Colombier 
767dd7cddfSDavid du Colombier enum
777dd7cddfSDavid du Colombier {
787dd7cddfSDavid du Colombier 	Mainproc,
797dd7cddfSDavid du Colombier 	Mouseproc,
807dd7cddfSDavid du Colombier 	NPROC,
817dd7cddfSDavid du Colombier };
827dd7cddfSDavid du Colombier 
837dd7cddfSDavid du Colombier enum
847dd7cddfSDavid du Colombier {
857dd7cddfSDavid du Colombier 	Ncolor	= 6,
867dd7cddfSDavid du Colombier 	Ysqueeze	= 2,	/* vertical squeezing of label text */
877dd7cddfSDavid du Colombier 	Labspace	= 2,	/* room around label */
887dd7cddfSDavid du Colombier 	Dot		= 2,	/* height of dot */
897dd7cddfSDavid du Colombier 	Opwid	= 5,	/* strlen("add  ") or strlen("drop ") */
9080ee5cbfSDavid du Colombier 	Nlab		= 3,	/* max number of labels on y axis */
9180ee5cbfSDavid du Colombier 	Lablen	= 16,	/* max length of label */
9280ee5cbfSDavid du Colombier 	Lx		= 4,	/* label tick length */
937dd7cddfSDavid du Colombier };
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier enum Menu2
967dd7cddfSDavid du Colombier {
977dd7cddfSDavid du Colombier 	Mcontext,
987dd7cddfSDavid du Colombier 	Mether,
997dd7cddfSDavid du Colombier 	Methererr,
1007dd7cddfSDavid du Colombier 	Metherin,
1017dd7cddfSDavid du Colombier 	Metherout,
1027dd7cddfSDavid du Colombier 	Mfault,
1037dd7cddfSDavid du Colombier 	Mintr,
1047dd7cddfSDavid du Colombier 	Mload,
1057dd7cddfSDavid du Colombier 	Mmem,
1067dd7cddfSDavid du Colombier 	Mswap,
1077dd7cddfSDavid du Colombier 	Msyscall,
1087dd7cddfSDavid du Colombier 	Mtlbmiss,
1097dd7cddfSDavid du Colombier 	Mtlbpurge,
11080ee5cbfSDavid du Colombier 	Mbattery,
1119a747e4fSDavid du Colombier 	Msignal,
1127dd7cddfSDavid du Colombier 	Nmenu2,
1137dd7cddfSDavid du Colombier };
1147dd7cddfSDavid du Colombier 
1157dd7cddfSDavid du Colombier char	*menu2str[Nmenu2+1] = {
1167dd7cddfSDavid du Colombier 	"add  context ",
1177dd7cddfSDavid du Colombier 	"add  ether   ",
1187dd7cddfSDavid du Colombier 	"add  ethererr",
1197dd7cddfSDavid du Colombier 	"add  etherin ",
1207dd7cddfSDavid du Colombier 	"add  etherout",
1217dd7cddfSDavid du Colombier 	"add  fault   ",
1227dd7cddfSDavid du Colombier 	"add  intr    ",
1237dd7cddfSDavid du Colombier 	"add  load    ",
1247dd7cddfSDavid du Colombier 	"add  mem     ",
1257dd7cddfSDavid du Colombier 	"add  swap    ",
1267dd7cddfSDavid du Colombier 	"add  syscall ",
1277dd7cddfSDavid du Colombier 	"add  tlbmiss ",
1287dd7cddfSDavid du Colombier 	"add  tlbpurge",
12980ee5cbfSDavid du Colombier 	"add  battery ",
1309a747e4fSDavid du Colombier 	"add  802.11b ",
1317dd7cddfSDavid du Colombier 	nil,
1327dd7cddfSDavid du Colombier };
1337dd7cddfSDavid du Colombier 
1347dd7cddfSDavid du Colombier 
13580ee5cbfSDavid du Colombier void	contextval(Machine*, long*, long*, int),
13680ee5cbfSDavid du Colombier 	etherval(Machine*, long*, long*, int),
13780ee5cbfSDavid du Colombier 	ethererrval(Machine*, long*, long*, int),
13880ee5cbfSDavid du Colombier 	etherinval(Machine*, long*, long*, int),
13980ee5cbfSDavid du Colombier 	etheroutval(Machine*, long*, long*, int),
14080ee5cbfSDavid du Colombier 	faultval(Machine*, long*, long*, int),
14180ee5cbfSDavid du Colombier 	intrval(Machine*, long*, long*, int),
14280ee5cbfSDavid du Colombier 	loadval(Machine*, long*, long*, int),
14380ee5cbfSDavid du Colombier 	memval(Machine*, long*, long*, int),
14480ee5cbfSDavid du Colombier 	swapval(Machine*, long*, long*, int),
14580ee5cbfSDavid du Colombier 	syscallval(Machine*, long*, long*, int),
14680ee5cbfSDavid du Colombier 	tlbmissval(Machine*, long*, long*, int),
14780ee5cbfSDavid du Colombier 	tlbpurgeval(Machine*, long*, long*, int),
1489a747e4fSDavid du Colombier 	batteryval(Machine*, long*, long*, int),
1499a747e4fSDavid du Colombier 	signalval(Machine*, long*, long*, int);
1507dd7cddfSDavid du Colombier 
1517dd7cddfSDavid du Colombier Menu	menu2 = {menu2str, nil};
1527dd7cddfSDavid du Colombier int		present[Nmenu2];
15380ee5cbfSDavid du Colombier void		(*newvaluefn[Nmenu2])(Machine*, long*, long*, int init) = {
1547dd7cddfSDavid du Colombier 	contextval,
1557dd7cddfSDavid du Colombier 	etherval,
1567dd7cddfSDavid du Colombier 	ethererrval,
1577dd7cddfSDavid du Colombier 	etherinval,
1587dd7cddfSDavid du Colombier 	etheroutval,
1597dd7cddfSDavid du Colombier 	faultval,
1607dd7cddfSDavid du Colombier 	intrval,
1617dd7cddfSDavid du Colombier 	loadval,
1627dd7cddfSDavid du Colombier 	memval,
1637dd7cddfSDavid du Colombier 	swapval,
1647dd7cddfSDavid du Colombier 	syscallval,
1657dd7cddfSDavid du Colombier 	tlbmissval,
1667dd7cddfSDavid du Colombier 	tlbpurgeval,
16780ee5cbfSDavid du Colombier 	batteryval,
1689a747e4fSDavid du Colombier 	signalval,
1697dd7cddfSDavid du Colombier };
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier Image	*cols[Ncolor][3];
1727dd7cddfSDavid du Colombier Graph	*graph;
1737dd7cddfSDavid du Colombier Machine	*mach;
1747dd7cddfSDavid du Colombier Font		*mediumfont;
1757dd7cddfSDavid du Colombier char		*mysysname;
1769a747e4fSDavid du Colombier char		argchars[] = "8bceEfimlnpstw";
1777dd7cddfSDavid du Colombier int		pids[NPROC];
1787dd7cddfSDavid du Colombier int 		parity;	/* toggled to avoid patterns in textured background */
1797dd7cddfSDavid du Colombier int		nmach;
1807dd7cddfSDavid du Colombier int		ngraph;	/* totaly number is ngraph*nmach */
18180ee5cbfSDavid du Colombier double	scale = 1.0;
18280ee5cbfSDavid du Colombier int		logscale = 0;
18380ee5cbfSDavid du Colombier int		ylabels = 0;
1849a747e4fSDavid du Colombier int		oldsystem = 0;
1857dd7cddfSDavid du Colombier 
1867dd7cddfSDavid du Colombier char		*procnames[NPROC] = {"main", "mouse"};
1877dd7cddfSDavid du Colombier 
1887dd7cddfSDavid du Colombier void
1897dd7cddfSDavid du Colombier killall(char *s)
1907dd7cddfSDavid du Colombier {
1917dd7cddfSDavid du Colombier 	int i, pid;
1927dd7cddfSDavid du Colombier 
1937dd7cddfSDavid du Colombier 	pid = getpid();
1947dd7cddfSDavid du Colombier 	for(i=0; i<NPROC; i++)
1957dd7cddfSDavid du Colombier 		if(pids[i] && pids[i]!=pid)
1967dd7cddfSDavid du Colombier 			postnote(PNPROC, pids[i], "kill");
1977dd7cddfSDavid du Colombier 	exits(s);
1987dd7cddfSDavid du Colombier }
1997dd7cddfSDavid du Colombier 
2007dd7cddfSDavid du Colombier void*
2017dd7cddfSDavid du Colombier emalloc(ulong sz)
2027dd7cddfSDavid du Colombier {
2037dd7cddfSDavid du Colombier 	void *v;
2047dd7cddfSDavid du Colombier 	v = malloc(sz);
2057dd7cddfSDavid du Colombier 	if(v == nil) {
2067dd7cddfSDavid du Colombier 		fprint(2, "stats: out of memory allocating %ld: %r\n", sz);
2077dd7cddfSDavid du Colombier 		killall("mem");
2087dd7cddfSDavid du Colombier 	}
2097dd7cddfSDavid du Colombier 	memset(v, 0, sz);
2107dd7cddfSDavid du Colombier 	return v;
2117dd7cddfSDavid du Colombier }
2127dd7cddfSDavid du Colombier 
2137dd7cddfSDavid du Colombier void*
2147dd7cddfSDavid du Colombier erealloc(void *v, ulong sz)
2157dd7cddfSDavid du Colombier {
2167dd7cddfSDavid du Colombier 	v = realloc(v, sz);
2177dd7cddfSDavid du Colombier 	if(v == nil) {
2187dd7cddfSDavid du Colombier 		fprint(2, "stats: out of memory reallocating %ld: %r\n", sz);
2197dd7cddfSDavid du Colombier 		killall("mem");
2207dd7cddfSDavid du Colombier 	}
2217dd7cddfSDavid du Colombier 	return v;
2223e12c5d1SDavid du Colombier }
2233e12c5d1SDavid du Colombier 
2243e12c5d1SDavid du Colombier char*
2257dd7cddfSDavid du Colombier estrdup(char *s)
2263e12c5d1SDavid du Colombier {
2277dd7cddfSDavid du Colombier 	char *t;
2287dd7cddfSDavid du Colombier 	if((t = strdup(s)) == nil) {
2297dd7cddfSDavid du Colombier 		fprint(2, "stats: out of memory in strdup(%.10s): %r\n", s);
2307dd7cddfSDavid du Colombier 		killall("mem");
2317dd7cddfSDavid du Colombier 	}
2327dd7cddfSDavid du Colombier 	return t;
2333e12c5d1SDavid du Colombier }
2343e12c5d1SDavid du Colombier 
2353e12c5d1SDavid du Colombier void
2367dd7cddfSDavid du Colombier mkcol(int i, int c0, int c1, int c2)
2373e12c5d1SDavid du Colombier {
2387dd7cddfSDavid du Colombier 	cols[i][0] = allocimagemix(display, c0, DWhite);
2397dd7cddfSDavid du Colombier 	cols[i][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c1);
2407dd7cddfSDavid du Colombier 	cols[i][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c2);
2417dd7cddfSDavid du Colombier }
2423e12c5d1SDavid du Colombier 
2437dd7cddfSDavid du Colombier void
2447dd7cddfSDavid du Colombier colinit(void)
2457dd7cddfSDavid du Colombier {
2467dd7cddfSDavid du Colombier 	mediumfont = openfont(display, "/lib/font/bit/pelm/latin1.8.font");
2477dd7cddfSDavid du Colombier 	if(mediumfont == nil)
2487dd7cddfSDavid du Colombier 		mediumfont = font;
2497dd7cddfSDavid du Colombier 
2507dd7cddfSDavid du Colombier 	/* Peach */
2517dd7cddfSDavid du Colombier 	mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF);
2527dd7cddfSDavid du Colombier 	/* Aqua */
2537dd7cddfSDavid du Colombier 	mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue);
2547dd7cddfSDavid du Colombier 	/* Yellow */
2557dd7cddfSDavid du Colombier 	mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen);
2567dd7cddfSDavid du Colombier 	/* Green */
2577dd7cddfSDavid du Colombier 	mkcol(3, DPalegreen, DMedgreen, DDarkgreen);
2587dd7cddfSDavid du Colombier 	/* Blue */
2597dd7cddfSDavid du Colombier 	mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF);
2607dd7cddfSDavid du Colombier 	/* Grey */
2617dd7cddfSDavid du Colombier 	cols[5][0] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF);
2627dd7cddfSDavid du Colombier 	cols[5][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF);
2637dd7cddfSDavid du Colombier 	cols[5][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x888888FF);
2647dd7cddfSDavid du Colombier }
2657dd7cddfSDavid du Colombier 
2667dd7cddfSDavid du Colombier int
2677dd7cddfSDavid du Colombier loadbuf(Machine *m, int *fd)
2687dd7cddfSDavid du Colombier {
2697dd7cddfSDavid du Colombier 	int n;
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier 
2727dd7cddfSDavid du Colombier 	if(*fd < 0)
2737dd7cddfSDavid du Colombier 		return 0;
2747dd7cddfSDavid du Colombier 	seek(*fd, 0, 0);
2757dd7cddfSDavid du Colombier 	n = read(*fd, m->buf, sizeof m->buf);
2767dd7cddfSDavid du Colombier 	if(n <= 0){
2777dd7cddfSDavid du Colombier 		close(*fd);
2787dd7cddfSDavid du Colombier 		*fd = -1;
2797dd7cddfSDavid du Colombier 		return 0;
2807dd7cddfSDavid du Colombier 	}
2817dd7cddfSDavid du Colombier 	m->bufp = m->buf;
2827dd7cddfSDavid du Colombier 	m->ebufp = m->buf+n;
2837dd7cddfSDavid du Colombier 	return 1;
2847dd7cddfSDavid du Colombier }
2857dd7cddfSDavid du Colombier 
2867dd7cddfSDavid du Colombier void
2877dd7cddfSDavid du Colombier label(Point p, int dy, char *text)
2887dd7cddfSDavid du Colombier {
2897dd7cddfSDavid du Colombier 	char *s;
2907dd7cddfSDavid du Colombier 	Rune r[2];
2917dd7cddfSDavid du Colombier 	int w, maxw, maxy;
2927dd7cddfSDavid du Colombier 
2937dd7cddfSDavid du Colombier 	p.x += Labspace;
2947dd7cddfSDavid du Colombier 	maxy = p.y+dy;
2957dd7cddfSDavid du Colombier 	maxw = 0;
2967dd7cddfSDavid du Colombier 	r[1] = '\0';
2977dd7cddfSDavid du Colombier 	for(s=text; *s; ){
2987dd7cddfSDavid du Colombier 		if(p.y+mediumfont->height-Ysqueeze > maxy)
2997dd7cddfSDavid du Colombier 			break;
3007dd7cddfSDavid du Colombier 		w = chartorune(r, s);
3017dd7cddfSDavid du Colombier 		s += w;
3027dd7cddfSDavid du Colombier 		w = runestringwidth(mediumfont, r);
3037dd7cddfSDavid du Colombier 		if(w > maxw)
3047dd7cddfSDavid du Colombier 			maxw = w;
3057dd7cddfSDavid du Colombier 		runestring(screen, p, display->black, ZP, mediumfont, r);
3067dd7cddfSDavid du Colombier 		p.y += mediumfont->height-Ysqueeze;
3077dd7cddfSDavid du Colombier 	}
3087dd7cddfSDavid du Colombier }
3097dd7cddfSDavid du Colombier 
3107dd7cddfSDavid du Colombier Point
3117dd7cddfSDavid du Colombier paritypt(int x)
3127dd7cddfSDavid du Colombier {
3137dd7cddfSDavid du Colombier 	return Pt(x+parity, 0);
3147dd7cddfSDavid du Colombier }
3157dd7cddfSDavid du Colombier 
3167dd7cddfSDavid du Colombier Point
3177dd7cddfSDavid du Colombier datapoint(Graph *g, int x, long v, long vmax)
3187dd7cddfSDavid du Colombier {
3197dd7cddfSDavid du Colombier 	Point p;
32080ee5cbfSDavid du Colombier 	double y;
3217dd7cddfSDavid du Colombier 
3227dd7cddfSDavid du Colombier 	p.x = x;
32380ee5cbfSDavid du Colombier 	y = ((double)v)/(vmax*scale);
32480ee5cbfSDavid du Colombier 	if(logscale){
32580ee5cbfSDavid du Colombier 		/*
32680ee5cbfSDavid du Colombier 		 * Arrange scale to cover a factor of 1000.
32780ee5cbfSDavid du Colombier 		 * vmax corresponds to the 100 mark.
32880ee5cbfSDavid du Colombier 		 * 10*vmax is the top of the scale.
32980ee5cbfSDavid du Colombier 		 */
33080ee5cbfSDavid du Colombier 		if(y <= 0.)
33180ee5cbfSDavid du Colombier 			y = 0;
33280ee5cbfSDavid du Colombier 		else{
33380ee5cbfSDavid du Colombier 			y = log10(y);
33480ee5cbfSDavid du Colombier 			/* 1 now corresponds to the top; -2 to the bottom; rescale */
33580ee5cbfSDavid du Colombier 			y = (y+2.)/3.;
33680ee5cbfSDavid du Colombier 		}
33780ee5cbfSDavid du Colombier 	}
33880ee5cbfSDavid du Colombier 	p.y = g->r.max.y - Dy(g->r)*y - Dot;
3397dd7cddfSDavid du Colombier 	if(p.y < g->r.min.y)
3407dd7cddfSDavid du Colombier 		p.y = g->r.min.y;
3417dd7cddfSDavid du Colombier 	if(p.y > g->r.max.y-Dot)
3427dd7cddfSDavid du Colombier 		p.y = g->r.max.y-Dot;
3437dd7cddfSDavid du Colombier 	return p;
3447dd7cddfSDavid du Colombier }
3457dd7cddfSDavid du Colombier 
3467dd7cddfSDavid du Colombier void
3477dd7cddfSDavid du Colombier drawdatum(Graph *g, int x, long prev, long v, long vmax)
3487dd7cddfSDavid du Colombier {
3497dd7cddfSDavid du Colombier 	int c;
3507dd7cddfSDavid du Colombier 	Point p, q;
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier 	c = g->colindex;
3537dd7cddfSDavid du Colombier 	p = datapoint(g, x, v, vmax);
3547dd7cddfSDavid du Colombier 	q = datapoint(g, x, prev, vmax);
3557dd7cddfSDavid du Colombier 	if(p.y < q.y){
3567dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, g->r.min.y, p.x+1, p.y), cols[c][0], nil, paritypt(p.x));
3577dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, p.y, p.x+1, q.y+Dot), cols[c][2], nil, ZP);
3587dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, q.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP);
3597dd7cddfSDavid du Colombier 	}else{
3607dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, g->r.min.y, p.x+1, q.y), cols[c][0], nil, paritypt(p.x));
3617dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, q.y, p.x+1, p.y+Dot), cols[c][2], nil, ZP);
3627dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, p.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP);
3637dd7cddfSDavid du Colombier 	}
3647dd7cddfSDavid du Colombier 
3657dd7cddfSDavid du Colombier }
3667dd7cddfSDavid du Colombier 
3677dd7cddfSDavid du Colombier void
3687dd7cddfSDavid du Colombier redraw(Graph *g, int vmax)
3697dd7cddfSDavid du Colombier {
3707dd7cddfSDavid du Colombier 	int i, c;
3717dd7cddfSDavid du Colombier 
3727dd7cddfSDavid du Colombier 	c = g->colindex;
3737dd7cddfSDavid du Colombier 	draw(screen, g->r, cols[c][0], nil, paritypt(g->r.min.x));
3747dd7cddfSDavid du Colombier 	for(i=1; i<Dx(g->r); i++)
3757dd7cddfSDavid du Colombier 		drawdatum(g, g->r.max.x-i, g->data[i-1], g->data[i], vmax);
3767dd7cddfSDavid du Colombier 	drawdatum(g, g->r.min.x, g->data[i], g->data[i], vmax);
3777dd7cddfSDavid du Colombier 	g->overflow = 0;
3787dd7cddfSDavid du Colombier }
3797dd7cddfSDavid du Colombier 
3807dd7cddfSDavid du Colombier void
3817dd7cddfSDavid du Colombier update1(Graph *g, long v, long vmax)
3827dd7cddfSDavid du Colombier {
3837dd7cddfSDavid du Colombier 	char buf[32];
38480ee5cbfSDavid du Colombier 	int overflow;
3857dd7cddfSDavid du Colombier 
3867dd7cddfSDavid du Colombier 	if(g->overflow && g->overtmp!=nil)
3877dd7cddfSDavid du Colombier 		draw(screen, g->overtmp->r, g->overtmp, nil, g->overtmp->r.min);
3887dd7cddfSDavid du Colombier 	draw(screen, g->r, screen, nil, Pt(g->r.min.x+1, g->r.min.y));
3897dd7cddfSDavid du Colombier 	drawdatum(g, g->r.max.x-1, g->data[0], v, vmax);
3907dd7cddfSDavid du Colombier 	memmove(g->data+1, g->data, (g->ndata-1)*sizeof(g->data[0]));
3917dd7cddfSDavid du Colombier 	g->data[0] = v;
3927dd7cddfSDavid du Colombier 	g->overflow = 0;
39380ee5cbfSDavid du Colombier 	if(logscale)
39480ee5cbfSDavid du Colombier 		overflow = (v>10*vmax*scale);
39580ee5cbfSDavid du Colombier 	else
39680ee5cbfSDavid du Colombier 		overflow = (v>vmax*scale);
39780ee5cbfSDavid du Colombier 	if(overflow && g->overtmp!=nil){
3987dd7cddfSDavid du Colombier 		g->overflow = 1;
3997dd7cddfSDavid du Colombier 		draw(g->overtmp, g->overtmp->r, screen, nil, g->overtmp->r.min);
4007dd7cddfSDavid du Colombier 		sprint(buf, "%ld", v);
4017dd7cddfSDavid du Colombier 		string(screen, g->overtmp->r.min, display->black, ZP, mediumfont, buf);
4027dd7cddfSDavid du Colombier 	}
4037dd7cddfSDavid du Colombier }
4047dd7cddfSDavid du Colombier 
4057dd7cddfSDavid du Colombier /* read one line of text from buffer and process integers */
4067dd7cddfSDavid du Colombier int
4077dd7cddfSDavid du Colombier readnums(Machine *m, int n, long *a, int spanlines)
4087dd7cddfSDavid du Colombier {
4097dd7cddfSDavid du Colombier 	int i;
4107dd7cddfSDavid du Colombier 	char *p, *ep;
4117dd7cddfSDavid du Colombier 
4127dd7cddfSDavid du Colombier 	if(spanlines)
4137dd7cddfSDavid du Colombier 		ep = m->ebufp;
4147dd7cddfSDavid du Colombier 	else
4157dd7cddfSDavid du Colombier 		for(ep=m->bufp; ep<m->ebufp; ep++)
4167dd7cddfSDavid du Colombier 			if(*ep == '\n')
4177dd7cddfSDavid du Colombier 				break;
4187dd7cddfSDavid du Colombier 	p = m->bufp;
4197dd7cddfSDavid du Colombier 	for(i=0; i<n && p<ep; i++){
4209a747e4fSDavid du Colombier 		while(p<ep && !isdigit(*p) && *p!='-')
4217dd7cddfSDavid du Colombier 			p++;
4227dd7cddfSDavid du Colombier 		if(p == ep)
4237dd7cddfSDavid du Colombier 			break;
4247dd7cddfSDavid du Colombier 		a[i] = strtol(p, &p, 10);
4257dd7cddfSDavid du Colombier 	}
4267dd7cddfSDavid du Colombier 	if(ep < m->ebufp)
4277dd7cddfSDavid du Colombier 		ep++;
4287dd7cddfSDavid du Colombier 	m->bufp = ep;
4297dd7cddfSDavid du Colombier 	return i == n;
4307dd7cddfSDavid du Colombier }
4317dd7cddfSDavid du Colombier 
4327dd7cddfSDavid du Colombier /* Network on fd1, mount driver on fd0 */
4337dd7cddfSDavid du Colombier static int
4347dd7cddfSDavid du Colombier filter(int fd)
4357dd7cddfSDavid du Colombier {
4367dd7cddfSDavid du Colombier 	int p[2];
4377dd7cddfSDavid du Colombier 
4387dd7cddfSDavid du Colombier 	if(pipe(p) < 0){
4397dd7cddfSDavid du Colombier 		fprint(2, "stats: can't pipe: %r\n");
4407dd7cddfSDavid du Colombier 		killall("pipe");
4417dd7cddfSDavid du Colombier 	}
4427dd7cddfSDavid du Colombier 
4437dd7cddfSDavid du Colombier 	switch(rfork(RFNOWAIT|RFPROC|RFFDG)) {
4447dd7cddfSDavid du Colombier 	case -1:
4457dd7cddfSDavid du Colombier 		sysfatal("rfork record module");
4467dd7cddfSDavid du Colombier 	case 0:
4477dd7cddfSDavid du Colombier 		dup(fd, 1);
4487dd7cddfSDavid du Colombier 		close(fd);
4497dd7cddfSDavid du Colombier 		dup(p[0], 0);
4507dd7cddfSDavid du Colombier 		close(p[0]);
4517dd7cddfSDavid du Colombier 		close(p[1]);
4527dd7cddfSDavid du Colombier 		execl("/bin/aux/fcall", "fcall", 0);
4537dd7cddfSDavid du Colombier 		fprint(2, "stats: can't exec fcall: %r\n");
4547dd7cddfSDavid du Colombier 		killall("fcall");
4557dd7cddfSDavid du Colombier 	default:
4567dd7cddfSDavid du Colombier 		close(fd);
4577dd7cddfSDavid du Colombier 		close(p[0]);
4587dd7cddfSDavid du Colombier 	}
4597dd7cddfSDavid du Colombier 	return p[1];
4607dd7cddfSDavid du Colombier }
4617dd7cddfSDavid du Colombier 
4627dd7cddfSDavid du Colombier /*
4637dd7cddfSDavid du Colombier  * 9fs
4647dd7cddfSDavid du Colombier  */
4657dd7cddfSDavid du Colombier int
4667dd7cddfSDavid du Colombier connect9fs(char *addr)
4677dd7cddfSDavid du Colombier {
4689a747e4fSDavid du Colombier 	char dir[256], *na;
4697dd7cddfSDavid du Colombier 	int fd;
4707dd7cddfSDavid du Colombier 
4717dd7cddfSDavid du Colombier 	fprint(2, "connect9fs...");
4727dd7cddfSDavid du Colombier 	na = netmkaddr(addr, 0, "9fs");
4737dd7cddfSDavid du Colombier 
4747dd7cddfSDavid du Colombier 	fprint(2, "dial %s...", na);
4757dd7cddfSDavid du Colombier 	if((fd = dial(na, 0, dir, 0)) < 0)
4767dd7cddfSDavid du Colombier 		return -1;
4777dd7cddfSDavid du Colombier 
4787dd7cddfSDavid du Colombier 	fprint(2, "dir %s...", dir);
4799a747e4fSDavid du Colombier //	if(strstr(dir, "tcp"))
4809a747e4fSDavid du Colombier //		fd = filter(fd);
4817dd7cddfSDavid du Colombier 	return fd;
4827dd7cddfSDavid du Colombier }
4837dd7cddfSDavid du Colombier 
4849a747e4fSDavid du Colombier int
4859a747e4fSDavid du Colombier old9p(int fd)
4869a747e4fSDavid du Colombier {
4879a747e4fSDavid du Colombier 	int p[2];
4889a747e4fSDavid du Colombier 
4899a747e4fSDavid du Colombier 	if(pipe(p) < 0)
4909a747e4fSDavid du Colombier 		return -1;
4919a747e4fSDavid du Colombier 
4929a747e4fSDavid du Colombier 	switch(rfork(RFPROC|RFFDG|RFNAMEG)) {
4939a747e4fSDavid du Colombier 	case -1:
4949a747e4fSDavid du Colombier 		return -1;
4959a747e4fSDavid du Colombier 	case 0:
4969a747e4fSDavid du Colombier 		if(fd != 1){
4979a747e4fSDavid du Colombier 			dup(fd, 1);
4989a747e4fSDavid du Colombier 			close(fd);
4999a747e4fSDavid du Colombier 		}
5009a747e4fSDavid du Colombier 		if(p[0] != 0){
5019a747e4fSDavid du Colombier 			dup(p[0], 0);
5029a747e4fSDavid du Colombier 			close(p[0]);
5039a747e4fSDavid du Colombier 		}
5049a747e4fSDavid du Colombier 		close(p[1]);
5059a747e4fSDavid du Colombier 		if(0){
5069a747e4fSDavid du Colombier 			fd = open("/sys/log/cpu", OWRITE);
5079a747e4fSDavid du Colombier 			if(fd != 2){
5089a747e4fSDavid du Colombier 				dup(fd, 2);
5099a747e4fSDavid du Colombier 				close(fd);
5109a747e4fSDavid du Colombier 			}
5119a747e4fSDavid du Colombier 			execl("/bin/srvold9p", "srvold9p", "-ds", 0);
5129a747e4fSDavid du Colombier 		} else
5139a747e4fSDavid du Colombier 			execl("/bin/srvold9p", "srvold9p", "-s", 0);
5149a747e4fSDavid du Colombier 		return -1;
5159a747e4fSDavid du Colombier 	default:
5169a747e4fSDavid du Colombier 		close(fd);
5179a747e4fSDavid du Colombier 		close(p[0]);
5189a747e4fSDavid du Colombier 	}
5199a747e4fSDavid du Colombier 	return p[1];
5209a747e4fSDavid du Colombier }
5219a747e4fSDavid du Colombier 
5229a747e4fSDavid du Colombier 
5237dd7cddfSDavid du Colombier /*
5247dd7cddfSDavid du Colombier  * exportfs
5257dd7cddfSDavid du Colombier  */
5267dd7cddfSDavid du Colombier int
5277dd7cddfSDavid du Colombier connectexportfs(char *addr)
5287dd7cddfSDavid du Colombier {
5299a747e4fSDavid du Colombier 	char buf[ERRMAX], dir[256], *na;
5307dd7cddfSDavid du Colombier 	int fd, n;
5317dd7cddfSDavid du Colombier 	char *tree;
5329a747e4fSDavid du Colombier 	AuthInfo *ai;
5337dd7cddfSDavid du Colombier 
5347dd7cddfSDavid du Colombier 	tree = "/";
5357dd7cddfSDavid du Colombier 	na = netmkaddr(addr, 0, "exportfs");
5367dd7cddfSDavid du Colombier 	if((fd = dial(na, 0, dir, 0)) < 0)
5377dd7cddfSDavid du Colombier 		return -1;
5387dd7cddfSDavid du Colombier 
5399a747e4fSDavid du Colombier 	ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client");
5409a747e4fSDavid du Colombier 	if(ai == nil)
5417dd7cddfSDavid du Colombier 		return -1;
5427dd7cddfSDavid du Colombier 
5437dd7cddfSDavid du Colombier 	n = write(fd, tree, strlen(tree));
5447dd7cddfSDavid du Colombier 	if(n < 0){
5457dd7cddfSDavid du Colombier 		close(fd);
5467dd7cddfSDavid du Colombier 		return -1;
5477dd7cddfSDavid du Colombier 	}
5487dd7cddfSDavid du Colombier 
5497dd7cddfSDavid du Colombier 	strcpy(buf, "can't read tree");
5507dd7cddfSDavid du Colombier 	n = read(fd, buf, sizeof buf - 1);
5517dd7cddfSDavid du Colombier 	if(n!=2 || buf[0]!='O' || buf[1]!='K'){
5527dd7cddfSDavid du Colombier 		buf[sizeof buf - 1] = '\0';
5537dd7cddfSDavid du Colombier 		werrstr("bad remote tree: %s\n", buf);
5547dd7cddfSDavid du Colombier 		close(fd);
5557dd7cddfSDavid du Colombier 		return -1;
5567dd7cddfSDavid du Colombier 	}
5577dd7cddfSDavid du Colombier 
5589a747e4fSDavid du Colombier //	if(strstr(dir, "tcp"))
5599a747e4fSDavid du Colombier //		fd = filter(fd);
5609a747e4fSDavid du Colombier 
5619a747e4fSDavid du Colombier 	if(oldsystem)
5629a747e4fSDavid du Colombier 		return old9p(fd);
5637dd7cddfSDavid du Colombier 
5647dd7cddfSDavid du Colombier 	return fd;
5657dd7cddfSDavid du Colombier }
5667dd7cddfSDavid du Colombier 
5677dd7cddfSDavid du Colombier void
5687dd7cddfSDavid du Colombier initmach(Machine *m, char *name)
5697dd7cddfSDavid du Colombier {
5707dd7cddfSDavid du Colombier 	int n, fd;
5717dd7cddfSDavid du Colombier 	long a[MAXNUM];
5727dd7cddfSDavid du Colombier 	char *p, mpt[256], buf[256];
5737dd7cddfSDavid du Colombier 
5747dd7cddfSDavid du Colombier 	p = strchr(name, '!');
5757dd7cddfSDavid du Colombier 	if(p){
5767dd7cddfSDavid du Colombier 		p++;
5777dd7cddfSDavid du Colombier 		m->name = estrdup(p+1);
5787dd7cddfSDavid du Colombier 	}else
5797dd7cddfSDavid du Colombier 		p = name;
5807dd7cddfSDavid du Colombier 	m->name = estrdup(p);
5817dd7cddfSDavid du Colombier 	m->remote = (strcmp(p, mysysname) != 0);
5827dd7cddfSDavid du Colombier 	if(m->remote == 0)
5837dd7cddfSDavid du Colombier 		strcpy(mpt, "");
5847dd7cddfSDavid du Colombier 	else{
5857dd7cddfSDavid du Colombier 		snprint(mpt, sizeof mpt, "/n/%s", p);
5867dd7cddfSDavid du Colombier 		fd = connectexportfs(name);
5877dd7cddfSDavid du Colombier 		if(fd < 0){
5887dd7cddfSDavid du Colombier 			fprint(2, "can't connect to %s: %r\n", name);
5897dd7cddfSDavid du Colombier 			killall("connect");
5907dd7cddfSDavid du Colombier 		}
5919a747e4fSDavid du Colombier 		/* BUG? need to use amount() now? */
5929a747e4fSDavid du Colombier 		if(mount(fd, -1, mpt, MREPL, "") < 0){
5937dd7cddfSDavid du Colombier 			fprint(2, "stats: mount %s on %s failed (%r); trying /n/sid\n", name, mpt);
5947dd7cddfSDavid du Colombier 			strcpy(mpt, "/n/sid");
5959a747e4fSDavid du Colombier 			if(mount(fd, -1, mpt, MREPL, "") < 0){
5967dd7cddfSDavid du Colombier 				fprint(2, "stats: mount %s on %s failed: %r\n", name, mpt);
5977dd7cddfSDavid du Colombier 				killall("mount");
5987dd7cddfSDavid du Colombier 			}
5997dd7cddfSDavid du Colombier 		}
6007dd7cddfSDavid du Colombier 	}
6017dd7cddfSDavid du Colombier 
6027dd7cddfSDavid du Colombier 	snprint(buf, sizeof buf, "%s/dev/swap", mpt);
6037dd7cddfSDavid du Colombier 	m->swapfd = open(buf, OREAD);
6047dd7cddfSDavid du Colombier 	if(loadbuf(m, &m->swapfd) && readnums(m, nelem(m->devswap), a, 0))
6057dd7cddfSDavid du Colombier 		memmove(m->devswap, a, sizeof m->devswap);
6067dd7cddfSDavid du Colombier 	else
6077dd7cddfSDavid du Colombier 		m->devswap[Maxmem] = m->devswap[Maxswap] = 100;
6087dd7cddfSDavid du Colombier 
6097dd7cddfSDavid du Colombier 	snprint(buf, sizeof buf, "%s/dev/sysstat", mpt);
6107dd7cddfSDavid du Colombier 	m->statsfd = open(buf, OREAD);
6117dd7cddfSDavid du Colombier 	if(loadbuf(m, &m->statsfd)){
6127dd7cddfSDavid du Colombier 		for(n=0; readnums(m, nelem(m->devsysstat), a, 0); n++)
6137dd7cddfSDavid du Colombier 			;
6147dd7cddfSDavid du Colombier 		m->nproc = n;
6157dd7cddfSDavid du Colombier 	}else
6167dd7cddfSDavid du Colombier 		m->nproc = 1;
6177dd7cddfSDavid du Colombier 
6187dd7cddfSDavid du Colombier 	snprint(buf, sizeof buf, "%s/net/ether0/0/stats", mpt);
6197dd7cddfSDavid du Colombier 	m->etherfd = open(buf, OREAD);
6207dd7cddfSDavid du Colombier 	if(loadbuf(m, &m->etherfd) && readnums(m, nelem(m->netetherstats), a, 1))
6217dd7cddfSDavid du Colombier 		memmove(m->netetherstats, a, sizeof m->netetherstats);
62280ee5cbfSDavid du Colombier 
6239a747e4fSDavid du Colombier 	snprint(buf, sizeof buf, "%s/net/ether0/0/ifstats", mpt);
6249a747e4fSDavid du Colombier 	m->ifstatsfd = open(buf, OREAD);
6259a747e4fSDavid du Colombier 	if(loadbuf(m, &m->ifstatsfd)){
6269a747e4fSDavid du Colombier 		/* need to check that this is a wavelan interface */
6279a747e4fSDavid du Colombier 		if(strncmp(m->buf, "Signal: ", 8) == 0 && readnums(m, nelem(m->netetherifstats), a, 1))
6289a747e4fSDavid du Colombier 			memmove(m->netetherifstats, a, sizeof m->netetherifstats);
6299a747e4fSDavid du Colombier 	}
6309a747e4fSDavid du Colombier 
63180ee5cbfSDavid du Colombier 	snprint(buf, sizeof buf, "%s/mnt/apm/battery", mpt);
63280ee5cbfSDavid du Colombier 	m->batteryfd = open(buf, OREAD);
6339a747e4fSDavid du Colombier 	m->bitsybatfd = -1;
6349a747e4fSDavid du Colombier 	if(m->batteryfd >= 0){
63580ee5cbfSDavid du Colombier 		if(loadbuf(m, &m->batteryfd) && readnums(m, nelem(m->batterystats), a, 0))
63680ee5cbfSDavid du Colombier 			memmove(m->batterystats, a, sizeof(m->batterystats));
6379a747e4fSDavid du Colombier 	}else{
6389a747e4fSDavid du Colombier 		snprint(buf, sizeof buf, "%s/dev/battery", mpt);
6399a747e4fSDavid du Colombier 		m->bitsybatfd = open(buf, OREAD);
6409a747e4fSDavid du Colombier 		if(loadbuf(m, &m->bitsybatfd) && readnums(m, 1, a, 0))
6419a747e4fSDavid du Colombier 			memmove(m->batterystats, a, sizeof(m->batterystats));
6429a747e4fSDavid du Colombier 	}
6437dd7cddfSDavid du Colombier }
6447dd7cddfSDavid du Colombier 
6457dd7cddfSDavid du Colombier jmp_buf catchalarm;
6467dd7cddfSDavid du Colombier 
6477dd7cddfSDavid du Colombier void
6487dd7cddfSDavid du Colombier alarmed(void *a, char *s)
6497dd7cddfSDavid du Colombier {
6507dd7cddfSDavid du Colombier 	if(strcmp(s, "alarm") == 0)
6517dd7cddfSDavid du Colombier 		notejmp(a, catchalarm, 1);
6523e12c5d1SDavid du Colombier 	noted(NDFLT);
6533e12c5d1SDavid du Colombier }
6547dd7cddfSDavid du Colombier 
6557dd7cddfSDavid du Colombier int
6567dd7cddfSDavid du Colombier needswap(int init)
6577dd7cddfSDavid du Colombier {
6587dd7cddfSDavid du Colombier 	return init | present[Mmem] | present[Mswap];
6597dd7cddfSDavid du Colombier }
6607dd7cddfSDavid du Colombier 
6617dd7cddfSDavid du Colombier 
6627dd7cddfSDavid du Colombier int
6637dd7cddfSDavid du Colombier needstat(int init)
6647dd7cddfSDavid du Colombier {
6657dd7cddfSDavid du Colombier 	return init | present[Mcontext]  | present[Mfault] | present[Mintr] | present[Mload] |
6667dd7cddfSDavid du Colombier 		present[Msyscall] | present[Mtlbmiss] | present[Mtlbpurge];
6677dd7cddfSDavid du Colombier }
6687dd7cddfSDavid du Colombier 
6697dd7cddfSDavid du Colombier 
6707dd7cddfSDavid du Colombier int
6717dd7cddfSDavid du Colombier needether(int init)
6727dd7cddfSDavid du Colombier {
6737dd7cddfSDavid du Colombier 	return init | present[Mether] | present[Metherin] | present[Metherout] | present[Methererr];
6747dd7cddfSDavid du Colombier }
6757dd7cddfSDavid du Colombier 
67680ee5cbfSDavid du Colombier int
67780ee5cbfSDavid du Colombier needbattery(int init)
67880ee5cbfSDavid du Colombier {
67980ee5cbfSDavid du Colombier 	return init | present[Mbattery];
68080ee5cbfSDavid du Colombier }
68180ee5cbfSDavid du Colombier 
6829a747e4fSDavid du Colombier int
6839a747e4fSDavid du Colombier needsignal(int init)
6849a747e4fSDavid du Colombier {
6859a747e4fSDavid du Colombier 	return init | present[Msignal];
6869a747e4fSDavid du Colombier }
6879a747e4fSDavid du Colombier 
6887dd7cddfSDavid du Colombier void
6897dd7cddfSDavid du Colombier readmach(Machine *m, int init)
6907dd7cddfSDavid du Colombier {
6917dd7cddfSDavid du Colombier 	int n, i;
6927dd7cddfSDavid du Colombier 	long a[8];
6937dd7cddfSDavid du Colombier 	char buf[32];
6947dd7cddfSDavid du Colombier 
6957dd7cddfSDavid du Colombier 	if(m->remote && (m->disable || setjmp(catchalarm))){
6967dd7cddfSDavid du Colombier 		if(m->disable == 0){
6977dd7cddfSDavid du Colombier 			snprint(buf, sizeof buf, "%s(dead)", m->name);
6987dd7cddfSDavid du Colombier 			m->name = estrdup(buf);
6997dd7cddfSDavid du Colombier 			if(display != nil)	/* else we're still initializing */
7007dd7cddfSDavid du Colombier 				eresized(0);
7017dd7cddfSDavid du Colombier 		}
7027dd7cddfSDavid du Colombier 		m->disable = 1;
7037dd7cddfSDavid du Colombier 		memmove(m->devsysstat, m->prevsysstat, sizeof m->devsysstat);
7047dd7cddfSDavid du Colombier 		memmove(m->netetherstats, m->prevetherstats, sizeof m->netetherstats);
7057dd7cddfSDavid du Colombier 		return;
7067dd7cddfSDavid du Colombier 	}
7077dd7cddfSDavid du Colombier 	if(m->remote){
7087dd7cddfSDavid du Colombier 		notify(alarmed);
7097dd7cddfSDavid du Colombier 		alarm(5000);
7107dd7cddfSDavid du Colombier 	}
7117dd7cddfSDavid du Colombier 	if(needswap(init) && loadbuf(m, &m->swapfd) && readnums(m, nelem(m->devswap), a, 0))
7127dd7cddfSDavid du Colombier 		memmove(m->devswap, a, sizeof m->devswap);
7137dd7cddfSDavid du Colombier 	if(needstat(init) && loadbuf(m, &m->statsfd)){
7147dd7cddfSDavid du Colombier 		memmove(m->prevsysstat, m->devsysstat, sizeof m->devsysstat);
7157dd7cddfSDavid du Colombier 		memset(m->devsysstat, 0, sizeof m->devsysstat);
7167dd7cddfSDavid du Colombier 		for(n=0; n<m->nproc && readnums(m, nelem(m->devsysstat), a, 0); n++)
7177dd7cddfSDavid du Colombier 			for(i=0; i<nelem(m->devsysstat); i++)
7187dd7cddfSDavid du Colombier 				m->devsysstat[i] += a[i];
7197dd7cddfSDavid du Colombier 	}
7207dd7cddfSDavid du Colombier 	if(needether(init) && loadbuf(m, &m->etherfd) && readnums(m, nelem(m->netetherstats), a, 1)){
7217dd7cddfSDavid du Colombier 		memmove(m->prevetherstats, m->netetherstats, sizeof m->netetherstats);
7227dd7cddfSDavid du Colombier 		memmove(m->netetherstats, a, sizeof m->netetherstats);
7237dd7cddfSDavid du Colombier 	}
7249a747e4fSDavid du Colombier 	if(needsignal(init) && loadbuf(m, &m->ifstatsfd) && strncmp(m->buf, "Signal: ", 8)==0 && readnums(m, nelem(m->netetherifstats), a, 1)){
7259a747e4fSDavid du Colombier 		memmove(m->netetherifstats, a, sizeof m->netetherifstats);
7269a747e4fSDavid du Colombier 	}
72780ee5cbfSDavid du Colombier 	if(needbattery(init) && loadbuf(m, &m->batteryfd) && readnums(m, nelem(m->batterystats), a, 0))
72880ee5cbfSDavid du Colombier 		memmove(m->batterystats, a, sizeof(m->batterystats));
7299a747e4fSDavid du Colombier 	if(needbattery(init) && loadbuf(m, &m->bitsybatfd) && readnums(m, 1, a, 0))
7309a747e4fSDavid du Colombier 		memmove(m->batterystats, a, sizeof(m->batterystats));
73180ee5cbfSDavid du Colombier 
7327dd7cddfSDavid du Colombier 	if(m->remote){
7337dd7cddfSDavid du Colombier 		alarm(0);
7347dd7cddfSDavid du Colombier 		notify(nil);
7357dd7cddfSDavid du Colombier 	}
7367dd7cddfSDavid du Colombier }
7377dd7cddfSDavid du Colombier 
7387dd7cddfSDavid du Colombier void
73980ee5cbfSDavid du Colombier memval(Machine *m, long *v, long *vmax, int)
7407dd7cddfSDavid du Colombier {
7417dd7cddfSDavid du Colombier 	*v = m->devswap[Mem];
7427dd7cddfSDavid du Colombier 	*vmax = m->devswap[Maxmem];
7437dd7cddfSDavid du Colombier }
7447dd7cddfSDavid du Colombier 
7457dd7cddfSDavid du Colombier void
74680ee5cbfSDavid du Colombier swapval(Machine *m, long *v, long *vmax, int)
7477dd7cddfSDavid du Colombier {
7487dd7cddfSDavid du Colombier 	*v = m->devswap[Swap];
7497dd7cddfSDavid du Colombier 	*vmax = m->devswap[Maxswap];
7507dd7cddfSDavid du Colombier }
7517dd7cddfSDavid du Colombier 
7527dd7cddfSDavid du Colombier void
75380ee5cbfSDavid du Colombier contextval(Machine *m, long *v, long *vmax, int init)
7547dd7cddfSDavid du Colombier {
7557dd7cddfSDavid du Colombier 	*v = m->devsysstat[Context]-m->prevsysstat[Context];
7567dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
75780ee5cbfSDavid du Colombier 	if(init)
75880ee5cbfSDavid du Colombier 		*vmax = 1000;
7597dd7cddfSDavid du Colombier }
7607dd7cddfSDavid du Colombier 
7617dd7cddfSDavid du Colombier void
76280ee5cbfSDavid du Colombier intrval(Machine *m, long *v, long *vmax, int init)
7637dd7cddfSDavid du Colombier {
7647dd7cddfSDavid du Colombier 	*v = m->devsysstat[Interrupt]-m->prevsysstat[Interrupt];
7657dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
76680ee5cbfSDavid du Colombier 	if(init)
76780ee5cbfSDavid du Colombier 		*vmax = 1000;
7687dd7cddfSDavid du Colombier }
7697dd7cddfSDavid du Colombier 
7707dd7cddfSDavid du Colombier void
77180ee5cbfSDavid du Colombier syscallval(Machine *m, long *v, long *vmax, int init)
7727dd7cddfSDavid du Colombier {
7737dd7cddfSDavid du Colombier 	*v = m->devsysstat[Syscall]-m->prevsysstat[Syscall];
7747dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
77580ee5cbfSDavid du Colombier 	if(init)
77680ee5cbfSDavid du Colombier 		*vmax = 1000;
7777dd7cddfSDavid du Colombier }
7787dd7cddfSDavid du Colombier 
7797dd7cddfSDavid du Colombier void
78080ee5cbfSDavid du Colombier faultval(Machine *m, long *v, long *vmax, int init)
7817dd7cddfSDavid du Colombier {
7827dd7cddfSDavid du Colombier 	*v = m->devsysstat[Fault]-m->prevsysstat[Fault];
7837dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
78480ee5cbfSDavid du Colombier 	if(init)
78580ee5cbfSDavid du Colombier 		*vmax = 1000;
7867dd7cddfSDavid du Colombier }
7877dd7cddfSDavid du Colombier 
7887dd7cddfSDavid du Colombier void
78980ee5cbfSDavid du Colombier tlbmissval(Machine *m, long *v, long *vmax, int init)
7907dd7cddfSDavid du Colombier {
7917dd7cddfSDavid du Colombier 	*v = m->devsysstat[TLBfault]-m->prevsysstat[TLBfault];
7927dd7cddfSDavid du Colombier 	*vmax = 10*m->nproc;
79380ee5cbfSDavid du Colombier 	if(init)
79480ee5cbfSDavid du Colombier 		*vmax = 10;
7957dd7cddfSDavid du Colombier }
7967dd7cddfSDavid du Colombier 
7977dd7cddfSDavid du Colombier void
79880ee5cbfSDavid du Colombier tlbpurgeval(Machine *m, long *v, long *vmax, int init)
7997dd7cddfSDavid du Colombier {
8007dd7cddfSDavid du Colombier 	*v = m->devsysstat[TLBpurge]-m->prevsysstat[TLBpurge];
8017dd7cddfSDavid du Colombier 	*vmax = 10*m->nproc;
80280ee5cbfSDavid du Colombier 	if(init)
80380ee5cbfSDavid du Colombier 		*vmax = 10;
8047dd7cddfSDavid du Colombier }
8057dd7cddfSDavid du Colombier 
8067dd7cddfSDavid du Colombier void
80780ee5cbfSDavid du Colombier loadval(Machine *m, long *v, long *vmax, int init)
8087dd7cddfSDavid du Colombier {
8097dd7cddfSDavid du Colombier 	*v = m->devsysstat[Load];
8107dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
81180ee5cbfSDavid du Colombier 	if(init)
81280ee5cbfSDavid du Colombier 		*vmax = 1000;
8137dd7cddfSDavid du Colombier }
8147dd7cddfSDavid du Colombier 
8157dd7cddfSDavid du Colombier void
81680ee5cbfSDavid du Colombier etherval(Machine *m, long *v, long *vmax, int init)
8177dd7cddfSDavid du Colombier {
8187dd7cddfSDavid du Colombier 	*v = m->netetherstats[In]-m->prevetherstats[In] + m->netetherstats[Out]-m->prevetherstats[Out];
8197dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
82080ee5cbfSDavid du Colombier 	if(init)
82180ee5cbfSDavid du Colombier 		*vmax = 1000;
8227dd7cddfSDavid du Colombier }
8237dd7cddfSDavid du Colombier 
8247dd7cddfSDavid du Colombier void
82580ee5cbfSDavid du Colombier etherinval(Machine *m, long *v, long *vmax, int init)
8267dd7cddfSDavid du Colombier {
8277dd7cddfSDavid du Colombier 	*v = m->netetherstats[In]-m->prevetherstats[In];
8287dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
82980ee5cbfSDavid du Colombier 	if(init)
83080ee5cbfSDavid du Colombier 		*vmax = 1000;
8317dd7cddfSDavid du Colombier }
8327dd7cddfSDavid du Colombier 
8337dd7cddfSDavid du Colombier void
83480ee5cbfSDavid du Colombier etheroutval(Machine *m, long *v, long *vmax, int init)
8357dd7cddfSDavid du Colombier {
8367dd7cddfSDavid du Colombier 	*v = m->netetherstats[Out]-m->prevetherstats[Out];
8377dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
83880ee5cbfSDavid du Colombier 	if(init)
83980ee5cbfSDavid du Colombier 		*vmax = 1000;
8407dd7cddfSDavid du Colombier }
8417dd7cddfSDavid du Colombier 
8427dd7cddfSDavid du Colombier void
84380ee5cbfSDavid du Colombier ethererrval(Machine *m, long *v, long *vmax, int init)
8447dd7cddfSDavid du Colombier {
8457dd7cddfSDavid du Colombier 	int i;
8467dd7cddfSDavid du Colombier 
8477dd7cddfSDavid du Colombier 	*v = 0;
8487dd7cddfSDavid du Colombier 	for(i=Err0; i<nelem(m->netetherstats); i++)
8497dd7cddfSDavid du Colombier 		*v += m->netetherstats[i];
8507dd7cddfSDavid du Colombier 	*vmax = 10*m->nproc;
85180ee5cbfSDavid du Colombier 	if(init)
85280ee5cbfSDavid du Colombier 		*vmax = 10;
85380ee5cbfSDavid du Colombier }
85480ee5cbfSDavid du Colombier 
85580ee5cbfSDavid du Colombier void
85680ee5cbfSDavid du Colombier batteryval(Machine *m, long *v, long *vmax, int)
85780ee5cbfSDavid du Colombier {
85880ee5cbfSDavid du Colombier 	*v = m->batterystats[0];
8599a747e4fSDavid du Colombier 	if(m->bitsybatfd >= 0)
8609a747e4fSDavid du Colombier 		*vmax = 184;		// at least on my bitsy...
8619a747e4fSDavid du Colombier 	else
86280ee5cbfSDavid du Colombier 		*vmax = 100;
8637dd7cddfSDavid du Colombier }
8647dd7cddfSDavid du Colombier 
8657dd7cddfSDavid du Colombier void
8669a747e4fSDavid du Colombier signalval(Machine *m, long *v, long *vmax, int)
8679a747e4fSDavid du Colombier {
8689a747e4fSDavid du Colombier 	long l;
8699a747e4fSDavid du Colombier 
8709a747e4fSDavid du Colombier 	*vmax = 1000;
8719a747e4fSDavid du Colombier 	l = m->netetherifstats[0];
8729a747e4fSDavid du Colombier 	/*
8739a747e4fSDavid du Colombier 	 * Range is seen to be from about -45 (strong) to -95 (weak); rescale
8749a747e4fSDavid du Colombier 	 */
8759a747e4fSDavid du Colombier 	if(l == 0){	/* probably not present */
8769a747e4fSDavid du Colombier 		*v = 0;
8779a747e4fSDavid du Colombier 		return;
8789a747e4fSDavid du Colombier 	}
8799a747e4fSDavid du Colombier 	*v = 20*(l+95);
8809a747e4fSDavid du Colombier }
8819a747e4fSDavid du Colombier 
8829a747e4fSDavid du Colombier void
8837dd7cddfSDavid du Colombier usage(void)
8847dd7cddfSDavid du Colombier {
8859a747e4fSDavid du Colombier 	fprint(2, "usage: stats [-O] [-S scale] [-LY] [-%s] [machine...]\n", argchars);
8867dd7cddfSDavid du Colombier 	exits("usage");
8877dd7cddfSDavid du Colombier }
8887dd7cddfSDavid du Colombier 
8897dd7cddfSDavid du Colombier void
8907dd7cddfSDavid du Colombier addgraph(int n)
8917dd7cddfSDavid du Colombier {
8927dd7cddfSDavid du Colombier 	Graph *g, *ograph;
8937dd7cddfSDavid du Colombier 	int i, j;
8947dd7cddfSDavid du Colombier 	static int nadd;
8957dd7cddfSDavid du Colombier 
8967dd7cddfSDavid du Colombier 	if(n > nelem(menu2str))
8977dd7cddfSDavid du Colombier 		abort();
8987dd7cddfSDavid du Colombier 	/* avoid two adjacent graphs of same color */
8997dd7cddfSDavid du Colombier 	if(ngraph>0 && graph[ngraph-1].colindex==nadd%Ncolor)
9007dd7cddfSDavid du Colombier 		nadd++;
9017dd7cddfSDavid du Colombier 	ograph = graph;
9027dd7cddfSDavid du Colombier 	graph = emalloc(nmach*(ngraph+1)*sizeof(Graph));
9037dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++)
9047dd7cddfSDavid du Colombier 		for(j=0; j<ngraph; j++)
9057dd7cddfSDavid du Colombier 			graph[i*(ngraph+1)+j] = ograph[i*ngraph+j];
9067dd7cddfSDavid du Colombier 	free(ograph);
9077dd7cddfSDavid du Colombier 	ngraph++;
9087dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++){
9097dd7cddfSDavid du Colombier 		g = &graph[i*ngraph+(ngraph-1)];
9107dd7cddfSDavid du Colombier 		memset(g, 0, sizeof(Graph));
9117dd7cddfSDavid du Colombier 		g->label = menu2str[n]+Opwid;
9127dd7cddfSDavid du Colombier 		g->newvalue = newvaluefn[n];
9137dd7cddfSDavid du Colombier 		g->update = update1;	/* no other update functions yet */
9147dd7cddfSDavid du Colombier 		g->mach = &mach[i];
9157dd7cddfSDavid du Colombier 		g->colindex = nadd%Ncolor;
9167dd7cddfSDavid du Colombier 	}
9177dd7cddfSDavid du Colombier 	present[n] = 1;
9187dd7cddfSDavid du Colombier 	nadd++;
9197dd7cddfSDavid du Colombier }
9207dd7cddfSDavid du Colombier 
9217dd7cddfSDavid du Colombier void
9227dd7cddfSDavid du Colombier dropgraph(int which)
9237dd7cddfSDavid du Colombier {
9247dd7cddfSDavid du Colombier 	Graph *ograph;
9257dd7cddfSDavid du Colombier 	int i, j, n;
9267dd7cddfSDavid du Colombier 
9277dd7cddfSDavid du Colombier 	if(which > nelem(menu2str))
9287dd7cddfSDavid du Colombier 		abort();
9297dd7cddfSDavid du Colombier 	/* convert n to index in graph table */
9307dd7cddfSDavid du Colombier 	n = -1;
9317dd7cddfSDavid du Colombier 	for(i=0; i<ngraph; i++)
9327dd7cddfSDavid du Colombier 		if(strcmp(menu2str[which]+Opwid, graph[i].label) == 0){
9337dd7cddfSDavid du Colombier 			n = i;
9347dd7cddfSDavid du Colombier 			break;
9357dd7cddfSDavid du Colombier 		}
9367dd7cddfSDavid du Colombier 	if(n < 0){
9377dd7cddfSDavid du Colombier 		fprint(2, "stats: internal error can't drop graph\n");
9387dd7cddfSDavid du Colombier 		killall("error");
9397dd7cddfSDavid du Colombier 	}
9407dd7cddfSDavid du Colombier 	ograph = graph;
9417dd7cddfSDavid du Colombier 	graph = emalloc(nmach*(ngraph-1)*sizeof(Graph));
9427dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++){
9437dd7cddfSDavid du Colombier 		for(j=0; j<n; j++)
9447dd7cddfSDavid du Colombier 			graph[i*(ngraph-1)+j] = ograph[i*ngraph+j];
9457dd7cddfSDavid du Colombier 		free(ograph[i*ngraph+j].data);
9467dd7cddfSDavid du Colombier 		freeimage(ograph[i*ngraph+j].overtmp);
9477dd7cddfSDavid du Colombier 		for(j++; j<ngraph; j++)
9487dd7cddfSDavid du Colombier 			graph[i*(ngraph-1)+j-1] = ograph[i*ngraph+j];
9497dd7cddfSDavid du Colombier 	}
9507dd7cddfSDavid du Colombier 	free(ograph);
9517dd7cddfSDavid du Colombier 	ngraph--;
9527dd7cddfSDavid du Colombier 	present[which] = 0;
9537dd7cddfSDavid du Colombier }
9547dd7cddfSDavid du Colombier 
9557dd7cddfSDavid du Colombier void
9567dd7cddfSDavid du Colombier addmachine(char *name)
9577dd7cddfSDavid du Colombier {
9587dd7cddfSDavid du Colombier 	if(ngraph > 0){
9597dd7cddfSDavid du Colombier 		fprint(2, "stats: internal error: ngraph>0 in addmachine()\n");
9607dd7cddfSDavid du Colombier 		usage();
9617dd7cddfSDavid du Colombier 	}
9627dd7cddfSDavid du Colombier 	if(mach == nil)
9637dd7cddfSDavid du Colombier 		nmach = 0;	/* a little dance to get us started with local machine by default */
9647dd7cddfSDavid du Colombier 	mach = erealloc(mach, (nmach+1)*sizeof(Machine));
9657dd7cddfSDavid du Colombier 	memset(mach+nmach, 0, sizeof(Machine));
9667dd7cddfSDavid du Colombier 	initmach(mach+nmach, name);
9677dd7cddfSDavid du Colombier 	nmach++;
9687dd7cddfSDavid du Colombier }
9697dd7cddfSDavid du Colombier 
9707dd7cddfSDavid du Colombier void
97180ee5cbfSDavid du Colombier labelstrs(Graph *g, char strs[Nlab][Lablen], int *np)
97280ee5cbfSDavid du Colombier {
97380ee5cbfSDavid du Colombier 	int j;
97480ee5cbfSDavid du Colombier 	long v, vmax;
97580ee5cbfSDavid du Colombier 
97680ee5cbfSDavid du Colombier 	g->newvalue(g->mach, &v, &vmax, 1);
97780ee5cbfSDavid du Colombier 	if(logscale){
97880ee5cbfSDavid du Colombier 		for(j=1; j<=2; j++)
97980ee5cbfSDavid du Colombier 			sprint(strs[j-1], "%g", scale*pow(10., j)*(double)vmax/100.);
98080ee5cbfSDavid du Colombier 		*np = 2;
98180ee5cbfSDavid du Colombier 	}else{
98280ee5cbfSDavid du Colombier 		for(j=1; j<=3; j++)
98380ee5cbfSDavid du Colombier 			sprint(strs[j-1], "%g", scale*(double)j*(double)vmax/4.0);
98480ee5cbfSDavid du Colombier 		*np = 3;
98580ee5cbfSDavid du Colombier 	}
98680ee5cbfSDavid du Colombier }
98780ee5cbfSDavid du Colombier 
98880ee5cbfSDavid du Colombier int
98980ee5cbfSDavid du Colombier labelwidth(void)
99080ee5cbfSDavid du Colombier {
99180ee5cbfSDavid du Colombier 	int i, j, n, w, maxw;
99280ee5cbfSDavid du Colombier 	char strs[Nlab][Lablen];
99380ee5cbfSDavid du Colombier 
99480ee5cbfSDavid du Colombier 	maxw = 0;
99580ee5cbfSDavid du Colombier 	for(i=0; i<ngraph; i++){
99680ee5cbfSDavid du Colombier 		/* choose value for rightmost graph */
99780ee5cbfSDavid du Colombier 		labelstrs(&graph[ngraph*(nmach-1)+i], strs, &n);
99880ee5cbfSDavid du Colombier 		for(j=0; j<n; j++){
99980ee5cbfSDavid du Colombier 			w = stringwidth(mediumfont, strs[j]);
100080ee5cbfSDavid du Colombier 			if(w > maxw)
100180ee5cbfSDavid du Colombier 				maxw = w;
100280ee5cbfSDavid du Colombier 		}
100380ee5cbfSDavid du Colombier 	}
100480ee5cbfSDavid du Colombier 	return maxw;
100580ee5cbfSDavid du Colombier }
100680ee5cbfSDavid du Colombier 
100780ee5cbfSDavid du Colombier void
10087dd7cddfSDavid du Colombier resize(void)
10097dd7cddfSDavid du Colombier {
101080ee5cbfSDavid du Colombier 	int i, j, k, n, startx, starty, x, y, dx, dy, ly, ondata, maxx, wid, nlab;
10117dd7cddfSDavid du Colombier 	Graph *g;
10127dd7cddfSDavid du Colombier 	Rectangle machr, r;
10137dd7cddfSDavid du Colombier 	long v, vmax;
101480ee5cbfSDavid du Colombier 	char buf[128], labs[Nlab][Lablen];
10157dd7cddfSDavid du Colombier 
10167dd7cddfSDavid du Colombier 	draw(screen, screen->r, display->white, nil, ZP);
10177dd7cddfSDavid du Colombier 
10187dd7cddfSDavid du Colombier 	/* label left edge */
10197dd7cddfSDavid du Colombier 	x = screen->r.min.x;
10207dd7cddfSDavid du Colombier 	y = screen->r.min.y + Labspace+mediumfont->height+Labspace;
10217dd7cddfSDavid du Colombier 	dy = (screen->r.max.y - y)/ngraph;
10227dd7cddfSDavid du Colombier 	dx = Labspace+stringwidth(mediumfont, "0")+Labspace;
10237dd7cddfSDavid du Colombier 	startx = x+dx+1;
10247dd7cddfSDavid du Colombier 	starty = y;
10257dd7cddfSDavid du Colombier 	for(i=0; i<ngraph; i++,y+=dy){
10267dd7cddfSDavid du Colombier 		draw(screen, Rect(x, y-1, screen->r.max.x, y), display->black, nil, ZP);
10277dd7cddfSDavid du Colombier 		draw(screen, Rect(x, y, x+dx, screen->r.max.y), cols[graph[i].colindex][0], nil, paritypt(x));
10287dd7cddfSDavid du Colombier 		label(Pt(x, y), dy, graph[i].label);
10297dd7cddfSDavid du Colombier 		draw(screen, Rect(x+dx, y, x+dx+1, screen->r.max.y), cols[graph[i].colindex][2], nil, ZP);
10307dd7cddfSDavid du Colombier 	}
10317dd7cddfSDavid du Colombier 
10327dd7cddfSDavid du Colombier 	/* label top edge */
10337dd7cddfSDavid du Colombier 	dx = (screen->r.max.x - startx)/nmach;
10347dd7cddfSDavid du Colombier 	for(x=startx, i=0; i<nmach; i++,x+=dx){
10357dd7cddfSDavid du Colombier 		draw(screen, Rect(x-1, starty-1, x, screen->r.max.y), display->black, nil, ZP);
10367dd7cddfSDavid du Colombier 		j = dx/stringwidth(mediumfont, "0");
10377dd7cddfSDavid du Colombier 		n = mach[i].nproc;
10387dd7cddfSDavid du Colombier 		if(n>1 && j>=1+3+(n>10)+(n>100)){	/* first char of name + (n) */
10397dd7cddfSDavid du Colombier 			j -= 3+(n>10)+(n>100);
10407dd7cddfSDavid du Colombier 			if(j <= 0)
10417dd7cddfSDavid du Colombier 				j = 1;
10427dd7cddfSDavid du Colombier 			snprint(buf, sizeof buf, "%.*s(%d)", j, mach[i].name, n);
10437dd7cddfSDavid du Colombier 		}else
10447dd7cddfSDavid du Colombier 			snprint(buf, sizeof buf, "%.*s", j, mach[i].name);
10457dd7cddfSDavid du Colombier 		string(screen, Pt(x+Labspace, screen->r.min.y + Labspace), display->black, ZP, mediumfont, buf);
10467dd7cddfSDavid du Colombier 	}
10477dd7cddfSDavid du Colombier 
104880ee5cbfSDavid du Colombier 	maxx = screen->r.max.x;
104980ee5cbfSDavid du Colombier 
105080ee5cbfSDavid du Colombier 	/* label right, if requested */
105180ee5cbfSDavid du Colombier 	if(ylabels && dy>Nlab*(mediumfont->height+1)){
105280ee5cbfSDavid du Colombier 		wid = labelwidth();
105380ee5cbfSDavid du Colombier 		if(wid < (maxx-startx)-30){
105480ee5cbfSDavid du Colombier 			/* else there's not enough room */
105580ee5cbfSDavid du Colombier 			maxx -= 1+Lx+wid;
105680ee5cbfSDavid du Colombier 			draw(screen, Rect(maxx, starty, maxx+1, screen->r.max.y), display->black, nil, ZP);
105780ee5cbfSDavid du Colombier 			y = starty;
105880ee5cbfSDavid du Colombier 			for(j=0; j<ngraph; j++, y+=dy){
105980ee5cbfSDavid du Colombier 				/* choose value for rightmost graph */
106080ee5cbfSDavid du Colombier 				g = &graph[ngraph*(nmach-1)+j];
106180ee5cbfSDavid du Colombier 				labelstrs(g, labs, &nlab);
106280ee5cbfSDavid du Colombier 				r = Rect(maxx+1, y, screen->r.max.x, y+dy-1);
106380ee5cbfSDavid du Colombier 				if(j == ngraph-1)
106480ee5cbfSDavid du Colombier 					r.max.y = screen->r.max.y;
106580ee5cbfSDavid du Colombier 				draw(screen, r, cols[g->colindex][0], nil, paritypt(r.min.x));
106680ee5cbfSDavid du Colombier 				for(k=0; k<nlab; k++){
106780ee5cbfSDavid du Colombier 					ly = y + (dy*(nlab-k)/(nlab+1));
106880ee5cbfSDavid du Colombier 					draw(screen, Rect(maxx+1, ly, maxx+1+Lx, ly+1), display->black, nil, ZP);
106980ee5cbfSDavid du Colombier 					ly -= mediumfont->height/2;
107080ee5cbfSDavid du Colombier 					string(screen, Pt(maxx+1+Lx, ly), display->black, ZP, mediumfont, labs[k]);
107180ee5cbfSDavid du Colombier 				}
107280ee5cbfSDavid du Colombier 			}
107380ee5cbfSDavid du Colombier 		}
107480ee5cbfSDavid du Colombier 	}
107580ee5cbfSDavid du Colombier 
10767dd7cddfSDavid du Colombier 	/* create graphs */
10777dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++){
107880ee5cbfSDavid du Colombier 		machr = Rect(startx+i*dx, starty, maxx, screen->r.max.y);
10797dd7cddfSDavid du Colombier 		if(i < nmach-1)
10807dd7cddfSDavid du Colombier 			machr.max.x = startx+(i+1)*dx - 1;
10817dd7cddfSDavid du Colombier 		y = starty;
10827dd7cddfSDavid du Colombier 		for(j=0; j<ngraph; j++, y+=dy){
10837dd7cddfSDavid du Colombier 			g = &graph[i*ngraph+j];
10847dd7cddfSDavid du Colombier 			/* allocate data */
10857dd7cddfSDavid du Colombier 			ondata = g->ndata;
10867dd7cddfSDavid du Colombier 			g->ndata = Dx(machr)+1;	/* may be too many if label will be drawn here; so what? */
10877dd7cddfSDavid du Colombier 			g->data = erealloc(g->data, g->ndata*sizeof(long));
10887dd7cddfSDavid du Colombier 			if(g->ndata > ondata)
10897dd7cddfSDavid du Colombier 				memset(g->data+ondata, 0, (g->ndata-ondata)*sizeof(long));
10907dd7cddfSDavid du Colombier 			/* set geometry */
10917dd7cddfSDavid du Colombier 			g->r = machr;
10927dd7cddfSDavid du Colombier 			g->r.min.y = y;
10937dd7cddfSDavid du Colombier 			g->r.max.y = y+dy - 1;
10947dd7cddfSDavid du Colombier 			if(j == ngraph-1)
10957dd7cddfSDavid du Colombier 				g->r.max.y = screen->r.max.y;
10967dd7cddfSDavid du Colombier 			draw(screen, g->r, cols[g->colindex][0], nil, paritypt(g->r.min.x));
10977dd7cddfSDavid du Colombier 			g->overflow = 0;
10987dd7cddfSDavid du Colombier 			r = g->r;
10997dd7cddfSDavid du Colombier 			r.max.y = r.min.y+mediumfont->height;
11007dd7cddfSDavid du Colombier 			r.max.x = r.min.x+stringwidth(mediumfont, "9999999");
11017dd7cddfSDavid du Colombier 			freeimage(g->overtmp);
11027dd7cddfSDavid du Colombier 			g->overtmp = nil;
11037dd7cddfSDavid du Colombier 			if(r.max.x <= g->r.max.x)
11047dd7cddfSDavid du Colombier 				g->overtmp = allocimage(display, r, screen->chan, 0, -1);
110580ee5cbfSDavid du Colombier 			g->newvalue(g->mach, &v, &vmax, 0);
11067dd7cddfSDavid du Colombier 			redraw(g, vmax);
11077dd7cddfSDavid du Colombier 		}
11087dd7cddfSDavid du Colombier 	}
11097dd7cddfSDavid du Colombier 
11107dd7cddfSDavid du Colombier 	flushimage(display, 1);
11117dd7cddfSDavid du Colombier }
11127dd7cddfSDavid du Colombier 
11137dd7cddfSDavid du Colombier void
11147dd7cddfSDavid du Colombier eresized(int new)
11157dd7cddfSDavid du Colombier {
11167dd7cddfSDavid du Colombier 	lockdisplay(display);
11177dd7cddfSDavid du Colombier 	if(new && getwindow(display, Refnone) < 0) {
11187dd7cddfSDavid du Colombier 		fprint(2, "stats: can't reattach to window\n");
11197dd7cddfSDavid du Colombier 		killall("reattach");
11207dd7cddfSDavid du Colombier 	}
11217dd7cddfSDavid du Colombier 	resize();
11227dd7cddfSDavid du Colombier 	unlockdisplay(display);
11237dd7cddfSDavid du Colombier }
11247dd7cddfSDavid du Colombier 
11257dd7cddfSDavid du Colombier void
11267dd7cddfSDavid du Colombier mouseproc(void)
11277dd7cddfSDavid du Colombier {
11287dd7cddfSDavid du Colombier 	Mouse mouse;
11297dd7cddfSDavid du Colombier 	int i;
11307dd7cddfSDavid du Colombier 
11317dd7cddfSDavid du Colombier 	for(;;){
11327dd7cddfSDavid du Colombier 		mouse = emouse();
11337dd7cddfSDavid du Colombier 		if(mouse.buttons == 4){
11347dd7cddfSDavid du Colombier 			lockdisplay(display);
11357dd7cddfSDavid du Colombier 			for(i=0; i<Nmenu2; i++)
11367dd7cddfSDavid du Colombier 				if(present[i])
11377dd7cddfSDavid du Colombier 					memmove(menu2str[i], "drop ", Opwid);
11387dd7cddfSDavid du Colombier 				else
11397dd7cddfSDavid du Colombier 					memmove(menu2str[i], "add  ", Opwid);
11407dd7cddfSDavid du Colombier 			i = emenuhit(3, &mouse, &menu2);
11417dd7cddfSDavid du Colombier 			if(i >= 0){
11427dd7cddfSDavid du Colombier 				if(!present[i])
11437dd7cddfSDavid du Colombier 					addgraph(i);
11447dd7cddfSDavid du Colombier 				else if(ngraph > 1)
11457dd7cddfSDavid du Colombier 					dropgraph(i);
11467dd7cddfSDavid du Colombier 				resize();
11477dd7cddfSDavid du Colombier 			}
11487dd7cddfSDavid du Colombier 			unlockdisplay(display);
11497dd7cddfSDavid du Colombier 		}
11507dd7cddfSDavid du Colombier 	}
11517dd7cddfSDavid du Colombier }
11527dd7cddfSDavid du Colombier 
11537dd7cddfSDavid du Colombier void
11547dd7cddfSDavid du Colombier startproc(void (*f)(void), int index)
11557dd7cddfSDavid du Colombier {
11567dd7cddfSDavid du Colombier 	int pid;
11577dd7cddfSDavid du Colombier 
11587dd7cddfSDavid du Colombier 	switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){
11597dd7cddfSDavid du Colombier 	case -1:
11607dd7cddfSDavid du Colombier 		fprint(2, "stats: fork failed: %r\n");
11617dd7cddfSDavid du Colombier 		killall("fork failed");
11627dd7cddfSDavid du Colombier 	case 0:
11637dd7cddfSDavid du Colombier 		f();
11647dd7cddfSDavid du Colombier 		fprint(2, "stats: %s process exits\n", procnames[index]);
11657dd7cddfSDavid du Colombier 		if(index >= 0)
11667dd7cddfSDavid du Colombier 			killall("process died");
11677dd7cddfSDavid du Colombier 		exits(nil);
11687dd7cddfSDavid du Colombier 	}
11697dd7cddfSDavid du Colombier 	if(index >= 0)
11707dd7cddfSDavid du Colombier 		pids[index] = pid;
11717dd7cddfSDavid du Colombier }
11727dd7cddfSDavid du Colombier 
11737dd7cddfSDavid du Colombier void
11747dd7cddfSDavid du Colombier main(int argc, char *argv[])
11757dd7cddfSDavid du Colombier {
11767dd7cddfSDavid du Colombier 	int i, j;
117780ee5cbfSDavid du Colombier 	char *s;
11787dd7cddfSDavid du Colombier 	long v, vmax, nargs;
11797dd7cddfSDavid du Colombier 	char args[100];
1180*3f695129SDavid du Colombier 	int sleeptime = 1000;
11817dd7cddfSDavid du Colombier 
11827dd7cddfSDavid du Colombier 	nmach = 1;
11837dd7cddfSDavid du Colombier 	mysysname = getenv("sysname");
11847dd7cddfSDavid du Colombier 	if(mysysname == nil){
11857dd7cddfSDavid du Colombier 		fprint(2, "stats: can't find $sysname: %r\n");
11867dd7cddfSDavid du Colombier 		exits("sysname");
11877dd7cddfSDavid du Colombier 	}
11887dd7cddfSDavid du Colombier 	mysysname = estrdup(mysysname);
11897dd7cddfSDavid du Colombier 
11907dd7cddfSDavid du Colombier 	nargs = 0;
11917dd7cddfSDavid du Colombier 	ARGBEGIN{
1192*3f695129SDavid du Colombier 	case 'T':
1193*3f695129SDavid du Colombier 		s = ARGF();
1194*3f695129SDavid du Colombier 		if(s == nil)
1195*3f695129SDavid du Colombier 			usage();
1196*3f695129SDavid du Colombier 		i = atoi(s);
1197*3f695129SDavid du Colombier 		if(i > 0)
1198*3f695129SDavid du Colombier 			sleeptime = 1000*i;
1199*3f695129SDavid du Colombier 		break;
120080ee5cbfSDavid du Colombier 	case 'S':
120180ee5cbfSDavid du Colombier 		s = ARGF();
120280ee5cbfSDavid du Colombier 		if(s == nil)
120380ee5cbfSDavid du Colombier 			usage();
120480ee5cbfSDavid du Colombier 		scale = atof(s);
120580ee5cbfSDavid du Colombier 		if(scale <= 0.)
120680ee5cbfSDavid du Colombier 			usage();
120780ee5cbfSDavid du Colombier 		break;
120880ee5cbfSDavid du Colombier 	case 'L':
120980ee5cbfSDavid du Colombier 		logscale++;
121080ee5cbfSDavid du Colombier 		break;
121180ee5cbfSDavid du Colombier 	case 'Y':
121280ee5cbfSDavid du Colombier 		ylabels++;
121380ee5cbfSDavid du Colombier 		break;
12149a747e4fSDavid du Colombier 	case 'O':
12159a747e4fSDavid du Colombier 		oldsystem = 1;
12169a747e4fSDavid du Colombier 		break;
12177dd7cddfSDavid du Colombier 	default:
12187dd7cddfSDavid du Colombier 		if(nargs>=sizeof args || strchr(argchars, ARGC())==nil)
12197dd7cddfSDavid du Colombier 			usage();
12207dd7cddfSDavid du Colombier 		args[nargs++] = ARGC();
12217dd7cddfSDavid du Colombier 	}ARGEND
12227dd7cddfSDavid du Colombier 
12237dd7cddfSDavid du Colombier 	if(argc == 0){
12247dd7cddfSDavid du Colombier 		mach = emalloc(nmach*sizeof(Machine));
12257dd7cddfSDavid du Colombier 		initmach(&mach[0], mysysname);
12267dd7cddfSDavid du Colombier 		readmach(&mach[0], 1);
12277dd7cddfSDavid du Colombier 	}else{
12287dd7cddfSDavid du Colombier 		for(i=0; i<argc; i++){
12297dd7cddfSDavid du Colombier 			addmachine(argv[i]);
12307dd7cddfSDavid du Colombier 			readmach(&mach[i], 1);
12317dd7cddfSDavid du Colombier 		}
12327dd7cddfSDavid du Colombier 	}
12337dd7cddfSDavid du Colombier 
12347dd7cddfSDavid du Colombier 	for(i=0; i<nargs; i++)
12357dd7cddfSDavid du Colombier 	switch(args[i]){
12367dd7cddfSDavid du Colombier 	default:
12377dd7cddfSDavid du Colombier 		fprint(2, "stats: internal error: unknown arg %c\n", args[i]);
12387dd7cddfSDavid du Colombier 		usage();
123980ee5cbfSDavid du Colombier 	case 'b':
124080ee5cbfSDavid du Colombier 		addgraph(Mbattery);
124180ee5cbfSDavid du Colombier 		break;
12427dd7cddfSDavid du Colombier 	case 'c':
12437dd7cddfSDavid du Colombier 		addgraph(Mcontext);
12447dd7cddfSDavid du Colombier 		break;
12457dd7cddfSDavid du Colombier 	case 'e':
12467dd7cddfSDavid du Colombier 		addgraph(Mether);
12477dd7cddfSDavid du Colombier 		break;
12487dd7cddfSDavid du Colombier 	case 'E':
12497dd7cddfSDavid du Colombier 		addgraph(Metherin);
12507dd7cddfSDavid du Colombier 		addgraph(Metherout);
12517dd7cddfSDavid du Colombier 		break;
12527dd7cddfSDavid du Colombier 	case 'f':
12537dd7cddfSDavid du Colombier 		addgraph(Mfault);
12547dd7cddfSDavid du Colombier 		break;
12557dd7cddfSDavid du Colombier 	case 'i':
12567dd7cddfSDavid du Colombier 		addgraph(Mintr);
12577dd7cddfSDavid du Colombier 		break;
12587dd7cddfSDavid du Colombier 	case 'l':
12597dd7cddfSDavid du Colombier 		addgraph(Mload);
12607dd7cddfSDavid du Colombier 		break;
12617dd7cddfSDavid du Colombier 	case 'm':
12627dd7cddfSDavid du Colombier 		addgraph(Mmem);
12637dd7cddfSDavid du Colombier 		break;
12647dd7cddfSDavid du Colombier 	case 'n':
12657dd7cddfSDavid du Colombier 		addgraph(Metherin);
12667dd7cddfSDavid du Colombier 		addgraph(Metherout);
12677dd7cddfSDavid du Colombier 		addgraph(Methererr);
12687dd7cddfSDavid du Colombier 		break;
12697dd7cddfSDavid du Colombier 	case 'p':
12707dd7cddfSDavid du Colombier 		addgraph(Mtlbpurge);
12717dd7cddfSDavid du Colombier 		break;
12727dd7cddfSDavid du Colombier 	case 's':
12737dd7cddfSDavid du Colombier 		addgraph(Msyscall);
12747dd7cddfSDavid du Colombier 		break;
12757dd7cddfSDavid du Colombier 	case 't':
12767dd7cddfSDavid du Colombier 		addgraph(Mtlbmiss);
12777dd7cddfSDavid du Colombier 		addgraph(Mtlbpurge);
12787dd7cddfSDavid du Colombier 		break;
12799a747e4fSDavid du Colombier 	case '8':
12809a747e4fSDavid du Colombier 		addgraph(Msignal);
12819a747e4fSDavid du Colombier 		break;
12827dd7cddfSDavid du Colombier 	case 'w':
12837dd7cddfSDavid du Colombier 		addgraph(Mswap);
12847dd7cddfSDavid du Colombier 		break;
12857dd7cddfSDavid du Colombier 	}
12867dd7cddfSDavid du Colombier 
12877dd7cddfSDavid du Colombier 	if(ngraph == 0)
12887dd7cddfSDavid du Colombier 		addgraph(Mload);
12897dd7cddfSDavid du Colombier 
12907dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++)
12917dd7cddfSDavid du Colombier 		for(j=0; j<ngraph; j++)
12927dd7cddfSDavid du Colombier 			graph[i*ngraph+j].mach = &mach[i];
12937dd7cddfSDavid du Colombier 
12947dd7cddfSDavid du Colombier 	if(initdraw(nil, nil, "stats") < 0){
12957dd7cddfSDavid du Colombier 		fprint(2, "stats: initdraw failed: %r\n");
12967dd7cddfSDavid du Colombier 		exits("initdraw");
12977dd7cddfSDavid du Colombier 	}
12987dd7cddfSDavid du Colombier 	colinit();
12997dd7cddfSDavid du Colombier 	einit(Emouse);
13007dd7cddfSDavid du Colombier 	notify(nil);
13017dd7cddfSDavid du Colombier 	startproc(mouseproc, Mouseproc);
13027dd7cddfSDavid du Colombier 	pids[Mainproc] = getpid();
13037dd7cddfSDavid du Colombier 	display->locking = 1;	/* tell library we're using the display lock */
13047dd7cddfSDavid du Colombier 
13057dd7cddfSDavid du Colombier 	resize();
13067dd7cddfSDavid du Colombier 
13077dd7cddfSDavid du Colombier 	unlockdisplay(display); /* display is still locked from initdraw() */
13087dd7cddfSDavid du Colombier 	for(;;){
13097dd7cddfSDavid du Colombier 		for(i=0; i<nmach; i++)
13107dd7cddfSDavid du Colombier 			readmach(&mach[i], 0);
13117dd7cddfSDavid du Colombier 		lockdisplay(display);
13127dd7cddfSDavid du Colombier 		parity = 1-parity;
13137dd7cddfSDavid du Colombier 		for(i=0; i<nmach*ngraph; i++){
131480ee5cbfSDavid du Colombier 			graph[i].newvalue(graph[i].mach, &v, &vmax, 0);
13157dd7cddfSDavid du Colombier 			graph[i].update(&graph[i], v, vmax);
13167dd7cddfSDavid du Colombier 		}
13177dd7cddfSDavid du Colombier 		flushimage(display, 1);
13187dd7cddfSDavid du Colombier 		unlockdisplay(display);
1319*3f695129SDavid du Colombier 		sleep(sleeptime);
13207dd7cddfSDavid du Colombier 	}
13217dd7cddfSDavid du Colombier }
1322