xref: /minix/external/bsd/top/dist/machine/m_aix5.c (revision e1cdaee1)
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