| 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 | } |