|
|
1.1 root 1: /* Copyright 1985, Massachusetts Institute of Technology */
2:
3: /*
4: * X Unix performance monitor.
5: */
6:
7: #ifndef lint
8: static 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:
46: struct packet {
47: int input, output, collisions;
48: };
49: static struct packet packets, old_packets;
50:
51: #define NUM_VALS_PER 1000
52: struct 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
59: static char do_time[NUM_VALS_PER];
60: static struct timeval current_time, saved_time;
61: static struct timezone dummy_zone;
62:
63: short 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
87: static 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:
95: static struct statistic stats[MAX_STATS];
96:
97: static struct timeval timeout = {
98: SEC_INC,USEC_INC};
99: static int num_stats, num_of_val = 0;
100: static int graph_x_offset = 0;
101: WindowInfo WInfo;
102:
103: Window Win;
104: char Host[40];
105: char *font_name = "6x10";
106: int background; /* color of background */
107: int foreground; /* color of graph */
108: int highlight; /* color of text, scale */
109: FontInfo *finfo; /* font information needed */
110: int debug = 0;
111: #define max(a,b) (a>b ? a:b)
112:
113: OpaqueFrame 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:
119: struct 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:
159: char dr_name[DK_NDRIVE][10];
160: char dr_unit[DK_NDRIVE];
161: double stat1();
162: int maxfree;
163: int hz;
164: struct
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: }
176: s, s1;
177: #define rate s.Rate
178: #define total s.Total
179: #define sum s.Sum
180: #define forkstat s.Forkstat
181:
182: struct vmmeter osum;
183: int deficit;
184: double etime;
185: int mf;
186: int swflag;
187:
188: int nintv;
189: long t;
190:
191: #define steal(where, var) lseek(mf, where, 0); read(mf, &var, sizeof var);
192: #define pgtok(a) ((a)*NBPG/1024)
193:
194: char *options[NUM_POSSIBLE_STATS+1] = {
195: "user", "system", "idle", "free", "disk", "interrupts",
196: "input", "output", "collision",
197: 0 /* Terminator! */ };
198:
199: short arrow []= {0x0000, 0x0020, 0x0070, 0x00f8, 0x01fc, 0x03fe, 0x0070,
200: 0x0070, 0x0070, 0x0070, 0x0070, 0x0070, 0x0070, 0x0000};
201: short mask []= {0x0020, 0x0070, 0x00f8, 0x01fc, 0x03fe, 0x07ff, 0x07ff,
202: 0x00f8, 0x00f8, 0x00f8, 0x00f8, 0x00f8, 0x00f8, 0x00f8};
203:
204:
205: main(argc, argv)
206: int argc;
207: char **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:
463: getcmd(to_match, table) /* Modified from ucb/lpr/lpc.c */
464: register char *to_match;
465: register 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:
492: init_stat(index, maxval, label_1, label_2)
493: int index, maxval;
494: char *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:
507: int perf_mon_selected(w, number, mask, timer)
508: int mask, number;
509: Window w;
510: struct 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(¤t_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:
646: int 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:
655: copy_cpu_stats(stat)
656: int *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:
671: collect_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:
725: min (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:
743: display_dividers(w, clear_first)
744: int clear_first;
745: Window 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:
772: redisplay(w)
773: Window 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:
806: redisplay_stat_values(w, height_of_stat, stat, stop_plus_one)
807: Window w;
808: int 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:
832: next_display(w)
833: Window 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:
890: int get_namelist(kernel_name, memory_name)
891: char *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:
926: double
927: stat1(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
941: read_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
983: read_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
1011: read_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
1039: read_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:
1065: usage()
1066: {
1067: fprintf(stderr,
1068: "Usage: xperfmon [host:display] option option .....\n");
1069: exit(1);
1070: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.