1/* 2 * Copyright (c) 1984 through 2008, William LeFebvre 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * * Neither the name of William LeFebvre nor the names of other 17 * contributors may be used to endorse or promote products derived from 18 * this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33/* 34 * top - a top users display for Unix 35 * 36 * SYNOPSIS: Intel based System V Release 4 37 * 38 * DESCRIPTION: 39 * System V release 4.0.x for i486 40 * System V release 4 for Okidata M88100 41 * System V release 4 for NCR 3000 series OS Rel 1.00 to 2.02 42 * System V release 4 for NCR 3000 series OS Rel 02.03.00 and above 43 * and probably other svr4 ports 44 * 45 * LIBS: -lelf 46 * 47 * AUTHORS: Andrew Herbert <andrew@werple.apana.org.au> 48 * Robert Boucher <boucher@sofkin.ca> 49 * Ported to System 3000 Release 2.03 by: 50 * Jeff Janvrin <jeff.janvrinColumbiaSC.NCR.COM> 51 */ 52 53#include "top.h" 54#include "machine.h" 55#include "utils.h" 56#include <stdio.h> 57#include <fcntl.h> 58#include <unistd.h> 59#include <stdlib.h> 60#include <errno.h> 61#include <dirent.h> 62#include <nlist.h> 63#include <string.h> 64#if TIME_WITH_SYS_TIME 65# include <sys/time.h> 66# include <time.h> 67#else 68# if HAVE_SYS_TIME_H 69# include <sys/time.h> 70# else 71# include <time.h> 72# endif 73#endif 74#include <sys/types.h> 75#include <sys/stat.h> 76#include <sys/param.h> 77#include <sys/procfs.h> 78#include <sys/sysinfo.h> 79#include <sys/sysmacros.h> 80#include <sys/vmmeter.h> 81#include <vm/anon.h> 82#include <sys/priocntl.h> 83#include <sys/rtpriocntl.h> 84#include <sys/tspriocntl.h> 85#include <sys/procset.h> 86#include <sys/var.h> 87 88#define UNIX "/stand/unix" 89#define KMEM "/dev/kmem" 90#define PROCFS "/proc" 91#define CPUSTATES 5 92 93#ifndef PRIO_MAX 94#define PRIO_MAX 20 95#endif 96#ifndef PRIO_MIN 97#define PRIO_MIN -20 98#endif 99 100#ifndef FSCALE 101#define FSHIFT 8 /* bits to right of fixed binary point */ 102#define FSCALE (1<<FSHIFT) 103#endif 104 105#define loaddouble(x) ((double)(x) / FSCALE) 106#define percent_cpu(x) ((double)(x)->pr_cpu / FSCALE) 107#define weighted_cpu(pct, pp) ( ((pp)->pr_time.tv_sec) == 0 ? 0.0 : \ 108 ((pp)->pr_cpu) / ((pp)->pr_time.tv_sec) ) 109#define pagetok(size) ctob(size) >> LOG1024 110 111/* definitions for the index in the nlist array */ 112#define X_AVENRUN 0 113#define X_MPID 1 114#define X_V 2 115#define X_NPROC 3 116#define X_ANONINFO 4 117#define X_TOTAL 5 118#define X_SYSINFO 6 119 120static struct nlist nlst[] = 121{ 122{"avenrun"}, /* 0 */ 123{"mpid"}, /* 1 */ 124{"v"}, /* 2 */ 125{"nproc"}, /* 3 */ 126{"anoninfo"}, /* 4 */ 127{"total"}, /* 5 */ 128{"sysinfo"}, /* 6 */ 129{NULL} 130}; 131 132static unsigned long avenrun_offset; 133static unsigned long mpid_offset; 134static unsigned long nproc_offset; 135static unsigned long anoninfo_offset; 136static unsigned long total_offset; 137static unsigned long sysinfo_offset; 138 139/* get_process_info passes back a handle. This is what it looks like: */ 140 141struct handle 142 { 143 struct prpsinfo **next_proc;/* points to next valid proc pointer */ 144 int remaining; /* number of pointers remaining */ 145 }; 146 147/* 148 * These definitions control the format of the per-process area 149 */ 150 151static char header[] = 152" PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND"; 153/* 0123456 -- field to fill in starts at header+6 */ 154#define UNAME_START 6 155#define Proc_format \ 156 "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %3d.0%% %5.2f%% %.16s" 157 158char *state_abbrev[] = 159{"", "sleep", "run", "zombie", "stop", "start", "cpu", "swap"}; 160 161int process_states[8]; 162char *procstatenames[] = 163{ 164 "", " sleeping, ", " running, ", " zombie, ", " stopped, ", 165 " starting, ", " on cpu, ", " swapped, ", 166 NULL 167}; 168 169int cpu_states[CPUSTATES]; 170char *cpustatenames[] = 171{"idle", "user", "kernel", "wait", "swap", NULL}; 172 173/* these are for detailing the memory statistics */ 174 175long memory_stats[5]; 176char *memorynames[] = 177{"K real, ", "K active, ", "K free, ", "K swap, ", "K free swap", NULL}; 178 179/* forward reference for qsort comparison function */ 180int proc_compare(); 181 182static int kmem = -1; 183static int nproc; 184static int bytes; 185static int use_stats = 0; 186static struct prpsinfo *pbase; 187static struct prpsinfo **pref; 188static DIR *proc_dir; 189 190/* useful externals */ 191extern int errno; 192extern char *sys_errlist[]; 193extern char *myname; 194extern int check_nlist (); 195extern int getkval (); 196extern void perror (); 197extern void getptable (); 198extern void quit (); 199extern int nlist (); 200 201int 202machine_init (struct statics *statics) 203 { 204 static struct var v; 205 206 /* fill in the statics information */ 207 statics->procstate_names = procstatenames; 208 statics->cpustate_names = cpustatenames; 209 statics->memory_names = memorynames; 210 211 /* get the list of symbols we want to access in the kernel */ 212 if (nlist (UNIX, nlst)) 213 { 214 (void) fprintf (stderr, "Unable to nlist %s\n", UNIX); 215 return (-1); 216 } 217 218 /* make sure they were all found */ 219 if (check_nlist (nlst) > 0) 220 return (-1); 221 222 /* open kernel memory */ 223 if ((kmem = open (KMEM, O_RDONLY)) == -1) 224 { 225 perror (KMEM); 226 return (-1); 227 } 228 229 /* get the symbol values out of kmem */ 230 /* NPROC Tuning parameter for max number of processes */ 231 (void) getkval (nlst[X_V].n_value, &v, sizeof (struct var), nlst[X_V].n_name); 232 nproc = v.v_proc; 233 234 /* stash away certain offsets for later use */ 235 mpid_offset = nlst[X_MPID].n_value; 236 nproc_offset = nlst[X_NPROC].n_value; 237 avenrun_offset = nlst[X_AVENRUN].n_value; 238 anoninfo_offset = nlst[X_ANONINFO].n_value; 239 total_offset = nlst[X_TOTAL].n_value; 240/* JJ this may need to be changed */ 241 sysinfo_offset = nlst[X_SYSINFO].n_value; 242 243 /* allocate space for proc structure array and array of pointers */ 244 bytes = nproc * sizeof (struct prpsinfo); 245 pbase = (struct prpsinfo *) malloc (bytes); 246 pref = (struct prpsinfo **) malloc (nproc * sizeof (struct prpsinfo *)); 247 248 /* Just in case ... */ 249 if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL) 250 { 251 (void) fprintf (stderr, "%s: can't allocate sufficient memory\n", myname); 252 return (-1); 253 } 254 255 if (!(proc_dir = opendir (PROCFS))) 256 { 257 (void) fprintf (stderr, "Unable to open %s\n", PROCFS); 258 return (-1); 259 } 260 261 if (chdir (PROCFS)) 262 { /* handy for later on when we're reading it */ 263 (void) fprintf (stderr, "Unable to chdir to %s\n", PROCFS); 264 return (-1); 265 } 266 267 /* all done! */ 268 return (0); 269 } 270 271char * 272format_header (char *uname_field) 273{ 274 register char *ptr; 275 276 ptr = header + UNAME_START; 277 while (*uname_field != '\0') 278 *ptr++ = *uname_field++; 279 280 return (header); 281} 282 283void 284get_system_info (struct system_info *si) 285{ 286 long avenrun[3]; 287 struct sysinfo sysinfo; 288 static struct sysinfo *mpinfo = NULL; /* array, per-processor sysinfo structures. */ 289 struct vmtotal total; 290 struct anoninfo anoninfo; 291 static long cp_old[CPUSTATES]; 292 static long cp_diff[CPUSTATES]; /* for cpu state percentages */ 293 static int num_cpus; 294 static int fd_cpu = 0; 295 register int i; 296 297 if ( use_stats == 1) { 298 if ( fd_cpu == 0 ) { 299 if ((fd_cpu = open("/stats/cpuinfo", O_RDONLY)) == -1) { 300 (void) fprintf (stderr, "%s: Open of /stats/cpuinfo failed\n", myname); 301 quit(2); 302 } 303 if (read(fd_cpu, &num_cpus, sizeof(int)) != sizeof(int)) { 304 (void) fprintf (stderr, "%s: Read of /stats/cpuinfo failed\n", myname); 305 quit(2); 306 } 307 close(fd_cpu); 308 } 309 if (mpinfo == NULL) { 310 mpinfo = (struct sysinfo *)calloc(num_cpus, sizeof(mpinfo[0])); 311 if (mpinfo == NULL) { 312 (void) fprintf (stderr, "%s: can't allocate space for per-processor sysinfos\n", myname); 313 quit(12); 314 } 315 } 316 /* Read the per cpu sysinfo structures into mpinfo struct. */ 317 read_sysinfos(num_cpus, mpinfo); 318 /* Add up all of the percpu sysinfos to get global sysinfo */ 319 sysinfo_data(num_cpus, &sysinfo, mpinfo); 320 } else { 321 (void) getkval (sysinfo_offset, &sysinfo, sizeof (struct sysinfo), "sysinfo"); 322 } 323 324 /* convert cp_time counts to percentages */ 325 (void) percentages (CPUSTATES, cpu_states, sysinfo.cpu, cp_old, cp_diff); 326 327 /* get mpid -- process id of last process */ 328 (void) getkval (mpid_offset, &(si->last_pid), sizeof (si->last_pid), 329 "mpid"); 330 331 /* get load average array */ 332 (void) getkval (avenrun_offset, (int *) avenrun, sizeof (avenrun), "avenrun"); 333 334 /* convert load averages to doubles */ 335 for (i = 0; i < 3; i++) 336 si->load_avg[i] = loaddouble (avenrun[i]); 337 338 /* get total -- systemwide main memory usage structure */ 339 (void) getkval (total_offset, (int *) (&total), sizeof (total), "total"); 340 /* convert memory stats to Kbytes */ 341 memory_stats[0] = pagetok (total.t_rm); 342 memory_stats[1] = pagetok (total.t_arm); 343 memory_stats[2] = pagetok (total.t_free); 344 (void) getkval (anoninfo_offset, (int *) (&anoninfo), sizeof (anoninfo), 345 "anoninfo"); 346 memory_stats[3] = pagetok (anoninfo.ani_max - anoninfo.ani_free); 347 memory_stats[4] = pagetok (anoninfo.ani_max - anoninfo.ani_resv); 348 349 /* set arrays and strings */ 350 si->cpustates = cpu_states; 351 si->memory = memory_stats; 352} 353 354static struct handle handle; 355 356caddr_t 357get_process_info ( 358 struct system_info *si, 359 struct process_select *sel, 360 int x) 361{ 362 register int i; 363 register int total_procs; 364 register int active_procs; 365 register struct prpsinfo **prefp; 366 register struct prpsinfo *pp; 367 368 /* these are copied out of sel for speed */ 369 int show_idle; 370 int show_system; 371 int show_uid; 372 373 /* Get current number of processes */ 374 (void) getkval (nproc_offset, (int *) (&nproc), sizeof (nproc), "nproc"); 375 376 /* read all the proc structures */ 377 getptable (pbase); 378 379 /* get a pointer to the states summary array */ 380 si->procstates = process_states; 381 382 /* set up flags which define what we are going to select */ 383 show_idle = sel->idle; 384 show_system = sel->system; 385 show_uid = sel->uid != -1; 386 387 /* count up process states and get pointers to interesting procs */ 388 total_procs = 0; 389 active_procs = 0; 390 (void) memset (process_states, 0, sizeof (process_states)); 391 prefp = pref; 392 393 for (pp = pbase, i = 0; i < nproc; pp++, i++) 394 { 395 /* 396 * Place pointers to each valid proc structure in pref[]. 397 * Process slots that are actually in use have a non-zero 398 * status field. Processes with SSYS set are system 399 * processes---these get ignored unless show_sysprocs is set. 400 */ 401 if (pp->pr_state != 0 && 402 (show_system || ((pp->pr_flag & SSYS) == 0))) 403 { 404 total_procs++; 405 process_states[pp->pr_state]++; 406 if ((!pp->pr_zomb) && 407 (show_idle || (pp->pr_state == SRUN) || (pp->pr_state == SONPROC)) && 408 (!show_uid || pp->pr_uid == (uid_t) sel->uid)) 409 { 410 *prefp++ = pp; 411 active_procs++; 412 } 413 } 414 } 415 416 /* if requested, sort the "interesting" processes */ 417 qsort ((char *) pref, active_procs, sizeof (struct prpsinfo *), proc_compare); 418 419 /* remember active and total counts */ 420 si->p_total = total_procs; 421 si->p_active = active_procs; 422 423 /* pass back a handle */ 424 handle.next_proc = pref; 425 handle.remaining = active_procs; 426 return ((caddr_t) & handle); 427} 428 429char fmt[MAX_COLS]; /* static area where result is built */ 430 431char * 432format_next_process ( 433 caddr_t handle, 434 char *(*get_userid) ()) 435{ 436 register struct prpsinfo *pp; 437 struct handle *hp; 438 register long cputime; 439 register double pctcpu; 440 441 /* find and remember the next proc structure */ 442 hp = (struct handle *) handle; 443 pp = *(hp->next_proc++); 444 hp->remaining--; 445 446 /* get the cpu usage and calculate the cpu percentages */ 447 cputime = pp->pr_time.tv_sec; 448 pctcpu = percent_cpu (pp); 449 450 /* format this entry */ 451 (void) sprintf (fmt, 452 Proc_format, 453 pp->pr_pid, 454 (*get_userid) (pp->pr_uid), 455 pp->pr_pri - PZERO, 456 pp->pr_nice - NZERO, 457 format_k(pagetok (pp->pr_size)), 458 format_k(pagetok (pp->pr_rssize)), 459 state_abbrev[pp->pr_state], 460 format_time(cputime), 461 (pp->pr_cpu & 0377), 462 100.0 * pctcpu, 463 printable(pp->pr_fname)); 464 465 /* return the result */ 466 return (fmt); 467} 468 469/* 470 * check_nlist(nlst) - checks the nlist to see if any symbols were not 471 * found. For every symbol that was not found, a one-line 472 * message is printed to stderr. The routine returns the 473 * number of symbols NOT found. 474 */ 475int 476check_nlist (register struct nlist *nlst) 477{ 478 register int i; 479 struct stat stat_buf; 480 481 /* check to see if we got ALL the symbols we requested */ 482 /* this will write one line to stderr for every symbol not found */ 483 484 i = 0; 485 while (nlst->n_name != NULL) 486 { 487 if (nlst->n_type == 0) 488 { 489 if (strcmp("sysinfo", nlst->n_name) == 0) 490 { 491 /* check to see if /stats file system exists. If so, */ 492 /* ignore error. */ 493 if ( !((stat("/stats/sysinfo", &stat_buf) == 0) && 494 (stat_buf.st_mode & S_IFREG)) ) 495 { 496 (void) fprintf (stderr, "kernel: no symbol named `%s'\n", nlst->n_name); 497 i = 1; 498 } else { 499 use_stats = 1; 500 } 501 } else { 502 503 /* this one wasn't found */ 504 (void) fprintf (stderr, "kernel: no symbol named `%s'\n", nlst->n_name); 505 i = 1; 506 } 507 } 508 nlst++; 509 } 510 return (i); 511} 512 513 514/* 515 * getkval(offset, ptr, size, refstr) - get a value out of the kernel. 516 * "offset" is the byte offset into the kernel for the desired value, 517 * "ptr" points to a buffer into which the value is retrieved, 518 * "size" is the size of the buffer (and the object to retrieve), 519 * "refstr" is a reference string used when printing error meessages, 520 * if "refstr" starts with a '!', then a failure on read will not 521 * be fatal (this may seem like a silly way to do things, but I 522 * really didn't want the overhead of another argument). 523 * 524 */ 525int 526getkval ( 527 unsigned long offset, 528 int *ptr, 529 int size, 530 char *refstr) 531{ 532#ifdef MIPS 533 if (lseek (kmem, (long) (offset & 0x7fffffff), 0) == -1) 534#else 535 if (lseek (kmem, (long) offset, 0) == -1) 536#endif 537 { 538 if (*refstr == '!') 539 refstr++; 540 (void) fprintf (stderr, "%s: lseek to %s: %s\n", 541 myname, refstr, sys_errlist[errno]); 542 quit (22); 543 } 544 if (read (kmem, (char *) ptr, size) == -1) 545 if (*refstr == '!') 546 /* we lost the race with the kernel, process isn't in memory */ 547 return (0); 548 else 549 { 550 (void) fprintf (stderr, "%s: reading %s: %s\n", 551 myname, refstr, sys_errlist[errno]); 552 quit (23); 553 } 554 return (1); 555} 556 557/* comparison routine for qsort */ 558 559/* 560 * proc_compare - comparison function for "qsort" 561 * Compares the resource consumption of two processes using five 562 * distinct keys. The keys (in descending order of importance) are: 563 * percent cpu, cpu ticks, state, resident set size, total virtual 564 * memory usage. The process states are ordered as follows (from least 565 * to most important): WAIT, zombie, sleep, stop, start, run. The 566 * array declaration below maps a process state index into a number 567 * that reflects this ordering. 568 */ 569 570 571unsigned char sorted_state[] = 572{ 573 0, /* not used */ 574 3, /* sleep */ 575 6, /* run */ 576 2, /* zombie */ 577 4, /* stop */ 578 5, /* start */ 579 7, /* run on a processor */ 580 1 /* being swapped (WAIT) */ 581}; 582 583int 584proc_compare ( 585 struct prpsinfo **pp1, 586 struct prpsinfo **pp2) 587{ 588 register struct prpsinfo *p1; 589 register struct prpsinfo *p2; 590 register long result; 591 592 /* remove one level of indirection */ 593 p1 = *pp1; 594 p2 = *pp2; 595 596 /* compare percent cpu (pctcpu) */ 597 if ((result = (long) (p2->pr_cpu - p1->pr_cpu)) == 0) 598 { 599 /* use cpticks to break the tie */ 600 if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0) 601 { 602 /* use process state to break the tie */ 603 if ((result = (long) (sorted_state[p2->pr_state] - 604 sorted_state[p1->pr_state])) == 0) 605 { 606 /* use priority to break the tie */ 607 if ((result = p2->pr_oldpri - p1->pr_oldpri) == 0) 608 { 609 /* use resident set size (rssize) to break the tie */ 610 if ((result = p2->pr_rssize - p1->pr_rssize) == 0) 611 { 612 /* use total memory to break the tie */ 613 result = (p2->pr_size - p1->pr_size); 614 } 615 } 616 } 617 } 618 } 619 return (result); 620 } 621 622/* 623get process table 624*/ 625void 626getptable (struct prpsinfo *baseptr) 627{ 628 struct prpsinfo *currproc; /* pointer to current proc structure */ 629 int numprocs = 0; 630 struct dirent *direntp; 631 632 for (rewinddir (proc_dir); direntp = readdir (proc_dir);) 633 { 634 int fd; 635 636 if ((fd = open (direntp->d_name, O_RDONLY)) < 0) 637 continue; 638 639 currproc = &baseptr[numprocs]; 640 if (ioctl (fd, PIOCPSINFO, currproc) < 0) 641 { 642 (void) close (fd); 643 continue; 644 } 645 646 numprocs++; 647 (void) close (fd); 648 } 649 650 if (nproc != numprocs) 651 nproc = numprocs; 652} 653 654/* return the owner of the specified process, for use in commands.c as we're 655 running setuid root */ 656int 657proc_owner (int pid) 658{ 659 register struct prpsinfo *p; 660 int i; 661 for (i = 0, p = pbase; i < nproc; i++, p++) 662 if (p->pr_pid == (pid_t)pid) 663 return (p->pr_uid); 664 665 return (-1); 666} 667 668#ifndef HAVE_SETPRIORITY 669int 670setpriority (int dummy, int who, int niceval) 671{ 672 int scale; 673 int prio; 674 pcinfo_t pcinfo; 675 pcparms_t pcparms; 676 tsparms_t *tsparms; 677 678 strcpy (pcinfo.pc_clname, "TS"); 679 if (priocntl (0, 0, PC_GETCID, (caddr_t) & pcinfo) == -1) 680 return (-1); 681 682 prio = niceval; 683 if (prio > PRIO_MAX) 684 prio = PRIO_MAX; 685 else if (prio < PRIO_MIN) 686 prio = PRIO_MIN; 687 688 tsparms = (tsparms_t *) pcparms.pc_clparms; 689 scale = ((tsinfo_t *) pcinfo.pc_clinfo)->ts_maxupri; 690 tsparms->ts_uprilim = tsparms->ts_upri = -(scale * prio) / 20; 691 pcparms.pc_cid = pcinfo.pc_cid; 692 693 if (priocntl (P_PID, who, PC_SETPARMS, (caddr_t) & pcparms) == -1) 694 return (-1); 695 696 return (0); 697} 698#endif 699 700/**************************************************************** 701 * read_sysinfos() - * 702 * Read all of the CPU specific sysinfo sturctures in from * 703 * the /stats file system. * 704 ****************************************************************/ 705read_sysinfos(num_cpus, buf) 706 int num_cpus; 707 struct sysinfo *buf; 708{ 709 710 static int fd1=0; /* file descriptor for /stats/sysinfo */ 711 int read_sz; 712 713 /* Open /stats/sysinfo one time only and leave it open */ 714 if (fd1==0) { 715 if ((fd1 = open("/stats/sysinfo", O_RDONLY)) == -1) 716 (void) fprintf (stderr, "%s: Open of /stats/sysinfo failed\n", myname); 717 } 718 /* reset the read pointer to the beginning of the file */ 719 if (lseek(fd1, 0L, SEEK_SET) == -1) 720 (void) fprintf (stderr, "%s: lseek to beginning of /stats/sysinfo failed\n", myname); 721 read_sz = num_cpus * sizeof(buf[0]); 722 if (read(fd1, buf, read_sz) != read_sz) 723 (void) fprintf (stderr, "%s: Read of /stats/sysinfo failed\n", myname); 724} 725 726/**************************************************************** 727 * sysinfo_data() - * 728 * Add up all of the CPU specific sysinfo sturctures to * 729 * make the GLOBAL sysinfo. * 730 ****************************************************************/ 731sysinfo_data(num_cpus, global_si, percpu_si) 732 int num_cpus; 733 struct sysinfo *global_si; 734 struct sysinfo *percpu_si; 735{ 736 struct sysinfo *percpu_p; 737 int cpu, i, *global, *src; 738 739 /* null out the global statistics from last sample */ 740 memset(global_si, 0, sizeof(struct sysinfo)); 741 742 percpu_p = (struct sysinfo *)percpu_si; 743 for(cpu = 0; cpu < num_cpus; cpu++) { 744 global = (int *)global_si; 745 src = (int *)percpu_p; 746 747 /* assume sysinfo ends on an int boundary */ 748 /* Currently, all of the struct sysinfo members are the same 749 * size as an int. If that changes, we may not be able to 750 * do this. But this should be safe. 751 */ 752 for(i=0; i<sizeof(struct sysinfo)/sizeof(int); i++) { 753 *global++ += *src++; 754 } 755 percpu_p++; 756 } 757} 758