xref: /plan9/sys/src/cmd/stats.c (revision f86ef3ceeb3c1245f69a9116300be0dfebc218fb)
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 
9*f86ef3ceSDavid du Colombier #define	MAXNUM	10	/* 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;
21*f86ef3ceSDavid du Colombier 	void		(*newvalue)(Machine*, ulong*, ulong*, int);
22*f86ef3ceSDavid du Colombier 	void		(*update)(Graph*, ulong, ulong);
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,
44dc5a79c1SDavid du Colombier 	Idle,
45*f86ef3ceSDavid du Colombier 	InIntr,
467dd7cddfSDavid du Colombier 	/* /net/ether0/0/stats */
477dd7cddfSDavid du Colombier 	In		= 0,
487dd7cddfSDavid du Colombier 	Out,
497dd7cddfSDavid du Colombier 	Err0,
503e12c5d1SDavid du Colombier };
513e12c5d1SDavid du Colombier 
527dd7cddfSDavid du Colombier struct Machine
533e12c5d1SDavid du Colombier {
547dd7cddfSDavid du Colombier 	char		*name;
557dd7cddfSDavid du Colombier 	int		remote;
567dd7cddfSDavid du Colombier 	int		statsfd;
577dd7cddfSDavid du Colombier 	int		swapfd;
587dd7cddfSDavid du Colombier 	int		etherfd;
599a747e4fSDavid du Colombier 	int		ifstatsfd;
6080ee5cbfSDavid du Colombier 	int		batteryfd;
619a747e4fSDavid du Colombier 	int		bitsybatfd;
627dd7cddfSDavid du Colombier 	int		disable;
633e12c5d1SDavid du Colombier 
64*f86ef3ceSDavid du Colombier 	ulong		devswap[4];
65*f86ef3ceSDavid du Colombier 	ulong		devsysstat[10];
66*f86ef3ceSDavid du Colombier 	ulong		prevsysstat[10];
677dd7cddfSDavid du Colombier 	int		nproc;
68*f86ef3ceSDavid du Colombier 	ulong		netetherstats[8];
69*f86ef3ceSDavid du Colombier 	ulong		prevetherstats[8];
70*f86ef3ceSDavid du Colombier 	ulong		batterystats[2];
71*f86ef3ceSDavid du Colombier 	ulong		netetherifstats[2];
723e12c5d1SDavid du Colombier 
737dd7cddfSDavid du Colombier 	char		buf[1024];
747dd7cddfSDavid du Colombier 	char		*bufp;
757dd7cddfSDavid du Colombier 	char		*ebufp;
763e12c5d1SDavid du Colombier };
777dd7cddfSDavid du Colombier 
787dd7cddfSDavid du Colombier enum
797dd7cddfSDavid du Colombier {
807dd7cddfSDavid du Colombier 	Mainproc,
817dd7cddfSDavid du Colombier 	Mouseproc,
827dd7cddfSDavid du Colombier 	NPROC,
837dd7cddfSDavid du Colombier };
847dd7cddfSDavid du Colombier 
857dd7cddfSDavid du Colombier enum
867dd7cddfSDavid du Colombier {
877dd7cddfSDavid du Colombier 	Ncolor	= 6,
887dd7cddfSDavid du Colombier 	Ysqueeze	= 2,	/* vertical squeezing of label text */
897dd7cddfSDavid du Colombier 	Labspace	= 2,	/* room around label */
907dd7cddfSDavid du Colombier 	Dot		= 2,	/* height of dot */
917dd7cddfSDavid du Colombier 	Opwid	= 5,	/* strlen("add  ") or strlen("drop ") */
9280ee5cbfSDavid du Colombier 	Nlab		= 3,	/* max number of labels on y axis */
9380ee5cbfSDavid du Colombier 	Lablen	= 16,	/* max length of label */
9480ee5cbfSDavid du Colombier 	Lx		= 4,	/* label tick length */
957dd7cddfSDavid du Colombier };
967dd7cddfSDavid du Colombier 
977dd7cddfSDavid du Colombier enum Menu2
987dd7cddfSDavid du Colombier {
99*f86ef3ceSDavid du Colombier 	Mbattery,
1007dd7cddfSDavid du Colombier 	Mcontext,
1017dd7cddfSDavid du Colombier 	Mether,
1027dd7cddfSDavid du Colombier 	Methererr,
1037dd7cddfSDavid du Colombier 	Metherin,
1047dd7cddfSDavid du Colombier 	Metherout,
1057dd7cddfSDavid du Colombier 	Mfault,
106*f86ef3ceSDavid du Colombier 	Midle,
107*f86ef3ceSDavid du Colombier 	Minintr,
1087dd7cddfSDavid du Colombier 	Mintr,
1097dd7cddfSDavid du Colombier 	Mload,
1107dd7cddfSDavid du Colombier 	Mmem,
1117dd7cddfSDavid du Colombier 	Mswap,
1127dd7cddfSDavid du Colombier 	Msyscall,
1137dd7cddfSDavid du Colombier 	Mtlbmiss,
1147dd7cddfSDavid du Colombier 	Mtlbpurge,
1159a747e4fSDavid du Colombier 	Msignal,
1167dd7cddfSDavid du Colombier 	Nmenu2,
1177dd7cddfSDavid du Colombier };
1187dd7cddfSDavid du Colombier 
1197dd7cddfSDavid du Colombier char	*menu2str[Nmenu2+1] = {
120*f86ef3ceSDavid du Colombier 	"add  battery ",
1217dd7cddfSDavid du Colombier 	"add  context ",
1227dd7cddfSDavid du Colombier 	"add  ether   ",
1237dd7cddfSDavid du Colombier 	"add  ethererr",
1247dd7cddfSDavid du Colombier 	"add  etherin ",
1257dd7cddfSDavid du Colombier 	"add  etherout",
1267dd7cddfSDavid du Colombier 	"add  fault   ",
127*f86ef3ceSDavid du Colombier 	"add  idle    ",
128*f86ef3ceSDavid du Colombier 	"add  inintr  ",
1297dd7cddfSDavid du Colombier 	"add  intr    ",
1307dd7cddfSDavid du Colombier 	"add  load    ",
1317dd7cddfSDavid du Colombier 	"add  mem     ",
1327dd7cddfSDavid du Colombier 	"add  swap    ",
1337dd7cddfSDavid du Colombier 	"add  syscall ",
1347dd7cddfSDavid du Colombier 	"add  tlbmiss ",
1357dd7cddfSDavid du Colombier 	"add  tlbpurge",
1369a747e4fSDavid du Colombier 	"add  802.11b ",
1377dd7cddfSDavid du Colombier 	nil,
1387dd7cddfSDavid du Colombier };
1397dd7cddfSDavid du Colombier 
1407dd7cddfSDavid du Colombier 
141*f86ef3ceSDavid du Colombier void	contextval(Machine*, ulong*, ulong*, int),
142*f86ef3ceSDavid du Colombier 	etherval(Machine*, ulong*, ulong*, int),
143*f86ef3ceSDavid du Colombier 	ethererrval(Machine*, ulong*, ulong*, int),
144*f86ef3ceSDavid du Colombier 	etherinval(Machine*, ulong*, ulong*, int),
145*f86ef3ceSDavid du Colombier 	etheroutval(Machine*, ulong*, ulong*, int),
146*f86ef3ceSDavid du Colombier 	faultval(Machine*, ulong*, ulong*, int),
147*f86ef3ceSDavid du Colombier 	intrval(Machine*, ulong*, ulong*, int),
148*f86ef3ceSDavid du Colombier 	inintrval(Machine*, ulong*, ulong*, int),
149*f86ef3ceSDavid du Colombier 	loadval(Machine*, ulong*, ulong*, int),
150*f86ef3ceSDavid du Colombier 	idleval(Machine*, ulong*, ulong*, int),
151*f86ef3ceSDavid du Colombier 	memval(Machine*, ulong*, ulong*, int),
152*f86ef3ceSDavid du Colombier 	swapval(Machine*, ulong*, ulong*, int),
153*f86ef3ceSDavid du Colombier 	syscallval(Machine*, ulong*, ulong*, int),
154*f86ef3ceSDavid du Colombier 	tlbmissval(Machine*, ulong*, ulong*, int),
155*f86ef3ceSDavid du Colombier 	tlbpurgeval(Machine*, ulong*, ulong*, int),
156*f86ef3ceSDavid du Colombier 	batteryval(Machine*, ulong*, ulong*, int),
157*f86ef3ceSDavid du Colombier 	signalval(Machine*, ulong*, ulong*, int);
1587dd7cddfSDavid du Colombier 
1597dd7cddfSDavid du Colombier Menu	menu2 = {menu2str, nil};
1607dd7cddfSDavid du Colombier int		present[Nmenu2];
161*f86ef3ceSDavid du Colombier void		(*newvaluefn[Nmenu2])(Machine*, ulong*, ulong*, int init) = {
162*f86ef3ceSDavid du Colombier 	batteryval,
1637dd7cddfSDavid du Colombier 	contextval,
1647dd7cddfSDavid du Colombier 	etherval,
1657dd7cddfSDavid du Colombier 	ethererrval,
1667dd7cddfSDavid du Colombier 	etherinval,
1677dd7cddfSDavid du Colombier 	etheroutval,
1687dd7cddfSDavid du Colombier 	faultval,
169*f86ef3ceSDavid du Colombier 	idleval,
170*f86ef3ceSDavid du Colombier 	inintrval,
1717dd7cddfSDavid du Colombier 	intrval,
1727dd7cddfSDavid du Colombier 	loadval,
1737dd7cddfSDavid du Colombier 	memval,
1747dd7cddfSDavid du Colombier 	swapval,
1757dd7cddfSDavid du Colombier 	syscallval,
1767dd7cddfSDavid du Colombier 	tlbmissval,
1777dd7cddfSDavid du Colombier 	tlbpurgeval,
1789a747e4fSDavid du Colombier 	signalval,
1797dd7cddfSDavid du Colombier };
1807dd7cddfSDavid du Colombier 
1817dd7cddfSDavid du Colombier Image	*cols[Ncolor][3];
1827dd7cddfSDavid du Colombier Graph	*graph;
1837dd7cddfSDavid du Colombier Machine	*mach;
1847dd7cddfSDavid du Colombier Font		*mediumfont;
1857dd7cddfSDavid du Colombier char		*mysysname;
186*f86ef3ceSDavid du Colombier char		argchars[] = "8bceEfiImlnpstw";
1877dd7cddfSDavid du Colombier int		pids[NPROC];
1887dd7cddfSDavid du Colombier int 		parity;	/* toggled to avoid patterns in textured background */
1897dd7cddfSDavid du Colombier int		nmach;
1907dd7cddfSDavid du Colombier int		ngraph;	/* totaly number is ngraph*nmach */
19180ee5cbfSDavid du Colombier double	scale = 1.0;
19280ee5cbfSDavid du Colombier int		logscale = 0;
19380ee5cbfSDavid du Colombier int		ylabels = 0;
1949a747e4fSDavid du Colombier int		oldsystem = 0;
1957dd7cddfSDavid du Colombier 
1967dd7cddfSDavid du Colombier char		*procnames[NPROC] = {"main", "mouse"};
1977dd7cddfSDavid du Colombier 
1987dd7cddfSDavid du Colombier void
1997dd7cddfSDavid du Colombier killall(char *s)
2007dd7cddfSDavid du Colombier {
2017dd7cddfSDavid du Colombier 	int i, pid;
2027dd7cddfSDavid du Colombier 
2037dd7cddfSDavid du Colombier 	pid = getpid();
2047dd7cddfSDavid du Colombier 	for(i=0; i<NPROC; i++)
2057dd7cddfSDavid du Colombier 		if(pids[i] && pids[i]!=pid)
2067dd7cddfSDavid du Colombier 			postnote(PNPROC, pids[i], "kill");
2077dd7cddfSDavid du Colombier 	exits(s);
2087dd7cddfSDavid du Colombier }
2097dd7cddfSDavid du Colombier 
2107dd7cddfSDavid du Colombier void*
2117dd7cddfSDavid du Colombier emalloc(ulong sz)
2127dd7cddfSDavid du Colombier {
2137dd7cddfSDavid du Colombier 	void *v;
2147dd7cddfSDavid du Colombier 	v = malloc(sz);
2157dd7cddfSDavid du Colombier 	if(v == nil) {
2167dd7cddfSDavid du Colombier 		fprint(2, "stats: out of memory allocating %ld: %r\n", sz);
2177dd7cddfSDavid du Colombier 		killall("mem");
2187dd7cddfSDavid du Colombier 	}
2197dd7cddfSDavid du Colombier 	memset(v, 0, sz);
2207dd7cddfSDavid du Colombier 	return v;
2217dd7cddfSDavid du Colombier }
2227dd7cddfSDavid du Colombier 
2237dd7cddfSDavid du Colombier void*
2247dd7cddfSDavid du Colombier erealloc(void *v, ulong sz)
2257dd7cddfSDavid du Colombier {
2267dd7cddfSDavid du Colombier 	v = realloc(v, sz);
2277dd7cddfSDavid du Colombier 	if(v == nil) {
2287dd7cddfSDavid du Colombier 		fprint(2, "stats: out of memory reallocating %ld: %r\n", sz);
2297dd7cddfSDavid du Colombier 		killall("mem");
2307dd7cddfSDavid du Colombier 	}
2317dd7cddfSDavid du Colombier 	return v;
2323e12c5d1SDavid du Colombier }
2333e12c5d1SDavid du Colombier 
2343e12c5d1SDavid du Colombier char*
2357dd7cddfSDavid du Colombier estrdup(char *s)
2363e12c5d1SDavid du Colombier {
2377dd7cddfSDavid du Colombier 	char *t;
2387dd7cddfSDavid du Colombier 	if((t = strdup(s)) == nil) {
2397dd7cddfSDavid du Colombier 		fprint(2, "stats: out of memory in strdup(%.10s): %r\n", s);
2407dd7cddfSDavid du Colombier 		killall("mem");
2417dd7cddfSDavid du Colombier 	}
2427dd7cddfSDavid du Colombier 	return t;
2433e12c5d1SDavid du Colombier }
2443e12c5d1SDavid du Colombier 
2453e12c5d1SDavid du Colombier void
2467dd7cddfSDavid du Colombier mkcol(int i, int c0, int c1, int c2)
2473e12c5d1SDavid du Colombier {
2487dd7cddfSDavid du Colombier 	cols[i][0] = allocimagemix(display, c0, DWhite);
2497dd7cddfSDavid du Colombier 	cols[i][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c1);
2507dd7cddfSDavid du Colombier 	cols[i][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c2);
2517dd7cddfSDavid du Colombier }
2523e12c5d1SDavid du Colombier 
2537dd7cddfSDavid du Colombier void
2547dd7cddfSDavid du Colombier colinit(void)
2557dd7cddfSDavid du Colombier {
2567dd7cddfSDavid du Colombier 	mediumfont = openfont(display, "/lib/font/bit/pelm/latin1.8.font");
2577dd7cddfSDavid du Colombier 	if(mediumfont == nil)
2587dd7cddfSDavid du Colombier 		mediumfont = font;
2597dd7cddfSDavid du Colombier 
2607dd7cddfSDavid du Colombier 	/* Peach */
2617dd7cddfSDavid du Colombier 	mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF);
2627dd7cddfSDavid du Colombier 	/* Aqua */
2637dd7cddfSDavid du Colombier 	mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue);
2647dd7cddfSDavid du Colombier 	/* Yellow */
2657dd7cddfSDavid du Colombier 	mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen);
2667dd7cddfSDavid du Colombier 	/* Green */
2677dd7cddfSDavid du Colombier 	mkcol(3, DPalegreen, DMedgreen, DDarkgreen);
2687dd7cddfSDavid du Colombier 	/* Blue */
2697dd7cddfSDavid du Colombier 	mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF);
2707dd7cddfSDavid du Colombier 	/* Grey */
2717dd7cddfSDavid du Colombier 	cols[5][0] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF);
2727dd7cddfSDavid du Colombier 	cols[5][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF);
2737dd7cddfSDavid du Colombier 	cols[5][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x888888FF);
2747dd7cddfSDavid du Colombier }
2757dd7cddfSDavid du Colombier 
2767dd7cddfSDavid du Colombier int
2777dd7cddfSDavid du Colombier loadbuf(Machine *m, int *fd)
2787dd7cddfSDavid du Colombier {
2797dd7cddfSDavid du Colombier 	int n;
2807dd7cddfSDavid du Colombier 
2817dd7cddfSDavid du Colombier 
2827dd7cddfSDavid du Colombier 	if(*fd < 0)
2837dd7cddfSDavid du Colombier 		return 0;
2847dd7cddfSDavid du Colombier 	seek(*fd, 0, 0);
2857dd7cddfSDavid du Colombier 	n = read(*fd, m->buf, sizeof m->buf);
2867dd7cddfSDavid du Colombier 	if(n <= 0){
2877dd7cddfSDavid du Colombier 		close(*fd);
2887dd7cddfSDavid du Colombier 		*fd = -1;
2897dd7cddfSDavid du Colombier 		return 0;
2907dd7cddfSDavid du Colombier 	}
2917dd7cddfSDavid du Colombier 	m->bufp = m->buf;
2927dd7cddfSDavid du Colombier 	m->ebufp = m->buf+n;
2937dd7cddfSDavid du Colombier 	return 1;
2947dd7cddfSDavid du Colombier }
2957dd7cddfSDavid du Colombier 
2967dd7cddfSDavid du Colombier void
2977dd7cddfSDavid du Colombier label(Point p, int dy, char *text)
2987dd7cddfSDavid du Colombier {
2997dd7cddfSDavid du Colombier 	char *s;
3007dd7cddfSDavid du Colombier 	Rune r[2];
3017dd7cddfSDavid du Colombier 	int w, maxw, maxy;
3027dd7cddfSDavid du Colombier 
3037dd7cddfSDavid du Colombier 	p.x += Labspace;
3047dd7cddfSDavid du Colombier 	maxy = p.y+dy;
3057dd7cddfSDavid du Colombier 	maxw = 0;
3067dd7cddfSDavid du Colombier 	r[1] = '\0';
3077dd7cddfSDavid du Colombier 	for(s=text; *s; ){
3087dd7cddfSDavid du Colombier 		if(p.y+mediumfont->height-Ysqueeze > maxy)
3097dd7cddfSDavid du Colombier 			break;
3107dd7cddfSDavid du Colombier 		w = chartorune(r, s);
3117dd7cddfSDavid du Colombier 		s += w;
3127dd7cddfSDavid du Colombier 		w = runestringwidth(mediumfont, r);
3137dd7cddfSDavid du Colombier 		if(w > maxw)
3147dd7cddfSDavid du Colombier 			maxw = w;
3157dd7cddfSDavid du Colombier 		runestring(screen, p, display->black, ZP, mediumfont, r);
3167dd7cddfSDavid du Colombier 		p.y += mediumfont->height-Ysqueeze;
3177dd7cddfSDavid du Colombier 	}
3187dd7cddfSDavid du Colombier }
3197dd7cddfSDavid du Colombier 
3207dd7cddfSDavid du Colombier Point
3217dd7cddfSDavid du Colombier paritypt(int x)
3227dd7cddfSDavid du Colombier {
3237dd7cddfSDavid du Colombier 	return Pt(x+parity, 0);
3247dd7cddfSDavid du Colombier }
3257dd7cddfSDavid du Colombier 
3267dd7cddfSDavid du Colombier Point
327*f86ef3ceSDavid du Colombier datapoint(Graph *g, int x, ulong v, ulong vmax)
3287dd7cddfSDavid du Colombier {
3297dd7cddfSDavid du Colombier 	Point p;
33080ee5cbfSDavid du Colombier 	double y;
3317dd7cddfSDavid du Colombier 
3327dd7cddfSDavid du Colombier 	p.x = x;
33380ee5cbfSDavid du Colombier 	y = ((double)v)/(vmax*scale);
33480ee5cbfSDavid du Colombier 	if(logscale){
33580ee5cbfSDavid du Colombier 		/*
33680ee5cbfSDavid du Colombier 		 * Arrange scale to cover a factor of 1000.
33780ee5cbfSDavid du Colombier 		 * vmax corresponds to the 100 mark.
33880ee5cbfSDavid du Colombier 		 * 10*vmax is the top of the scale.
33980ee5cbfSDavid du Colombier 		 */
34080ee5cbfSDavid du Colombier 		if(y <= 0.)
34180ee5cbfSDavid du Colombier 			y = 0;
34280ee5cbfSDavid du Colombier 		else{
34380ee5cbfSDavid du Colombier 			y = log10(y);
34480ee5cbfSDavid du Colombier 			/* 1 now corresponds to the top; -2 to the bottom; rescale */
34580ee5cbfSDavid du Colombier 			y = (y+2.)/3.;
34680ee5cbfSDavid du Colombier 		}
34780ee5cbfSDavid du Colombier 	}
34880ee5cbfSDavid du Colombier 	p.y = g->r.max.y - Dy(g->r)*y - Dot;
3497dd7cddfSDavid du Colombier 	if(p.y < g->r.min.y)
3507dd7cddfSDavid du Colombier 		p.y = g->r.min.y;
3517dd7cddfSDavid du Colombier 	if(p.y > g->r.max.y-Dot)
3527dd7cddfSDavid du Colombier 		p.y = g->r.max.y-Dot;
3537dd7cddfSDavid du Colombier 	return p;
3547dd7cddfSDavid du Colombier }
3557dd7cddfSDavid du Colombier 
3567dd7cddfSDavid du Colombier void
357*f86ef3ceSDavid du Colombier drawdatum(Graph *g, int x, ulong prev, ulong v, ulong vmax)
3587dd7cddfSDavid du Colombier {
3597dd7cddfSDavid du Colombier 	int c;
3607dd7cddfSDavid du Colombier 	Point p, q;
3617dd7cddfSDavid du Colombier 
3627dd7cddfSDavid du Colombier 	c = g->colindex;
3637dd7cddfSDavid du Colombier 	p = datapoint(g, x, v, vmax);
3647dd7cddfSDavid du Colombier 	q = datapoint(g, x, prev, vmax);
3657dd7cddfSDavid du Colombier 	if(p.y < q.y){
3667dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, g->r.min.y, p.x+1, p.y), cols[c][0], nil, paritypt(p.x));
3677dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, p.y, p.x+1, q.y+Dot), cols[c][2], nil, ZP);
3687dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, q.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP);
3697dd7cddfSDavid du Colombier 	}else{
3707dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, g->r.min.y, p.x+1, q.y), cols[c][0], nil, paritypt(p.x));
3717dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, q.y, p.x+1, p.y+Dot), cols[c][2], nil, ZP);
3727dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, p.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP);
3737dd7cddfSDavid du Colombier 	}
3747dd7cddfSDavid du Colombier 
3757dd7cddfSDavid du Colombier }
3767dd7cddfSDavid du Colombier 
3777dd7cddfSDavid du Colombier void
3787dd7cddfSDavid du Colombier redraw(Graph *g, int vmax)
3797dd7cddfSDavid du Colombier {
3807dd7cddfSDavid du Colombier 	int i, c;
3817dd7cddfSDavid du Colombier 
3827dd7cddfSDavid du Colombier 	c = g->colindex;
3837dd7cddfSDavid du Colombier 	draw(screen, g->r, cols[c][0], nil, paritypt(g->r.min.x));
3847dd7cddfSDavid du Colombier 	for(i=1; i<Dx(g->r); i++)
3857dd7cddfSDavid du Colombier 		drawdatum(g, g->r.max.x-i, g->data[i-1], g->data[i], vmax);
3867dd7cddfSDavid du Colombier 	drawdatum(g, g->r.min.x, g->data[i], g->data[i], vmax);
3877dd7cddfSDavid du Colombier 	g->overflow = 0;
3887dd7cddfSDavid du Colombier }
3897dd7cddfSDavid du Colombier 
3907dd7cddfSDavid du Colombier void
391*f86ef3ceSDavid du Colombier update1(Graph *g, ulong v, ulong vmax)
3927dd7cddfSDavid du Colombier {
3937dd7cddfSDavid du Colombier 	char buf[32];
39480ee5cbfSDavid du Colombier 	int overflow;
3957dd7cddfSDavid du Colombier 
3967dd7cddfSDavid du Colombier 	if(g->overflow && g->overtmp!=nil)
3977dd7cddfSDavid du Colombier 		draw(screen, g->overtmp->r, g->overtmp, nil, g->overtmp->r.min);
3987dd7cddfSDavid du Colombier 	draw(screen, g->r, screen, nil, Pt(g->r.min.x+1, g->r.min.y));
3997dd7cddfSDavid du Colombier 	drawdatum(g, g->r.max.x-1, g->data[0], v, vmax);
4007dd7cddfSDavid du Colombier 	memmove(g->data+1, g->data, (g->ndata-1)*sizeof(g->data[0]));
4017dd7cddfSDavid du Colombier 	g->data[0] = v;
4027dd7cddfSDavid du Colombier 	g->overflow = 0;
40380ee5cbfSDavid du Colombier 	if(logscale)
40480ee5cbfSDavid du Colombier 		overflow = (v>10*vmax*scale);
40580ee5cbfSDavid du Colombier 	else
40680ee5cbfSDavid du Colombier 		overflow = (v>vmax*scale);
40780ee5cbfSDavid du Colombier 	if(overflow && g->overtmp!=nil){
4087dd7cddfSDavid du Colombier 		g->overflow = 1;
4097dd7cddfSDavid du Colombier 		draw(g->overtmp, g->overtmp->r, screen, nil, g->overtmp->r.min);
4107dd7cddfSDavid du Colombier 		sprint(buf, "%ld", v);
4117dd7cddfSDavid du Colombier 		string(screen, g->overtmp->r.min, display->black, ZP, mediumfont, buf);
4127dd7cddfSDavid du Colombier 	}
4137dd7cddfSDavid du Colombier }
4147dd7cddfSDavid du Colombier 
4157dd7cddfSDavid du Colombier /* read one line of text from buffer and process integers */
4167dd7cddfSDavid du Colombier int
417*f86ef3ceSDavid du Colombier readnums(Machine *m, int n, ulong *a, int spanlines)
4187dd7cddfSDavid du Colombier {
4197dd7cddfSDavid du Colombier 	int i;
4207dd7cddfSDavid du Colombier 	char *p, *ep;
4217dd7cddfSDavid du Colombier 
4227dd7cddfSDavid du Colombier 	if(spanlines)
4237dd7cddfSDavid du Colombier 		ep = m->ebufp;
4247dd7cddfSDavid du Colombier 	else
4257dd7cddfSDavid du Colombier 		for(ep=m->bufp; ep<m->ebufp; ep++)
4267dd7cddfSDavid du Colombier 			if(*ep == '\n')
4277dd7cddfSDavid du Colombier 				break;
4287dd7cddfSDavid du Colombier 	p = m->bufp;
4297dd7cddfSDavid du Colombier 	for(i=0; i<n && p<ep; i++){
4309a747e4fSDavid du Colombier 		while(p<ep && !isdigit(*p) && *p!='-')
4317dd7cddfSDavid du Colombier 			p++;
4327dd7cddfSDavid du Colombier 		if(p == ep)
4337dd7cddfSDavid du Colombier 			break;
434*f86ef3ceSDavid du Colombier 		a[i] = strtoul(p, &p, 10);
4357dd7cddfSDavid du Colombier 	}
4367dd7cddfSDavid du Colombier 	if(ep < m->ebufp)
4377dd7cddfSDavid du Colombier 		ep++;
4387dd7cddfSDavid du Colombier 	m->bufp = ep;
4397dd7cddfSDavid du Colombier 	return i == n;
4407dd7cddfSDavid du Colombier }
4417dd7cddfSDavid du Colombier 
4427dd7cddfSDavid du Colombier /* Network on fd1, mount driver on fd0 */
4437dd7cddfSDavid du Colombier static int
4447dd7cddfSDavid du Colombier filter(int fd)
4457dd7cddfSDavid du Colombier {
4467dd7cddfSDavid du Colombier 	int p[2];
4477dd7cddfSDavid du Colombier 
4487dd7cddfSDavid du Colombier 	if(pipe(p) < 0){
4497dd7cddfSDavid du Colombier 		fprint(2, "stats: can't pipe: %r\n");
4507dd7cddfSDavid du Colombier 		killall("pipe");
4517dd7cddfSDavid du Colombier 	}
4527dd7cddfSDavid du Colombier 
4537dd7cddfSDavid du Colombier 	switch(rfork(RFNOWAIT|RFPROC|RFFDG)) {
4547dd7cddfSDavid du Colombier 	case -1:
4557dd7cddfSDavid du Colombier 		sysfatal("rfork record module");
4567dd7cddfSDavid du Colombier 	case 0:
4577dd7cddfSDavid du Colombier 		dup(fd, 1);
4587dd7cddfSDavid du Colombier 		close(fd);
4597dd7cddfSDavid du Colombier 		dup(p[0], 0);
4607dd7cddfSDavid du Colombier 		close(p[0]);
4617dd7cddfSDavid du Colombier 		close(p[1]);
4627dd7cddfSDavid du Colombier 		execl("/bin/aux/fcall", "fcall", 0);
4637dd7cddfSDavid du Colombier 		fprint(2, "stats: can't exec fcall: %r\n");
4647dd7cddfSDavid du Colombier 		killall("fcall");
4657dd7cddfSDavid du Colombier 	default:
4667dd7cddfSDavid du Colombier 		close(fd);
4677dd7cddfSDavid du Colombier 		close(p[0]);
4687dd7cddfSDavid du Colombier 	}
4697dd7cddfSDavid du Colombier 	return p[1];
4707dd7cddfSDavid du Colombier }
4717dd7cddfSDavid du Colombier 
4727dd7cddfSDavid du Colombier /*
4737dd7cddfSDavid du Colombier  * 9fs
4747dd7cddfSDavid du Colombier  */
4757dd7cddfSDavid du Colombier int
4767dd7cddfSDavid du Colombier connect9fs(char *addr)
4777dd7cddfSDavid du Colombier {
4789a747e4fSDavid du Colombier 	char dir[256], *na;
4797dd7cddfSDavid du Colombier 	int fd;
4807dd7cddfSDavid du Colombier 
4817dd7cddfSDavid du Colombier 	fprint(2, "connect9fs...");
4827dd7cddfSDavid du Colombier 	na = netmkaddr(addr, 0, "9fs");
4837dd7cddfSDavid du Colombier 
4847dd7cddfSDavid du Colombier 	fprint(2, "dial %s...", na);
4857dd7cddfSDavid du Colombier 	if((fd = dial(na, 0, dir, 0)) < 0)
4867dd7cddfSDavid du Colombier 		return -1;
4877dd7cddfSDavid du Colombier 
4887dd7cddfSDavid du Colombier 	fprint(2, "dir %s...", dir);
4899a747e4fSDavid du Colombier //	if(strstr(dir, "tcp"))
4909a747e4fSDavid du Colombier //		fd = filter(fd);
4917dd7cddfSDavid du Colombier 	return fd;
4927dd7cddfSDavid du Colombier }
4937dd7cddfSDavid du Colombier 
4949a747e4fSDavid du Colombier int
4959a747e4fSDavid du Colombier old9p(int fd)
4969a747e4fSDavid du Colombier {
4979a747e4fSDavid du Colombier 	int p[2];
4989a747e4fSDavid du Colombier 
4999a747e4fSDavid du Colombier 	if(pipe(p) < 0)
5009a747e4fSDavid du Colombier 		return -1;
5019a747e4fSDavid du Colombier 
5029a747e4fSDavid du Colombier 	switch(rfork(RFPROC|RFFDG|RFNAMEG)) {
5039a747e4fSDavid du Colombier 	case -1:
5049a747e4fSDavid du Colombier 		return -1;
5059a747e4fSDavid du Colombier 	case 0:
5069a747e4fSDavid du Colombier 		if(fd != 1){
5079a747e4fSDavid du Colombier 			dup(fd, 1);
5089a747e4fSDavid du Colombier 			close(fd);
5099a747e4fSDavid du Colombier 		}
5109a747e4fSDavid du Colombier 		if(p[0] != 0){
5119a747e4fSDavid du Colombier 			dup(p[0], 0);
5129a747e4fSDavid du Colombier 			close(p[0]);
5139a747e4fSDavid du Colombier 		}
5149a747e4fSDavid du Colombier 		close(p[1]);
5159a747e4fSDavid du Colombier 		if(0){
5169a747e4fSDavid du Colombier 			fd = open("/sys/log/cpu", OWRITE);
5179a747e4fSDavid du Colombier 			if(fd != 2){
5189a747e4fSDavid du Colombier 				dup(fd, 2);
5199a747e4fSDavid du Colombier 				close(fd);
5209a747e4fSDavid du Colombier 			}
5219a747e4fSDavid du Colombier 			execl("/bin/srvold9p", "srvold9p", "-ds", 0);
5229a747e4fSDavid du Colombier 		} else
5239a747e4fSDavid du Colombier 			execl("/bin/srvold9p", "srvold9p", "-s", 0);
5249a747e4fSDavid du Colombier 		return -1;
5259a747e4fSDavid du Colombier 	default:
5269a747e4fSDavid du Colombier 		close(fd);
5279a747e4fSDavid du Colombier 		close(p[0]);
5289a747e4fSDavid du Colombier 	}
5299a747e4fSDavid du Colombier 	return p[1];
5309a747e4fSDavid du Colombier }
5319a747e4fSDavid du Colombier 
5329a747e4fSDavid du Colombier 
5337dd7cddfSDavid du Colombier /*
5347dd7cddfSDavid du Colombier  * exportfs
5357dd7cddfSDavid du Colombier  */
5367dd7cddfSDavid du Colombier int
5377dd7cddfSDavid du Colombier connectexportfs(char *addr)
5387dd7cddfSDavid du Colombier {
5399a747e4fSDavid du Colombier 	char buf[ERRMAX], dir[256], *na;
5407dd7cddfSDavid du Colombier 	int fd, n;
5417dd7cddfSDavid du Colombier 	char *tree;
5429a747e4fSDavid du Colombier 	AuthInfo *ai;
5437dd7cddfSDavid du Colombier 
5447dd7cddfSDavid du Colombier 	tree = "/";
5457dd7cddfSDavid du Colombier 	na = netmkaddr(addr, 0, "exportfs");
5467dd7cddfSDavid du Colombier 	if((fd = dial(na, 0, dir, 0)) < 0)
5477dd7cddfSDavid du Colombier 		return -1;
5487dd7cddfSDavid du Colombier 
5499a747e4fSDavid du Colombier 	ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client");
5509a747e4fSDavid du Colombier 	if(ai == nil)
5517dd7cddfSDavid du Colombier 		return -1;
5527dd7cddfSDavid du Colombier 
5537dd7cddfSDavid du Colombier 	n = write(fd, tree, strlen(tree));
5547dd7cddfSDavid du Colombier 	if(n < 0){
5557dd7cddfSDavid du Colombier 		close(fd);
5567dd7cddfSDavid du Colombier 		return -1;
5577dd7cddfSDavid du Colombier 	}
5587dd7cddfSDavid du Colombier 
5597dd7cddfSDavid du Colombier 	strcpy(buf, "can't read tree");
5607dd7cddfSDavid du Colombier 	n = read(fd, buf, sizeof buf - 1);
5617dd7cddfSDavid du Colombier 	if(n!=2 || buf[0]!='O' || buf[1]!='K'){
5627dd7cddfSDavid du Colombier 		buf[sizeof buf - 1] = '\0';
5637dd7cddfSDavid du Colombier 		werrstr("bad remote tree: %s\n", buf);
5647dd7cddfSDavid du Colombier 		close(fd);
5657dd7cddfSDavid du Colombier 		return -1;
5667dd7cddfSDavid du Colombier 	}
5677dd7cddfSDavid du Colombier 
5689a747e4fSDavid du Colombier //	if(strstr(dir, "tcp"))
5699a747e4fSDavid du Colombier //		fd = filter(fd);
5709a747e4fSDavid du Colombier 
5719a747e4fSDavid du Colombier 	if(oldsystem)
5729a747e4fSDavid du Colombier 		return old9p(fd);
5737dd7cddfSDavid du Colombier 
5747dd7cddfSDavid du Colombier 	return fd;
5757dd7cddfSDavid du Colombier }
5767dd7cddfSDavid du Colombier 
5777dd7cddfSDavid du Colombier void
5787dd7cddfSDavid du Colombier initmach(Machine *m, char *name)
5797dd7cddfSDavid du Colombier {
5807dd7cddfSDavid du Colombier 	int n, fd;
581*f86ef3ceSDavid du Colombier 	ulong a[MAXNUM];
5827dd7cddfSDavid du Colombier 	char *p, mpt[256], buf[256];
5837dd7cddfSDavid du Colombier 
5847dd7cddfSDavid du Colombier 	p = strchr(name, '!');
5857dd7cddfSDavid du Colombier 	if(p){
5867dd7cddfSDavid du Colombier 		p++;
5877dd7cddfSDavid du Colombier 		m->name = estrdup(p+1);
5887dd7cddfSDavid du Colombier 	}else
5897dd7cddfSDavid du Colombier 		p = name;
5907dd7cddfSDavid du Colombier 	m->name = estrdup(p);
5917dd7cddfSDavid du Colombier 	m->remote = (strcmp(p, mysysname) != 0);
5927dd7cddfSDavid du Colombier 	if(m->remote == 0)
5937dd7cddfSDavid du Colombier 		strcpy(mpt, "");
5947dd7cddfSDavid du Colombier 	else{
5957dd7cddfSDavid du Colombier 		snprint(mpt, sizeof mpt, "/n/%s", p);
5967dd7cddfSDavid du Colombier 		fd = connectexportfs(name);
5977dd7cddfSDavid du Colombier 		if(fd < 0){
5987dd7cddfSDavid du Colombier 			fprint(2, "can't connect to %s: %r\n", name);
5997dd7cddfSDavid du Colombier 			killall("connect");
6007dd7cddfSDavid du Colombier 		}
6019a747e4fSDavid du Colombier 		/* BUG? need to use amount() now? */
6029a747e4fSDavid du Colombier 		if(mount(fd, -1, mpt, MREPL, "") < 0){
6037dd7cddfSDavid du Colombier 			fprint(2, "stats: mount %s on %s failed (%r); trying /n/sid\n", name, mpt);
6047dd7cddfSDavid du Colombier 			strcpy(mpt, "/n/sid");
6059a747e4fSDavid du Colombier 			if(mount(fd, -1, mpt, MREPL, "") < 0){
6067dd7cddfSDavid du Colombier 				fprint(2, "stats: mount %s on %s failed: %r\n", name, mpt);
6077dd7cddfSDavid du Colombier 				killall("mount");
6087dd7cddfSDavid du Colombier 			}
6097dd7cddfSDavid du Colombier 		}
6107dd7cddfSDavid du Colombier 	}
6117dd7cddfSDavid du Colombier 
6127dd7cddfSDavid du Colombier 	snprint(buf, sizeof buf, "%s/dev/swap", mpt);
6137dd7cddfSDavid du Colombier 	m->swapfd = open(buf, OREAD);
6147dd7cddfSDavid du Colombier 	if(loadbuf(m, &m->swapfd) && readnums(m, nelem(m->devswap), a, 0))
6157dd7cddfSDavid du Colombier 		memmove(m->devswap, a, sizeof m->devswap);
6167dd7cddfSDavid du Colombier 	else
6177dd7cddfSDavid du Colombier 		m->devswap[Maxmem] = m->devswap[Maxswap] = 100;
6187dd7cddfSDavid du Colombier 
6197dd7cddfSDavid du Colombier 	snprint(buf, sizeof buf, "%s/dev/sysstat", mpt);
6207dd7cddfSDavid du Colombier 	m->statsfd = open(buf, OREAD);
6217dd7cddfSDavid du Colombier 	if(loadbuf(m, &m->statsfd)){
6227dd7cddfSDavid du Colombier 		for(n=0; readnums(m, nelem(m->devsysstat), a, 0); n++)
6237dd7cddfSDavid du Colombier 			;
6247dd7cddfSDavid du Colombier 		m->nproc = n;
6257dd7cddfSDavid du Colombier 	}else
6267dd7cddfSDavid du Colombier 		m->nproc = 1;
6277dd7cddfSDavid du Colombier 
6287dd7cddfSDavid du Colombier 	snprint(buf, sizeof buf, "%s/net/ether0/0/stats", mpt);
6297dd7cddfSDavid du Colombier 	m->etherfd = open(buf, OREAD);
6307dd7cddfSDavid du Colombier 	if(loadbuf(m, &m->etherfd) && readnums(m, nelem(m->netetherstats), a, 1))
6317dd7cddfSDavid du Colombier 		memmove(m->netetherstats, a, sizeof m->netetherstats);
63280ee5cbfSDavid du Colombier 
6339a747e4fSDavid du Colombier 	snprint(buf, sizeof buf, "%s/net/ether0/0/ifstats", mpt);
6349a747e4fSDavid du Colombier 	m->ifstatsfd = open(buf, OREAD);
6359a747e4fSDavid du Colombier 	if(loadbuf(m, &m->ifstatsfd)){
6369a747e4fSDavid du Colombier 		/* need to check that this is a wavelan interface */
6379a747e4fSDavid du Colombier 		if(strncmp(m->buf, "Signal: ", 8) == 0 && readnums(m, nelem(m->netetherifstats), a, 1))
6389a747e4fSDavid du Colombier 			memmove(m->netetherifstats, a, sizeof m->netetherifstats);
6399a747e4fSDavid du Colombier 	}
6409a747e4fSDavid du Colombier 
64180ee5cbfSDavid du Colombier 	snprint(buf, sizeof buf, "%s/mnt/apm/battery", mpt);
64280ee5cbfSDavid du Colombier 	m->batteryfd = open(buf, OREAD);
6439a747e4fSDavid du Colombier 	m->bitsybatfd = -1;
6449a747e4fSDavid du Colombier 	if(m->batteryfd >= 0){
64580ee5cbfSDavid du Colombier 		if(loadbuf(m, &m->batteryfd) && readnums(m, nelem(m->batterystats), a, 0))
64680ee5cbfSDavid du Colombier 			memmove(m->batterystats, a, sizeof(m->batterystats));
6479a747e4fSDavid du Colombier 	}else{
6489a747e4fSDavid du Colombier 		snprint(buf, sizeof buf, "%s/dev/battery", mpt);
6499a747e4fSDavid du Colombier 		m->bitsybatfd = open(buf, OREAD);
6509a747e4fSDavid du Colombier 		if(loadbuf(m, &m->bitsybatfd) && readnums(m, 1, a, 0))
6519a747e4fSDavid du Colombier 			memmove(m->batterystats, a, sizeof(m->batterystats));
6529a747e4fSDavid du Colombier 	}
6537dd7cddfSDavid du Colombier }
6547dd7cddfSDavid du Colombier 
6557dd7cddfSDavid du Colombier jmp_buf catchalarm;
6567dd7cddfSDavid du Colombier 
6577dd7cddfSDavid du Colombier void
6587dd7cddfSDavid du Colombier alarmed(void *a, char *s)
6597dd7cddfSDavid du Colombier {
6607dd7cddfSDavid du Colombier 	if(strcmp(s, "alarm") == 0)
6617dd7cddfSDavid du Colombier 		notejmp(a, catchalarm, 1);
6623e12c5d1SDavid du Colombier 	noted(NDFLT);
6633e12c5d1SDavid du Colombier }
6647dd7cddfSDavid du Colombier 
6657dd7cddfSDavid du Colombier int
6667dd7cddfSDavid du Colombier needswap(int init)
6677dd7cddfSDavid du Colombier {
6687dd7cddfSDavid du Colombier 	return init | present[Mmem] | present[Mswap];
6697dd7cddfSDavid du Colombier }
6707dd7cddfSDavid du Colombier 
6717dd7cddfSDavid du Colombier 
6727dd7cddfSDavid du Colombier int
6737dd7cddfSDavid du Colombier needstat(int init)
6747dd7cddfSDavid du Colombier {
675dc5a79c1SDavid du Colombier 	return init | present[Mcontext]  | present[Mfault] | present[Mintr] | present[Mload] | present[Midle] |
676*f86ef3ceSDavid du Colombier 		present[Minintr] | present[Msyscall] | present[Mtlbmiss] | present[Mtlbpurge];
6777dd7cddfSDavid du Colombier }
6787dd7cddfSDavid du Colombier 
6797dd7cddfSDavid du Colombier 
6807dd7cddfSDavid du Colombier int
6817dd7cddfSDavid du Colombier needether(int init)
6827dd7cddfSDavid du Colombier {
6837dd7cddfSDavid du Colombier 	return init | present[Mether] | present[Metherin] | present[Metherout] | present[Methererr];
6847dd7cddfSDavid du Colombier }
6857dd7cddfSDavid du Colombier 
68680ee5cbfSDavid du Colombier int
68780ee5cbfSDavid du Colombier needbattery(int init)
68880ee5cbfSDavid du Colombier {
68980ee5cbfSDavid du Colombier 	return init | present[Mbattery];
69080ee5cbfSDavid du Colombier }
69180ee5cbfSDavid du Colombier 
6929a747e4fSDavid du Colombier int
6939a747e4fSDavid du Colombier needsignal(int init)
6949a747e4fSDavid du Colombier {
6959a747e4fSDavid du Colombier 	return init | present[Msignal];
6969a747e4fSDavid du Colombier }
6979a747e4fSDavid du Colombier 
6987dd7cddfSDavid du Colombier void
6997dd7cddfSDavid du Colombier readmach(Machine *m, int init)
7007dd7cddfSDavid du Colombier {
7017dd7cddfSDavid du Colombier 	int n, i;
702*f86ef3ceSDavid du Colombier 	ulong a[8];
7037dd7cddfSDavid du Colombier 	char buf[32];
7047dd7cddfSDavid du Colombier 
7057dd7cddfSDavid du Colombier 	if(m->remote && (m->disable || setjmp(catchalarm))){
7067dd7cddfSDavid du Colombier 		if(m->disable == 0){
7077dd7cddfSDavid du Colombier 			snprint(buf, sizeof buf, "%s(dead)", m->name);
7087dd7cddfSDavid du Colombier 			m->name = estrdup(buf);
7097dd7cddfSDavid du Colombier 			if(display != nil)	/* else we're still initializing */
7107dd7cddfSDavid du Colombier 				eresized(0);
7117dd7cddfSDavid du Colombier 		}
7127dd7cddfSDavid du Colombier 		m->disable = 1;
7137dd7cddfSDavid du Colombier 		memmove(m->devsysstat, m->prevsysstat, sizeof m->devsysstat);
7147dd7cddfSDavid du Colombier 		memmove(m->netetherstats, m->prevetherstats, sizeof m->netetherstats);
7157dd7cddfSDavid du Colombier 		return;
7167dd7cddfSDavid du Colombier 	}
7177dd7cddfSDavid du Colombier 	if(m->remote){
7187dd7cddfSDavid du Colombier 		notify(alarmed);
7197dd7cddfSDavid du Colombier 		alarm(5000);
7207dd7cddfSDavid du Colombier 	}
7217dd7cddfSDavid du Colombier 	if(needswap(init) && loadbuf(m, &m->swapfd) && readnums(m, nelem(m->devswap), a, 0))
7227dd7cddfSDavid du Colombier 		memmove(m->devswap, a, sizeof m->devswap);
7237dd7cddfSDavid du Colombier 	if(needstat(init) && loadbuf(m, &m->statsfd)){
7247dd7cddfSDavid du Colombier 		memmove(m->prevsysstat, m->devsysstat, sizeof m->devsysstat);
7257dd7cddfSDavid du Colombier 		memset(m->devsysstat, 0, sizeof m->devsysstat);
7267dd7cddfSDavid du Colombier 		for(n=0; n<m->nproc && readnums(m, nelem(m->devsysstat), a, 0); n++)
7277dd7cddfSDavid du Colombier 			for(i=0; i<nelem(m->devsysstat); i++)
7287dd7cddfSDavid du Colombier 				m->devsysstat[i] += a[i];
7297dd7cddfSDavid du Colombier 	}
7307dd7cddfSDavid du Colombier 	if(needether(init) && loadbuf(m, &m->etherfd) && readnums(m, nelem(m->netetherstats), a, 1)){
7317dd7cddfSDavid du Colombier 		memmove(m->prevetherstats, m->netetherstats, sizeof m->netetherstats);
7327dd7cddfSDavid du Colombier 		memmove(m->netetherstats, a, sizeof m->netetherstats);
7337dd7cddfSDavid du Colombier 	}
7349a747e4fSDavid du Colombier 	if(needsignal(init) && loadbuf(m, &m->ifstatsfd) && strncmp(m->buf, "Signal: ", 8)==0 && readnums(m, nelem(m->netetherifstats), a, 1)){
7359a747e4fSDavid du Colombier 		memmove(m->netetherifstats, a, sizeof m->netetherifstats);
7369a747e4fSDavid du Colombier 	}
73780ee5cbfSDavid du Colombier 	if(needbattery(init) && loadbuf(m, &m->batteryfd) && readnums(m, nelem(m->batterystats), a, 0))
73880ee5cbfSDavid du Colombier 		memmove(m->batterystats, a, sizeof(m->batterystats));
7399a747e4fSDavid du Colombier 	if(needbattery(init) && loadbuf(m, &m->bitsybatfd) && readnums(m, 1, a, 0))
7409a747e4fSDavid du Colombier 		memmove(m->batterystats, a, sizeof(m->batterystats));
74180ee5cbfSDavid du Colombier 
7427dd7cddfSDavid du Colombier 	if(m->remote){
7437dd7cddfSDavid du Colombier 		alarm(0);
7447dd7cddfSDavid du Colombier 		notify(nil);
7457dd7cddfSDavid du Colombier 	}
7467dd7cddfSDavid du Colombier }
7477dd7cddfSDavid du Colombier 
7487dd7cddfSDavid du Colombier void
749*f86ef3ceSDavid du Colombier memval(Machine *m, ulong *v, ulong *vmax, int)
7507dd7cddfSDavid du Colombier {
7517dd7cddfSDavid du Colombier 	*v = m->devswap[Mem];
7527dd7cddfSDavid du Colombier 	*vmax = m->devswap[Maxmem];
7537dd7cddfSDavid du Colombier }
7547dd7cddfSDavid du Colombier 
7557dd7cddfSDavid du Colombier void
756*f86ef3ceSDavid du Colombier swapval(Machine *m, ulong *v, ulong *vmax, int)
7577dd7cddfSDavid du Colombier {
7587dd7cddfSDavid du Colombier 	*v = m->devswap[Swap];
7597dd7cddfSDavid du Colombier 	*vmax = m->devswap[Maxswap];
7607dd7cddfSDavid du Colombier }
7617dd7cddfSDavid du Colombier 
7627dd7cddfSDavid du Colombier void
763*f86ef3ceSDavid du Colombier contextval(Machine *m, ulong *v, ulong *vmax, int init)
7647dd7cddfSDavid du Colombier {
7657dd7cddfSDavid du Colombier 	*v = m->devsysstat[Context]-m->prevsysstat[Context];
7667dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
76780ee5cbfSDavid du Colombier 	if(init)
76880ee5cbfSDavid du Colombier 		*vmax = 1000;
7697dd7cddfSDavid du Colombier }
7707dd7cddfSDavid du Colombier 
7717dd7cddfSDavid du Colombier void
772*f86ef3ceSDavid du Colombier intrval(Machine *m, ulong *v, ulong *vmax, int init)
7737dd7cddfSDavid du Colombier {
7747dd7cddfSDavid du Colombier 	*v = m->devsysstat[Interrupt]-m->prevsysstat[Interrupt];
7757dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
77680ee5cbfSDavid du Colombier 	if(init)
77780ee5cbfSDavid du Colombier 		*vmax = 1000;
7787dd7cddfSDavid du Colombier }
7797dd7cddfSDavid du Colombier 
7807dd7cddfSDavid du Colombier void
781*f86ef3ceSDavid du Colombier syscallval(Machine *m, ulong *v, ulong *vmax, int init)
7827dd7cddfSDavid du Colombier {
7837dd7cddfSDavid du Colombier 	*v = m->devsysstat[Syscall]-m->prevsysstat[Syscall];
7847dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
78580ee5cbfSDavid du Colombier 	if(init)
78680ee5cbfSDavid du Colombier 		*vmax = 1000;
7877dd7cddfSDavid du Colombier }
7887dd7cddfSDavid du Colombier 
7897dd7cddfSDavid du Colombier void
790*f86ef3ceSDavid du Colombier faultval(Machine *m, ulong *v, ulong *vmax, int init)
7917dd7cddfSDavid du Colombier {
7927dd7cddfSDavid du Colombier 	*v = m->devsysstat[Fault]-m->prevsysstat[Fault];
7937dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
79480ee5cbfSDavid du Colombier 	if(init)
79580ee5cbfSDavid du Colombier 		*vmax = 1000;
7967dd7cddfSDavid du Colombier }
7977dd7cddfSDavid du Colombier 
7987dd7cddfSDavid du Colombier void
799*f86ef3ceSDavid du Colombier tlbmissval(Machine *m, ulong *v, ulong *vmax, int init)
8007dd7cddfSDavid du Colombier {
8017dd7cddfSDavid du Colombier 	*v = m->devsysstat[TLBfault]-m->prevsysstat[TLBfault];
8027dd7cddfSDavid du Colombier 	*vmax = 10*m->nproc;
80380ee5cbfSDavid du Colombier 	if(init)
80480ee5cbfSDavid du Colombier 		*vmax = 10;
8057dd7cddfSDavid du Colombier }
8067dd7cddfSDavid du Colombier 
8077dd7cddfSDavid du Colombier void
808*f86ef3ceSDavid du Colombier tlbpurgeval(Machine *m, ulong *v, ulong *vmax, int init)
8097dd7cddfSDavid du Colombier {
8107dd7cddfSDavid du Colombier 	*v = m->devsysstat[TLBpurge]-m->prevsysstat[TLBpurge];
8117dd7cddfSDavid du Colombier 	*vmax = 10*m->nproc;
81280ee5cbfSDavid du Colombier 	if(init)
81380ee5cbfSDavid du Colombier 		*vmax = 10;
8147dd7cddfSDavid du Colombier }
8157dd7cddfSDavid du Colombier 
8167dd7cddfSDavid du Colombier void
817*f86ef3ceSDavid du Colombier loadval(Machine *m, ulong *v, ulong *vmax, int init)
8187dd7cddfSDavid du Colombier {
8197dd7cddfSDavid du Colombier 	*v = m->devsysstat[Load];
8207dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
82180ee5cbfSDavid du Colombier 	if(init)
82280ee5cbfSDavid du Colombier 		*vmax = 1000;
8237dd7cddfSDavid du Colombier }
8247dd7cddfSDavid du Colombier 
8257dd7cddfSDavid du Colombier void
826*f86ef3ceSDavid du Colombier idleval(Machine *m, ulong *v, ulong *vmax, int)
827dc5a79c1SDavid du Colombier {
828*f86ef3ceSDavid du Colombier 	*v = m->devsysstat[Idle]/m->nproc;
829dc5a79c1SDavid du Colombier 	*vmax = 100;
830dc5a79c1SDavid du Colombier }
831dc5a79c1SDavid du Colombier 
832dc5a79c1SDavid du Colombier void
833*f86ef3ceSDavid du Colombier inintrval(Machine *m, ulong *v, ulong *vmax, int)
834*f86ef3ceSDavid du Colombier {
835*f86ef3ceSDavid du Colombier 	*v = m->devsysstat[InIntr]/m->nproc;
836*f86ef3ceSDavid du Colombier 	*vmax = 100;
837*f86ef3ceSDavid du Colombier }
838*f86ef3ceSDavid du Colombier 
839*f86ef3ceSDavid du Colombier void
840*f86ef3ceSDavid du Colombier etherval(Machine *m, ulong *v, ulong *vmax, int init)
8417dd7cddfSDavid du Colombier {
8427dd7cddfSDavid du Colombier 	*v = m->netetherstats[In]-m->prevetherstats[In] + m->netetherstats[Out]-m->prevetherstats[Out];
8437dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
84480ee5cbfSDavid du Colombier 	if(init)
84580ee5cbfSDavid du Colombier 		*vmax = 1000;
8467dd7cddfSDavid du Colombier }
8477dd7cddfSDavid du Colombier 
8487dd7cddfSDavid du Colombier void
849*f86ef3ceSDavid du Colombier etherinval(Machine *m, ulong *v, ulong *vmax, int init)
8507dd7cddfSDavid du Colombier {
8517dd7cddfSDavid du Colombier 	*v = m->netetherstats[In]-m->prevetherstats[In];
8527dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
85380ee5cbfSDavid du Colombier 	if(init)
85480ee5cbfSDavid du Colombier 		*vmax = 1000;
8557dd7cddfSDavid du Colombier }
8567dd7cddfSDavid du Colombier 
8577dd7cddfSDavid du Colombier void
858*f86ef3ceSDavid du Colombier etheroutval(Machine *m, ulong *v, ulong *vmax, int init)
8597dd7cddfSDavid du Colombier {
8607dd7cddfSDavid du Colombier 	*v = m->netetherstats[Out]-m->prevetherstats[Out];
8617dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
86280ee5cbfSDavid du Colombier 	if(init)
86380ee5cbfSDavid du Colombier 		*vmax = 1000;
8647dd7cddfSDavid du Colombier }
8657dd7cddfSDavid du Colombier 
8667dd7cddfSDavid du Colombier void
867*f86ef3ceSDavid du Colombier ethererrval(Machine *m, ulong *v, ulong *vmax, int init)
8687dd7cddfSDavid du Colombier {
8697dd7cddfSDavid du Colombier 	int i;
8707dd7cddfSDavid du Colombier 
8717dd7cddfSDavid du Colombier 	*v = 0;
8727dd7cddfSDavid du Colombier 	for(i=Err0; i<nelem(m->netetherstats); i++)
8737dd7cddfSDavid du Colombier 		*v += m->netetherstats[i];
8747dd7cddfSDavid du Colombier 	*vmax = 10*m->nproc;
87580ee5cbfSDavid du Colombier 	if(init)
87680ee5cbfSDavid du Colombier 		*vmax = 10;
87780ee5cbfSDavid du Colombier }
87880ee5cbfSDavid du Colombier 
87980ee5cbfSDavid du Colombier void
880*f86ef3ceSDavid du Colombier batteryval(Machine *m, ulong *v, ulong *vmax, int)
88180ee5cbfSDavid du Colombier {
88280ee5cbfSDavid du Colombier 	*v = m->batterystats[0];
8839a747e4fSDavid du Colombier 	if(m->bitsybatfd >= 0)
8849a747e4fSDavid du Colombier 		*vmax = 184;		// at least on my bitsy...
8859a747e4fSDavid du Colombier 	else
88680ee5cbfSDavid du Colombier 		*vmax = 100;
8877dd7cddfSDavid du Colombier }
8887dd7cddfSDavid du Colombier 
8897dd7cddfSDavid du Colombier void
890*f86ef3ceSDavid du Colombier signalval(Machine *m, ulong *v, ulong *vmax, int)
8919a747e4fSDavid du Colombier {
892*f86ef3ceSDavid du Colombier 	ulong l;
8939a747e4fSDavid du Colombier 
8949a747e4fSDavid du Colombier 	*vmax = 1000;
8959a747e4fSDavid du Colombier 	l = m->netetherifstats[0];
8969a747e4fSDavid du Colombier 	/*
8979a747e4fSDavid du Colombier 	 * Range is seen to be from about -45 (strong) to -95 (weak); rescale
8989a747e4fSDavid du Colombier 	 */
8999a747e4fSDavid du Colombier 	if(l == 0){	/* probably not present */
9009a747e4fSDavid du Colombier 		*v = 0;
9019a747e4fSDavid du Colombier 		return;
9029a747e4fSDavid du Colombier 	}
9039a747e4fSDavid du Colombier 	*v = 20*(l+95);
9049a747e4fSDavid du Colombier }
9059a747e4fSDavid du Colombier 
9069a747e4fSDavid du Colombier void
9077dd7cddfSDavid du Colombier usage(void)
9087dd7cddfSDavid du Colombier {
9099a747e4fSDavid du Colombier 	fprint(2, "usage: stats [-O] [-S scale] [-LY] [-%s] [machine...]\n", argchars);
9107dd7cddfSDavid du Colombier 	exits("usage");
9117dd7cddfSDavid du Colombier }
9127dd7cddfSDavid du Colombier 
9137dd7cddfSDavid du Colombier void
9147dd7cddfSDavid du Colombier addgraph(int n)
9157dd7cddfSDavid du Colombier {
9167dd7cddfSDavid du Colombier 	Graph *g, *ograph;
9177dd7cddfSDavid du Colombier 	int i, j;
9187dd7cddfSDavid du Colombier 	static int nadd;
9197dd7cddfSDavid du Colombier 
9207dd7cddfSDavid du Colombier 	if(n > nelem(menu2str))
9217dd7cddfSDavid du Colombier 		abort();
9227dd7cddfSDavid du Colombier 	/* avoid two adjacent graphs of same color */
9237dd7cddfSDavid du Colombier 	if(ngraph>0 && graph[ngraph-1].colindex==nadd%Ncolor)
9247dd7cddfSDavid du Colombier 		nadd++;
9257dd7cddfSDavid du Colombier 	ograph = graph;
9267dd7cddfSDavid du Colombier 	graph = emalloc(nmach*(ngraph+1)*sizeof(Graph));
9277dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++)
9287dd7cddfSDavid du Colombier 		for(j=0; j<ngraph; j++)
9297dd7cddfSDavid du Colombier 			graph[i*(ngraph+1)+j] = ograph[i*ngraph+j];
9307dd7cddfSDavid du Colombier 	free(ograph);
9317dd7cddfSDavid du Colombier 	ngraph++;
9327dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++){
9337dd7cddfSDavid du Colombier 		g = &graph[i*ngraph+(ngraph-1)];
9347dd7cddfSDavid du Colombier 		memset(g, 0, sizeof(Graph));
9357dd7cddfSDavid du Colombier 		g->label = menu2str[n]+Opwid;
9367dd7cddfSDavid du Colombier 		g->newvalue = newvaluefn[n];
9377dd7cddfSDavid du Colombier 		g->update = update1;	/* no other update functions yet */
9387dd7cddfSDavid du Colombier 		g->mach = &mach[i];
9397dd7cddfSDavid du Colombier 		g->colindex = nadd%Ncolor;
9407dd7cddfSDavid du Colombier 	}
9417dd7cddfSDavid du Colombier 	present[n] = 1;
9427dd7cddfSDavid du Colombier 	nadd++;
9437dd7cddfSDavid du Colombier }
9447dd7cddfSDavid du Colombier 
9457dd7cddfSDavid du Colombier void
9467dd7cddfSDavid du Colombier dropgraph(int which)
9477dd7cddfSDavid du Colombier {
9487dd7cddfSDavid du Colombier 	Graph *ograph;
9497dd7cddfSDavid du Colombier 	int i, j, n;
9507dd7cddfSDavid du Colombier 
9517dd7cddfSDavid du Colombier 	if(which > nelem(menu2str))
9527dd7cddfSDavid du Colombier 		abort();
9537dd7cddfSDavid du Colombier 	/* convert n to index in graph table */
9547dd7cddfSDavid du Colombier 	n = -1;
9557dd7cddfSDavid du Colombier 	for(i=0; i<ngraph; i++)
9567dd7cddfSDavid du Colombier 		if(strcmp(menu2str[which]+Opwid, graph[i].label) == 0){
9577dd7cddfSDavid du Colombier 			n = i;
9587dd7cddfSDavid du Colombier 			break;
9597dd7cddfSDavid du Colombier 		}
9607dd7cddfSDavid du Colombier 	if(n < 0){
9617dd7cddfSDavid du Colombier 		fprint(2, "stats: internal error can't drop graph\n");
9627dd7cddfSDavid du Colombier 		killall("error");
9637dd7cddfSDavid du Colombier 	}
9647dd7cddfSDavid du Colombier 	ograph = graph;
9657dd7cddfSDavid du Colombier 	graph = emalloc(nmach*(ngraph-1)*sizeof(Graph));
9667dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++){
9677dd7cddfSDavid du Colombier 		for(j=0; j<n; j++)
9687dd7cddfSDavid du Colombier 			graph[i*(ngraph-1)+j] = ograph[i*ngraph+j];
9697dd7cddfSDavid du Colombier 		free(ograph[i*ngraph+j].data);
9707dd7cddfSDavid du Colombier 		freeimage(ograph[i*ngraph+j].overtmp);
9717dd7cddfSDavid du Colombier 		for(j++; j<ngraph; j++)
9727dd7cddfSDavid du Colombier 			graph[i*(ngraph-1)+j-1] = ograph[i*ngraph+j];
9737dd7cddfSDavid du Colombier 	}
9747dd7cddfSDavid du Colombier 	free(ograph);
9757dd7cddfSDavid du Colombier 	ngraph--;
9767dd7cddfSDavid du Colombier 	present[which] = 0;
9777dd7cddfSDavid du Colombier }
9787dd7cddfSDavid du Colombier 
9797dd7cddfSDavid du Colombier void
9807dd7cddfSDavid du Colombier addmachine(char *name)
9817dd7cddfSDavid du Colombier {
9827dd7cddfSDavid du Colombier 	if(ngraph > 0){
9837dd7cddfSDavid du Colombier 		fprint(2, "stats: internal error: ngraph>0 in addmachine()\n");
9847dd7cddfSDavid du Colombier 		usage();
9857dd7cddfSDavid du Colombier 	}
9867dd7cddfSDavid du Colombier 	if(mach == nil)
9877dd7cddfSDavid du Colombier 		nmach = 0;	/* a little dance to get us started with local machine by default */
9887dd7cddfSDavid du Colombier 	mach = erealloc(mach, (nmach+1)*sizeof(Machine));
9897dd7cddfSDavid du Colombier 	memset(mach+nmach, 0, sizeof(Machine));
9907dd7cddfSDavid du Colombier 	initmach(mach+nmach, name);
9917dd7cddfSDavid du Colombier 	nmach++;
9927dd7cddfSDavid du Colombier }
9937dd7cddfSDavid du Colombier 
9947dd7cddfSDavid du Colombier void
99580ee5cbfSDavid du Colombier labelstrs(Graph *g, char strs[Nlab][Lablen], int *np)
99680ee5cbfSDavid du Colombier {
99780ee5cbfSDavid du Colombier 	int j;
998*f86ef3ceSDavid du Colombier 	ulong v, vmax;
99980ee5cbfSDavid du Colombier 
100080ee5cbfSDavid du Colombier 	g->newvalue(g->mach, &v, &vmax, 1);
100180ee5cbfSDavid du Colombier 	if(logscale){
100280ee5cbfSDavid du Colombier 		for(j=1; j<=2; j++)
100380ee5cbfSDavid du Colombier 			sprint(strs[j-1], "%g", scale*pow(10., j)*(double)vmax/100.);
100480ee5cbfSDavid du Colombier 		*np = 2;
100580ee5cbfSDavid du Colombier 	}else{
100680ee5cbfSDavid du Colombier 		for(j=1; j<=3; j++)
100780ee5cbfSDavid du Colombier 			sprint(strs[j-1], "%g", scale*(double)j*(double)vmax/4.0);
100880ee5cbfSDavid du Colombier 		*np = 3;
100980ee5cbfSDavid du Colombier 	}
101080ee5cbfSDavid du Colombier }
101180ee5cbfSDavid du Colombier 
101280ee5cbfSDavid du Colombier int
101380ee5cbfSDavid du Colombier labelwidth(void)
101480ee5cbfSDavid du Colombier {
101580ee5cbfSDavid du Colombier 	int i, j, n, w, maxw;
101680ee5cbfSDavid du Colombier 	char strs[Nlab][Lablen];
101780ee5cbfSDavid du Colombier 
101880ee5cbfSDavid du Colombier 	maxw = 0;
101980ee5cbfSDavid du Colombier 	for(i=0; i<ngraph; i++){
102080ee5cbfSDavid du Colombier 		/* choose value for rightmost graph */
102180ee5cbfSDavid du Colombier 		labelstrs(&graph[ngraph*(nmach-1)+i], strs, &n);
102280ee5cbfSDavid du Colombier 		for(j=0; j<n; j++){
102380ee5cbfSDavid du Colombier 			w = stringwidth(mediumfont, strs[j]);
102480ee5cbfSDavid du Colombier 			if(w > maxw)
102580ee5cbfSDavid du Colombier 				maxw = w;
102680ee5cbfSDavid du Colombier 		}
102780ee5cbfSDavid du Colombier 	}
102880ee5cbfSDavid du Colombier 	return maxw;
102980ee5cbfSDavid du Colombier }
103080ee5cbfSDavid du Colombier 
103180ee5cbfSDavid du Colombier void
10327dd7cddfSDavid du Colombier resize(void)
10337dd7cddfSDavid du Colombier {
103480ee5cbfSDavid du Colombier 	int i, j, k, n, startx, starty, x, y, dx, dy, ly, ondata, maxx, wid, nlab;
10357dd7cddfSDavid du Colombier 	Graph *g;
10367dd7cddfSDavid du Colombier 	Rectangle machr, r;
1037*f86ef3ceSDavid du Colombier 	ulong v, vmax;
103880ee5cbfSDavid du Colombier 	char buf[128], labs[Nlab][Lablen];
10397dd7cddfSDavid du Colombier 
10407dd7cddfSDavid du Colombier 	draw(screen, screen->r, display->white, nil, ZP);
10417dd7cddfSDavid du Colombier 
10427dd7cddfSDavid du Colombier 	/* label left edge */
10437dd7cddfSDavid du Colombier 	x = screen->r.min.x;
10447dd7cddfSDavid du Colombier 	y = screen->r.min.y + Labspace+mediumfont->height+Labspace;
10457dd7cddfSDavid du Colombier 	dy = (screen->r.max.y - y)/ngraph;
10467dd7cddfSDavid du Colombier 	dx = Labspace+stringwidth(mediumfont, "0")+Labspace;
10477dd7cddfSDavid du Colombier 	startx = x+dx+1;
10487dd7cddfSDavid du Colombier 	starty = y;
10497dd7cddfSDavid du Colombier 	for(i=0; i<ngraph; i++,y+=dy){
10507dd7cddfSDavid du Colombier 		draw(screen, Rect(x, y-1, screen->r.max.x, y), display->black, nil, ZP);
10517dd7cddfSDavid du Colombier 		draw(screen, Rect(x, y, x+dx, screen->r.max.y), cols[graph[i].colindex][0], nil, paritypt(x));
10527dd7cddfSDavid du Colombier 		label(Pt(x, y), dy, graph[i].label);
10537dd7cddfSDavid du Colombier 		draw(screen, Rect(x+dx, y, x+dx+1, screen->r.max.y), cols[graph[i].colindex][2], nil, ZP);
10547dd7cddfSDavid du Colombier 	}
10557dd7cddfSDavid du Colombier 
10567dd7cddfSDavid du Colombier 	/* label top edge */
10577dd7cddfSDavid du Colombier 	dx = (screen->r.max.x - startx)/nmach;
10587dd7cddfSDavid du Colombier 	for(x=startx, i=0; i<nmach; i++,x+=dx){
10597dd7cddfSDavid du Colombier 		draw(screen, Rect(x-1, starty-1, x, screen->r.max.y), display->black, nil, ZP);
10607dd7cddfSDavid du Colombier 		j = dx/stringwidth(mediumfont, "0");
10617dd7cddfSDavid du Colombier 		n = mach[i].nproc;
10627dd7cddfSDavid du Colombier 		if(n>1 && j>=1+3+(n>10)+(n>100)){	/* first char of name + (n) */
10637dd7cddfSDavid du Colombier 			j -= 3+(n>10)+(n>100);
10647dd7cddfSDavid du Colombier 			if(j <= 0)
10657dd7cddfSDavid du Colombier 				j = 1;
10667dd7cddfSDavid du Colombier 			snprint(buf, sizeof buf, "%.*s(%d)", j, mach[i].name, n);
10677dd7cddfSDavid du Colombier 		}else
10687dd7cddfSDavid du Colombier 			snprint(buf, sizeof buf, "%.*s", j, mach[i].name);
10697dd7cddfSDavid du Colombier 		string(screen, Pt(x+Labspace, screen->r.min.y + Labspace), display->black, ZP, mediumfont, buf);
10707dd7cddfSDavid du Colombier 	}
10717dd7cddfSDavid du Colombier 
107280ee5cbfSDavid du Colombier 	maxx = screen->r.max.x;
107380ee5cbfSDavid du Colombier 
107480ee5cbfSDavid du Colombier 	/* label right, if requested */
107580ee5cbfSDavid du Colombier 	if(ylabels && dy>Nlab*(mediumfont->height+1)){
107680ee5cbfSDavid du Colombier 		wid = labelwidth();
107780ee5cbfSDavid du Colombier 		if(wid < (maxx-startx)-30){
107880ee5cbfSDavid du Colombier 			/* else there's not enough room */
107980ee5cbfSDavid du Colombier 			maxx -= 1+Lx+wid;
108080ee5cbfSDavid du Colombier 			draw(screen, Rect(maxx, starty, maxx+1, screen->r.max.y), display->black, nil, ZP);
108180ee5cbfSDavid du Colombier 			y = starty;
108280ee5cbfSDavid du Colombier 			for(j=0; j<ngraph; j++, y+=dy){
108380ee5cbfSDavid du Colombier 				/* choose value for rightmost graph */
108480ee5cbfSDavid du Colombier 				g = &graph[ngraph*(nmach-1)+j];
108580ee5cbfSDavid du Colombier 				labelstrs(g, labs, &nlab);
108680ee5cbfSDavid du Colombier 				r = Rect(maxx+1, y, screen->r.max.x, y+dy-1);
108780ee5cbfSDavid du Colombier 				if(j == ngraph-1)
108880ee5cbfSDavid du Colombier 					r.max.y = screen->r.max.y;
108980ee5cbfSDavid du Colombier 				draw(screen, r, cols[g->colindex][0], nil, paritypt(r.min.x));
109080ee5cbfSDavid du Colombier 				for(k=0; k<nlab; k++){
109180ee5cbfSDavid du Colombier 					ly = y + (dy*(nlab-k)/(nlab+1));
109280ee5cbfSDavid du Colombier 					draw(screen, Rect(maxx+1, ly, maxx+1+Lx, ly+1), display->black, nil, ZP);
109380ee5cbfSDavid du Colombier 					ly -= mediumfont->height/2;
109480ee5cbfSDavid du Colombier 					string(screen, Pt(maxx+1+Lx, ly), display->black, ZP, mediumfont, labs[k]);
109580ee5cbfSDavid du Colombier 				}
109680ee5cbfSDavid du Colombier 			}
109780ee5cbfSDavid du Colombier 		}
109880ee5cbfSDavid du Colombier 	}
109980ee5cbfSDavid du Colombier 
11007dd7cddfSDavid du Colombier 	/* create graphs */
11017dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++){
110280ee5cbfSDavid du Colombier 		machr = Rect(startx+i*dx, starty, maxx, screen->r.max.y);
11037dd7cddfSDavid du Colombier 		if(i < nmach-1)
11047dd7cddfSDavid du Colombier 			machr.max.x = startx+(i+1)*dx - 1;
11057dd7cddfSDavid du Colombier 		y = starty;
11067dd7cddfSDavid du Colombier 		for(j=0; j<ngraph; j++, y+=dy){
11077dd7cddfSDavid du Colombier 			g = &graph[i*ngraph+j];
11087dd7cddfSDavid du Colombier 			/* allocate data */
11097dd7cddfSDavid du Colombier 			ondata = g->ndata;
11107dd7cddfSDavid du Colombier 			g->ndata = Dx(machr)+1;	/* may be too many if label will be drawn here; so what? */
1111*f86ef3ceSDavid du Colombier 			g->data = erealloc(g->data, g->ndata*sizeof(ulong));
11127dd7cddfSDavid du Colombier 			if(g->ndata > ondata)
1113*f86ef3ceSDavid du Colombier 				memset(g->data+ondata, 0, (g->ndata-ondata)*sizeof(ulong));
11147dd7cddfSDavid du Colombier 			/* set geometry */
11157dd7cddfSDavid du Colombier 			g->r = machr;
11167dd7cddfSDavid du Colombier 			g->r.min.y = y;
11177dd7cddfSDavid du Colombier 			g->r.max.y = y+dy - 1;
11187dd7cddfSDavid du Colombier 			if(j == ngraph-1)
11197dd7cddfSDavid du Colombier 				g->r.max.y = screen->r.max.y;
11207dd7cddfSDavid du Colombier 			draw(screen, g->r, cols[g->colindex][0], nil, paritypt(g->r.min.x));
11217dd7cddfSDavid du Colombier 			g->overflow = 0;
11227dd7cddfSDavid du Colombier 			r = g->r;
11237dd7cddfSDavid du Colombier 			r.max.y = r.min.y+mediumfont->height;
11247dd7cddfSDavid du Colombier 			r.max.x = r.min.x+stringwidth(mediumfont, "9999999");
11257dd7cddfSDavid du Colombier 			freeimage(g->overtmp);
11267dd7cddfSDavid du Colombier 			g->overtmp = nil;
11277dd7cddfSDavid du Colombier 			if(r.max.x <= g->r.max.x)
11287dd7cddfSDavid du Colombier 				g->overtmp = allocimage(display, r, screen->chan, 0, -1);
112980ee5cbfSDavid du Colombier 			g->newvalue(g->mach, &v, &vmax, 0);
11307dd7cddfSDavid du Colombier 			redraw(g, vmax);
11317dd7cddfSDavid du Colombier 		}
11327dd7cddfSDavid du Colombier 	}
11337dd7cddfSDavid du Colombier 
11347dd7cddfSDavid du Colombier 	flushimage(display, 1);
11357dd7cddfSDavid du Colombier }
11367dd7cddfSDavid du Colombier 
11377dd7cddfSDavid du Colombier void
11387dd7cddfSDavid du Colombier eresized(int new)
11397dd7cddfSDavid du Colombier {
11407dd7cddfSDavid du Colombier 	lockdisplay(display);
11417dd7cddfSDavid du Colombier 	if(new && getwindow(display, Refnone) < 0) {
11427dd7cddfSDavid du Colombier 		fprint(2, "stats: can't reattach to window\n");
11437dd7cddfSDavid du Colombier 		killall("reattach");
11447dd7cddfSDavid du Colombier 	}
11457dd7cddfSDavid du Colombier 	resize();
11467dd7cddfSDavid du Colombier 	unlockdisplay(display);
11477dd7cddfSDavid du Colombier }
11487dd7cddfSDavid du Colombier 
11497dd7cddfSDavid du Colombier void
11507dd7cddfSDavid du Colombier mouseproc(void)
11517dd7cddfSDavid du Colombier {
11527dd7cddfSDavid du Colombier 	Mouse mouse;
11537dd7cddfSDavid du Colombier 	int i;
11547dd7cddfSDavid du Colombier 
11557dd7cddfSDavid du Colombier 	for(;;){
11567dd7cddfSDavid du Colombier 		mouse = emouse();
11577dd7cddfSDavid du Colombier 		if(mouse.buttons == 4){
11587dd7cddfSDavid du Colombier 			lockdisplay(display);
11597dd7cddfSDavid du Colombier 			for(i=0; i<Nmenu2; i++)
11607dd7cddfSDavid du Colombier 				if(present[i])
11617dd7cddfSDavid du Colombier 					memmove(menu2str[i], "drop ", Opwid);
11627dd7cddfSDavid du Colombier 				else
11637dd7cddfSDavid du Colombier 					memmove(menu2str[i], "add  ", Opwid);
11647dd7cddfSDavid du Colombier 			i = emenuhit(3, &mouse, &menu2);
11657dd7cddfSDavid du Colombier 			if(i >= 0){
11667dd7cddfSDavid du Colombier 				if(!present[i])
11677dd7cddfSDavid du Colombier 					addgraph(i);
11687dd7cddfSDavid du Colombier 				else if(ngraph > 1)
11697dd7cddfSDavid du Colombier 					dropgraph(i);
11707dd7cddfSDavid du Colombier 				resize();
11717dd7cddfSDavid du Colombier 			}
11727dd7cddfSDavid du Colombier 			unlockdisplay(display);
11737dd7cddfSDavid du Colombier 		}
11747dd7cddfSDavid du Colombier 	}
11757dd7cddfSDavid du Colombier }
11767dd7cddfSDavid du Colombier 
11777dd7cddfSDavid du Colombier void
11787dd7cddfSDavid du Colombier startproc(void (*f)(void), int index)
11797dd7cddfSDavid du Colombier {
11807dd7cddfSDavid du Colombier 	int pid;
11817dd7cddfSDavid du Colombier 
11827dd7cddfSDavid du Colombier 	switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){
11837dd7cddfSDavid du Colombier 	case -1:
11847dd7cddfSDavid du Colombier 		fprint(2, "stats: fork failed: %r\n");
11857dd7cddfSDavid du Colombier 		killall("fork failed");
11867dd7cddfSDavid du Colombier 	case 0:
11877dd7cddfSDavid du Colombier 		f();
11887dd7cddfSDavid du Colombier 		fprint(2, "stats: %s process exits\n", procnames[index]);
11897dd7cddfSDavid du Colombier 		if(index >= 0)
11907dd7cddfSDavid du Colombier 			killall("process died");
11917dd7cddfSDavid du Colombier 		exits(nil);
11927dd7cddfSDavid du Colombier 	}
11937dd7cddfSDavid du Colombier 	if(index >= 0)
11947dd7cddfSDavid du Colombier 		pids[index] = pid;
11957dd7cddfSDavid du Colombier }
11967dd7cddfSDavid du Colombier 
11977dd7cddfSDavid du Colombier void
11987dd7cddfSDavid du Colombier main(int argc, char *argv[])
11997dd7cddfSDavid du Colombier {
12007dd7cddfSDavid du Colombier 	int i, j;
120180ee5cbfSDavid du Colombier 	char *s;
1202*f86ef3ceSDavid du Colombier 	ulong v, vmax, nargs;
12037dd7cddfSDavid du Colombier 	char args[100];
12043f695129SDavid du Colombier 	int sleeptime = 1000;
12057dd7cddfSDavid du Colombier 
12067dd7cddfSDavid du Colombier 	nmach = 1;
12077dd7cddfSDavid du Colombier 	mysysname = getenv("sysname");
12087dd7cddfSDavid du Colombier 	if(mysysname == nil){
12097dd7cddfSDavid du Colombier 		fprint(2, "stats: can't find $sysname: %r\n");
12107dd7cddfSDavid du Colombier 		exits("sysname");
12117dd7cddfSDavid du Colombier 	}
12127dd7cddfSDavid du Colombier 	mysysname = estrdup(mysysname);
12137dd7cddfSDavid du Colombier 
12147dd7cddfSDavid du Colombier 	nargs = 0;
12157dd7cddfSDavid du Colombier 	ARGBEGIN{
12163f695129SDavid du Colombier 	case 'T':
12173f695129SDavid du Colombier 		s = ARGF();
12183f695129SDavid du Colombier 		if(s == nil)
12193f695129SDavid du Colombier 			usage();
12203f695129SDavid du Colombier 		i = atoi(s);
12213f695129SDavid du Colombier 		if(i > 0)
12223f695129SDavid du Colombier 			sleeptime = 1000*i;
12233f695129SDavid du Colombier 		break;
122480ee5cbfSDavid du Colombier 	case 'S':
122580ee5cbfSDavid du Colombier 		s = ARGF();
122680ee5cbfSDavid du Colombier 		if(s == nil)
122780ee5cbfSDavid du Colombier 			usage();
122880ee5cbfSDavid du Colombier 		scale = atof(s);
122980ee5cbfSDavid du Colombier 		if(scale <= 0.)
123080ee5cbfSDavid du Colombier 			usage();
123180ee5cbfSDavid du Colombier 		break;
123280ee5cbfSDavid du Colombier 	case 'L':
123380ee5cbfSDavid du Colombier 		logscale++;
123480ee5cbfSDavid du Colombier 		break;
123580ee5cbfSDavid du Colombier 	case 'Y':
123680ee5cbfSDavid du Colombier 		ylabels++;
123780ee5cbfSDavid du Colombier 		break;
12389a747e4fSDavid du Colombier 	case 'O':
12399a747e4fSDavid du Colombier 		oldsystem = 1;
12409a747e4fSDavid du Colombier 		break;
12417dd7cddfSDavid du Colombier 	default:
12427dd7cddfSDavid du Colombier 		if(nargs>=sizeof args || strchr(argchars, ARGC())==nil)
12437dd7cddfSDavid du Colombier 			usage();
12447dd7cddfSDavid du Colombier 		args[nargs++] = ARGC();
12457dd7cddfSDavid du Colombier 	}ARGEND
12467dd7cddfSDavid du Colombier 
12477dd7cddfSDavid du Colombier 	if(argc == 0){
12487dd7cddfSDavid du Colombier 		mach = emalloc(nmach*sizeof(Machine));
12497dd7cddfSDavid du Colombier 		initmach(&mach[0], mysysname);
12507dd7cddfSDavid du Colombier 		readmach(&mach[0], 1);
12517dd7cddfSDavid du Colombier 	}else{
12527dd7cddfSDavid du Colombier 		for(i=0; i<argc; i++){
12537dd7cddfSDavid du Colombier 			addmachine(argv[i]);
12547dd7cddfSDavid du Colombier 			readmach(&mach[i], 1);
12557dd7cddfSDavid du Colombier 		}
12567dd7cddfSDavid du Colombier 	}
12577dd7cddfSDavid du Colombier 
12587dd7cddfSDavid du Colombier 	for(i=0; i<nargs; i++)
12597dd7cddfSDavid du Colombier 	switch(args[i]){
12607dd7cddfSDavid du Colombier 	default:
12617dd7cddfSDavid du Colombier 		fprint(2, "stats: internal error: unknown arg %c\n", args[i]);
12627dd7cddfSDavid du Colombier 		usage();
126380ee5cbfSDavid du Colombier 	case 'b':
126480ee5cbfSDavid du Colombier 		addgraph(Mbattery);
126580ee5cbfSDavid du Colombier 		break;
12667dd7cddfSDavid du Colombier 	case 'c':
12677dd7cddfSDavid du Colombier 		addgraph(Mcontext);
12687dd7cddfSDavid du Colombier 		break;
12697dd7cddfSDavid du Colombier 	case 'e':
12707dd7cddfSDavid du Colombier 		addgraph(Mether);
12717dd7cddfSDavid du Colombier 		break;
12727dd7cddfSDavid du Colombier 	case 'E':
12737dd7cddfSDavid du Colombier 		addgraph(Metherin);
12747dd7cddfSDavid du Colombier 		addgraph(Metherout);
12757dd7cddfSDavid du Colombier 		break;
12767dd7cddfSDavid du Colombier 	case 'f':
12777dd7cddfSDavid du Colombier 		addgraph(Mfault);
12787dd7cddfSDavid du Colombier 		break;
12797dd7cddfSDavid du Colombier 	case 'i':
12807dd7cddfSDavid du Colombier 		addgraph(Mintr);
12817dd7cddfSDavid du Colombier 		break;
1282*f86ef3ceSDavid du Colombier 	case 'I':
1283*f86ef3ceSDavid du Colombier 		addgraph(Mload);
1284*f86ef3ceSDavid du Colombier 		addgraph(Midle);
1285*f86ef3ceSDavid du Colombier 		addgraph(Minintr);
1286*f86ef3ceSDavid du Colombier 		break;
12877dd7cddfSDavid du Colombier 	case 'l':
12887dd7cddfSDavid du Colombier 		addgraph(Mload);
12897dd7cddfSDavid du Colombier 		break;
12907dd7cddfSDavid du Colombier 	case 'm':
12917dd7cddfSDavid du Colombier 		addgraph(Mmem);
12927dd7cddfSDavid du Colombier 		break;
12937dd7cddfSDavid du Colombier 	case 'n':
12947dd7cddfSDavid du Colombier 		addgraph(Metherin);
12957dd7cddfSDavid du Colombier 		addgraph(Metherout);
12967dd7cddfSDavid du Colombier 		addgraph(Methererr);
12977dd7cddfSDavid du Colombier 		break;
12987dd7cddfSDavid du Colombier 	case 'p':
12997dd7cddfSDavid du Colombier 		addgraph(Mtlbpurge);
13007dd7cddfSDavid du Colombier 		break;
13017dd7cddfSDavid du Colombier 	case 's':
13027dd7cddfSDavid du Colombier 		addgraph(Msyscall);
13037dd7cddfSDavid du Colombier 		break;
13047dd7cddfSDavid du Colombier 	case 't':
13057dd7cddfSDavid du Colombier 		addgraph(Mtlbmiss);
13067dd7cddfSDavid du Colombier 		addgraph(Mtlbpurge);
13077dd7cddfSDavid du Colombier 		break;
13089a747e4fSDavid du Colombier 	case '8':
13099a747e4fSDavid du Colombier 		addgraph(Msignal);
13109a747e4fSDavid du Colombier 		break;
13117dd7cddfSDavid du Colombier 	case 'w':
13127dd7cddfSDavid du Colombier 		addgraph(Mswap);
13137dd7cddfSDavid du Colombier 		break;
13147dd7cddfSDavid du Colombier 	}
13157dd7cddfSDavid du Colombier 
13167dd7cddfSDavid du Colombier 	if(ngraph == 0)
13177dd7cddfSDavid du Colombier 		addgraph(Mload);
13187dd7cddfSDavid du Colombier 
13197dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++)
13207dd7cddfSDavid du Colombier 		for(j=0; j<ngraph; j++)
13217dd7cddfSDavid du Colombier 			graph[i*ngraph+j].mach = &mach[i];
13227dd7cddfSDavid du Colombier 
13237dd7cddfSDavid du Colombier 	if(initdraw(nil, nil, "stats") < 0){
13247dd7cddfSDavid du Colombier 		fprint(2, "stats: initdraw failed: %r\n");
13257dd7cddfSDavid du Colombier 		exits("initdraw");
13267dd7cddfSDavid du Colombier 	}
13277dd7cddfSDavid du Colombier 	colinit();
13287dd7cddfSDavid du Colombier 	einit(Emouse);
13297dd7cddfSDavid du Colombier 	notify(nil);
13307dd7cddfSDavid du Colombier 	startproc(mouseproc, Mouseproc);
13317dd7cddfSDavid du Colombier 	pids[Mainproc] = getpid();
13327dd7cddfSDavid du Colombier 	display->locking = 1;	/* tell library we're using the display lock */
13337dd7cddfSDavid du Colombier 
13347dd7cddfSDavid du Colombier 	resize();
13357dd7cddfSDavid du Colombier 
13367dd7cddfSDavid du Colombier 	unlockdisplay(display); /* display is still locked from initdraw() */
13377dd7cddfSDavid du Colombier 	for(;;){
13387dd7cddfSDavid du Colombier 		for(i=0; i<nmach; i++)
13397dd7cddfSDavid du Colombier 			readmach(&mach[i], 0);
13407dd7cddfSDavid du Colombier 		lockdisplay(display);
13417dd7cddfSDavid du Colombier 		parity = 1-parity;
13427dd7cddfSDavid du Colombier 		for(i=0; i<nmach*ngraph; i++){
134380ee5cbfSDavid du Colombier 			graph[i].newvalue(graph[i].mach, &v, &vmax, 0);
13447dd7cddfSDavid du Colombier 			graph[i].update(&graph[i], v, vmax);
13457dd7cddfSDavid du Colombier 		}
13467dd7cddfSDavid du Colombier 		flushimage(display, 1);
13477dd7cddfSDavid du Colombier 		unlockdisplay(display);
13483f695129SDavid du Colombier 		sleep(sleeptime);
13497dd7cddfSDavid du Colombier 	}
13507dd7cddfSDavid du Colombier }
1351