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