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