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 */ 85 struct 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 105 static 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 */ 116 struct 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 */ 125 static 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 */ 135 int process_states[9]; 136 char *procstatenames[] = { 137 " none, ", " sleeping, ", " state2, ", " runnable, ", 138 " idle, ", " zombie, ", " stopped, ", " running, ", " swapped, ", 139 NULL 140 }; 141 142 /* these are for detailing the cpu states */ 143 int cpu_states[CPU_NTIMES]; 144 char *cpustatenames[] = { 145 "idle", "user", "kernel", "wait", 146 NULL 147 }; 148 149 /* these are for detailing the memory statistics */ 150 long memory_stats[7]; 151 char *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 159 long swap_stats[3]; 160 char *swapnames[] = { 161 "K total, ", "K free", NULL 162 }; 163 #define M_VIRTUAL 0 164 #define M_VIRTFREE 1 165 166 char *state_abbrev[] = { 167 NULL, NULL, NULL, NULL, "idle", "zomb", "stop", "run", "swap" 168 }; 169 170 /* sorting orders. first is default */ 171 char *ordernames[] = { 172 "cpu", "size", "res", "time", "pri", NULL 173 }; 174 175 /* compare routines */ 176 int compare_cpu(), compare_size(), compare_res(), compare_time(), 177 compare_prio(); 178 179 int (*proc_compares[])() = { 180 compare_cpu, 181 compare_size, 182 compare_res, 183 compare_time, 184 compare_prio, 185 NULL 186 }; 187 188 /* useful externals */ 189 long percentages(int cnt, int *out, long *new, long *old, long *diffs); 190 char *format_time(long seconds); 191 192 #ifdef OLD 193 /* useful globals */ 194 int kmem; /* file descriptor */ 195 196 /* offsets in kernel */ 197 static unsigned long avenrun_offset; 198 static unsigned long sysinfo_offset; 199 static unsigned long vmker_offset; 200 static unsigned long v_offset; 201 #endif 202 203 /* used for calculating cpu state percentages */ 204 static long cp_time[CPU_NTIMES]; 205 static long cp_old[CPU_NTIMES]; 206 static long cp_diff[CPU_NTIMES]; 207 208 /* the runqueue length is a cumulative value. keep old value */ 209 long old_runque; 210 211 /* process info */ 212 struct kernvars v_info; /* to determine nprocs */ 213 int nprocs; /* maximum nr of procs in proctab */ 214 int ncpus; /* nr of cpus installed */ 215 216 struct procentry64 *p_info; /* needed for vm and ru info */ 217 struct procentry64 **pref; /* processes selected for display */ 218 struct timeval64 *cpu_proc, *old_cpu_proc; /* total cpu used by each process */ 219 int pref_len; /* number of processes selected */ 220 221 /* needed to calculate WCPU */ 222 unsigned long curtime; 223 224 /* needed to calculate CPU */ 225 struct timeval curtimeval; 226 struct timeval lasttimeval; 227 228 #ifdef OLD 229 int getkval(unsigned long offset, caddr_t ptr, int size, char *refstr); 230 #endif 231 232 void *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 */ 246 int 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 296 char *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 313 void 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 413 static struct handle handle; 414 415 caddr_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 530 char 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 536 char *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 */ 598 int 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 657 static 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 672 int 673 compare_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 694 int 695 compare_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 716 int 717 compare_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 738 int 739 compare_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 760 int 761 compare_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 780 int proc_owner(pid) 781 int 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