Home | History | Annotate | Line # | Download | only in machine
      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 (at) fwi.uva.nl>
     50  *
     51  * PATCHES: Antoine Tabary <tabary (at) bruyeres.cea.fr>, Dan Nelson <dnelson (at) 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 (at) 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