xref: /plan9-contrib/sys/src/cmd/stats.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <u.h>
2 #include <libc.h>
3 #include <libg.h>
4 
5 #define Min(a, b)	((a) < (b) ? (a) : (b))
6 int *vector;
7 int nvec;
8 int cmax = 1;
9 Rectangle scroll;
10 int height;
11 int lasttype = -1;
12 int type;
13 char *mon;
14 Point pbot, ptop;
15 int ys[4];
16 
17 char   *getstr(int);
18 void	reshape(Rectangle);
19 int	getstat(void);
20 int	inittype(int);
21 void	ignore(void*, char*);
22 void	mousepkt(int, char*);
23 int	sysfield(int, int);
24 
25 enum
26 {
27 	Memory=0,
28 	Ether,
29 	Swap,
30 	Contxt,	 /* Code relies on the order of these up to load - Dont move! */
31 	Intr,
32 	Syscall,
33 	Fault,
34 	Tlbfault,
35 	Tlbpurge,
36 	Load,
37 	Ntype
38 };
39 
40 void
41 main(int argc, char **argv)
42 {
43 	int l, t, n, ms, scaled, i;
44 	char buf[128];
45 	Point p1;
46 
47 	ARGBEGIN{
48 	case 'm':
49 		type = Memory;
50 		break;
51 	case 'w':
52 		type = Swap;
53 		break;
54 	case 'e':
55 		type = Ether;
56 		break;
57 	case 'c':
58 		type = Contxt;
59 		break;
60 	case 'i':
61 		type = Intr;
62 		break;
63 	case 's':
64 		type = Syscall;
65 		break;
66 	case 'f':
67 		type = Fault;
68 		break;
69 	case 't':
70 		type = Tlbfault;
71 		break;
72 	case 'p':
73 		type = Tlbpurge;
74 		break;
75 	case 'l':
76 		type = Load;
77 		break;
78 	default:
79 		fprint(2, "usage: stats [-mwecisftpl]\n");
80 		exits("usage");
81 	}ARGEND
82 
83 	binit(0, 0, "stats");
84 
85 	ms = open("/dev/mouse", OREAD);
86 	if(ms < 0) {
87 		perror("open mouse");
88 		exits("mouse");
89 	}
90 
91 	reshape(screen.r);
92 
93 	notify(ignore);
94 
95 	for(;;) {
96 		if(vector[nvec-1] == cmax) {
97 			cmax = 0;
98 			for(i = 0; i < nvec-1; i++)
99 				if(vector[i] > cmax)
100 					cmax = vector[i];
101 			reshape(screen.r);
102 		}
103 
104 		l = vector[0];
105 		memmove(vector+1, vector, sizeof(int) * (nvec-1));
106 		vector[0] = getstat();
107 		vector[0] = l+(vector[0]-l)/2;
108 
109 		if(vector[0] > cmax) {
110 			cmax = vector[0];
111 			reshape(screen.r);
112 		}
113 		segment(&screen, ptop, pbot, 1, Zero);
114 		scaled = (vector[0]*height)/cmax;
115 		segment(&screen, pbot, sub(pbot, Pt(0, scaled)), 1, F);
116 		for(i = 0; i < 4; i++)
117 			point(&screen, Pt(ptop.x, ys[i]), 0xff, F);
118 		p1 = scroll.min;
119 		p1.x--;
120 		bitblt(&screen, p1, &screen, scroll, S);
121 
122 		sprint(buf, "%d %s", cmax, mon);
123 		string(&screen, scroll.min, font, buf, S);
124 		bflush();
125 		do {
126 			alarm(1000);
127 			n = read(ms, buf, sizeof(buf));
128 			if(n >= 14) {
129 				t = alarm(0);
130 				if(t == 0)
131 					t = 1000;
132 				mousepkt(ms, buf);
133 				alarm(t);
134 			}
135 		}while(n > 0);
136 	}
137 }
138 
139 void
140 mousepkt(int ms, char *buf)
141 {
142 	if(buf[0] != 'm')
143 		return;
144 	if(buf[1] & 0x80) {			/* Reshaped */
145 		reshape(bscreenrect(0));
146 		return;
147 	}
148 	if(buf[1] & 0x07) {			/* Button */
149 		type++;
150 		if(type == Ntype)
151 			type = 0;
152 		/* wait for button up */
153 		while(read(ms, buf, 14) == 14 && (buf[1] & 0x07))
154 			;
155 	}
156 }
157 
158 void
159 reshape(Rectangle r)
160 {
161 	int *newvector;
162 	Point p1, p2;
163 	int q, i, width, scaled;
164 
165 	if(cmax == 0)
166 		cmax = 1;
167 
168 	screen.r = r;
169 	scroll = inset(r, 4);
170 	height = scroll.max.y - scroll.min.y;
171 	width = scroll.max.x - scroll.min.x;
172 
173 	newvector = malloc(width*sizeof(int));
174 	memset(newvector, 0, width*sizeof(int));
175 	if(vector) {
176 		memmove(newvector, vector, Min(width, nvec)*sizeof(int));
177 		free(vector);
178 	}
179 	nvec = width;
180 	vector = newvector;
181 
182 	bitblt(&screen, screen.r.min, &screen, screen.r, Zero);
183 	border(&screen, screen.r, 1, F);
184 
185 	p1 = scroll.min;
186 	p2 = Pt(scroll.max.x, scroll.min.y);
187 	q = height/4;
188 	for(i = 0; i < 4; i++) {
189 		segment(&screen, p1, p2, 0xff, F);
190 		ys[i] = p1.y;
191 		p1.y += q;
192 		p2.y += q;
193 	}
194 
195 	ptop.x = scroll.max.x-1;
196 	pbot.x = ptop.x;
197 	ptop.y = scroll.min.y;
198 	pbot.y = scroll.max.y;
199 
200 	p1 = pbot;
201 	for(i = 0; i < nvec; i++) {
202 		scaled = (vector[i]*height)/cmax;
203 		segment(&screen, p1, sub(p1, Pt(0, scaled)), 1, F);
204 		p1.x -= 1;
205 	}
206 }
207 
208 int
209 getstat(void)
210 {
211 	static int fd, nfd;
212 	static int lastval;
213 	int newval, val;
214 	char *s;
215 
216 	if(type != lasttype) {
217 		for(;;) {
218 			close(fd);
219 			fd = inittype(type);
220 			if(fd >= 0)
221 				break;
222 			type++;
223 			if(type == Ntype)
224 				type = Memory;
225 		}
226 		lasttype = type;
227 		lastval = 0;
228 	}
229 
230 	switch(type) {
231 	case Memory:
232 		s = getstr(fd);
233 		return atoi(s);
234 	case Swap:
235 		s = getstr(fd);
236 		s = strchr(s, 'y');
237 		s++;
238 		return atoi(s);
239 	case Ether:
240 		s = getstr(fd);
241 		s = strchr(s, ':');	/* In */
242 		val = atoi(s+1);
243 		s = strchr(s, ':');	/* Out */
244 		val += atoi(s+1);
245 		if(lastval == 0)
246 			lastval = val;
247 		newval = val-lastval;
248 		lastval = val;
249 		return newval;
250 	case Contxt:
251 	case Intr:
252 	case Syscall:
253 	case Fault:
254 	case Tlbfault:
255 	case Tlbpurge:
256 		val = sysfield(fd, type-Contxt+1);
257 		if(lastval == 0)
258 			lastval = val;
259 		newval = val-lastval;
260 		lastval = val;
261 		return newval;
262 	case Load:
263 		return sysfield(fd, 7);
264 	}
265 }
266 
267 int
268 inittype(int type)
269 {
270 	char *s;
271 	int f;
272 
273 	f = -1;
274 	memset(vector, 0, nvec*sizeof(int));
275 	switch(type) {
276 	case Memory:
277 		mon = "mem";
278 		f = open("/dev/swap", OREAD);
279 		s = getstr(f);
280 		s = strchr(s, '/');
281 		s++;
282 		cmax = atoi(s);
283 		reshape(screen.r);
284 		break;
285 	case Swap:
286 		mon = "swap";
287 		f = open("/dev/swap", OREAD);
288 		s = getstr(f);
289 		s = strchr(s, 'y');
290 		s = strchr(s, '/');
291 		s++;
292 		cmax = atoi(s);
293 		reshape	(screen.r);
294 		break;
295 	case Ether:
296 		mon = "ether";
297 		f = open("#l/ether/0/stats", OREAD);
298 		cmax = 1;
299 		reshape	(screen.r);
300 		break;
301 	case Contxt:
302 		mon = "contxt";
303 		f = open("/dev/sysstat", OREAD);
304 		cmax = 1;
305 		reshape	(screen.r);
306 		break;
307 	case Intr:
308 		mon = "intr";
309 		f = open("/dev/sysstat", OREAD);
310 		cmax = 1;
311 		reshape	(screen.r);
312 		break;
313 	case Syscall:
314 		mon = "syscall";
315 		f = open("/dev/sysstat", OREAD);
316 		cmax = 1;
317 		reshape	(screen.r);
318 		break;
319 	case Fault:
320 		mon = "fault";
321 		f = open("/dev/sysstat", OREAD);
322 		cmax = 1;
323 		reshape	(screen.r);
324 		break;
325 	case Tlbfault:
326 		mon = "tlbmiss";
327 		f = open("/dev/sysstat", OREAD);
328 		cmax = 1;
329 		reshape	(screen.r);
330 		break;
331 	case Tlbpurge:
332 		mon = "tlbpurge";
333 		f = open("/dev/sysstat", OREAD);
334 		cmax = 1;
335 		reshape	(screen.r);
336 		break;
337 	case Load:
338 		mon = "load";
339 		f = open("/dev/sysstat", OREAD);
340 		cmax = 1;
341 		reshape	(screen.r);
342 		break;
343 	}
344 	if(f < 0) {
345 		fprint(2, "stats: %s: %r", mon);
346 		sleep(500);
347 	}
348 
349 	return f;
350 }
351 
352 int
353 sysfield(int fd, int nr)
354 {
355 	int val = 0;
356 	char *s;
357 
358 	s = getstr(fd);
359 	for(;;) {
360 		val += atoi(s+(nr*12));
361 		s = strchr(s, '\n');
362 		if(s == 0 || *++s == '\0')
363 			break;
364 		s++;
365 	};
366 	return val;
367 }
368 
369 char *
370 getstr(int fd)
371 {
372 	static char buf[1000];
373 	int n;
374 
375 	if(seek(fd, 0, 0) < 0)
376 		exits("getstr: seek");
377 	n = read(fd, buf, sizeof(buf));
378 	if(n < 0)
379 		exits("getstr: read");
380 	buf[n] = 0;
381 	return buf;
382 }
383 
384 void
385 ignore(void *a, char *c)
386 {
387 	USED(a);
388 	if(strcmp(c, "alarm") == 0)
389 		noted(NCONT);
390 
391 	noted(NDFLT);
392 }
393