xref: /minix3/external/bsd/top/dist/machine/m_irixsgi.c (revision b89261ba018da33f0bd8cd05f5a1fe9e7a9c837b)
1*b89261baSDavid van Moolenbroek /*
2*b89261baSDavid van Moolenbroek  * Copyright (c) 1984 through 2008, William LeFebvre
3*b89261baSDavid van Moolenbroek  * All rights reserved.
4*b89261baSDavid van Moolenbroek  *
5*b89261baSDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
6*b89261baSDavid van Moolenbroek  * modification, are permitted provided that the following conditions are met:
7*b89261baSDavid van Moolenbroek  *
8*b89261baSDavid van Moolenbroek  *     * Redistributions of source code must retain the above copyright
9*b89261baSDavid van Moolenbroek  * notice, this list of conditions and the following disclaimer.
10*b89261baSDavid van Moolenbroek  *
11*b89261baSDavid van Moolenbroek  *     * Redistributions in binary form must reproduce the above
12*b89261baSDavid van Moolenbroek  * copyright notice, this list of conditions and the following disclaimer
13*b89261baSDavid van Moolenbroek  * in the documentation and/or other materials provided with the
14*b89261baSDavid van Moolenbroek  * distribution.
15*b89261baSDavid van Moolenbroek  *
16*b89261baSDavid van Moolenbroek  *     * Neither the name of William LeFebvre nor the names of other
17*b89261baSDavid van Moolenbroek  * contributors may be used to endorse or promote products derived from
18*b89261baSDavid van Moolenbroek  * this software without specific prior written permission.
19*b89261baSDavid van Moolenbroek  *
20*b89261baSDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*b89261baSDavid van Moolenbroek  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*b89261baSDavid van Moolenbroek  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23*b89261baSDavid van Moolenbroek  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24*b89261baSDavid van Moolenbroek  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25*b89261baSDavid van Moolenbroek  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26*b89261baSDavid van Moolenbroek  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27*b89261baSDavid van Moolenbroek  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28*b89261baSDavid van Moolenbroek  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29*b89261baSDavid van Moolenbroek  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30*b89261baSDavid van Moolenbroek  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*b89261baSDavid van Moolenbroek  */
32*b89261baSDavid van Moolenbroek 
33*b89261baSDavid van Moolenbroek /*
34*b89261baSDavid van Moolenbroek  * top - a top users display for Unix
35*b89261baSDavid van Moolenbroek  *
36*b89261baSDavid van Moolenbroek  * SYNOPSIS:  Any SGI machine running IRIX 6.2 and up
37*b89261baSDavid van Moolenbroek  *
38*b89261baSDavid van Moolenbroek  * DESCRIPTION:
39*b89261baSDavid van Moolenbroek  * This is the machine-dependent module for IRIX as supplied by
40*b89261baSDavid van Moolenbroek  * engineers at SGI.
41*b89261baSDavid van Moolenbroek  *
42*b89261baSDavid van Moolenbroek  * CFLAGS: -DHAVE_GETOPT -D_OLD_TERMIOS -DORDER
43*b89261baSDavid van Moolenbroek  *
44*b89261baSDavid van Moolenbroek  * AUTHOR: Sandeep Cariapa <cariapa@sgi.com>
45*b89261baSDavid van Moolenbroek  * AUTHOR: Larry McVoy <lm@sgi.com>
46*b89261baSDavid van Moolenbroek  * Sandeep did all the hard work; I ported to 6.2 and fixed up some formats.
47*b89261baSDavid van Moolenbroek  * AUTHOR: John Schimmel <jes@sgi.com>
48*b89261baSDavid van Moolenbroek  * He did the all irix merge.
49*b89261baSDavid van Moolenbroek  * AUTHOR: Ariel Faigon <ariel@sgi.com>
50*b89261baSDavid van Moolenbroek  *	Ported to Ficus/Kudzu (IRIX 6.4+).
51*b89261baSDavid van Moolenbroek  *	Got rid of all nlist and different (elf64, elf32, COFF) kernel
52*b89261baSDavid van Moolenbroek  *	dependencies
53*b89261baSDavid van Moolenbroek  *	Various small fixes and enhancements: multiple CPUs, nicer formats.
54*b89261baSDavid van Moolenbroek  *	Added -DORDER process display ordering
55*b89261baSDavid van Moolenbroek  *	cleaned most -fullwarn'ings.
56*b89261baSDavid van Moolenbroek  *	Need -D_OLD_TERMIOS when compiling on IRIX 6.4 to work on 6.2 systems
57*b89261baSDavid van Moolenbroek  *	Support much bigger values in memory sizes (over Peta-byte)
58*b89261baSDavid van Moolenbroek  * AUTHOR: William LeFebvre
59*b89261baSDavid van Moolenbroek  *      Converted to ANSI C and updated to new module interface
60*b89261baSDavid van Moolenbroek  */
61*b89261baSDavid van Moolenbroek 
62*b89261baSDavid van Moolenbroek #define _KMEMUSER
63*b89261baSDavid van Moolenbroek 
64*b89261baSDavid van Moolenbroek #include "config.h"
65*b89261baSDavid van Moolenbroek 
66*b89261baSDavid van Moolenbroek #include <sys/types.h>
67*b89261baSDavid van Moolenbroek #include <sys/time.h>
68*b89261baSDavid van Moolenbroek #include <sys/stat.h>
69*b89261baSDavid van Moolenbroek #include <sys/swap.h>
70*b89261baSDavid van Moolenbroek #include <sys/proc.h>
71*b89261baSDavid van Moolenbroek #include <sys/procfs.h>
72*b89261baSDavid van Moolenbroek #include <sys/sysinfo.h>
73*b89261baSDavid van Moolenbroek #include <sys/sysmp.h>
74*b89261baSDavid van Moolenbroek #include <sys/utsname.h>
75*b89261baSDavid van Moolenbroek #include <sys/schedctl.h>	/* for < 6.4 NDPHIMAX et al. */
76*b89261baSDavid van Moolenbroek #include <paths.h>
77*b89261baSDavid van Moolenbroek #include <assert.h>
78*b89261baSDavid van Moolenbroek #include <values.h>
79*b89261baSDavid van Moolenbroek #include <dirent.h>
80*b89261baSDavid van Moolenbroek #include <stdio.h>
81*b89261baSDavid van Moolenbroek #include <unistd.h>
82*b89261baSDavid van Moolenbroek #include <stdlib.h>
83*b89261baSDavid van Moolenbroek #include <errno.h>
84*b89261baSDavid van Moolenbroek #include <fcntl.h>
85*b89261baSDavid van Moolenbroek #include <dlfcn.h>
86*b89261baSDavid van Moolenbroek 
87*b89261baSDavid van Moolenbroek #include "top.h"
88*b89261baSDavid van Moolenbroek #include "machine.h"
89*b89261baSDavid van Moolenbroek #include "utils.h"
90*b89261baSDavid van Moolenbroek 
91*b89261baSDavid van Moolenbroek #define KMEM	"/dev/kmem"
92*b89261baSDavid van Moolenbroek 
93*b89261baSDavid van Moolenbroek typedef double load_avg;
94*b89261baSDavid van Moolenbroek #define loaddouble(la) (la)
95*b89261baSDavid van Moolenbroek #define intload(i) ((double)(i))
96*b89261baSDavid van Moolenbroek 
97*b89261baSDavid van Moolenbroek /*
98*b89261baSDavid van Moolenbroek  * Structure for keeping track of CPU times from last time around
99*b89261baSDavid van Moolenbroek  * the program.  We keep these things in a hash table, which is
100*b89261baSDavid van Moolenbroek  * recreated at every cycle.
101*b89261baSDavid van Moolenbroek  */
102*b89261baSDavid van Moolenbroek struct oldproc {
103*b89261baSDavid van Moolenbroek 	pid_t	oldpid;
104*b89261baSDavid van Moolenbroek 	double	oldtime;
105*b89261baSDavid van Moolenbroek 	double	oldpct;
106*b89261baSDavid van Moolenbroek };
107*b89261baSDavid van Moolenbroek static int oldprocs;                    /* size of table */
108*b89261baSDavid van Moolenbroek static struct oldproc *oldbase;
109*b89261baSDavid van Moolenbroek #define HASH(x) ((x << 1) % oldprocs)
110*b89261baSDavid van Moolenbroek 
111*b89261baSDavid van Moolenbroek 
112*b89261baSDavid van Moolenbroek #define pagetok(pages) ((((uint64_t) pages) * pagesize) >> 10)
113*b89261baSDavid van Moolenbroek 
114*b89261baSDavid van Moolenbroek /*
115*b89261baSDavid van Moolenbroek  * Ugly hack, save space and complexity of allocating and maintaining
116*b89261baSDavid van Moolenbroek  * parallel arrays to the prpsinfo array: use spare space (pr_fill area)
117*b89261baSDavid van Moolenbroek  * in prpsinfo structures to store %CPU calculated values
118*b89261baSDavid van Moolenbroek  */
119*b89261baSDavid van Moolenbroek #define D_align(addr)		(((unsigned long)(addr) & ~0x0fU))
120*b89261baSDavid van Moolenbroek #define percent_cpu(pp)		(* (double *) D_align(&((pp)->pr_fill[0])))
121*b89261baSDavid van Moolenbroek #define weighted_cpu(pp)	(* (double *) D_align(&((pp)->pr_fill[4])))
122*b89261baSDavid van Moolenbroek 
123*b89261baSDavid van Moolenbroek 
124*b89261baSDavid van Moolenbroek /* Username field to fill in starts at: */
125*b89261baSDavid van Moolenbroek #define UNAME_START 16
126*b89261baSDavid van Moolenbroek 
127*b89261baSDavid van Moolenbroek /*
128*b89261baSDavid van Moolenbroek  *  These definitions control the format of the per-process area
129*b89261baSDavid van Moolenbroek  */
130*b89261baSDavid van Moolenbroek static char header[] =
131*b89261baSDavid van Moolenbroek "    PID    PGRP X         PRI   SIZE   RES STATE    TIME %WCPU  %CPU COMMAND";
132*b89261baSDavid van Moolenbroek /*
133*b89261baSDavid van Moolenbroek  012345678901234567890123456789012345678901234567890123456789012345678901234567
134*b89261baSDavid van Moolenbroek           10        20        30        40        50        60        70
135*b89261baSDavid van Moolenbroek  */
136*b89261baSDavid van Moolenbroek 
137*b89261baSDavid van Moolenbroek /*       PID PGRP USER  PRI   SIZE  RES   STATE  TIME  %WCPU %CPU  CMD */
138*b89261baSDavid van Moolenbroek #define Proc_format \
139*b89261baSDavid van Moolenbroek 	"%7d %7d %-8.8s %4.4s %6.6s %5.5s %-6.6s %6.6s %5.2f %5.2f %-.10s"
140*b89261baSDavid van Moolenbroek 
141*b89261baSDavid van Moolenbroek 
142*b89261baSDavid van Moolenbroek /*
143*b89261baSDavid van Moolenbroek  * these are for detailing the cpu states
144*b89261baSDavid van Moolenbroek  * Data is taken from the sysinfo structure (see <sys/sysinfo.h>)
145*b89261baSDavid van Moolenbroek  * We rely on the following values:
146*b89261baSDavid van Moolenbroek  *
147*b89261baSDavid van Moolenbroek  *	#define CPU_IDLE        0
148*b89261baSDavid van Moolenbroek  *	#define CPU_USER        1
149*b89261baSDavid van Moolenbroek  *	#define CPU_KERNEL      2
150*b89261baSDavid van Moolenbroek  *	#define CPU_WAIT        3
151*b89261baSDavid van Moolenbroek  *	#define CPU_SXBRK       4
152*b89261baSDavid van Moolenbroek  *	#define CPU_INTR        5
153*b89261baSDavid van Moolenbroek  */
154*b89261baSDavid van Moolenbroek #ifndef CPU_STATES	/* defined only in 6.4 and up */
155*b89261baSDavid van Moolenbroek # define CPU_STATES 6
156*b89261baSDavid van Moolenbroek #endif
157*b89261baSDavid van Moolenbroek 
158*b89261baSDavid van Moolenbroek int	cpu_states[CPU_STATES];
159*b89261baSDavid van Moolenbroek char	*cpustatenames[] = {
160*b89261baSDavid van Moolenbroek 	"idle", "usr", "ker", "wait", "xbrk", "intr",
161*b89261baSDavid van Moolenbroek 	NULL
162*b89261baSDavid van Moolenbroek };
163*b89261baSDavid van Moolenbroek 
164*b89261baSDavid van Moolenbroek /* these are for detailing the memory statistics */
165*b89261baSDavid van Moolenbroek 
166*b89261baSDavid van Moolenbroek #define MEMSTATS 10
167*b89261baSDavid van Moolenbroek int	memory_stats[MEMSTATS];
168*b89261baSDavid van Moolenbroek char	*memorynames[] = {
169*b89261baSDavid van Moolenbroek 	"K max, ", "K avail, ", "K free, ", "K swap, ", "K free swap", NULL
170*b89261baSDavid van Moolenbroek };
171*b89261baSDavid van Moolenbroek 
172*b89261baSDavid van Moolenbroek char	uname_str[40];
173*b89261baSDavid van Moolenbroek double	load[3];
174*b89261baSDavid van Moolenbroek static  char fmt[MAX_COLS + 2];
175*b89261baSDavid van Moolenbroek int	numcpus;
176*b89261baSDavid van Moolenbroek 
177*b89261baSDavid van Moolenbroek /* useful externals */
178*b89261baSDavid van Moolenbroek extern int	errno;
179*b89261baSDavid van Moolenbroek extern char	*sys_errlist[];
180*b89261baSDavid van Moolenbroek 
181*b89261baSDavid van Moolenbroek extern char	*myname;
182*b89261baSDavid van Moolenbroek extern char	*format_k();
183*b89261baSDavid van Moolenbroek extern char	*format_time();
184*b89261baSDavid van Moolenbroek extern long	percentages();
185*b89261baSDavid van Moolenbroek 
186*b89261baSDavid van Moolenbroek static int kmem;
187*b89261baSDavid van Moolenbroek static unsigned long avenrun_offset;
188*b89261baSDavid van Moolenbroek 
189*b89261baSDavid van Moolenbroek static float	irix_ver;		/* for easy numeric comparison */
190*b89261baSDavid van Moolenbroek 
191*b89261baSDavid van Moolenbroek static struct prpsinfo	*pbase;
192*b89261baSDavid van Moolenbroek static struct prpsinfo	**pref;
193*b89261baSDavid van Moolenbroek static struct oldproc	*oldbase;
194*b89261baSDavid van Moolenbroek static int		oldprocs;	/* size of table */
195*b89261baSDavid van Moolenbroek 
196*b89261baSDavid van Moolenbroek static DIR	*procdir;
197*b89261baSDavid van Moolenbroek 
198*b89261baSDavid van Moolenbroek static int	ptable_size;	/* allocated process table size */
199*b89261baSDavid van Moolenbroek static int	nproc;		/* estimated process table size */
200*b89261baSDavid van Moolenbroek static int	pagesize;
201*b89261baSDavid van Moolenbroek 
202*b89261baSDavid van Moolenbroek /* get_process_info passes back a handle.  This is what it looks like: */
203*b89261baSDavid van Moolenbroek struct handle {
204*b89261baSDavid van Moolenbroek 	struct prpsinfo **next_proc;	/* points to next valid proc pointer */
205*b89261baSDavid van Moolenbroek 	int		remaining;	/* number of pointers remaining */
206*b89261baSDavid van Moolenbroek };
207*b89261baSDavid van Moolenbroek 
208*b89261baSDavid van Moolenbroek static struct handle	handle;
209*b89261baSDavid van Moolenbroek 
210*b89261baSDavid van Moolenbroek void getptable(struct prpsinfo *baseptr);
211*b89261baSDavid van Moolenbroek void size(int fd, struct prpsinfo *ps);
212*b89261baSDavid van Moolenbroek 
213*b89261baSDavid van Moolenbroek extern char *ordernames[];
214*b89261baSDavid van Moolenbroek 
215*b89261baSDavid van Moolenbroek /*
216*b89261baSDavid van Moolenbroek  * Process states letters are mapped into numbers
217*b89261baSDavid van Moolenbroek  * 6.5 seems to have changed the semantics of prpsinfo.pr_state
218*b89261baSDavid van Moolenbroek  * so we rely, (like ps does) on the char value pr_sname.
219*b89261baSDavid van Moolenbroek  * The order we use here is what may be most interesting
220*b89261baSDavid van Moolenbroek  * to top users:  Most interesting state on top, least on bottom.
221*b89261baSDavid van Moolenbroek  * 'S' (sleeping) is the most common case so I put it _after_
222*b89261baSDavid van Moolenbroek  * zombie, even though it is more "active" than zombie.
223*b89261baSDavid van Moolenbroek  *
224*b89261baSDavid van Moolenbroek  * State letters and their meanings:
225*b89261baSDavid van Moolenbroek  *
226*b89261baSDavid van Moolenbroek  *	R   Process is running (may not have a processor yet)
227*b89261baSDavid van Moolenbroek  *	I   Process is in intermediate state of creation
228*b89261baSDavid van Moolenbroek  *	X   Process is waiting for memory
229*b89261baSDavid van Moolenbroek  *	T   Process is stopped
230*b89261baSDavid van Moolenbroek  *	Z   Process is terminated and parent not waiting (zombie)
231*b89261baSDavid van Moolenbroek  *	S   Process is sleeping, waiting for a resource
232*b89261baSDavid van Moolenbroek  */
233*b89261baSDavid van Moolenbroek 
234*b89261baSDavid van Moolenbroek /* abbreviated process states */
235*b89261baSDavid van Moolenbroek static char *state_abbrev[] =
236*b89261baSDavid van Moolenbroek { "", "sleep", "zomb", "stop", "swap", "start", "ready", "run", NULL };
237*b89261baSDavid van Moolenbroek 
238*b89261baSDavid van Moolenbroek /* Same but a little "wordier", used in CPU activity summary */
239*b89261baSDavid van Moolenbroek int     process_states[8];	/* per state counters */
240*b89261baSDavid van Moolenbroek char	*procstatenames[] = {
241*b89261baSDavid van Moolenbroek 	/* ready to run is considered running here */
242*b89261baSDavid van Moolenbroek 	"",		" sleeping, ",	" zombie, ",	" stopped, ",
243*b89261baSDavid van Moolenbroek 	" swapped, ",	" starting, ",	" ready, ",	" running, ",
244*b89261baSDavid van Moolenbroek 	NULL
245*b89261baSDavid van Moolenbroek };
246*b89261baSDavid van Moolenbroek 
247*b89261baSDavid van Moolenbroek #define S_RUNNING	7
248*b89261baSDavid van Moolenbroek #define S_READY		6
249*b89261baSDavid van Moolenbroek #define S_STARTING	5
250*b89261baSDavid van Moolenbroek #define S_SWAPPED	4
251*b89261baSDavid van Moolenbroek #define S_STOPPED	3
252*b89261baSDavid van Moolenbroek #define S_ZOMBIE	2
253*b89261baSDavid van Moolenbroek #define S_SLEEPING	1
254*b89261baSDavid van Moolenbroek 
255*b89261baSDavid van Moolenbroek #define IS_ACTIVE(pp) \
256*b89261baSDavid van Moolenbroek 	(first_screen ? proc_state(pp) >= S_STARTING : percent_cpu(pp) > 0.0)
257*b89261baSDavid van Moolenbroek 
258*b89261baSDavid van Moolenbroek /*
259*b89261baSDavid van Moolenbroek  * proc_state
260*b89261baSDavid van Moolenbroek  *	map the pr_sname value to an integer.
261*b89261baSDavid van Moolenbroek  *	used as an index into state_abbrev[]
262*b89261baSDavid van Moolenbroek  *	as well as an "order" key
263*b89261baSDavid van Moolenbroek  */
proc_state(struct prpsinfo * pp)264*b89261baSDavid van Moolenbroek static int proc_state(struct prpsinfo *pp)
265*b89261baSDavid van Moolenbroek {
266*b89261baSDavid van Moolenbroek     char psname = pp->pr_sname;
267*b89261baSDavid van Moolenbroek 
268*b89261baSDavid van Moolenbroek     switch (psname) {
269*b89261baSDavid van Moolenbroek 	case 'R': return
270*b89261baSDavid van Moolenbroek 		 (pp->pr_sonproc >= 0 && pp->pr_sonproc < numcpus) ?
271*b89261baSDavid van Moolenbroek 			S_RUNNING /* on a processor */ : S_READY;
272*b89261baSDavid van Moolenbroek 	case 'I': return S_STARTING;
273*b89261baSDavid van Moolenbroek 	case 'X': return S_SWAPPED;
274*b89261baSDavid van Moolenbroek 	case 'T': return S_STOPPED;
275*b89261baSDavid van Moolenbroek 	case 'Z': return S_ZOMBIE;
276*b89261baSDavid van Moolenbroek 	case 'S': return S_SLEEPING;
277*b89261baSDavid van Moolenbroek 	default : return 0;
278*b89261baSDavid van Moolenbroek     }
279*b89261baSDavid van Moolenbroek }
280*b89261baSDavid van Moolenbroek 
281*b89261baSDavid van Moolenbroek 
282*b89261baSDavid van Moolenbroek /*
283*b89261baSDavid van Moolenbroek  * To avoid nlist'ing the kernel (with all the different kernel type
284*b89261baSDavid van Moolenbroek  * complexities), we estimate the size of the needed working process
285*b89261baSDavid van Moolenbroek  * table by scanning  /proc/pinfo and taking the number of entries
286*b89261baSDavid van Moolenbroek  * multiplied by some reasonable factor.
287*b89261baSDavid van Moolenbroek  * Assume current dir is _PATH_PROCFSPI
288*b89261baSDavid van Moolenbroek  */
active_proc_count()289*b89261baSDavid van Moolenbroek static int active_proc_count()
290*b89261baSDavid van Moolenbroek {
291*b89261baSDavid van Moolenbroek 	DIR	*dirp;
292*b89261baSDavid van Moolenbroek 	int	pcnt;
293*b89261baSDavid van Moolenbroek 
294*b89261baSDavid van Moolenbroek 	if ((dirp = opendir(".")) == NULL) {
295*b89261baSDavid van Moolenbroek 		(void) fprintf(stderr, "%s: Unable to open %s\n",
296*b89261baSDavid van Moolenbroek 					myname, _PATH_PROCFSPI);
297*b89261baSDavid van Moolenbroek 		exit(1);
298*b89261baSDavid van Moolenbroek 	}
299*b89261baSDavid van Moolenbroek 	for (pcnt = 0; readdir(dirp) != NULL; pcnt++)
300*b89261baSDavid van Moolenbroek 		;
301*b89261baSDavid van Moolenbroek 	closedir(dirp);
302*b89261baSDavid van Moolenbroek 
303*b89261baSDavid van Moolenbroek 	return pcnt;
304*b89261baSDavid van Moolenbroek }
305*b89261baSDavid van Moolenbroek 
306*b89261baSDavid van Moolenbroek /*
307*b89261baSDavid van Moolenbroek  * allocate space for:
308*b89261baSDavid van Moolenbroek  *	proc structure array
309*b89261baSDavid van Moolenbroek  *	array of pointers to the above (used for sorting)
310*b89261baSDavid van Moolenbroek  *	array for storing per-process old CPU usage
311*b89261baSDavid van Moolenbroek  */
312*b89261baSDavid van Moolenbroek void
allocate_proc_tables()313*b89261baSDavid van Moolenbroek allocate_proc_tables()
314*b89261baSDavid van Moolenbroek {
315*b89261baSDavid van Moolenbroek 	int	n_active = active_proc_count();
316*b89261baSDavid van Moolenbroek 
317*b89261baSDavid van Moolenbroek 	if (pbase != NULL)  /* && n_active < ptable_size */
318*b89261baSDavid van Moolenbroek 		return;
319*b89261baSDavid van Moolenbroek 
320*b89261baSDavid van Moolenbroek 	/* Need to realloc if we exceed, but factor should be enough */
321*b89261baSDavid van Moolenbroek 	nproc = n_active * 5;
322*b89261baSDavid van Moolenbroek 	oldprocs = 2 * nproc;
323*b89261baSDavid van Moolenbroek 
324*b89261baSDavid van Moolenbroek 	pbase = (struct prpsinfo *)
325*b89261baSDavid van Moolenbroek 		malloc(nproc * sizeof(struct prpsinfo));
326*b89261baSDavid van Moolenbroek 	pref = (struct prpsinfo **)
327*b89261baSDavid van Moolenbroek 		malloc(nproc * sizeof(struct prpsinfo *));
328*b89261baSDavid van Moolenbroek 	oldbase = (struct oldproc *)
329*b89261baSDavid van Moolenbroek 		malloc (oldprocs * sizeof(struct oldproc));
330*b89261baSDavid van Moolenbroek 
331*b89261baSDavid van Moolenbroek 	ptable_size = nproc;
332*b89261baSDavid van Moolenbroek 
333*b89261baSDavid van Moolenbroek 	if (pbase == NULL || pref == NULL || oldbase == NULL) {
334*b89261baSDavid van Moolenbroek 		(void) fprintf(stderr, "%s: malloc: out of memory\n", myname);
335*b89261baSDavid van Moolenbroek 		exit (1);
336*b89261baSDavid van Moolenbroek 	}
337*b89261baSDavid van Moolenbroek }
338*b89261baSDavid van Moolenbroek 
339*b89261baSDavid van Moolenbroek int
machine_init(struct statics * statics)340*b89261baSDavid van Moolenbroek machine_init(struct statics *statics)
341*b89261baSDavid van Moolenbroek {
342*b89261baSDavid van Moolenbroek 	struct oldproc	*op, *endbase;
343*b89261baSDavid van Moolenbroek 	int		pcnt = 0;
344*b89261baSDavid van Moolenbroek 	struct utsname	utsname;
345*b89261baSDavid van Moolenbroek 	char		tmpbuf[20];
346*b89261baSDavid van Moolenbroek 
347*b89261baSDavid van Moolenbroek 	uname(&utsname);
348*b89261baSDavid van Moolenbroek 	irix_ver = (float) atof((const char *)utsname.release);
349*b89261baSDavid van Moolenbroek 	strncpy(tmpbuf, utsname.release, 9);
350*b89261baSDavid van Moolenbroek 	tmpbuf[9] = '\0';
351*b89261baSDavid van Moolenbroek 	sprintf(uname_str, "%s %-.14s %s %s",
352*b89261baSDavid van Moolenbroek 		utsname.sysname, utsname.nodename,
353*b89261baSDavid van Moolenbroek 		tmpbuf, utsname.machine);
354*b89261baSDavid van Moolenbroek 
355*b89261baSDavid van Moolenbroek 	pagesize = getpagesize();
356*b89261baSDavid van Moolenbroek 
357*b89261baSDavid van Moolenbroek 	if ((kmem = open(KMEM, O_RDONLY)) == -1) {
358*b89261baSDavid van Moolenbroek 		perror(KMEM);
359*b89261baSDavid van Moolenbroek 		return -1;
360*b89261baSDavid van Moolenbroek 	}
361*b89261baSDavid van Moolenbroek 
362*b89261baSDavid van Moolenbroek 	if (chdir(_PATH_PROCFSPI)) {
363*b89261baSDavid van Moolenbroek 		/* handy for later on when we're reading it */
364*b89261baSDavid van Moolenbroek 		(void) fprintf(stderr, "%s: Unable to chdir to %s\n",
365*b89261baSDavid van Moolenbroek 					myname, _PATH_PROCFSPI);
366*b89261baSDavid van Moolenbroek 		return -1;
367*b89261baSDavid van Moolenbroek 	}
368*b89261baSDavid van Moolenbroek 	if ((procdir = opendir(".")) == NULL) {
369*b89261baSDavid van Moolenbroek 		(void) fprintf(stderr, "%s: Unable to open %s\n",
370*b89261baSDavid van Moolenbroek 					myname, _PATH_PROCFSPI);
371*b89261baSDavid van Moolenbroek 		return -1;
372*b89261baSDavid van Moolenbroek 	}
373*b89261baSDavid van Moolenbroek 
374*b89261baSDavid van Moolenbroek 	if ((avenrun_offset = sysmp(MP_KERNADDR, MPKA_AVENRUN)) == -1) {
375*b89261baSDavid van Moolenbroek 		perror("sysmp(MP_KERNADDR, MPKA_AVENRUN)");
376*b89261baSDavid van Moolenbroek 		return -1;
377*b89261baSDavid van Moolenbroek 	}
378*b89261baSDavid van Moolenbroek 
379*b89261baSDavid van Moolenbroek 	allocate_proc_tables();
380*b89261baSDavid van Moolenbroek 
381*b89261baSDavid van Moolenbroek 	oldprocs = 2 * nproc;
382*b89261baSDavid van Moolenbroek 	endbase = oldbase + oldprocs;
383*b89261baSDavid van Moolenbroek 	for (op = oldbase; op < endbase; op++) {
384*b89261baSDavid van Moolenbroek 		op->oldpid = -1;
385*b89261baSDavid van Moolenbroek 	}
386*b89261baSDavid van Moolenbroek 
387*b89261baSDavid van Moolenbroek 	statics->cpustate_names = cpustatenames;
388*b89261baSDavid van Moolenbroek 	statics->memory_names = memorynames;
389*b89261baSDavid van Moolenbroek 	statics->order_names = ordernames;
390*b89261baSDavid van Moolenbroek 	statics->procstate_names = procstatenames;
391*b89261baSDavid van Moolenbroek 
392*b89261baSDavid van Moolenbroek 	return (0);
393*b89261baSDavid van Moolenbroek }
394*b89261baSDavid van Moolenbroek 
395*b89261baSDavid van Moolenbroek char   *
format_header(register char * uname_field)396*b89261baSDavid van Moolenbroek format_header(register char *uname_field)
397*b89261baSDavid van Moolenbroek 
398*b89261baSDavid van Moolenbroek {
399*b89261baSDavid van Moolenbroek 	register char *ptr;
400*b89261baSDavid van Moolenbroek 
401*b89261baSDavid van Moolenbroek 	ptr = header + UNAME_START;
402*b89261baSDavid van Moolenbroek 	while (*uname_field != '\0') {
403*b89261baSDavid van Moolenbroek 		*ptr++ = *uname_field++;
404*b89261baSDavid van Moolenbroek 	}
405*b89261baSDavid van Moolenbroek 
406*b89261baSDavid van Moolenbroek 	return (header);
407*b89261baSDavid van Moolenbroek }
408*b89261baSDavid van Moolenbroek 
409*b89261baSDavid van Moolenbroek void
get_system_info(struct system_info * si)410*b89261baSDavid van Moolenbroek get_system_info(struct system_info *si)
411*b89261baSDavid van Moolenbroek 
412*b89261baSDavid van Moolenbroek {
413*b89261baSDavid van Moolenbroek 	int		i;
414*b89261baSDavid van Moolenbroek 	int		avenrun[3];
415*b89261baSDavid van Moolenbroek 	struct rminfo	realmem;
416*b89261baSDavid van Moolenbroek 	struct sysinfo	sysinfo;
417*b89261baSDavid van Moolenbroek 	static time_t	cp_old [CPU_STATES];
418*b89261baSDavid van Moolenbroek 	static time_t	cp_diff[CPU_STATES];	/* for cpu state percentages */
419*b89261baSDavid van Moolenbroek 	off_t		fswap;		/* current free swap in blocks */
420*b89261baSDavid van Moolenbroek 	off_t		tswap;		/* total swap in blocks */
421*b89261baSDavid van Moolenbroek 
422*b89261baSDavid van Moolenbroek 	(void) getkval(avenrun_offset, (int *) avenrun, sizeof(avenrun), "avenrun");
423*b89261baSDavid van Moolenbroek 
424*b89261baSDavid van Moolenbroek 	for (i = 0; i < 3; i++) {
425*b89261baSDavid van Moolenbroek 		si->load_avg[i] = loaddouble(avenrun[i]);
426*b89261baSDavid van Moolenbroek 		si->load_avg[i] /= 1024.0;
427*b89261baSDavid van Moolenbroek 	}
428*b89261baSDavid van Moolenbroek 
429*b89261baSDavid van Moolenbroek 	if ((numcpus = sysmp(MP_NPROCS)) == -1) {
430*b89261baSDavid van Moolenbroek 		perror("sysmp(MP_NPROCS)");
431*b89261baSDavid van Moolenbroek 		return;
432*b89261baSDavid van Moolenbroek 	}
433*b89261baSDavid van Moolenbroek 
434*b89261baSDavid van Moolenbroek 	if (sysmp(MP_SAGET, MPSA_RMINFO, &realmem, sizeof(realmem)) == -1) {
435*b89261baSDavid van Moolenbroek 		perror("sysmp(MP_SAGET,MPSA_RMINFO, ...)");
436*b89261baSDavid van Moolenbroek 		return;
437*b89261baSDavid van Moolenbroek 	}
438*b89261baSDavid van Moolenbroek 
439*b89261baSDavid van Moolenbroek 	swapctl(SC_GETFREESWAP, &fswap);
440*b89261baSDavid van Moolenbroek 	swapctl(SC_GETSWAPTOT, &tswap);
441*b89261baSDavid van Moolenbroek 
442*b89261baSDavid van Moolenbroek 	memory_stats[0] = pagetok(realmem.physmem);
443*b89261baSDavid van Moolenbroek 	memory_stats[1] = pagetok(realmem.availrmem);
444*b89261baSDavid van Moolenbroek 	memory_stats[2] = pagetok(realmem.freemem);
445*b89261baSDavid van Moolenbroek 	memory_stats[3] = tswap / 2;
446*b89261baSDavid van Moolenbroek 	memory_stats[4] = fswap / 2;
447*b89261baSDavid van Moolenbroek 
448*b89261baSDavid van Moolenbroek 	if (sysmp(MP_SAGET,MPSA_SINFO, &sysinfo,sizeof(struct sysinfo)) == -1) {
449*b89261baSDavid van Moolenbroek 		perror("sysmp(MP_SAGET,MPSA_SINFO)");
450*b89261baSDavid van Moolenbroek 		return;
451*b89261baSDavid van Moolenbroek 	}
452*b89261baSDavid van Moolenbroek 	(void) percentages(CPU_STATES, cpu_states, sysinfo.cpu, cp_old, cp_diff);
453*b89261baSDavid van Moolenbroek 
454*b89261baSDavid van Moolenbroek 	si->cpustates = cpu_states;
455*b89261baSDavid van Moolenbroek 	si->memory = memory_stats;
456*b89261baSDavid van Moolenbroek 	si->last_pid = -1;
457*b89261baSDavid van Moolenbroek 
458*b89261baSDavid van Moolenbroek 	return;
459*b89261baSDavid van Moolenbroek }
460*b89261baSDavid van Moolenbroek 
461*b89261baSDavid van Moolenbroek caddr_t
get_process_info(struct system_info * si,struct process_select * sel,int compare_index)462*b89261baSDavid van Moolenbroek get_process_info(struct system_info *si, struct process_select *sel, int compare_index)
463*b89261baSDavid van Moolenbroek 
464*b89261baSDavid van Moolenbroek {
465*b89261baSDavid van Moolenbroek 	int		i, total_procs, active_procs;
466*b89261baSDavid van Moolenbroek 	struct prpsinfo	**prefp;
467*b89261baSDavid van Moolenbroek 	struct prpsinfo	*pp;
468*b89261baSDavid van Moolenbroek 	int		show_uid;
469*b89261baSDavid van Moolenbroek 	static char	first_screen = 1;
470*b89261baSDavid van Moolenbroek 
471*b89261baSDavid van Moolenbroek 	/* read all the proc structures */
472*b89261baSDavid van Moolenbroek 	getptable(pbase);
473*b89261baSDavid van Moolenbroek 
474*b89261baSDavid van Moolenbroek 	/* get a pointer to the states summary array */
475*b89261baSDavid van Moolenbroek 	si->procstates = process_states;
476*b89261baSDavid van Moolenbroek 
477*b89261baSDavid van Moolenbroek 	/* set up flags which define what we are going to select */
478*b89261baSDavid van Moolenbroek 	show_uid = sel->uid != -1;
479*b89261baSDavid van Moolenbroek 
480*b89261baSDavid van Moolenbroek 	/* count up process states and get pointers to interesting procs */
481*b89261baSDavid van Moolenbroek 	total_procs = 0;
482*b89261baSDavid van Moolenbroek 	active_procs = 0;
483*b89261baSDavid van Moolenbroek 	(void) memset(process_states, 0, sizeof(process_states));
484*b89261baSDavid van Moolenbroek 	prefp = pref;
485*b89261baSDavid van Moolenbroek 
486*b89261baSDavid van Moolenbroek 	for (pp = pbase, i = 0; i < nproc; pp++, i++) {
487*b89261baSDavid van Moolenbroek 		/*
488*b89261baSDavid van Moolenbroek 		 * Place pointers to each valid proc structure in pref[].
489*b89261baSDavid van Moolenbroek 		 * Process slots that are actually in use have a non-zero
490*b89261baSDavid van Moolenbroek 		 * status field.  Processes with SSYS set are system
491*b89261baSDavid van Moolenbroek 		 * processes---these get ignored unless show_system is set.
492*b89261baSDavid van Moolenbroek 		 * Ariel: IRIX 6.4 had to redefine "system processes"
493*b89261baSDavid van Moolenbroek 		 * They do not exist outside the kernel in new kernels.
494*b89261baSDavid van Moolenbroek 		 * Now defining as uid==0 and ppid==1 (init children)
495*b89261baSDavid van Moolenbroek 		 */
496*b89261baSDavid van Moolenbroek 		if (pp->pr_state &&
497*b89261baSDavid van Moolenbroek 			(sel->system || !(pp->pr_uid==0 && pp->pr_ppid==1))) {
498*b89261baSDavid van Moolenbroek 			total_procs++;
499*b89261baSDavid van Moolenbroek 			process_states[proc_state(pp)]++;
500*b89261baSDavid van Moolenbroek 			/*
501*b89261baSDavid van Moolenbroek 			 * zombies are actually interesting (to avoid)
502*b89261baSDavid van Moolenbroek 			 * although they are not active, so I leave them
503*b89261baSDavid van Moolenbroek 			 * displayed.
504*b89261baSDavid van Moolenbroek 			 */
505*b89261baSDavid van Moolenbroek 			if (/* (! pp->pr_zomb) && */
506*b89261baSDavid van Moolenbroek 			    (sel->idle || IS_ACTIVE(pp)) &&
507*b89261baSDavid van Moolenbroek 			    (! show_uid || pp->pr_uid == (uid_t) sel->uid)) {
508*b89261baSDavid van Moolenbroek 				*prefp++ = pp;
509*b89261baSDavid van Moolenbroek 				active_procs++;
510*b89261baSDavid van Moolenbroek 			}
511*b89261baSDavid van Moolenbroek 		}
512*b89261baSDavid van Moolenbroek 	}
513*b89261baSDavid van Moolenbroek 	first_screen = 0;
514*b89261baSDavid van Moolenbroek 
515*b89261baSDavid van Moolenbroek 	/* if requested, sort the "interesting" processes */
516*b89261baSDavid van Moolenbroek 	qsort((char *) pref, active_procs, sizeof(struct prpsinfo *),
517*b89261baSDavid van Moolenbroek 	      proc_compares[compare_index]);
518*b89261baSDavid van Moolenbroek 
519*b89261baSDavid van Moolenbroek 	/* remember active and total counts */
520*b89261baSDavid van Moolenbroek 	si->p_total = total_procs;
521*b89261baSDavid van Moolenbroek 	si->p_active = active_procs;
522*b89261baSDavid van Moolenbroek 
523*b89261baSDavid van Moolenbroek 	/* pass back a handle */
524*b89261baSDavid van Moolenbroek 	handle.next_proc = pref;
525*b89261baSDavid van Moolenbroek 	handle.remaining = active_procs;
526*b89261baSDavid van Moolenbroek 	return ((caddr_t) &handle);
527*b89261baSDavid van Moolenbroek }
528*b89261baSDavid van Moolenbroek 
529*b89261baSDavid van Moolenbroek /*
530*b89261baSDavid van Moolenbroek  * Added cpu_id to running processes, add 'ready' (to run) state
531*b89261baSDavid van Moolenbroek  */
532*b89261baSDavid van Moolenbroek static char *
format_state(struct prpsinfo * pp)533*b89261baSDavid van Moolenbroek format_state(struct prpsinfo *pp)
534*b89261baSDavid van Moolenbroek 
535*b89261baSDavid van Moolenbroek {
536*b89261baSDavid van Moolenbroek 	static char	state_str[16];
537*b89261baSDavid van Moolenbroek 	int		state = proc_state(pp);
538*b89261baSDavid van Moolenbroek 
539*b89261baSDavid van Moolenbroek 	if (state == S_RUNNING) {
540*b89261baSDavid van Moolenbroek 		/*
541*b89261baSDavid van Moolenbroek 		 * Alert: 6.2 (MP only?) binary incompatibility
542*b89261baSDavid van Moolenbroek 		 * pp->pr_sonproc apparently (?) has a different
543*b89261baSDavid van Moolenbroek 		 * offset on 6.2 machines... I've seen cases where
544*b89261baSDavid van Moolenbroek 		 * a 6.4 compiled top running on 6.2 printed
545*b89261baSDavid van Moolenbroek 		 * a garbage CPU-id. To be safe, I print the CPU-id
546*b89261baSDavid van Moolenbroek 		 * only if it falls within range [0..numcpus-1]
547*b89261baSDavid van Moolenbroek 		 */
548*b89261baSDavid van Moolenbroek 		sprintf(state_str, "run/%d", pp->pr_sonproc);
549*b89261baSDavid van Moolenbroek 		return state_str;
550*b89261baSDavid van Moolenbroek 	}
551*b89261baSDavid van Moolenbroek 
552*b89261baSDavid van Moolenbroek 	/* default */
553*b89261baSDavid van Moolenbroek 	return state_abbrev[state];
554*b89261baSDavid van Moolenbroek }
555*b89261baSDavid van Moolenbroek 
556*b89261baSDavid van Moolenbroek static char *
format_prio(struct prpsinfo * pp)557*b89261baSDavid van Moolenbroek format_prio(struct prpsinfo *pp)
558*b89261baSDavid van Moolenbroek 
559*b89261baSDavid van Moolenbroek {
560*b89261baSDavid van Moolenbroek     static char	prio_str[10];
561*b89261baSDavid van Moolenbroek 
562*b89261baSDavid van Moolenbroek     if (irix_ver < 6.4) {
563*b89261baSDavid van Moolenbroek 	/*
564*b89261baSDavid van Moolenbroek 	 * Note: this is _compiled_ on 6.x where x >= 4 but I would like
565*b89261baSDavid van Moolenbroek 	 * it to run on 6.2 6.3 as well (backward binary compatibility).
566*b89261baSDavid van Moolenbroek 	 * Scheduling is completely different between these IRIX versions
567*b89261baSDavid van Moolenbroek 	 * and some scheduling classes may even have different names.
568*b89261baSDavid van Moolenbroek 	 *
569*b89261baSDavid van Moolenbroek 	 * The solution: have more than one style of 'priority' depending
570*b89261baSDavid van Moolenbroek 	 * on the OS version.
571*b89261baSDavid van Moolenbroek 	 *
572*b89261baSDavid van Moolenbroek 	 * See npri(1) + nice(2) + realtime(5) for scheduling classes,
573*b89261baSDavid van Moolenbroek 	 * and priority values.
574*b89261baSDavid van Moolenbroek 	 */
575*b89261baSDavid van Moolenbroek 	if (pp->pr_pri <= NDPHIMIN)			/* real time? */
576*b89261baSDavid van Moolenbroek 		sprintf(prio_str, "+%d", pp->pr_pri);
577*b89261baSDavid van Moolenbroek 	else if (pp->pr_pri <= NDPNORMMIN)		/* normal interactive */
578*b89261baSDavid van Moolenbroek 		sprintf(prio_str, "%d", pp->pr_pri);
579*b89261baSDavid van Moolenbroek 	else						/* batch: low prio */
580*b89261baSDavid van Moolenbroek 		sprintf(prio_str, "b%d", pp->pr_pri);
581*b89261baSDavid van Moolenbroek 
582*b89261baSDavid van Moolenbroek     } else {
583*b89261baSDavid van Moolenbroek 
584*b89261baSDavid van Moolenbroek 	/* copied from Kostadis's code */
585*b89261baSDavid van Moolenbroek 
586*b89261baSDavid van Moolenbroek 	if (strcmp(pp->pr_clname, "RT") == 0)		/* real time */
587*b89261baSDavid van Moolenbroek 		sprintf(prio_str, "+%d", pp->pr_pri);
588*b89261baSDavid van Moolenbroek 	else if (strcmp(pp->pr_clname, "DL") == 0)	/* unsupported ? */
589*b89261baSDavid van Moolenbroek 		sprintf(prio_str, "d%d", pp->pr_pri);
590*b89261baSDavid van Moolenbroek 	else if (strcmp(pp->pr_clname, "GN") == 0)
591*b89261baSDavid van Moolenbroek 		sprintf(prio_str, "g%d", pp->pr_pri);
592*b89261baSDavid van Moolenbroek 	else if (strcmp(pp->pr_clname, "GB") == 0)
593*b89261baSDavid van Moolenbroek 		sprintf(prio_str, "p%d", pp->pr_pri);
594*b89261baSDavid van Moolenbroek 
595*b89261baSDavid van Moolenbroek 	else if (strcmp(pp->pr_clname, "WL") == 0)	/* weightless */
596*b89261baSDavid van Moolenbroek 		return "w";
597*b89261baSDavid van Moolenbroek 	else if (strcmp(pp->pr_clname, "BC") == 0)
598*b89261baSDavid van Moolenbroek 		return "bc";				/* batch critical */
599*b89261baSDavid van Moolenbroek 	else if (strcmp(pp->pr_clname, "B") == 0)
600*b89261baSDavid van Moolenbroek 		return "b";				/* batch */
601*b89261baSDavid van Moolenbroek 	else
602*b89261baSDavid van Moolenbroek 		sprintf(prio_str, "%d", pp->pr_pri);
603*b89261baSDavid van Moolenbroek     }
604*b89261baSDavid van Moolenbroek     return prio_str;
605*b89261baSDavid van Moolenbroek }
606*b89261baSDavid van Moolenbroek 
607*b89261baSDavid van Moolenbroek static double
clip_percent(double pct)608*b89261baSDavid van Moolenbroek clip_percent(double pct)
609*b89261baSDavid van Moolenbroek 
610*b89261baSDavid van Moolenbroek {
611*b89261baSDavid van Moolenbroek     if (pct < 0) {
612*b89261baSDavid van Moolenbroek 	return 0.0;
613*b89261baSDavid van Moolenbroek     } else if (pct >= 100) {
614*b89261baSDavid van Moolenbroek 	return 99.99;
615*b89261baSDavid van Moolenbroek     }
616*b89261baSDavid van Moolenbroek     return pct;
617*b89261baSDavid van Moolenbroek }
618*b89261baSDavid van Moolenbroek 
619*b89261baSDavid van Moolenbroek char *
format_next_process(caddr_t handle,char * (* get_userid)())620*b89261baSDavid van Moolenbroek format_next_process(caddr_t handle, char *(*get_userid)())
621*b89261baSDavid van Moolenbroek 
622*b89261baSDavid van Moolenbroek {
623*b89261baSDavid van Moolenbroek 	struct prpsinfo	*pp;
624*b89261baSDavid van Moolenbroek 	struct handle	*hp;
625*b89261baSDavid van Moolenbroek 	long		cputime;
626*b89261baSDavid van Moolenbroek 
627*b89261baSDavid van Moolenbroek 	/* find and remember the next proc structure */
628*b89261baSDavid van Moolenbroek 	hp = (struct handle *) handle;
629*b89261baSDavid van Moolenbroek 	pp = *(hp->next_proc++);
630*b89261baSDavid van Moolenbroek 	hp->remaining--;
631*b89261baSDavid van Moolenbroek 
632*b89261baSDavid van Moolenbroek 	/* get the process cpu usage since startup */
633*b89261baSDavid van Moolenbroek 	cputime = pp->pr_time.tv_sec;
634*b89261baSDavid van Moolenbroek 
635*b89261baSDavid van Moolenbroek 	/* format this entry */
636*b89261baSDavid van Moolenbroek 	sprintf(fmt,
637*b89261baSDavid van Moolenbroek 		Proc_format,
638*b89261baSDavid van Moolenbroek 		pp->pr_pid,
639*b89261baSDavid van Moolenbroek 		pp->pr_pgrp,
640*b89261baSDavid van Moolenbroek 		(*get_userid) (pp->pr_uid),
641*b89261baSDavid van Moolenbroek 		format_prio(pp),
642*b89261baSDavid van Moolenbroek 		format_k(pagetok(pp->pr_size)),
643*b89261baSDavid van Moolenbroek 		format_k(pagetok(pp->pr_rssize)),
644*b89261baSDavid van Moolenbroek 		format_state(pp),
645*b89261baSDavid van Moolenbroek 		format_time(cputime),
646*b89261baSDavid van Moolenbroek 		clip_percent(weighted_cpu(pp)),
647*b89261baSDavid van Moolenbroek 		clip_percent(percent_cpu(pp)),
648*b89261baSDavid van Moolenbroek 		printable(pp->pr_fname));
649*b89261baSDavid van Moolenbroek 
650*b89261baSDavid van Moolenbroek 	/* return the result */
651*b89261baSDavid van Moolenbroek 	return (fmt);
652*b89261baSDavid van Moolenbroek }
653*b89261baSDavid van Moolenbroek 
654*b89261baSDavid van Moolenbroek /*
655*b89261baSDavid van Moolenbroek  *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
656*b89261baSDavid van Moolenbroek  *	"offset" is the byte offset into the kernel for the desired value,
657*b89261baSDavid van Moolenbroek  *  	"ptr" points to a buffer into which the value is retrieved,
658*b89261baSDavid van Moolenbroek  *  	"size" is the size of the buffer (and the object to retrieve),
659*b89261baSDavid van Moolenbroek  *  	"refstr" is a reference string used when printing error meessages,
660*b89261baSDavid van Moolenbroek  *	    if "refstr" starts with a '!', then a failure on read will not
661*b89261baSDavid van Moolenbroek  *  	    be fatal (this may seem like a silly way to do things, but I
662*b89261baSDavid van Moolenbroek  *  	    really didn't want the overhead of another argument).
663*b89261baSDavid van Moolenbroek  *
664*b89261baSDavid van Moolenbroek  */
665*b89261baSDavid van Moolenbroek 
666*b89261baSDavid van Moolenbroek int
getkval(unsigned long offset,int * ptr,int size,char * refstr)667*b89261baSDavid van Moolenbroek getkval(unsigned long offset, int *ptr, int size, char *refstr)
668*b89261baSDavid van Moolenbroek 
669*b89261baSDavid van Moolenbroek {
670*b89261baSDavid van Moolenbroek 	if (lseek(kmem, (long) offset, SEEK_SET) == -1) {
671*b89261baSDavid van Moolenbroek 		if (*refstr == '!')
672*b89261baSDavid van Moolenbroek 			refstr++;
673*b89261baSDavid van Moolenbroek 		(void) fprintf(stderr, "%s: %s: lseek to %s: %s\n",
674*b89261baSDavid van Moolenbroek 				myname, KMEM, refstr, strerror(errno));
675*b89261baSDavid van Moolenbroek 		exit(0);
676*b89261baSDavid van Moolenbroek 	}
677*b89261baSDavid van Moolenbroek 	if (read(kmem, (char *) ptr, size) == -1) {
678*b89261baSDavid van Moolenbroek 		if (*refstr == '!')
679*b89261baSDavid van Moolenbroek 			return (0);
680*b89261baSDavid van Moolenbroek 		else {
681*b89261baSDavid van Moolenbroek 			(void) fprintf(stderr, "%s: %s: reading %s: %s\n",
682*b89261baSDavid van Moolenbroek 				myname, KMEM, refstr, strerror(errno));
683*b89261baSDavid van Moolenbroek 			exit(0);
684*b89261baSDavid van Moolenbroek 		}
685*b89261baSDavid van Moolenbroek 	}
686*b89261baSDavid van Moolenbroek 	return (1);
687*b89261baSDavid van Moolenbroek }
688*b89261baSDavid van Moolenbroek 
689*b89261baSDavid van Moolenbroek /*
690*b89261baSDavid van Moolenbroek  *  compare_K - comparison functions for "qsort"
691*b89261baSDavid van Moolenbroek  *	Compares the resource consumption of two processes using five
692*b89261baSDavid van Moolenbroek  *  	distinct keys.  The keys are:
693*b89261baSDavid van Moolenbroek  *  	percent cpu, cpu ticks, state, resident set size, total virtual
694*b89261baSDavid van Moolenbroek  *  	memory usage.  The process states are ordered as follows (from least
695*b89261baSDavid van Moolenbroek  *  	to most important):  WAIT, zombie, sleep, stop, idle, run.
696*b89261baSDavid van Moolenbroek  *  	Different comparison functions are used for different orderings.
697*b89261baSDavid van Moolenbroek  */
698*b89261baSDavid van Moolenbroek 
699*b89261baSDavid van Moolenbroek /* these are names given to allowed sorting orders -- first is default */
700*b89261baSDavid van Moolenbroek char *ordernames[] = {
701*b89261baSDavid van Moolenbroek 	/*
702*b89261baSDavid van Moolenbroek 	 * Aliases for user convenience/friendliness:
703*b89261baSDavid van Moolenbroek 	 *	mem == size
704*b89261baSDavid van Moolenbroek 	 *	rss == res
705*b89261baSDavid van Moolenbroek 	 */
706*b89261baSDavid van Moolenbroek 	"cpu", "size", "mem", "res", "rss",
707*b89261baSDavid van Moolenbroek 	"time", "state", "command", "prio", NULL
708*b89261baSDavid van Moolenbroek };
709*b89261baSDavid van Moolenbroek 
710*b89261baSDavid van Moolenbroek /* forward definitions for comparison functions */
711*b89261baSDavid van Moolenbroek int compare_cpu(struct prpsinfo **pp1, struct prpsinfo **pp2);
712*b89261baSDavid van Moolenbroek int compare_size(struct prpsinfo **pp1, struct prpsinfo **pp2);
713*b89261baSDavid van Moolenbroek int compare_res(struct prpsinfo **pp1, struct prpsinfo **pp2);
714*b89261baSDavid van Moolenbroek int compare_time(struct prpsinfo **pp1, struct prpsinfo **pp2);
715*b89261baSDavid van Moolenbroek int compare_state(struct prpsinfo **pp1, struct prpsinfo **pp2);
716*b89261baSDavid van Moolenbroek int compare_cmd(struct prpsinfo **pp1, struct prpsinfo **pp2);
717*b89261baSDavid van Moolenbroek int compare_prio(struct prpsinfo **pp1, struct prpsinfo **pp2);
718*b89261baSDavid van Moolenbroek 
719*b89261baSDavid van Moolenbroek int (*proc_compares[])() = {
720*b89261baSDavid van Moolenbroek 	compare_cpu,
721*b89261baSDavid van Moolenbroek 	compare_size,
722*b89261baSDavid van Moolenbroek 	compare_size,
723*b89261baSDavid van Moolenbroek 	compare_res,
724*b89261baSDavid van Moolenbroek 	compare_res,
725*b89261baSDavid van Moolenbroek 	compare_time,
726*b89261baSDavid van Moolenbroek 	compare_state,
727*b89261baSDavid van Moolenbroek 	compare_cmd,
728*b89261baSDavid van Moolenbroek 	compare_prio,
729*b89261baSDavid van Moolenbroek 	NULL
730*b89261baSDavid van Moolenbroek };
731*b89261baSDavid van Moolenbroek 
732*b89261baSDavid van Moolenbroek 
733*b89261baSDavid van Moolenbroek /*
734*b89261baSDavid van Moolenbroek  * The possible comparison expressions.  These are defined in such a way
735*b89261baSDavid van Moolenbroek  * that they can be merely listed in the source code to define the actual
736*b89261baSDavid van Moolenbroek  * desired ordering.
737*b89261baSDavid van Moolenbroek  */
738*b89261baSDavid van Moolenbroek 
739*b89261baSDavid van Moolenbroek #define ORDERKEY_PCTCPU	\
740*b89261baSDavid van Moolenbroek 	if (dresult = percent_cpu(p2) - percent_cpu(p1),\
741*b89261baSDavid van Moolenbroek 	(result = dresult > 0.0 ? 1 : dresult < 0.0 ? -1 : 0) == 0)
742*b89261baSDavid van Moolenbroek #define ORDERKEY_CPTICKS \
743*b89261baSDavid van Moolenbroek 	if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0)
744*b89261baSDavid van Moolenbroek #define ORDERKEY_STATE  if ((result = proc_state(p2) - proc_state(p1)) == 0)
745*b89261baSDavid van Moolenbroek #define ORDERKEY_PRIO	if ((result = p2->pr_oldpri - p1->pr_oldpri) == 0)
746*b89261baSDavid van Moolenbroek #define ORDERKEY_RSSIZE	if ((result = p2->pr_rssize - p1->pr_rssize) == 0)
747*b89261baSDavid van Moolenbroek #define ORDERKEY_MEM	if ((result = (p2->pr_size - p1->pr_size)) == 0)
748*b89261baSDavid van Moolenbroek #define ORDERKEY_CMD	if ((result = strcmp(p1->pr_fname,p2->pr_fname)) == 0)
749*b89261baSDavid van Moolenbroek 
compare_cpu(struct prpsinfo ** pp1,struct prpsinfo ** pp2)750*b89261baSDavid van Moolenbroek int compare_cpu(struct prpsinfo **pp1, struct prpsinfo **pp2)
751*b89261baSDavid van Moolenbroek {
752*b89261baSDavid van Moolenbroek 	struct prpsinfo	*p1, *p2;
753*b89261baSDavid van Moolenbroek 	int		result;
754*b89261baSDavid van Moolenbroek 	double		dresult;
755*b89261baSDavid van Moolenbroek 
756*b89261baSDavid van Moolenbroek 	/* remove one level of indirection */
757*b89261baSDavid van Moolenbroek 	p1 = *pp1;
758*b89261baSDavid van Moolenbroek 	p2 = *pp2;
759*b89261baSDavid van Moolenbroek 	/*
760*b89261baSDavid van Moolenbroek 	 * order by various keys, resorting to the next one
761*b89261baSDavid van Moolenbroek 	 * whenever there's a tie in comparisons
762*b89261baSDavid van Moolenbroek 	 */
763*b89261baSDavid van Moolenbroek 	ORDERKEY_PCTCPU
764*b89261baSDavid van Moolenbroek 	ORDERKEY_CPTICKS
765*b89261baSDavid van Moolenbroek 	ORDERKEY_STATE
766*b89261baSDavid van Moolenbroek 	ORDERKEY_PRIO
767*b89261baSDavid van Moolenbroek 	ORDERKEY_RSSIZE
768*b89261baSDavid van Moolenbroek 	ORDERKEY_MEM
769*b89261baSDavid van Moolenbroek 	;
770*b89261baSDavid van Moolenbroek 	return (result);
771*b89261baSDavid van Moolenbroek }
772*b89261baSDavid van Moolenbroek 
compare_size(struct prpsinfo ** pp1,struct prpsinfo ** pp2)773*b89261baSDavid van Moolenbroek int compare_size(struct prpsinfo **pp1, struct prpsinfo **pp2)
774*b89261baSDavid van Moolenbroek {
775*b89261baSDavid van Moolenbroek 	struct prpsinfo	*p1, *p2;
776*b89261baSDavid van Moolenbroek 	int		result;
777*b89261baSDavid van Moolenbroek 	double		dresult;
778*b89261baSDavid van Moolenbroek 
779*b89261baSDavid van Moolenbroek 	/* remove one level of indirection */
780*b89261baSDavid van Moolenbroek 	p1 = *pp1;
781*b89261baSDavid van Moolenbroek 	p2 = *pp2;
782*b89261baSDavid van Moolenbroek 	/*
783*b89261baSDavid van Moolenbroek 	 * order by various keys, resorting to the next one
784*b89261baSDavid van Moolenbroek 	 * whenever there's a tie in comparisons
785*b89261baSDavid van Moolenbroek 	 */
786*b89261baSDavid van Moolenbroek 	ORDERKEY_MEM
787*b89261baSDavid van Moolenbroek 	ORDERKEY_RSSIZE
788*b89261baSDavid van Moolenbroek 	ORDERKEY_PCTCPU
789*b89261baSDavid van Moolenbroek 	ORDERKEY_CPTICKS
790*b89261baSDavid van Moolenbroek 	ORDERKEY_STATE
791*b89261baSDavid van Moolenbroek 	ORDERKEY_PRIO
792*b89261baSDavid van Moolenbroek 	;
793*b89261baSDavid van Moolenbroek 	return (result);
794*b89261baSDavid van Moolenbroek }
795*b89261baSDavid van Moolenbroek 
compare_res(struct prpsinfo ** pp1,struct prpsinfo ** pp2)796*b89261baSDavid van Moolenbroek int compare_res(struct prpsinfo **pp1, struct prpsinfo **pp2)
797*b89261baSDavid van Moolenbroek {
798*b89261baSDavid van Moolenbroek 	struct prpsinfo	*p1, *p2;
799*b89261baSDavid van Moolenbroek 	int		result;
800*b89261baSDavid van Moolenbroek 	double		dresult;
801*b89261baSDavid van Moolenbroek 
802*b89261baSDavid van Moolenbroek 	/* remove one level of indirection */
803*b89261baSDavid van Moolenbroek 	p1 = *pp1;
804*b89261baSDavid van Moolenbroek 	p2 = *pp2;
805*b89261baSDavid van Moolenbroek 	/*
806*b89261baSDavid van Moolenbroek 	 * order by various keys, resorting to the next one
807*b89261baSDavid van Moolenbroek 	 * whenever there's a tie in comparisons
808*b89261baSDavid van Moolenbroek 	 */
809*b89261baSDavid van Moolenbroek 	ORDERKEY_RSSIZE
810*b89261baSDavid van Moolenbroek 	ORDERKEY_MEM
811*b89261baSDavid van Moolenbroek 	ORDERKEY_PCTCPU
812*b89261baSDavid van Moolenbroek 	ORDERKEY_CPTICKS
813*b89261baSDavid van Moolenbroek 	ORDERKEY_STATE
814*b89261baSDavid van Moolenbroek 	ORDERKEY_PRIO
815*b89261baSDavid van Moolenbroek 	;
816*b89261baSDavid van Moolenbroek 	return (result);
817*b89261baSDavid van Moolenbroek }
818*b89261baSDavid van Moolenbroek 
compare_time(struct prpsinfo ** pp1,struct prpsinfo ** pp2)819*b89261baSDavid van Moolenbroek int compare_time(struct prpsinfo **pp1, struct prpsinfo **pp2)
820*b89261baSDavid van Moolenbroek {
821*b89261baSDavid van Moolenbroek 	struct prpsinfo	*p1, *p2;
822*b89261baSDavid van Moolenbroek 	int		result;
823*b89261baSDavid van Moolenbroek 	double		dresult;
824*b89261baSDavid van Moolenbroek 
825*b89261baSDavid van Moolenbroek 	/* remove one level of indirection */
826*b89261baSDavid van Moolenbroek 	p1 = *pp1;
827*b89261baSDavid van Moolenbroek 	p2 = *pp2;
828*b89261baSDavid van Moolenbroek 	/*
829*b89261baSDavid van Moolenbroek 	 * order by various keys, resorting to the next one
830*b89261baSDavid van Moolenbroek 	 * whenever there's a tie in comparisons
831*b89261baSDavid van Moolenbroek 	 */
832*b89261baSDavid van Moolenbroek 	ORDERKEY_CPTICKS
833*b89261baSDavid van Moolenbroek 	ORDERKEY_RSSIZE
834*b89261baSDavid van Moolenbroek 	ORDERKEY_MEM
835*b89261baSDavid van Moolenbroek 	ORDERKEY_PCTCPU
836*b89261baSDavid van Moolenbroek 	ORDERKEY_STATE
837*b89261baSDavid van Moolenbroek 	ORDERKEY_PRIO
838*b89261baSDavid van Moolenbroek 	;
839*b89261baSDavid van Moolenbroek 	return (result);
840*b89261baSDavid van Moolenbroek }
841*b89261baSDavid van Moolenbroek 
compare_cmd(struct prpsinfo ** pp1,struct prpsinfo ** pp2)842*b89261baSDavid van Moolenbroek int compare_cmd(struct prpsinfo **pp1, struct prpsinfo **pp2)
843*b89261baSDavid van Moolenbroek {
844*b89261baSDavid van Moolenbroek 	struct prpsinfo	*p1, *p2;
845*b89261baSDavid van Moolenbroek 	int		result;
846*b89261baSDavid van Moolenbroek 	double		dresult;
847*b89261baSDavid van Moolenbroek 
848*b89261baSDavid van Moolenbroek 	/* remove one level of indirection */
849*b89261baSDavid van Moolenbroek 	p1 = *pp1;
850*b89261baSDavid van Moolenbroek 	p2 = *pp2;
851*b89261baSDavid van Moolenbroek 	/*
852*b89261baSDavid van Moolenbroek 	 * order by various keys, resorting to the next one
853*b89261baSDavid van Moolenbroek 	 * whenever there's a tie in comparisons
854*b89261baSDavid van Moolenbroek 	 */
855*b89261baSDavid van Moolenbroek 	ORDERKEY_CMD
856*b89261baSDavid van Moolenbroek 	ORDERKEY_PCTCPU
857*b89261baSDavid van Moolenbroek 	ORDERKEY_CPTICKS
858*b89261baSDavid van Moolenbroek 	ORDERKEY_RSSIZE
859*b89261baSDavid van Moolenbroek 	;
860*b89261baSDavid van Moolenbroek 	return (result);
861*b89261baSDavid van Moolenbroek }
862*b89261baSDavid van Moolenbroek 
compare_state(struct prpsinfo ** pp1,struct prpsinfo ** pp2)863*b89261baSDavid van Moolenbroek int compare_state(struct prpsinfo **pp1, struct prpsinfo **pp2)
864*b89261baSDavid van Moolenbroek {
865*b89261baSDavid van Moolenbroek 	struct prpsinfo	*p1, *p2;
866*b89261baSDavid van Moolenbroek 	int		result;
867*b89261baSDavid van Moolenbroek 	double		dresult;
868*b89261baSDavid van Moolenbroek 
869*b89261baSDavid van Moolenbroek 	/* remove one level of indirection */
870*b89261baSDavid van Moolenbroek 	p1 = *pp1;
871*b89261baSDavid van Moolenbroek 	p2 = *pp2;
872*b89261baSDavid van Moolenbroek 	/*
873*b89261baSDavid van Moolenbroek 	 * order by various keys, resorting to the next one
874*b89261baSDavid van Moolenbroek 	 * whenever there's a tie in comparisons
875*b89261baSDavid van Moolenbroek 	 */
876*b89261baSDavid van Moolenbroek 	ORDERKEY_STATE
877*b89261baSDavid van Moolenbroek 	ORDERKEY_PCTCPU
878*b89261baSDavid van Moolenbroek 	ORDERKEY_CPTICKS
879*b89261baSDavid van Moolenbroek 	ORDERKEY_RSSIZE
880*b89261baSDavid van Moolenbroek 	;
881*b89261baSDavid van Moolenbroek 	return (result);
882*b89261baSDavid van Moolenbroek }
883*b89261baSDavid van Moolenbroek 
compare_prio(struct prpsinfo ** pp1,struct prpsinfo ** pp2)884*b89261baSDavid van Moolenbroek int compare_prio(struct prpsinfo **pp1, struct prpsinfo **pp2)
885*b89261baSDavid van Moolenbroek {
886*b89261baSDavid van Moolenbroek 	struct prpsinfo	*p1, *p2;
887*b89261baSDavid van Moolenbroek 	int		result;
888*b89261baSDavid van Moolenbroek 	double		dresult;
889*b89261baSDavid van Moolenbroek 
890*b89261baSDavid van Moolenbroek 	/* remove one level of indirection */
891*b89261baSDavid van Moolenbroek 	p1 = *pp1;
892*b89261baSDavid van Moolenbroek 	p2 = *pp2;
893*b89261baSDavid van Moolenbroek 	/*
894*b89261baSDavid van Moolenbroek 	 * order by various keys, resorting to the next one
895*b89261baSDavid van Moolenbroek 	 * whenever there's a tie in comparisons
896*b89261baSDavid van Moolenbroek 	 */
897*b89261baSDavid van Moolenbroek 	ORDERKEY_PRIO
898*b89261baSDavid van Moolenbroek 	ORDERKEY_PCTCPU
899*b89261baSDavid van Moolenbroek 	;
900*b89261baSDavid van Moolenbroek 	return (result);
901*b89261baSDavid van Moolenbroek }
902*b89261baSDavid van Moolenbroek 
903*b89261baSDavid van Moolenbroek 
904*b89261baSDavid van Moolenbroek 
905*b89261baSDavid van Moolenbroek /* return the owner of the specified process. */
906*b89261baSDavid van Moolenbroek uid_t
proc_owner(pid_t pid)907*b89261baSDavid van Moolenbroek proc_owner(pid_t pid)
908*b89261baSDavid van Moolenbroek 
909*b89261baSDavid van Moolenbroek {
910*b89261baSDavid van Moolenbroek 	register struct prpsinfo *p;
911*b89261baSDavid van Moolenbroek 	int     i;
912*b89261baSDavid van Moolenbroek 
913*b89261baSDavid van Moolenbroek 	for (i = 0, p = pbase; i < nproc; i++, p++)
914*b89261baSDavid van Moolenbroek 		if (p->pr_pid == pid)
915*b89261baSDavid van Moolenbroek 			return (p->pr_uid);
916*b89261baSDavid van Moolenbroek 
917*b89261baSDavid van Moolenbroek 	return (-1);
918*b89261baSDavid van Moolenbroek }
919*b89261baSDavid van Moolenbroek 
920*b89261baSDavid van Moolenbroek #ifdef DO_MAPSIZE
921*b89261baSDavid van Moolenbroek static void
size(int fd,struct prpsinfo * ps)922*b89261baSDavid van Moolenbroek size(int fd, struct prpsinfo *ps)
923*b89261baSDavid van Moolenbroek 
924*b89261baSDavid van Moolenbroek {
925*b89261baSDavid van Moolenbroek 	prmap_sgi_arg_t maparg;
926*b89261baSDavid van Moolenbroek 	struct prmap_sgi maps[256];
927*b89261baSDavid van Moolenbroek 	int	nmaps;
928*b89261baSDavid van Moolenbroek 	double	sz;
929*b89261baSDavid van Moolenbroek 	int	i;
930*b89261baSDavid van Moolenbroek 
931*b89261baSDavid van Moolenbroek 	maparg.pr_vaddr = (caddr_t) maps;
932*b89261baSDavid van Moolenbroek 	maparg.pr_size = sizeof maps;
933*b89261baSDavid van Moolenbroek 	if ((nmaps = ioctl(fd, PIOCMAP_SGI, &maparg)) == -1) {
934*b89261baSDavid van Moolenbroek 		/* XXX - this will be confusing */
935*b89261baSDavid van Moolenbroek 		return;
936*b89261baSDavid van Moolenbroek 	}
937*b89261baSDavid van Moolenbroek 	for (i = 0, sz = 0; i < nmaps; ++i) {
938*b89261baSDavid van Moolenbroek 		sz += (double) maps[i].pr_wsize / MA_WSIZE_FRAC;
939*b89261baSDavid van Moolenbroek 	}
940*b89261baSDavid van Moolenbroek 	ps->pr_rssize = (long) sz;
941*b89261baSDavid van Moolenbroek }
942*b89261baSDavid van Moolenbroek #endif
943*b89261baSDavid van Moolenbroek 
944*b89261baSDavid van Moolenbroek /* get process table */
945*b89261baSDavid van Moolenbroek void
getptable(struct prpsinfo * baseptr)946*b89261baSDavid van Moolenbroek getptable(struct prpsinfo *baseptr)
947*b89261baSDavid van Moolenbroek 
948*b89261baSDavid van Moolenbroek {
949*b89261baSDavid van Moolenbroek 	struct prpsinfo		*currproc; /* ptr to current proc struct */
950*b89261baSDavid van Moolenbroek 	int			i, numprocs;
951*b89261baSDavid van Moolenbroek 	struct dirent		*direntp;
952*b89261baSDavid van Moolenbroek 	struct oldproc		*op, *endbase;
953*b89261baSDavid van Moolenbroek 	static struct timeval	lasttime, thistime;
954*b89261baSDavid van Moolenbroek 	static double		timediff, alpha, beta;
955*b89261baSDavid van Moolenbroek 
956*b89261baSDavid van Moolenbroek 	/* measure time between last call to getptable and current call */
957*b89261baSDavid van Moolenbroek 	gettimeofday (&thistime, NULL);
958*b89261baSDavid van Moolenbroek 
959*b89261baSDavid van Moolenbroek 	/*
960*b89261baSDavid van Moolenbroek 	 * To avoid divides, we keep times in nanoseconds.  This is
961*b89261baSDavid van Moolenbroek 	 * scaled by 1e7 rather than 1e9 so that when we divide we
962*b89261baSDavid van Moolenbroek 	 * get percent.
963*b89261baSDavid van Moolenbroek 	 */
964*b89261baSDavid van Moolenbroek 	timediff = ((double) thistime.tv_sec  * 1.0e7 -
965*b89261baSDavid van Moolenbroek 		    (double) lasttime.tv_sec  * 1.0e7)
966*b89261baSDavid van Moolenbroek 				+
967*b89261baSDavid van Moolenbroek 		   ((double) thistime.tv_usec * 10 -
968*b89261baSDavid van Moolenbroek 		    (double) lasttime.tv_usec * 10);
969*b89261baSDavid van Moolenbroek 
970*b89261baSDavid van Moolenbroek 	/*
971*b89261baSDavid van Moolenbroek 	 * Under extreme load conditions, sca has experienced
972*b89261baSDavid van Moolenbroek 	 * an assert(timediff > 0) failure here. His guess is that
973*b89261baSDavid van Moolenbroek 	 * sometimes timed resets the time backwards and gettimeofday
974*b89261baSDavid van Moolenbroek 	 * returns a lower number on a later call.
975*b89261baSDavid van Moolenbroek 	 * To be on the safe side I fix it here by setting timediff
976*b89261baSDavid van Moolenbroek 	 * to some arbitrary small value (in nanoseconds).
977*b89261baSDavid van Moolenbroek 	 */
978*b89261baSDavid van Moolenbroek 	if (timediff <= 0.0) timediff = 100.0;
979*b89261baSDavid van Moolenbroek 
980*b89261baSDavid van Moolenbroek 	lasttime = thistime;	/* prepare for next round */
981*b89261baSDavid van Moolenbroek 
982*b89261baSDavid van Moolenbroek 	/*
983*b89261baSDavid van Moolenbroek 	 * constants for exponential decaying average.
984*b89261baSDavid van Moolenbroek 	 *	avg = alpha * new + beta * avg
985*b89261baSDavid van Moolenbroek 	 * The goal is 50% decay in 30 sec.  However if the sample period
986*b89261baSDavid van Moolenbroek 	 * is greater than 30 sec, there's not a lot we can do.
987*b89261baSDavid van Moolenbroek 	 */
988*b89261baSDavid van Moolenbroek 	if (timediff < 30.0e7) {
989*b89261baSDavid van Moolenbroek 		alpha = 0.5 * (timediff / 15.0e7);
990*b89261baSDavid van Moolenbroek 		beta = 1.0 - alpha;
991*b89261baSDavid van Moolenbroek 	} else {
992*b89261baSDavid van Moolenbroek 		alpha = 0.5;
993*b89261baSDavid van Moolenbroek 		beta = 0.5;
994*b89261baSDavid van Moolenbroek 	}
995*b89261baSDavid van Moolenbroek 	assert(alpha >= 0); assert(alpha <= 1);
996*b89261baSDavid van Moolenbroek 	assert(beta >= 0); assert(beta <= 1);
997*b89261baSDavid van Moolenbroek 
998*b89261baSDavid van Moolenbroek 	endbase = oldbase + oldprocs;
999*b89261baSDavid van Moolenbroek 	currproc = baseptr;
1000*b89261baSDavid van Moolenbroek 
1001*b89261baSDavid van Moolenbroek 	for (numprocs = 0, rewinddir(procdir); direntp = readdir(procdir);) {
1002*b89261baSDavid van Moolenbroek 		int     fd;
1003*b89261baSDavid van Moolenbroek 
1004*b89261baSDavid van Moolenbroek 		if ((fd = open(direntp->d_name, O_RDONLY)) < 0)
1005*b89261baSDavid van Moolenbroek 			continue;
1006*b89261baSDavid van Moolenbroek 
1007*b89261baSDavid van Moolenbroek 		currproc = baseptr + numprocs;
1008*b89261baSDavid van Moolenbroek 
1009*b89261baSDavid van Moolenbroek 		if (ioctl(fd, PIOCPSINFO, currproc) < 0) {
1010*b89261baSDavid van Moolenbroek 			(void) close(fd);
1011*b89261baSDavid van Moolenbroek 			continue;
1012*b89261baSDavid van Moolenbroek 		}
1013*b89261baSDavid van Moolenbroek 
1014*b89261baSDavid van Moolenbroek 		/*
1015*b89261baSDavid van Moolenbroek 		 * SVR4 doesn't keep track of CPU% in the kernel,
1016*b89261baSDavid van Moolenbroek 		 * so we have to do our own.
1017*b89261baSDavid van Moolenbroek 		 * See if we've heard of this process before.
1018*b89261baSDavid van Moolenbroek 		 * If so, compute % based on CPU since last time.
1019*b89261baSDavid van Moolenbroek 		 */
1020*b89261baSDavid van Moolenbroek 		op = oldbase + HASH (currproc->pr_pid);
1021*b89261baSDavid van Moolenbroek 		for (;;) {
1022*b89261baSDavid van Moolenbroek 			if (op->oldpid == -1) /* not there */
1023*b89261baSDavid van Moolenbroek 				break;
1024*b89261baSDavid van Moolenbroek 			if (op->oldpid == currproc->pr_pid) {
1025*b89261baSDavid van Moolenbroek 				/* found old data */
1026*b89261baSDavid van Moolenbroek 				percent_cpu(currproc) =
1027*b89261baSDavid van Moolenbroek 					((currproc->pr_time.tv_sec * 1.0e9 +
1028*b89261baSDavid van Moolenbroek 					currproc->pr_time.tv_nsec)
1029*b89261baSDavid van Moolenbroek 					- op->oldtime) / timediff;
1030*b89261baSDavid van Moolenbroek 
1031*b89261baSDavid van Moolenbroek 				weighted_cpu(currproc) =
1032*b89261baSDavid van Moolenbroek 					op->oldpct * beta +
1033*b89261baSDavid van Moolenbroek 					percent_cpu(currproc) * alpha;
1034*b89261baSDavid van Moolenbroek 
1035*b89261baSDavid van Moolenbroek 				break;
1036*b89261baSDavid van Moolenbroek 			}
1037*b89261baSDavid van Moolenbroek 			op++;		/* try next entry in hash table */
1038*b89261baSDavid van Moolenbroek 			if (op == endbase)    /* table wrap around */
1039*b89261baSDavid van Moolenbroek 				op = oldbase;
1040*b89261baSDavid van Moolenbroek 		}
1041*b89261baSDavid van Moolenbroek 
1042*b89261baSDavid van Moolenbroek 		/* Otherwise, it's new, so use all of its CPU time */
1043*b89261baSDavid van Moolenbroek 		if (op->oldpid == -1) {
1044*b89261baSDavid van Moolenbroek 			if (lasttime.tv_sec) {
1045*b89261baSDavid van Moolenbroek 				percent_cpu(currproc) =
1046*b89261baSDavid van Moolenbroek 					(currproc->pr_time.tv_sec * 1.0e9 +
1047*b89261baSDavid van Moolenbroek 					currproc->pr_time.tv_nsec) / timediff;
1048*b89261baSDavid van Moolenbroek 
1049*b89261baSDavid van Moolenbroek 				weighted_cpu(currproc) = percent_cpu(currproc);
1050*b89261baSDavid van Moolenbroek 			} else {
1051*b89261baSDavid van Moolenbroek 				/* first screen -- no difference is possible */
1052*b89261baSDavid van Moolenbroek 				percent_cpu(currproc) = 0.0;
1053*b89261baSDavid van Moolenbroek 				weighted_cpu(currproc) = 0.0;
1054*b89261baSDavid van Moolenbroek 			}
1055*b89261baSDavid van Moolenbroek 		}
1056*b89261baSDavid van Moolenbroek 
1057*b89261baSDavid van Moolenbroek #ifdef DO_MAPSIZE
1058*b89261baSDavid van Moolenbroek 		size(fd, currproc);
1059*b89261baSDavid van Moolenbroek #endif
1060*b89261baSDavid van Moolenbroek 		numprocs++;
1061*b89261baSDavid van Moolenbroek 		(void) close(fd);
1062*b89261baSDavid van Moolenbroek 
1063*b89261baSDavid van Moolenbroek 		/*
1064*b89261baSDavid van Moolenbroek 		 * Bug: in case process count grew so dramatically
1065*b89261baSDavid van Moolenbroek 		 * as to exceed to table size. We give up on a full scan.
1066*b89261baSDavid van Moolenbroek 		 * the chances of this to happen are extremely slim due to
1067*b89261baSDavid van Moolenbroek 		 * the big factor we're using. getting nproc from nlist
1068*b89261baSDavid van Moolenbroek 		 * is not worth the headache. realloc wouldn't work either
1069*b89261baSDavid van Moolenbroek 		 * because we have pointers to the proc table so we cannot
1070*b89261baSDavid van Moolenbroek 		 * move it around.
1071*b89261baSDavid van Moolenbroek 		 */
1072*b89261baSDavid van Moolenbroek 		if (numprocs >= ptable_size) {
1073*b89261baSDavid van Moolenbroek 			fprintf(stderr,
1074*b89261baSDavid van Moolenbroek 				"preallocated proc table size (%d) exceeded, "
1075*b89261baSDavid van Moolenbroek 				"skipping some processes\n", ptable_size);
1076*b89261baSDavid van Moolenbroek 			break;
1077*b89261baSDavid van Moolenbroek 		}
1078*b89261baSDavid van Moolenbroek 	}
1079*b89261baSDavid van Moolenbroek 	nproc = numprocs;
1080*b89261baSDavid van Moolenbroek 
1081*b89261baSDavid van Moolenbroek 	/*
1082*b89261baSDavid van Moolenbroek 	 * Save current CPU time for next time around
1083*b89261baSDavid van Moolenbroek 	 * For the moment recreate the hash table each time, as the code
1084*b89261baSDavid van Moolenbroek 	 * is easier that way.
1085*b89261baSDavid van Moolenbroek 	 */
1086*b89261baSDavid van Moolenbroek 	oldprocs = 2 * nproc;
1087*b89261baSDavid van Moolenbroek 	endbase = oldbase + oldprocs;
1088*b89261baSDavid van Moolenbroek 
1089*b89261baSDavid van Moolenbroek 	for (op = oldbase; op < endbase; op++)
1090*b89261baSDavid van Moolenbroek 		op->oldpid = -1;
1091*b89261baSDavid van Moolenbroek 
1092*b89261baSDavid van Moolenbroek 	for (i = 0, currproc = baseptr; i < nproc; i++, currproc++) {
1093*b89261baSDavid van Moolenbroek 
1094*b89261baSDavid van Moolenbroek 		/* find an empty spot */
1095*b89261baSDavid van Moolenbroek 		op = oldbase + HASH (currproc->pr_pid);
1096*b89261baSDavid van Moolenbroek 		for (;;) {
1097*b89261baSDavid van Moolenbroek 			if (op->oldpid == -1)
1098*b89261baSDavid van Moolenbroek 				break;
1099*b89261baSDavid van Moolenbroek 			op++;
1100*b89261baSDavid van Moolenbroek 			if (op == endbase)
1101*b89261baSDavid van Moolenbroek 				op = oldbase;
1102*b89261baSDavid van Moolenbroek         	}
1103*b89261baSDavid van Moolenbroek 		op->oldpid = currproc->pr_pid;
1104*b89261baSDavid van Moolenbroek 		op->oldtime = (currproc->pr_time.tv_sec * 1.0e9 +
1105*b89261baSDavid van Moolenbroek 				currproc->pr_time.tv_nsec);
1106*b89261baSDavid van Moolenbroek 		op->oldpct = weighted_cpu(currproc);
1107*b89261baSDavid van Moolenbroek 	}
1108*b89261baSDavid van Moolenbroek }
1109*b89261baSDavid van Moolenbroek 
1110