BSD 4_3_Tahoe development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Sun, 24 Apr 1988 10:45:18 +0000 (02:45 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Sun, 24 Apr 1988 10:45:18 +0000 (02:45 -0800)
Work on file usr/src/new/X/xperfmon/xperfmon.c

Synthesized-from: CSRG/cd2/4.3tahoe

usr/src/new/X/xperfmon/xperfmon.c [new file with mode: 0644]

diff --git a/usr/src/new/X/xperfmon/xperfmon.c b/usr/src/new/X/xperfmon/xperfmon.c
new file mode 100644 (file)
index 0000000..b664726
--- /dev/null
@@ -0,0 +1,1070 @@
+/* Copyright 1985, Massachusetts Institute of Technology */
+
+/*
+ * X Unix performance monitor.
+ */
+
+#ifndef lint
+static char *rcsid_xperfmon_c = "$Header: xperfmon.c,v 10.13 86/11/25 18:31:37 jg Rel $";
+#endif lint
+
+/*
+ * Simple graphical performance monitor for system-wide data.
+ */
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/vm.h>
+#include <sys/dkstat.h>
+#include <nlist.h>
+#include <sys/buf.h>
+#ifdef vax
+#include <vaxuba/ubavar.h>
+#include <vaxmba/mbavar.h>
+#endif vax
+#ifdef sun
+#include <sundev/mbvar.h>
+#endif sun
+#ifdef ibm032  /* IBM RT/PC */
+#include <caio/ioccvar.h>
+#endif ibm032
+#ifdef tahoe
+#include <tahoevba/vbavar.h>
+#endif
+#include <X/Xlib.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/file.h>
+#include <sys/time.h>
+
+#include <strings.h>
+
+#define        USEC_INC        50000
+#define        SEC_INC         1
+
+struct packet {
+       int     input, output, collisions;
+};
+static struct packet packets, old_packets;
+
+#define NUM_VALS_PER   1000
+struct statistic {
+       int     min_val, max_val;
+       int     value[NUM_VALS_PER];
+       char    *label, *label2;
+};
+
+#define SECS_PER_TIME_TICK     10
+static char do_time[NUM_VALS_PER];
+static struct timeval current_time, saved_time;
+static struct timezone dummy_zone;
+
+short gray_bits[16] = {
+    0xaaaa, 0x5555, 0xaaaa, 0x5555,
+    0xaaaa, 0x5555, 0xaaaa, 0x5555,
+    0xaaaa, 0x5555, 0xaaaa, 0x5555,
+    0xaaaa, 0x5555, 0xaaaa, 0x5555};
+
+/*
+ * The array stats always has valid info for stats[i], 0 <= i < num_stats.
+ * For each valid stats[i], stats[i].value[j] is valid for 0 <= j < num_of_val.
+ * The info for the k-th possible statistic of interest is recorded, if it is
+ *   recorded at all, in stats[possible_stats[k]].
+ */
+
+#define        NO_STAT                 -1
+#define USER_CPU_PERCENTAGE    0
+#define SYSTEM_CPU_PERCENTAGE  1
+#define IDLE_CPU_PERCENTAGE    2
+#define FREE_MEM               3
+#define DISK_TRANSFERS         4
+#define INTERRUPTS             5
+#define INPUT_PACKETS          6
+#define OUTPUT_PACKETS         7
+#define COLLISION_PACKETS      8
+#define NUM_POSSIBLE_STATS     9
+static int                     possible_stats[NUM_POSSIBLE_STATS];
+#define WANT_STAT(x)           (possible_stats[(x)] != NO_STAT)
+
+#define        MAX_STATS               10
+
+#define DEFAULT_BORDER_WIDTH   3
+#define DEFAULT_POSITION       "=%dx%d-0+0"
+
+static struct statistic        stats[MAX_STATS];
+
+static struct timeval timeout = {
+       SEC_INC,USEC_INC};
+static int num_stats, num_of_val = 0;
+static int graph_x_offset = 0;
+WindowInfo     WInfo;
+
+Window Win;
+char Host[40];
+char *font_name = "6x10";
+int background;                                    /* color of background */
+int foreground;                                    /* color of graph */
+int highlight;                             /* color of text, scale */
+FontInfo *finfo;                           /* font information needed */
+int debug = 0;
+#define max(a,b) (a>b ? a:b)
+
+OpaqueFrame win;
+
+#define FORALLPOSSIBLESTATS(stat)\
+       for (stat = 0; stat < NUM_POSSIBLE_STATS; stat++)
+#define FORALLSTATS(stat) for (stat = 0; stat < num_stats; stat++)
+
+struct nlist nl[] = {
+#define X_CPTIME       0
+       { "_cp_time" },
+#define X_RATE   1
+       { "_rate" },
+#define X_TOTAL         2
+       { "_total" },
+#define X_DEFICIT       3
+       { "_deficit" },
+#define X_FORKSTAT      4
+       { "_forkstat" },
+#define X_SUM     5
+       { "_sum" },
+#define X_FIRSTFREE     6
+       { "_firstfree" },
+#define X_MAXFREE       7
+       { "_maxfree" },
+#define X_BOOTTIME      8
+       { "_boottime" },
+#define X_DKXFER       9
+       { "_dk_xfer" },
+#define X_REC     10
+       { "_rectime" },
+#define X_PGIN   11
+       { "_pgintime" },
+#define X_HZ       12
+       { "_hz" },
+#define X_MBDINIT       13
+       { "_mbdinit" },
+#define N_IFNET       14
+       { "_ifnet" },
+#define X_UBDINIT      15
+       { "_ubdinit" },
+#define X_IOCINIT      16
+       { "_ioccdinit" },
+#define        X_VBDINIT       17
+       { "_vbdinit" },
+       { "" },
+};
+
+char dr_name[DK_NDRIVE][10];
+char dr_unit[DK_NDRIVE];
+double  stat1();
+int     maxfree;
+int     hz;
+struct
+{
+       int     busy;
+       long    time[CPUSTATES];
+       long    xfer[DK_NDRIVE];
+       struct  vmmeter Rate;
+       struct  vmtotal Total;
+       struct  vmmeter Sum;
+       struct  forkstat Forkstat;
+       unsigned rectime;
+       unsigned pgintime;
+} 
+s, s1;
+#define rate       s.Rate
+#define total     s.Total
+#define sum         s.Sum
+#define forkstat       s.Forkstat
+
+struct  vmmeter osum;
+int     deficit;
+double  etime;
+int     mf;
+int     swflag;
+
+int nintv;
+long t;
+
+#define steal(where, var) lseek(mf, where, 0); read(mf, &var, sizeof var);
+#define pgtok(a) ((a)*NBPG/1024)
+
+char   *options[NUM_POSSIBLE_STATS+1] = {
+       "user", "system", "idle", "free", "disk", "interrupts",
+       "input", "output", "collision",
+       0  /* Terminator! */  };
+
+short  arrow []=  {0x0000, 0x0020, 0x0070, 0x00f8, 0x01fc, 0x03fe, 0x0070,
+                  0x0070, 0x0070, 0x0070, 0x0070, 0x0070, 0x0070, 0x0000};
+short  mask []=   {0x0020, 0x0070, 0x00f8, 0x01fc, 0x03fe, 0x07ff, 0x07ff,
+                  0x00f8, 0x00f8, 0x00f8, 0x00f8, 0x00f8, 0x00f8, 0x00f8};
+
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+       int     stat;
+       int     have_disk;
+       struct  timeval timeleft;
+       char    display[40];
+       char    *strind;
+       int     Select_mask, select_mask = 0;
+       int     maxplus1, n;
+       Cursor  cursor;
+       char    *geometry = NULL;               /* location of window */
+       char    def[32];
+       int     reverse = 0;
+       double  update = -1.;
+       double  atof();
+       char    *border_color;
+       char    *fore_color;
+       char    *back_color;
+       char    *high_color;
+       Pixmap  border_pixmap;
+       char    *option;
+       int     opt;
+       int     i;
+       int     minheight, minwidth;
+       
+       Color cdef;
+       int border_width = DEFAULT_BORDER_WIDTH;
+
+       display[0] = '\0';
+
+       if ((option = XGetDefault(argv[0],"ReverseVideo")) != NULL )
+               if (strcmp (option, "on") == 0)
+                       reverse = 1;
+       if ((option = XGetDefault(argv[0],"BorderWidth")) != NULL)
+               border_width = atoi(option);
+       if ((option = XGetDefault(argv[0],"BodyFont")) != NULL)
+               font_name = option;
+       if ((border_color = XGetDefault(argv[0],"Border")) == NULL)
+               border_color = XGetDefault(argv[0],"BorderColor");
+       back_color = XGetDefault(argv[0],"Background");
+       fore_color = XGetDefault(argv[0],"Foreground");
+       high_color = XGetDefault(argv[0],"Highlight");
+       if ((option = XGetDefault(argv[0],"Update")) != NULL)
+               update = atof(option);
+
+       nintv = get_namelist("/vmunix", "/dev/kmem");
+       collect_stats();
+       etime = 1.0;
+       have_disk = (total_disk_transfers() ? 1 : 0);
+
+       /* Initialize stats */
+       FORALLPOSSIBLESTATS(stat)
+               possible_stats[stat] = NO_STAT;
+       num_stats = 0;
+       for (i = 1; i < argc; i++) {                    /* Parse line */
+               if (argv[i][0] == '=') {
+                       geometry = argv[i];
+                       continue;
+               }
+               if (index(argv[i], ':') != NULL) {      /* host:display */
+                       strncpy(display, argv[i], sizeof(display));
+                       continue;
+               }
+               if (strcmp(argv[i], "-rv") == 0 ||
+               strcmp(argv[i], "-reverse") == 0) {     /* black on white */
+                       reverse = 1;
+                       continue;
+               }
+               if (strcmp(argv[i], "-fw") == 0 ||
+               strcmp(argv[i], "-forward") == 0) {     /* white on black */
+                       reverse = 0;
+                       continue;
+               }
+               if (strcmp(argv[i], "-bw") == 0 ||
+               strcmp(argv[i], "-border") == 0) {      /* border width */
+                       if (++i >= argc) usage();
+                       border_width = atoi(argv[i]);
+                       continue;
+               }
+               if (strcmp(argv[i], "-fn") == 0 ||
+               strcmp(argv[i], "-font") == 0) {        /* host name font */
+                       if (++i >= argc) usage();
+                       font_name = argv[i];
+                       continue;
+               }
+               if (strcmp(argv[i], "-bd") == 0 ||
+               strcmp(argv[i], "-color") == 0) {       /* border color */
+                       if (++i >= argc) usage();
+                       border_color = argv[i];
+                       continue;
+               }
+               if (strcmp(argv[i], "-fg") == 0 ||
+               strcmp(argv[i], "-foreground") == 0) {  /* foreground color */
+                       if (++i >= argc) usage();
+                       fore_color = argv[i];
+                       continue;
+               }
+               if (strcmp(argv[i], "-bg") == 0 ||
+               strcmp(argv[i], "-background") == 0) {  /* background color */
+                       if (++i >= argc) usage();
+                       back_color = argv[i];
+                       continue;
+               }
+               if (strcmp(argv[i], "-hl") == 0 ||
+               strcmp(argv[i], "-highlight") == 0) {   /* highlight color */
+                       if (++i >= argc) usage();
+                       high_color = argv[i];
+                       continue;
+               }
+               if (strcmp(argv[i], "-u") == 0 ||
+               strcmp(argv[i], "-update") == 0) {      /* update interval */
+                       if (++i >= argc) usage();
+                       update = atof(argv[i]);
+                       continue;
+               }
+               opt = getcmd(argv[i], options);
+               if (opt >= 0 && opt < NUM_POSSIBLE_STATS) {
+                       if (num_stats == MAX_STATS) {
+                               fprintf(stderr,
+                                   "MAX_STATS exceeded, please recompile!\n");
+                       }
+                       else possible_stats[opt] = num_stats++;
+                       continue;
+               }
+               usage();
+       }
+       
+       if (num_stats == 0)
+               FORALLPOSSIBLESTATS(stat) {
+                       if ((stat == DISK_TRANSFERS) && (have_disk == 0)) continue;
+                       possible_stats[stat] = num_stats++;
+                       if (num_stats == MAX_STATS) break;
+               }
+       have_disk = 0;  /* so max # of packets = 40 */
+       init_stat(USER_CPU_PERCENTAGE, 100, "User", " CPU");
+       init_stat(SYSTEM_CPU_PERCENTAGE, 100, "System", " CPU");
+       init_stat(IDLE_CPU_PERCENTAGE, 100, "Idle", " CPU");
+       init_stat(FREE_MEM, pgtok(maxfree), "Free", " memory");
+       init_stat(DISK_TRANSFERS, 40, "Disk", " transfers");
+       init_stat(INTERRUPTS, 60, "Interrupts", "");
+       init_stat(INPUT_PACKETS, (have_disk ? 20 : 40), "Input", " packets");
+       init_stat(OUTPUT_PACKETS, (have_disk ? 20 : 40), "Output", " packets");
+       init_stat(COLLISION_PACKETS, 10, "Collision", " packets");
+       if (border_width < 0) border_width = DEFAULT_BORDER_WIDTH;
+       if (update > .09) {
+               timeout.tv_sec = update;
+               timeout.tv_usec = (update - (double)((int)update)) * 1000000.;
+       }
+       if (!XOpenDisplay (display)){
+           fprintf(stderr, "%s: Can't open display '%s'\n",
+                   argv[0], XDisplayName(display));
+           exit(1);
+       }
+       if ((finfo = XOpenFont(font_name)) == NULL) {
+               fprintf(stderr, "Can't load font %s!\n", font_name);
+               exit(1);
+       }
+       gethostname(Host, sizeof (Host));
+       strcat(Host, ":");
+       FORALLSTATS(stat) {
+               int s_width;
+               s_width = XStringWidth (stats[stat].label, finfo, 0, 0);
+               graph_x_offset = max(graph_x_offset, s_width);
+               s_width = XStringWidth (stats[stat].label2, finfo, 0, 0);
+               graph_x_offset = max(graph_x_offset, s_width);
+       }
+       graph_x_offset += 15;
+       if(debug) fprintf(stderr, "graph_x_offset=%d\n", graph_x_offset);
+       gettimeofday(&saved_time, &dummy_zone);
+
+       if (border_color && DisplayCells() > 2 &&
+               XParseColor(border_color, &cdef) && XGetHardwareColor(&cdef))
+               border_pixmap = XMakeTile(cdef.pixel);
+       else if (border_color && strcmp(border_color, "black") == 0)
+               border_pixmap = BlackPixmap;
+       else if (border_color && strcmp(border_color, "white") == 0)
+               border_pixmap = WhitePixmap;
+       else    
+               border_pixmap = XMakePixmap (
+                       (Bitmap) XStoreBitmap (16, 16, gray_bits),
+                                       BlackPixel, WhitePixel);
+
+
+
+       if (back_color && DisplayCells() > 2 &&
+           XParseColor(back_color, &cdef) && XGetHardwareColor(&cdef)) {
+               background = cdef.pixel;
+       } else if (back_color && (strcmp(back_color, "white") == 0)) {
+               background = WhitePixel;
+               reverse = 0;
+       } else if (back_color && (strcmp(back_color, "black") == 0)) {
+               background = BlackPixel;
+               reverse = 0;
+       } else
+           background = BlackPixel;
+
+       if (fore_color && DisplayCells() > 2 &&
+           XParseColor(fore_color, &cdef) && XGetHardwareColor(&cdef)) {
+               foreground = cdef.pixel;
+       } else if (fore_color && (strcmp(fore_color, "black") == 0)) {
+               foreground = BlackPixel;
+               reverse = 0;
+       } else if (fore_color && (strcmp(fore_color, "white") == 0)) {
+               foreground = WhitePixel;
+               reverse = 0;
+       } else
+           foreground = WhitePixel;
+
+       if (high_color && DisplayCells() > 2 &&
+           XParseColor(high_color, &cdef) && XGetHardwareColor(&cdef)) {
+               highlight = cdef.pixel;
+       } else
+           highlight = foreground;
+
+       if (reverse) {
+               highlight = background;
+               background = foreground;
+               foreground = highlight;
+       }
+       win.bdrwidth = border_width;
+       win.border = border_pixmap;
+       win.background = XMakeTile(background);
+
+       minheight = (finfo->height * 2 + 2) * num_stats;
+       minwidth  = graph_x_offset + 100;
+       sprintf(def, DEFAULT_POSITION, minwidth+100, 
+               (finfo->height * 3 + 3) * num_stats);
+
+       Win = XCreate ("Performance Monitor", argv[0], geometry, def, &win,
+               minwidth, minheight);
+
+       win.height -= 10;
+       XMapWindow (Win);
+       cursor = XCreateCursor (11, 14, arrow, mask, 5, 1, 1, 0, GXcopyInverted);
+       XDefineCursor (Win, cursor);
+
+       redisplay (Win);
+       timeleft = timeout;
+       Select_mask = 1<<dpyno();
+       maxplus1 = 1+dpyno();
+       XSelectInput(Win, KeyPressed | ExposeWindow | ExposeCopy);
+       while(1) {
+               select_mask = Select_mask;
+               if(debug) fprintf(stderr, "time=[%d,%d]\n",
+               timeleft.tv_sec, timeleft.tv_usec);
+               XFlush();
+               if ((n = select(maxplus1, &select_mask, NULL, NULL, &timeleft))
+                   < 0) exit(46);
+               if(debug)
+                       fprintf(stderr,"selected n=%d mask=0x%x, time=[%d,%d]\n",
+                       n, select_mask, timeleft.tv_sec, timeleft.tv_usec);
+               if (perf_mon_selected (Win, n, select_mask, &timeleft)
+                   < 0) break;
+       }
+}
+
+getcmd(to_match, table)                        /* Modified from ucb/lpr/lpc.c */
+register char *to_match;
+register char **table;
+{
+       register char *p, *q;
+       int found, index, nmatches, longest;
+
+       longest = nmatches = 0;
+       found = index = -1;
+       for (p = *table; p; p = *(++table)) {
+               index++;
+               for (q = to_match; *q == *p++; q++)
+                       if (*q == 0)            /* exact match? */
+                               return(index);
+               if (!*q) {                      /* the to_match was a prefix */
+                       if (q - to_match > longest) {
+                               longest = q - to_match;
+                               nmatches = 1;
+                               found = index;
+                       } 
+                       else if (q - to_match == longest)
+                               nmatches++;
+               }
+       }
+       if (nmatches > 1)
+               return(-1);
+       return(found);
+}
+
+init_stat(index, maxval, label_1, label_2)
+int index, maxval;
+char *label_1, *label_2;
+{
+       if WANT_STAT(index) {
+               index = possible_stats[index];
+               stats[index].max_val = maxval;
+               stats[index].label = label_1;
+               stats[index].label2 = label_2;
+       }
+}
+
+#define        TIMER_EXPIRED(timer)                                            \
+(*timer && ((*timer)->tv_sec == 0) && ((*timer)->tv_usec == 0))
+
+int perf_mon_selected(w, number, mask, timer)
+int mask, number;
+Window w;
+struct timeval *timer;
+{
+       if(number == 0) {       /*timer expired */
+               int *target[CPUSTATES-1], trash;
+               collect_stats();
+               for (trash = 0; trash < CPUSTATES-1; trash++)
+                       target[trash] = &trash;
+               if WANT_STAT(USER_CPU_PERCENTAGE)
+                       target[0] =
+                           &stats[possible_stats[USER_CPU_PERCENTAGE]].value[num_of_val];
+               if WANT_STAT(SYSTEM_CPU_PERCENTAGE)
+                       target[1] =
+                           &stats[possible_stats[SYSTEM_CPU_PERCENTAGE]].value[num_of_val];
+               if WANT_STAT(IDLE_CPU_PERCENTAGE)
+                       target[2] =
+                           &stats[possible_stats[IDLE_CPU_PERCENTAGE]].value[num_of_val];
+               copy_cpu_stats(target);
+               if WANT_STAT(FREE_MEM)
+                       stats[possible_stats[FREE_MEM]].value[num_of_val] =
+                           pgtok(total.t_free);
+               if WANT_STAT(DISK_TRANSFERS)
+                       stats[possible_stats[DISK_TRANSFERS]].value[num_of_val] =
+                           total_disk_transfers();
+               if WANT_STAT(INTERRUPTS)
+                       stats[possible_stats[INTERRUPTS]].value[num_of_val] =
+                           (rate.v_intr/nintv) - hz;
+               if WANT_STAT(INPUT_PACKETS)
+                       stats[possible_stats[INPUT_PACKETS]].value[num_of_val] =
+                           packets.input - old_packets.input;
+               if WANT_STAT(OUTPUT_PACKETS)
+                       stats[possible_stats[OUTPUT_PACKETS]].value[num_of_val] =
+                           packets.output - old_packets.output;
+               if WANT_STAT(COLLISION_PACKETS)
+                       stats[possible_stats[COLLISION_PACKETS]].value[num_of_val] =
+                           packets.collisions - old_packets.collisions;
+               gettimeofday(&current_time, &dummy_zone);
+               if (current_time.tv_sec < saved_time.tv_sec) {
+                       /* Super-user must have set the clock back */
+                       saved_time = current_time;
+                       saved_time.tv_sec -= SECS_PER_TIME_TICK;
+               }
+               if (saved_time.tv_sec+SECS_PER_TIME_TICK <= current_time.tv_sec) {
+                       saved_time = current_time;
+                       do_time[num_of_val] = 1;
+               } 
+               else
+                       do_time[num_of_val] = 0;
+               next_display(w);
+       }
+       if (mask & (1 << dpyno())){
+               XEvent event;
+               XEvent pevent;
+               XExposeWindowEvent *exp_event;
+               int key;
+               if(!XPending()) return (-1); /* end of file on connection */
+               while (XPending())
+                 {
+                       XNextEvent (&event);
+                       switch (event.type) {
+                       case KeyPressed:
+                               if ((key = mapkey(((XKeyPressedEvent *)&event)->detail)) > 0)
+                                       switch(key){
+                                       case 'f': /* faster usec timeout */
+                                               if (timeout.tv_usec >= USEC_INC)
+                                                       timeout.tv_usec -= USEC_INC;
+                                               else {
+                                                       if (timeout.tv_sec >= SEC_INC) {
+                                                               timeout.tv_sec -= SEC_INC;
+                                                               timeout.tv_usec = 1000000-USEC_INC;
+                                                       }
+                                               }
+                                               break;
+                                       case 's': /* slower usec timeout */
+                                               if (timeout.tv_usec < 1000000-USEC_INC)
+                                                       timeout.tv_usec += USEC_INC;
+                                               else {
+                                                       timeout.tv_usec = 0;
+                                                       timeout.tv_sec += 1;
+                                               }
+                                               break;
+                                       case 'F': /* faster sec timeout */
+                                               if (timeout.tv_sec >= SEC_INC)
+                                                       timeout.tv_sec -= SEC_INC;
+                                               break;
+                                       case 'S': /* slower sec timeout */
+                                               timeout.tv_sec += SEC_INC;
+                                               break;
+                                       case 'R': /* reset */
+                                               timeout.tv_sec = SEC_INC;
+                                               timeout.tv_usec = USEC_INC;
+                                               num_of_val = 0;
+                                               redisplay(w);
+                                               break;
+                                       case 'h':
+                                       case 'H':
+                                       case '?': /* Help */
+                                               printf("%s\n%s\n%s\n%s\n%s\n%s\n",
+                                               "'s' slower usec timeout",
+                                               "'f' faster usec timeout",
+                                               "'S' slower sec timeout",
+                                               "'F' faster sec timeout",
+                                               "'R' reset timeout and display",
+                                               "'q' or 'Q' quit");
+                                               /*
+                                                * Don't reset timeout
+                                                */
+                                               return(0);
+                                       case 'q':
+                                       case 'Q':
+                                               return(-1);
+                                       }       /* switch(key) */
+                               break;
+                       case ExposeWindow:
+                               XSync(0);
+                               while (XPending() != 0) {
+                                       XPeekEvent (&pevent);
+                                       if (pevent.type != ExposeWindow) break;
+                                       XNextEvent(&event);
+                               }
+
+                               exp_event = (XExposeWindowEvent *) &event;
+                               win.x = exp_event->x;
+                               win.y = exp_event->y;
+                               win.width = exp_event->width;
+                               win.height = exp_event->height - 10;
+                               redisplay(w);
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+       *timer = timeout;
+       return(0);
+}
+
+int total_disk_transfers()
+{
+       register int i, total_xfers = 0;
+
+       for(i=0; i < DK_NDRIVE; i++)
+               total_xfers += s.xfer[i];
+       return(total_xfers/etime);
+}
+
+copy_cpu_stats(stat)
+int *stat[CPUSTATES-1];
+{
+       register int i;
+
+       for(i=0; i<CPUSTATES; i++) {
+               float f = stat1(i);
+               if (i == 0) {           /* US+NI */
+                       i++;
+                       f += stat1(i);
+               }
+               if (stat[i-1] != 0)
+                       *stat[i-1] = f;
+       }
+}
+
+collect_stats()
+{
+
+       off_t ifnetaddr = (long)nl[N_IFNET].n_value;
+
+       register int i;
+
+       lseek(mf, (long)nl[X_CPTIME].n_value, 0);
+       read(mf, s.time, sizeof s.time);
+       lseek(mf, (long)nl[X_DKXFER].n_value, 0);
+       read(mf, s.xfer, sizeof s.xfer);
+       if (nintv != 1) {
+               steal((long)nl[X_SUM].n_value, rate);
+       } 
+       else {
+               steal((long)nl[X_RATE].n_value, rate);
+       }
+       steal((long)nl[X_TOTAL].n_value, total);
+       osum = sum;
+       steal((long)nl[X_SUM].n_value, sum);
+       steal((long)nl[X_DEFICIT].n_value, deficit);
+       etime = 0;
+       for (i=0; i < DK_NDRIVE; i++) {
+               t = s.xfer[i];
+               s.xfer[i] -= s1.xfer[i];
+               s1.xfer[i] = t;
+       }
+       for (i=0; i < CPUSTATES; i++) {
+               t = s.time[i];
+               s.time[i] -= s1.time[i];
+               s1.time[i] = t;
+               etime += s.time[i];
+       }
+       if(etime == 0.)
+               etime = 1.;
+       etime /= 60.;
+       nintv = 1;
+
+       if (nl[N_IFNET].n_value != 0) {
+               struct ifnet ifnet;
+               steal((long)nl[N_IFNET].n_value, ifnetaddr);
+               old_packets = packets;
+               packets.input = packets.output = packets.collisions = 0;
+               while (ifnetaddr) {
+                       steal(ifnetaddr, ifnet);
+                       packets.input += ifnet.if_ipackets;
+                       packets.output += ifnet.if_opackets;
+                       packets.collisions += ifnet.if_collisions;
+                       ifnetaddr = (off_t) ifnet.if_next;
+               }
+       }
+
+}
+
+min (a, b)
+       int a,b;
+{
+       return(a<b ? a:b);
+}
+
+#define        YORIGIN_FOR_STAT(num)   ((((num)*win.height)/num_stats)+3)
+#define        YMIDPOINT_FOR_STAT(num) ((((num)*win.height+win.height/2)/num_stats) + 5)
+#define Y_FOR_STAT_VAL(stat, num_of_val)                               \
+       y_base - min(height_of_stat, (  \
+               height_of_stat*(                                        \
+                 stats[stat].value[num_of_val]-stats[stat].min_val)/(  \
+                 stats[stat].max_val-stats[stat].min_val)))
+#define First_Point(v, xv, yv) {v->x = xv; v->y = yv;\
+               v++->flags = VertexDontDraw; }
+#define Next_Point(v, xv, yv) {v->x = xv; v->y = yv;\
+               v++->flags = VertexRelative | VertexDrawLastPoint; }
+
+display_dividers(w, clear_first)
+int clear_first;
+Window w;
+{
+       register int    i, stat;
+       register int lwidth = win.width - graph_x_offset;
+       Vertex v[NUM_VALS_PER];
+       register Vertex *vp;
+
+       if(debug) fprintf(stderr, "num_of_val=%d\n", num_of_val);
+       FORALLSTATS(stat) {
+               register int y_org = YORIGIN_FOR_STAT(stat+1);
+               vp = v;
+               if (clear_first)
+                       XPixSet(w, graph_x_offset, y_org-2, lwidth, 5, background);
+               /* Draw the horizontal line and then add the tick marks */
+               XLine(w, graph_x_offset, y_org, win.width, y_org, 1, 1, 
+                   foreground, GXcopy, ~0);
+               for (i = 0; i < num_of_val; i++) {
+                       if (do_time[i]){
+                               First_Point(vp, graph_x_offset + i, y_org - 2);
+                               Next_Point(vp, 0, 4);
+                       }
+               }
+               if (vp != v)
+                       XDraw(w, v, vp-v, 1, 1, foreground, GXcopy, ~0);
+       }
+}
+
+redisplay(w)
+Window w;
+{
+       register int height_of_stat, stat;
+
+       XClear (w);
+       display_dividers(w, 0);
+       height_of_stat = YORIGIN_FOR_STAT(1) - YORIGIN_FOR_STAT(0) - 10;
+       XTextMask (w, 0, 0, Host, strlen (Host), finfo->id, highlight);
+       FORALLSTATS(stat) {
+               register int y_origin_of_stat = YORIGIN_FOR_STAT(stat);
+               int text_size;
+               char temp[20];
+               XTextMask (w, 0, YMIDPOINT_FOR_STAT(stat),
+                   stats[stat].label, strlen (stats[stat].label), finfo->id,
+                   highlight);
+               XTextMask (w, 0, YMIDPOINT_FOR_STAT(stat)+10,
+                   stats[stat].label2, strlen (stats[stat].label2), finfo->id, 
+                   highlight);
+               sprintf(temp, "%d", stats[stat].max_val);
+               text_size = XStringWidth (temp, finfo, 0, 0);
+               XTextMask (w, graph_x_offset-5-text_size, y_origin_of_stat+5,
+                       temp, strlen (temp), finfo->id, highlight);
+               sprintf(temp, "%d", stats[stat].min_val);
+               text_size = XStringWidth (temp, finfo, 0, 0);
+               XTextMask (w, graph_x_offset-5-text_size,
+                   y_origin_of_stat-1+height_of_stat, temp, strlen (temp),
+                   finfo->id, highlight);
+       }
+       if (num_of_val > 0) FORALLSTATS(stat) 
+               redisplay_stat_values(w, height_of_stat, stat, num_of_val);
+
+}
+
+redisplay_stat_values(w, height_of_stat, stat, stop_plus_one)
+Window w;
+int height_of_stat, stat, stop_plus_one;
+{
+       register int j, newY;
+       Vertex v[NUM_VALS_PER];
+       register Vertex *vp = v;
+       int y_base = YORIGIN_FOR_STAT(stat+1)-5;
+       newY = Y_FOR_STAT_VAL(stat, 0);
+       First_Point(vp, graph_x_offset, newY);
+       for (j = 1; j < stop_plus_one; ) {
+               register int npts = 0, oldY = newY;
+               do {
+                       newY = Y_FOR_STAT_VAL(stat, j);
+                       j++; 
+                       npts++;
+               } 
+               while ((oldY == newY) && (j < stop_plus_one));
+               if (--npts)
+                       Next_Point(vp, npts, 0);
+               Next_Point(vp, 1, newY - oldY);
+       }
+       if (vp != v)
+               XDraw(w, v, vp-v, 1, 1, foreground, GXcopy, ~0);
+}
+
+next_display(w)
+Window w;
+{
+       int stat, height_of_stat, redisp = 0;
+
+       height_of_stat = YORIGIN_FOR_STAT(1) - YORIGIN_FOR_STAT(0) - 10;
+       FORALLSTATS(stat) {
+               int newY, oldY;
+               int y_base = YORIGIN_FOR_STAT(stat+1)-5;
+               newY = Y_FOR_STAT_VAL(stat, num_of_val);
+               if (num_of_val == 0)
+                       oldY = newY;
+               else
+                       oldY = Y_FOR_STAT_VAL(stat, num_of_val-1);
+               XLine(w, graph_x_offset+num_of_val, oldY,
+                   graph_x_offset+num_of_val+1, newY, 1, 1, foreground, 
+                   GXcopy, ~0);
+               if (do_time[num_of_val]) {
+                       y_base += 5;
+                       XLine(w, graph_x_offset+num_of_val, y_base-2,
+                           graph_x_offset+num_of_val, y_base+2,
+                           1, 1, foreground, GXcopy, ~0);
+               }
+       }
+       if (++num_of_val >= NUM_VALS_PER ||
+           num_of_val >= win.width-graph_x_offset) {
+               int num_shift_left = (win.width-graph_x_offset)/2;
+               int width = (win.width-graph_x_offset) - num_shift_left;
+               register int j;
+               for (j = num_shift_left; j < num_of_val; j++)
+                       do_time[j-num_shift_left] = do_time[j];
+               FORALLSTATS(stat) {
+                       register int ys = YORIGIN_FOR_STAT(stat)+5, nmax = 1, t;
+                       for (j = num_shift_left; j < num_of_val; j++) {
+                               t = stats[stat].value[j-num_shift_left] =
+                                   stats[stat].value[j];
+                               nmax = nmax > t ? nmax : t;
+                       }
+                       if (stat >= FREE_MEM && stat < COLLISION_PACKETS  && nmax != stats[stat].max_val) {
+                               stats[stat].max_val = nmax;
+                               redisp = 1;
+                       }
+                       if (!redisp) {
+                               XMoveArea(w, graph_x_offset+num_shift_left,
+                               ys, graph_x_offset, ys, width, height_of_stat+2);
+                               XPixSet(w, graph_x_offset+num_shift_left,
+                                 ys, width, height_of_stat+2, background);
+
+                       }
+               }
+               num_of_val -= num_shift_left+1;
+               if (redisp)
+                       redisplay(w);
+               else
+                       display_dividers(w, 1);
+       }
+}
+
+int get_namelist(kernel_name, memory_name)
+char *kernel_name, *memory_name;
+{
+       time_t now;
+       time_t boottime;
+       register int i;
+       int nintv;
+
+       nlist(kernel_name, nl);
+       if(nl[0].n_type == 0) {
+               fprintf(stderr, "no %s namelist\n", kernel_name);
+               exit(1);
+       }
+       mf = open(memory_name, 0);
+       if (mf < 0) {
+               fprintf(stderr, "cannot open %s\n", memory_name);
+               exit(1);
+       }
+       steal((long)nl[X_MAXFREE].n_value, maxfree);
+       steal((long)nl[X_BOOTTIME].n_value, boottime);
+       steal((long)nl[X_HZ].n_value, hz);
+       for (i = 0; i < DK_NDRIVE; i++) {
+               strcpy(dr_name[i], "xx");
+               dr_unit[i] = i;
+       }
+       read_names();
+       time(&now);
+       nintv = now - boottime;
+       if (nintv <= 0 || nintv > 60*60*24*365*10) {
+               fprintf(stderr,
+               "Time makes no sense... namelist must be wrong.\n");
+               exit(1);
+       }
+       return(nintv);
+}
+
+double
+stat1(row)
+{
+       double t;
+       register i;
+
+       t = 0;
+       for(i=0; i<CPUSTATES; i++)
+               t += s.time[i];
+       if(t == 0.)
+               t = 1.;
+       return(s.time[row]*100./t);
+}
+
+#ifdef vax
+read_names()
+{
+       struct mba_device mdev;
+       register struct mba_device *mp;
+       struct mba_driver mdrv;
+       short two_char;
+       char *cp = (char *) &two_char;
+       struct uba_device udev, *up;
+       struct uba_driver udrv;
+
+       mp = (struct mba_device *) nl[X_MBDINIT].n_value;
+       up = (struct uba_device *) nl[X_UBDINIT].n_value;
+       if (up == 0) {
+               fprintf(stderr, "perfmon: Disk init info not in namelist\n");
+               exit(1);
+       }
+       if(mp) for (;;) {
+               steal(mp++, mdev);
+               if (mdev.mi_driver == 0)
+                       break;
+               if (mdev.mi_dk < 0 || mdev.mi_alive == 0)
+                       continue;
+               steal(mdev.mi_driver, mdrv);
+               steal(mdrv.md_dname, two_char);
+               sprintf(dr_name[mdev.mi_dk], "%c%c", cp[0], cp[1]);
+               dr_unit[mdev.mi_dk] = mdev.mi_unit;
+       }
+       if(up) for (;;) {
+               steal(up++, udev);
+               if (udev.ui_driver == 0)
+                       break;
+               if (udev.ui_dk < 0 || udev.ui_alive == 0)
+                       continue;
+               steal(udev.ui_driver, udrv);
+               steal(udrv.ud_dname, two_char);
+               sprintf(dr_name[udev.ui_dk], "%c%c", cp[0], cp[1]);
+               dr_unit[udev.ui_dk] = udev.ui_unit;
+       }
+}
+#endif vax
+
+#ifdef sun
+read_names()
+{
+       struct mb_device mdev;
+       register struct mb_device *mp;
+       struct mb_driver mdrv;
+       short two_char;
+       char *cp = (char *) &two_char;
+
+       mp = (struct mb_device *) nl[X_MBDINIT].n_value;
+       if (mp == 0) {
+               fprintf(stderr, "vmstat: Disk init info not in namelist\n");
+               exit(1);
+       }
+       for (;;) {
+               steal(mp++, mdev);
+               if (mdev.md_driver == 0)
+                       break;
+               if (mdev.md_dk < 0 || mdev.md_alive == 0)
+                       continue;
+               steal(mdev.md_driver, mdrv);
+               steal(mdrv.mdr_dname, two_char);
+               sprintf(dr_name[mdev.md_dk], "%c%c", cp[0], cp[1]);
+               dr_unit[mdev.md_dk] = mdev.md_unit;
+       }
+}
+#endif sun
+
+#ifdef ibm032
+read_names()
+{
+       struct iocc_device mdev;
+       register struct iocc_device *mp;
+       struct iocc_driver mdrv;
+       short two_char;
+       char *cp = (char *) &two_char;
+
+       mp = (struct iocc_device *) nl[X_IOCINIT].n_value;
+       if (mp == 0) {
+               fprintf(stderr, "vmstat: Disk init info not in namelist\n");
+               exit(1);
+       }
+       for (;;) {
+               steal(mp++, mdev);
+               if (mdev.iod_driver == 0)
+                       break;
+               if (mdev.iod_dk < 0 || mdev.iod_alive == 0)
+                       continue;
+               steal(mdev.iod_driver, mdrv);
+               steal(mdrv.idr_dname, two_char);
+               sprintf(dr_name[mdev.iod_dk], "%c%c", cp[0], cp[1]);
+               dr_unit[mdev.iod_dk] = mdev.iod_unit;
+       }
+}
+#endif ibm032
+
+#ifdef tahoe
+read_names()
+{
+       struct vba_device udev, *up;
+       struct vba_driver udrv;
+       short two_char;
+       char *cp = (char *)&two_char;
+
+       up = (struct vba_device *) nl[X_VBDINIT].n_value;
+       if (up == 0) {
+               fprintf(stderr, "vmstat: Disk init info not in namelist\n");
+               exit(1);
+       }
+       for (;;) {
+               steal(up++, udev);
+               if (udev.ui_driver == 0)
+                       break;
+               if (udev.ui_dk < 0 || udev.ui_alive == 0)
+                       continue;
+               steal(udev.ui_driver, udrv);
+               steal(udrv.ud_dname, two_char);
+               sprintf(dr_name[udev.ui_dk], "%c%c%d",
+                    cp[0], cp[1], udev.ui_unit);
+       }
+}
+#endif
+
+usage()
+{
+       fprintf(stderr,
+               "Usage: xperfmon [host:display] option option .....\n");
+       exit(1);
+}