Home | History | Annotate | Line # | Download | only in machine
      1  1.1  christos /*
      2  1.1  christos  * Copyright (c) 1984 through 2008, William LeFebvre
      3  1.1  christos  * All rights reserved.
      4  1.1  christos  *
      5  1.1  christos  * Redistribution and use in source and binary forms, with or without
      6  1.1  christos  * modification, are permitted provided that the following conditions are met:
      7  1.1  christos  *
      8  1.1  christos  *     * Redistributions of source code must retain the above copyright
      9  1.1  christos  * notice, this list of conditions and the following disclaimer.
     10  1.1  christos  *
     11  1.1  christos  *     * Redistributions in binary form must reproduce the above
     12  1.1  christos  * copyright notice, this list of conditions and the following disclaimer
     13  1.1  christos  * in the documentation and/or other materials provided with the
     14  1.1  christos  * distribution.
     15  1.1  christos  *
     16  1.1  christos  *     * Neither the name of William LeFebvre nor the names of other
     17  1.1  christos  * contributors may be used to endorse or promote products derived from
     18  1.1  christos  * this software without specific prior written permission.
     19  1.1  christos  *
     20  1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  1.1  christos  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22  1.1  christos  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     23  1.1  christos  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     24  1.1  christos  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25  1.1  christos  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     26  1.1  christos  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  1.1  christos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  1.1  christos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  1.1  christos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30  1.1  christos  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  1.1  christos  */
     32  1.1  christos 
     33  1.1  christos /*
     34  1.1  christos  * top - a top users display for Unix
     35  1.1  christos  *
     36  1.1  christos  * SYNOPSIS:  PowerPC running AIX 5.1 or higher
     37  1.1  christos  *
     38  1.1  christos  * DESCRIPTION:
     39  1.1  christos  * This is the machine-dependent module for AIX 5.1 and higher (may work on
     40  1.1  christos  * older releases too).  It is currently only tested on PowerPC
     41  1.1  christos  * architectures.
     42  1.1  christos  *
     43  1.1  christos  * TERMCAP: -lcurses
     44  1.1  christos  *
     45  1.1  christos  * CFLAGS: -DORDER -DHAVE_GETOPT -DHAVE_STRERROR -DMAXPROCS=10240
     46  1.1  christos  *
     47  1.1  christos  * LIBS: -lperfstat
     48  1.1  christos  *
     49  1.1  christos  * AUTHOR:  Joep Vesseur <joep (at) fwi.uva.nl>
     50  1.1  christos  *
     51  1.1  christos  * PATCHES: Antoine Tabary <tabary (at) bruyeres.cea.fr>, Dan Nelson <dnelson (at) allantgroup.com>
     52  1.1  christos  */
     53  1.1  christos 
     54  1.1  christos #define MAXPROCS 10240
     55  1.1  christos 
     56  1.1  christos #include "config.h"
     57  1.1  christos 
     58  1.1  christos #include <time.h>
     59  1.1  christos #include <stdlib.h>
     60  1.1  christos #include <string.h>
     61  1.1  christos #include <stdio.h>
     62  1.1  christos #include <fcntl.h>
     63  1.1  christos #include <nlist.h>
     64  1.1  christos #include <procinfo.h>
     65  1.1  christos #include <sys/types.h>
     66  1.1  christos #include <sys/proc.h>
     67  1.1  christos #include <sys/sysinfo.h>
     68  1.1  christos #include <sys/sysconfig.h>
     69  1.1  christos #include <pwd.h>
     70  1.1  christos #include <errno.h>
     71  1.1  christos #include <libperfstat.h>
     72  1.1  christos #include "top.h"
     73  1.1  christos #include "machine.h"
     74  1.1  christos #include "utils.h"
     75  1.1  christos 
     76  1.1  christos 
     77  1.1  christos #define PROCRESS(p) (((p)->pi_trss + (p)->pi_drss)*4)
     78  1.1  christos #define PROCSIZE(p) (((p)->pi_tsize/1024+(p)->pi_dvm)*4)
     79  1.1  christos #define PROCTIME(pi) (pi->pi_ru.ru_utime.tv_sec + pi->pi_ru.ru_stime.tv_sec)
     80  1.1  christos 
     81  1.1  christos #ifdef OLD
     82  1.1  christos /*
     83  1.1  christos  * structure definition taken from 'monitor' by Jussi Maki (jmaki (at) hut.fi)
     84  1.1  christos  */
     85  1.1  christos struct vmker {
     86  1.1  christos     uint n0,n1,n2,n3,n4,n5,n6,n7,n8;
     87  1.1  christos     uint totalmem;
     88  1.1  christos     uint badmem; /* this is used in RS/6000 model 220 */
     89  1.1  christos     uint freemem;
     90  1.1  christos     uint n12;
     91  1.1  christos     uint numperm;   /* this seems to keep other than text and data segment
     92  1.1  christos                        usage; name taken from /usr/lpp/bos/samples/vmtune.c */
     93  1.1  christos     uint totalvmem,freevmem;
     94  1.1  christos     uint n15, n16, n17, n18, n19;
     95  1.1  christos };
     96  1.1  christos 
     97  1.1  christos #define KMEM "/dev/kmem"
     98  1.1  christos 
     99  1.1  christos /* Indices in the nlist array */
    100  1.1  christos #define X_AVENRUN       0
    101  1.1  christos #define X_SYSINFO       1
    102  1.1  christos #define X_VMKER         2
    103  1.1  christos #define X_V             3
    104  1.1  christos 
    105  1.1  christos static struct nlist nlst[] = {
    106  1.1  christos     { "avenrun", 0, 0, 0, 0, 0 }, /* 0 */
    107  1.1  christos     { "sysinfo", 0, 0, 0, 0, 0 }, /* 1 */
    108  1.1  christos     { "vmker",   0, 0, 0, 0, 0 }, /* 2 */
    109  1.1  christos     { "v",       0, 0, 0, 0, 0 }, /* 3 */
    110  1.1  christos     {  NULL, 0, 0, 0, 0, 0 }
    111  1.1  christos };
    112  1.1  christos 
    113  1.1  christos #endif
    114  1.1  christos 
    115  1.1  christos /* get_process_info returns handle. definition is here */
    116  1.1  christos struct handle
    117  1.1  christos {
    118  1.1  christos 	struct procentry64 **next_proc;
    119  1.1  christos 	int remaining;
    120  1.1  christos };
    121  1.1  christos 
    122  1.1  christos /*
    123  1.1  christos  *  These definitions control the format of the per-process area
    124  1.1  christos  */
    125  1.1  christos static char header[] =
    126  1.1  christos   "   PID X        PRI NICE   SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
    127  1.1  christos /* 0123456   -- field to fill in starts at header+6 */
    128  1.1  christos #define UNAME_START 7
    129  1.1  christos 
    130  1.1  christos #define Proc_format \
    131  1.1  christos 	"%6d %-8.8s %3d %4d %5d%c %4d%c %-5s %6s %5.2f%% %5.2f%% %.14s%s"
    132  1.1  christos 
    133  1.1  christos 
    134  1.1  christos /* these are for detailing the process states */
    135  1.1  christos int process_states[9];
    136  1.1  christos char *procstatenames[] = {
    137  1.1  christos     " none, ", " sleeping, ", " state2, ", " runnable, ",
    138  1.1  christos     " idle, ", " zombie, ", " stopped, ", " running, ", " swapped, ",
    139  1.1  christos     NULL
    140  1.1  christos };
    141  1.1  christos 
    142  1.1  christos /* these are for detailing the cpu states */
    143  1.1  christos int cpu_states[CPU_NTIMES];
    144  1.1  christos char *cpustatenames[] = {
    145  1.1  christos     "idle", "user", "kernel", "wait",
    146  1.1  christos     NULL
    147  1.1  christos };
    148  1.1  christos 
    149  1.1  christos /* these are for detailing the memory statistics */
    150  1.1  christos long memory_stats[7];
    151  1.1  christos char *memorynames[] = {
    152  1.1  christos     "K total, ", "K buf, ", "K sys, ", "K free", NULL
    153  1.1  christos };
    154  1.1  christos #define M_REAL		0
    155  1.1  christos #define M_BUFFERS	1
    156  1.1  christos #define M_SYSTEM	2
    157  1.1  christos #define M_REALFREE	3
    158  1.1  christos 
    159  1.1  christos long swap_stats[3];
    160  1.1  christos char *swapnames[] = {
    161  1.1  christos     "K total, ", "K free", NULL
    162  1.1  christos };
    163  1.1  christos #define M_VIRTUAL 0
    164  1.1  christos #define M_VIRTFREE 1
    165  1.1  christos 
    166  1.1  christos char *state_abbrev[] = {
    167  1.1  christos     NULL, NULL, NULL, NULL, "idle", "zomb", "stop", "run", "swap"
    168  1.1  christos };
    169  1.1  christos 
    170  1.1  christos /* sorting orders. first is default */
    171  1.1  christos char *ordernames[] = {
    172  1.1  christos     "cpu", "size", "res", "time", "pri", NULL
    173  1.1  christos };
    174  1.1  christos 
    175  1.1  christos /* compare routines */
    176  1.1  christos int compare_cpu(), compare_size(), compare_res(), compare_time(),
    177  1.1  christos     compare_prio();
    178  1.1  christos 
    179  1.1  christos int (*proc_compares[])() = {
    180  1.1  christos     compare_cpu,
    181  1.1  christos     compare_size,
    182  1.1  christos     compare_res,
    183  1.1  christos     compare_time,
    184  1.1  christos     compare_prio,
    185  1.1  christos     NULL
    186  1.1  christos };
    187  1.1  christos 
    188  1.1  christos /* useful externals */
    189  1.1  christos long percentages(int cnt, int *out, long *new, long *old, long *diffs);
    190  1.1  christos char *format_time(long seconds);
    191  1.1  christos 
    192  1.1  christos #ifdef OLD
    193  1.1  christos /* useful globals */
    194  1.1  christos int kmem;			/* file descriptor */
    195  1.1  christos 
    196  1.1  christos /* offsets in kernel */
    197  1.1  christos static unsigned long avenrun_offset;
    198  1.1  christos static unsigned long sysinfo_offset;
    199  1.1  christos static unsigned long vmker_offset;
    200  1.1  christos static unsigned long v_offset;
    201  1.1  christos #endif
    202  1.1  christos 
    203  1.1  christos /* used for calculating cpu state percentages */
    204  1.1  christos static long cp_time[CPU_NTIMES];
    205  1.1  christos static long cp_old[CPU_NTIMES];
    206  1.1  christos static long cp_diff[CPU_NTIMES];
    207  1.1  christos 
    208  1.1  christos /* the runqueue length is a cumulative value. keep old value */
    209  1.1  christos long old_runque;
    210  1.1  christos 
    211  1.1  christos /* process info */
    212  1.1  christos struct kernvars v_info;		/* to determine nprocs */
    213  1.1  christos int nprocs;			/* maximum nr of procs in proctab */
    214  1.1  christos int ncpus;			/* nr of cpus installed */
    215  1.1  christos 
    216  1.1  christos struct procentry64 *p_info;	/* needed for vm and ru info */
    217  1.1  christos struct procentry64 **pref;	/* processes selected for display */
    218  1.1  christos struct timeval64 *cpu_proc, *old_cpu_proc; /* total cpu used by each process */
    219  1.1  christos int pref_len;			/* number of processes selected */
    220  1.1  christos 
    221  1.1  christos /* needed to calculate WCPU */
    222  1.1  christos unsigned long curtime;
    223  1.1  christos 
    224  1.1  christos /* needed to calculate CPU */
    225  1.1  christos struct timeval curtimeval;
    226  1.1  christos struct timeval lasttimeval;
    227  1.1  christos 
    228  1.1  christos #ifdef OLD
    229  1.1  christos int getkval(unsigned long offset, caddr_t ptr, int size, char *refstr);
    230  1.1  christos #endif
    231  1.1  christos 
    232  1.1  christos void *xmalloc(long size)
    233  1.1  christos {
    234  1.1  christos 	void *p = malloc(size);
    235  1.1  christos 	if (!p)
    236  1.1  christos 	{
    237  1.1  christos 		fprintf(stderr,"Could not allocate %ld bytes: %s\n", size, strerror(errno));
    238  1.1  christos 		exit(1);
    239  1.1  christos 	}
    240  1.1  christos 	return p;
    241  1.1  christos }
    242  1.1  christos 
    243  1.1  christos /*
    244  1.1  christos  * Initialize globals, get kernel offsets and stuff...
    245  1.1  christos  */
    246  1.1  christos int machine_init(statics)
    247  1.1  christos     struct statics *statics;
    248  1.1  christos {
    249  1.1  christos #ifdef OLD
    250  1.1  christos     if ((kmem = open(KMEM, O_RDONLY)) == -1) {
    251  1.1  christos 	perror(KMEM);
    252  1.1  christos 	return -1;
    253  1.1  christos     }
    254  1.1  christos 
    255  1.1  christos     /* get kernel symbol offsets */
    256  1.1  christos     if (knlist(nlst, 4, sizeof(struct nlist)) != 0) {
    257  1.1  christos 	perror("knlist");
    258  1.1  christos 	return -1;
    259  1.1  christos     }
    260  1.1  christos     avenrun_offset = nlst[X_AVENRUN].n_value;
    261  1.1  christos     sysinfo_offset = nlst[X_SYSINFO].n_value;
    262  1.1  christos     vmker_offset   = nlst[X_VMKER].n_value;
    263  1.1  christos     v_offset       = nlst[X_V].n_value;
    264  1.1  christos 
    265  1.1  christos     getkval(v_offset, (caddr_t)&v_info, sizeof v_info, "v");
    266  1.1  christos #else
    267  1.1  christos 	sysconfig(SYS_GETPARMS, &v_info, sizeof v_info);
    268  1.1  christos #endif
    269  1.1  christos     ncpus = v_info.v_ncpus;	/* number of cpus */
    270  1.1  christos 
    271  1.1  christos /* procentry64 is 4912 bytes, and PROCMASK(PIDMAX) is 262144.  That'd
    272  1.1  christos    require 1.2gb for the p_info array, which is way overkill.  Raise
    273  1.1  christos    MAXPROCS if you have more than 10240 active processes in the system.
    274  1.1  christos */
    275  1.1  christos 
    276  1.1  christos #if 0
    277  1.1  christos     nprocs = PROCMASK(PIDMAX);
    278  1.1  christos #else
    279  1.1  christos     nprocs = MAXPROCS;
    280  1.1  christos #endif
    281  1.1  christos 
    282  1.1  christos     cpu_proc = (struct timeval64 *)xmalloc(PROCMASK(PIDMAX) * sizeof (struct timeval64));
    283  1.1  christos     old_cpu_proc = (struct timeval64 *)xmalloc(PROCMASK(PIDMAX) * sizeof (struct timeval64));
    284  1.1  christos     p_info = (struct procentry64 *)xmalloc(nprocs * sizeof (struct procentry64));
    285  1.1  christos     pref = (struct procentry64 **)xmalloc(nprocs * sizeof (struct procentry64 *));
    286  1.1  christos 
    287  1.1  christos     statics->procstate_names = procstatenames;
    288  1.1  christos     statics->cpustate_names = cpustatenames;
    289  1.1  christos     statics->memory_names = memorynames;
    290  1.1  christos     statics->swap_names = swapnames;
    291  1.1  christos     statics->order_names = ordernames;
    292  1.1  christos 
    293  1.1  christos     return(0);
    294  1.1  christos }
    295  1.1  christos 
    296  1.1  christos char *format_header(uname_field)
    297  1.1  christos     register char *uname_field;
    298  1.1  christos {
    299  1.1  christos     register char *ptr;
    300  1.1  christos 
    301  1.1  christos     ptr = header + UNAME_START;
    302  1.1  christos     while (*uname_field != '\0')
    303  1.1  christos     {
    304  1.1  christos 	*ptr++ = *uname_field++;
    305  1.1  christos     }
    306  1.1  christos 
    307  1.1  christos     return(header);
    308  1.1  christos }
    309  1.1  christos 
    310  1.1  christos 
    311  1.1  christos 
    312  1.1  christos 
    313  1.1  christos void get_system_info(si)
    314  1.1  christos     struct system_info *si;
    315  1.1  christos {
    316  1.1  christos #ifdef OLD
    317  1.1  christos     long long load_avg[3];
    318  1.1  christos     struct sysinfo64 s_info;
    319  1.1  christos     struct vmker m_info;
    320  1.1  christos #else
    321  1.1  christos     perfstat_memory_total_t m_info1;
    322  1.1  christos     perfstat_cpu_total_t s_info1;
    323  1.1  christos #endif
    324  1.1  christos     int i;
    325  1.1  christos     int total = 0;
    326  1.1  christos 
    327  1.1  christos #ifdef OLD
    328  1.1  christos     /* get the load avarage array */
    329  1.1  christos     getkval(avenrun_offset, (caddr_t)load_avg, sizeof load_avg, "avenrun");
    330  1.1  christos 
    331  1.1  christos     /* get the sysinfo structure */
    332  1.1  christos     getkval(sysinfo_offset, (caddr_t)&s_info, sizeof s_info, "sysinfo64");
    333  1.1  christos 
    334  1.1  christos     /* get vmker structure */
    335  1.1  christos     getkval(vmker_offset, (caddr_t)&m_info, sizeof m_info, "vmker");
    336  1.1  christos #else
    337  1.1  christos     /* cpu stats */
    338  1.1  christos     perfstat_cpu_total(NULL, &s_info1, sizeof s_info1, 1);
    339  1.1  christos 
    340  1.1  christos     /* memory stats */
    341  1.1  christos     perfstat_memory_total(NULL, &m_info1, sizeof m_info1, 1);
    342  1.1  christos #endif
    343  1.1  christos 
    344  1.1  christos 
    345  1.1  christos #ifdef OLD
    346  1.1  christos     /* convert load avarages to doubles */
    347  1.1  christos     for (i = 0; i < 3; i++)
    348  1.1  christos 	si->load_avg[i] = (double)load_avg[i]/65536.0;
    349  1.1  christos 
    350  1.1  christos     /* calculate cpu state in percentages */
    351  1.1  christos     for (i = 0; i < CPU_NTIMES; i++) {
    352  1.1  christos 	cp_old[i] = cp_time[i];
    353  1.1  christos 	cp_time[i] = s_info.cpu[i];
    354  1.1  christos 	cp_diff[i] = cp_time[i] - cp_old[i];
    355  1.1  christos 	total += cp_diff[i];
    356  1.1  christos     }
    357  1.1  christos 
    358  1.1  christos #else
    359  1.1  christos     /* convert load avarages to doubles */
    360  1.1  christos     for (i = 0; i < 3; i++)
    361  1.1  christos         si->load_avg[i] = (double)s_info1.loadavg[i]/(1<<SBITS);
    362  1.1  christos 
    363  1.1  christos     /* calculate cpu state in percentages */
    364  1.1  christos     for (i = 0; i < CPU_NTIMES; i++) {
    365  1.1  christos 	cp_old[i] = cp_time[i];
    366  1.1  christos 	cp_time[i] = (	i==CPU_IDLE?s_info1.idle:
    367  1.1  christos 			i==CPU_USER?s_info1.user:
    368  1.1  christos 			i==CPU_KERNEL?s_info1.sys:
    369  1.1  christos 			i==CPU_WAIT?s_info1.wait:0);
    370  1.1  christos 	cp_diff[i] = cp_time[i] - cp_old[i];
    371  1.1  christos 	total += cp_diff[i];
    372  1.1  christos     }
    373  1.1  christos #endif
    374  1.1  christos     for (i = 0; i < CPU_NTIMES; i++) {
    375  1.1  christos         cpu_states[i] = 1000 * cp_diff[i] / total;
    376  1.1  christos     }
    377  1.1  christos 
    378  1.1  christos     /* calculate memory statistics, scale 4K pages */
    379  1.1  christos #ifdef OLD
    380  1.1  christos #define PAGE_TO_MB(a) ((a)*4/1024)
    381  1.1  christos     memory_stats[M_TOTAL]    = PAGE_TO_MB(m_info.totalmem+m_info.totalvmem);
    382  1.1  christos     memory_stats[M_REAL]     = PAGE_TO_MB(m_info.totalmem);
    383  1.1  christos     memory_stats[M_REALFREE] = PAGE_TO_MB(m_info.freemem);
    384  1.1  christos     memory_stats[M_BUFFERS]  = PAGE_TO_MB(m_info.numperm);
    385  1.1  christos     swap_stats[M_VIRTUAL]  = PAGE_TO_MB(m_info.totalvmem);
    386  1.1  christos     swap_stats[M_VIRTFREE] = PAGE_TO_MB(m_info.freevmem);
    387  1.1  christos #else
    388  1.1  christos #define PAGE_TO_KB(a) ((a)*4)
    389  1.1  christos     memory_stats[M_REAL] = PAGE_TO_KB(m_info1.real_total);
    390  1.1  christos     memory_stats[M_BUFFERS] = PAGE_TO_KB(m_info1.numperm);
    391  1.1  christos #ifdef _AIXVERSION_520
    392  1.1  christos     memory_stats[M_SYSTEM] = PAGE_TO_KB(m_info1.real_system);
    393  1.1  christos #endif
    394  1.1  christos     memory_stats[M_REALFREE] = PAGE_TO_KB(m_info1.real_free);
    395  1.1  christos     swap_stats[M_VIRTUAL] = PAGE_TO_KB(m_info1.pgsp_total);
    396  1.1  christos     swap_stats[M_VIRTFREE] = PAGE_TO_KB(m_info1.pgsp_free);
    397  1.1  christos #endif
    398  1.1  christos 
    399  1.1  christos     /* runnable processes */
    400  1.1  christos #ifdef OLD
    401  1.1  christos     process_states[0] = s_info.runque - old_runque;
    402  1.1  christos     old_runque = s_info.runque;
    403  1.1  christos #else
    404  1.1  christos     process_states[0] = s_info1.runque - old_runque;
    405  1.1  christos     old_runque = s_info1.runque;
    406  1.1  christos #endif
    407  1.1  christos 
    408  1.1  christos     si->cpustates = cpu_states;
    409  1.1  christos     si->memory = memory_stats;
    410  1.1  christos     si->swap = swap_stats;
    411  1.1  christos }
    412  1.1  christos 
    413  1.1  christos static struct handle handle;
    414  1.1  christos 
    415  1.1  christos caddr_t get_process_info(si, sel, compare_index)
    416  1.1  christos     struct system_info *si;
    417  1.1  christos     struct process_select *sel;
    418  1.1  christos     int compare_index;
    419  1.1  christos {
    420  1.1  christos     int i, nproc;
    421  1.1  christos     int active_procs = 0, total_procs = 0;
    422  1.1  christos     struct procentry64 *pp, **p_pref = pref;
    423  1.1  christos     struct timeval64 *cpu_proc_temp;
    424  1.1  christos     double timediff;
    425  1.1  christos     pid_t procsindex = 0;
    426  1.1  christos 
    427  1.1  christos     si->procstates = process_states;
    428  1.1  christos 
    429  1.1  christos     curtime = time(0);
    430  1.1  christos     lasttimeval = curtimeval;
    431  1.1  christos     gettimeofday(&curtimeval, NULL);
    432  1.1  christos 
    433  1.1  christos     /* get the procentry64 structures of all running processes */
    434  1.1  christos     nproc = getprocs64(p_info, sizeof (struct procentry64), NULL, 0,
    435  1.1  christos                        &procsindex, nprocs);
    436  1.1  christos     if (nproc < 0) {
    437  1.1  christos 	perror("getprocs64");
    438  1.1  christos 	quit(1);
    439  1.1  christos     }
    440  1.1  christos 
    441  1.1  christos     /* the swapper has no cmd-line attached */
    442  1.1  christos     strcpy(p_info[0].pi_comm, "swapper");
    443  1.1  christos 
    444  1.1  christos     if (lasttimeval.tv_sec)
    445  1.1  christos     {
    446  1.1  christos         timediff = (curtimeval.tv_sec - lasttimeval.tv_sec) +
    447  1.1  christos                    1.0*(curtimeval.tv_usec - lasttimeval.tv_usec) / uS_PER_SECOND;
    448  1.1  christos     }
    449  1.1  christos 
    450  1.1  christos     /* The pi_cpu value is wildly inaccurate.  The maximum value is 120, but
    451  1.1  christos        when the scheduling timer fires, the field is zeroed for all
    452  1.1  christos        processes and ramps up over a short period of time.  Instead of using
    453  1.1  christos        this weird number, manually calculate an accurate value from the
    454  1.1  christos        rusage data.  Store this run's rusage in cpu_proc[pid], and subtract
    455  1.1  christos        from old_cpu_proc.
    456  1.1  christos     */
    457  1.1  christos     for (pp = p_info, i = 0; i < nproc; pp++, i++) {
    458  1.1  christos         pid_t pid = PROCMASK(pp->pi_pid);
    459  1.1  christos 
    460  1.1  christos         /* total system and user time into cpu_proc */
    461  1.1  christos         cpu_proc[pid] = pp->pi_ru.ru_utime;
    462  1.1  christos         cpu_proc[pid].tv_sec += pp->pi_ru.ru_stime.tv_sec;
    463  1.1  christos         cpu_proc[pid].tv_usec += pp->pi_ru.ru_stime.tv_usec;
    464  1.1  christos         if (cpu_proc[pid].tv_usec > NS_PER_SEC) {
    465  1.1  christos             cpu_proc[pid].tv_sec++;
    466  1.1  christos             cpu_proc[pid].tv_usec -= NS_PER_SEC;
    467  1.1  christos         }
    468  1.1  christos 
    469  1.1  christos         /* If this process was around during the previous update, calculate
    470  1.1  christos            a true %CPU.  If not, convert the kernel's cpu value from its
    471  1.1  christos            120-max value to a 10000-max one.
    472  1.1  christos         */
    473  1.1  christos         if (old_cpu_proc[pid].tv_sec == 0 && old_cpu_proc[pid].tv_usec == 0)
    474  1.1  christos             pp->pi_cpu = pp->pi_cpu * 10000 / 120;
    475  1.1  christos         else
    476  1.1  christos             pp->pi_cpu = ((cpu_proc[pid].tv_sec - old_cpu_proc[pid].tv_sec) +
    477  1.1  christos                          1.0*(cpu_proc[pid].tv_usec - old_cpu_proc[pid].tv_usec) / NS_PER_SEC) / timediff * 10000;
    478  1.1  christos     }
    479  1.1  christos 
    480  1.1  christos     /* remember our current values as old_cpu_proc, and zero out cpu_proc
    481  1.1  christos        for the next update cycle */
    482  1.1  christos     memset(old_cpu_proc, 0, sizeof(struct timeval64) * nprocs);
    483  1.1  christos     cpu_proc_temp = cpu_proc;
    484  1.1  christos     cpu_proc = old_cpu_proc;
    485  1.1  christos     old_cpu_proc = cpu_proc_temp;
    486  1.1  christos 
    487  1.1  christos     memset(process_states, 0, sizeof process_states);
    488  1.1  christos 
    489  1.1  christos     /* build a list of pointers to processes to show. */
    490  1.1  christos     for (pp = p_info, i = 0; i < nproc; pp++, i++) {
    491  1.1  christos 
    492  1.1  christos 	/* AIX marks all runnable processes as ACTIVE. We want to know
    493  1.1  christos 	   which processes are sleeping, so check used cpu and adjust status
    494  1.1  christos 	   field accordingly
    495  1.1  christos 	 */
    496  1.1  christos 	if (pp->pi_state == SACTIVE && pp->pi_cpu == 0)
    497  1.1  christos 	    pp->pi_state = SIDL;
    498  1.1  christos 
    499  1.1  christos         if (pp->pi_state && (sel->system || ((pp->pi_flags & SKPROC) == 0))) {
    500  1.1  christos 	    total_procs++;
    501  1.1  christos 	    process_states[pp->pi_state]++;
    502  1.1  christos 	    if ( (pp->pi_state != SZOMB) &&
    503  1.1  christos 		(sel->idle || pp->pi_cpu != 0 || (pp->pi_state == SACTIVE))
    504  1.1  christos 		&& (sel->uid == -1 || pp->pi_uid == (uid_t)sel->uid)) {
    505  1.1  christos                 *p_pref++ = pp;
    506  1.1  christos 		active_procs++;
    507  1.1  christos 	    }
    508  1.1  christos 	}
    509  1.1  christos     }
    510  1.1  christos 
    511  1.1  christos     /* the pref array now holds pointers to the procentry64 structures in
    512  1.1  christos      * the p_info array that were selected for display
    513  1.1  christos      */
    514  1.1  christos 
    515  1.1  christos     /* sort if requested */
    516  1.1  christos     if ( proc_compares[compare_index] != NULL)
    517  1.1  christos 	qsort((char *)pref, active_procs, sizeof (struct procentry64 *),
    518  1.1  christos 	      proc_compares[compare_index]);
    519  1.1  christos 
    520  1.1  christos     si->last_pid = -1;		/* no way to figure out last used pid */
    521  1.1  christos     si->p_total = total_procs;
    522  1.1  christos     si->p_active = pref_len = active_procs;
    523  1.1  christos 
    524  1.1  christos     handle.next_proc = pref;
    525  1.1  christos     handle.remaining = active_procs;
    526  1.1  christos 
    527  1.1  christos     return((caddr_t)&handle);
    528  1.1  christos }
    529  1.1  christos 
    530  1.1  christos char fmt[128];		/* static area where result is built */
    531  1.1  christos 
    532  1.1  christos /* define what weighted cpu is. use definition of %CPU from 'man ps(1)' */
    533  1.1  christos #define weighted_cpu(pp) (PROCTIME(pp) == 0 ? 0.0 : \
    534  1.1  christos                         (((PROCTIME(pp)*100.0)/(curtime-pi->pi_start))))
    535  1.1  christos 
    536  1.1  christos char *format_next_process(handle, get_userid)
    537  1.1  christos     caddr_t handle;
    538  1.1  christos     char *(*get_userid)();
    539  1.1  christos {
    540  1.1  christos     register struct handle *hp;
    541  1.1  christos     register struct procentry64 *pi;
    542  1.1  christos     long cpu_time;
    543  1.1  christos     int proc_size, proc_ress;
    544  1.1  christos     char size_unit = 'K';
    545  1.1  christos     char ress_unit = 'K';
    546  1.1  christos 
    547  1.1  christos     hp = (struct handle *)handle;
    548  1.1  christos     if (hp->remaining == 0) {	/* safe guard */
    549  1.1  christos 	fmt[0] = '\0';
    550  1.1  christos 	return fmt;
    551  1.1  christos     }
    552  1.1  christos     pi = *(hp->next_proc++);
    553  1.1  christos     hp->remaining--;
    554  1.1  christos 
    555  1.1  christos     cpu_time = PROCTIME(pi);
    556  1.1  christos 
    557  1.1  christos     /* we disply sizes up to 10M in KiloBytes, beyond 10M in MegaBytes */
    558  1.1  christos     if ((proc_size = (pi->pi_tsize/1024+pi->pi_dvm)*4) > 10240) {
    559  1.1  christos 	proc_size /= 1024;
    560  1.1  christos 	size_unit = 'M';
    561  1.1  christos     }
    562  1.1  christos     if ((proc_ress = (pi->pi_trss + pi->pi_drss)*4) > 10240) {
    563  1.1  christos 	proc_ress /= 1024;
    564  1.1  christos 	ress_unit = 'M';
    565  1.1  christos     }
    566  1.1  christos 
    567  1.1  christos     sprintf(fmt, Proc_format ,
    568  1.1  christos             pi->pi_pid,					  /* PID */
    569  1.1  christos             (*get_userid)(pi->pi_uid),			  /* login name */
    570  1.1  christos 	        pi->pi_nice,				  /* fixed or vari */
    571  1.1  christos             getpriority(PRIO_PROCESS, pi->pi_pid),
    572  1.1  christos             proc_size,					  /* size */
    573  1.1  christos             size_unit,					  /* K or M */
    574  1.1  christos             proc_ress,					  /* resident */
    575  1.1  christos             ress_unit,					  /* K or M */
    576  1.1  christos             state_abbrev[pi->pi_state],			  /* process state */
    577  1.1  christos             format_time(cpu_time),			  /* time used */
    578  1.1  christos             weighted_cpu(pi),	                          /* WCPU */
    579  1.1  christos             pi->pi_cpu / 100.0,                     /* CPU */
    580  1.1  christos             printable(pi->pi_comm),                       /* COMM */
    581  1.1  christos             (pi->pi_flags & SKPROC) == 0 ? "" : " (sys)"  /* kernel process? */
    582  1.1  christos 	    );
    583  1.1  christos     return(fmt);
    584  1.1  christos }
    585  1.1  christos 
    586  1.1  christos #ifdef OLD
    587  1.1  christos /*
    588  1.1  christos  *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
    589  1.1  christos  *	"offset" is the byte offset into the kernel for the desired value,
    590  1.1  christos  *  	"ptr" points to a buffer into which the value is retrieved,
    591  1.1  christos  *  	"size" is the size of the buffer (and the object to retrieve),
    592  1.1  christos  *  	"refstr" is a reference string used when printing error meessages,
    593  1.1  christos  *	    if "refstr" starts with a '!', then a failure on read will not
    594  1.1  christos  *  	    be fatal (this may seem like a silly way to do things, but I
    595  1.1  christos  *  	    really didn't want the overhead of another argument).
    596  1.1  christos  *
    597  1.1  christos  */
    598  1.1  christos int getkval(offset, ptr, size, refstr)
    599  1.1  christos     unsigned long offset;
    600  1.1  christos     caddr_t ptr;
    601  1.1  christos     int size;
    602  1.1  christos     char *refstr;
    603  1.1  christos {
    604  1.1  christos     int upper_2gb = 0;
    605  1.1  christos 
    606  1.1  christos     /* reads above 2Gb are done by seeking to offset%2Gb, and supplying
    607  1.1  christos      * 1 (opposed to 0) as fourth parameter to readx (see 'man kmem')
    608  1.1  christos      */
    609  1.1  christos     if (offset > 1<<31) {
    610  1.1  christos 	upper_2gb = 1;
    611  1.1  christos 	offset &= 0x7fffffff;
    612  1.1  christos     }
    613  1.1  christos 
    614  1.1  christos     if (lseek(kmem, offset, SEEK_SET) != offset) {
    615  1.1  christos 	fprintf(stderr, "top: lseek failed\n");
    616  1.1  christos 	quit(2);
    617  1.1  christos     }
    618  1.1  christos 
    619  1.1  christos     if (readx(kmem, ptr, size, upper_2gb) != size) {
    620  1.1  christos 	if (*refstr == '!')
    621  1.1  christos 	    return 0;
    622  1.1  christos 	else {
    623  1.1  christos 	    fprintf(stderr, "top: kvm_read for %s: %s\n", refstr,
    624  1.1  christos 		    sys_errlist[errno]);
    625  1.1  christos 	    quit(2);
    626  1.1  christos 	}
    627  1.1  christos     }
    628  1.1  christos 
    629  1.1  christos     return 1 ;
    630  1.1  christos }
    631  1.1  christos #endif
    632  1.1  christos 
    633  1.1  christos /* comparison routine for qsort */
    634  1.1  christos /*
    635  1.1  christos  * The following code is taken from the solaris module and adjusted
    636  1.1  christos  * for AIX -- JV .
    637  1.1  christos  */
    638  1.1  christos 
    639  1.1  christos #define ORDERKEY_PCTCPU \
    640  1.1  christos            if ((result = pi2->pi_cpu - pi1->pi_cpu) == 0)
    641  1.1  christos 
    642  1.1  christos #define ORDERKEY_CPTICKS \
    643  1.1  christos            if ((result = PROCTIME(pi2) - PROCTIME(pi1)) == 0)
    644  1.1  christos 
    645  1.1  christos #define ORDERKEY_STATE \
    646  1.1  christos            if ((result = sorted_state[pi2->pi_state]  \
    647  1.1  christos                          - sorted_state[pi1->pi_state])  == 0)
    648  1.1  christos 
    649  1.1  christos /* Nice values directly reflect the process' priority, and are always >0 ;-) */
    650  1.1  christos #define ORDERKEY_PRIO \
    651  1.1  christos 	   if ((result = pi1->pi_nice - pi2->pi_nice) == 0)
    652  1.1  christos #define ORDERKEY_RSSIZE \
    653  1.1  christos            if ((result = PROCRESS(pi2) - PROCRESS(pi1)) == 0)
    654  1.1  christos #define ORDERKEY_MEM \
    655  1.1  christos            if ((result = PROCSIZE(pi2) - PROCSIZE(pi1)) == 0)
    656  1.1  christos 
    657  1.1  christos static unsigned char sorted_state[] =
    658  1.1  christos {
    659  1.1  christos     0,	/* not used */
    660  1.1  christos     0,
    661  1.1  christos     0,
    662  1.1  christos     0,
    663  1.1  christos     3,	/* sleep */
    664  1.1  christos     1,	/* zombie */
    665  1.1  christos     4,	/* stop */
    666  1.1  christos     6,	/* run */
    667  1.1  christos     2,	/* swap */
    668  1.1  christos };
    669  1.1  christos 
    670  1.1  christos /* compare_cpu - the comparison function for sorting by cpu percentage */
    671  1.1  christos 
    672  1.1  christos int
    673  1.1  christos compare_cpu(ppi1, ppi2)
    674  1.1  christos     struct procentry64 **ppi1;
    675  1.1  christos     struct procentry64 **ppi2;
    676  1.1  christos {
    677  1.1  christos     register struct procentry64 *pi1 = *ppi1, *pi2 = *ppi2;
    678  1.1  christos     register int result;
    679  1.1  christos 
    680  1.1  christos     ORDERKEY_PCTCPU
    681  1.1  christos     ORDERKEY_CPTICKS
    682  1.1  christos     ORDERKEY_STATE
    683  1.1  christos     ORDERKEY_PRIO
    684  1.1  christos     ORDERKEY_RSSIZE
    685  1.1  christos     ORDERKEY_MEM
    686  1.1  christos     ;
    687  1.1  christos 
    688  1.1  christos     return result;
    689  1.1  christos }
    690  1.1  christos 
    691  1.1  christos 
    692  1.1  christos /* compare_size - the comparison function for sorting by total memory usage */
    693  1.1  christos 
    694  1.1  christos int
    695  1.1  christos compare_size(ppi1, ppi2)
    696  1.1  christos     struct procentry64 **ppi1;
    697  1.1  christos     struct procentry64 **ppi2;
    698  1.1  christos {
    699  1.1  christos     register struct procentry64 *pi1 = *ppi1, *pi2 = *ppi2;
    700  1.1  christos     register int result;
    701  1.1  christos 
    702  1.1  christos     ORDERKEY_MEM
    703  1.1  christos     ORDERKEY_RSSIZE
    704  1.1  christos     ORDERKEY_PCTCPU
    705  1.1  christos     ORDERKEY_CPTICKS
    706  1.1  christos     ORDERKEY_STATE
    707  1.1  christos     ORDERKEY_PRIO
    708  1.1  christos     ;
    709  1.1  christos 
    710  1.1  christos     return result;
    711  1.1  christos }
    712  1.1  christos 
    713  1.1  christos 
    714  1.1  christos /* compare_res - the comparison function for sorting by resident set size */
    715  1.1  christos 
    716  1.1  christos int
    717  1.1  christos compare_res(ppi1, ppi2)
    718  1.1  christos     struct procentry64 **ppi1;
    719  1.1  christos     struct procentry64 **ppi2;
    720  1.1  christos {
    721  1.1  christos     register struct procentry64 *pi1 = *ppi1, *pi2 = *ppi2;
    722  1.1  christos     register int result;
    723  1.1  christos 
    724  1.1  christos     ORDERKEY_RSSIZE
    725  1.1  christos     ORDERKEY_MEM
    726  1.1  christos     ORDERKEY_PCTCPU
    727  1.1  christos     ORDERKEY_CPTICKS
    728  1.1  christos     ORDERKEY_STATE
    729  1.1  christos     ORDERKEY_PRIO
    730  1.1  christos     ;
    731  1.1  christos 
    732  1.1  christos     return result;
    733  1.1  christos }
    734  1.1  christos 
    735  1.1  christos 
    736  1.1  christos /* compare_time - the comparison function for sorting by total cpu time */
    737  1.1  christos 
    738  1.1  christos int
    739  1.1  christos compare_time(ppi1, ppi2)
    740  1.1  christos     struct procentry64 **ppi1;
    741  1.1  christos     struct procentry64 **ppi2;
    742  1.1  christos {
    743  1.1  christos     register struct procentry64 *pi1 = *ppi1, *pi2 = *ppi2;
    744  1.1  christos     register int result;
    745  1.1  christos 
    746  1.1  christos     ORDERKEY_CPTICKS
    747  1.1  christos     ORDERKEY_PCTCPU
    748  1.1  christos     ORDERKEY_STATE
    749  1.1  christos     ORDERKEY_PRIO
    750  1.1  christos     ORDERKEY_MEM
    751  1.1  christos     ORDERKEY_RSSIZE
    752  1.1  christos     ;
    753  1.1  christos 
    754  1.1  christos     return result;
    755  1.1  christos }
    756  1.1  christos 
    757  1.1  christos 
    758  1.1  christos /* compare_prio - the comparison function for sorting by cpu percentage */
    759  1.1  christos 
    760  1.1  christos int
    761  1.1  christos compare_prio(ppi1, ppi2)
    762  1.1  christos     struct procentry64 **ppi1;
    763  1.1  christos     struct procentry64 **ppi2;
    764  1.1  christos {
    765  1.1  christos     register struct procentry64 *pi1 = *ppi1, *pi2 = *ppi2;
    766  1.1  christos     register int result;
    767  1.1  christos 
    768  1.1  christos     ORDERKEY_PRIO
    769  1.1  christos     ORDERKEY_PCTCPU
    770  1.1  christos     ORDERKEY_CPTICKS
    771  1.1  christos     ORDERKEY_STATE
    772  1.1  christos     ORDERKEY_RSSIZE
    773  1.1  christos     ORDERKEY_MEM
    774  1.1  christos     ;
    775  1.1  christos 
    776  1.1  christos     return result;
    777  1.1  christos }
    778  1.1  christos 
    779  1.1  christos 
    780  1.1  christos int proc_owner(pid)
    781  1.1  christos int pid;
    782  1.1  christos {
    783  1.1  christos    register struct procentry64 **prefp = pref;
    784  1.1  christos    register int cnt = pref_len;
    785  1.1  christos 
    786  1.1  christos    while (--cnt >= 0) {
    787  1.1  christos        if ((*prefp)->pi_pid == pid)
    788  1.1  christos 	   return (*prefp)->pi_uid;
    789  1.1  christos        prefp++;
    790  1.1  christos    }
    791  1.1  christos 
    792  1.1  christos    return(-1);
    793  1.1  christos }
    794