machine.c revision 159520
1233294Sstas/*
2102644Snectar * top - a top users display for Unix
355682Smarkm *
4142403Snectar * SYNOPSIS:  For FreeBSD-2.x and later
5233294Sstas *
6233294Sstas * DESCRIPTION:
755682Smarkm * Originally written for BSD4.4 system by Christos Zoulas.
855682Smarkm * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider
955682Smarkm * Order support hacked in from top-3.5beta6/machine/m_aix41.c
1055682Smarkm *   by Monte Mitzelfelt (for latest top see http://www.groupsys.com/topinfo/)
1155682Smarkm *
1255682Smarkm * This is the machine-dependent module for FreeBSD 2.2
1355682Smarkm * Works for:
1455682Smarkm *	FreeBSD 2.2.x, 3.x, 4.x, and probably FreeBSD 2.1.x
1555682Smarkm *
1690926Snectar * LIBS: -lkvm
1790926Snectar *
18233294Sstas * AUTHOR:  Christos Zoulas <christos@ee.cornell.edu>
1990926Snectar *          Steven Wallace  <swallace@freebsd.org>
20233294Sstas *          Wolfram Schneider <wosch@FreeBSD.org>
2190926Snectar *          Thomas Moestl <tmoestl@gmx.net>
22233294Sstas *
2355682Smarkm * $FreeBSD: head/usr.bin/top/machine.c 159520 2006-06-11 19:18:39Z se $
2455682Smarkm */
2555682Smarkm
26233294Sstas#include <sys/param.h>
2755682Smarkm#include <sys/errno.h>
28233294Sstas#include <sys/file.h>
29102644Snectar#include <sys/proc.h>
30102644Snectar#include <sys/resource.h>
31102644Snectar#include <sys/rtprio.h>
32127808Snectar#include <sys/signal.h>
3390926Snectar#include <sys/sysctl.h>
34127808Snectar#include <sys/time.h>
3555682Smarkm#include <sys/user.h>
3655682Smarkm#include <sys/vmmeter.h>
3755682Smarkm
3855682Smarkm#include <kvm.h>
3955682Smarkm#include <math.h>
4055682Smarkm#include <nlist.h>
41178825Sdfr#include <paths.h>
4255682Smarkm#include <pwd.h>
43142403Snectar#include <stdio.h>
44142403Snectar#include <stdlib.h>
45142403Snectar#include <string.h>
46233294Sstas#include <strings.h>
47233294Sstas#include <unistd.h>
48178825Sdfr
49142403Snectar#include "top.h"
50233294Sstas#include "machine.h"
51142403Snectar#include "screen.h"
52142403Snectar#include "utils.h"
53142403Snectar
54233294Sstas#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
55142403Snectar#define	SMPUNAMELEN	13
56142403Snectar#define	UPUNAMELEN	15
57142403Snectar
58142403Snectarextern struct process_select ps;
59142403Snectarextern char* printable(char *);
60142403Snectarstatic int smpmode;
61142403Snectarenum displaymodes displaymode;
62142403Snectarstatic int namelength = 8;
63142403Snectarstatic int cmdlengthdelta;
64142403Snectar
65142403Snectar/* Prototypes for top internals */
66142403Snectarvoid quit(int);
67142403Snectar
68142403Snectar/* get_process_info passes back a handle.  This is what it looks like: */
69233294Sstas
70142403Snectarstruct handle {
71142403Snectar	struct kinfo_proc **next_proc;	/* points to next valid proc pointer */
72142403Snectar	int remaining;			/* number of pointers remaining */
73142403Snectar};
74178825Sdfr
75142403Snectar/* declarations for load_avg */
76142403Snectar#include "loadavg.h"
77142403Snectar
78142403Snectar/* define what weighted cpu is.  */
79142403Snectar#define weighted_cpu(pct, pp) ((pp)->ki_swtime == 0 ? 0.0 : \
80142403Snectar			 ((pct) / (1.0 - exp((pp)->ki_swtime * logcpu))))
81142403Snectar
82142403Snectar/* what we consider to be process size: */
83233294Sstas#define PROCSIZE(pp) ((pp)->ki_size / 1024)
84233294Sstas
85233294Sstas#define RU(pp)	(&(pp)->ki_rusage)
86233294Sstas#define RUTOT(pp) \
87233294Sstas	(RU(pp)->ru_inblock + RU(pp)->ru_oublock + RU(pp)->ru_majflt)
88233294Sstas
89178825Sdfr
90178825Sdfr/* definitions for indices in the nlist array */
91178825Sdfr
92178825Sdfr/*
93178825Sdfr *  These definitions control the format of the per-process area
94178825Sdfr */
95178825Sdfr
96233294Sstasstatic char io_header[] =
97142403Snectar    "  PID %-*.*s   VCSW  IVCSW   READ  WRITE  FAULT  TOTAL PERCENT COMMAND";
98142403Snectar
99178825Sdfr#define io_Proc_format \
100142403Snectar    "%5d %-*.*s %6ld %6ld %6ld %6ld %6ld %6ld %6.2f%% %.*s"
101142403Snectar
102233294Sstasstatic char smp_header_thr[] =
103178825Sdfr    "  PID %-*.*s  THR PRI NICE   SIZE    RES STATE  C   TIME %6s COMMAND";
104233294Sstasstatic char smp_header[] =
105178825Sdfr    "  PID %-*.*s "   "PRI NICE   SIZE    RES STATE  C   TIME %6s COMMAND";
106142403Snectar
107142403Snectar#define smp_Proc_format \
108142403Snectar    "%5d %-*.*s %s%3d %4s%7s %6s %-6.6s %1x%7s %5.2f%% %.*s"
109233294Sstas
110142403Snectarstatic char up_header_thr[] =
111142403Snectar    "  PID %-*.*s  THR PRI NICE   SIZE    RES STATE    TIME %6s COMMAND";
112142403Snectarstatic char up_header[] =
113233294Sstas    "  PID %-*.*s "   "PRI NICE   SIZE    RES STATE    TIME %6s COMMAND";
114233294Sstas
115233294Sstas#define up_Proc_format \
116233294Sstas    "%5d %-*.*s %s%3d %4s%7s %6s %-6.6s%.0d%7s %5.2f%% %.*s"
117233294Sstas
118233294Sstas
119233294Sstas/* process state names for the "STATE" column of the display */
120233294Sstas/* the extra nulls in the string "run" are for adding a slash and
121233294Sstas   the processor number when needed */
122233294Sstas
123233294Sstaschar *state_abbrev[] = {
124233294Sstas	"", "START", "RUN\0\0\0", "SLEEP", "STOP", "ZOMB", "WAIT", "LOCK"
125233294Sstas};
126142403Snectar
127142403Snectar
128142403Snectarstatic kvm_t *kd;
129142403Snectar
130142403Snectar/* values that we stash away in _init and use in later routines */
131142403Snectar
132142403Snectarstatic double logcpu;
133142403Snectar
134178825Sdfr/* these are retrieved from the kernel in _init */
135178825Sdfr
136178825Sdfrstatic load_avg  ccpu;
137178825Sdfr
138178825Sdfr/* these are used in the get_ functions */
139142403Snectar
140178825Sdfrstatic int lastpid;
141178825Sdfr
142142403Snectar/* these are for calculating cpu state percentages */
143142403Snectar
144142403Snectarstatic long cp_time[CPUSTATES];
145142403Snectarstatic long cp_old[CPUSTATES];
146142403Snectarstatic long cp_diff[CPUSTATES];
147142403Snectar
148178825Sdfr/* these are for detailing the process states */
149178825Sdfr
150178825Sdfrint process_states[8];
151142403Snectarchar *procstatenames[] = {
152142403Snectar	"", " starting, ", " running, ", " sleeping, ", " stopped, ",
153142403Snectar	" zombie, ", " waiting, ", " lock, ",
154178825Sdfr	NULL
155178825Sdfr};
156233294Sstas
157233294Sstas/* these are for detailing the cpu states */
158142403Snectar
159142403Snectarint cpu_states[CPUSTATES];
160142403Snectarchar *cpustatenames[] = {
161142403Snectar	"user", "nice", "system", "interrupt", "idle", NULL
162142403Snectar};
163142403Snectar
164233294Sstas/* these are for detailing the memory statistics */
165233294Sstas
166233294Sstasint memory_stats[7];
167142403Snectarchar *memorynames[] = {
168142403Snectar	"K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ",
169178825Sdfr	"K Free", NULL
170178825Sdfr};
171178825Sdfr
172142403Snectarint swap_stats[7];
173178825Sdfrchar *swapnames[] = {
174178825Sdfr	"K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out",
175178825Sdfr	NULL
176233294Sstas};
177233294Sstas
178233294Sstas
179233294Sstas/* these are for keeping track of the proc array */
180233294Sstas
181233294Sstasstatic int nproc;
182233294Sstasstatic int onproc = -1;
183233294Sstasstatic int pref_len;
184233294Sstasstatic struct kinfo_proc *pbase;
185233294Sstasstatic struct kinfo_proc **pref;
186233294Sstasstatic struct kinfo_proc *previous_procs;
187233294Sstasstatic struct kinfo_proc **previous_pref;
188233294Sstasstatic int previous_proc_count = 0;
189233294Sstasstatic int previous_proc_count_max = 0;
190233294Sstas
191233294Sstas/* total number of io operations */
192233294Sstasstatic long total_inblock;
193233294Sstasstatic long total_oublock;
194233294Sstasstatic long total_majflt;
195233294Sstas
196233294Sstas/* these are for getting the memory statistics */
197233294Sstas
198233294Sstasstatic int pageshift;		/* log base 2 of the pagesize */
199233294Sstas
200233294Sstas/* define pagetok in terms of pageshift */
201233294Sstas
202233294Sstas#define pagetok(size) ((size) << pageshift)
203233294Sstas
204142403Snectar/* useful externals */
205233294Sstaslong percentages();
206142403Snectar
207142403Snectar#ifdef ORDER
208142403Snectar/*
209142403Snectar * Sorting orders.  The first element is the default.
210127808Snectar */
21155682Smarkmchar *ordernames[] = {
21272445Sassar	"cpu", "size", "res", "time", "pri", "threads",
213127808Snectar	"total", "read", "write", "fault", "vcsw", "ivcsw", NULL
214233294Sstas};
215233294Sstas#endif
216127808Snectar
217127808Snectarstatic int compare_pid(const void *a, const void *b);
218127808Snectarstatic const char *format_nice(const struct kinfo_proc *pp);
21955682Smarkmstatic void getsysctl(const char *name, void *ptr, size_t len);
22055682Smarkmstatic int swapmode(int *retavail, int *retfree);
221233294Sstas
222233294Sstasint
22355682Smarkmmachine_init(struct statics *statics)
22455682Smarkm{
22555682Smarkm	int pagesize;
226233294Sstas	size_t modelen;
227127808Snectar	struct passwd *pw;
22890926Snectar
22972445Sassar	modelen = sizeof(smpmode);
230127808Snectar	if ((sysctlbyname("machdep.smp_active", &smpmode, &modelen,
231127808Snectar	    NULL, 0) != 0 &&
232233294Sstas	    sysctlbyname("kern.smp.active", &smpmode, &modelen,
23355682Smarkm	    NULL, 0) != 0) ||
234127808Snectar	    modelen != sizeof(smpmode))
235233294Sstas		smpmode = 0;
23690926Snectar
237178825Sdfr	while ((pw = getpwent()) != NULL) {
238178825Sdfr		if (strlen(pw->pw_name) > namelength)
23972445Sassar			namelength = strlen(pw->pw_name);
240233294Sstas	}
241233294Sstas	if (smpmode && namelength > SMPUNAMELEN)
242233294Sstas		namelength = SMPUNAMELEN;
243127808Snectar	else if (namelength > UPUNAMELEN)
244127808Snectar		namelength = UPUNAMELEN;
245127808Snectar
246127808Snectar	kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
247127808Snectar	if (kd == NULL)
248233294Sstas		return (-1);
249178825Sdfr
25055682Smarkm	GETSYSCTL("kern.ccpu", ccpu);
25172445Sassar
252178825Sdfr	/* this is used in calculating WCPU -- calculate it ahead of time */
253127808Snectar	logcpu = log(loaddouble(ccpu));
254127808Snectar
255233294Sstas	pbase = NULL;
256233294Sstas	pref = NULL;
257127808Snectar	nproc = 0;
258127808Snectar	onproc = -1;
259233294Sstas
260178825Sdfr	/* get the page size and calculate pageshift from it */
261127808Snectar	pagesize = getpagesize();
262127808Snectar	pageshift = 0;
263127808Snectar	while (pagesize > 1) {
26490926Snectar		pageshift++;
265233294Sstas		pagesize >>= 1;
266127808Snectar	}
267178825Sdfr
26855682Smarkm	/* we only need the amount of log(2)1024 for our conversion */
269102644Snectar	pageshift -= LOG1024;
270102644Snectar
271178825Sdfr	/* fill in the statics information */
272127808Snectar	statics->procstate_names = procstatenames;
273127808Snectar	statics->cpustate_names = cpustatenames;
27455682Smarkm	statics->memory_names = memorynames;
27555682Smarkm	statics->swap_names = swapnames;
27690926Snectar#ifdef ORDER
277127808Snectar	statics->order_names = ordernames;
278127808Snectar#endif
279127808Snectar
280127808Snectar	/* all done! */
281127808Snectar	return (0);
28290926Snectar}
28390926Snectar
28490926Snectarchar *
285127808Snectarformat_header(char *uname_field)
286127808Snectar{
287127808Snectar	static char Header[128];
288127808Snectar	const char *prehead;
289233294Sstas
290127808Snectar	switch (displaymode) {
291127808Snectar	case DISP_CPU:
292233294Sstas		/*
293178825Sdfr		 * The logic of picking the right header format seems reverse
294127808Snectar		 * here because we only want to display a THR column when
295127808Snectar		 * "thread mode" is off (and threads are not listed as
296127808Snectar		 * separate lines).
297127808Snectar		 */
298127808Snectar		prehead = smpmode ?
299127808Snectar		    (ps.thread ? smp_header : smp_header_thr) :
300127808Snectar		    (ps.thread ? up_header : up_header_thr);
301127808Snectar		snprintf(Header, sizeof(Header), prehead,
302178825Sdfr		    namelength, namelength, uname_field,
303178825Sdfr		    ps.wcpu ? "WCPU" : "CPU");
304178825Sdfr		break;
305178825Sdfr	case DISP_IO:
306127808Snectar		prehead = io_header;
307127808Snectar		snprintf(Header, sizeof(Header), prehead,
30855682Smarkm		    namelength, namelength, uname_field);
309127808Snectar		break;
310233294Sstas	}
311233294Sstas	cmdlengthdelta = strlen(Header) - 7;
312127808Snectar	return (Header);
313127808Snectar}
314127808Snectar
315127808Snectarstatic int swappgsin = -1;
316127808Snectarstatic int swappgsout = -1;
31755682Smarkmextern struct timeval timeout;
318127808Snectar
319127808Snectarvoid
320178825Sdfrget_system_info(struct system_info *si)
321127808Snectar{
322127808Snectar	long total;
32355682Smarkm	struct loadavg sysload;
32455682Smarkm	int mib[2];
325127808Snectar	struct timeval boottime;
326127808Snectar	size_t bt_size;
327233294Sstas	int i;
328127808Snectar
329127808Snectar	/* get the cp_time array */
330233294Sstas	GETSYSCTL("kern.cp_time", cp_time);
33155682Smarkm	GETSYSCTL("vm.loadavg", sysload);
33255682Smarkm	GETSYSCTL("kern.lastpid", lastpid);
333120945Snectar
334127808Snectar	/* convert load averages to doubles */
335233294Sstas	for (i = 0; i < 3; i++)
336178825Sdfr		si->load_avg[i] = (double)sysload.ldavg[i] / sysload.fscale;
337233294Sstas
338233294Sstas	/* convert cp_time counts to percentages */
339233294Sstas	total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
34055682Smarkm
341233294Sstas	/* sum memory & swap statistics */
342127808Snectar	{
343233294Sstas		static unsigned int swap_delay = 0;
344233294Sstas		static int swapavail = 0;
34555682Smarkm		static int swapfree = 0;
346127808Snectar		static int bufspace = 0;
347127808Snectar		static int nspgsin, nspgsout;
348127808Snectar
349127808Snectar		GETSYSCTL("vfs.bufspace", bufspace);
350233294Sstas		GETSYSCTL("vm.stats.vm.v_active_count", memory_stats[0]);
351127808Snectar		GETSYSCTL("vm.stats.vm.v_inactive_count", memory_stats[1]);
352127808Snectar		GETSYSCTL("vm.stats.vm.v_wire_count", memory_stats[2]);
353233294Sstas		GETSYSCTL("vm.stats.vm.v_cache_count", memory_stats[3]);
354233294Sstas		GETSYSCTL("vm.stats.vm.v_free_count", memory_stats[5]);
355233294Sstas		GETSYSCTL("vm.stats.vm.v_swappgsin", nspgsin);
356233294Sstas		GETSYSCTL("vm.stats.vm.v_swappgsout", nspgsout);
35755682Smarkm		/* convert memory stats to Kbytes */
358233294Sstas		memory_stats[0] = pagetok(memory_stats[0]);
359127808Snectar		memory_stats[1] = pagetok(memory_stats[1]);
360127808Snectar		memory_stats[2] = pagetok(memory_stats[2]);
361233294Sstas		memory_stats[3] = pagetok(memory_stats[3]);
362233294Sstas		memory_stats[4] = bufspace / 1024;
363102644Snectar		memory_stats[5] = pagetok(memory_stats[5]);
36455682Smarkm		memory_stats[6] = -1;
365178825Sdfr
36655682Smarkm		/* first interval */
36755682Smarkm		if (swappgsin < 0) {
36855682Smarkm			swap_stats[4] = 0;
369178825Sdfr			swap_stats[5] = 0;
37090926Snectar		}
37190926Snectar
37290926Snectar		/* compute differences between old and new swap statistic */
37390926Snectar		else {
37455682Smarkm			swap_stats[4] = pagetok(((nspgsin - swappgsin)));
375178825Sdfr			swap_stats[5] = pagetok(((nspgsout - swappgsout)));
376178825Sdfr		}
377178825Sdfr
378178825Sdfr		swappgsin = nspgsin;
379178825Sdfr		swappgsout = nspgsout;
380233294Sstas
381127808Snectar		/* call CPU heavy swapmode() only for changes */
382233294Sstas		if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) {
383233294Sstas			swap_stats[3] = swapmode(&swapavail, &swapfree);
384127808Snectar			swap_stats[0] = swapavail;
385233294Sstas			swap_stats[1] = swapavail - swapfree;
386178825Sdfr			swap_stats[2] = swapfree;
387178825Sdfr		}
388127808Snectar		swap_delay = 1;
389127808Snectar		swap_stats[6] = -1;
390127808Snectar	}
391127808Snectar
392127808Snectar	/* set arrays and strings */
393127808Snectar	si->cpustates = cpu_states;
394178825Sdfr	si->memory = memory_stats;
395127808Snectar	si->swap = swap_stats;
396178825Sdfr
397178825Sdfr
398102644Snectar	if (lastpid > 0) {
399102644Snectar		si->last_pid = lastpid;
400102644Snectar	} else {
401178825Sdfr		si->last_pid = -1;
402127808Snectar	}
403127808Snectar
404127808Snectar	/*
405127808Snectar	 * Print how long system has been up.
406127808Snectar	 * (Found by looking getting "boottime" from the kernel)
407127808Snectar	 */
408178825Sdfr	mib[0] = CTL_KERN;
409127808Snectar	mib[1] = KERN_BOOTTIME;
410127808Snectar	bt_size = sizeof(boottime);
41172445Sassar	if (sysctl(mib, 2, &boottime, &bt_size, NULL, 0) != -1 &&
412127808Snectar	    boottime.tv_sec != 0) {
413127808Snectar		si->boottime = boottime;
414178825Sdfr	} else {
415127808Snectar		si->boottime.tv_sec = -1;
416127808Snectar	}
417142403Snectar}
418127808Snectar
419178825Sdfr#define NOPROC	((void *)-1)
420127808Snectar
421127808Snectar/*
422178825Sdfr * We need to compare data from the old process entry with the new
423127808Snectar * process entry.
424127808Snectar * To facilitate doing this quickly we stash a pointer in the kinfo_proc
425178825Sdfr * structure to cache the mapping.  We also use a negative cache pointer
426233294Sstas * of NOPROC to avoid duplicate lookups.
427127808Snectar * XXX: this could be done when the actual processes are fetched, we do
428127808Snectar * it here out of laziness.
429233294Sstas */
430178825Sdfrconst struct kinfo_proc *
431178825Sdfrget_old_proc(struct kinfo_proc *pp)
432233294Sstas{
433233294Sstas	struct kinfo_proc **oldpp, *oldp;
434233294Sstas
435233294Sstas	/*
436233294Sstas	 * If this is the first fetch of the kinfo_procs then we don't have
437102644Snectar	 * any previous entries.
43890926Snectar	 */
43972445Sassar	if (previous_proc_count == 0)
44055682Smarkm		return (NULL);
441233294Sstas	/* negative cache? */
44255682Smarkm	if (pp->ki_udata == NOPROC)
44355682Smarkm		return (NULL);
44455682Smarkm	/* cached? */
44555682Smarkm	if (pp->ki_udata != NULL)
44655682Smarkm		return (pp->ki_udata);
44755682Smarkm	/*
448233294Sstas	 * Not cached,
44955682Smarkm	 * 1) look up based on pid.
450120945Snectar	 * 2) compare process start.
45190926Snectar	 * If we fail here, then setup a negative cache entry, otherwise
45272445Sassar	 * cache it.
45355682Smarkm	 */
45490926Snectar	oldpp = bsearch(&pp, previous_pref, previous_proc_count,
455233294Sstas	    sizeof(*previous_pref), compare_pid);
45690926Snectar	if (oldpp == NULL) {
457178825Sdfr		pp->ki_udata = NOPROC;
458178825Sdfr		return (NULL);
459178825Sdfr	}
460178825Sdfr	oldp = *oldpp;
461233294Sstas	if (bcmp(&oldp->ki_start, &pp->ki_start, sizeof(pp->ki_start)) != 0) {
462233294Sstas		pp->ki_udata = NOPROC;
463178825Sdfr		return (NULL);
464233294Sstas	}
465178825Sdfr	pp->ki_udata = oldp;
46690926Snectar	return (oldp);
46772445Sassar}
46872445Sassar
469178825Sdfr/*
470178825Sdfr * Return the total amount of IO done in blocks in/out and faults.
47172445Sassar * store the values individually in the pointers passed in.
472233294Sstas */
47372445Sassarlong
47455682Smarkmget_io_stats(struct kinfo_proc *pp, long *inp, long *oup, long *flp,
47590926Snectar    long *vcsw, long *ivcsw)
476178825Sdfr{
477233294Sstas	const struct kinfo_proc *oldp;
478233294Sstas	static struct kinfo_proc dummy;
479233294Sstas	long ret;
480233294Sstas
481233294Sstas	oldp = get_old_proc(pp);
482233294Sstas	if (oldp == NULL) {
483233294Sstas		bzero(&dummy, sizeof(dummy));
484178825Sdfr		oldp = &dummy;
485178825Sdfr	}
486178825Sdfr	*inp = RU(pp)->ru_inblock - RU(oldp)->ru_inblock;
487178825Sdfr	*oup = RU(pp)->ru_oublock - RU(oldp)->ru_oublock;
488178825Sdfr	*flp = RU(pp)->ru_majflt - RU(oldp)->ru_majflt;
489178825Sdfr	*vcsw = RU(pp)->ru_nvcsw - RU(oldp)->ru_nvcsw;
490178825Sdfr	*ivcsw = RU(pp)->ru_nivcsw - RU(oldp)->ru_nivcsw;
491178825Sdfr	ret =
492178825Sdfr	    (RU(pp)->ru_inblock - RU(oldp)->ru_inblock) +
493178825Sdfr	    (RU(pp)->ru_oublock - RU(oldp)->ru_oublock) +
494233294Sstas	    (RU(pp)->ru_majflt - RU(oldp)->ru_majflt);
495233294Sstas	return (ret);
496233294Sstas}
497233294Sstas
49872445Sassar/*
49972445Sassar * Return the total number of block in/out and faults by a process.
500178825Sdfr */
50172445Sassarlong
50272445Sassarget_io_total(struct kinfo_proc *pp)
50355682Smarkm{
504233294Sstas	long dummy;
505233294Sstas
506233294Sstas	return (get_io_stats(pp, &dummy, &dummy, &dummy, &dummy, &dummy));
507233294Sstas}
508233294Sstas
509233294Sstasstatic struct handle handle;
510233294Sstas
511233294Sstascaddr_t
512233294Sstasget_process_info(struct system_info *si, struct process_select *sel,
51390926Snectar    int (*compare)(const void *, const void *))
51455682Smarkm{
51555682Smarkm	int i;
516233294Sstas	int total_procs;
517142403Snectar	long p_io;
518142403Snectar	long p_inblock, p_oublock, p_majflt, p_vcsw, p_ivcsw;
519142403Snectar	int active_procs;
520142403Snectar	struct kinfo_proc **prefp;
521233294Sstas	struct kinfo_proc *pp;
522233294Sstas	struct kinfo_proc *prev_pp = NULL;
523142403Snectar
524142403Snectar	/* these are copied out of sel for speed */
525142403Snectar	int show_idle;
526233294Sstas	int show_self;
527233294Sstas	int show_system;
528233294Sstas	int show_uid;
529142403Snectar	int show_command;
530142403Snectar
531142403Snectar	/*
532142403Snectar	 * Save the previous process info.
533142403Snectar	 */
534142403Snectar	if (previous_proc_count_max < nproc) {
535142403Snectar		free(previous_procs);
536142403Snectar		previous_procs = malloc(nproc * sizeof(*previous_procs));
537142403Snectar		free(previous_pref);
538142403Snectar		previous_pref = malloc(nproc * sizeof(*previous_pref));
539142403Snectar		if (previous_procs == NULL || previous_pref == NULL) {
540142403Snectar			(void) fprintf(stderr, "top: Out of memory.\n");
541142403Snectar			quit(23);
542142403Snectar		}
543142403Snectar		previous_proc_count_max = nproc;
544142403Snectar	}
545142403Snectar	if (nproc) {
546233294Sstas		for (i = 0; i < nproc; i++)
54755682Smarkm			previous_pref[i] = &previous_procs[i];
54855682Smarkm		bcopy(pbase, previous_procs, nproc * sizeof(*previous_procs));
549178825Sdfr		qsort(previous_pref, nproc, sizeof(*previous_pref),
550233294Sstas		    compare_pid);
551233294Sstas	}
552233294Sstas	previous_proc_count = nproc;
553233294Sstas
554233294Sstas	pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc);
555233294Sstas	if (nproc > onproc)
556233294Sstas		pref = realloc(pref, sizeof(*pref) * (onproc = nproc));
557233294Sstas	if (pref == NULL || pbase == NULL) {
558233294Sstas		(void) fprintf(stderr, "top: Out of memory.\n");
559233294Sstas		quit(23);
560233294Sstas	}
561233294Sstas	/* get a pointer to the states summary array */
562233294Sstas	si->procstates = process_states;
563233294Sstas
564233294Sstas	/* set up flags which define what we are going to select */
565233294Sstas	show_idle = sel->idle;
566233294Sstas	show_self = sel->self == -1;
567233294Sstas	show_system = sel->system;
568233294Sstas	show_uid = sel->uid != -1;
569233294Sstas	show_command = sel->command != NULL;
570233294Sstas
57155682Smarkm	/* count up process states and get pointers to interesting procs */
57255682Smarkm	total_procs = 0;
57355682Smarkm	active_procs = 0;
574233294Sstas	total_inblock = 0;
575233294Sstas	total_oublock = 0;
576233294Sstas	total_majflt = 0;
577233294Sstas	memset((char *)process_states, 0, sizeof(process_states));
578233294Sstas	prefp = pref;
579233294Sstas	for (pp = pbase, i = 0; i < nproc; pp++, i++) {
580233294Sstas
58155682Smarkm		if (pp->ki_stat == 0)
58290926Snectar			/* not in use */
583233294Sstas			continue;
584233294Sstas
585233294Sstas		if (!show_self && pp->ki_pid == sel->self)
586233294Sstas			/* skip self */
587233294Sstas			continue;
588233294Sstas
589233294Sstas		if (!show_system && (pp->ki_flag & P_SYSTEM))
590178825Sdfr			/* skip system process */
591178825Sdfr			continue;
592178825Sdfr
593233294Sstas		p_io = get_io_stats(pp, &p_inblock, &p_oublock, &p_majflt,
594233294Sstas		    &p_vcsw, &p_ivcsw);
595233294Sstas		total_inblock += p_inblock;
596233294Sstas		total_oublock += p_oublock;
597233294Sstas		total_majflt += p_majflt;
598233294Sstas		total_procs++;
599233294Sstas		process_states[pp->ki_stat]++;
600233294Sstas
601233294Sstas		if (pp->ki_stat == SZOMB)
602233294Sstas			/* skip zombies */
603233294Sstas			continue;
604233294Sstas
605233294Sstas		if (displaymode == DISP_CPU && !show_idle &&
606233294Sstas		    (pp->ki_pctcpu == 0 ||
607233294Sstas		     pp->ki_stat == SSTOP || pp->ki_stat == SIDL))
608233294Sstas			/* skip idle or non-running processes */
609233294Sstas			continue;
610233294Sstas
611233294Sstas		if (displaymode == DISP_IO && !show_idle && p_io == 0)
612233294Sstas			/* skip processes that aren't doing I/O */
613233294Sstas			continue;
61455682Smarkm
615178825Sdfr		if (show_uid && pp->ki_ruid != (uid_t)sel->uid)
616178825Sdfr			/* skip proc. that don't belong to the selected UID */
617233294Sstas			continue;
618233294Sstas
619233294Sstas		/*
620233294Sstas		 * When not showing threads, take the first thread
621233294Sstas		 * for output and add the fields that we can from
622233294Sstas		 * the rest of the process's threads rather than
623233294Sstas		 * using the system's mostly-broken KERN_PROC_PROC.
624178825Sdfr		 */
625178825Sdfr		if (sel->thread || prev_pp == NULL ||
626233294Sstas		    prev_pp->ki_pid != pp->ki_pid) {
627233294Sstas			*prefp++ = pp;
628233294Sstas			active_procs++;
629233294Sstas			prev_pp = pp;
630233294Sstas		} else {
631233294Sstas			prev_pp->ki_pctcpu += pp->ki_pctcpu;
632233294Sstas		}
633178825Sdfr	}
63455682Smarkm
635233294Sstas	/* if requested, sort the "interesting" processes */
636233294Sstas	if (compare != NULL)
637233294Sstas		qsort(pref, active_procs, sizeof(*pref), compare);
638233294Sstas
639233294Sstas	/* remember active and total counts */
640233294Sstas	si->p_total = total_procs;
641233294Sstas	si->p_active = pref_len = active_procs;
64290926Snectar
64372445Sassar	/* pass back a handle */
644178825Sdfr	handle.next_proc = pref;
645233294Sstas	handle.remaining = active_procs;
646233294Sstas	return ((caddr_t)&handle);
647233294Sstas}
64890926Snectar
64972445Sassarstatic char fmt[128];	/* static area where result is built */
650178825Sdfr
65190926Snectarchar *
65255682Smarkmformat_next_process(caddr_t handle, char *(*get_userid)(int))
653178825Sdfr{
654178825Sdfr	struct kinfo_proc *pp;
655178825Sdfr	const struct kinfo_proc *oldp;
656178825Sdfr	long cputime;
65790926Snectar	double pct;
65855682Smarkm	struct handle *hp;
659178825Sdfr	char status[16];
660178825Sdfr	int state;
661178825Sdfr	struct rusage ru, *rup;
662178825Sdfr	long p_tot, s_tot;
66390926Snectar	char *proc_fmt, thr_buf[6];
66472445Sassar
665178825Sdfr	/* find and remember the next proc structure */
66690926Snectar	hp = (struct handle *)handle;
66755682Smarkm	pp = *(hp->next_proc++);
668178825Sdfr	hp->remaining--;
66990926Snectar
67090926Snectar	/* get the process's command name */
671142403Snectar	if ((pp->ki_sflag & PS_INMEM) == 0) {
67290926Snectar		/*
67390926Snectar		 * Print swapped processes as <pname>
67490926Snectar		 */
67590926Snectar		size_t len;
676233294Sstas
677233294Sstas		len = strlen(pp->ki_comm);
678233294Sstas		if (len > sizeof(pp->ki_comm) - 3)
679233294Sstas			len = sizeof(pp->ki_comm) - 3;
680233294Sstas		memmove(pp->ki_comm + 1, pp->ki_comm, len);
681233294Sstas		pp->ki_comm[0] = '<';
682233294Sstas		pp->ki_comm[len + 1] = '>';
683233294Sstas		pp->ki_comm[len + 2] = '\0';
684233294Sstas	}
685233294Sstas
686233294Sstas	/*
687233294Sstas	 * Convert the process's runtime from microseconds to seconds.  This
688233294Sstas	 * time includes the interrupt time although that is not wanted here.
689233294Sstas	 * ps(1) is similarly sloppy.
690233294Sstas	 */
69172445Sassar	cputime = (pp->ki_runtime + 500000) / 1000000;
692233294Sstas
693233294Sstas	/* calculate the base for cpu percentages */
694233294Sstas	pct = pctdouble(pp->ki_pctcpu);
695233294Sstas
696233294Sstas	/* generate "STATE" field */
69790926Snectar	switch (state = pp->ki_stat) {
69872445Sassar	case SRUN:
699233294Sstas		if (smpmode && pp->ki_oncpu != 0xff)
700233294Sstas			sprintf(status, "CPU%d", pp->ki_oncpu);
701233294Sstas		else
702233294Sstas			strcpy(status, "RUN");
703233294Sstas		break;
70490926Snectar	case SLOCK:
70572445Sassar		if (pp->ki_kiflag & KI_LOCKBLOCK) {
706233294Sstas			sprintf(status, "*%.6s", pp->ki_lockname);
707233294Sstas			break;
708233294Sstas		}
709233294Sstas		/* fall through */
710233294Sstas	case SSLEEP:
711102644Snectar		if (pp->ki_wmesg != NULL) {
712102644Snectar			sprintf(status, "%.6s", pp->ki_wmesg);
713102644Snectar			break;
714102644Snectar		}
715102644Snectar		/* FALLTHROUGH */
716102644Snectar	default:
717233294Sstas
71890926Snectar		if (state >= 0 &&
719178825Sdfr		    state < sizeof(state_abbrev) / sizeof(*state_abbrev))
720233294Sstas			sprintf(status, "%.6s", state_abbrev[state]);
721233294Sstas		else
722233294Sstas			sprintf(status, "?%5d", state);
723233294Sstas		break;
724233294Sstas	}
725233294Sstas
726233294Sstas	if (displaymode == DISP_IO) {
727233294Sstas		oldp = get_old_proc(pp);
728233294Sstas		if (oldp != NULL) {
729233294Sstas			ru.ru_inblock = RU(pp)->ru_inblock -
730233294Sstas			    RU(oldp)->ru_inblock;
731233294Sstas			ru.ru_oublock = RU(pp)->ru_oublock -
732233294Sstas			    RU(oldp)->ru_oublock;
733233294Sstas			ru.ru_majflt = RU(pp)->ru_majflt - RU(oldp)->ru_majflt;
734233294Sstas			ru.ru_nvcsw = RU(pp)->ru_nvcsw - RU(oldp)->ru_nvcsw;
735233294Sstas			ru.ru_nivcsw = RU(pp)->ru_nivcsw - RU(oldp)->ru_nivcsw;
73655682Smarkm			rup = &ru;
737233294Sstas		} else {
738233294Sstas			rup = RU(pp);
739233294Sstas		}
740233294Sstas		p_tot = rup->ru_inblock + rup->ru_oublock + rup->ru_majflt;
741233294Sstas		s_tot = total_inblock + total_oublock + total_majflt;
742233294Sstas
743233294Sstas		sprintf(fmt, io_Proc_format,
74455682Smarkm		    pp->ki_pid,
74590926Snectar		    namelength, namelength, (*get_userid)(pp->ki_ruid),
746233294Sstas		    rup->ru_nvcsw,
747233294Sstas		    rup->ru_nivcsw,
748233294Sstas		    rup->ru_inblock,
749233294Sstas		    rup->ru_oublock,
750233294Sstas		    rup->ru_majflt,
751233294Sstas		    p_tot,
752233294Sstas		    s_tot == 0 ? 0.0 : (p_tot * 100.0 / s_tot),
753233294Sstas		    screen_width > cmdlengthdelta ?
754233294Sstas		    screen_width - cmdlengthdelta : 0,
755233294Sstas		    printable(pp->ki_comm));
756233294Sstas		return (fmt);
757233294Sstas	}
758233294Sstas
759233294Sstas	/* format this entry */
760233294Sstas	proc_fmt = smpmode ? smp_Proc_format : up_Proc_format;
761233294Sstas	if (ps.thread != 0)
762233294Sstas		thr_buf[0] = '\0';
763233294Sstas	else
764233294Sstas		snprintf(thr_buf, sizeof(thr_buf), "%*d ",
765233294Sstas		    sizeof(thr_buf) - 2, pp->ki_numthreads);
766233294Sstas
767233294Sstas	sprintf(fmt, proc_fmt,
768233294Sstas	    pp->ki_pid,
769233294Sstas	    namelength, namelength, (*get_userid)(pp->ki_ruid),
770233294Sstas	    thr_buf,
771233294Sstas	    pp->ki_pri.pri_level - PZERO,
772233294Sstas	    format_nice(pp),
773233294Sstas	    format_k2(PROCSIZE(pp)),
77455682Smarkm	    format_k2(pagetok(pp->ki_rssize)),
775233294Sstas	    status,
776233294Sstas	    smpmode ? pp->ki_lastcpu : 0,
777233294Sstas	    format_time(cputime),
778233294Sstas	    ps.wcpu ? 100.0 * weighted_cpu(pct, pp) : 100.0 * pct,
779233294Sstas	    screen_width > cmdlengthdelta ? screen_width - cmdlengthdelta : 0,
780233294Sstas	    printable(pp->ki_comm));
78155682Smarkm
782233294Sstas	/* return the result */
783233294Sstas	return (fmt);
784233294Sstas}
785233294Sstas
786233294Sstasstatic void
787233294Sstasgetsysctl(const char *name, void *ptr, size_t len)
788233294Sstas{
789233294Sstas	size_t nlen = len;
790233294Sstas
791233294Sstas	if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
792233294Sstas		fprintf(stderr, "top: sysctl(%s...) failed: %s\n", name,
793233294Sstas		    strerror(errno));
79472445Sassar		quit(23);
795102644Snectar	}
79672445Sassar	if (nlen != len) {
79772445Sassar		fprintf(stderr, "top: sysctl(%s...) expected %lu, got %lu\n",
79872445Sassar		    name, (unsigned long)len, (unsigned long)nlen);
799233294Sstas		quit(23);
800233294Sstas	}
801102644Snectar}
802142403Snectar
80355682Smarkmstatic
80472445Sassarconst char *format_nice(const struct kinfo_proc *pp)
80572445Sassar{
806233294Sstas	static char nicebuf[5];
80755682Smarkm
808102644Snectar	snprintf(nicebuf, sizeof(nicebuf), "%4d",
80972445Sassar	    /*
81072445Sassar	     * normal time      -> nice value -20 - +20
81172445Sassar	     * real time 0 - 31 -> nice value -52 - -21
812233294Sstas	     * idle time 0 - 31 -> nice value +21 - +52
813233294Sstas	     */
814233294Sstas	    (pp->ki_pri.pri_class ==  PRI_TIMESHARE ?
815233294Sstas		pp->ki_nice - NZERO :
816178825Sdfr		(PRI_IS_REALTIME(pp->ki_pri.pri_class) ?
817233294Sstas		    (PRIO_MIN - 1 - (PRI_MAX_REALTIME - pp->ki_pri.pri_level)) :
818233294Sstas		    (PRIO_MAX + 1 + pp->ki_pri.pri_level - PRI_MIN_IDLE))));
819233294Sstas	return (nicebuf);
820233294Sstas}
821233294Sstas
822233294Sstas/* comparison routines for qsort */
823233294Sstas
824178825Sdfrstatic int
825127808Snectarcompare_pid(const void *p1, const void *p2)
826127808Snectar{
827127808Snectar	const struct kinfo_proc * const *pp1 = p1;
828127808Snectar	const struct kinfo_proc * const *pp2 = p2;
829127808Snectar
830127808Snectar	if ((*pp2)->ki_pid < 0 || (*pp1)->ki_pid < 0)
831127808Snectar		abort();
832233294Sstas
833233294Sstas	return ((*pp1)->ki_pid - (*pp2)->ki_pid);
834233294Sstas}
835127808Snectar
836233294Sstas/*
837127808Snectar *  proc_compare - comparison function for "qsort"
83878527Sassar *	Compares the resource consumption of two processes using five
839102644Snectar *	distinct keys.  The keys (in descending order of importance) are:
840233294Sstas *	percent cpu, cpu ticks, state, resident set size, total virtual
841233294Sstas *	memory usage.  The process states are ordered as follows (from least
84278527Sassar *	to most important):  WAIT, zombie, sleep, stop, start, run.  The
84355682Smarkm *	array declaration below maps a process state index into a number
844127808Snectar *	that reflects this ordering.
84555682Smarkm */
84655682Smarkm
847233294Sstasstatic int sorted_state[] = {
848233294Sstas	0,	/* not used		*/
849233294Sstas	3,	/* sleep		*/
850233294Sstas	1,	/* ABANDONED (WAIT)	*/
851233294Sstas	6,	/* run			*/
852233294Sstas	5,	/* start		*/
853233294Sstas	2,	/* zombie		*/
854233294Sstas	4	/* stop			*/
855233294Sstas};
856233294Sstas
857233294Sstas
858233294Sstas#define ORDERKEY_PCTCPU(a, b) do { \
859233294Sstas	long diff; \
860178825Sdfr	if (ps.wcpu) \
861178825Sdfr		diff = floor(1.0E6 * weighted_cpu(pctdouble((b)->ki_pctcpu), \
862178825Sdfr		    (b))) - \
863178825Sdfr		    floor(1.0E6 * weighted_cpu(pctdouble((a)->ki_pctcpu), \
864178825Sdfr		    (a))); \
865178825Sdfr	else \
866178825Sdfr		diff = (long)(b)->ki_pctcpu - (long)(a)->ki_pctcpu; \
867178825Sdfr	if (diff != 0) \
868178825Sdfr		return (diff > 0 ? 1 : -1); \
869178825Sdfr} while (0)
870178825Sdfr
871178825Sdfr#define ORDERKEY_CPTICKS(a, b) do { \
872102644Snectar	int64_t diff = (int64_t)(b)->ki_runtime - (int64_t)(a)->ki_runtime; \
87355682Smarkm	if (diff != 0) \
874178825Sdfr		return (diff > 0 ? 1 : -1); \
875233294Sstas} while (0)
876233294Sstas
877233294Sstas#define ORDERKEY_STATE(a, b) do { \
878102644Snectar	int diff = sorted_state[(b)->ki_stat] - sorted_state[(a)->ki_stat]; \
879233294Sstas	if (diff != 0) \
880233294Sstas		return (diff > 0 ? 1 : -1); \
881102644Snectar} while (0)
882233294Sstas
88355682Smarkm#define ORDERKEY_PRIO(a, b) do { \
884233294Sstas	int diff = (int)(b)->ki_pri.pri_level - (int)(a)->ki_pri.pri_level; \
885233294Sstas	if (diff != 0) \
88672445Sassar		return (diff > 0 ? 1 : -1); \
88755682Smarkm} while (0)
88855682Smarkm
88990926Snectar#define	ORDERKEY_THREADS(a, b) do { \
890127808Snectar	int diff = (int)(b)->ki_numthreads - (int)(a)->ki_numthreads; \
89190926Snectar	if (diff != 0) \
89255682Smarkm		return (diff > 0 ? 1 : -1); \
89355682Smarkm} while (0)
89455682Smarkm
89590926Snectar#define ORDERKEY_RSSIZE(a, b) do { \
89690926Snectar	long diff = (long)(b)->ki_rssize - (long)(a)->ki_rssize; \
897233294Sstas	if (diff != 0) \
898178825Sdfr		return (diff > 0 ? 1 : -1); \
899142403Snectar} while (0)
90090926Snectar
90155682Smarkm#define ORDERKEY_MEM(a, b) do { \
90255682Smarkm	long diff = (long)PROCSIZE((b)) - (long)PROCSIZE((a)); \
90390926Snectar	if (diff != 0) \
90455682Smarkm		return (diff > 0 ? 1 : -1); \
90555682Smarkm} while (0)
90655682Smarkm
90790926Snectar/* compare_cpu - the comparison function for sorting by cpu percentage */
90890926Snectar
90955682Smarkmint
91090926Snectar#ifdef ORDER
911127808Snectarcompare_cpu(void *arg1, void *arg2)
91290926Snectar#else
91390926Snectarproc_compare(void *arg1, void *arg2)
91455682Smarkm#endif
91555682Smarkm{
91655682Smarkm	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
917178825Sdfr	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
91855682Smarkm
91955682Smarkm	ORDERKEY_PCTCPU(p1, p2);
920178825Sdfr	ORDERKEY_CPTICKS(p1, p2);
921233294Sstas	ORDERKEY_STATE(p1, p2);
92255682Smarkm	ORDERKEY_PRIO(p1, p2);
92355682Smarkm	ORDERKEY_RSSIZE(p1, p2);
92490926Snectar	ORDERKEY_MEM(p1, p2);
92590926Snectar
92690926Snectar	return (0);
92755682Smarkm}
928178825Sdfr
929178825Sdfr#ifdef ORDER
93055682Smarkm/* "cpu" compare routines */
93190926Snectarint compare_size(), compare_res(), compare_time(), compare_prio(),
932233294Sstas    compare_threads();
933127808Snectar
93490926Snectar/*
935178825Sdfr * "io" compare routines.  Context switches aren't i/o, but are displayed
93655682Smarkm * on the "io" display.
93790926Snectar */
93855682Smarkmint compare_iototal(), compare_ioread(), compare_iowrite(), compare_iofault(),
93990926Snectar    compare_vcsw(), compare_ivcsw();
94055682Smarkm
941142403Snectarint (*compares[])() = {
942142403Snectar	compare_cpu,
943233294Sstas	compare_size,
944233294Sstas	compare_res,
94590926Snectar	compare_time,
94655682Smarkm	compare_prio,
94790926Snectar	compare_threads,
94890926Snectar	compare_iototal,
949120945Snectar	compare_ioread,
950120945Snectar	compare_iowrite,
951120945Snectar	compare_iofault,
952178825Sdfr	compare_vcsw,
953178825Sdfr	compare_ivcsw,
954233294Sstas	NULL
955233294Sstas};
956178825Sdfr
95790926Snectar/* compare_size - the comparison function for sorting by total memory usage */
95890926Snectar
959178825Sdfrint
960178825Sdfrcompare_size(void *arg1, void *arg2)
961233294Sstas{
962233294Sstas	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
96390926Snectar	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
96490926Snectar
965233294Sstas	ORDERKEY_MEM(p1, p2);
96690926Snectar	ORDERKEY_RSSIZE(p1, p2);
967233294Sstas	ORDERKEY_PCTCPU(p1, p2);
968233294Sstas	ORDERKEY_CPTICKS(p1, p2);
969178825Sdfr	ORDERKEY_STATE(p1, p2);
970178825Sdfr	ORDERKEY_PRIO(p1, p2);
971233294Sstas
972233294Sstas	return (0);
973178825Sdfr}
974178825Sdfr
975233294Sstas/* compare_res - the comparison function for sorting by resident set size */
976233294Sstas
97790926Snectarint
97890926Snectarcompare_res(void *arg1, void *arg2)
97955682Smarkm{
980233294Sstas	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
981127808Snectar	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
98290926Snectar
98355682Smarkm	ORDERKEY_RSSIZE(p1, p2);
98490926Snectar	ORDERKEY_MEM(p1, p2);
98555682Smarkm	ORDERKEY_PCTCPU(p1, p2);
98690926Snectar	ORDERKEY_CPTICKS(p1, p2);
98790926Snectar	ORDERKEY_STATE(p1, p2);
98890926Snectar	ORDERKEY_PRIO(p1, p2);
989127808Snectar
990127808Snectar	return (0);
991127808Snectar}
992127808Snectar
993127808Snectar/* compare_time - the comparison function for sorting by total cpu time */
994127808Snectar
995127808Snectarint
996127808Snectarcompare_time(void *arg1, void *arg2)
997178825Sdfr{
998178825Sdfr	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
999178825Sdfr	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
1000178825Sdfr
1001233294Sstas	ORDERKEY_CPTICKS(p1, p2);
100290926Snectar	ORDERKEY_PCTCPU(p1, p2);
1003233294Sstas	ORDERKEY_STATE(p1, p2);
1004233294Sstas	ORDERKEY_PRIO(p1, p2);
100590926Snectar	ORDERKEY_RSSIZE(p1, p2);
1006127808Snectar	ORDERKEY_MEM(p1, p2);
1007178825Sdfr
1008178825Sdfr	return (0);
1009178825Sdfr}
1010178825Sdfr
1011178825Sdfr/* compare_prio - the comparison function for sorting by priority */
1012178825Sdfr
1013178825Sdfrint
1014178825Sdfrcompare_prio(void *arg1, void *arg2)
1015233294Sstas{
1016233294Sstas	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
1017233294Sstas	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
1018233294Sstas
1019233294Sstas	ORDERKEY_PRIO(p1, p2);
1020233294Sstas	ORDERKEY_CPTICKS(p1, p2);
1021233294Sstas	ORDERKEY_PCTCPU(p1, p2);
1022233294Sstas	ORDERKEY_STATE(p1, p2);
102390926Snectar	ORDERKEY_RSSIZE(p1, p2);
102490926Snectar	ORDERKEY_MEM(p1, p2);
102555682Smarkm
102655682Smarkm	return (0);
102755682Smarkm}
102855682Smarkm
102955682Smarkm/* compare_threads - the comparison function for sorting by threads */
103072445Sassarint
103172445Sassarcompare_threads(void *arg1, void *arg2)
103272445Sassar{
103372445Sassar	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
103455682Smarkm	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
103555682Smarkm
103655682Smarkm	ORDERKEY_THREADS(p1, p2);
1037178825Sdfr	ORDERKEY_PCTCPU(p1, p2);
1038178825Sdfr	ORDERKEY_CPTICKS(p1, p2);
103955682Smarkm	ORDERKEY_STATE(p1, p2);
104055682Smarkm	ORDERKEY_PRIO(p1, p2);
104155682Smarkm	ORDERKEY_RSSIZE(p1, p2);
104255682Smarkm	ORDERKEY_MEM(p1, p2);
104355682Smarkm
104455682Smarkm	return (0);
104572445Sassar}
104672445Sassar#endif /* ORDER */
104755682Smarkm
1048178825Sdfr/* assorted comparison functions for sorting by i/o */
1049178825Sdfr
1050178825Sdfrint
1051178825Sdfr#ifdef ORDER
1052178825Sdfrcompare_iototal(void *arg1, void *arg2)
1053178825Sdfr#else
1054178825Sdfrio_compare(void *arg1, void *arg2)
1055178825Sdfr#endif
1056178825Sdfr{
1057178825Sdfr	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
1058178825Sdfr	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
105955682Smarkm
106055682Smarkm	return (get_io_total(p2) - get_io_total(p1));
106155682Smarkm}
1062102644Snectar
1063102644Snectar#ifdef ORDER
1064178825Sdfrint
1065178825Sdfrcompare_ioread(void *arg1, void *arg2)
1066102644Snectar{
1067102644Snectar	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
1068102644Snectar	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
1069102644Snectar	long dummy, inp1, inp2;
1070102644Snectar
1071102644Snectar	(void) get_io_stats(p1, &inp1, &dummy, &dummy, &dummy, &dummy);
1072178825Sdfr	(void) get_io_stats(p2, &inp2, &dummy, &dummy, &dummy, &dummy);
1073102644Snectar
1074102644Snectar	return (inp2 - inp1);
1075102644Snectar}
1076102644Snectar
1077102644Snectarint
1078102644Snectarcompare_iowrite(void *arg1, void *arg2)
1079102644Snectar{
1080102644Snectar	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
1081102644Snectar	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
1082102644Snectar	long dummy, oup1, oup2;
1083102644Snectar
1084102644Snectar	(void) get_io_stats(p1, &dummy, &oup1, &dummy, &dummy, &dummy);
1085102644Snectar	(void) get_io_stats(p2, &dummy, &oup2, &dummy, &dummy, &dummy);
1086102644Snectar
1087102644Snectar	return (oup2 - oup1);
1088178825Sdfr}
1089102644Snectar
1090102644Snectarint
1091102644Snectarcompare_iofault(void *arg1, void *arg2)
1092102644Snectar{
1093233294Sstas	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
1094233294Sstas	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
1095233294Sstas	long dummy, flp1, flp2;
109655682Smarkm
109755682Smarkm	(void) get_io_stats(p1, &dummy, &dummy, &flp1, &dummy, &dummy);
109855682Smarkm	(void) get_io_stats(p2, &dummy, &dummy, &flp2, &dummy, &dummy);
109955682Smarkm
110055682Smarkm	return (flp2 - flp1);
110155682Smarkm}
110255682Smarkm
110355682Smarkmint
110455682Smarkmcompare_vcsw(void *arg1, void *arg2)
110555682Smarkm{
110655682Smarkm	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
110755682Smarkm	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
110855682Smarkm	long dummy, flp1, flp2;
110955682Smarkm
111055682Smarkm	(void) get_io_stats(p1, &dummy, &dummy, &dummy, &flp1, &dummy);
111155682Smarkm	(void) get_io_stats(p2, &dummy, &dummy, &dummy, &flp2, &dummy);
111255682Smarkm
111355682Smarkm	return (flp2 - flp1);
111455682Smarkm}
111555682Smarkm
111655682Smarkmint
111755682Smarkmcompare_ivcsw(void *arg1, void *arg2)
111855682Smarkm{
111955682Smarkm	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
112055682Smarkm	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
112155682Smarkm	long dummy, flp1, flp2;
112255682Smarkm
112355682Smarkm	(void) get_io_stats(p1, &dummy, &dummy, &dummy, &dummy, &flp1);
112455682Smarkm	(void) get_io_stats(p2, &dummy, &dummy, &dummy, &dummy, &flp2);
112555682Smarkm
112655682Smarkm	return (flp2 - flp1);
112755682Smarkm}
112855682Smarkm#endif /* ORDER */
112955682Smarkm
113055682Smarkm/*
113155682Smarkm * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
113255682Smarkm *		the process does not exist.
113355682Smarkm *		It is EXTREMLY IMPORTANT that this function work correctly.
113455682Smarkm *		If top runs setuid root (as in SVR4), then this function
113555682Smarkm *		is the only thing that stands in the way of a serious
113655682Smarkm *		security problem.  It validates requests for the "kill"
113755682Smarkm *		and "renice" commands.
113855682Smarkm */
113955682Smarkm
114055682Smarkmint
114155682Smarkmproc_owner(int pid)
114255682Smarkm{
114355682Smarkm	int cnt;
114455682Smarkm	struct kinfo_proc **prefp;
114555682Smarkm	struct kinfo_proc *pp;
114655682Smarkm
114755682Smarkm	prefp = pref;
114855682Smarkm	cnt = pref_len;
114955682Smarkm	while (--cnt >= 0) {
115055682Smarkm		pp = *prefp++;
115155682Smarkm		if (pp->ki_pid == (pid_t)pid)
115255682Smarkm			return ((int)pp->ki_ruid);
115355682Smarkm	}
115455682Smarkm	return (-1);
115555682Smarkm}
115655682Smarkm
115755682Smarkmstatic int
115855682Smarkmswapmode(int *retavail, int *retfree)
115955682Smarkm{
116072445Sassar	int n;
1161178825Sdfr	int pagesize = getpagesize();
116255682Smarkm	struct kvm_swap swapary[1];
1163178825Sdfr
1164178825Sdfr	*retavail = 0;
1165178825Sdfr	*retfree = 0;
1166120945Snectar
1167178825Sdfr#define CONVERT(v)	((quad_t)(v) * pagesize / 1024)
116855682Smarkm
116955682Smarkm	n = kvm_getswapinfo(kd, swapary, 1, 0);
117055682Smarkm	if (n < 0 || swapary[0].ksw_total == 0)
117155682Smarkm		return (0);
117255682Smarkm
117355682Smarkm	*retavail = CONVERT(swapary[0].ksw_total);
1174178825Sdfr	*retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used);
1175178825Sdfr
1176178825Sdfr	n = (int)(swapary[0].ksw_used * 100.0 / swapary[0].ksw_total);
1177178825Sdfr	return (n);
1178178825Sdfr}
1179178825Sdfr