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
xmalloc(long size)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 */
machine_init(statics)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
format_header(uname_field)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
get_system_info(si)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
get_process_info(si,sel,compare_index)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
format_next_process(handle,get_userid)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 */
getkval(offset,ptr,size,refstr)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
compare_cpu(ppi1,ppi2)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
compare_size(ppi1,ppi2)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
compare_res(ppi1,ppi2)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
compare_time(ppi1,ppi2)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
compare_prio(ppi1,ppi2)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
proc_owner(pid)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