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