BSD 4_3_Tahoe development
[unix-history] / usr / src / new / X / xperfmon / xperfmon.c
CommitLineData
da47b949
C
1/* Copyright 1985, Massachusetts Institute of Technology */
2
3/*
4 * X Unix performance monitor.
5 */
6
7#ifndef lint
8static char *rcsid_xperfmon_c = "$Header: xperfmon.c,v 10.13 86/11/25 18:31:37 jg Rel $";
9#endif lint
10
11/*
12 * Simple graphical performance monitor for system-wide data.
13 */
14
15#include <stdio.h>
16#include <sys/param.h>
17#include <sys/socket.h>
18#include <sys/vm.h>
19#include <sys/dkstat.h>
20#include <nlist.h>
21#include <sys/buf.h>
22#ifdef vax
23#include <vaxuba/ubavar.h>
24#include <vaxmba/mbavar.h>
25#endif vax
26#ifdef sun
27#include <sundev/mbvar.h>
28#endif sun
29#ifdef ibm032 /* IBM RT/PC */
30#include <caio/ioccvar.h>
31#endif ibm032
32#ifdef tahoe
33#include <tahoevba/vbavar.h>
34#endif
35#include <X/Xlib.h>
36#include <net/if.h>
37#include <netinet/in.h>
38#include <sys/file.h>
39#include <sys/time.h>
40
41#include <strings.h>
42
43#define USEC_INC 50000
44#define SEC_INC 1
45
46struct packet {
47 int input, output, collisions;
48};
49static struct packet packets, old_packets;
50
51#define NUM_VALS_PER 1000
52struct statistic {
53 int min_val, max_val;
54 int value[NUM_VALS_PER];
55 char *label, *label2;
56};
57
58#define SECS_PER_TIME_TICK 10
59static char do_time[NUM_VALS_PER];
60static struct timeval current_time, saved_time;
61static struct timezone dummy_zone;
62
63short gray_bits[16] = {
64 0xaaaa, 0x5555, 0xaaaa, 0x5555,
65 0xaaaa, 0x5555, 0xaaaa, 0x5555,
66 0xaaaa, 0x5555, 0xaaaa, 0x5555,
67 0xaaaa, 0x5555, 0xaaaa, 0x5555};
68
69/*
70 * The array stats always has valid info for stats[i], 0 <= i < num_stats.
71 * For each valid stats[i], stats[i].value[j] is valid for 0 <= j < num_of_val.
72 * The info for the k-th possible statistic of interest is recorded, if it is
73 * recorded at all, in stats[possible_stats[k]].
74 */
75
76#define NO_STAT -1
77#define USER_CPU_PERCENTAGE 0
78#define SYSTEM_CPU_PERCENTAGE 1
79#define IDLE_CPU_PERCENTAGE 2
80#define FREE_MEM 3
81#define DISK_TRANSFERS 4
82#define INTERRUPTS 5
83#define INPUT_PACKETS 6
84#define OUTPUT_PACKETS 7
85#define COLLISION_PACKETS 8
86#define NUM_POSSIBLE_STATS 9
87static int possible_stats[NUM_POSSIBLE_STATS];
88#define WANT_STAT(x) (possible_stats[(x)] != NO_STAT)
89
90#define MAX_STATS 10
91
92#define DEFAULT_BORDER_WIDTH 3
93#define DEFAULT_POSITION "=%dx%d-0+0"
94
95static struct statistic stats[MAX_STATS];
96
97static struct timeval timeout = {
98 SEC_INC,USEC_INC};
99static int num_stats, num_of_val = 0;
100static int graph_x_offset = 0;
101WindowInfo WInfo;
102
103Window Win;
104char Host[40];
105char *font_name = "6x10";
106int background; /* color of background */
107int foreground; /* color of graph */
108int highlight; /* color of text, scale */
109FontInfo *finfo; /* font information needed */
110int debug = 0;
111#define max(a,b) (a>b ? a:b)
112
113OpaqueFrame win;
114
115#define FORALLPOSSIBLESTATS(stat)\
116 for (stat = 0; stat < NUM_POSSIBLE_STATS; stat++)
117#define FORALLSTATS(stat) for (stat = 0; stat < num_stats; stat++)
118
119struct nlist nl[] = {
120#define X_CPTIME 0
121 { "_cp_time" },
122#define X_RATE 1
123 { "_rate" },
124#define X_TOTAL 2
125 { "_total" },
126#define X_DEFICIT 3
127 { "_deficit" },
128#define X_FORKSTAT 4
129 { "_forkstat" },
130#define X_SUM 5
131 { "_sum" },
132#define X_FIRSTFREE 6
133 { "_firstfree" },
134#define X_MAXFREE 7
135 { "_maxfree" },
136#define X_BOOTTIME 8
137 { "_boottime" },
138#define X_DKXFER 9
139 { "_dk_xfer" },
140#define X_REC 10
141 { "_rectime" },
142#define X_PGIN 11
143 { "_pgintime" },
144#define X_HZ 12
145 { "_hz" },
146#define X_MBDINIT 13
147 { "_mbdinit" },
148#define N_IFNET 14
149 { "_ifnet" },
150#define X_UBDINIT 15
151 { "_ubdinit" },
152#define X_IOCINIT 16
153 { "_ioccdinit" },
154#define X_VBDINIT 17
155 { "_vbdinit" },
156 { "" },
157};
158
159char dr_name[DK_NDRIVE][10];
160char dr_unit[DK_NDRIVE];
161double stat1();
162int maxfree;
163int hz;
164struct
165{
166 int busy;
167 long time[CPUSTATES];
168 long xfer[DK_NDRIVE];
169 struct vmmeter Rate;
170 struct vmtotal Total;
171 struct vmmeter Sum;
172 struct forkstat Forkstat;
173 unsigned rectime;
174 unsigned pgintime;
175}
176s, s1;
177#define rate s.Rate
178#define total s.Total
179#define sum s.Sum
180#define forkstat s.Forkstat
181
182struct vmmeter osum;
183int deficit;
184double etime;
185int mf;
186int swflag;
187
188int nintv;
189long t;
190
191#define steal(where, var) lseek(mf, where, 0); read(mf, &var, sizeof var);
192#define pgtok(a) ((a)*NBPG/1024)
193
194char *options[NUM_POSSIBLE_STATS+1] = {
195 "user", "system", "idle", "free", "disk", "interrupts",
196 "input", "output", "collision",
197 0 /* Terminator! */ };
198
199short arrow []= {0x0000, 0x0020, 0x0070, 0x00f8, 0x01fc, 0x03fe, 0x0070,
200 0x0070, 0x0070, 0x0070, 0x0070, 0x0070, 0x0070, 0x0000};
201short mask []= {0x0020, 0x0070, 0x00f8, 0x01fc, 0x03fe, 0x07ff, 0x07ff,
202 0x00f8, 0x00f8, 0x00f8, 0x00f8, 0x00f8, 0x00f8, 0x00f8};
203
204
205main(argc, argv)
206int argc;
207char **argv;
208{
209 int stat;
210 int have_disk;
211 struct timeval timeleft;
212 char display[40];
213 char *strind;
214 int Select_mask, select_mask = 0;
215 int maxplus1, n;
216 Cursor cursor;
217 char *geometry = NULL; /* location of window */
218 char def[32];
219 int reverse = 0;
220 double update = -1.;
221 double atof();
222 char *border_color;
223 char *fore_color;
224 char *back_color;
225 char *high_color;
226 Pixmap border_pixmap;
227 char *option;
228 int opt;
229 int i;
230 int minheight, minwidth;
231
232 Color cdef;
233 int border_width = DEFAULT_BORDER_WIDTH;
234
235 display[0] = '\0';
236
237 if ((option = XGetDefault(argv[0],"ReverseVideo")) != NULL )
238 if (strcmp (option, "on") == 0)
239 reverse = 1;
240 if ((option = XGetDefault(argv[0],"BorderWidth")) != NULL)
241 border_width = atoi(option);
242 if ((option = XGetDefault(argv[0],"BodyFont")) != NULL)
243 font_name = option;
244 if ((border_color = XGetDefault(argv[0],"Border")) == NULL)
245 border_color = XGetDefault(argv[0],"BorderColor");
246 back_color = XGetDefault(argv[0],"Background");
247 fore_color = XGetDefault(argv[0],"Foreground");
248 high_color = XGetDefault(argv[0],"Highlight");
249 if ((option = XGetDefault(argv[0],"Update")) != NULL)
250 update = atof(option);
251
252 nintv = get_namelist("/vmunix", "/dev/kmem");
253 collect_stats();
254 etime = 1.0;
255 have_disk = (total_disk_transfers() ? 1 : 0);
256
257 /* Initialize stats */
258 FORALLPOSSIBLESTATS(stat)
259 possible_stats[stat] = NO_STAT;
260 num_stats = 0;
261 for (i = 1; i < argc; i++) { /* Parse line */
262 if (argv[i][0] == '=') {
263 geometry = argv[i];
264 continue;
265 }
266 if (index(argv[i], ':') != NULL) { /* host:display */
267 strncpy(display, argv[i], sizeof(display));
268 continue;
269 }
270 if (strcmp(argv[i], "-rv") == 0 ||
271 strcmp(argv[i], "-reverse") == 0) { /* black on white */
272 reverse = 1;
273 continue;
274 }
275 if (strcmp(argv[i], "-fw") == 0 ||
276 strcmp(argv[i], "-forward") == 0) { /* white on black */
277 reverse = 0;
278 continue;
279 }
280 if (strcmp(argv[i], "-bw") == 0 ||
281 strcmp(argv[i], "-border") == 0) { /* border width */
282 if (++i >= argc) usage();
283 border_width = atoi(argv[i]);
284 continue;
285 }
286 if (strcmp(argv[i], "-fn") == 0 ||
287 strcmp(argv[i], "-font") == 0) { /* host name font */
288 if (++i >= argc) usage();
289 font_name = argv[i];
290 continue;
291 }
292 if (strcmp(argv[i], "-bd") == 0 ||
293 strcmp(argv[i], "-color") == 0) { /* border color */
294 if (++i >= argc) usage();
295 border_color = argv[i];
296 continue;
297 }
298 if (strcmp(argv[i], "-fg") == 0 ||
299 strcmp(argv[i], "-foreground") == 0) { /* foreground color */
300 if (++i >= argc) usage();
301 fore_color = argv[i];
302 continue;
303 }
304 if (strcmp(argv[i], "-bg") == 0 ||
305 strcmp(argv[i], "-background") == 0) { /* background color */
306 if (++i >= argc) usage();
307 back_color = argv[i];
308 continue;
309 }
310 if (strcmp(argv[i], "-hl") == 0 ||
311 strcmp(argv[i], "-highlight") == 0) { /* highlight color */
312 if (++i >= argc) usage();
313 high_color = argv[i];
314 continue;
315 }
316 if (strcmp(argv[i], "-u") == 0 ||
317 strcmp(argv[i], "-update") == 0) { /* update interval */
318 if (++i >= argc) usage();
319 update = atof(argv[i]);
320 continue;
321 }
322 opt = getcmd(argv[i], options);
323 if (opt >= 0 && opt < NUM_POSSIBLE_STATS) {
324 if (num_stats == MAX_STATS) {
325 fprintf(stderr,
326 "MAX_STATS exceeded, please recompile!\n");
327 }
328 else possible_stats[opt] = num_stats++;
329 continue;
330 }
331 usage();
332 }
333
334 if (num_stats == 0)
335 FORALLPOSSIBLESTATS(stat) {
336 if ((stat == DISK_TRANSFERS) && (have_disk == 0)) continue;
337 possible_stats[stat] = num_stats++;
338 if (num_stats == MAX_STATS) break;
339 }
340 have_disk = 0; /* so max # of packets = 40 */
341 init_stat(USER_CPU_PERCENTAGE, 100, "User", " CPU");
342 init_stat(SYSTEM_CPU_PERCENTAGE, 100, "System", " CPU");
343 init_stat(IDLE_CPU_PERCENTAGE, 100, "Idle", " CPU");
344 init_stat(FREE_MEM, pgtok(maxfree), "Free", " memory");
345 init_stat(DISK_TRANSFERS, 40, "Disk", " transfers");
346 init_stat(INTERRUPTS, 60, "Interrupts", "");
347 init_stat(INPUT_PACKETS, (have_disk ? 20 : 40), "Input", " packets");
348 init_stat(OUTPUT_PACKETS, (have_disk ? 20 : 40), "Output", " packets");
349 init_stat(COLLISION_PACKETS, 10, "Collision", " packets");
350 if (border_width < 0) border_width = DEFAULT_BORDER_WIDTH;
351 if (update > .09) {
352 timeout.tv_sec = update;
353 timeout.tv_usec = (update - (double)((int)update)) * 1000000.;
354 }
355 if (!XOpenDisplay (display)){
356 fprintf(stderr, "%s: Can't open display '%s'\n",
357 argv[0], XDisplayName(display));
358 exit(1);
359 }
360 if ((finfo = XOpenFont(font_name)) == NULL) {
361 fprintf(stderr, "Can't load font %s!\n", font_name);
362 exit(1);
363 }
364 gethostname(Host, sizeof (Host));
365 strcat(Host, ":");
366 FORALLSTATS(stat) {
367 int s_width;
368 s_width = XStringWidth (stats[stat].label, finfo, 0, 0);
369 graph_x_offset = max(graph_x_offset, s_width);
370 s_width = XStringWidth (stats[stat].label2, finfo, 0, 0);
371 graph_x_offset = max(graph_x_offset, s_width);
372 }
373 graph_x_offset += 15;
374 if(debug) fprintf(stderr, "graph_x_offset=%d\n", graph_x_offset);
375 gettimeofday(&saved_time, &dummy_zone);
376
377 if (border_color && DisplayCells() > 2 &&
378 XParseColor(border_color, &cdef) && XGetHardwareColor(&cdef))
379 border_pixmap = XMakeTile(cdef.pixel);
380 else if (border_color && strcmp(border_color, "black") == 0)
381 border_pixmap = BlackPixmap;
382 else if (border_color && strcmp(border_color, "white") == 0)
383 border_pixmap = WhitePixmap;
384 else
385 border_pixmap = XMakePixmap (
386 (Bitmap) XStoreBitmap (16, 16, gray_bits),
387 BlackPixel, WhitePixel);
388
389
390
391 if (back_color && DisplayCells() > 2 &&
392 XParseColor(back_color, &cdef) && XGetHardwareColor(&cdef)) {
393 background = cdef.pixel;
394 } else if (back_color && (strcmp(back_color, "white") == 0)) {
395 background = WhitePixel;
396 reverse = 0;
397 } else if (back_color && (strcmp(back_color, "black") == 0)) {
398 background = BlackPixel;
399 reverse = 0;
400 } else
401 background = BlackPixel;
402
403 if (fore_color && DisplayCells() > 2 &&
404 XParseColor(fore_color, &cdef) && XGetHardwareColor(&cdef)) {
405 foreground = cdef.pixel;
406 } else if (fore_color && (strcmp(fore_color, "black") == 0)) {
407 foreground = BlackPixel;
408 reverse = 0;
409 } else if (fore_color && (strcmp(fore_color, "white") == 0)) {
410 foreground = WhitePixel;
411 reverse = 0;
412 } else
413 foreground = WhitePixel;
414
415 if (high_color && DisplayCells() > 2 &&
416 XParseColor(high_color, &cdef) && XGetHardwareColor(&cdef)) {
417 highlight = cdef.pixel;
418 } else
419 highlight = foreground;
420
421 if (reverse) {
422 highlight = background;
423 background = foreground;
424 foreground = highlight;
425 }
426 win.bdrwidth = border_width;
427 win.border = border_pixmap;
428 win.background = XMakeTile(background);
429
430 minheight = (finfo->height * 2 + 2) * num_stats;
431 minwidth = graph_x_offset + 100;
432 sprintf(def, DEFAULT_POSITION, minwidth+100,
433 (finfo->height * 3 + 3) * num_stats);
434
435 Win = XCreate ("Performance Monitor", argv[0], geometry, def, &win,
436 minwidth, minheight);
437
438 win.height -= 10;
439 XMapWindow (Win);
440 cursor = XCreateCursor (11, 14, arrow, mask, 5, 1, 1, 0, GXcopyInverted);
441 XDefineCursor (Win, cursor);
442
443 redisplay (Win);
444 timeleft = timeout;
445 Select_mask = 1<<dpyno();
446 maxplus1 = 1+dpyno();
447 XSelectInput(Win, KeyPressed | ExposeWindow | ExposeCopy);
448 while(1) {
449 select_mask = Select_mask;
450 if(debug) fprintf(stderr, "time=[%d,%d]\n",
451 timeleft.tv_sec, timeleft.tv_usec);
452 XFlush();
453 if ((n = select(maxplus1, &select_mask, NULL, NULL, &timeleft))
454 < 0) exit(46);
455 if(debug)
456 fprintf(stderr,"selected n=%d mask=0x%x, time=[%d,%d]\n",
457 n, select_mask, timeleft.tv_sec, timeleft.tv_usec);
458 if (perf_mon_selected (Win, n, select_mask, &timeleft)
459 < 0) break;
460 }
461}
462
463getcmd(to_match, table) /* Modified from ucb/lpr/lpc.c */
464register char *to_match;
465register char **table;
466{
467 register char *p, *q;
468 int found, index, nmatches, longest;
469
470 longest = nmatches = 0;
471 found = index = -1;
472 for (p = *table; p; p = *(++table)) {
473 index++;
474 for (q = to_match; *q == *p++; q++)
475 if (*q == 0) /* exact match? */
476 return(index);
477 if (!*q) { /* the to_match was a prefix */
478 if (q - to_match > longest) {
479 longest = q - to_match;
480 nmatches = 1;
481 found = index;
482 }
483 else if (q - to_match == longest)
484 nmatches++;
485 }
486 }
487 if (nmatches > 1)
488 return(-1);
489 return(found);
490}
491
492init_stat(index, maxval, label_1, label_2)
493int index, maxval;
494char *label_1, *label_2;
495{
496 if WANT_STAT(index) {
497 index = possible_stats[index];
498 stats[index].max_val = maxval;
499 stats[index].label = label_1;
500 stats[index].label2 = label_2;
501 }
502}
503
504#define TIMER_EXPIRED(timer) \
505(*timer && ((*timer)->tv_sec == 0) && ((*timer)->tv_usec == 0))
506
507int perf_mon_selected(w, number, mask, timer)
508int mask, number;
509Window w;
510struct timeval *timer;
511{
512 if(number == 0) { /*timer expired */
513 int *target[CPUSTATES-1], trash;
514 collect_stats();
515 for (trash = 0; trash < CPUSTATES-1; trash++)
516 target[trash] = &trash;
517 if WANT_STAT(USER_CPU_PERCENTAGE)
518 target[0] =
519 &stats[possible_stats[USER_CPU_PERCENTAGE]].value[num_of_val];
520 if WANT_STAT(SYSTEM_CPU_PERCENTAGE)
521 target[1] =
522 &stats[possible_stats[SYSTEM_CPU_PERCENTAGE]].value[num_of_val];
523 if WANT_STAT(IDLE_CPU_PERCENTAGE)
524 target[2] =
525 &stats[possible_stats[IDLE_CPU_PERCENTAGE]].value[num_of_val];
526 copy_cpu_stats(target);
527 if WANT_STAT(FREE_MEM)
528 stats[possible_stats[FREE_MEM]].value[num_of_val] =
529 pgtok(total.t_free);
530 if WANT_STAT(DISK_TRANSFERS)
531 stats[possible_stats[DISK_TRANSFERS]].value[num_of_val] =
532 total_disk_transfers();
533 if WANT_STAT(INTERRUPTS)
534 stats[possible_stats[INTERRUPTS]].value[num_of_val] =
535 (rate.v_intr/nintv) - hz;
536 if WANT_STAT(INPUT_PACKETS)
537 stats[possible_stats[INPUT_PACKETS]].value[num_of_val] =
538 packets.input - old_packets.input;
539 if WANT_STAT(OUTPUT_PACKETS)
540 stats[possible_stats[OUTPUT_PACKETS]].value[num_of_val] =
541 packets.output - old_packets.output;
542 if WANT_STAT(COLLISION_PACKETS)
543 stats[possible_stats[COLLISION_PACKETS]].value[num_of_val] =
544 packets.collisions - old_packets.collisions;
545 gettimeofday(&current_time, &dummy_zone);
546 if (current_time.tv_sec < saved_time.tv_sec) {
547 /* Super-user must have set the clock back */
548 saved_time = current_time;
549 saved_time.tv_sec -= SECS_PER_TIME_TICK;
550 }
551 if (saved_time.tv_sec+SECS_PER_TIME_TICK <= current_time.tv_sec) {
552 saved_time = current_time;
553 do_time[num_of_val] = 1;
554 }
555 else
556 do_time[num_of_val] = 0;
557 next_display(w);
558 }
559 if (mask & (1 << dpyno())){
560 XEvent event;
561 XEvent pevent;
562 XExposeWindowEvent *exp_event;
563 int key;
564 if(!XPending()) return (-1); /* end of file on connection */
565 while (XPending())
566 {
567 XNextEvent (&event);
568 switch (event.type) {
569 case KeyPressed:
570 if ((key = mapkey(((XKeyPressedEvent *)&event)->detail)) > 0)
571 switch(key){
572 case 'f': /* faster usec timeout */
573 if (timeout.tv_usec >= USEC_INC)
574 timeout.tv_usec -= USEC_INC;
575 else {
576 if (timeout.tv_sec >= SEC_INC) {
577 timeout.tv_sec -= SEC_INC;
578 timeout.tv_usec = 1000000-USEC_INC;
579 }
580 }
581 break;
582 case 's': /* slower usec timeout */
583 if (timeout.tv_usec < 1000000-USEC_INC)
584 timeout.tv_usec += USEC_INC;
585 else {
586 timeout.tv_usec = 0;
587 timeout.tv_sec += 1;
588 }
589 break;
590 case 'F': /* faster sec timeout */
591 if (timeout.tv_sec >= SEC_INC)
592 timeout.tv_sec -= SEC_INC;
593 break;
594 case 'S': /* slower sec timeout */
595 timeout.tv_sec += SEC_INC;
596 break;
597 case 'R': /* reset */
598 timeout.tv_sec = SEC_INC;
599 timeout.tv_usec = USEC_INC;
600 num_of_val = 0;
601 redisplay(w);
602 break;
603 case 'h':
604 case 'H':
605 case '?': /* Help */
606 printf("%s\n%s\n%s\n%s\n%s\n%s\n",
607 "'s' slower usec timeout",
608 "'f' faster usec timeout",
609 "'S' slower sec timeout",
610 "'F' faster sec timeout",
611 "'R' reset timeout and display",
612 "'q' or 'Q' quit");
613 /*
614 * Don't reset timeout
615 */
616 return(0);
617 case 'q':
618 case 'Q':
619 return(-1);
620 } /* switch(key) */
621 break;
622 case ExposeWindow:
623 XSync(0);
624 while (XPending() != 0) {
625 XPeekEvent (&pevent);
626 if (pevent.type != ExposeWindow) break;
627 XNextEvent(&event);
628 }
629
630 exp_event = (XExposeWindowEvent *) &event;
631 win.x = exp_event->x;
632 win.y = exp_event->y;
633 win.width = exp_event->width;
634 win.height = exp_event->height - 10;
635 redisplay(w);
636 break;
637 default:
638 break;
639 }
640 }
641 }
642 *timer = timeout;
643 return(0);
644}
645
646int total_disk_transfers()
647{
648 register int i, total_xfers = 0;
649
650 for(i=0; i < DK_NDRIVE; i++)
651 total_xfers += s.xfer[i];
652 return(total_xfers/etime);
653}
654
655copy_cpu_stats(stat)
656int *stat[CPUSTATES-1];
657{
658 register int i;
659
660 for(i=0; i<CPUSTATES; i++) {
661 float f = stat1(i);
662 if (i == 0) { /* US+NI */
663 i++;
664 f += stat1(i);
665 }
666 if (stat[i-1] != 0)
667 *stat[i-1] = f;
668 }
669}
670
671collect_stats()
672{
673
674 off_t ifnetaddr = (long)nl[N_IFNET].n_value;
675
676 register int i;
677
678 lseek(mf, (long)nl[X_CPTIME].n_value, 0);
679 read(mf, s.time, sizeof s.time);
680 lseek(mf, (long)nl[X_DKXFER].n_value, 0);
681 read(mf, s.xfer, sizeof s.xfer);
682 if (nintv != 1) {
683 steal((long)nl[X_SUM].n_value, rate);
684 }
685 else {
686 steal((long)nl[X_RATE].n_value, rate);
687 }
688 steal((long)nl[X_TOTAL].n_value, total);
689 osum = sum;
690 steal((long)nl[X_SUM].n_value, sum);
691 steal((long)nl[X_DEFICIT].n_value, deficit);
692 etime = 0;
693 for (i=0; i < DK_NDRIVE; i++) {
694 t = s.xfer[i];
695 s.xfer[i] -= s1.xfer[i];
696 s1.xfer[i] = t;
697 }
698 for (i=0; i < CPUSTATES; i++) {
699 t = s.time[i];
700 s.time[i] -= s1.time[i];
701 s1.time[i] = t;
702 etime += s.time[i];
703 }
704 if(etime == 0.)
705 etime = 1.;
706 etime /= 60.;
707 nintv = 1;
708
709 if (nl[N_IFNET].n_value != 0) {
710 struct ifnet ifnet;
711 steal((long)nl[N_IFNET].n_value, ifnetaddr);
712 old_packets = packets;
713 packets.input = packets.output = packets.collisions = 0;
714 while (ifnetaddr) {
715 steal(ifnetaddr, ifnet);
716 packets.input += ifnet.if_ipackets;
717 packets.output += ifnet.if_opackets;
718 packets.collisions += ifnet.if_collisions;
719 ifnetaddr = (off_t) ifnet.if_next;
720 }
721 }
722
723}
724
725min (a, b)
726 int a,b;
727{
728 return(a<b ? a:b);
729}
730
731#define YORIGIN_FOR_STAT(num) ((((num)*win.height)/num_stats)+3)
732#define YMIDPOINT_FOR_STAT(num) ((((num)*win.height+win.height/2)/num_stats) + 5)
733#define Y_FOR_STAT_VAL(stat, num_of_val) \
734 y_base - min(height_of_stat, ( \
735 height_of_stat*( \
736 stats[stat].value[num_of_val]-stats[stat].min_val)/( \
737 stats[stat].max_val-stats[stat].min_val)))
738#define First_Point(v, xv, yv) {v->x = xv; v->y = yv;\
739 v++->flags = VertexDontDraw; }
740#define Next_Point(v, xv, yv) {v->x = xv; v->y = yv;\
741 v++->flags = VertexRelative | VertexDrawLastPoint; }
742
743display_dividers(w, clear_first)
744int clear_first;
745Window w;
746{
747 register int i, stat;
748 register int lwidth = win.width - graph_x_offset;
749 Vertex v[NUM_VALS_PER];
750 register Vertex *vp;
751
752 if(debug) fprintf(stderr, "num_of_val=%d\n", num_of_val);
753 FORALLSTATS(stat) {
754 register int y_org = YORIGIN_FOR_STAT(stat+1);
755 vp = v;
756 if (clear_first)
757 XPixSet(w, graph_x_offset, y_org-2, lwidth, 5, background);
758 /* Draw the horizontal line and then add the tick marks */
759 XLine(w, graph_x_offset, y_org, win.width, y_org, 1, 1,
760 foreground, GXcopy, ~0);
761 for (i = 0; i < num_of_val; i++) {
762 if (do_time[i]){
763 First_Point(vp, graph_x_offset + i, y_org - 2);
764 Next_Point(vp, 0, 4);
765 }
766 }
767 if (vp != v)
768 XDraw(w, v, vp-v, 1, 1, foreground, GXcopy, ~0);
769 }
770}
771
772redisplay(w)
773Window w;
774{
775 register int height_of_stat, stat;
776
777 XClear (w);
778 display_dividers(w, 0);
779 height_of_stat = YORIGIN_FOR_STAT(1) - YORIGIN_FOR_STAT(0) - 10;
780 XTextMask (w, 0, 0, Host, strlen (Host), finfo->id, highlight);
781 FORALLSTATS(stat) {
782 register int y_origin_of_stat = YORIGIN_FOR_STAT(stat);
783 int text_size;
784 char temp[20];
785 XTextMask (w, 0, YMIDPOINT_FOR_STAT(stat),
786 stats[stat].label, strlen (stats[stat].label), finfo->id,
787 highlight);
788 XTextMask (w, 0, YMIDPOINT_FOR_STAT(stat)+10,
789 stats[stat].label2, strlen (stats[stat].label2), finfo->id,
790 highlight);
791 sprintf(temp, "%d", stats[stat].max_val);
792 text_size = XStringWidth (temp, finfo, 0, 0);
793 XTextMask (w, graph_x_offset-5-text_size, y_origin_of_stat+5,
794 temp, strlen (temp), finfo->id, highlight);
795 sprintf(temp, "%d", stats[stat].min_val);
796 text_size = XStringWidth (temp, finfo, 0, 0);
797 XTextMask (w, graph_x_offset-5-text_size,
798 y_origin_of_stat-1+height_of_stat, temp, strlen (temp),
799 finfo->id, highlight);
800 }
801 if (num_of_val > 0) FORALLSTATS(stat)
802 redisplay_stat_values(w, height_of_stat, stat, num_of_val);
803
804}
805
806redisplay_stat_values(w, height_of_stat, stat, stop_plus_one)
807Window w;
808int height_of_stat, stat, stop_plus_one;
809{
810 register int j, newY;
811 Vertex v[NUM_VALS_PER];
812 register Vertex *vp = v;
813 int y_base = YORIGIN_FOR_STAT(stat+1)-5;
814 newY = Y_FOR_STAT_VAL(stat, 0);
815 First_Point(vp, graph_x_offset, newY);
816 for (j = 1; j < stop_plus_one; ) {
817 register int npts = 0, oldY = newY;
818 do {
819 newY = Y_FOR_STAT_VAL(stat, j);
820 j++;
821 npts++;
822 }
823 while ((oldY == newY) && (j < stop_plus_one));
824 if (--npts)
825 Next_Point(vp, npts, 0);
826 Next_Point(vp, 1, newY - oldY);
827 }
828 if (vp != v)
829 XDraw(w, v, vp-v, 1, 1, foreground, GXcopy, ~0);
830}
831
832next_display(w)
833Window w;
834{
835 int stat, height_of_stat, redisp = 0;
836
837 height_of_stat = YORIGIN_FOR_STAT(1) - YORIGIN_FOR_STAT(0) - 10;
838 FORALLSTATS(stat) {
839 int newY, oldY;
840 int y_base = YORIGIN_FOR_STAT(stat+1)-5;
841 newY = Y_FOR_STAT_VAL(stat, num_of_val);
842 if (num_of_val == 0)
843 oldY = newY;
844 else
845 oldY = Y_FOR_STAT_VAL(stat, num_of_val-1);
846 XLine(w, graph_x_offset+num_of_val, oldY,
847 graph_x_offset+num_of_val+1, newY, 1, 1, foreground,
848 GXcopy, ~0);
849 if (do_time[num_of_val]) {
850 y_base += 5;
851 XLine(w, graph_x_offset+num_of_val, y_base-2,
852 graph_x_offset+num_of_val, y_base+2,
853 1, 1, foreground, GXcopy, ~0);
854 }
855 }
856 if (++num_of_val >= NUM_VALS_PER ||
857 num_of_val >= win.width-graph_x_offset) {
858 int num_shift_left = (win.width-graph_x_offset)/2;
859 int width = (win.width-graph_x_offset) - num_shift_left;
860 register int j;
861 for (j = num_shift_left; j < num_of_val; j++)
862 do_time[j-num_shift_left] = do_time[j];
863 FORALLSTATS(stat) {
864 register int ys = YORIGIN_FOR_STAT(stat)+5, nmax = 1, t;
865 for (j = num_shift_left; j < num_of_val; j++) {
866 t = stats[stat].value[j-num_shift_left] =
867 stats[stat].value[j];
868 nmax = nmax > t ? nmax : t;
869 }
870 if (stat >= FREE_MEM && stat < COLLISION_PACKETS && nmax != stats[stat].max_val) {
871 stats[stat].max_val = nmax;
872 redisp = 1;
873 }
874 if (!redisp) {
875 XMoveArea(w, graph_x_offset+num_shift_left,
876 ys, graph_x_offset, ys, width, height_of_stat+2);
877 XPixSet(w, graph_x_offset+num_shift_left,
878 ys, width, height_of_stat+2, background);
879
880 }
881 }
882 num_of_val -= num_shift_left+1;
883 if (redisp)
884 redisplay(w);
885 else
886 display_dividers(w, 1);
887 }
888}
889
890int get_namelist(kernel_name, memory_name)
891char *kernel_name, *memory_name;
892{
893 time_t now;
894 time_t boottime;
895 register int i;
896 int nintv;
897
898 nlist(kernel_name, nl);
899 if(nl[0].n_type == 0) {
900 fprintf(stderr, "no %s namelist\n", kernel_name);
901 exit(1);
902 }
903 mf = open(memory_name, 0);
904 if (mf < 0) {
905 fprintf(stderr, "cannot open %s\n", memory_name);
906 exit(1);
907 }
908 steal((long)nl[X_MAXFREE].n_value, maxfree);
909 steal((long)nl[X_BOOTTIME].n_value, boottime);
910 steal((long)nl[X_HZ].n_value, hz);
911 for (i = 0; i < DK_NDRIVE; i++) {
912 strcpy(dr_name[i], "xx");
913 dr_unit[i] = i;
914 }
915 read_names();
916 time(&now);
917 nintv = now - boottime;
918 if (nintv <= 0 || nintv > 60*60*24*365*10) {
919 fprintf(stderr,
920 "Time makes no sense... namelist must be wrong.\n");
921 exit(1);
922 }
923 return(nintv);
924}
925
926double
927stat1(row)
928{
929 double t;
930 register i;
931
932 t = 0;
933 for(i=0; i<CPUSTATES; i++)
934 t += s.time[i];
935 if(t == 0.)
936 t = 1.;
937 return(s.time[row]*100./t);
938}
939
940#ifdef vax
941read_names()
942{
943 struct mba_device mdev;
944 register struct mba_device *mp;
945 struct mba_driver mdrv;
946 short two_char;
947 char *cp = (char *) &two_char;
948 struct uba_device udev, *up;
949 struct uba_driver udrv;
950
951 mp = (struct mba_device *) nl[X_MBDINIT].n_value;
952 up = (struct uba_device *) nl[X_UBDINIT].n_value;
953 if (up == 0) {
954 fprintf(stderr, "perfmon: Disk init info not in namelist\n");
955 exit(1);
956 }
957 if(mp) for (;;) {
958 steal(mp++, mdev);
959 if (mdev.mi_driver == 0)
960 break;
961 if (mdev.mi_dk < 0 || mdev.mi_alive == 0)
962 continue;
963 steal(mdev.mi_driver, mdrv);
964 steal(mdrv.md_dname, two_char);
965 sprintf(dr_name[mdev.mi_dk], "%c%c", cp[0], cp[1]);
966 dr_unit[mdev.mi_dk] = mdev.mi_unit;
967 }
968 if(up) for (;;) {
969 steal(up++, udev);
970 if (udev.ui_driver == 0)
971 break;
972 if (udev.ui_dk < 0 || udev.ui_alive == 0)
973 continue;
974 steal(udev.ui_driver, udrv);
975 steal(udrv.ud_dname, two_char);
976 sprintf(dr_name[udev.ui_dk], "%c%c", cp[0], cp[1]);
977 dr_unit[udev.ui_dk] = udev.ui_unit;
978 }
979}
980#endif vax
981
982#ifdef sun
983read_names()
984{
985 struct mb_device mdev;
986 register struct mb_device *mp;
987 struct mb_driver mdrv;
988 short two_char;
989 char *cp = (char *) &two_char;
990
991 mp = (struct mb_device *) nl[X_MBDINIT].n_value;
992 if (mp == 0) {
993 fprintf(stderr, "vmstat: Disk init info not in namelist\n");
994 exit(1);
995 }
996 for (;;) {
997 steal(mp++, mdev);
998 if (mdev.md_driver == 0)
999 break;
1000 if (mdev.md_dk < 0 || mdev.md_alive == 0)
1001 continue;
1002 steal(mdev.md_driver, mdrv);
1003 steal(mdrv.mdr_dname, two_char);
1004 sprintf(dr_name[mdev.md_dk], "%c%c", cp[0], cp[1]);
1005 dr_unit[mdev.md_dk] = mdev.md_unit;
1006 }
1007}
1008#endif sun
1009
1010#ifdef ibm032
1011read_names()
1012{
1013 struct iocc_device mdev;
1014 register struct iocc_device *mp;
1015 struct iocc_driver mdrv;
1016 short two_char;
1017 char *cp = (char *) &two_char;
1018
1019 mp = (struct iocc_device *) nl[X_IOCINIT].n_value;
1020 if (mp == 0) {
1021 fprintf(stderr, "vmstat: Disk init info not in namelist\n");
1022 exit(1);
1023 }
1024 for (;;) {
1025 steal(mp++, mdev);
1026 if (mdev.iod_driver == 0)
1027 break;
1028 if (mdev.iod_dk < 0 || mdev.iod_alive == 0)
1029 continue;
1030 steal(mdev.iod_driver, mdrv);
1031 steal(mdrv.idr_dname, two_char);
1032 sprintf(dr_name[mdev.iod_dk], "%c%c", cp[0], cp[1]);
1033 dr_unit[mdev.iod_dk] = mdev.iod_unit;
1034 }
1035}
1036#endif ibm032
1037
1038#ifdef tahoe
1039read_names()
1040{
1041 struct vba_device udev, *up;
1042 struct vba_driver udrv;
1043 short two_char;
1044 char *cp = (char *)&two_char;
1045
1046 up = (struct vba_device *) nl[X_VBDINIT].n_value;
1047 if (up == 0) {
1048 fprintf(stderr, "vmstat: Disk init info not in namelist\n");
1049 exit(1);
1050 }
1051 for (;;) {
1052 steal(up++, udev);
1053 if (udev.ui_driver == 0)
1054 break;
1055 if (udev.ui_dk < 0 || udev.ui_alive == 0)
1056 continue;
1057 steal(udev.ui_driver, udrv);
1058 steal(udrv.ud_dname, two_char);
1059 sprintf(dr_name[udev.ui_dk], "%c%c%d",
1060 cp[0], cp[1], udev.ui_unit);
1061 }
1062}
1063#endif
1064
1065usage()
1066{
1067 fprintf(stderr,
1068 "Usage: xperfmon [host:display] option option .....\n");
1069 exit(1);
1070}