xref: /netbsd-src/external/bsd/top/dist/machine/m_irix5.c (revision 10dd2532a5fc0a73e461275cb9fca28fc3013d32)
1*10dd2532Schristos /*
2*10dd2532Schristos  * Copyright (c) 1984 through 2008, William LeFebvre
3*10dd2532Schristos  * All rights reserved.
4*10dd2532Schristos  *
5*10dd2532Schristos  * Redistribution and use in source and binary forms, with or without
6*10dd2532Schristos  * modification, are permitted provided that the following conditions are met:
7*10dd2532Schristos  *
8*10dd2532Schristos  *     * Redistributions of source code must retain the above copyright
9*10dd2532Schristos  * notice, this list of conditions and the following disclaimer.
10*10dd2532Schristos  *
11*10dd2532Schristos  *     * Redistributions in binary form must reproduce the above
12*10dd2532Schristos  * copyright notice, this list of conditions and the following disclaimer
13*10dd2532Schristos  * in the documentation and/or other materials provided with the
14*10dd2532Schristos  * distribution.
15*10dd2532Schristos  *
16*10dd2532Schristos  *     * Neither the name of William LeFebvre nor the names of other
17*10dd2532Schristos  * contributors may be used to endorse or promote products derived from
18*10dd2532Schristos  * this software without specific prior written permission.
19*10dd2532Schristos  *
20*10dd2532Schristos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*10dd2532Schristos  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*10dd2532Schristos  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23*10dd2532Schristos  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24*10dd2532Schristos  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25*10dd2532Schristos  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26*10dd2532Schristos  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27*10dd2532Schristos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28*10dd2532Schristos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29*10dd2532Schristos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30*10dd2532Schristos  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*10dd2532Schristos  */
32*10dd2532Schristos 
33*10dd2532Schristos /*
34*10dd2532Schristos  * top - a top users display for Unix
35*10dd2532Schristos  *
36*10dd2532Schristos  * SYNOPSIS:  any uniprocessor, 32 bit SGI machine running IRIX 5.3
37*10dd2532Schristos  *
38*10dd2532Schristos  * DESCRIPTION:
39*10dd2532Schristos  * This is the machine-dependent module for IRIX 5.3.
40*10dd2532Schristos  * It has been tested on Indys running 5.3 and Indigos running 5.3XFS
41*10dd2532Schristos  *
42*10dd2532Schristos  * LIBS: -lmld
43*10dd2532Schristos  * CFLAGS: -DHAVE_GETOPT
44*10dd2532Schristos  *
45*10dd2532Schristos  * AUTHOR: Sandeep Cariapa <cariapa@sgi.com>
46*10dd2532Schristos  * This is not a supported product of Silicon Graphics, Inc.
47*10dd2532Schristos  * Please do not call SGI for support.
48*10dd2532Schristos  *
49*10dd2532Schristos  */
50*10dd2532Schristos 
51*10dd2532Schristos #define _KMEMUSER
52*10dd2532Schristos 
53*10dd2532Schristos #include "config.h"
54*10dd2532Schristos 
55*10dd2532Schristos #include <sys/types.h>
56*10dd2532Schristos #include <sys/time.h>
57*10dd2532Schristos #include <sys/stat.h>
58*10dd2532Schristos #include <sys/swap.h>
59*10dd2532Schristos #include <sys/proc.h>
60*10dd2532Schristos #include <sys/procfs.h>
61*10dd2532Schristos #include <sys/sysinfo.h>
62*10dd2532Schristos #include <sys/sysmp.h>
63*10dd2532Schristos #include <paths.h>
64*10dd2532Schristos #include <dirent.h>
65*10dd2532Schristos #include <stdio.h>
66*10dd2532Schristos #include <nlist.h>
67*10dd2532Schristos #include <unistd.h>
68*10dd2532Schristos #include <errno.h>
69*10dd2532Schristos #include <fcntl.h>
70*10dd2532Schristos #include "top.h"
71*10dd2532Schristos #include "machine.h"
72*10dd2532Schristos 
73*10dd2532Schristos #ifdef IRIX64
74*10dd2532Schristos #define nlist nlist64
75*10dd2532Schristos #define lseek lseek64
76*10dd2532Schristos #define off_t off64_t
77*10dd2532Schristos #endif
78*10dd2532Schristos 
79*10dd2532Schristos #define UNIX	"/unix"
80*10dd2532Schristos #define KMEM	"/dev/kmem"
81*10dd2532Schristos #define CPUSTATES 6
82*10dd2532Schristos 
83*10dd2532Schristos #ifndef FSCALE
84*10dd2532Schristos #define FSHIFT  8		/* bits to right of fixed binary point */
85*10dd2532Schristos #define FSCALE  (1<<FSHIFT)
86*10dd2532Schristos #endif /* FSCALE */
87*10dd2532Schristos 
88*10dd2532Schristos #ifdef FIXED_LOADAVG
89*10dd2532Schristos   typedef long load_avg;
90*10dd2532Schristos # define loaddouble(la) ((double)(la) / FIXED_LOADAVG)
91*10dd2532Schristos # define intload(i) ((int)((i) * FIXED_LOADAVG))
92*10dd2532Schristos #else
93*10dd2532Schristos   typedef double load_avg;
94*10dd2532Schristos # define loaddouble(la) (la)
95*10dd2532Schristos # define intload(i) ((double)(i))
96*10dd2532Schristos #endif
97*10dd2532Schristos 
98*10dd2532Schristos #define percent_cpu(pp) (*(double *)pp->pr_fill)
99*10dd2532Schristos #define weighted_cpu(pp) (*(double *)&pp->pr_fill[2])
100*10dd2532Schristos 
101*10dd2532Schristos static int pagesize;
102*10dd2532Schristos #define pagetok(size) ((size)*pagesize)
103*10dd2532Schristos 
104*10dd2532Schristos static int numcpus;
105*10dd2532Schristos 
106*10dd2532Schristos /*
107*10dd2532Schristos  *  These definitions control the format of the per-process area
108*10dd2532Schristos  */
109*10dd2532Schristos 
110*10dd2532Schristos static char header[] =
111*10dd2532Schristos   "  PID X        PRI NICE  SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
112*10dd2532Schristos /* 0123456   -- field to fill in starts at header+6 */
113*10dd2532Schristos #define UNAME_START 6
114*10dd2532Schristos 
115*10dd2532Schristos #define Proc_format \
116*10dd2532Schristos 	"%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %.16s"
117*10dd2532Schristos 
118*10dd2532Schristos /* these are for detailing the process states */
119*10dd2532Schristos char *state_abbrev[] =
120*10dd2532Schristos {"", "sleep", "run\0\0\0", "zombie", "stop", "idle", "", "swap"};
121*10dd2532Schristos 
122*10dd2532Schristos int process_states[8];
123*10dd2532Schristos char *procstatenames[] = {
124*10dd2532Schristos     "", " sleeping, ", " running, ", " zombie, ", " stopped, ",
125*10dd2532Schristos     " idle, ", "", " swapped, ",
126*10dd2532Schristos     NULL
127*10dd2532Schristos };
128*10dd2532Schristos 
129*10dd2532Schristos /* these are for detailing the cpu states */
130*10dd2532Schristos int cpu_states[CPUSTATES];
131*10dd2532Schristos char *cpustatenames[] = {
132*10dd2532Schristos     "idle", "usr", "ker", "wait", "swp", "intr",
133*10dd2532Schristos     NULL
134*10dd2532Schristos };
135*10dd2532Schristos 
136*10dd2532Schristos /* these are for detailing the memory statistics */
137*10dd2532Schristos 
138*10dd2532Schristos long memory_stats[5];
139*10dd2532Schristos char *memorynames[] = {
140*10dd2532Schristos     "K max, ", "K avail, ", "K free, ", "K swap, ", "K free swap", NULL
141*10dd2532Schristos };
142*10dd2532Schristos 
143*10dd2532Schristos /* useful externals */
144*10dd2532Schristos extern int errno;
145*10dd2532Schristos extern char *myname;
146*10dd2532Schristos extern char *sys_errlist[];
147*10dd2532Schristos extern char *format_k();
148*10dd2532Schristos extern char *format_time();
149*10dd2532Schristos extern long percentages();
150*10dd2532Schristos 
151*10dd2532Schristos /* forward references */
152*10dd2532Schristos int proc_compare (void *pp1, void *pp2);
153*10dd2532Schristos 
154*10dd2532Schristos #define X_AVENRUN	0
155*10dd2532Schristos #define X_NPROC		1
156*10dd2532Schristos #define X_FREEMEM	2
157*10dd2532Schristos #define X_MAXMEM	3
158*10dd2532Schristos #define X_AVAILRMEM     4
159*10dd2532Schristos #define X_MPID		5
160*10dd2532Schristos 
161*10dd2532Schristos static struct nlist nlst[] = {
162*10dd2532Schristos { "avenrun" },		/* 0. Array containing the 3 load averages. */
163*10dd2532Schristos { "nproc" },		/* 1. Kernel parameter: Max number of processes. */
164*10dd2532Schristos { "freemem" },		/* 2. Amount of free memory in system. */
165*10dd2532Schristos { "maxmem" },		/* 3. Maximum amount of memory usable by system. */
166*10dd2532Schristos { "availrmem" },        /* 4. Available real memory. */
167*10dd2532Schristos #ifndef IRIX64
168*10dd2532Schristos { "mpid" },		/* 5. PID of last process. */
169*10dd2532Schristos #endif
170*10dd2532Schristos { 0 }
171*10dd2532Schristos };
172*10dd2532Schristos static unsigned long avenrun_offset;
173*10dd2532Schristos static unsigned long nproc_offset;
174*10dd2532Schristos static unsigned long freemem_offset;
175*10dd2532Schristos static unsigned long maxmem_offset;
176*10dd2532Schristos static unsigned long availrmem_offset;
177*10dd2532Schristos static unsigned long mpid_offset;
178*10dd2532Schristos double load[3];
179*10dd2532Schristos char fmt[MAX_COLS];
180*10dd2532Schristos static int kmem;
181*10dd2532Schristos static int nproc;
182*10dd2532Schristos static int bytes;
183*10dd2532Schristos static struct prpsinfo *pbase;
184*10dd2532Schristos static struct prpsinfo **pref;
185*10dd2532Schristos static DIR *procdir;
186*10dd2532Schristos 
187*10dd2532Schristos /* get_process_info passes back a handle.  This is what it looks like: */
188*10dd2532Schristos struct handle  {
189*10dd2532Schristos   struct prpsinfo **next_proc;/* points to next valid proc pointer */
190*10dd2532Schristos   int remaining;	      /* number of pointers remaining */
191*10dd2532Schristos };
192*10dd2532Schristos 
193*10dd2532Schristos static struct handle handle;
194*10dd2532Schristos void getptable();
195*10dd2532Schristos 
196*10dd2532Schristos /*
197*10dd2532Schristos  * Structure for keeping track of CPU times from last time around
198*10dd2532Schristos  * the program.  We keep these things in a hash table, which is
199*10dd2532Schristos  * recreated at every cycle.
200*10dd2532Schristos  */
201*10dd2532Schristos struct oldproc
202*10dd2532Schristos   {
203*10dd2532Schristos     pid_t oldpid;
204*10dd2532Schristos     double oldtime;
205*10dd2532Schristos     double oldpct;
206*10dd2532Schristos   };
207*10dd2532Schristos static int oldprocs;			/* size of table */
208*10dd2532Schristos static struct oldproc *oldbase;
209*10dd2532Schristos #define HASH(x) ((x << 1) % oldprocs)
210*10dd2532Schristos #define PRPSINFOSIZE (sizeof(struct prpsinfo))
211*10dd2532Schristos 
machine_init(statics)212*10dd2532Schristos int machine_init(statics)
213*10dd2532Schristos      struct statics *statics;
214*10dd2532Schristos {
215*10dd2532Schristos   struct oldproc *op, *endbase;
216*10dd2532Schristos 
217*10dd2532Schristos   if ((kmem = open(KMEM, O_RDONLY)) == -1) {
218*10dd2532Schristos     perror(KMEM);
219*10dd2532Schristos     return(-1);
220*10dd2532Schristos   }
221*10dd2532Schristos 
222*10dd2532Schristos   /* get the list of symbols we want to access in the kernel */
223*10dd2532Schristos   (void) nlist(UNIX, nlst);
224*10dd2532Schristos   if (nlst[0].n_type == 0) {
225*10dd2532Schristos     fprintf(stderr, "%s: nlist failed\n", myname);
226*10dd2532Schristos     return(-1);
227*10dd2532Schristos   }
228*10dd2532Schristos 
229*10dd2532Schristos   /* Check if we got all of 'em. */
230*10dd2532Schristos   if (check_nlist(nlst) > 0) {
231*10dd2532Schristos       return(-1);
232*10dd2532Schristos     }
233*10dd2532Schristos   avenrun_offset = nlst[X_AVENRUN].n_value;
234*10dd2532Schristos   nproc_offset = nlst[X_NPROC].n_value;
235*10dd2532Schristos   freemem_offset = nlst[X_FREEMEM].n_value;
236*10dd2532Schristos   maxmem_offset = nlst[X_MAXMEM].n_value;
237*10dd2532Schristos   availrmem_offset = nlst[X_AVAILRMEM].n_value;
238*10dd2532Schristos #ifndef IRIX64
239*10dd2532Schristos    mpid_offset = nlst[X_MPID].n_value;
240*10dd2532Schristos #endif
241*10dd2532Schristos 
242*10dd2532Schristos   /* Got to do this first so that we can map real estate for the
243*10dd2532Schristos      process array. */
244*10dd2532Schristos   (void) getkval(nproc_offset, (int *) (&nproc), sizeof(nproc), "nproc");
245*10dd2532Schristos 
246*10dd2532Schristos   /* allocate space for proc structure array and array of pointers */
247*10dd2532Schristos   bytes = nproc * sizeof (struct prpsinfo);
248*10dd2532Schristos   pbase = (struct prpsinfo *) malloc (bytes);
249*10dd2532Schristos   pref = (struct prpsinfo **) malloc (nproc * sizeof (struct prpsinfo *));
250*10dd2532Schristos   oldbase = (struct oldproc *) malloc (2 * nproc * sizeof (struct oldproc));
251*10dd2532Schristos 
252*10dd2532Schristos   /* Just in case ... */
253*10dd2532Schristos   if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL ||
254*10dd2532Schristos       oldbase == (struct oldproc *)NULL) {
255*10dd2532Schristos     (void) fprintf (stderr, "%s: can't allocate sufficient memory\n", myname);
256*10dd2532Schristos     return (-1);
257*10dd2532Schristos   }
258*10dd2532Schristos 
259*10dd2532Schristos   oldprocs = 2 * nproc;
260*10dd2532Schristos   endbase = oldbase + oldprocs;
261*10dd2532Schristos   for (op = oldbase; op < endbase; op++) {
262*10dd2532Schristos     op->oldpid = -1;
263*10dd2532Schristos   }
264*10dd2532Schristos 
265*10dd2532Schristos   if (!(procdir = opendir (_PATH_PROCFSPI))) {
266*10dd2532Schristos     (void) fprintf (stderr, "Unable to open %s\n", _PATH_PROCFSPI);
267*10dd2532Schristos     return (-1);
268*10dd2532Schristos   }
269*10dd2532Schristos 
270*10dd2532Schristos   if (chdir (_PATH_PROCFSPI)) {
271*10dd2532Schristos     /* handy for later on when we're reading it */
272*10dd2532Schristos     (void) fprintf (stderr, "Unable to chdir to %s\n", _PATH_PROCFSPI);
273*10dd2532Schristos     return (-1);
274*10dd2532Schristos   }
275*10dd2532Schristos 
276*10dd2532Schristos   statics->procstate_names = procstatenames;
277*10dd2532Schristos   statics->cpustate_names = cpustatenames;
278*10dd2532Schristos   statics->memory_names = memorynames;
279*10dd2532Schristos 
280*10dd2532Schristos   pagesize = getpagesize()/1024;
281*10dd2532Schristos 
282*10dd2532Schristos   /* all done! */
283*10dd2532Schristos   return(0);
284*10dd2532Schristos }
285*10dd2532Schristos 
format_header(uname_field)286*10dd2532Schristos char *format_header(uname_field)
287*10dd2532Schristos      register char *uname_field;
288*10dd2532Schristos 
289*10dd2532Schristos {
290*10dd2532Schristos   register char *ptr;
291*10dd2532Schristos 
292*10dd2532Schristos   ptr = header + UNAME_START;
293*10dd2532Schristos   while (*uname_field != '\0') {
294*10dd2532Schristos     *ptr++ = *uname_field++;
295*10dd2532Schristos   }
296*10dd2532Schristos 
297*10dd2532Schristos   return(header);
298*10dd2532Schristos }
299*10dd2532Schristos 
get_system_info(si)300*10dd2532Schristos void get_system_info(si)
301*10dd2532Schristos      struct system_info *si;
302*10dd2532Schristos 
303*10dd2532Schristos {
304*10dd2532Schristos   register int i;
305*10dd2532Schristos   int avenrun[3];
306*10dd2532Schristos   static int freemem;
307*10dd2532Schristos   static int maxmem;
308*10dd2532Schristos   static int availrmem;
309*10dd2532Schristos   struct sysinfo sysinfo;
310*10dd2532Schristos   static long cp_new[CPUSTATES];
311*10dd2532Schristos   static long cp_old[CPUSTATES];
312*10dd2532Schristos   static long cp_diff[CPUSTATES]; /* for cpu state percentages */
313*10dd2532Schristos   off_t  fswap;          /* current free swap in blocks */
314*10dd2532Schristos   off_t  tswap;          /* total swap in blocks */
315*10dd2532Schristos 
316*10dd2532Schristos   (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun), "avenrun");
317*10dd2532Schristos   for (i = 0; i < 3; i++) {
318*10dd2532Schristos     si->load_avg[i] = loaddouble (avenrun[i]);
319*10dd2532Schristos     si->load_avg[i] = si->load_avg[i]/1024.0;
320*10dd2532Schristos   }
321*10dd2532Schristos 
322*10dd2532Schristos   (void) getkval(freemem_offset, (int *) (&freemem), sizeof(freemem),
323*10dd2532Schristos "freemem");
324*10dd2532Schristos   (void) getkval(maxmem_offset, (int *) (&maxmem), sizeof(maxmem), "maxmem");
325*10dd2532Schristos   (void) getkval(availrmem_offset, (int *) (&availrmem), sizeof(availrmem),
326*10dd2532Schristos "availrmem");
327*10dd2532Schristos #ifdef IRIX64
328*10dd2532Schristos   si->last_pid = 0;
329*10dd2532Schristos #else
330*10dd2532Schristos   (void) getkval(mpid_offset, &(si->last_pid), sizeof (si->last_pid), "mpid");
331*10dd2532Schristos #endif
332*10dd2532Schristos   swapctl(SC_GETFREESWAP, &fswap);
333*10dd2532Schristos   swapctl(SC_GETSWAPTOT, &tswap);
334*10dd2532Schristos   memory_stats[0] = pagetok(maxmem);
335*10dd2532Schristos   memory_stats[1] = pagetok(availrmem);
336*10dd2532Schristos   memory_stats[2] = pagetok(freemem);
337*10dd2532Schristos   memory_stats[3] = tswap / 2;
338*10dd2532Schristos   memory_stats[4] = fswap / 2;
339*10dd2532Schristos 
340*10dd2532Schristos   /* use sysmp() to get current sysinfo usage. Can run into all kinds of
341*10dd2532Schristos      problems if you try to nlist this kernel variable. */
342*10dd2532Schristos   if (sysmp(MP_SAGET, MPSA_SINFO, &sysinfo, sizeof(struct sysinfo)) == -1) {
343*10dd2532Schristos     perror("sysmp");
344*10dd2532Schristos     return;
345*10dd2532Schristos   }
346*10dd2532Schristos   /* copy sysinfo.cpu to an array of longs, as expected by percentages() */
347*10dd2532Schristos   for (i = 0; i < CPUSTATES; i++) {
348*10dd2532Schristos     cp_new[i] = sysinfo.cpu[i];
349*10dd2532Schristos   }
350*10dd2532Schristos   (void) percentages (CPUSTATES, cpu_states, cp_new, cp_old, cp_diff);
351*10dd2532Schristos 
352*10dd2532Schristos   si->cpustates = cpu_states;
353*10dd2532Schristos   si->memory = memory_stats;
354*10dd2532Schristos 
355*10dd2532Schristos   numcpus = sysmp(MP_NPROCS);
356*10dd2532Schristos 
357*10dd2532Schristos   /* add a slash to the "run" state abbreviation */
358*10dd2532Schristos   if (numcpus > 1) {
359*10dd2532Schristos     state_abbrev[SRUN][3] = '/';
360*10dd2532Schristos   }
361*10dd2532Schristos 
362*10dd2532Schristos   return;
363*10dd2532Schristos }
364*10dd2532Schristos 
get_process_info(si,sel,x)365*10dd2532Schristos caddr_t get_process_info(si, sel, x)
366*10dd2532Schristos      struct system_info *si;
367*10dd2532Schristos      struct process_select *sel;
368*10dd2532Schristos      int x;
369*10dd2532Schristos {
370*10dd2532Schristos   register int i;
371*10dd2532Schristos   register int total_procs;
372*10dd2532Schristos   register int active_procs;
373*10dd2532Schristos   register struct prpsinfo **prefp;
374*10dd2532Schristos   register struct prpsinfo *pp;
375*10dd2532Schristos 
376*10dd2532Schristos   /* these are copied out of sel for speed */
377*10dd2532Schristos   int show_idle;
378*10dd2532Schristos   int show_system;
379*10dd2532Schristos   int show_uid;
380*10dd2532Schristos 
381*10dd2532Schristos   /* read all the proc structures */
382*10dd2532Schristos   getptable (pbase);
383*10dd2532Schristos 
384*10dd2532Schristos   /* get a pointer to the states summary array */
385*10dd2532Schristos   si->procstates = process_states;
386*10dd2532Schristos 
387*10dd2532Schristos   /* set up flags which define what we are going to select */
388*10dd2532Schristos   show_idle = sel->idle;
389*10dd2532Schristos   show_system = sel->system;
390*10dd2532Schristos   show_uid = sel->uid != -1;
391*10dd2532Schristos 
392*10dd2532Schristos   /* count up process states and get pointers to interesting procs */
393*10dd2532Schristos   total_procs = 0;
394*10dd2532Schristos   active_procs = 0;
395*10dd2532Schristos   (void) memset (process_states, 0, sizeof (process_states));
396*10dd2532Schristos   prefp = pref;
397*10dd2532Schristos 
398*10dd2532Schristos   for (pp = pbase, i = 0; i < nproc; pp++, i++)    {
399*10dd2532Schristos     /*
400*10dd2532Schristos      *  Place pointers to each valid proc structure in pref[].
401*10dd2532Schristos      *  Process slots that are actually in use have a non-zero
402*10dd2532Schristos      *  status field.  Processes with SSYS set are system
403*10dd2532Schristos      *  processes---these get ignored unless show_system is set.
404*10dd2532Schristos      */
405*10dd2532Schristos     if (pp->pr_state != 0 &&
406*10dd2532Schristos 	(show_system || ((pp->pr_flag & SSYS) == 0))) {
407*10dd2532Schristos       total_procs++;
408*10dd2532Schristos       process_states[pp->pr_state]++;
409*10dd2532Schristos       if ((!pp->pr_zomb) &&
410*10dd2532Schristos 	  (show_idle || (pp->pr_state == SRUN)) &&
411*10dd2532Schristos 	  (!show_uid || pp->pr_uid == (uid_t) sel->uid))  {
412*10dd2532Schristos 	*prefp++ = pp;
413*10dd2532Schristos 	active_procs++;
414*10dd2532Schristos       }
415*10dd2532Schristos     }
416*10dd2532Schristos   }
417*10dd2532Schristos 
418*10dd2532Schristos   /* if requested, sort the "interesting" processes */
419*10dd2532Schristos   if (compare != NULL)
420*10dd2532Schristos     qsort ((char *) pref, active_procs, sizeof (struct prpsinfo *), proc_compare);
421*10dd2532Schristos 
422*10dd2532Schristos   /* remember active and total counts */
423*10dd2532Schristos   si->p_total = total_procs;
424*10dd2532Schristos   si->p_active = active_procs;
425*10dd2532Schristos 
426*10dd2532Schristos   /* pass back a handle */
427*10dd2532Schristos   handle.next_proc = pref;
428*10dd2532Schristos   handle.remaining = active_procs;
429*10dd2532Schristos   return((caddr_t)&handle);
430*10dd2532Schristos }
431*10dd2532Schristos 
format_next_process(handle,get_userid)432*10dd2532Schristos char *format_next_process(handle, get_userid)
433*10dd2532Schristos      caddr_t handle;
434*10dd2532Schristos      char *(*get_userid)();
435*10dd2532Schristos 
436*10dd2532Schristos {
437*10dd2532Schristos   register struct prpsinfo *pp;
438*10dd2532Schristos   struct handle *hp;
439*10dd2532Schristos   register long cputime;
440*10dd2532Schristos   register double pctcpu;
441*10dd2532Schristos 
442*10dd2532Schristos   /* find and remember the next proc structure */
443*10dd2532Schristos   hp = (struct handle *) handle;
444*10dd2532Schristos   pp = *(hp->next_proc++);
445*10dd2532Schristos   hp->remaining--;
446*10dd2532Schristos 
447*10dd2532Schristos   /* get the cpu usage and calculate the cpu percentages */
448*10dd2532Schristos   cputime = pp->pr_time.tv_sec;
449*10dd2532Schristos   pctcpu = percent_cpu (pp);
450*10dd2532Schristos 
451*10dd2532Schristos   if (numcpus > 1) {
452*10dd2532Schristos 	if (pp->pr_sonproc < 0)
453*10dd2532Schristos 		state_abbrev[SRUN][4] = '*';
454*10dd2532Schristos 	else
455*10dd2532Schristos 		state_abbrev[SRUN][4] = pp->pr_sonproc + '0';
456*10dd2532Schristos   }
457*10dd2532Schristos 
458*10dd2532Schristos   /* format this entry */
459*10dd2532Schristos   sprintf (fmt,
460*10dd2532Schristos 	   Proc_format,
461*10dd2532Schristos 	   pp->pr_pid,
462*10dd2532Schristos 	   (*get_userid) (pp->pr_uid),
463*10dd2532Schristos 	   pp->pr_pri - PZERO,
464*10dd2532Schristos 	   pp->pr_nice - NZERO,
465*10dd2532Schristos 	   format_k(pagetok(pp->pr_size)),
466*10dd2532Schristos 	   format_k(pagetok(pp->pr_rssize)),
467*10dd2532Schristos 	   state_abbrev[pp->pr_state],
468*10dd2532Schristos 	   format_time(cputime),
469*10dd2532Schristos 	   weighted_cpu (pp),
470*10dd2532Schristos 	   pctcpu,
471*10dd2532Schristos 	   pp->pr_fname);
472*10dd2532Schristos 
473*10dd2532Schristos   /* return the result */
474*10dd2532Schristos     return(fmt);
475*10dd2532Schristos }
476*10dd2532Schristos 
477*10dd2532Schristos /*
478*10dd2532Schristos  *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
479*10dd2532Schristos  *	"offset" is the byte offset into the kernel for the desired value,
480*10dd2532Schristos  *  	"ptr" points to a buffer into which the value is retrieved,
481*10dd2532Schristos  *  	"size" is the size of the buffer (and the object to retrieve),
482*10dd2532Schristos  *  	"refstr" is a reference string used when printing error meessages,
483*10dd2532Schristos  *	    if "refstr" starts with a '!', then a failure on read will not
484*10dd2532Schristos  *  	    be fatal (this may seem like a silly way to do things, but I
485*10dd2532Schristos  *  	    really didn't want the overhead of another argument).
486*10dd2532Schristos  *
487*10dd2532Schristos  */
488*10dd2532Schristos 
getkval(offset,ptr,size,refstr)489*10dd2532Schristos int getkval(offset, ptr, size, refstr)
490*10dd2532Schristos      off_t offset;
491*10dd2532Schristos      int *ptr;
492*10dd2532Schristos      int size;
493*10dd2532Schristos      char *refstr;
494*10dd2532Schristos 
495*10dd2532Schristos {
496*10dd2532Schristos   if (lseek(kmem, offset, SEEK_SET) == -1) {
497*10dd2532Schristos     if (*refstr == '!')
498*10dd2532Schristos       refstr++;
499*10dd2532Schristos     (void) fprintf(stderr, "%s: lseek to %s: %s\n", KMEM,
500*10dd2532Schristos 		   refstr, strerror(errno));
501*10dd2532Schristos     quit(0);
502*10dd2532Schristos   }
503*10dd2532Schristos   if (read(kmem, (char *) ptr, size) == -1) {
504*10dd2532Schristos     if (*refstr == '!')
505*10dd2532Schristos       return(0);
506*10dd2532Schristos     else {
507*10dd2532Schristos       (void) fprintf(stderr, "%s: reading %s: %s\n", KMEM,
508*10dd2532Schristos 		     refstr, strerror(errno));
509*10dd2532Schristos       quit(0);
510*10dd2532Schristos     }
511*10dd2532Schristos   }
512*10dd2532Schristos   return(1);
513*10dd2532Schristos }
514*10dd2532Schristos 
515*10dd2532Schristos /*
516*10dd2532Schristos  *  proc_compare - comparison function for "qsort"
517*10dd2532Schristos  *	Compares the resource consumption of two processes using five
518*10dd2532Schristos  *  	distinct keys.  The keys (in descending order of importance) are:
519*10dd2532Schristos  *  	percent cpu, cpu ticks, state, resident set size, total virtual
520*10dd2532Schristos  *  	memory usage.  The process states are ordered as follows (from least
521*10dd2532Schristos  *  	to most important):  WAIT, zombie, sleep, stop, idle, run.  The
522*10dd2532Schristos  *  	array declaration below maps a process state index into a number
523*10dd2532Schristos  *  	that reflects this ordering.
524*10dd2532Schristos  */
525*10dd2532Schristos 
526*10dd2532Schristos 
527*10dd2532Schristos unsigned char sorted_state[] =
528*10dd2532Schristos {
529*10dd2532Schristos   0,				/* not used		*/
530*10dd2532Schristos   3,				/* sleep		*/
531*10dd2532Schristos   6,				/* run			*/
532*10dd2532Schristos   2,				/* zombie		*/
533*10dd2532Schristos   4,				/* stop			*/
534*10dd2532Schristos   5,				/* idle 		*/
535*10dd2532Schristos   0,				/* not used             */
536*10dd2532Schristos   1				/* being swapped (WAIT)	*/
537*10dd2532Schristos };
538*10dd2532Schristos 
proc_compare(pp1,pp2)539*10dd2532Schristos int proc_compare (pp1, pp2)
540*10dd2532Schristos      void *pp1;
541*10dd2532Schristos      void *pp2;
542*10dd2532Schristos {
543*10dd2532Schristos   register struct prpsinfo *p1;
544*10dd2532Schristos   register struct prpsinfo *p2;
545*10dd2532Schristos   register long result;
546*10dd2532Schristos 
547*10dd2532Schristos   /* remove one level of indirection */
548*10dd2532Schristos   p1 = *(struct prpsinfo **)pp1;
549*10dd2532Schristos   p2 = *(struct prpsinfo **)pp2;
550*10dd2532Schristos 
551*10dd2532Schristos   /* compare percent cpu (pctcpu) */
552*10dd2532Schristos   if ((result = (long) (p2->pr_cpu - p1->pr_cpu)) == 0) {
553*10dd2532Schristos     /* use cpticks to break the tie */
554*10dd2532Schristos     if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0) {
555*10dd2532Schristos       /* use process state to break the tie */
556*10dd2532Schristos       if ((result = (long) (sorted_state[p2->pr_state] -
557*10dd2532Schristos 			    sorted_state[p1->pr_state])) == 0) {
558*10dd2532Schristos 	/* use priority to break the tie */
559*10dd2532Schristos 	if ((result = p2->pr_oldpri - p1->pr_oldpri) == 0)  {
560*10dd2532Schristos 	  /* use resident set size (rssize) to break the tie */
561*10dd2532Schristos 	  if ((result = p2->pr_rssize - p1->pr_rssize) == 0)  {
562*10dd2532Schristos 	    /* use total memory to break the tie */
563*10dd2532Schristos 	    result = (p2->pr_size - p1->pr_size);
564*10dd2532Schristos 	  }
565*10dd2532Schristos 	}
566*10dd2532Schristos       }
567*10dd2532Schristos     }
568*10dd2532Schristos   }
569*10dd2532Schristos   return (result);
570*10dd2532Schristos }
571*10dd2532Schristos 
572*10dd2532Schristos /* return the owner of the specified process. */
proc_owner(pid)573*10dd2532Schristos int proc_owner (pid)
574*10dd2532Schristos      int pid;
575*10dd2532Schristos {
576*10dd2532Schristos   register struct prpsinfo *p;
577*10dd2532Schristos   int i;
578*10dd2532Schristos 
579*10dd2532Schristos   for (i = 0, p = pbase; i < nproc; i++, p++)
580*10dd2532Schristos     if (p->pr_pid == (oid_t)pid)
581*10dd2532Schristos       return ((int)p->pr_uid);
582*10dd2532Schristos 
583*10dd2532Schristos   return (-1);
584*10dd2532Schristos }
585*10dd2532Schristos 
586*10dd2532Schristos /*
587*10dd2532Schristos  * check_nlist(nlst) - checks the nlist to see if any symbols were not
588*10dd2532Schristos  *		found.  For every symbol that was not found, a one-line
589*10dd2532Schristos  *		message is printed to stderr.  The routine returns the
590*10dd2532Schristos  *		number of symbols NOT found.
591*10dd2532Schristos  */
592*10dd2532Schristos 
check_nlist(nlst)593*10dd2532Schristos int check_nlist(nlst)
594*10dd2532Schristos      register struct nlist *nlst;
595*10dd2532Schristos 
596*10dd2532Schristos {
597*10dd2532Schristos   register int i;
598*10dd2532Schristos 
599*10dd2532Schristos   /* check to see if we got ALL the symbols we requested */
600*10dd2532Schristos   /* this will write one line to stderr for every symbol not found */
601*10dd2532Schristos 
602*10dd2532Schristos   i = 0;
603*10dd2532Schristos   while (nlst->n_name != NULL)   {
604*10dd2532Schristos       if (nlst->n_type == 0) {
605*10dd2532Schristos 	  /* this one wasn't found */
606*10dd2532Schristos 	  fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
607*10dd2532Schristos 	  i = 1;
608*10dd2532Schristos 	}
609*10dd2532Schristos       nlst++;
610*10dd2532Schristos     }
611*10dd2532Schristos 
612*10dd2532Schristos   return(i);
613*10dd2532Schristos }
614*10dd2532Schristos 
615*10dd2532Schristos /* get process table */
getptable(baseptr)616*10dd2532Schristos void getptable (baseptr)
617*10dd2532Schristos      struct prpsinfo *baseptr;
618*10dd2532Schristos {
619*10dd2532Schristos   struct prpsinfo *currproc;	/* pointer to current proc structure	*/
620*10dd2532Schristos   int numprocs = 0;
621*10dd2532Schristos   int i;
622*10dd2532Schristos   struct dirent *directp;
623*10dd2532Schristos   struct oldproc *op;
624*10dd2532Schristos   static struct timeval lasttime =
625*10dd2532Schristos   {0L, 0L};
626*10dd2532Schristos   struct timeval thistime;
627*10dd2532Schristos   struct timezone thiszone;
628*10dd2532Schristos   double timediff;
629*10dd2532Schristos   double alpha, beta;
630*10dd2532Schristos   struct oldproc *endbase;
631*10dd2532Schristos 
632*10dd2532Schristos   gettimeofday (&thistime, &thiszone);
633*10dd2532Schristos 
634*10dd2532Schristos   /*
635*10dd2532Schristos    * To avoid divides, we keep times in nanoseconds.  This is
636*10dd2532Schristos    * scaled by 1e7 rather than 1e9 so that when we divide we
637*10dd2532Schristos    * get percent.
638*10dd2532Schristos    */
639*10dd2532Schristos   if (lasttime.tv_sec)
640*10dd2532Schristos     timediff = ((double) thistime.tv_sec * 1.0e7 +
641*10dd2532Schristos 		((double) thistime.tv_usec * 10.0)) -
642*10dd2532Schristos       ((double) lasttime.tv_sec * 1.0e7 +
643*10dd2532Schristos        ((double) lasttime.tv_usec * 10.0));
644*10dd2532Schristos   else
645*10dd2532Schristos     timediff = 1.0e7;
646*10dd2532Schristos 
647*10dd2532Schristos   /*
648*10dd2532Schristos      * constants for exponential average.  avg = alpha * new + beta * avg
649*10dd2532Schristos      * The goal is 50% decay in 30 sec.  However if the sample period
650*10dd2532Schristos      * is greater than 30 sec, there's not a lot we can do.
651*10dd2532Schristos      */
652*10dd2532Schristos   if (timediff < 30.0e7)
653*10dd2532Schristos     {
654*10dd2532Schristos       alpha = 0.5 * (timediff / 30.0e7);
655*10dd2532Schristos       beta = 1.0 - alpha;
656*10dd2532Schristos     }
657*10dd2532Schristos   else
658*10dd2532Schristos     {
659*10dd2532Schristos       alpha = 0.5;
660*10dd2532Schristos       beta = 0.5;
661*10dd2532Schristos     }
662*10dd2532Schristos 
663*10dd2532Schristos   endbase = oldbase + oldprocs;
664*10dd2532Schristos   currproc = baseptr;
665*10dd2532Schristos 
666*10dd2532Schristos 
667*10dd2532Schristos   for (rewinddir (procdir); directp = readdir (procdir);)
668*10dd2532Schristos     {
669*10dd2532Schristos       int fd;
670*10dd2532Schristos 
671*10dd2532Schristos       if ((fd = open (directp->d_name, O_RDONLY)) < 0)
672*10dd2532Schristos 	continue;
673*10dd2532Schristos 
674*10dd2532Schristos       currproc = &baseptr[numprocs];
675*10dd2532Schristos       if (ioctl (fd, PIOCPSINFO, currproc) < 0)
676*10dd2532Schristos 	{
677*10dd2532Schristos 	  (void) close (fd);
678*10dd2532Schristos 	  continue;
679*10dd2532Schristos 	}
680*10dd2532Schristos 
681*10dd2532Schristos       /*
682*10dd2532Schristos        * SVr4 doesn't keep track of CPU% in the kernel, so we have
683*10dd2532Schristos        * to do our own.  See if we've heard of this process before.
684*10dd2532Schristos        * If so, compute % based on CPU since last time.
685*10dd2532Schristos        */
686*10dd2532Schristos       op = oldbase + HASH (currproc->pr_pid);
687*10dd2532Schristos       while (1)
688*10dd2532Schristos 	{
689*10dd2532Schristos 	  if (op->oldpid == -1)	/* not there */
690*10dd2532Schristos 	    break;
691*10dd2532Schristos 	  if (op->oldpid == currproc->pr_pid)
692*10dd2532Schristos 	    {			/* found old data */
693*10dd2532Schristos 	      percent_cpu (currproc) =
694*10dd2532Schristos 		((currproc->pr_time.tv_sec * 1.0e9 +
695*10dd2532Schristos 		  currproc->pr_time.tv_nsec)
696*10dd2532Schristos 		 - op->oldtime) / timediff;
697*10dd2532Schristos 	      weighted_cpu (currproc) =
698*10dd2532Schristos 		op->oldpct * beta + percent_cpu (currproc) * alpha;
699*10dd2532Schristos 
700*10dd2532Schristos 	      break;
701*10dd2532Schristos 	    }
702*10dd2532Schristos 	  op++;			/* try next entry in hash table */
703*10dd2532Schristos 	  if (op == endbase)	/* table wrapped around */
704*10dd2532Schristos 	    op = oldbase;
705*10dd2532Schristos 	}
706*10dd2532Schristos 
707*10dd2532Schristos       /* Otherwise, it's new, so use all of its CPU time */
708*10dd2532Schristos       if (op->oldpid == -1)
709*10dd2532Schristos 	{
710*10dd2532Schristos 	  if (lasttime.tv_sec)
711*10dd2532Schristos 	    {
712*10dd2532Schristos 	      percent_cpu (currproc) =
713*10dd2532Schristos 		(currproc->pr_time.tv_sec * 1.0e9 +
714*10dd2532Schristos 		 currproc->pr_time.tv_nsec) / timediff;
715*10dd2532Schristos 	      weighted_cpu (currproc) =
716*10dd2532Schristos 		percent_cpu (currproc);
717*10dd2532Schristos 	    }
718*10dd2532Schristos 	  else
719*10dd2532Schristos 	    {			/* first screen -- no difference is possible */
720*10dd2532Schristos 	      percent_cpu (currproc) = 0.0;
721*10dd2532Schristos 	      weighted_cpu (currproc) = 0.0;
722*10dd2532Schristos 	    }
723*10dd2532Schristos 	}
724*10dd2532Schristos 
725*10dd2532Schristos       numprocs++;
726*10dd2532Schristos       (void) close (fd);
727*10dd2532Schristos     }
728*10dd2532Schristos 
729*10dd2532Schristos   if (nproc != numprocs)
730*10dd2532Schristos     nproc = numprocs;
731*10dd2532Schristos 
732*10dd2532Schristos   /*
733*10dd2532Schristos    * Save current CPU time for next time around
734*10dd2532Schristos    * For the moment recreate the hash table each time, as the code
735*10dd2532Schristos    * is easier that way.
736*10dd2532Schristos    */
737*10dd2532Schristos   oldprocs = 2 * nproc;
738*10dd2532Schristos   endbase = oldbase + oldprocs;
739*10dd2532Schristos   for (op = oldbase; op < endbase; op++)
740*10dd2532Schristos     op->oldpid = -1;
741*10dd2532Schristos   for (i = 0, currproc = baseptr;
742*10dd2532Schristos        i < nproc;
743*10dd2532Schristos      i++, currproc = (struct prpsinfo *) ((char *) currproc + PRPSINFOSIZE))
744*10dd2532Schristos     {
745*10dd2532Schristos       /* find an empty spot */
746*10dd2532Schristos       op = oldbase + HASH (currproc->pr_pid);
747*10dd2532Schristos       while (1)
748*10dd2532Schristos 	{
749*10dd2532Schristos 	  if (op->oldpid == -1)
750*10dd2532Schristos 	    break;
751*10dd2532Schristos 	  op++;
752*10dd2532Schristos 	  if (op == endbase)
753*10dd2532Schristos 	    op = oldbase;
754*10dd2532Schristos 	}
755*10dd2532Schristos       op->oldpid = currproc->pr_pid;
756*10dd2532Schristos       op->oldtime = (currproc->pr_time.tv_sec * 1.0e9 +
757*10dd2532Schristos 		     currproc->pr_time.tv_nsec);
758*10dd2532Schristos       op->oldpct = weighted_cpu (currproc);
759*10dd2532Schristos     }
760*10dd2532Schristos   lasttime = thistime;
761*10dd2532Schristos 
762*10dd2532Schristos }
763*10dd2532Schristos 
764