xref: /plan9/sys/src/cmd/stats.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3*7dd7cddfSDavid du Colombier #include <ctype.h>
4*7dd7cddfSDavid du Colombier #include <auth.h>
5*7dd7cddfSDavid du Colombier #include <fcall.h>
6*7dd7cddfSDavid du Colombier #include <draw.h>
7*7dd7cddfSDavid du Colombier #include <event.h>
83e12c5d1SDavid du Colombier 
9*7dd7cddfSDavid du Colombier #define	MAXNUM	8	/* maximum number of numbers on data line */
103e12c5d1SDavid du Colombier 
11*7dd7cddfSDavid du Colombier typedef struct Graph		Graph;
12*7dd7cddfSDavid du Colombier typedef struct Machine	Machine;
13*7dd7cddfSDavid du Colombier 
14*7dd7cddfSDavid du Colombier struct Graph
15*7dd7cddfSDavid du Colombier {
16*7dd7cddfSDavid du Colombier 	int		colindex;
17*7dd7cddfSDavid du Colombier 	Rectangle	r;
18*7dd7cddfSDavid du Colombier 	int		*data;
19*7dd7cddfSDavid du Colombier 	int		ndata;
20*7dd7cddfSDavid du Colombier 	char		*label;
21*7dd7cddfSDavid du Colombier 	void		(*newvalue)(Machine*, long*, long*);
22*7dd7cddfSDavid du Colombier 	void		(*update)(Graph*, long, long);
23*7dd7cddfSDavid du Colombier 	Machine	*mach;
24*7dd7cddfSDavid du Colombier 	int		overflow;
25*7dd7cddfSDavid du Colombier 	Image	*overtmp;
26*7dd7cddfSDavid du Colombier };
273e12c5d1SDavid du Colombier 
283e12c5d1SDavid du Colombier enum
293e12c5d1SDavid du Colombier {
30*7dd7cddfSDavid du Colombier 	/* /dev/swap */
31*7dd7cddfSDavid du Colombier 	Mem		= 0,
32*7dd7cddfSDavid du Colombier 	Maxmem,
333e12c5d1SDavid du Colombier 	Swap,
34*7dd7cddfSDavid du Colombier 	Maxswap,
35*7dd7cddfSDavid du Colombier 	/* /dev/sysstats */
36*7dd7cddfSDavid du Colombier 	Procno	= 0,
37*7dd7cddfSDavid du Colombier 	Context,
38*7dd7cddfSDavid du Colombier 	Interrupt,
393e12c5d1SDavid du Colombier 	Syscall,
403e12c5d1SDavid du Colombier 	Fault,
41*7dd7cddfSDavid du Colombier 	TLBfault,
42*7dd7cddfSDavid du Colombier 	TLBpurge,
433e12c5d1SDavid du Colombier 	Load,
44*7dd7cddfSDavid du Colombier 	/* /net/ether0/0/stats */
45*7dd7cddfSDavid du Colombier 	In		= 0,
46*7dd7cddfSDavid du Colombier 	Out,
47*7dd7cddfSDavid du Colombier 	Err0,
483e12c5d1SDavid du Colombier };
493e12c5d1SDavid du Colombier 
50*7dd7cddfSDavid du Colombier struct Machine
513e12c5d1SDavid du Colombier {
52*7dd7cddfSDavid du Colombier 	char		*name;
53*7dd7cddfSDavid du Colombier 	int		remote;
54*7dd7cddfSDavid du Colombier 	int		statsfd;
55*7dd7cddfSDavid du Colombier 	int		swapfd;
56*7dd7cddfSDavid du Colombier 	int		etherfd;
57*7dd7cddfSDavid du Colombier 	int		disable;
583e12c5d1SDavid du Colombier 
59*7dd7cddfSDavid du Colombier 	long		devswap[4];
60*7dd7cddfSDavid du Colombier 	long		devsysstat[8];
61*7dd7cddfSDavid du Colombier 	long		prevsysstat[8];
62*7dd7cddfSDavid du Colombier 	int		nproc;
63*7dd7cddfSDavid du Colombier 	long		netetherstats[8];
64*7dd7cddfSDavid du Colombier 	long		prevetherstats[8];
653e12c5d1SDavid du Colombier 
66*7dd7cddfSDavid du Colombier 	char		buf[1024];
67*7dd7cddfSDavid du Colombier 	char		*bufp;
68*7dd7cddfSDavid du Colombier 	char		*ebufp;
693e12c5d1SDavid du Colombier };
70*7dd7cddfSDavid du Colombier 
71*7dd7cddfSDavid du Colombier enum
72*7dd7cddfSDavid du Colombier {
73*7dd7cddfSDavid du Colombier 	Mainproc,
74*7dd7cddfSDavid du Colombier 	Mouseproc,
75*7dd7cddfSDavid du Colombier 	NPROC,
76*7dd7cddfSDavid du Colombier };
77*7dd7cddfSDavid du Colombier 
78*7dd7cddfSDavid du Colombier enum
79*7dd7cddfSDavid du Colombier {
80*7dd7cddfSDavid du Colombier 	Ncolor	= 6,
81*7dd7cddfSDavid du Colombier 	Ysqueeze	= 2,	/* vertical squeezing of label text */
82*7dd7cddfSDavid du Colombier 	Labspace	= 2,	/* room around label */
83*7dd7cddfSDavid du Colombier 	Dot		= 2,	/* height of dot */
84*7dd7cddfSDavid du Colombier 	Opwid	= 5,	/* strlen("add  ") or strlen("drop ") */
85*7dd7cddfSDavid du Colombier };
86*7dd7cddfSDavid du Colombier 
87*7dd7cddfSDavid du Colombier enum Menu2
88*7dd7cddfSDavid du Colombier {
89*7dd7cddfSDavid du Colombier 	Mcontext,
90*7dd7cddfSDavid du Colombier 	Mether,
91*7dd7cddfSDavid du Colombier 	Methererr,
92*7dd7cddfSDavid du Colombier 	Metherin,
93*7dd7cddfSDavid du Colombier 	Metherout,
94*7dd7cddfSDavid du Colombier 	Mfault,
95*7dd7cddfSDavid du Colombier 	Mintr,
96*7dd7cddfSDavid du Colombier 	Mload,
97*7dd7cddfSDavid du Colombier 	Mmem,
98*7dd7cddfSDavid du Colombier 	Mswap,
99*7dd7cddfSDavid du Colombier 	Msyscall,
100*7dd7cddfSDavid du Colombier 	Mtlbmiss,
101*7dd7cddfSDavid du Colombier 	Mtlbpurge,
102*7dd7cddfSDavid du Colombier 	Nmenu2,
103*7dd7cddfSDavid du Colombier };
104*7dd7cddfSDavid du Colombier 
105*7dd7cddfSDavid du Colombier char	*menu2str[Nmenu2+1] = {
106*7dd7cddfSDavid du Colombier 	"add  context ",
107*7dd7cddfSDavid du Colombier 	"add  ether   ",
108*7dd7cddfSDavid du Colombier 	"add  ethererr",
109*7dd7cddfSDavid du Colombier 	"add  etherin ",
110*7dd7cddfSDavid du Colombier 	"add  etherout",
111*7dd7cddfSDavid du Colombier 	"add  fault   ",
112*7dd7cddfSDavid du Colombier 	"add  intr    ",
113*7dd7cddfSDavid du Colombier 	"add  load    ",
114*7dd7cddfSDavid du Colombier 	"add  mem     ",
115*7dd7cddfSDavid du Colombier 	"add  swap    ",
116*7dd7cddfSDavid du Colombier 	"add  syscall ",
117*7dd7cddfSDavid du Colombier 	"add  tlbmiss ",
118*7dd7cddfSDavid du Colombier 	"add  tlbpurge",
119*7dd7cddfSDavid du Colombier 	nil,
120*7dd7cddfSDavid du Colombier };
121*7dd7cddfSDavid du Colombier 
122*7dd7cddfSDavid du Colombier 
123*7dd7cddfSDavid du Colombier void	contextval(Machine*, long*, long*),
124*7dd7cddfSDavid du Colombier 	etherval(Machine*, long*, long*),
125*7dd7cddfSDavid du Colombier 	ethererrval(Machine*, long*, long*),
126*7dd7cddfSDavid du Colombier 	etherinval(Machine*, long*, long*),
127*7dd7cddfSDavid du Colombier 	etheroutval(Machine*, long*, long*),
128*7dd7cddfSDavid du Colombier 	faultval(Machine*, long*, long*),
129*7dd7cddfSDavid du Colombier 	intrval(Machine*, long*, long*),
130*7dd7cddfSDavid du Colombier 	loadval(Machine*, long*, long*),
131*7dd7cddfSDavid du Colombier 	memval(Machine*, long*, long*),
132*7dd7cddfSDavid du Colombier 	swapval(Machine*, long*, long*),
133*7dd7cddfSDavid du Colombier 	syscallval(Machine*, long*, long*),
134*7dd7cddfSDavid du Colombier 	tlbmissval(Machine*, long*, long*),
135*7dd7cddfSDavid du Colombier 	tlbpurgeval(Machine*, long*, long*);
136*7dd7cddfSDavid du Colombier 
137*7dd7cddfSDavid du Colombier Menu	menu2 = {menu2str, nil};
138*7dd7cddfSDavid du Colombier int		present[Nmenu2];
139*7dd7cddfSDavid du Colombier void		(*newvaluefn[Nmenu2])(Machine*, long*, long*) = {
140*7dd7cddfSDavid du Colombier 	contextval,
141*7dd7cddfSDavid du Colombier 	etherval,
142*7dd7cddfSDavid du Colombier 	ethererrval,
143*7dd7cddfSDavid du Colombier 	etherinval,
144*7dd7cddfSDavid du Colombier 	etheroutval,
145*7dd7cddfSDavid du Colombier 	faultval,
146*7dd7cddfSDavid du Colombier 	intrval,
147*7dd7cddfSDavid du Colombier 	loadval,
148*7dd7cddfSDavid du Colombier 	memval,
149*7dd7cddfSDavid du Colombier 	swapval,
150*7dd7cddfSDavid du Colombier 	syscallval,
151*7dd7cddfSDavid du Colombier 	tlbmissval,
152*7dd7cddfSDavid du Colombier 	tlbpurgeval,
153*7dd7cddfSDavid du Colombier };
154*7dd7cddfSDavid du Colombier 
155*7dd7cddfSDavid du Colombier Image	*cols[Ncolor][3];
156*7dd7cddfSDavid du Colombier Graph	*graph;
157*7dd7cddfSDavid du Colombier Machine	*mach;
158*7dd7cddfSDavid du Colombier Font		*mediumfont;
159*7dd7cddfSDavid du Colombier char		*mysysname;
160*7dd7cddfSDavid du Colombier char		argchars[] = "ceEfimlnpstw";
161*7dd7cddfSDavid du Colombier int		pids[NPROC];
162*7dd7cddfSDavid du Colombier int 		parity;	/* toggled to avoid patterns in textured background */
163*7dd7cddfSDavid du Colombier int		nmach;
164*7dd7cddfSDavid du Colombier int		ngraph;	/* totaly number is ngraph*nmach */
165*7dd7cddfSDavid du Colombier 
166*7dd7cddfSDavid du Colombier char		*procnames[NPROC] = {"main", "mouse"};
167*7dd7cddfSDavid du Colombier 
168*7dd7cddfSDavid du Colombier void
169*7dd7cddfSDavid du Colombier killall(char *s)
170*7dd7cddfSDavid du Colombier {
171*7dd7cddfSDavid du Colombier 	int i, pid;
172*7dd7cddfSDavid du Colombier 
173*7dd7cddfSDavid du Colombier 	pid = getpid();
174*7dd7cddfSDavid du Colombier 	for(i=0; i<NPROC; i++)
175*7dd7cddfSDavid du Colombier 		if(pids[i] && pids[i]!=pid)
176*7dd7cddfSDavid du Colombier 			postnote(PNPROC, pids[i], "kill");
177*7dd7cddfSDavid du Colombier 	exits(s);
178*7dd7cddfSDavid du Colombier }
179*7dd7cddfSDavid du Colombier 
180*7dd7cddfSDavid du Colombier void*
181*7dd7cddfSDavid du Colombier emalloc(ulong sz)
182*7dd7cddfSDavid du Colombier {
183*7dd7cddfSDavid du Colombier 	void *v;
184*7dd7cddfSDavid du Colombier 	v = malloc(sz);
185*7dd7cddfSDavid du Colombier 	if(v == nil) {
186*7dd7cddfSDavid du Colombier 		fprint(2, "stats: out of memory allocating %ld: %r\n", sz);
187*7dd7cddfSDavid du Colombier 		killall("mem");
188*7dd7cddfSDavid du Colombier 	}
189*7dd7cddfSDavid du Colombier 	memset(v, 0, sz);
190*7dd7cddfSDavid du Colombier 	return v;
191*7dd7cddfSDavid du Colombier }
192*7dd7cddfSDavid du Colombier 
193*7dd7cddfSDavid du Colombier void*
194*7dd7cddfSDavid du Colombier erealloc(void *v, ulong sz)
195*7dd7cddfSDavid du Colombier {
196*7dd7cddfSDavid du Colombier 	v = realloc(v, sz);
197*7dd7cddfSDavid du Colombier 	if(v == nil) {
198*7dd7cddfSDavid du Colombier 		fprint(2, "stats: out of memory reallocating %ld: %r\n", sz);
199*7dd7cddfSDavid du Colombier 		killall("mem");
200*7dd7cddfSDavid du Colombier 	}
201*7dd7cddfSDavid du Colombier 	return v;
2023e12c5d1SDavid du Colombier }
2033e12c5d1SDavid du Colombier 
2043e12c5d1SDavid du Colombier char*
205*7dd7cddfSDavid du Colombier estrdup(char *s)
2063e12c5d1SDavid du Colombier {
207*7dd7cddfSDavid du Colombier 	char *t;
208*7dd7cddfSDavid du Colombier 	if((t = strdup(s)) == nil) {
209*7dd7cddfSDavid du Colombier 		fprint(2, "stats: out of memory in strdup(%.10s): %r\n", s);
210*7dd7cddfSDavid du Colombier 		killall("mem");
211*7dd7cddfSDavid du Colombier 	}
212*7dd7cddfSDavid du Colombier 	return t;
2133e12c5d1SDavid du Colombier }
2143e12c5d1SDavid du Colombier 
2153e12c5d1SDavid du Colombier void
216*7dd7cddfSDavid du Colombier mkcol(int i, int c0, int c1, int c2)
2173e12c5d1SDavid du Colombier {
218*7dd7cddfSDavid du Colombier 	cols[i][0] = allocimagemix(display, c0, DWhite);
219*7dd7cddfSDavid du Colombier 	cols[i][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c1);
220*7dd7cddfSDavid du Colombier 	cols[i][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c2);
221*7dd7cddfSDavid du Colombier }
2223e12c5d1SDavid du Colombier 
223*7dd7cddfSDavid du Colombier void
224*7dd7cddfSDavid du Colombier colinit(void)
225*7dd7cddfSDavid du Colombier {
226*7dd7cddfSDavid du Colombier 	mediumfont = openfont(display, "/lib/font/bit/pelm/latin1.8.font");
227*7dd7cddfSDavid du Colombier 	if(mediumfont == nil)
228*7dd7cddfSDavid du Colombier 		mediumfont = font;
229*7dd7cddfSDavid du Colombier 
230*7dd7cddfSDavid du Colombier 	/* Peach */
231*7dd7cddfSDavid du Colombier 	mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF);
232*7dd7cddfSDavid du Colombier 	/* Aqua */
233*7dd7cddfSDavid du Colombier 	mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue);
234*7dd7cddfSDavid du Colombier 	/* Yellow */
235*7dd7cddfSDavid du Colombier 	mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen);
236*7dd7cddfSDavid du Colombier 	/* Green */
237*7dd7cddfSDavid du Colombier 	mkcol(3, DPalegreen, DMedgreen, DDarkgreen);
238*7dd7cddfSDavid du Colombier 	/* Blue */
239*7dd7cddfSDavid du Colombier 	mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF);
240*7dd7cddfSDavid du Colombier 	/* Grey */
241*7dd7cddfSDavid du Colombier 	cols[5][0] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF);
242*7dd7cddfSDavid du Colombier 	cols[5][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF);
243*7dd7cddfSDavid du Colombier 	cols[5][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x888888FF);
244*7dd7cddfSDavid du Colombier }
245*7dd7cddfSDavid du Colombier 
246*7dd7cddfSDavid du Colombier int
247*7dd7cddfSDavid du Colombier loadbuf(Machine *m, int *fd)
248*7dd7cddfSDavid du Colombier {
249*7dd7cddfSDavid du Colombier 	int n;
250*7dd7cddfSDavid du Colombier 
251*7dd7cddfSDavid du Colombier 
252*7dd7cddfSDavid du Colombier 	if(*fd < 0)
253*7dd7cddfSDavid du Colombier 		return 0;
254*7dd7cddfSDavid du Colombier 	seek(*fd, 0, 0);
255*7dd7cddfSDavid du Colombier 	n = read(*fd, m->buf, sizeof m->buf);
256*7dd7cddfSDavid du Colombier 	if(n <= 0){
257*7dd7cddfSDavid du Colombier 		close(*fd);
258*7dd7cddfSDavid du Colombier 		*fd = -1;
259*7dd7cddfSDavid du Colombier 		return 0;
260*7dd7cddfSDavid du Colombier 	}
261*7dd7cddfSDavid du Colombier 	m->bufp = m->buf;
262*7dd7cddfSDavid du Colombier 	m->ebufp = m->buf+n;
263*7dd7cddfSDavid du Colombier 	return 1;
264*7dd7cddfSDavid du Colombier }
265*7dd7cddfSDavid du Colombier 
266*7dd7cddfSDavid du Colombier void
267*7dd7cddfSDavid du Colombier label(Point p, int dy, char *text)
268*7dd7cddfSDavid du Colombier {
269*7dd7cddfSDavid du Colombier 	char *s;
270*7dd7cddfSDavid du Colombier 	Rune r[2];
271*7dd7cddfSDavid du Colombier 	int w, maxw, maxy;
272*7dd7cddfSDavid du Colombier 
273*7dd7cddfSDavid du Colombier 	p.x += Labspace;
274*7dd7cddfSDavid du Colombier 	maxy = p.y+dy;
275*7dd7cddfSDavid du Colombier 	maxw = 0;
276*7dd7cddfSDavid du Colombier 	r[1] = '\0';
277*7dd7cddfSDavid du Colombier 	for(s=text; *s; ){
278*7dd7cddfSDavid du Colombier 		if(p.y+mediumfont->height-Ysqueeze > maxy)
279*7dd7cddfSDavid du Colombier 			break;
280*7dd7cddfSDavid du Colombier 		w = chartorune(r, s);
281*7dd7cddfSDavid du Colombier 		s += w;
282*7dd7cddfSDavid du Colombier 		w = runestringwidth(mediumfont, r);
283*7dd7cddfSDavid du Colombier 		if(w > maxw)
284*7dd7cddfSDavid du Colombier 			maxw = w;
285*7dd7cddfSDavid du Colombier 		runestring(screen, p, display->black, ZP, mediumfont, r);
286*7dd7cddfSDavid du Colombier 		p.y += mediumfont->height-Ysqueeze;
287*7dd7cddfSDavid du Colombier 	}
288*7dd7cddfSDavid du Colombier }
289*7dd7cddfSDavid du Colombier 
290*7dd7cddfSDavid du Colombier Point
291*7dd7cddfSDavid du Colombier paritypt(int x)
292*7dd7cddfSDavid du Colombier {
293*7dd7cddfSDavid du Colombier 	return Pt(x+parity, 0);
294*7dd7cddfSDavid du Colombier }
295*7dd7cddfSDavid du Colombier 
296*7dd7cddfSDavid du Colombier Point
297*7dd7cddfSDavid du Colombier datapoint(Graph *g, int x, long v, long vmax)
298*7dd7cddfSDavid du Colombier {
299*7dd7cddfSDavid du Colombier 	Point p;
300*7dd7cddfSDavid du Colombier 
301*7dd7cddfSDavid du Colombier 	p.x = x;
302*7dd7cddfSDavid du Colombier 	p.y = g->r.max.y - Dy(g->r)*v/vmax - Dot;
303*7dd7cddfSDavid du Colombier 	if(p.y < g->r.min.y)
304*7dd7cddfSDavid du Colombier 		p.y = g->r.min.y;
305*7dd7cddfSDavid du Colombier 	if(p.y > g->r.max.y-Dot)
306*7dd7cddfSDavid du Colombier 		p.y = g->r.max.y-Dot;
307*7dd7cddfSDavid du Colombier 	return p;
308*7dd7cddfSDavid du Colombier }
309*7dd7cddfSDavid du Colombier 
310*7dd7cddfSDavid du Colombier void
311*7dd7cddfSDavid du Colombier drawdatum(Graph *g, int x, long prev, long v, long vmax)
312*7dd7cddfSDavid du Colombier {
313*7dd7cddfSDavid du Colombier 	int c;
314*7dd7cddfSDavid du Colombier 	Point p, q;
315*7dd7cddfSDavid du Colombier 
316*7dd7cddfSDavid du Colombier 	c = g->colindex;
317*7dd7cddfSDavid du Colombier 	p = datapoint(g, x, v, vmax);
318*7dd7cddfSDavid du Colombier 	q = datapoint(g, x, prev, vmax);
319*7dd7cddfSDavid du Colombier 	if(p.y < q.y){
320*7dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, g->r.min.y, p.x+1, p.y), cols[c][0], nil, paritypt(p.x));
321*7dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, p.y, p.x+1, q.y+Dot), cols[c][2], nil, ZP);
322*7dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, q.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP);
323*7dd7cddfSDavid du Colombier 	}else{
324*7dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, g->r.min.y, p.x+1, q.y), cols[c][0], nil, paritypt(p.x));
325*7dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, q.y, p.x+1, p.y+Dot), cols[c][2], nil, ZP);
326*7dd7cddfSDavid du Colombier 		draw(screen, Rect(p.x, p.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP);
327*7dd7cddfSDavid du Colombier 	}
328*7dd7cddfSDavid du Colombier 
329*7dd7cddfSDavid du Colombier }
330*7dd7cddfSDavid du Colombier 
331*7dd7cddfSDavid du Colombier void
332*7dd7cddfSDavid du Colombier redraw(Graph *g, int vmax)
333*7dd7cddfSDavid du Colombier {
334*7dd7cddfSDavid du Colombier 	int i, c;
335*7dd7cddfSDavid du Colombier 
336*7dd7cddfSDavid du Colombier 	c = g->colindex;
337*7dd7cddfSDavid du Colombier 	draw(screen, g->r, cols[c][0], nil, paritypt(g->r.min.x));
338*7dd7cddfSDavid du Colombier 	for(i=1; i<Dx(g->r); i++)
339*7dd7cddfSDavid du Colombier 		drawdatum(g, g->r.max.x-i, g->data[i-1], g->data[i], vmax);
340*7dd7cddfSDavid du Colombier 	drawdatum(g, g->r.min.x, g->data[i], g->data[i], vmax);
341*7dd7cddfSDavid du Colombier 	g->overflow = 0;
342*7dd7cddfSDavid du Colombier }
343*7dd7cddfSDavid du Colombier 
344*7dd7cddfSDavid du Colombier void
345*7dd7cddfSDavid du Colombier update1(Graph *g, long v, long vmax)
346*7dd7cddfSDavid du Colombier {
347*7dd7cddfSDavid du Colombier 	char buf[32];
348*7dd7cddfSDavid du Colombier 
349*7dd7cddfSDavid du Colombier 	if(g->overflow && g->overtmp!=nil)
350*7dd7cddfSDavid du Colombier 		draw(screen, g->overtmp->r, g->overtmp, nil, g->overtmp->r.min);
351*7dd7cddfSDavid du Colombier 	draw(screen, g->r, screen, nil, Pt(g->r.min.x+1, g->r.min.y));
352*7dd7cddfSDavid du Colombier 	drawdatum(g, g->r.max.x-1, g->data[0], v, vmax);
353*7dd7cddfSDavid du Colombier 	memmove(g->data+1, g->data, (g->ndata-1)*sizeof(g->data[0]));
354*7dd7cddfSDavid du Colombier 	g->data[0] = v;
355*7dd7cddfSDavid du Colombier 	g->overflow = 0;
356*7dd7cddfSDavid du Colombier 	if(v>vmax && g->overtmp!=nil){
357*7dd7cddfSDavid du Colombier 		g->overflow = 1;
358*7dd7cddfSDavid du Colombier 		draw(g->overtmp, g->overtmp->r, screen, nil, g->overtmp->r.min);
359*7dd7cddfSDavid du Colombier 		sprint(buf, "%ld", v);
360*7dd7cddfSDavid du Colombier 		string(screen, g->overtmp->r.min, display->black, ZP, mediumfont, buf);
361*7dd7cddfSDavid du Colombier 	}
362*7dd7cddfSDavid du Colombier }
363*7dd7cddfSDavid du Colombier 
364*7dd7cddfSDavid du Colombier /* read one line of text from buffer and process integers */
365*7dd7cddfSDavid du Colombier int
366*7dd7cddfSDavid du Colombier readnums(Machine *m, int n, long *a, int spanlines)
367*7dd7cddfSDavid du Colombier {
368*7dd7cddfSDavid du Colombier 	int i;
369*7dd7cddfSDavid du Colombier 	char *p, *ep;
370*7dd7cddfSDavid du Colombier 
371*7dd7cddfSDavid du Colombier 	if(spanlines)
372*7dd7cddfSDavid du Colombier 		ep = m->ebufp;
373*7dd7cddfSDavid du Colombier 	else
374*7dd7cddfSDavid du Colombier 		for(ep=m->bufp; ep<m->ebufp; ep++)
375*7dd7cddfSDavid du Colombier 			if(*ep == '\n')
376*7dd7cddfSDavid du Colombier 				break;
377*7dd7cddfSDavid du Colombier 	p = m->bufp;
378*7dd7cddfSDavid du Colombier 	for(i=0; i<n && p<ep; i++){
379*7dd7cddfSDavid du Colombier 		while(p<ep && !isdigit(*p))
380*7dd7cddfSDavid du Colombier 			p++;
381*7dd7cddfSDavid du Colombier 		if(p == ep)
382*7dd7cddfSDavid du Colombier 			break;
383*7dd7cddfSDavid du Colombier 		a[i] = strtol(p, &p, 10);
384*7dd7cddfSDavid du Colombier 	}
385*7dd7cddfSDavid du Colombier 	if(ep < m->ebufp)
386*7dd7cddfSDavid du Colombier 		ep++;
387*7dd7cddfSDavid du Colombier 	m->bufp = ep;
388*7dd7cddfSDavid du Colombier 	return i == n;
389*7dd7cddfSDavid du Colombier }
390*7dd7cddfSDavid du Colombier 
391*7dd7cddfSDavid du Colombier /* Network on fd1, mount driver on fd0 */
392*7dd7cddfSDavid du Colombier static int
393*7dd7cddfSDavid du Colombier filter(int fd)
394*7dd7cddfSDavid du Colombier {
395*7dd7cddfSDavid du Colombier 	int p[2];
396*7dd7cddfSDavid du Colombier 
397*7dd7cddfSDavid du Colombier 	if(pipe(p) < 0){
398*7dd7cddfSDavid du Colombier 		fprint(2, "stats: can't pipe: %r\n");
399*7dd7cddfSDavid du Colombier 		killall("pipe");
400*7dd7cddfSDavid du Colombier 	}
401*7dd7cddfSDavid du Colombier 
402*7dd7cddfSDavid du Colombier 	switch(rfork(RFNOWAIT|RFPROC|RFFDG)) {
403*7dd7cddfSDavid du Colombier 	case -1:
404*7dd7cddfSDavid du Colombier 		sysfatal("rfork record module");
405*7dd7cddfSDavid du Colombier 	case 0:
406*7dd7cddfSDavid du Colombier 		dup(fd, 1);
407*7dd7cddfSDavid du Colombier 		close(fd);
408*7dd7cddfSDavid du Colombier 		dup(p[0], 0);
409*7dd7cddfSDavid du Colombier 		close(p[0]);
410*7dd7cddfSDavid du Colombier 		close(p[1]);
411*7dd7cddfSDavid du Colombier 		execl("/bin/aux/fcall", "fcall", 0);
412*7dd7cddfSDavid du Colombier 		fprint(2, "stats: can't exec fcall: %r\n");
413*7dd7cddfSDavid du Colombier 		killall("fcall");
414*7dd7cddfSDavid du Colombier 	default:
415*7dd7cddfSDavid du Colombier 		close(fd);
416*7dd7cddfSDavid du Colombier 		close(p[0]);
417*7dd7cddfSDavid du Colombier 	}
418*7dd7cddfSDavid du Colombier 	return p[1];
419*7dd7cddfSDavid du Colombier }
420*7dd7cddfSDavid du Colombier 
421*7dd7cddfSDavid du Colombier /*
422*7dd7cddfSDavid du Colombier  * 9fs
423*7dd7cddfSDavid du Colombier  */
424*7dd7cddfSDavid du Colombier int
425*7dd7cddfSDavid du Colombier connect9fs(char *addr)
426*7dd7cddfSDavid du Colombier {
427*7dd7cddfSDavid du Colombier 	char dir[4*NAMELEN], *na;
428*7dd7cddfSDavid du Colombier 	int fd;
429*7dd7cddfSDavid du Colombier 
430*7dd7cddfSDavid du Colombier 	fprint(2, "connect9fs...");
431*7dd7cddfSDavid du Colombier 	na = netmkaddr(addr, 0, "9fs");
432*7dd7cddfSDavid du Colombier 
433*7dd7cddfSDavid du Colombier 	fprint(2, "dial %s...", na);
434*7dd7cddfSDavid du Colombier 	if((fd = dial(na, 0, dir, 0)) < 0)
435*7dd7cddfSDavid du Colombier 		return -1;
436*7dd7cddfSDavid du Colombier 
437*7dd7cddfSDavid du Colombier 	fprint(2, "dir %s...", dir);
438*7dd7cddfSDavid du Colombier 	if(strstr(dir, "tcp"))
439*7dd7cddfSDavid du Colombier 		fd = filter(fd);
440*7dd7cddfSDavid du Colombier 	return fd;
441*7dd7cddfSDavid du Colombier }
442*7dd7cddfSDavid du Colombier 
443*7dd7cddfSDavid du Colombier /*
444*7dd7cddfSDavid du Colombier  * exportfs
445*7dd7cddfSDavid du Colombier  */
446*7dd7cddfSDavid du Colombier int
447*7dd7cddfSDavid du Colombier connectexportfs(char *addr)
448*7dd7cddfSDavid du Colombier {
449*7dd7cddfSDavid du Colombier 	char buf[ERRLEN], dir[4*NAMELEN], *na;
450*7dd7cddfSDavid du Colombier 	int fd, n;
451*7dd7cddfSDavid du Colombier 	char *tree;
452*7dd7cddfSDavid du Colombier 
453*7dd7cddfSDavid du Colombier 	tree = "/";
454*7dd7cddfSDavid du Colombier 	na = netmkaddr(addr, 0, "exportfs");
455*7dd7cddfSDavid du Colombier 	if((fd = dial(na, 0, dir, 0)) < 0)
456*7dd7cddfSDavid du Colombier 		return -1;
457*7dd7cddfSDavid du Colombier 
458*7dd7cddfSDavid du Colombier 	if(auth(fd) < 0){
459*7dd7cddfSDavid du Colombier 		close(fd);
460*7dd7cddfSDavid du Colombier 		return -1;
461*7dd7cddfSDavid du Colombier 	}
462*7dd7cddfSDavid du Colombier 
463*7dd7cddfSDavid du Colombier 	n = write(fd, tree, strlen(tree));
464*7dd7cddfSDavid du Colombier 	if(n < 0){
465*7dd7cddfSDavid du Colombier 		close(fd);
466*7dd7cddfSDavid du Colombier 		return -1;
467*7dd7cddfSDavid du Colombier 	}
468*7dd7cddfSDavid du Colombier 
469*7dd7cddfSDavid du Colombier 	strcpy(buf, "can't read tree");
470*7dd7cddfSDavid du Colombier 	n = read(fd, buf, sizeof buf - 1);
471*7dd7cddfSDavid du Colombier 	if(n!=2 || buf[0]!='O' || buf[1]!='K'){
472*7dd7cddfSDavid du Colombier 		buf[sizeof buf - 1] = '\0';
473*7dd7cddfSDavid du Colombier 		werrstr("bad remote tree: %s\n", buf);
474*7dd7cddfSDavid du Colombier 		close(fd);
475*7dd7cddfSDavid du Colombier 		return -1;
476*7dd7cddfSDavid du Colombier 	}
477*7dd7cddfSDavid du Colombier 
478*7dd7cddfSDavid du Colombier 	if(strstr(dir, "tcp"))
479*7dd7cddfSDavid du Colombier 		fd = filter(fd);
480*7dd7cddfSDavid du Colombier 
481*7dd7cddfSDavid du Colombier 	return fd;
482*7dd7cddfSDavid du Colombier }
483*7dd7cddfSDavid du Colombier 
484*7dd7cddfSDavid du Colombier void
485*7dd7cddfSDavid du Colombier initmach(Machine *m, char *name)
486*7dd7cddfSDavid du Colombier {
487*7dd7cddfSDavid du Colombier 	int n, fd;
488*7dd7cddfSDavid du Colombier 	long a[MAXNUM];
489*7dd7cddfSDavid du Colombier 	char *p, mpt[256], buf[256];
490*7dd7cddfSDavid du Colombier 
491*7dd7cddfSDavid du Colombier 	p = strchr(name, '!');
492*7dd7cddfSDavid du Colombier 	if(p){
493*7dd7cddfSDavid du Colombier 		p++;
494*7dd7cddfSDavid du Colombier 		m->name = estrdup(p+1);
495*7dd7cddfSDavid du Colombier 	}else
496*7dd7cddfSDavid du Colombier 		p = name;
497*7dd7cddfSDavid du Colombier 	m->name = estrdup(p);
498*7dd7cddfSDavid du Colombier 	m->remote = (strcmp(p, mysysname) != 0);
499*7dd7cddfSDavid du Colombier 	if(m->remote == 0)
500*7dd7cddfSDavid du Colombier 		strcpy(mpt, "");
501*7dd7cddfSDavid du Colombier 	else{
502*7dd7cddfSDavid du Colombier 		snprint(mpt, sizeof mpt, "/n/%s", p);
503*7dd7cddfSDavid du Colombier 		fd = connectexportfs(name);
504*7dd7cddfSDavid du Colombier 		if(fd < 0){
505*7dd7cddfSDavid du Colombier 			fprint(2, "can't connect to %s: %r\n", name);
506*7dd7cddfSDavid du Colombier 			killall("connect");
507*7dd7cddfSDavid du Colombier 		}
508*7dd7cddfSDavid du Colombier 		if(mount(fd, mpt, MREPL, "") < 0){
509*7dd7cddfSDavid du Colombier 			fprint(2, "stats: mount %s on %s failed (%r); trying /n/sid\n", name, mpt);
510*7dd7cddfSDavid du Colombier 			strcpy(mpt, "/n/sid");
511*7dd7cddfSDavid du Colombier 			if(mount(fd, mpt, MREPL, "") < 0){
512*7dd7cddfSDavid du Colombier 				fprint(2, "stats: mount %s on %s failed: %r\n", name, mpt);
513*7dd7cddfSDavid du Colombier 				killall("mount");
514*7dd7cddfSDavid du Colombier 			}
515*7dd7cddfSDavid du Colombier 		}
516*7dd7cddfSDavid du Colombier 	}
517*7dd7cddfSDavid du Colombier 
518*7dd7cddfSDavid du Colombier 	snprint(buf, sizeof buf, "%s/dev/swap", mpt);
519*7dd7cddfSDavid du Colombier 	m->swapfd = open(buf, OREAD);
520*7dd7cddfSDavid du Colombier 	if(loadbuf(m, &m->swapfd) && readnums(m, nelem(m->devswap), a, 0))
521*7dd7cddfSDavid du Colombier 		memmove(m->devswap, a, sizeof m->devswap);
522*7dd7cddfSDavid du Colombier 	else
523*7dd7cddfSDavid du Colombier 		m->devswap[Maxmem] = m->devswap[Maxswap] = 100;
524*7dd7cddfSDavid du Colombier 
525*7dd7cddfSDavid du Colombier 	snprint(buf, sizeof buf, "%s/dev/sysstat", mpt);
526*7dd7cddfSDavid du Colombier 	m->statsfd = open(buf, OREAD);
527*7dd7cddfSDavid du Colombier 	if(loadbuf(m, &m->statsfd)){
528*7dd7cddfSDavid du Colombier 		for(n=0; readnums(m, nelem(m->devsysstat), a, 0); n++)
529*7dd7cddfSDavid du Colombier 			;
530*7dd7cddfSDavid du Colombier 		m->nproc = n;
531*7dd7cddfSDavid du Colombier 	}else
532*7dd7cddfSDavid du Colombier 		m->nproc = 1;
533*7dd7cddfSDavid du Colombier 
534*7dd7cddfSDavid du Colombier 	snprint(buf, sizeof buf, "%s/net/ether0/0/stats", mpt);
535*7dd7cddfSDavid du Colombier 	m->etherfd = open(buf, OREAD);
536*7dd7cddfSDavid du Colombier 	if(loadbuf(m, &m->etherfd) &&  readnums(m, nelem(m->netetherstats), a, 1))
537*7dd7cddfSDavid du Colombier 		memmove(m->netetherstats, a, sizeof m->netetherstats);
538*7dd7cddfSDavid du Colombier }
539*7dd7cddfSDavid du Colombier 
540*7dd7cddfSDavid du Colombier jmp_buf catchalarm;
541*7dd7cddfSDavid du Colombier 
542*7dd7cddfSDavid du Colombier void
543*7dd7cddfSDavid du Colombier alarmed(void *a, char *s)
544*7dd7cddfSDavid du Colombier {
545*7dd7cddfSDavid du Colombier 	if(strcmp(s, "alarm") == 0)
546*7dd7cddfSDavid du Colombier 		notejmp(a, catchalarm, 1);
5473e12c5d1SDavid du Colombier 	noted(NDFLT);
5483e12c5d1SDavid du Colombier }
549*7dd7cddfSDavid du Colombier 
550*7dd7cddfSDavid du Colombier int
551*7dd7cddfSDavid du Colombier needswap(int init)
552*7dd7cddfSDavid du Colombier {
553*7dd7cddfSDavid du Colombier 	return init | present[Mmem] | present[Mswap];
554*7dd7cddfSDavid du Colombier }
555*7dd7cddfSDavid du Colombier 
556*7dd7cddfSDavid du Colombier 
557*7dd7cddfSDavid du Colombier int
558*7dd7cddfSDavid du Colombier needstat(int init)
559*7dd7cddfSDavid du Colombier {
560*7dd7cddfSDavid du Colombier 	return init | present[Mcontext]  | present[Mfault] | present[Mintr] | present[Mload] |
561*7dd7cddfSDavid du Colombier 		present[Msyscall] | present[Mtlbmiss] | present[Mtlbpurge];
562*7dd7cddfSDavid du Colombier }
563*7dd7cddfSDavid du Colombier 
564*7dd7cddfSDavid du Colombier 
565*7dd7cddfSDavid du Colombier int
566*7dd7cddfSDavid du Colombier needether(int init)
567*7dd7cddfSDavid du Colombier {
568*7dd7cddfSDavid du Colombier 	return init | present[Mether] | present[Metherin] | present[Metherout] | present[Methererr];
569*7dd7cddfSDavid du Colombier }
570*7dd7cddfSDavid du Colombier 
571*7dd7cddfSDavid du Colombier void
572*7dd7cddfSDavid du Colombier readmach(Machine *m, int init)
573*7dd7cddfSDavid du Colombier {
574*7dd7cddfSDavid du Colombier 	int n, i;
575*7dd7cddfSDavid du Colombier 	long a[8];
576*7dd7cddfSDavid du Colombier 	char buf[32];
577*7dd7cddfSDavid du Colombier 
578*7dd7cddfSDavid du Colombier 	if(m->remote && (m->disable || setjmp(catchalarm))){
579*7dd7cddfSDavid du Colombier 		if(m->disable == 0){
580*7dd7cddfSDavid du Colombier 			snprint(buf, sizeof buf, "%s(dead)", m->name);
581*7dd7cddfSDavid du Colombier 			m->name = estrdup(buf);
582*7dd7cddfSDavid du Colombier 			if(display != nil)	/* else we're still initializing */
583*7dd7cddfSDavid du Colombier 				eresized(0);
584*7dd7cddfSDavid du Colombier 		}
585*7dd7cddfSDavid du Colombier 		m->disable = 1;
586*7dd7cddfSDavid du Colombier 		memmove(m->devsysstat, m->prevsysstat, sizeof m->devsysstat);
587*7dd7cddfSDavid du Colombier 		memmove(m->netetherstats, m->prevetherstats, sizeof m->netetherstats);
588*7dd7cddfSDavid du Colombier 		return;
589*7dd7cddfSDavid du Colombier 	}
590*7dd7cddfSDavid du Colombier 	if(m->remote){
591*7dd7cddfSDavid du Colombier 		notify(alarmed);
592*7dd7cddfSDavid du Colombier 		alarm(5000);
593*7dd7cddfSDavid du Colombier 	}
594*7dd7cddfSDavid du Colombier 	if(needswap(init) && loadbuf(m, &m->swapfd) && readnums(m, nelem(m->devswap), a, 0))
595*7dd7cddfSDavid du Colombier 		memmove(m->devswap, a, sizeof m->devswap);
596*7dd7cddfSDavid du Colombier 	if(needstat(init) && loadbuf(m, &m->statsfd)){
597*7dd7cddfSDavid du Colombier 		memmove(m->prevsysstat, m->devsysstat, sizeof m->devsysstat);
598*7dd7cddfSDavid du Colombier 		memset(m->devsysstat, 0, sizeof m->devsysstat);
599*7dd7cddfSDavid du Colombier 		for(n=0; n<m->nproc && readnums(m, nelem(m->devsysstat), a, 0); n++)
600*7dd7cddfSDavid du Colombier 			for(i=0; i<nelem(m->devsysstat); i++)
601*7dd7cddfSDavid du Colombier 				m->devsysstat[i] += a[i];
602*7dd7cddfSDavid du Colombier 	}
603*7dd7cddfSDavid du Colombier 	if(needether(init) && loadbuf(m, &m->etherfd) && readnums(m, nelem(m->netetherstats), a, 1)){
604*7dd7cddfSDavid du Colombier 		memmove(m->prevetherstats, m->netetherstats, sizeof m->netetherstats);
605*7dd7cddfSDavid du Colombier 		memmove(m->netetherstats, a, sizeof m->netetherstats);
606*7dd7cddfSDavid du Colombier 	}
607*7dd7cddfSDavid du Colombier 	if(m->remote){
608*7dd7cddfSDavid du Colombier 		alarm(0);
609*7dd7cddfSDavid du Colombier 		notify(nil);
610*7dd7cddfSDavid du Colombier 	}
611*7dd7cddfSDavid du Colombier }
612*7dd7cddfSDavid du Colombier 
613*7dd7cddfSDavid du Colombier void
614*7dd7cddfSDavid du Colombier memval(Machine *m, long *v, long *vmax)
615*7dd7cddfSDavid du Colombier {
616*7dd7cddfSDavid du Colombier 	*v = m->devswap[Mem];
617*7dd7cddfSDavid du Colombier 	*vmax = m->devswap[Maxmem];
618*7dd7cddfSDavid du Colombier }
619*7dd7cddfSDavid du Colombier 
620*7dd7cddfSDavid du Colombier void
621*7dd7cddfSDavid du Colombier swapval(Machine *m, long *v, long *vmax)
622*7dd7cddfSDavid du Colombier {
623*7dd7cddfSDavid du Colombier 	*v = m->devswap[Swap];
624*7dd7cddfSDavid du Colombier 	*vmax = m->devswap[Maxswap];
625*7dd7cddfSDavid du Colombier }
626*7dd7cddfSDavid du Colombier 
627*7dd7cddfSDavid du Colombier void
628*7dd7cddfSDavid du Colombier contextval(Machine *m, long *v, long *vmax)
629*7dd7cddfSDavid du Colombier {
630*7dd7cddfSDavid du Colombier 	*v = m->devsysstat[Context]-m->prevsysstat[Context];
631*7dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
632*7dd7cddfSDavid du Colombier }
633*7dd7cddfSDavid du Colombier 
634*7dd7cddfSDavid du Colombier void
635*7dd7cddfSDavid du Colombier intrval(Machine *m, long *v, long *vmax)
636*7dd7cddfSDavid du Colombier {
637*7dd7cddfSDavid du Colombier 	*v = m->devsysstat[Interrupt]-m->prevsysstat[Interrupt];
638*7dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
639*7dd7cddfSDavid du Colombier }
640*7dd7cddfSDavid du Colombier 
641*7dd7cddfSDavid du Colombier void
642*7dd7cddfSDavid du Colombier syscallval(Machine *m, long *v, long *vmax)
643*7dd7cddfSDavid du Colombier {
644*7dd7cddfSDavid du Colombier 	*v = m->devsysstat[Syscall]-m->prevsysstat[Syscall];
645*7dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
646*7dd7cddfSDavid du Colombier }
647*7dd7cddfSDavid du Colombier 
648*7dd7cddfSDavid du Colombier void
649*7dd7cddfSDavid du Colombier faultval(Machine *m, long *v, long *vmax)
650*7dd7cddfSDavid du Colombier {
651*7dd7cddfSDavid du Colombier 	*v = m->devsysstat[Fault]-m->prevsysstat[Fault];
652*7dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
653*7dd7cddfSDavid du Colombier }
654*7dd7cddfSDavid du Colombier 
655*7dd7cddfSDavid du Colombier void
656*7dd7cddfSDavid du Colombier tlbmissval(Machine *m, long *v, long *vmax)
657*7dd7cddfSDavid du Colombier {
658*7dd7cddfSDavid du Colombier 	*v = m->devsysstat[TLBfault]-m->prevsysstat[TLBfault];
659*7dd7cddfSDavid du Colombier 	*vmax = 10*m->nproc;
660*7dd7cddfSDavid du Colombier }
661*7dd7cddfSDavid du Colombier 
662*7dd7cddfSDavid du Colombier void
663*7dd7cddfSDavid du Colombier tlbpurgeval(Machine *m, long *v, long *vmax)
664*7dd7cddfSDavid du Colombier {
665*7dd7cddfSDavid du Colombier 	*v = m->devsysstat[TLBpurge]-m->prevsysstat[TLBpurge];
666*7dd7cddfSDavid du Colombier 	*vmax = 10*m->nproc;
667*7dd7cddfSDavid du Colombier }
668*7dd7cddfSDavid du Colombier 
669*7dd7cddfSDavid du Colombier void
670*7dd7cddfSDavid du Colombier loadval(Machine *m, long *v, long *vmax)
671*7dd7cddfSDavid du Colombier {
672*7dd7cddfSDavid du Colombier 	*v = m->devsysstat[Load];
673*7dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
674*7dd7cddfSDavid du Colombier }
675*7dd7cddfSDavid du Colombier 
676*7dd7cddfSDavid du Colombier void
677*7dd7cddfSDavid du Colombier etherval(Machine *m, long *v, long *vmax)
678*7dd7cddfSDavid du Colombier {
679*7dd7cddfSDavid du Colombier 	*v = m->netetherstats[In]-m->prevetherstats[In] + m->netetherstats[Out]-m->prevetherstats[Out];
680*7dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
681*7dd7cddfSDavid du Colombier }
682*7dd7cddfSDavid du Colombier 
683*7dd7cddfSDavid du Colombier void
684*7dd7cddfSDavid du Colombier etherinval(Machine *m, long *v, long *vmax)
685*7dd7cddfSDavid du Colombier {
686*7dd7cddfSDavid du Colombier 	*v = m->netetherstats[In]-m->prevetherstats[In];
687*7dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
688*7dd7cddfSDavid du Colombier }
689*7dd7cddfSDavid du Colombier 
690*7dd7cddfSDavid du Colombier void
691*7dd7cddfSDavid du Colombier etheroutval(Machine *m, long *v, long *vmax)
692*7dd7cddfSDavid du Colombier {
693*7dd7cddfSDavid du Colombier 	*v = m->netetherstats[Out]-m->prevetherstats[Out];
694*7dd7cddfSDavid du Colombier 	*vmax = 1000*m->nproc;
695*7dd7cddfSDavid du Colombier }
696*7dd7cddfSDavid du Colombier 
697*7dd7cddfSDavid du Colombier void
698*7dd7cddfSDavid du Colombier ethererrval(Machine *m, long *v, long *vmax)
699*7dd7cddfSDavid du Colombier {
700*7dd7cddfSDavid du Colombier 	int i;
701*7dd7cddfSDavid du Colombier 
702*7dd7cddfSDavid du Colombier 	*v = 0;
703*7dd7cddfSDavid du Colombier 	for(i=Err0; i<nelem(m->netetherstats); i++)
704*7dd7cddfSDavid du Colombier 		*v += m->netetherstats[i];
705*7dd7cddfSDavid du Colombier 	*vmax = 10*m->nproc;
706*7dd7cddfSDavid du Colombier }
707*7dd7cddfSDavid du Colombier 
708*7dd7cddfSDavid du Colombier void
709*7dd7cddfSDavid du Colombier usage(void)
710*7dd7cddfSDavid du Colombier {
711*7dd7cddfSDavid du Colombier 	fprint(2, "usage: stats [-%s] [machine...]\n", argchars);
712*7dd7cddfSDavid du Colombier 	exits("usage");
713*7dd7cddfSDavid du Colombier }
714*7dd7cddfSDavid du Colombier 
715*7dd7cddfSDavid du Colombier void
716*7dd7cddfSDavid du Colombier addgraph(int n)
717*7dd7cddfSDavid du Colombier {
718*7dd7cddfSDavid du Colombier 	Graph *g, *ograph;
719*7dd7cddfSDavid du Colombier 	int i, j;
720*7dd7cddfSDavid du Colombier 	static int nadd;
721*7dd7cddfSDavid du Colombier 
722*7dd7cddfSDavid du Colombier 	if(n > nelem(menu2str))
723*7dd7cddfSDavid du Colombier 		abort();
724*7dd7cddfSDavid du Colombier 	/* avoid two adjacent graphs of same color */
725*7dd7cddfSDavid du Colombier 	if(ngraph>0 && graph[ngraph-1].colindex==nadd%Ncolor)
726*7dd7cddfSDavid du Colombier 		nadd++;
727*7dd7cddfSDavid du Colombier 	ograph = graph;
728*7dd7cddfSDavid du Colombier 	graph = emalloc(nmach*(ngraph+1)*sizeof(Graph));
729*7dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++)
730*7dd7cddfSDavid du Colombier 		for(j=0; j<ngraph; j++)
731*7dd7cddfSDavid du Colombier 			graph[i*(ngraph+1)+j] = ograph[i*ngraph+j];
732*7dd7cddfSDavid du Colombier 	free(ograph);
733*7dd7cddfSDavid du Colombier 	ngraph++;
734*7dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++){
735*7dd7cddfSDavid du Colombier 		g = &graph[i*ngraph+(ngraph-1)];
736*7dd7cddfSDavid du Colombier 		memset(g, 0, sizeof(Graph));
737*7dd7cddfSDavid du Colombier 		g->label = menu2str[n]+Opwid;
738*7dd7cddfSDavid du Colombier 		g->newvalue = newvaluefn[n];
739*7dd7cddfSDavid du Colombier 		g->update = update1;	/* no other update functions yet */
740*7dd7cddfSDavid du Colombier 		g->mach = &mach[i];
741*7dd7cddfSDavid du Colombier 		g->colindex = nadd%Ncolor;
742*7dd7cddfSDavid du Colombier 	}
743*7dd7cddfSDavid du Colombier 	present[n] = 1;
744*7dd7cddfSDavid du Colombier 	nadd++;
745*7dd7cddfSDavid du Colombier }
746*7dd7cddfSDavid du Colombier 
747*7dd7cddfSDavid du Colombier void
748*7dd7cddfSDavid du Colombier dropgraph(int which)
749*7dd7cddfSDavid du Colombier {
750*7dd7cddfSDavid du Colombier 	Graph *ograph;
751*7dd7cddfSDavid du Colombier 	int i, j, n;
752*7dd7cddfSDavid du Colombier 
753*7dd7cddfSDavid du Colombier 	if(which > nelem(menu2str))
754*7dd7cddfSDavid du Colombier 		abort();
755*7dd7cddfSDavid du Colombier 	/* convert n to index in graph table */
756*7dd7cddfSDavid du Colombier 	n = -1;
757*7dd7cddfSDavid du Colombier 	for(i=0; i<ngraph; i++)
758*7dd7cddfSDavid du Colombier 		if(strcmp(menu2str[which]+Opwid, graph[i].label) == 0){
759*7dd7cddfSDavid du Colombier 			n = i;
760*7dd7cddfSDavid du Colombier 			break;
761*7dd7cddfSDavid du Colombier 		}
762*7dd7cddfSDavid du Colombier 	if(n < 0){
763*7dd7cddfSDavid du Colombier 		fprint(2, "stats: internal error can't drop graph\n");
764*7dd7cddfSDavid du Colombier 		killall("error");
765*7dd7cddfSDavid du Colombier 	}
766*7dd7cddfSDavid du Colombier 	ograph = graph;
767*7dd7cddfSDavid du Colombier 	graph = emalloc(nmach*(ngraph-1)*sizeof(Graph));
768*7dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++){
769*7dd7cddfSDavid du Colombier 		for(j=0; j<n; j++)
770*7dd7cddfSDavid du Colombier 			graph[i*(ngraph-1)+j] = ograph[i*ngraph+j];
771*7dd7cddfSDavid du Colombier 		free(ograph[i*ngraph+j].data);
772*7dd7cddfSDavid du Colombier 		freeimage(ograph[i*ngraph+j].overtmp);
773*7dd7cddfSDavid du Colombier 		for(j++; j<ngraph; j++)
774*7dd7cddfSDavid du Colombier 			graph[i*(ngraph-1)+j-1] = ograph[i*ngraph+j];
775*7dd7cddfSDavid du Colombier 	}
776*7dd7cddfSDavid du Colombier 	free(ograph);
777*7dd7cddfSDavid du Colombier 	ngraph--;
778*7dd7cddfSDavid du Colombier 	present[which] = 0;
779*7dd7cddfSDavid du Colombier }
780*7dd7cddfSDavid du Colombier 
781*7dd7cddfSDavid du Colombier void
782*7dd7cddfSDavid du Colombier addmachine(char *name)
783*7dd7cddfSDavid du Colombier {
784*7dd7cddfSDavid du Colombier 	if(ngraph > 0){
785*7dd7cddfSDavid du Colombier 		fprint(2, "stats: internal error: ngraph>0 in addmachine()\n");
786*7dd7cddfSDavid du Colombier 		usage();
787*7dd7cddfSDavid du Colombier 	}
788*7dd7cddfSDavid du Colombier 	if(mach == nil)
789*7dd7cddfSDavid du Colombier 		nmach = 0;	/* a little dance to get us started with local machine by default */
790*7dd7cddfSDavid du Colombier 	mach = erealloc(mach, (nmach+1)*sizeof(Machine));
791*7dd7cddfSDavid du Colombier 	memset(mach+nmach, 0, sizeof(Machine));
792*7dd7cddfSDavid du Colombier 	initmach(mach+nmach, name);
793*7dd7cddfSDavid du Colombier 	nmach++;
794*7dd7cddfSDavid du Colombier }
795*7dd7cddfSDavid du Colombier 
796*7dd7cddfSDavid du Colombier void
797*7dd7cddfSDavid du Colombier resize(void)
798*7dd7cddfSDavid du Colombier {
799*7dd7cddfSDavid du Colombier 	int i, j, n, startx, starty, x, y, dx, dy, ondata;
800*7dd7cddfSDavid du Colombier 	Graph *g;
801*7dd7cddfSDavid du Colombier 	Rectangle machr, r;
802*7dd7cddfSDavid du Colombier 	long v, vmax;
803*7dd7cddfSDavid du Colombier 	char buf[128];
804*7dd7cddfSDavid du Colombier 
805*7dd7cddfSDavid du Colombier 	draw(screen, screen->r, display->white, nil, ZP);
806*7dd7cddfSDavid du Colombier 
807*7dd7cddfSDavid du Colombier 	/* label left edge */
808*7dd7cddfSDavid du Colombier 	x = screen->r.min.x;
809*7dd7cddfSDavid du Colombier 	y = screen->r.min.y + Labspace+mediumfont->height+Labspace;
810*7dd7cddfSDavid du Colombier 	dy = (screen->r.max.y - y)/ngraph;
811*7dd7cddfSDavid du Colombier 	dx = Labspace+stringwidth(mediumfont, "0")+Labspace;
812*7dd7cddfSDavid du Colombier 	startx = x+dx+1;
813*7dd7cddfSDavid du Colombier 	starty = y;
814*7dd7cddfSDavid du Colombier 	for(i=0; i<ngraph; i++,y+=dy){
815*7dd7cddfSDavid du Colombier 		draw(screen, Rect(x, y-1, screen->r.max.x, y), display->black, nil, ZP);
816*7dd7cddfSDavid du Colombier 		draw(screen, Rect(x, y, x+dx, screen->r.max.y), cols[graph[i].colindex][0], nil, paritypt(x));
817*7dd7cddfSDavid du Colombier 		label(Pt(x, y), dy, graph[i].label);
818*7dd7cddfSDavid du Colombier 		draw(screen, Rect(x+dx, y, x+dx+1, screen->r.max.y), cols[graph[i].colindex][2], nil, ZP);
819*7dd7cddfSDavid du Colombier 	}
820*7dd7cddfSDavid du Colombier 
821*7dd7cddfSDavid du Colombier 	/* label top edge */
822*7dd7cddfSDavid du Colombier 	dx = (screen->r.max.x - startx)/nmach;
823*7dd7cddfSDavid du Colombier 	for(x=startx, i=0; i<nmach; i++,x+=dx){
824*7dd7cddfSDavid du Colombier 		draw(screen, Rect(x-1, starty-1, x, screen->r.max.y), display->black, nil, ZP);
825*7dd7cddfSDavid du Colombier 		j = dx/stringwidth(mediumfont, "0");
826*7dd7cddfSDavid du Colombier 		n = mach[i].nproc;
827*7dd7cddfSDavid du Colombier 		if(n>1 && j>=1+3+(n>10)+(n>100)){	/* first char of name + (n) */
828*7dd7cddfSDavid du Colombier 			j -= 3+(n>10)+(n>100);
829*7dd7cddfSDavid du Colombier 			if(j <= 0)
830*7dd7cddfSDavid du Colombier 				j = 1;
831*7dd7cddfSDavid du Colombier 			snprint(buf, sizeof buf, "%.*s(%d)", j, mach[i].name, n);
832*7dd7cddfSDavid du Colombier 		}else
833*7dd7cddfSDavid du Colombier 			snprint(buf, sizeof buf, "%.*s", j, mach[i].name);
834*7dd7cddfSDavid du Colombier 		string(screen, Pt(x+Labspace, screen->r.min.y + Labspace), display->black, ZP, mediumfont, buf);
835*7dd7cddfSDavid du Colombier 	}
836*7dd7cddfSDavid du Colombier 
837*7dd7cddfSDavid du Colombier 	/* create graphs */
838*7dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++){
839*7dd7cddfSDavid du Colombier 		machr = Rect(startx+i*dx, starty, screen->r.max.x, screen->r.max.y);
840*7dd7cddfSDavid du Colombier 		if(i < nmach-1)
841*7dd7cddfSDavid du Colombier 			machr.max.x = startx+(i+1)*dx - 1;
842*7dd7cddfSDavid du Colombier 		y = starty;
843*7dd7cddfSDavid du Colombier 		for(j=0; j<ngraph; j++, y+=dy){
844*7dd7cddfSDavid du Colombier 			g = &graph[i*ngraph+j];
845*7dd7cddfSDavid du Colombier 			/* allocate data */
846*7dd7cddfSDavid du Colombier 			ondata = g->ndata;
847*7dd7cddfSDavid du Colombier 			g->ndata = Dx(machr)+1;	/* may be too many if label will be drawn here; so what? */
848*7dd7cddfSDavid du Colombier 			g->data = erealloc(g->data, g->ndata*sizeof(long));
849*7dd7cddfSDavid du Colombier 			if(g->ndata > ondata)
850*7dd7cddfSDavid du Colombier 				memset(g->data+ondata, 0, (g->ndata-ondata)*sizeof(long));
851*7dd7cddfSDavid du Colombier 			/* set geometry */
852*7dd7cddfSDavid du Colombier 			g->r = machr;
853*7dd7cddfSDavid du Colombier 			g->r.min.y = y;
854*7dd7cddfSDavid du Colombier 			g->r.max.y = y+dy - 1;
855*7dd7cddfSDavid du Colombier 			if(j == ngraph-1)
856*7dd7cddfSDavid du Colombier 				g->r.max.y = screen->r.max.y;
857*7dd7cddfSDavid du Colombier 			draw(screen, g->r, cols[g->colindex][0], nil, paritypt(g->r.min.x));
858*7dd7cddfSDavid du Colombier 			g->overflow = 0;
859*7dd7cddfSDavid du Colombier 			r = g->r;
860*7dd7cddfSDavid du Colombier 			r.max.y = r.min.y+mediumfont->height;
861*7dd7cddfSDavid du Colombier 			r.max.x = r.min.x+stringwidth(mediumfont, "9999999");
862*7dd7cddfSDavid du Colombier 			freeimage(g->overtmp);
863*7dd7cddfSDavid du Colombier 			g->overtmp = nil;
864*7dd7cddfSDavid du Colombier 			if(r.max.x <= g->r.max.x)
865*7dd7cddfSDavid du Colombier 				g->overtmp = allocimage(display, r, screen->chan, 0, -1);
866*7dd7cddfSDavid du Colombier 			g->newvalue(g->mach, &v, &vmax);
867*7dd7cddfSDavid du Colombier 			redraw(g, vmax);
868*7dd7cddfSDavid du Colombier 		}
869*7dd7cddfSDavid du Colombier 	}
870*7dd7cddfSDavid du Colombier 
871*7dd7cddfSDavid du Colombier 	flushimage(display, 1);
872*7dd7cddfSDavid du Colombier }
873*7dd7cddfSDavid du Colombier 
874*7dd7cddfSDavid du Colombier void
875*7dd7cddfSDavid du Colombier eresized(int new)
876*7dd7cddfSDavid du Colombier {
877*7dd7cddfSDavid du Colombier 	lockdisplay(display);
878*7dd7cddfSDavid du Colombier 	if(new && getwindow(display, Refnone) < 0) {
879*7dd7cddfSDavid du Colombier 		fprint(2, "stats: can't reattach to window\n");
880*7dd7cddfSDavid du Colombier 		killall("reattach");
881*7dd7cddfSDavid du Colombier 	}
882*7dd7cddfSDavid du Colombier 	resize();
883*7dd7cddfSDavid du Colombier 	unlockdisplay(display);
884*7dd7cddfSDavid du Colombier }
885*7dd7cddfSDavid du Colombier 
886*7dd7cddfSDavid du Colombier void
887*7dd7cddfSDavid du Colombier mouseproc(void)
888*7dd7cddfSDavid du Colombier {
889*7dd7cddfSDavid du Colombier 	Mouse mouse;
890*7dd7cddfSDavid du Colombier 	int i;
891*7dd7cddfSDavid du Colombier 
892*7dd7cddfSDavid du Colombier 	for(;;){
893*7dd7cddfSDavid du Colombier 		mouse = emouse();
894*7dd7cddfSDavid du Colombier 		if(mouse.buttons == 4){
895*7dd7cddfSDavid du Colombier 			lockdisplay(display);
896*7dd7cddfSDavid du Colombier 			for(i=0; i<Nmenu2; i++)
897*7dd7cddfSDavid du Colombier 				if(present[i])
898*7dd7cddfSDavid du Colombier 					memmove(menu2str[i], "drop ", Opwid);
899*7dd7cddfSDavid du Colombier 				else
900*7dd7cddfSDavid du Colombier 					memmove(menu2str[i], "add  ", Opwid);
901*7dd7cddfSDavid du Colombier 			i = emenuhit(3, &mouse, &menu2);
902*7dd7cddfSDavid du Colombier 			if(i >= 0){
903*7dd7cddfSDavid du Colombier 				if(!present[i])
904*7dd7cddfSDavid du Colombier 					addgraph(i);
905*7dd7cddfSDavid du Colombier 				else if(ngraph > 1)
906*7dd7cddfSDavid du Colombier 					dropgraph(i);
907*7dd7cddfSDavid du Colombier 				resize();
908*7dd7cddfSDavid du Colombier 			}
909*7dd7cddfSDavid du Colombier 			unlockdisplay(display);
910*7dd7cddfSDavid du Colombier 		}
911*7dd7cddfSDavid du Colombier 	}
912*7dd7cddfSDavid du Colombier }
913*7dd7cddfSDavid du Colombier 
914*7dd7cddfSDavid du Colombier void
915*7dd7cddfSDavid du Colombier startproc(void (*f)(void), int index)
916*7dd7cddfSDavid du Colombier {
917*7dd7cddfSDavid du Colombier 	int pid;
918*7dd7cddfSDavid du Colombier 
919*7dd7cddfSDavid du Colombier 	switch(pid = rfork(RFPROC|RFMEM|RFNOWAIT)){
920*7dd7cddfSDavid du Colombier 	case -1:
921*7dd7cddfSDavid du Colombier 		fprint(2, "stats: fork failed: %r\n");
922*7dd7cddfSDavid du Colombier 		killall("fork failed");
923*7dd7cddfSDavid du Colombier 	case 0:
924*7dd7cddfSDavid du Colombier 		f();
925*7dd7cddfSDavid du Colombier 		fprint(2, "stats: %s process exits\n", procnames[index]);
926*7dd7cddfSDavid du Colombier 		if(index >= 0)
927*7dd7cddfSDavid du Colombier 			killall("process died");
928*7dd7cddfSDavid du Colombier 		exits(nil);
929*7dd7cddfSDavid du Colombier 	}
930*7dd7cddfSDavid du Colombier 	if(index >= 0)
931*7dd7cddfSDavid du Colombier 		pids[index] = pid;
932*7dd7cddfSDavid du Colombier }
933*7dd7cddfSDavid du Colombier 
934*7dd7cddfSDavid du Colombier void
935*7dd7cddfSDavid du Colombier main(int argc, char *argv[])
936*7dd7cddfSDavid du Colombier {
937*7dd7cddfSDavid du Colombier 	int i, j;
938*7dd7cddfSDavid du Colombier 	long v, vmax, nargs;
939*7dd7cddfSDavid du Colombier 	char args[100];
940*7dd7cddfSDavid du Colombier 
941*7dd7cddfSDavid du Colombier 	nmach = 1;
942*7dd7cddfSDavid du Colombier 	mysysname = getenv("sysname");
943*7dd7cddfSDavid du Colombier 	if(mysysname == nil){
944*7dd7cddfSDavid du Colombier 		fprint(2, "stats: can't find $sysname: %r\n");
945*7dd7cddfSDavid du Colombier 		exits("sysname");
946*7dd7cddfSDavid du Colombier 	}
947*7dd7cddfSDavid du Colombier 	mysysname = estrdup(mysysname);
948*7dd7cddfSDavid du Colombier 
949*7dd7cddfSDavid du Colombier 	nargs = 0;
950*7dd7cddfSDavid du Colombier 	ARGBEGIN{
951*7dd7cddfSDavid du Colombier 	default:
952*7dd7cddfSDavid du Colombier 		if(nargs>=sizeof args || strchr(argchars, ARGC())==nil)
953*7dd7cddfSDavid du Colombier 			usage();
954*7dd7cddfSDavid du Colombier 		args[nargs++] = ARGC();
955*7dd7cddfSDavid du Colombier 	}ARGEND
956*7dd7cddfSDavid du Colombier 
957*7dd7cddfSDavid du Colombier 	if(argc == 0){
958*7dd7cddfSDavid du Colombier 		mach = emalloc(nmach*sizeof(Machine));
959*7dd7cddfSDavid du Colombier 		initmach(&mach[0], mysysname);
960*7dd7cddfSDavid du Colombier 		readmach(&mach[0], 1);
961*7dd7cddfSDavid du Colombier 	}else{
962*7dd7cddfSDavid du Colombier 		for(i=0; i<argc; i++){
963*7dd7cddfSDavid du Colombier 			addmachine(argv[i]);
964*7dd7cddfSDavid du Colombier 			readmach(&mach[i], 1);
965*7dd7cddfSDavid du Colombier 		}
966*7dd7cddfSDavid du Colombier 	}
967*7dd7cddfSDavid du Colombier 
968*7dd7cddfSDavid du Colombier 	for(i=0; i<nargs; i++)
969*7dd7cddfSDavid du Colombier 	switch(args[i]){
970*7dd7cddfSDavid du Colombier 	default:
971*7dd7cddfSDavid du Colombier 		fprint(2, "stats: internal error: unknown arg %c\n", args[i]);
972*7dd7cddfSDavid du Colombier 		usage();
973*7dd7cddfSDavid du Colombier 	case 'c':
974*7dd7cddfSDavid du Colombier 		addgraph(Mcontext);
975*7dd7cddfSDavid du Colombier 		break;
976*7dd7cddfSDavid du Colombier 	case 'e':
977*7dd7cddfSDavid du Colombier 		addgraph(Mether);
978*7dd7cddfSDavid du Colombier 		break;
979*7dd7cddfSDavid du Colombier 	case 'E':
980*7dd7cddfSDavid du Colombier 		addgraph(Metherin);
981*7dd7cddfSDavid du Colombier 		addgraph(Metherout);
982*7dd7cddfSDavid du Colombier 		break;
983*7dd7cddfSDavid du Colombier 	case 'f':
984*7dd7cddfSDavid du Colombier 		addgraph(Mfault);
985*7dd7cddfSDavid du Colombier 		break;
986*7dd7cddfSDavid du Colombier 	case 'i':
987*7dd7cddfSDavid du Colombier 		addgraph(Mintr);
988*7dd7cddfSDavid du Colombier 		break;
989*7dd7cddfSDavid du Colombier 	case 'l':
990*7dd7cddfSDavid du Colombier 		addgraph(Mload);
991*7dd7cddfSDavid du Colombier 		break;
992*7dd7cddfSDavid du Colombier 	case 'm':
993*7dd7cddfSDavid du Colombier 		addgraph(Mmem);
994*7dd7cddfSDavid du Colombier 		break;
995*7dd7cddfSDavid du Colombier 	case 'n':
996*7dd7cddfSDavid du Colombier 		addgraph(Metherin);
997*7dd7cddfSDavid du Colombier 		addgraph(Metherout);
998*7dd7cddfSDavid du Colombier 		addgraph(Methererr);
999*7dd7cddfSDavid du Colombier 		break;
1000*7dd7cddfSDavid du Colombier 	case 'p':
1001*7dd7cddfSDavid du Colombier 		addgraph(Mtlbpurge);
1002*7dd7cddfSDavid du Colombier 		break;
1003*7dd7cddfSDavid du Colombier 	case 's':
1004*7dd7cddfSDavid du Colombier 		addgraph(Msyscall);
1005*7dd7cddfSDavid du Colombier 		break;
1006*7dd7cddfSDavid du Colombier 	case 't':
1007*7dd7cddfSDavid du Colombier 		addgraph(Mtlbmiss);
1008*7dd7cddfSDavid du Colombier 		addgraph(Mtlbpurge);
1009*7dd7cddfSDavid du Colombier 		break;
1010*7dd7cddfSDavid du Colombier 	case 'w':
1011*7dd7cddfSDavid du Colombier 		addgraph(Mswap);
1012*7dd7cddfSDavid du Colombier 		break;
1013*7dd7cddfSDavid du Colombier 	}
1014*7dd7cddfSDavid du Colombier 
1015*7dd7cddfSDavid du Colombier 	if(ngraph == 0)
1016*7dd7cddfSDavid du Colombier 		addgraph(Mload);
1017*7dd7cddfSDavid du Colombier 
1018*7dd7cddfSDavid du Colombier 	for(i=0; i<nmach; i++)
1019*7dd7cddfSDavid du Colombier 		for(j=0; j<ngraph; j++)
1020*7dd7cddfSDavid du Colombier 			graph[i*ngraph+j].mach = &mach[i];
1021*7dd7cddfSDavid du Colombier 
1022*7dd7cddfSDavid du Colombier 	if(initdraw(nil, nil, "stats") < 0){
1023*7dd7cddfSDavid du Colombier 		fprint(2, "stats: initdraw failed: %r\n");
1024*7dd7cddfSDavid du Colombier 		exits("initdraw");
1025*7dd7cddfSDavid du Colombier 	}
1026*7dd7cddfSDavid du Colombier 	colinit();
1027*7dd7cddfSDavid du Colombier 	einit(Emouse);
1028*7dd7cddfSDavid du Colombier 	notify(nil);
1029*7dd7cddfSDavid du Colombier 	startproc(mouseproc, Mouseproc);
1030*7dd7cddfSDavid du Colombier 	pids[Mainproc] = getpid();
1031*7dd7cddfSDavid du Colombier 	display->locking = 1;	/* tell library we're using the display lock */
1032*7dd7cddfSDavid du Colombier 
1033*7dd7cddfSDavid du Colombier 	resize();
1034*7dd7cddfSDavid du Colombier 
1035*7dd7cddfSDavid du Colombier 	unlockdisplay(display); /* display is still locked from initdraw() */
1036*7dd7cddfSDavid du Colombier 	for(;;){
1037*7dd7cddfSDavid du Colombier 		for(i=0; i<nmach; i++)
1038*7dd7cddfSDavid du Colombier 			readmach(&mach[i], 0);
1039*7dd7cddfSDavid du Colombier 		lockdisplay(display);
1040*7dd7cddfSDavid du Colombier 		parity = 1-parity;
1041*7dd7cddfSDavid du Colombier 		for(i=0; i<nmach*ngraph; i++){
1042*7dd7cddfSDavid du Colombier 			graph[i].newvalue(graph[i].mach, &v, &vmax);
1043*7dd7cddfSDavid du Colombier 			graph[i].update(&graph[i], v, vmax);
1044*7dd7cddfSDavid du Colombier 		}
1045*7dd7cddfSDavid du Colombier 		flushimage(display, 1);
1046*7dd7cddfSDavid du Colombier 		unlockdisplay(display);
1047*7dd7cddfSDavid du Colombier 		sleep(1000);
1048*7dd7cddfSDavid du Colombier 	}
1049*7dd7cddfSDavid du Colombier }
1050