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: PowerPC running AIX 5.1 or higher 37 * 38 * DESCRIPTION: 39 * This is the machine-dependent module for AIX 5.1 and higher (may work on 40 * older releases too). It is currently only tested on PowerPC 41 * architectures. 42 * 43 * TERMCAP: -lcurses 44 * 45 * CFLAGS: -DORDER -DHAVE_GETOPT -DHAVE_STRERROR -DMAXPROCS=10240 46 * 47 * LIBS: -lperfstat 48 * 49 * AUTHOR: Joep Vesseur <joep@fwi.uva.nl> 50 * 51 * PATCHES: Antoine Tabary <tabary@bruyeres.cea.fr>, Dan Nelson <dnelson@allantgroup.com> 52 */ 53 54#define MAXPROCS 10240 55 56#include "config.h" 57 58#include <time.h> 59#include <stdlib.h> 60#include <string.h> 61#include <stdio.h> 62#include <fcntl.h> 63#include <nlist.h> 64#include <procinfo.h> 65#include <sys/types.h> 66#include <sys/proc.h> 67#include <sys/sysinfo.h> 68#include <sys/sysconfig.h> 69#include <pwd.h> 70#include <errno.h> 71#include <libperfstat.h> 72#include "top.h" 73#include "machine.h" 74#include "utils.h" 75 76 77#define PROCRESS(p) (((p)->pi_trss + (p)->pi_drss)*4) 78#define PROCSIZE(p) (((p)->pi_tsize/1024+(p)->pi_dvm)*4) 79#define PROCTIME(pi) (pi->pi_ru.ru_utime.tv_sec + pi->pi_ru.ru_stime.tv_sec) 80 81#ifdef OLD 82/* 83 * structure definition taken from 'monitor' by Jussi Maki (jmaki@hut.fi) 84 */ 85struct vmker { 86 uint n0,n1,n2,n3,n4,n5,n6,n7,n8; 87 uint totalmem; 88 uint badmem; /* this is used in RS/6000 model 220 */ 89 uint freemem; 90 uint n12; 91 uint numperm; /* this seems to keep other than text and data segment 92 usage; name taken from /usr/lpp/bos/samples/vmtune.c */ 93 uint totalvmem,freevmem; 94 uint n15, n16, n17, n18, n19; 95}; 96 97#define KMEM "/dev/kmem" 98 99/* Indices in the nlist array */ 100#define X_AVENRUN 0 101#define X_SYSINFO 1 102#define X_VMKER 2 103#define X_V 3 104 105static struct nlist nlst[] = { 106 { "avenrun", 0, 0, 0, 0, 0 }, /* 0 */ 107 { "sysinfo", 0, 0, 0, 0, 0 }, /* 1 */ 108 { "vmker", 0, 0, 0, 0, 0 }, /* 2 */ 109 { "v", 0, 0, 0, 0, 0 }, /* 3 */ 110 { NULL, 0, 0, 0, 0, 0 } 111}; 112 113#endif 114 115/* get_process_info returns handle. definition is here */ 116struct handle 117{ 118 struct procentry64 **next_proc; 119 int remaining; 120}; 121 122/* 123 * These definitions control the format of the per-process area 124 */ 125static char header[] = 126 " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND"; 127/* 0123456 -- field to fill in starts at header+6 */ 128#define UNAME_START 7 129 130#define Proc_format \ 131 "%6d %-8.8s %3d %4d %5d%c %4d%c %-5s %6s %5.2f%% %5.2f%% %.14s%s" 132 133 134/* these are for detailing the process states */ 135int process_states[9]; 136char *procstatenames[] = { 137 " none, ", " sleeping, ", " state2, ", " runnable, ", 138 " idle, ", " zombie, ", " stopped, ", " running, ", " swapped, ", 139 NULL 140}; 141 142/* these are for detailing the cpu states */ 143int cpu_states[CPU_NTIMES]; 144char *cpustatenames[] = { 145 "idle", "user", "kernel", "wait", 146 NULL 147}; 148 149/* these are for detailing the memory statistics */ 150long memory_stats[7]; 151char *memorynames[] = { 152 "K total, ", "K buf, ", "K sys, ", "K free", NULL 153}; 154#define M_REAL 0 155#define M_BUFFERS 1 156#define M_SYSTEM 2 157#define M_REALFREE 3 158 159long swap_stats[3]; 160char *swapnames[] = { 161 "K total, ", "K free", NULL 162}; 163#define M_VIRTUAL 0 164#define M_VIRTFREE 1 165 166char *state_abbrev[] = { 167 NULL, NULL, NULL, NULL, "idle", "zomb", "stop", "run", "swap" 168}; 169 170/* sorting orders. first is default */ 171char *ordernames[] = { 172 "cpu", "size", "res", "time", "pri", NULL 173}; 174 175/* compare routines */ 176int compare_cpu(), compare_size(), compare_res(), compare_time(), 177 compare_prio(); 178 179int (*proc_compares[])() = { 180 compare_cpu, 181 compare_size, 182 compare_res, 183 compare_time, 184 compare_prio, 185 NULL 186}; 187 188/* useful externals */ 189long percentages(int cnt, int *out, long *new, long *old, long *diffs); 190char *format_time(long seconds); 191 192#ifdef OLD 193/* useful globals */ 194int kmem; /* file descriptor */ 195 196/* offsets in kernel */ 197static unsigned long avenrun_offset; 198static unsigned long sysinfo_offset; 199static unsigned long vmker_offset; 200static unsigned long v_offset; 201#endif 202 203/* used for calculating cpu state percentages */ 204static long cp_time[CPU_NTIMES]; 205static long cp_old[CPU_NTIMES]; 206static long cp_diff[CPU_NTIMES]; 207 208/* the runqueue length is a cumulative value. keep old value */ 209long old_runque; 210 211/* process info */ 212struct kernvars v_info; /* to determine nprocs */ 213int nprocs; /* maximum nr of procs in proctab */ 214int ncpus; /* nr of cpus installed */ 215 216struct procentry64 *p_info; /* needed for vm and ru info */ 217struct procentry64 **pref; /* processes selected for display */ 218struct timeval64 *cpu_proc, *old_cpu_proc; /* total cpu used by each process */ 219int pref_len; /* number of processes selected */ 220 221/* needed to calculate WCPU */ 222unsigned long curtime; 223 224/* needed to calculate CPU */ 225struct timeval curtimeval; 226struct timeval lasttimeval; 227 228#ifdef OLD 229int getkval(unsigned long offset, caddr_t ptr, int size, char *refstr); 230#endif 231 232void *xmalloc(long size) 233{ 234 void *p = malloc(size); 235 if (!p) 236 { 237 fprintf(stderr,"Could not allocate %ld bytes: %s\n", size, strerror(errno)); 238 exit(1); 239 } 240 return p; 241} 242 243/* 244 * Initialize globals, get kernel offsets and stuff... 245 */ 246int machine_init(statics) 247 struct statics *statics; 248{ 249#ifdef OLD 250 if ((kmem = open(KMEM, O_RDONLY)) == -1) { 251 perror(KMEM); 252 return -1; 253 } 254 255 /* get kernel symbol offsets */ 256 if (knlist(nlst, 4, sizeof(struct nlist)) != 0) { 257 perror("knlist"); 258 return -1; 259 } 260 avenrun_offset = nlst[X_AVENRUN].n_value; 261 sysinfo_offset = nlst[X_SYSINFO].n_value; 262 vmker_offset = nlst[X_VMKER].n_value; 263 v_offset = nlst[X_V].n_value; 264 265 getkval(v_offset, (caddr_t)&v_info, sizeof v_info, "v"); 266#else 267 sysconfig(SYS_GETPARMS, &v_info, sizeof v_info); 268#endif 269 ncpus = v_info.v_ncpus; /* number of cpus */ 270 271/* procentry64 is 4912 bytes, and PROCMASK(PIDMAX) is 262144. That'd 272 require 1.2gb for the p_info array, which is way overkill. Raise 273 MAXPROCS if you have more than 10240 active processes in the system. 274*/ 275 276#if 0 277 nprocs = PROCMASK(PIDMAX); 278#else 279 nprocs = MAXPROCS; 280#endif 281 282 cpu_proc = (struct timeval64 *)xmalloc(PROCMASK(PIDMAX) * sizeof (struct timeval64)); 283 old_cpu_proc = (struct timeval64 *)xmalloc(PROCMASK(PIDMAX) * sizeof (struct timeval64)); 284 p_info = (struct procentry64 *)xmalloc(nprocs * sizeof (struct procentry64)); 285 pref = (struct procentry64 **)xmalloc(nprocs * sizeof (struct procentry64 *)); 286 287 statics->procstate_names = procstatenames; 288 statics->cpustate_names = cpustatenames; 289 statics->memory_names = memorynames; 290 statics->swap_names = swapnames; 291 statics->order_names = ordernames; 292 293 return(0); 294} 295 296char *format_header(uname_field) 297 register char *uname_field; 298{ 299 register char *ptr; 300 301 ptr = header + UNAME_START; 302 while (*uname_field != '\0') 303 { 304 *ptr++ = *uname_field++; 305 } 306 307 return(header); 308} 309 310 311 312 313void get_system_info(si) 314 struct system_info *si; 315{ 316#ifdef OLD 317 long long load_avg[3]; 318 struct sysinfo64 s_info; 319 struct vmker m_info; 320#else 321 perfstat_memory_total_t m_info1; 322 perfstat_cpu_total_t s_info1; 323#endif 324 int i; 325 int total = 0; 326 327#ifdef OLD 328 /* get the load avarage array */ 329 getkval(avenrun_offset, (caddr_t)load_avg, sizeof load_avg, "avenrun"); 330 331 /* get the sysinfo structure */ 332 getkval(sysinfo_offset, (caddr_t)&s_info, sizeof s_info, "sysinfo64"); 333 334 /* get vmker structure */ 335 getkval(vmker_offset, (caddr_t)&m_info, sizeof m_info, "vmker"); 336#else 337 /* cpu stats */ 338 perfstat_cpu_total(NULL, &s_info1, sizeof s_info1, 1); 339 340 /* memory stats */ 341 perfstat_memory_total(NULL, &m_info1, sizeof m_info1, 1); 342#endif 343 344 345#ifdef OLD 346 /* convert load avarages to doubles */ 347 for (i = 0; i < 3; i++) 348 si->load_avg[i] = (double)load_avg[i]/65536.0; 349 350 /* calculate cpu state in percentages */ 351 for (i = 0; i < CPU_NTIMES; i++) { 352 cp_old[i] = cp_time[i]; 353 cp_time[i] = s_info.cpu[i]; 354 cp_diff[i] = cp_time[i] - cp_old[i]; 355 total += cp_diff[i]; 356 } 357 358#else 359 /* convert load avarages to doubles */ 360 for (i = 0; i < 3; i++) 361 si->load_avg[i] = (double)s_info1.loadavg[i]/(1<<SBITS); 362 363 /* calculate cpu state in percentages */ 364 for (i = 0; i < CPU_NTIMES; i++) { 365 cp_old[i] = cp_time[i]; 366 cp_time[i] = ( i==CPU_IDLE?s_info1.idle: 367 i==CPU_USER?s_info1.user: 368 i==CPU_KERNEL?s_info1.sys: 369 i==CPU_WAIT?s_info1.wait:0); 370 cp_diff[i] = cp_time[i] - cp_old[i]; 371 total += cp_diff[i]; 372 } 373#endif 374 for (i = 0; i < CPU_NTIMES; i++) { 375 cpu_states[i] = 1000 * cp_diff[i] / total; 376 } 377 378 /* calculate memory statistics, scale 4K pages */ 379#ifdef OLD 380#define PAGE_TO_MB(a) ((a)*4/1024) 381 memory_stats[M_TOTAL] = PAGE_TO_MB(m_info.totalmem+m_info.totalvmem); 382 memory_stats[M_REAL] = PAGE_TO_MB(m_info.totalmem); 383 memory_stats[M_REALFREE] = PAGE_TO_MB(m_info.freemem); 384 memory_stats[M_BUFFERS] = PAGE_TO_MB(m_info.numperm); 385 swap_stats[M_VIRTUAL] = PAGE_TO_MB(m_info.totalvmem); 386 swap_stats[M_VIRTFREE] = PAGE_TO_MB(m_info.freevmem); 387#else 388#define PAGE_TO_KB(a) ((a)*4) 389 memory_stats[M_REAL] = PAGE_TO_KB(m_info1.real_total); 390 memory_stats[M_BUFFERS] = PAGE_TO_KB(m_info1.numperm); 391#ifdef _AIXVERSION_520 392 memory_stats[M_SYSTEM] = PAGE_TO_KB(m_info1.real_system); 393#endif 394 memory_stats[M_REALFREE] = PAGE_TO_KB(m_info1.real_free); 395 swap_stats[M_VIRTUAL] = PAGE_TO_KB(m_info1.pgsp_total); 396 swap_stats[M_VIRTFREE] = PAGE_TO_KB(m_info1.pgsp_free); 397#endif 398 399 /* runnable processes */ 400#ifdef OLD 401 process_states[0] = s_info.runque - old_runque; 402 old_runque = s_info.runque; 403#else 404 process_states[0] = s_info1.runque - old_runque; 405 old_runque = s_info1.runque; 406#endif 407 408 si->cpustates = cpu_states; 409 si->memory = memory_stats; 410 si->swap = swap_stats; 411} 412 413static struct handle handle; 414 415caddr_t get_process_info(si, sel, compare_index) 416 struct system_info *si; 417 struct process_select *sel; 418 int compare_index; 419{ 420 int i, nproc; 421 int active_procs = 0, total_procs = 0; 422 struct procentry64 *pp, **p_pref = pref; 423 struct timeval64 *cpu_proc_temp; 424 double timediff; 425 pid_t procsindex = 0; 426 427 si->procstates = process_states; 428 429 curtime = time(0); 430 lasttimeval = curtimeval; 431 gettimeofday(&curtimeval, NULL); 432 433 /* get the procentry64 structures of all running processes */ 434 nproc = getprocs64(p_info, sizeof (struct procentry64), NULL, 0, 435 &procsindex, nprocs); 436 if (nproc < 0) { 437 perror("getprocs64"); 438 quit(1); 439 } 440 441 /* the swapper has no cmd-line attached */ 442 strcpy(p_info[0].pi_comm, "swapper"); 443 444 if (lasttimeval.tv_sec) 445 { 446 timediff = (curtimeval.tv_sec - lasttimeval.tv_sec) + 447 1.0*(curtimeval.tv_usec - lasttimeval.tv_usec) / uS_PER_SECOND; 448 } 449 450 /* The pi_cpu value is wildly inaccurate. The maximum value is 120, but 451 when the scheduling timer fires, the field is zeroed for all 452 processes and ramps up over a short period of time. Instead of using 453 this weird number, manually calculate an accurate value from the 454 rusage data. Store this run's rusage in cpu_proc[pid], and subtract 455 from old_cpu_proc. 456 */ 457 for (pp = p_info, i = 0; i < nproc; pp++, i++) { 458 pid_t pid = PROCMASK(pp->pi_pid); 459 460 /* total system and user time into cpu_proc */ 461 cpu_proc[pid] = pp->pi_ru.ru_utime; 462 cpu_proc[pid].tv_sec += pp->pi_ru.ru_stime.tv_sec; 463 cpu_proc[pid].tv_usec += pp->pi_ru.ru_stime.tv_usec; 464 if (cpu_proc[pid].tv_usec > NS_PER_SEC) { 465 cpu_proc[pid].tv_sec++; 466 cpu_proc[pid].tv_usec -= NS_PER_SEC; 467 } 468 469 /* If this process was around during the previous update, calculate 470 a true %CPU. If not, convert the kernel's cpu value from its 471 120-max value to a 10000-max one. 472 */ 473 if (old_cpu_proc[pid].tv_sec == 0 && old_cpu_proc[pid].tv_usec == 0) 474 pp->pi_cpu = pp->pi_cpu * 10000 / 120; 475 else 476 pp->pi_cpu = ((cpu_proc[pid].tv_sec - old_cpu_proc[pid].tv_sec) + 477 1.0*(cpu_proc[pid].tv_usec - old_cpu_proc[pid].tv_usec) / NS_PER_SEC) / timediff * 10000; 478 } 479 480 /* remember our current values as old_cpu_proc, and zero out cpu_proc 481 for the next update cycle */ 482 memset(old_cpu_proc, 0, sizeof(struct timeval64) * nprocs); 483 cpu_proc_temp = cpu_proc; 484 cpu_proc = old_cpu_proc; 485 old_cpu_proc = cpu_proc_temp; 486 487 memset(process_states, 0, sizeof process_states); 488 489 /* build a list of pointers to processes to show. */ 490 for (pp = p_info, i = 0; i < nproc; pp++, i++) { 491 492 /* AIX marks all runnable processes as ACTIVE. We want to know 493 which processes are sleeping, so check used cpu and adjust status 494 field accordingly 495 */ 496 if (pp->pi_state == SACTIVE && pp->pi_cpu == 0) 497 pp->pi_state = SIDL; 498 499 if (pp->pi_state && (sel->system || ((pp->pi_flags & SKPROC) == 0))) { 500 total_procs++; 501 process_states[pp->pi_state]++; 502 if ( (pp->pi_state != SZOMB) && 503 (sel->idle || pp->pi_cpu != 0 || (pp->pi_state == SACTIVE)) 504 && (sel->uid == -1 || pp->pi_uid == (uid_t)sel->uid)) { 505 *p_pref++ = pp; 506 active_procs++; 507 } 508 } 509 } 510 511 /* the pref array now holds pointers to the procentry64 structures in 512 * the p_info array that were selected for display 513 */ 514 515 /* sort if requested */ 516 if ( proc_compares[compare_index] != NULL) 517 qsort((char *)pref, active_procs, sizeof (struct procentry64 *), 518 proc_compares[compare_index]); 519 520 si->last_pid = -1; /* no way to figure out last used pid */ 521 si->p_total = total_procs; 522 si->p_active = pref_len = active_procs; 523 524 handle.next_proc = pref; 525 handle.remaining = active_procs; 526 527 return((caddr_t)&handle); 528} 529 530char fmt[128]; /* static area where result is built */ 531 532/* define what weighted cpu is. use definition of %CPU from 'man ps(1)' */ 533#define weighted_cpu(pp) (PROCTIME(pp) == 0 ? 0.0 : \ 534 (((PROCTIME(pp)*100.0)/(curtime-pi->pi_start)))) 535 536char *format_next_process(handle, get_userid) 537 caddr_t handle; 538 char *(*get_userid)(); 539{ 540 register struct handle *hp; 541 register struct procentry64 *pi; 542 long cpu_time; 543 int proc_size, proc_ress; 544 char size_unit = 'K'; 545 char ress_unit = 'K'; 546 547 hp = (struct handle *)handle; 548 if (hp->remaining == 0) { /* safe guard */ 549 fmt[0] = '\0'; 550 return fmt; 551 } 552 pi = *(hp->next_proc++); 553 hp->remaining--; 554 555 cpu_time = PROCTIME(pi); 556 557 /* we disply sizes up to 10M in KiloBytes, beyond 10M in MegaBytes */ 558 if ((proc_size = (pi->pi_tsize/1024+pi->pi_dvm)*4) > 10240) { 559 proc_size /= 1024; 560 size_unit = 'M'; 561 } 562 if ((proc_ress = (pi->pi_trss + pi->pi_drss)*4) > 10240) { 563 proc_ress /= 1024; 564 ress_unit = 'M'; 565 } 566 567 sprintf(fmt, Proc_format , 568 pi->pi_pid, /* PID */ 569 (*get_userid)(pi->pi_uid), /* login name */ 570 pi->pi_nice, /* fixed or vari */ 571 getpriority(PRIO_PROCESS, pi->pi_pid), 572 proc_size, /* size */ 573 size_unit, /* K or M */ 574 proc_ress, /* resident */ 575 ress_unit, /* K or M */ 576 state_abbrev[pi->pi_state], /* process state */ 577 format_time(cpu_time), /* time used */ 578 weighted_cpu(pi), /* WCPU */ 579 pi->pi_cpu / 100.0, /* CPU */ 580 printable(pi->pi_comm), /* COMM */ 581 (pi->pi_flags & SKPROC) == 0 ? "" : " (sys)" /* kernel process? */ 582 ); 583 return(fmt); 584} 585 586#ifdef OLD 587/* 588 * getkval(offset, ptr, size, refstr) - get a value out of the kernel. 589 * "offset" is the byte offset into the kernel for the desired value, 590 * "ptr" points to a buffer into which the value is retrieved, 591 * "size" is the size of the buffer (and the object to retrieve), 592 * "refstr" is a reference string used when printing error meessages, 593 * if "refstr" starts with a '!', then a failure on read will not 594 * be fatal (this may seem like a silly way to do things, but I 595 * really didn't want the overhead of another argument). 596 * 597 */ 598int getkval(offset, ptr, size, refstr) 599 unsigned long offset; 600 caddr_t ptr; 601 int size; 602 char *refstr; 603{ 604 int upper_2gb = 0; 605 606 /* reads above 2Gb are done by seeking to offset%2Gb, and supplying 607 * 1 (opposed to 0) as fourth parameter to readx (see 'man kmem') 608 */ 609 if (offset > 1<<31) { 610 upper_2gb = 1; 611 offset &= 0x7fffffff; 612 } 613 614 if (lseek(kmem, offset, SEEK_SET) != offset) { 615 fprintf(stderr, "top: lseek failed\n"); 616 quit(2); 617 } 618 619 if (readx(kmem, ptr, size, upper_2gb) != size) { 620 if (*refstr == '!') 621 return 0; 622 else { 623 fprintf(stderr, "top: kvm_read for %s: %s\n", refstr, 624 sys_errlist[errno]); 625 quit(2); 626 } 627 } 628 629 return 1 ; 630} 631#endif 632 633/* comparison routine for qsort */ 634/* 635 * The following code is taken from the solaris module and adjusted 636 * for AIX -- JV . 637 */ 638 639#define ORDERKEY_PCTCPU \ 640 if ((result = pi2->pi_cpu - pi1->pi_cpu) == 0) 641 642#define ORDERKEY_CPTICKS \ 643 if ((result = PROCTIME(pi2) - PROCTIME(pi1)) == 0) 644 645#define ORDERKEY_STATE \ 646 if ((result = sorted_state[pi2->pi_state] \ 647 - sorted_state[pi1->pi_state]) == 0) 648 649/* Nice values directly reflect the process' priority, and are always >0 ;-) */ 650#define ORDERKEY_PRIO \ 651 if ((result = pi1->pi_nice - pi2->pi_nice) == 0) 652#define ORDERKEY_RSSIZE \ 653 if ((result = PROCRESS(pi2) - PROCRESS(pi1)) == 0) 654#define ORDERKEY_MEM \ 655 if ((result = PROCSIZE(pi2) - PROCSIZE(pi1)) == 0) 656 657static unsigned char sorted_state[] = 658{ 659 0, /* not used */ 660 0, 661 0, 662 0, 663 3, /* sleep */ 664 1, /* zombie */ 665 4, /* stop */ 666 6, /* run */ 667 2, /* swap */ 668}; 669 670/* compare_cpu - the comparison function for sorting by cpu percentage */ 671 672int 673compare_cpu(ppi1, ppi2) 674 struct procentry64 **ppi1; 675 struct procentry64 **ppi2; 676{ 677 register struct procentry64 *pi1 = *ppi1, *pi2 = *ppi2; 678 register int result; 679 680 ORDERKEY_PCTCPU 681 ORDERKEY_CPTICKS 682 ORDERKEY_STATE 683 ORDERKEY_PRIO 684 ORDERKEY_RSSIZE 685 ORDERKEY_MEM 686 ; 687 688 return result; 689} 690 691 692/* compare_size - the comparison function for sorting by total memory usage */ 693 694int 695compare_size(ppi1, ppi2) 696 struct procentry64 **ppi1; 697 struct procentry64 **ppi2; 698{ 699 register struct procentry64 *pi1 = *ppi1, *pi2 = *ppi2; 700 register int result; 701 702 ORDERKEY_MEM 703 ORDERKEY_RSSIZE 704 ORDERKEY_PCTCPU 705 ORDERKEY_CPTICKS 706 ORDERKEY_STATE 707 ORDERKEY_PRIO 708 ; 709 710 return result; 711} 712 713 714/* compare_res - the comparison function for sorting by resident set size */ 715 716int 717compare_res(ppi1, ppi2) 718 struct procentry64 **ppi1; 719 struct procentry64 **ppi2; 720{ 721 register struct procentry64 *pi1 = *ppi1, *pi2 = *ppi2; 722 register int result; 723 724 ORDERKEY_RSSIZE 725 ORDERKEY_MEM 726 ORDERKEY_PCTCPU 727 ORDERKEY_CPTICKS 728 ORDERKEY_STATE 729 ORDERKEY_PRIO 730 ; 731 732 return result; 733} 734 735 736/* compare_time - the comparison function for sorting by total cpu time */ 737 738int 739compare_time(ppi1, ppi2) 740 struct procentry64 **ppi1; 741 struct procentry64 **ppi2; 742{ 743 register struct procentry64 *pi1 = *ppi1, *pi2 = *ppi2; 744 register int result; 745 746 ORDERKEY_CPTICKS 747 ORDERKEY_PCTCPU 748 ORDERKEY_STATE 749 ORDERKEY_PRIO 750 ORDERKEY_MEM 751 ORDERKEY_RSSIZE 752 ; 753 754 return result; 755} 756 757 758/* compare_prio - the comparison function for sorting by cpu percentage */ 759 760int 761compare_prio(ppi1, ppi2) 762 struct procentry64 **ppi1; 763 struct procentry64 **ppi2; 764{ 765 register struct procentry64 *pi1 = *ppi1, *pi2 = *ppi2; 766 register int result; 767 768 ORDERKEY_PRIO 769 ORDERKEY_PCTCPU 770 ORDERKEY_CPTICKS 771 ORDERKEY_STATE 772 ORDERKEY_RSSIZE 773 ORDERKEY_MEM 774 ; 775 776 return result; 777} 778 779 780int proc_owner(pid) 781int pid; 782{ 783 register struct procentry64 **prefp = pref; 784 register int cnt = pref_len; 785 786 while (--cnt >= 0) { 787 if ((*prefp)->pi_pid == pid) 788 return (*prefp)->pi_uid; 789 prefp++; 790 } 791 792 return(-1); 793} 794