xref: /freebsd/usr.bin/top/machine.c (revision e19249f7a74c3437340bf48888d4325b36be5a15)
1511d9c65SJoerg Wunsch /*
2511d9c65SJoerg Wunsch  * top - a top users display for Unix
3511d9c65SJoerg Wunsch  *
433d56839SNick Hibma  * SYNOPSIS:  For FreeBSD-2.x and later
5511d9c65SJoerg Wunsch  *
6511d9c65SJoerg Wunsch  * DESCRIPTION:
7511d9c65SJoerg Wunsch  * Originally written for BSD4.4 system by Christos Zoulas.
8511d9c65SJoerg Wunsch  * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider
9f3b2c2d1SWolfram Schneider  * Order support hacked in from top-3.5beta6/machine/m_aix41.c
10f3b2c2d1SWolfram Schneider  *   by Monte Mitzelfelt (for latest top see http://www.groupsys.com/topinfo/)
11511d9c65SJoerg Wunsch  *
12511d9c65SJoerg Wunsch  * This is the machine-dependent module for FreeBSD 2.2
13511d9c65SJoerg Wunsch  * Works for:
1433d56839SNick Hibma  *	FreeBSD 2.2.x, 3.x, 4.x, and probably FreeBSD 2.1.x
15511d9c65SJoerg Wunsch  *
16511d9c65SJoerg Wunsch  * LIBS: -lkvm
17511d9c65SJoerg Wunsch  *
18511d9c65SJoerg Wunsch  * AUTHOR:  Christos Zoulas <christos@ee.cornell.edu>
19511d9c65SJoerg Wunsch  *          Steven Wallace  <swallace@freebsd.org>
20511d9c65SJoerg Wunsch  *          Wolfram Schneider <wosch@FreeBSD.org>
2139d513ecSRobert Watson  *          Thomas Moestl <tmoestl@gmx.net>
22511d9c65SJoerg Wunsch  *
23c3aac50fSPeter Wemm  * $FreeBSD$
24511d9c65SJoerg Wunsch  */
25511d9c65SJoerg Wunsch 
26511d9c65SJoerg Wunsch #include <sys/param.h>
27511d9c65SJoerg Wunsch #include <sys/errno.h>
28511d9c65SJoerg Wunsch #include <sys/file.h>
29511d9c65SJoerg Wunsch #include <sys/proc.h>
30e5aff02fSPeter Wemm #include <sys/resource.h>
31e5aff02fSPeter Wemm #include <sys/rtprio.h>
32cd23263cSDag-Erling Smørgrav #include <sys/signal.h>
33cd23263cSDag-Erling Smørgrav #include <sys/sysctl.h>
34cd23263cSDag-Erling Smørgrav #include <sys/time.h>
35cd23263cSDag-Erling Smørgrav #include <sys/user.h>
36cd23263cSDag-Erling Smørgrav #include <sys/vmmeter.h>
37511d9c65SJoerg Wunsch 
38cd23263cSDag-Erling Smørgrav #include <kvm.h>
39cd23263cSDag-Erling Smørgrav #include <math.h>
40cd23263cSDag-Erling Smørgrav #include <nlist.h>
414946a00bSDag-Erling Smørgrav #include <paths.h>
42cd23263cSDag-Erling Smørgrav #include <pwd.h>
43cd23263cSDag-Erling Smørgrav #include <stdio.h>
44511d9c65SJoerg Wunsch #include <stdlib.h>
4542649453SStefan Farfeleder #include <string.h>
4642649453SStefan Farfeleder #include <strings.h>
4739d513ecSRobert Watson #include <unistd.h>
48faac60c8SStanislav Sedov #include <vis.h>
49511d9c65SJoerg Wunsch 
50511d9c65SJoerg Wunsch #include "top.h"
51511d9c65SJoerg Wunsch #include "machine.h"
527f18d5d3SJohn Baldwin #include "screen.h"
5339d513ecSRobert Watson #include "utils.h"
54511d9c65SJoerg Wunsch 
5539d513ecSRobert Watson #define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
56c413702aSDavid E. O'Brien #define	SMPUNAMELEN	13
57c413702aSDavid E. O'Brien #define	UPUNAMELEN	15
5839d513ecSRobert Watson 
5932efd263SGiorgos Keramidas extern struct process_select ps;
603f330d7dSWarner Losh extern char* printable(char *);
6194154ff8SPeter Wemm static int smpmode;
62db6bb7fcSAlfred Perlstein enum displaymodes displaymode;
63c413702aSDavid E. O'Brien static int namelength = 8;
647f18d5d3SJohn Baldwin static int cmdlengthdelta;
65511d9c65SJoerg Wunsch 
6639d513ecSRobert Watson /* Prototypes for top internals */
673f330d7dSWarner Losh void quit(int);
68511d9c65SJoerg Wunsch 
69511d9c65SJoerg Wunsch /* get_process_info passes back a handle.  This is what it looks like: */
70511d9c65SJoerg Wunsch 
71789e3877SBruce Evans struct handle {
72511d9c65SJoerg Wunsch 	struct kinfo_proc **next_proc;	/* points to next valid proc pointer */
73511d9c65SJoerg Wunsch 	int remaining;			/* number of pointers remaining */
74511d9c65SJoerg Wunsch };
75511d9c65SJoerg Wunsch 
76511d9c65SJoerg Wunsch /* declarations for load_avg */
77511d9c65SJoerg Wunsch #include "loadavg.h"
78511d9c65SJoerg Wunsch 
79511d9c65SJoerg Wunsch /* define what weighted cpu is.  */
801f7d2501SKirk McKusick #define weighted_cpu(pct, pp) ((pp)->ki_swtime == 0 ? 0.0 : \
811f7d2501SKirk McKusick 			 ((pct) / (1.0 - exp((pp)->ki_swtime * logcpu))))
82511d9c65SJoerg Wunsch 
83511d9c65SJoerg Wunsch /* what we consider to be process size: */
841f7d2501SKirk McKusick #define PROCSIZE(pp) ((pp)->ki_size / 1024)
85511d9c65SJoerg Wunsch 
86db6bb7fcSAlfred Perlstein #define RU(pp)	(&(pp)->ki_rusage)
87db6bb7fcSAlfred Perlstein #define RUTOT(pp) \
88db6bb7fcSAlfred Perlstein 	(RU(pp)->ru_inblock + RU(pp)->ru_oublock + RU(pp)->ru_majflt)
89db6bb7fcSAlfred Perlstein 
90db6bb7fcSAlfred Perlstein 
91511d9c65SJoerg Wunsch /* definitions for indices in the nlist array */
92511d9c65SJoerg Wunsch 
93511d9c65SJoerg Wunsch /*
94511d9c65SJoerg Wunsch  *  These definitions control the format of the per-process area
95511d9c65SJoerg Wunsch  */
96511d9c65SJoerg Wunsch 
97db6bb7fcSAlfred Perlstein static char io_header[] =
986000ced1SRong-En Fan     "  PID%s %-*.*s   VCSW  IVCSW   READ  WRITE  FAULT  TOTAL PERCENT COMMAND";
99db6bb7fcSAlfred Perlstein 
100db6bb7fcSAlfred Perlstein #define io_Proc_format \
1016000ced1SRong-En Fan     "%5d%s %-*.*s %6ld %6ld %6ld %6ld %6ld %6ld %6.2f%% %.*s"
102db6bb7fcSAlfred Perlstein 
10332efd263SGiorgos Keramidas static char smp_header_thr[] =
1046000ced1SRong-En Fan     "  PID%s %-*.*s  THR PRI NICE   SIZE    RES STATE  C   TIME %6s COMMAND";
10594154ff8SPeter Wemm static char smp_header[] =
1066000ced1SRong-En Fan     "  PID%s %-*.*s "   "PRI NICE   SIZE    RES STATE  C   TIME %6s COMMAND";
107511d9c65SJoerg Wunsch 
10894154ff8SPeter Wemm #define smp_Proc_format \
1096000ced1SRong-En Fan     "%5d%s %-*.*s %s%3d %4s%7s %6s %-6.6s %1x%7s %5.2f%% %.*s"
110511d9c65SJoerg Wunsch 
11132efd263SGiorgos Keramidas static char up_header_thr[] =
1126000ced1SRong-En Fan     "  PID%s %-*.*s  THR PRI NICE   SIZE    RES STATE    TIME %6s COMMAND";
11394154ff8SPeter Wemm static char up_header[] =
1146000ced1SRong-En Fan     "  PID%s %-*.*s "   "PRI NICE   SIZE    RES STATE    TIME %6s COMMAND";
115511d9c65SJoerg Wunsch 
11694154ff8SPeter Wemm #define up_Proc_format \
1176000ced1SRong-En Fan     "%5d%s %-*.*s %s%3d %4s%7s %6s %-6.6s%.0d%7s %5.2f%% %.*s"
118511d9c65SJoerg Wunsch 
119511d9c65SJoerg Wunsch 
120511d9c65SJoerg Wunsch /* process state names for the "STATE" column of the display */
121511d9c65SJoerg Wunsch /* the extra nulls in the string "run" are for adding a slash and
122511d9c65SJoerg Wunsch    the processor number when needed */
123511d9c65SJoerg Wunsch 
124789e3877SBruce Evans char *state_abbrev[] = {
1250d632649SJohn Baldwin 	"", "START", "RUN\0\0\0", "SLEEP", "STOP", "ZOMB", "WAIT", "LOCK"
126511d9c65SJoerg Wunsch };
127511d9c65SJoerg Wunsch 
128511d9c65SJoerg Wunsch 
129511d9c65SJoerg Wunsch static kvm_t *kd;
130511d9c65SJoerg Wunsch 
131511d9c65SJoerg Wunsch /* values that we stash away in _init and use in later routines */
132511d9c65SJoerg Wunsch 
133511d9c65SJoerg Wunsch static double logcpu;
134511d9c65SJoerg Wunsch 
135511d9c65SJoerg Wunsch /* these are retrieved from the kernel in _init */
136511d9c65SJoerg Wunsch 
137511d9c65SJoerg Wunsch static load_avg  ccpu;
138511d9c65SJoerg Wunsch 
13939d513ecSRobert Watson /* these are used in the get_ functions */
140511d9c65SJoerg Wunsch 
14139d513ecSRobert Watson static int lastpid;
142511d9c65SJoerg Wunsch 
143511d9c65SJoerg Wunsch /* these are for calculating cpu state percentages */
144511d9c65SJoerg Wunsch 
145511d9c65SJoerg Wunsch static long cp_time[CPUSTATES];
146511d9c65SJoerg Wunsch static long cp_old[CPUSTATES];
147511d9c65SJoerg Wunsch static long cp_diff[CPUSTATES];
148511d9c65SJoerg Wunsch 
149511d9c65SJoerg Wunsch /* these are for detailing the process states */
150511d9c65SJoerg Wunsch 
1510384fff8SJason Evans int process_states[8];
152511d9c65SJoerg Wunsch char *procstatenames[] = {
153511d9c65SJoerg Wunsch 	"", " starting, ", " running, ", " sleeping, ", " stopped, ",
1540d632649SJohn Baldwin 	" zombie, ", " waiting, ", " lock, ",
155511d9c65SJoerg Wunsch 	NULL
156511d9c65SJoerg Wunsch };
157511d9c65SJoerg Wunsch 
158511d9c65SJoerg Wunsch /* these are for detailing the cpu states */
159511d9c65SJoerg Wunsch 
160511d9c65SJoerg Wunsch int cpu_states[CPUSTATES];
161511d9c65SJoerg Wunsch char *cpustatenames[] = {
162511d9c65SJoerg Wunsch 	"user", "nice", "system", "interrupt", "idle", NULL
163511d9c65SJoerg Wunsch };
164511d9c65SJoerg Wunsch 
165511d9c65SJoerg Wunsch /* these are for detailing the memory statistics */
166511d9c65SJoerg Wunsch 
167511d9c65SJoerg Wunsch int memory_stats[7];
168511d9c65SJoerg Wunsch char *memorynames[] = {
169789e3877SBruce Evans 	"K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ",
170789e3877SBruce Evans 	"K Free", NULL
171511d9c65SJoerg Wunsch };
172511d9c65SJoerg Wunsch 
173511d9c65SJoerg Wunsch int swap_stats[7];
174511d9c65SJoerg Wunsch char *swapnames[] = {
175511d9c65SJoerg Wunsch 	"K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out",
176511d9c65SJoerg Wunsch 	NULL
177511d9c65SJoerg Wunsch };
178511d9c65SJoerg Wunsch 
179511d9c65SJoerg Wunsch 
180511d9c65SJoerg Wunsch /* these are for keeping track of the proc array */
181511d9c65SJoerg Wunsch 
182511d9c65SJoerg Wunsch static int nproc;
183511d9c65SJoerg Wunsch static int onproc = -1;
184511d9c65SJoerg Wunsch static int pref_len;
185511d9c65SJoerg Wunsch static struct kinfo_proc *pbase;
186511d9c65SJoerg Wunsch static struct kinfo_proc **pref;
187db6bb7fcSAlfred Perlstein static struct kinfo_proc *previous_procs;
188db6bb7fcSAlfred Perlstein static struct kinfo_proc **previous_pref;
189db6bb7fcSAlfred Perlstein static int previous_proc_count = 0;
190db6bb7fcSAlfred Perlstein static int previous_proc_count_max = 0;
191511d9c65SJoerg Wunsch 
1927fe9a86aSAlfred Perlstein /* total number of io operations */
1937fe9a86aSAlfred Perlstein static long total_inblock;
1947fe9a86aSAlfred Perlstein static long total_oublock;
1957fe9a86aSAlfred Perlstein static long total_majflt;
1967fe9a86aSAlfred Perlstein 
197511d9c65SJoerg Wunsch /* these are for getting the memory statistics */
198511d9c65SJoerg Wunsch 
199511d9c65SJoerg Wunsch static int pageshift;		/* log base 2 of the pagesize */
200511d9c65SJoerg Wunsch 
201511d9c65SJoerg Wunsch /* define pagetok in terms of pageshift */
202511d9c65SJoerg Wunsch 
203511d9c65SJoerg Wunsch #define pagetok(size) ((size) << pageshift)
204511d9c65SJoerg Wunsch 
205511d9c65SJoerg Wunsch /* useful externals */
206511d9c65SJoerg Wunsch long percentages();
207511d9c65SJoerg Wunsch 
208f3b2c2d1SWolfram Schneider #ifdef ORDER
20926b2243aSGiorgos Keramidas /*
21032efd263SGiorgos Keramidas  * Sorting orders.  The first element is the default.
21126b2243aSGiorgos Keramidas  */
2125d320d4bSAlfred Perlstein char *ordernames[] = {
21332efd263SGiorgos Keramidas 	"cpu", "size", "res", "time", "pri", "threads",
2146000ced1SRong-En Fan 	"total", "read", "write", "fault", "vcsw", "ivcsw",
2156000ced1SRong-En Fan 	"jid", NULL
21626b2243aSGiorgos Keramidas };
217f3b2c2d1SWolfram Schneider #endif
218f3b2c2d1SWolfram Schneider 
2196000ced1SRong-En Fan static int compare_jid(const void *a, const void *b);
220de916c8bSBruce Evans static int compare_pid(const void *a, const void *b);
221de916c8bSBruce Evans static const char *format_nice(const struct kinfo_proc *pp);
222de916c8bSBruce Evans static void getsysctl(const char *name, void *ptr, size_t len);
223de916c8bSBruce Evans static int swapmode(int *retavail, int *retfree);
224de916c8bSBruce Evans 
225511d9c65SJoerg Wunsch int
226f6a10feaSDag-Erling Smørgrav machine_init(struct statics *statics)
227511d9c65SJoerg Wunsch {
228970636e9SAlfred Perlstein 	int pagesize;
22998e53e5bSAndrew Gallatin 	size_t modelen;
230a2aff8b2SPeter Wemm 	struct passwd *pw;
23194154ff8SPeter Wemm 
23294154ff8SPeter Wemm 	modelen = sizeof(smpmode);
233789e3877SBruce Evans 	if ((sysctlbyname("machdep.smp_active", &smpmode, &modelen,
234789e3877SBruce Evans 	    NULL, 0) != 0 &&
235789e3877SBruce Evans 	    sysctlbyname("kern.smp.active", &smpmode, &modelen,
236789e3877SBruce Evans 	    NULL, 0) != 0) ||
23794154ff8SPeter Wemm 	    modelen != sizeof(smpmode))
23894154ff8SPeter Wemm 		smpmode = 0;
239511d9c65SJoerg Wunsch 
240a2aff8b2SPeter Wemm 	while ((pw = getpwent()) != NULL) {
241a2aff8b2SPeter Wemm 		if (strlen(pw->pw_name) > namelength)
242a2aff8b2SPeter Wemm 			namelength = strlen(pw->pw_name);
243a2aff8b2SPeter Wemm 	}
244c413702aSDavid E. O'Brien 	if (smpmode && namelength > SMPUNAMELEN)
245c413702aSDavid E. O'Brien 		namelength = SMPUNAMELEN;
246c413702aSDavid E. O'Brien 	else if (namelength > UPUNAMELEN)
247c413702aSDavid E. O'Brien 		namelength = UPUNAMELEN;
248a2aff8b2SPeter Wemm 
2494946a00bSDag-Erling Smørgrav 	kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
2504946a00bSDag-Erling Smørgrav 	if (kd == NULL)
2514946a00bSDag-Erling Smørgrav 		return (-1);
252511d9c65SJoerg Wunsch 
25339d513ecSRobert Watson 	GETSYSCTL("kern.ccpu", ccpu);
254511d9c65SJoerg Wunsch 
255511d9c65SJoerg Wunsch 	/* this is used in calculating WCPU -- calculate it ahead of time */
256511d9c65SJoerg Wunsch 	logcpu = log(loaddouble(ccpu));
257511d9c65SJoerg Wunsch 
258511d9c65SJoerg Wunsch 	pbase = NULL;
259511d9c65SJoerg Wunsch 	pref = NULL;
260511d9c65SJoerg Wunsch 	nproc = 0;
261511d9c65SJoerg Wunsch 	onproc = -1;
262789e3877SBruce Evans 
263789e3877SBruce Evans 	/* get the page size and calculate pageshift from it */
264511d9c65SJoerg Wunsch 	pagesize = getpagesize();
265511d9c65SJoerg Wunsch 	pageshift = 0;
2664946a00bSDag-Erling Smørgrav 	while (pagesize > 1) {
267511d9c65SJoerg Wunsch 		pageshift++;
268511d9c65SJoerg Wunsch 		pagesize >>= 1;
269511d9c65SJoerg Wunsch 	}
270511d9c65SJoerg Wunsch 
271511d9c65SJoerg Wunsch 	/* we only need the amount of log(2)1024 for our conversion */
272511d9c65SJoerg Wunsch 	pageshift -= LOG1024;
273511d9c65SJoerg Wunsch 
274511d9c65SJoerg Wunsch 	/* fill in the statics information */
275511d9c65SJoerg Wunsch 	statics->procstate_names = procstatenames;
276511d9c65SJoerg Wunsch 	statics->cpustate_names = cpustatenames;
277511d9c65SJoerg Wunsch 	statics->memory_names = memorynames;
278511d9c65SJoerg Wunsch 	statics->swap_names = swapnames;
279f3b2c2d1SWolfram Schneider #ifdef ORDER
2805d320d4bSAlfred Perlstein 	statics->order_names = ordernames;
281f3b2c2d1SWolfram Schneider #endif
282511d9c65SJoerg Wunsch 
283511d9c65SJoerg Wunsch 	/* all done! */
284511d9c65SJoerg Wunsch 	return (0);
285511d9c65SJoerg Wunsch }
286511d9c65SJoerg Wunsch 
287970636e9SAlfred Perlstein char *
288f6a10feaSDag-Erling Smørgrav format_header(char *uname_field)
289511d9c65SJoerg Wunsch {
290a2aff8b2SPeter Wemm 	static char Header[128];
291db6bb7fcSAlfred Perlstein 	const char *prehead;
292511d9c65SJoerg Wunsch 
293db6bb7fcSAlfred Perlstein 	switch (displaymode) {
294db6bb7fcSAlfred Perlstein 	case DISP_CPU:
29532efd263SGiorgos Keramidas 		/*
29632efd263SGiorgos Keramidas 		 * The logic of picking the right header format seems reverse
29732efd263SGiorgos Keramidas 		 * here because we only want to display a THR column when
29832efd263SGiorgos Keramidas 		 * "thread mode" is off (and threads are not listed as
29932efd263SGiorgos Keramidas 		 * separate lines).
30032efd263SGiorgos Keramidas 		 */
30132efd263SGiorgos Keramidas 		prehead = smpmode ?
30232efd263SGiorgos Keramidas 		    (ps.thread ? smp_header : smp_header_thr) :
30332efd263SGiorgos Keramidas 		    (ps.thread ? up_header : up_header_thr);
304bbf750fbSGiorgos Keramidas 		snprintf(Header, sizeof(Header), prehead,
3056000ced1SRong-En Fan 		    ps.jail ? " JID" : "",
306bbf750fbSGiorgos Keramidas 		    namelength, namelength, uname_field,
307bbf750fbSGiorgos Keramidas 		    ps.wcpu ? "WCPU" : "CPU");
308db6bb7fcSAlfred Perlstein 		break;
309db6bb7fcSAlfred Perlstein 	case DISP_IO:
310db6bb7fcSAlfred Perlstein 		prehead = io_header;
311db6bb7fcSAlfred Perlstein 		snprintf(Header, sizeof(Header), prehead,
3126000ced1SRong-En Fan 		    ps.jail ? " JID" : "",
313a2aff8b2SPeter Wemm 		    namelength, namelength, uname_field);
314bbf750fbSGiorgos Keramidas 		break;
315bbf750fbSGiorgos Keramidas 	}
3167f18d5d3SJohn Baldwin 	cmdlengthdelta = strlen(Header) - 7;
317ea9e70bfSDag-Erling Smørgrav 	return (Header);
318511d9c65SJoerg Wunsch }
319511d9c65SJoerg Wunsch 
320511d9c65SJoerg Wunsch static int swappgsin = -1;
321511d9c65SJoerg Wunsch static int swappgsout = -1;
322511d9c65SJoerg Wunsch extern struct timeval timeout;
323511d9c65SJoerg Wunsch 
324511d9c65SJoerg Wunsch void
325f6a10feaSDag-Erling Smørgrav get_system_info(struct system_info *si)
326511d9c65SJoerg Wunsch {
327511d9c65SJoerg Wunsch 	long total;
32898e53e5bSAndrew Gallatin 	struct loadavg sysload;
329a2641311SDavid E. O'Brien 	int mib[2];
330a2641311SDavid E. O'Brien 	struct timeval boottime;
331a2641311SDavid E. O'Brien 	size_t bt_size;
3324946a00bSDag-Erling Smørgrav 	int i;
333511d9c65SJoerg Wunsch 
334511d9c65SJoerg Wunsch 	/* get the cp_time array */
33539d513ecSRobert Watson 	GETSYSCTL("kern.cp_time", cp_time);
33698e53e5bSAndrew Gallatin 	GETSYSCTL("vm.loadavg", sysload);
33739d513ecSRobert Watson 	GETSYSCTL("kern.lastpid", lastpid);
338511d9c65SJoerg Wunsch 
339511d9c65SJoerg Wunsch 	/* convert load averages to doubles */
340511d9c65SJoerg Wunsch 	for (i = 0; i < 3; i++)
3414946a00bSDag-Erling Smørgrav 		si->load_avg[i] = (double)sysload.ldavg[i] / sysload.fscale;
342511d9c65SJoerg Wunsch 
343511d9c65SJoerg Wunsch 	/* convert cp_time counts to percentages */
344511d9c65SJoerg Wunsch 	total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
345511d9c65SJoerg Wunsch 
346511d9c65SJoerg Wunsch 	/* sum memory & swap statistics */
347511d9c65SJoerg Wunsch 	{
348511d9c65SJoerg Wunsch 		static unsigned int swap_delay = 0;
349511d9c65SJoerg Wunsch 		static int swapavail = 0;
350511d9c65SJoerg Wunsch 		static int swapfree = 0;
351511d9c65SJoerg Wunsch 		static int bufspace = 0;
35239d513ecSRobert Watson 		static int nspgsin, nspgsout;
353511d9c65SJoerg Wunsch 
35439d513ecSRobert Watson 		GETSYSCTL("vfs.bufspace", bufspace);
35539d513ecSRobert Watson 		GETSYSCTL("vm.stats.vm.v_active_count", memory_stats[0]);
35639d513ecSRobert Watson 		GETSYSCTL("vm.stats.vm.v_inactive_count", memory_stats[1]);
35739d513ecSRobert Watson 		GETSYSCTL("vm.stats.vm.v_wire_count", memory_stats[2]);
35839d513ecSRobert Watson 		GETSYSCTL("vm.stats.vm.v_cache_count", memory_stats[3]);
35939d513ecSRobert Watson 		GETSYSCTL("vm.stats.vm.v_free_count", memory_stats[5]);
36039d513ecSRobert Watson 		GETSYSCTL("vm.stats.vm.v_swappgsin", nspgsin);
36139d513ecSRobert Watson 		GETSYSCTL("vm.stats.vm.v_swappgsout", nspgsout);
362511d9c65SJoerg Wunsch 		/* convert memory stats to Kbytes */
3636243f7acSThomas Moestl 		memory_stats[0] = pagetok(memory_stats[0]);
3646243f7acSThomas Moestl 		memory_stats[1] = pagetok(memory_stats[1]);
3656243f7acSThomas Moestl 		memory_stats[2] = pagetok(memory_stats[2]);
3666243f7acSThomas Moestl 		memory_stats[3] = pagetok(memory_stats[3]);
367511d9c65SJoerg Wunsch 		memory_stats[4] = bufspace / 1024;
3686243f7acSThomas Moestl 		memory_stats[5] = pagetok(memory_stats[5]);
369511d9c65SJoerg Wunsch 		memory_stats[6] = -1;
370511d9c65SJoerg Wunsch 
371511d9c65SJoerg Wunsch 		/* first interval */
372511d9c65SJoerg Wunsch 		if (swappgsin < 0) {
373511d9c65SJoerg Wunsch 			swap_stats[4] = 0;
374511d9c65SJoerg Wunsch 			swap_stats[5] = 0;
375511d9c65SJoerg Wunsch 		}
376511d9c65SJoerg Wunsch 
377511d9c65SJoerg Wunsch 		/* compute differences between old and new swap statistic */
378511d9c65SJoerg Wunsch 		else {
37939d513ecSRobert Watson 			swap_stats[4] = pagetok(((nspgsin - swappgsin)));
38039d513ecSRobert Watson 			swap_stats[5] = pagetok(((nspgsout - swappgsout)));
381511d9c65SJoerg Wunsch 		}
382511d9c65SJoerg Wunsch 
38339d513ecSRobert Watson 		swappgsin = nspgsin;
38439d513ecSRobert Watson 		swappgsout = nspgsout;
385511d9c65SJoerg Wunsch 
386511d9c65SJoerg Wunsch 		/* call CPU heavy swapmode() only for changes */
387511d9c65SJoerg Wunsch 		if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) {
388511d9c65SJoerg Wunsch 			swap_stats[3] = swapmode(&swapavail, &swapfree);
389511d9c65SJoerg Wunsch 			swap_stats[0] = swapavail;
390511d9c65SJoerg Wunsch 			swap_stats[1] = swapavail - swapfree;
391511d9c65SJoerg Wunsch 			swap_stats[2] = swapfree;
392511d9c65SJoerg Wunsch 		}
393511d9c65SJoerg Wunsch 		swap_delay = 1;
394511d9c65SJoerg Wunsch 		swap_stats[6] = -1;
395511d9c65SJoerg Wunsch 	}
396511d9c65SJoerg Wunsch 
397511d9c65SJoerg Wunsch 	/* set arrays and strings */
398511d9c65SJoerg Wunsch 	si->cpustates = cpu_states;
399511d9c65SJoerg Wunsch 	si->memory = memory_stats;
400511d9c65SJoerg Wunsch 	si->swap = swap_stats;
401511d9c65SJoerg Wunsch 
402511d9c65SJoerg Wunsch 
403511d9c65SJoerg Wunsch 	if (lastpid > 0) {
404511d9c65SJoerg Wunsch 		si->last_pid = lastpid;
405511d9c65SJoerg Wunsch 	} else {
406511d9c65SJoerg Wunsch 		si->last_pid = -1;
407511d9c65SJoerg Wunsch 	}
408a2641311SDavid E. O'Brien 
409a2641311SDavid E. O'Brien 	/*
410a2641311SDavid E. O'Brien 	 * Print how long system has been up.
411a2641311SDavid E. O'Brien 	 * (Found by looking getting "boottime" from the kernel)
412a2641311SDavid E. O'Brien 	 */
413a2641311SDavid E. O'Brien 	mib[0] = CTL_KERN;
414a2641311SDavid E. O'Brien 	mib[1] = KERN_BOOTTIME;
415a2641311SDavid E. O'Brien 	bt_size = sizeof(boottime);
416a2641311SDavid E. O'Brien 	if (sysctl(mib, 2, &boottime, &bt_size, NULL, 0) != -1 &&
417a2641311SDavid E. O'Brien 	    boottime.tv_sec != 0) {
418a2641311SDavid E. O'Brien 		si->boottime = boottime;
419a2641311SDavid E. O'Brien 	} else {
420a2641311SDavid E. O'Brien 		si->boottime.tv_sec = -1;
421a2641311SDavid E. O'Brien 	}
422511d9c65SJoerg Wunsch }
423511d9c65SJoerg Wunsch 
42498c151d6SAlfred Perlstein #define NOPROC	((void *)-1)
42598c151d6SAlfred Perlstein 
426dcd6f4bdSAlfred Perlstein /*
427dcd6f4bdSAlfred Perlstein  * We need to compare data from the old process entry with the new
428dcd6f4bdSAlfred Perlstein  * process entry.
429dcd6f4bdSAlfred Perlstein  * To facilitate doing this quickly we stash a pointer in the kinfo_proc
430dcd6f4bdSAlfred Perlstein  * structure to cache the mapping.  We also use a negative cache pointer
431dcd6f4bdSAlfred Perlstein  * of NOPROC to avoid duplicate lookups.
432dcd6f4bdSAlfred Perlstein  * XXX: this could be done when the actual processes are fetched, we do
433dcd6f4bdSAlfred Perlstein  * it here out of laziness.
434dcd6f4bdSAlfred Perlstein  */
435db6bb7fcSAlfred Perlstein const struct kinfo_proc *
436db6bb7fcSAlfred Perlstein get_old_proc(struct kinfo_proc *pp)
437db6bb7fcSAlfred Perlstein {
438db6bb7fcSAlfred Perlstein 	struct kinfo_proc **oldpp, *oldp;
439db6bb7fcSAlfred Perlstein 
440dcd6f4bdSAlfred Perlstein 	/*
441dcd6f4bdSAlfred Perlstein 	 * If this is the first fetch of the kinfo_procs then we don't have
442dcd6f4bdSAlfred Perlstein 	 * any previous entries.
443dcd6f4bdSAlfred Perlstein 	 */
444db6bb7fcSAlfred Perlstein 	if (previous_proc_count == 0)
445db6bb7fcSAlfred Perlstein 		return (NULL);
446dcd6f4bdSAlfred Perlstein 	/* negative cache? */
44798c151d6SAlfred Perlstein 	if (pp->ki_udata == NOPROC)
44898c151d6SAlfred Perlstein 		return (NULL);
449dcd6f4bdSAlfred Perlstein 	/* cached? */
45098c151d6SAlfred Perlstein 	if (pp->ki_udata != NULL)
45198c151d6SAlfred Perlstein 		return (pp->ki_udata);
452dcd6f4bdSAlfred Perlstein 	/*
453dcd6f4bdSAlfred Perlstein 	 * Not cached,
454dcd6f4bdSAlfred Perlstein 	 * 1) look up based on pid.
455dcd6f4bdSAlfred Perlstein 	 * 2) compare process start.
456dcd6f4bdSAlfred Perlstein 	 * If we fail here, then setup a negative cache entry, otherwise
457dcd6f4bdSAlfred Perlstein 	 * cache it.
458dcd6f4bdSAlfred Perlstein 	 */
459db6bb7fcSAlfred Perlstein 	oldpp = bsearch(&pp, previous_pref, previous_proc_count,
4604946a00bSDag-Erling Smørgrav 	    sizeof(*previous_pref), compare_pid);
46198c151d6SAlfred Perlstein 	if (oldpp == NULL) {
46298c151d6SAlfred Perlstein 		pp->ki_udata = NOPROC;
463db6bb7fcSAlfred Perlstein 		return (NULL);
46498c151d6SAlfred Perlstein 	}
465db6bb7fcSAlfred Perlstein 	oldp = *oldpp;
46698c151d6SAlfred Perlstein 	if (bcmp(&oldp->ki_start, &pp->ki_start, sizeof(pp->ki_start)) != 0) {
46798c151d6SAlfred Perlstein 		pp->ki_udata = NOPROC;
468db6bb7fcSAlfred Perlstein 		return (NULL);
46998c151d6SAlfred Perlstein 	}
47098c151d6SAlfred Perlstein 	pp->ki_udata = oldp;
471db6bb7fcSAlfred Perlstein 	return (oldp);
472db6bb7fcSAlfred Perlstein }
473db6bb7fcSAlfred Perlstein 
474dcd6f4bdSAlfred Perlstein /*
475dcd6f4bdSAlfred Perlstein  * Return the total amount of IO done in blocks in/out and faults.
476dcd6f4bdSAlfred Perlstein  * store the values individually in the pointers passed in.
477dcd6f4bdSAlfred Perlstein  */
478db6bb7fcSAlfred Perlstein long
479789e3877SBruce Evans get_io_stats(struct kinfo_proc *pp, long *inp, long *oup, long *flp,
480789e3877SBruce Evans     long *vcsw, long *ivcsw)
481db6bb7fcSAlfred Perlstein {
482db6bb7fcSAlfred Perlstein 	const struct kinfo_proc *oldp;
483db6bb7fcSAlfred Perlstein 	static struct kinfo_proc dummy;
484db6bb7fcSAlfred Perlstein 	long ret;
485db6bb7fcSAlfred Perlstein 
486db6bb7fcSAlfred Perlstein 	oldp = get_old_proc(pp);
487db6bb7fcSAlfred Perlstein 	if (oldp == NULL) {
488db6bb7fcSAlfred Perlstein 		bzero(&dummy, sizeof(dummy));
489db6bb7fcSAlfred Perlstein 		oldp = &dummy;
490db6bb7fcSAlfred Perlstein 	}
4917fe9a86aSAlfred Perlstein 	*inp = RU(pp)->ru_inblock - RU(oldp)->ru_inblock;
4927fe9a86aSAlfred Perlstein 	*oup = RU(pp)->ru_oublock - RU(oldp)->ru_oublock;
4937fe9a86aSAlfred Perlstein 	*flp = RU(pp)->ru_majflt - RU(oldp)->ru_majflt;
4945d320d4bSAlfred Perlstein 	*vcsw = RU(pp)->ru_nvcsw - RU(oldp)->ru_nvcsw;
4955d320d4bSAlfred Perlstein 	*ivcsw = RU(pp)->ru_nivcsw - RU(oldp)->ru_nivcsw;
496db6bb7fcSAlfred Perlstein 	ret =
497db6bb7fcSAlfred Perlstein 	    (RU(pp)->ru_inblock - RU(oldp)->ru_inblock) +
498db6bb7fcSAlfred Perlstein 	    (RU(pp)->ru_oublock - RU(oldp)->ru_oublock) +
499db6bb7fcSAlfred Perlstein 	    (RU(pp)->ru_majflt - RU(oldp)->ru_majflt);
500db6bb7fcSAlfred Perlstein 	return (ret);
501db6bb7fcSAlfred Perlstein }
502db6bb7fcSAlfred Perlstein 
503dcd6f4bdSAlfred Perlstein /*
504dcd6f4bdSAlfred Perlstein  * Return the total number of block in/out and faults by a process.
505dcd6f4bdSAlfred Perlstein  */
5067fe9a86aSAlfred Perlstein long
5077fe9a86aSAlfred Perlstein get_io_total(struct kinfo_proc *pp)
5087fe9a86aSAlfred Perlstein {
5097fe9a86aSAlfred Perlstein 	long dummy;
5107fe9a86aSAlfred Perlstein 
5115d320d4bSAlfred Perlstein 	return (get_io_stats(pp, &dummy, &dummy, &dummy, &dummy, &dummy));
5127fe9a86aSAlfred Perlstein }
5137fe9a86aSAlfred Perlstein 
514511d9c65SJoerg Wunsch static struct handle handle;
515511d9c65SJoerg Wunsch 
516970636e9SAlfred Perlstein caddr_t
517f6a10feaSDag-Erling Smørgrav get_process_info(struct system_info *si, struct process_select *sel,
5184946a00bSDag-Erling Smørgrav     int (*compare)(const void *, const void *))
519511d9c65SJoerg Wunsch {
520970636e9SAlfred Perlstein 	int i;
521970636e9SAlfred Perlstein 	int total_procs;
5227fe9a86aSAlfred Perlstein 	long p_io;
5235d320d4bSAlfred Perlstein 	long p_inblock, p_oublock, p_majflt, p_vcsw, p_ivcsw;
524970636e9SAlfred Perlstein 	int active_procs;
525970636e9SAlfred Perlstein 	struct kinfo_proc **prefp;
526970636e9SAlfred Perlstein 	struct kinfo_proc *pp;
527cac4b14cSBrian Feldman 	struct kinfo_proc *prev_pp = NULL;
528511d9c65SJoerg Wunsch 
529511d9c65SJoerg Wunsch 	/* these are copied out of sel for speed */
530511d9c65SJoerg Wunsch 	int show_idle;
531e7cdb972SDag-Erling Smørgrav 	int show_self;
532511d9c65SJoerg Wunsch 	int show_system;
533511d9c65SJoerg Wunsch 	int show_uid;
534511d9c65SJoerg Wunsch 	int show_command;
535511d9c65SJoerg Wunsch 
536db6bb7fcSAlfred Perlstein 	/*
537db6bb7fcSAlfred Perlstein 	 * Save the previous process info.
538db6bb7fcSAlfred Perlstein 	 */
539db6bb7fcSAlfred Perlstein 	if (previous_proc_count_max < nproc) {
540db6bb7fcSAlfred Perlstein 		free(previous_procs);
5414946a00bSDag-Erling Smørgrav 		previous_procs = malloc(nproc * sizeof(*previous_procs));
542db6bb7fcSAlfred Perlstein 		free(previous_pref);
5434946a00bSDag-Erling Smørgrav 		previous_pref = malloc(nproc * sizeof(*previous_pref));
544db6bb7fcSAlfred Perlstein 		if (previous_procs == NULL || previous_pref == NULL) {
545db6bb7fcSAlfred Perlstein 			(void) fprintf(stderr, "top: Out of memory.\n");
546db6bb7fcSAlfred Perlstein 			quit(23);
547db6bb7fcSAlfred Perlstein 		}
548db6bb7fcSAlfred Perlstein 		previous_proc_count_max = nproc;
549db6bb7fcSAlfred Perlstein 	}
550db6bb7fcSAlfred Perlstein 	if (nproc) {
551db6bb7fcSAlfred Perlstein 		for (i = 0; i < nproc; i++)
552db6bb7fcSAlfred Perlstein 			previous_pref[i] = &previous_procs[i];
5534946a00bSDag-Erling Smørgrav 		bcopy(pbase, previous_procs, nproc * sizeof(*previous_procs));
554789e3877SBruce Evans 		qsort(previous_pref, nproc, sizeof(*previous_pref),
555789e3877SBruce Evans 		    compare_pid);
556db6bb7fcSAlfred Perlstein 	}
557db6bb7fcSAlfred Perlstein 	previous_proc_count = nproc;
558db6bb7fcSAlfred Perlstein 
559cac4b14cSBrian Feldman 	pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc);
560511d9c65SJoerg Wunsch 	if (nproc > onproc)
5614946a00bSDag-Erling Smørgrav 		pref = realloc(pref, sizeof(*pref) * (onproc = nproc));
562511d9c65SJoerg Wunsch 	if (pref == NULL || pbase == NULL) {
563511d9c65SJoerg Wunsch 		(void) fprintf(stderr, "top: Out of memory.\n");
564511d9c65SJoerg Wunsch 		quit(23);
565511d9c65SJoerg Wunsch 	}
566511d9c65SJoerg Wunsch 	/* get a pointer to the states summary array */
567511d9c65SJoerg Wunsch 	si->procstates = process_states;
568511d9c65SJoerg Wunsch 
569511d9c65SJoerg Wunsch 	/* set up flags which define what we are going to select */
570511d9c65SJoerg Wunsch 	show_idle = sel->idle;
5719b30d697SDag-Erling Smørgrav 	show_self = sel->self == -1;
572511d9c65SJoerg Wunsch 	show_system = sel->system;
573511d9c65SJoerg Wunsch 	show_uid = sel->uid != -1;
574511d9c65SJoerg Wunsch 	show_command = sel->command != NULL;
575511d9c65SJoerg Wunsch 
576511d9c65SJoerg Wunsch 	/* count up process states and get pointers to interesting procs */
577511d9c65SJoerg Wunsch 	total_procs = 0;
578511d9c65SJoerg Wunsch 	active_procs = 0;
5797fe9a86aSAlfred Perlstein 	total_inblock = 0;
5807fe9a86aSAlfred Perlstein 	total_oublock = 0;
5817fe9a86aSAlfred Perlstein 	total_majflt = 0;
582511d9c65SJoerg Wunsch 	memset((char *)process_states, 0, sizeof(process_states));
583511d9c65SJoerg Wunsch 	prefp = pref;
5844946a00bSDag-Erling Smørgrav 	for (pp = pbase, i = 0; i < nproc; pp++, i++) {
5857fe9a86aSAlfred Perlstein 
586d62a717dSDag-Erling Smørgrav 		if (pp->ki_stat == 0)
587d62a717dSDag-Erling Smørgrav 			/* not in use */
588d62a717dSDag-Erling Smørgrav 			continue;
589d62a717dSDag-Erling Smørgrav 
590d62a717dSDag-Erling Smørgrav 		if (!show_self && pp->ki_pid == sel->self)
591d62a717dSDag-Erling Smørgrav 			/* skip self */
592d62a717dSDag-Erling Smørgrav 			continue;
593d62a717dSDag-Erling Smørgrav 
594d62a717dSDag-Erling Smørgrav 		if (!show_system && (pp->ki_flag & P_SYSTEM))
595d62a717dSDag-Erling Smørgrav 			/* skip system process */
596d62a717dSDag-Erling Smørgrav 			continue;
597d62a717dSDag-Erling Smørgrav 
598789e3877SBruce Evans 		p_io = get_io_stats(pp, &p_inblock, &p_oublock, &p_majflt,
599789e3877SBruce Evans 		    &p_vcsw, &p_ivcsw);
6007fe9a86aSAlfred Perlstein 		total_inblock += p_inblock;
6017fe9a86aSAlfred Perlstein 		total_oublock += p_oublock;
6027fe9a86aSAlfred Perlstein 		total_majflt += p_majflt;
603511d9c65SJoerg Wunsch 		total_procs++;
6044946a00bSDag-Erling Smørgrav 		process_states[pp->ki_stat]++;
605d62a717dSDag-Erling Smørgrav 
606d62a717dSDag-Erling Smørgrav 		if (pp->ki_stat == SZOMB)
607d62a717dSDag-Erling Smørgrav 			/* skip zombies */
608d62a717dSDag-Erling Smørgrav 			continue;
609d62a717dSDag-Erling Smørgrav 
610d62a717dSDag-Erling Smørgrav 		if (displaymode == DISP_CPU && !show_idle &&
611d1b76f3fSStefan Eßer 		    (pp->ki_pctcpu == 0 ||
612d1b76f3fSStefan Eßer 		     pp->ki_stat == SSTOP || pp->ki_stat == SIDL))
613d62a717dSDag-Erling Smørgrav 			/* skip idle or non-running processes */
614d62a717dSDag-Erling Smørgrav 			continue;
615d62a717dSDag-Erling Smørgrav 
616d62a717dSDag-Erling Smørgrav 		if (displaymode == DISP_IO && !show_idle && p_io == 0)
617d62a717dSDag-Erling Smørgrav 			/* skip processes that aren't doing I/O */
618d62a717dSDag-Erling Smørgrav 			continue;
619d62a717dSDag-Erling Smørgrav 
620d62a717dSDag-Erling Smørgrav 		if (show_uid && pp->ki_ruid != (uid_t)sel->uid)
621789e3877SBruce Evans 			/* skip proc. that don't belong to the selected UID */
622d62a717dSDag-Erling Smørgrav 			continue;
623d62a717dSDag-Erling Smørgrav 
624cac4b14cSBrian Feldman 		/*
625cac4b14cSBrian Feldman 		 * When not showing threads, take the first thread
626cac4b14cSBrian Feldman 		 * for output and add the fields that we can from
627cac4b14cSBrian Feldman 		 * the rest of the process's threads rather than
628cac4b14cSBrian Feldman 		 * using the system's mostly-broken KERN_PROC_PROC.
629cac4b14cSBrian Feldman 		 */
6304946a00bSDag-Erling Smørgrav 		if (sel->thread || prev_pp == NULL ||
6314946a00bSDag-Erling Smørgrav 		    prev_pp->ki_pid != pp->ki_pid) {
632511d9c65SJoerg Wunsch 			*prefp++ = pp;
633511d9c65SJoerg Wunsch 			active_procs++;
634cac4b14cSBrian Feldman 			prev_pp = pp;
635cac4b14cSBrian Feldman 		} else {
636cac4b14cSBrian Feldman 			prev_pp->ki_pctcpu += pp->ki_pctcpu;
637cac4b14cSBrian Feldman 		}
638511d9c65SJoerg Wunsch 	}
639511d9c65SJoerg Wunsch 
640511d9c65SJoerg Wunsch 	/* if requested, sort the "interesting" processes */
641511d9c65SJoerg Wunsch 	if (compare != NULL)
6424946a00bSDag-Erling Smørgrav 		qsort(pref, active_procs, sizeof(*pref), compare);
643511d9c65SJoerg Wunsch 
644511d9c65SJoerg Wunsch 	/* remember active and total counts */
645511d9c65SJoerg Wunsch 	si->p_total = total_procs;
646511d9c65SJoerg Wunsch 	si->p_active = pref_len = active_procs;
647511d9c65SJoerg Wunsch 
648511d9c65SJoerg Wunsch 	/* pass back a handle */
649511d9c65SJoerg Wunsch 	handle.next_proc = pref;
650511d9c65SJoerg Wunsch 	handle.remaining = active_procs;
651511d9c65SJoerg Wunsch 	return ((caddr_t)&handle);
652511d9c65SJoerg Wunsch }
653511d9c65SJoerg Wunsch 
6544946a00bSDag-Erling Smørgrav static char fmt[128];	/* static area where result is built */
655511d9c65SJoerg Wunsch 
656970636e9SAlfred Perlstein char *
657faac60c8SStanislav Sedov format_next_process(caddr_t handle, char *(*get_userid)(int), int flags)
658511d9c65SJoerg Wunsch {
659970636e9SAlfred Perlstein 	struct kinfo_proc *pp;
660db6bb7fcSAlfred Perlstein 	const struct kinfo_proc *oldp;
661970636e9SAlfred Perlstein 	long cputime;
662970636e9SAlfred Perlstein 	double pct;
663511d9c65SJoerg Wunsch 	struct handle *hp;
664511d9c65SJoerg Wunsch 	char status[16];
6651005b436SBill Fenner 	int state;
666db6bb7fcSAlfred Perlstein 	struct rusage ru, *rup;
6677fe9a86aSAlfred Perlstein 	long p_tot, s_tot;
6686000ced1SRong-En Fan 	char *proc_fmt, thr_buf[6], jid_buf[6];
669faac60c8SStanislav Sedov 	char *cmdbuf = NULL;
670faac60c8SStanislav Sedov 	char **args;
671511d9c65SJoerg Wunsch 
672511d9c65SJoerg Wunsch 	/* find and remember the next proc structure */
673511d9c65SJoerg Wunsch 	hp = (struct handle *)handle;
674511d9c65SJoerg Wunsch 	pp = *(hp->next_proc++);
675511d9c65SJoerg Wunsch 	hp->remaining--;
676511d9c65SJoerg Wunsch 
677a8224b82SBruce Evans 	/* get the process's command name */
6780821b7caSJohn Baldwin 	if ((pp->ki_sflag & PS_INMEM) == 0) {
679511d9c65SJoerg Wunsch 		/*
680511d9c65SJoerg Wunsch 		 * Print swapped processes as <pname>
681511d9c65SJoerg Wunsch 		 */
682789e3877SBruce Evans 		size_t len;
683789e3877SBruce Evans 
684789e3877SBruce Evans 		len = strlen(pp->ki_comm);
6854946a00bSDag-Erling Smørgrav 		if (len > sizeof(pp->ki_comm) - 3)
6864946a00bSDag-Erling Smørgrav 			len = sizeof(pp->ki_comm) - 3;
6874946a00bSDag-Erling Smørgrav 		memmove(pp->ki_comm + 1, pp->ki_comm, len);
6884946a00bSDag-Erling Smørgrav 		pp->ki_comm[0] = '<';
6894946a00bSDag-Erling Smørgrav 		pp->ki_comm[len + 1] = '>';
6904946a00bSDag-Erling Smørgrav 		pp->ki_comm[len + 2] = '\0';
691511d9c65SJoerg Wunsch 	}
692511d9c65SJoerg Wunsch 
693a8224b82SBruce Evans 	/*
694a8224b82SBruce Evans 	 * Convert the process's runtime from microseconds to seconds.  This
695a8224b82SBruce Evans 	 * time includes the interrupt time although that is not wanted here.
696a8224b82SBruce Evans 	 * ps(1) is similarly sloppy.
697a8224b82SBruce Evans 	 */
6981f7d2501SKirk McKusick 	cputime = (pp->ki_runtime + 500000) / 1000000;
699511d9c65SJoerg Wunsch 
700511d9c65SJoerg Wunsch 	/* calculate the base for cpu percentages */
7011f7d2501SKirk McKusick 	pct = pctdouble(pp->ki_pctcpu);
702511d9c65SJoerg Wunsch 
703511d9c65SJoerg Wunsch 	/* generate "STATE" field */
7041f7d2501SKirk McKusick 	switch (state = pp->ki_stat) {
705511d9c65SJoerg Wunsch 	case SRUN:
7061f7d2501SKirk McKusick 		if (smpmode && pp->ki_oncpu != 0xff)
7071f7d2501SKirk McKusick 			sprintf(status, "CPU%d", pp->ki_oncpu);
708511d9c65SJoerg Wunsch 		else
709511d9c65SJoerg Wunsch 			strcpy(status, "RUN");
710511d9c65SJoerg Wunsch 		break;
7110d632649SJohn Baldwin 	case SLOCK:
7120d632649SJohn Baldwin 		if (pp->ki_kiflag & KI_LOCKBLOCK) {
7130d632649SJohn Baldwin 			sprintf(status, "*%.6s", pp->ki_lockname);
714089f9b7eSJohn Baldwin 			break;
715089f9b7eSJohn Baldwin 		}
716089f9b7eSJohn Baldwin 		/* fall through */
717511d9c65SJoerg Wunsch 	case SSLEEP:
7181f7d2501SKirk McKusick 		if (pp->ki_wmesg != NULL) {
7191f7d2501SKirk McKusick 			sprintf(status, "%.6s", pp->ki_wmesg);
720511d9c65SJoerg Wunsch 			break;
721511d9c65SJoerg Wunsch 		}
72293b0017fSPhilippe Charnier 		/* FALLTHROUGH */
723511d9c65SJoerg Wunsch 	default:
7241005b436SBill Fenner 
7251005b436SBill Fenner 		if (state >= 0 &&
7261005b436SBill Fenner 		    state < sizeof(state_abbrev) / sizeof(*state_abbrev))
7274946a00bSDag-Erling Smørgrav 			sprintf(status, "%.6s", state_abbrev[state]);
7281005b436SBill Fenner 		else
7291005b436SBill Fenner 			sprintf(status, "?%5d", state);
730511d9c65SJoerg Wunsch 		break;
731511d9c65SJoerg Wunsch 	}
732511d9c65SJoerg Wunsch 
733faac60c8SStanislav Sedov 	cmdbuf = (char *)malloc(cmdlengthdelta + 1);
734faac60c8SStanislav Sedov 	if (cmdbuf == NULL) {
735faac60c8SStanislav Sedov 		warn("malloc(%d)", cmdlengthdelta + 1);
736faac60c8SStanislav Sedov 		return NULL;
737faac60c8SStanislav Sedov 	}
738faac60c8SStanislav Sedov 
739faac60c8SStanislav Sedov 	if (!(flags & FMT_SHOWARGS)) {
740faac60c8SStanislav Sedov 		snprintf(cmdbuf, cmdlengthdelta, "%s", pp->ki_comm);
741faac60c8SStanislav Sedov 	}
742faac60c8SStanislav Sedov 	else if (pp->ki_args == NULL ||
743faac60c8SStanislav Sedov 	    (args = kvm_getargv(kd, pp, cmdlengthdelta)) == NULL || !(*args))
744faac60c8SStanislav Sedov 		snprintf(cmdbuf, cmdlengthdelta, "[%s]", pp->ki_comm);
745faac60c8SStanislav Sedov 	else {
746faac60c8SStanislav Sedov 		char *src, *dst, *argbuf;
747faac60c8SStanislav Sedov 		char *cmd;
748faac60c8SStanislav Sedov 		size_t argbuflen;
749faac60c8SStanislav Sedov 		size_t len;
750faac60c8SStanislav Sedov 
751faac60c8SStanislav Sedov 		argbuflen = cmdlengthdelta * 4;
752faac60c8SStanislav Sedov 		argbuf = (char *)malloc(argbuflen + 1);
753faac60c8SStanislav Sedov 		if (argbuf == NULL) {
754faac60c8SStanislav Sedov 			warn("malloc(%d)", argbuflen + 1);
755faac60c8SStanislav Sedov 			free(cmdbuf);
756faac60c8SStanislav Sedov 			return NULL;
757faac60c8SStanislav Sedov 		}
758faac60c8SStanislav Sedov 
759faac60c8SStanislav Sedov 		dst = argbuf;
760faac60c8SStanislav Sedov 
761faac60c8SStanislav Sedov 		/* Extract cmd name from argv */
762faac60c8SStanislav Sedov 		cmd = strrchr(*args, '/');
763faac60c8SStanislav Sedov 		if (cmd == NULL)
764faac60c8SStanislav Sedov 			cmd = *args;
765faac60c8SStanislav Sedov 		else
766faac60c8SStanislav Sedov 			cmd++;
767faac60c8SStanislav Sedov 
768faac60c8SStanislav Sedov 		for (; (src = *args++) != NULL; ) {
769faac60c8SStanislav Sedov 			if (*src == '\0')
770faac60c8SStanislav Sedov 				continue;
771faac60c8SStanislav Sedov 			len = (argbuflen - (dst - argbuf) - 1) / 4;
772faac60c8SStanislav Sedov 			strvisx(dst, src, strlen(src) < len ? strlen(src) : len,
773faac60c8SStanislav Sedov 			    VIS_NL | VIS_CSTYLE);
774faac60c8SStanislav Sedov 			while (*dst != '\0')
775faac60c8SStanislav Sedov 				dst++;
776faac60c8SStanislav Sedov 			if ((argbuflen - (dst - argbuf) - 1) / 4 > 0)
777faac60c8SStanislav Sedov 				*dst++ = ' '; /* add delimiting space */
778faac60c8SStanislav Sedov 		}
779faac60c8SStanislav Sedov 		if (dst != argbuf && dst[-1] == ' ')
780faac60c8SStanislav Sedov 			dst--;
781faac60c8SStanislav Sedov 		*dst = '\0';
782faac60c8SStanislav Sedov 
783faac60c8SStanislav Sedov 		if (strcmp(cmd, pp->ki_comm) != 0 )
784faac60c8SStanislav Sedov 			snprintf(cmdbuf, cmdlengthdelta, "%s (%s)",argbuf, \
785faac60c8SStanislav Sedov 				 pp->ki_comm);
786faac60c8SStanislav Sedov 		else
787faac60c8SStanislav Sedov 			strlcpy(cmdbuf, argbuf, cmdlengthdelta);
788faac60c8SStanislav Sedov 
789faac60c8SStanislav Sedov 		free(argbuf);
790faac60c8SStanislav Sedov 	}
791faac60c8SStanislav Sedov 
7926000ced1SRong-En Fan 	if (ps.jail == 0)
7936000ced1SRong-En Fan 		jid_buf[0] = '\0';
7946000ced1SRong-En Fan 	else
7956000ced1SRong-En Fan 		snprintf(jid_buf, sizeof(jid_buf), " %*d",
7966000ced1SRong-En Fan 		    sizeof(jid_buf) - 3, pp->ki_jid);
7976000ced1SRong-En Fan 
798db6bb7fcSAlfred Perlstein 	if (displaymode == DISP_IO) {
799db6bb7fcSAlfred Perlstein 		oldp = get_old_proc(pp);
800db6bb7fcSAlfred Perlstein 		if (oldp != NULL) {
801789e3877SBruce Evans 			ru.ru_inblock = RU(pp)->ru_inblock -
802789e3877SBruce Evans 			    RU(oldp)->ru_inblock;
803789e3877SBruce Evans 			ru.ru_oublock = RU(pp)->ru_oublock -
804789e3877SBruce Evans 			    RU(oldp)->ru_oublock;
805db6bb7fcSAlfred Perlstein 			ru.ru_majflt = RU(pp)->ru_majflt - RU(oldp)->ru_majflt;
8065d320d4bSAlfred Perlstein 			ru.ru_nvcsw = RU(pp)->ru_nvcsw - RU(oldp)->ru_nvcsw;
8075d320d4bSAlfred Perlstein 			ru.ru_nivcsw = RU(pp)->ru_nivcsw - RU(oldp)->ru_nivcsw;
808db6bb7fcSAlfred Perlstein 			rup = &ru;
809db6bb7fcSAlfred Perlstein 		} else {
810db6bb7fcSAlfred Perlstein 			rup = RU(pp);
811db6bb7fcSAlfred Perlstein 		}
8127fe9a86aSAlfred Perlstein 		p_tot = rup->ru_inblock + rup->ru_oublock + rup->ru_majflt;
8137fe9a86aSAlfred Perlstein 		s_tot = total_inblock + total_oublock + total_majflt;
814db6bb7fcSAlfred Perlstein 
815db6bb7fcSAlfred Perlstein 		sprintf(fmt, io_Proc_format,
816db6bb7fcSAlfred Perlstein 		    pp->ki_pid,
8176000ced1SRong-En Fan 		    jid_buf,
818789e3877SBruce Evans 		    namelength, namelength, (*get_userid)(pp->ki_ruid),
8195d320d4bSAlfred Perlstein 		    rup->ru_nvcsw,
8205d320d4bSAlfred Perlstein 		    rup->ru_nivcsw,
8214946a00bSDag-Erling Smørgrav 		    rup->ru_inblock,
8224946a00bSDag-Erling Smørgrav 		    rup->ru_oublock,
8234946a00bSDag-Erling Smørgrav 		    rup->ru_majflt,
8244946a00bSDag-Erling Smørgrav 		    p_tot,
8254946a00bSDag-Erling Smørgrav 		    s_tot == 0 ? 0.0 : (p_tot * 100.0 / s_tot),
826db6bb7fcSAlfred Perlstein 		    screen_width > cmdlengthdelta ?
827db6bb7fcSAlfred Perlstein 		    screen_width - cmdlengthdelta : 0,
828faac60c8SStanislav Sedov 		    printable(cmdbuf));
829faac60c8SStanislav Sedov 
830faac60c8SStanislav Sedov 		free(cmdbuf);
831faac60c8SStanislav Sedov 
832db6bb7fcSAlfred Perlstein 		return (fmt);
833db6bb7fcSAlfred Perlstein 	}
83432efd263SGiorgos Keramidas 
835511d9c65SJoerg Wunsch 	/* format this entry */
83632efd263SGiorgos Keramidas 	proc_fmt = smpmode ? smp_Proc_format : up_Proc_format;
83732efd263SGiorgos Keramidas 	if (ps.thread != 0)
83832efd263SGiorgos Keramidas 		thr_buf[0] = '\0';
83932efd263SGiorgos Keramidas 	else
84032efd263SGiorgos Keramidas 		snprintf(thr_buf, sizeof(thr_buf), "%*d ",
84132efd263SGiorgos Keramidas 		    sizeof(thr_buf) - 2, pp->ki_numthreads);
84232efd263SGiorgos Keramidas 
84332efd263SGiorgos Keramidas 	sprintf(fmt, proc_fmt,
8441f7d2501SKirk McKusick 	    pp->ki_pid,
8456000ced1SRong-En Fan 	    jid_buf,
846789e3877SBruce Evans 	    namelength, namelength, (*get_userid)(pp->ki_ruid),
84732efd263SGiorgos Keramidas 	    thr_buf,
8484c85452bSJake Burkholder 	    pp->ki_pri.pri_level - PZERO,
849de916c8bSBruce Evans 	    format_nice(pp),
8508fbaa58aSDmitrij Tejblum 	    format_k2(PROCSIZE(pp)),
8511f7d2501SKirk McKusick 	    format_k2(pagetok(pp->ki_rssize)),
852511d9c65SJoerg Wunsch 	    status,
8531f7d2501SKirk McKusick 	    smpmode ? pp->ki_lastcpu : 0,
854511d9c65SJoerg Wunsch 	    format_time(cputime),
855bbf750fbSGiorgos Keramidas 	    ps.wcpu ? 100.0 * weighted_cpu(pct, pp) : 100.0 * pct,
856789e3877SBruce Evans 	    screen_width > cmdlengthdelta ? screen_width - cmdlengthdelta : 0,
857faac60c8SStanislav Sedov 	    printable(cmdbuf));
858faac60c8SStanislav Sedov 
859faac60c8SStanislav Sedov 	free(cmdbuf);
860511d9c65SJoerg Wunsch 
861511d9c65SJoerg Wunsch 	/* return the result */
862511d9c65SJoerg Wunsch 	return (fmt);
863511d9c65SJoerg Wunsch }
864511d9c65SJoerg Wunsch 
865970636e9SAlfred Perlstein static void
866de916c8bSBruce Evans getsysctl(const char *name, void *ptr, size_t len)
867511d9c65SJoerg Wunsch {
86898e53e5bSAndrew Gallatin 	size_t nlen = len;
869970636e9SAlfred Perlstein 
87039d513ecSRobert Watson 	if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
87139d513ecSRobert Watson 		fprintf(stderr, "top: sysctl(%s...) failed: %s\n", name,
87239d513ecSRobert Watson 		    strerror(errno));
873511d9c65SJoerg Wunsch 		quit(23);
874511d9c65SJoerg Wunsch 	}
87539d513ecSRobert Watson 	if (nlen != len) {
876789e3877SBruce Evans 		fprintf(stderr, "top: sysctl(%s...) expected %lu, got %lu\n",
877789e3877SBruce Evans 		    name, (unsigned long)len, (unsigned long)nlen);
87839d513ecSRobert Watson 		quit(23);
879511d9c65SJoerg Wunsch 	}
880511d9c65SJoerg Wunsch }
881511d9c65SJoerg Wunsch 
8828dbbff5bSBruce Evans static const char *
8838dbbff5bSBruce Evans format_nice(const struct kinfo_proc *pp)
884de916c8bSBruce Evans {
8858dbbff5bSBruce Evans 	const char *fifo, *kthread;
8868dbbff5bSBruce Evans 	int rtpri;
8878dbbff5bSBruce Evans 	static char nicebuf[4 + 1];
888de916c8bSBruce Evans 
8898dbbff5bSBruce Evans 	fifo = PRI_NEED_RR(pp->ki_pri.pri_class) ? "" : "F";
8908dbbff5bSBruce Evans 	kthread = (pp->ki_flag & P_KTHREAD) ? "k" : "";
8918dbbff5bSBruce Evans 	switch (PRI_BASE(pp->ki_pri.pri_class)) {
8928dbbff5bSBruce Evans 	case PRI_ITHD:
8938dbbff5bSBruce Evans 		return ("-");
8948dbbff5bSBruce Evans 	case PRI_REALTIME:
895e19249f7SBruce Evans 		/*
896e19249f7SBruce Evans 		 * XXX: the kernel doesn't tell us the original rtprio and
897e19249f7SBruce Evans 		 * doesn't really know what it was, so to recover it we
898e19249f7SBruce Evans 		 * must be more chummy with the implementation than the
899e19249f7SBruce Evans 		 * implementation is with itself.  pri_user gives a
900e19249f7SBruce Evans 		 * constant "base" priority, but is only initialized
901e19249f7SBruce Evans 		 * properly for user threads.  pri_native gives what the
902e19249f7SBruce Evans 		 * kernel calls the "base" priority, but it isn't constant
903e19249f7SBruce Evans 		 * since it is changed by priority propagation.  pri_native
904e19249f7SBruce Evans 		 * also isn't properly initialized for all threads, but it
905e19249f7SBruce Evans 		 * is properly initialized for kernel realtime and idletime
906e19249f7SBruce Evans 		 * threads.  Thus we use pri_user for the base priority of
907e19249f7SBruce Evans 		 * user threads (it is always correct) and pri_native for
908e19249f7SBruce Evans 		 * the base priority of kernel realtime and idletime threads
909e19249f7SBruce Evans 		 * (there is nothing better, and it is usually correct).
910e19249f7SBruce Evans 		 *
911e19249f7SBruce Evans 		 * The field width and thus the buffer are too small for
912e19249f7SBruce Evans 		 * values like "kr31F", but such values shouldn't occur,
913e19249f7SBruce Evans 		 * and if they do then the tailing "F" is not displayed.
914e19249f7SBruce Evans 		 */
915e19249f7SBruce Evans 		rtpri = ((pp->ki_flag & P_KTHREAD) ? pp->ki_pri.pri_native :
916e19249f7SBruce Evans 		    pp->ki_pri.pri_user) - PRI_MIN_REALTIME;
9178dbbff5bSBruce Evans 		snprintf(nicebuf, sizeof(nicebuf), "%sr%d%s",
9188dbbff5bSBruce Evans 		    kthread, rtpri, fifo);
9198dbbff5bSBruce Evans 		break;
9208dbbff5bSBruce Evans 	case PRI_TIMESHARE:
9218dbbff5bSBruce Evans 		if (pp->ki_flag & P_KTHREAD)
9228dbbff5bSBruce Evans 			return ("-");
9238dbbff5bSBruce Evans 		snprintf(nicebuf, sizeof(nicebuf), "%d", pp->ki_nice - NZERO);
9248dbbff5bSBruce Evans 		break;
9258dbbff5bSBruce Evans 	case PRI_IDLE:
926e19249f7SBruce Evans 		/* XXX: as above. */
927e19249f7SBruce Evans 		rtpri = ((pp->ki_flag & P_KTHREAD) ? pp->ki_pri.pri_native :
928e19249f7SBruce Evans 		    pp->ki_pri.pri_user) - PRI_MIN_IDLE;
9298dbbff5bSBruce Evans 		snprintf(nicebuf, sizeof(nicebuf), "%si%d%s",
9308dbbff5bSBruce Evans 		    kthread, rtpri, fifo);
9318dbbff5bSBruce Evans 		break;
9328dbbff5bSBruce Evans 	default:
9338dbbff5bSBruce Evans 		return ("?");
9348dbbff5bSBruce Evans 	}
935de916c8bSBruce Evans 	return (nicebuf);
936de916c8bSBruce Evans }
937de916c8bSBruce Evans 
938f3b2c2d1SWolfram Schneider /* comparison routines for qsort */
939511d9c65SJoerg Wunsch 
940de916c8bSBruce Evans static int
941f6a10feaSDag-Erling Smørgrav compare_pid(const void *p1, const void *p2)
942db6bb7fcSAlfred Perlstein {
943db6bb7fcSAlfred Perlstein 	const struct kinfo_proc * const *pp1 = p1;
944db6bb7fcSAlfred Perlstein 	const struct kinfo_proc * const *pp2 = p2;
945db6bb7fcSAlfred Perlstein 
946db6bb7fcSAlfred Perlstein 	if ((*pp2)->ki_pid < 0 || (*pp1)->ki_pid < 0)
947db6bb7fcSAlfred Perlstein 		abort();
948db6bb7fcSAlfred Perlstein 
949db6bb7fcSAlfred Perlstein 	return ((*pp1)->ki_pid - (*pp2)->ki_pid);
950db6bb7fcSAlfred Perlstein }
951db6bb7fcSAlfred Perlstein 
952511d9c65SJoerg Wunsch /*
953511d9c65SJoerg Wunsch  *  proc_compare - comparison function for "qsort"
954511d9c65SJoerg Wunsch  *	Compares the resource consumption of two processes using five
955511d9c65SJoerg Wunsch  *	distinct keys.  The keys (in descending order of importance) are:
956511d9c65SJoerg Wunsch  *	percent cpu, cpu ticks, state, resident set size, total virtual
957511d9c65SJoerg Wunsch  *	memory usage.  The process states are ordered as follows (from least
958511d9c65SJoerg Wunsch  *	to most important):  WAIT, zombie, sleep, stop, start, run.  The
959511d9c65SJoerg Wunsch  *	array declaration below maps a process state index into a number
960511d9c65SJoerg Wunsch  *	that reflects this ordering.
961511d9c65SJoerg Wunsch  */
962511d9c65SJoerg Wunsch 
963789e3877SBruce Evans static int sorted_state[] = {
964511d9c65SJoerg Wunsch 	0,	/* not used		*/
965511d9c65SJoerg Wunsch 	3,	/* sleep		*/
966511d9c65SJoerg Wunsch 	1,	/* ABANDONED (WAIT)	*/
967511d9c65SJoerg Wunsch 	6,	/* run			*/
968511d9c65SJoerg Wunsch 	5,	/* start		*/
969511d9c65SJoerg Wunsch 	2,	/* zombie		*/
970511d9c65SJoerg Wunsch 	4	/* stop			*/
971511d9c65SJoerg Wunsch };
972511d9c65SJoerg Wunsch 
973f3b2c2d1SWolfram Schneider 
9744946a00bSDag-Erling Smørgrav #define ORDERKEY_PCTCPU(a, b) do { \
975bbf750fbSGiorgos Keramidas 	long diff; \
976bbf750fbSGiorgos Keramidas 	if (ps.wcpu) \
977789e3877SBruce Evans 		diff = floor(1.0E6 * weighted_cpu(pctdouble((b)->ki_pctcpu), \
978789e3877SBruce Evans 		    (b))) - \
979789e3877SBruce Evans 		    floor(1.0E6 * weighted_cpu(pctdouble((a)->ki_pctcpu), \
980789e3877SBruce Evans 		    (a))); \
981bbf750fbSGiorgos Keramidas 	else \
982bbf750fbSGiorgos Keramidas 		diff = (long)(b)->ki_pctcpu - (long)(a)->ki_pctcpu; \
9834946a00bSDag-Erling Smørgrav 	if (diff != 0) \
9844946a00bSDag-Erling Smørgrav 		return (diff > 0 ? 1 : -1); \
9854946a00bSDag-Erling Smørgrav } while (0)
986f3b2c2d1SWolfram Schneider 
9874946a00bSDag-Erling Smørgrav #define ORDERKEY_CPTICKS(a, b) do { \
988e38035a5SDag-Erling Smørgrav 	int64_t diff = (int64_t)(b)->ki_runtime - (int64_t)(a)->ki_runtime; \
9894946a00bSDag-Erling Smørgrav 	if (diff != 0) \
9904946a00bSDag-Erling Smørgrav 		return (diff > 0 ? 1 : -1); \
9914946a00bSDag-Erling Smørgrav } while (0)
992f3b2c2d1SWolfram Schneider 
9934946a00bSDag-Erling Smørgrav #define ORDERKEY_STATE(a, b) do { \
9944946a00bSDag-Erling Smørgrav 	int diff = sorted_state[(b)->ki_stat] - sorted_state[(a)->ki_stat]; \
9954946a00bSDag-Erling Smørgrav 	if (diff != 0) \
9964946a00bSDag-Erling Smørgrav 		return (diff > 0 ? 1 : -1); \
9974946a00bSDag-Erling Smørgrav } while (0)
998f3b2c2d1SWolfram Schneider 
9994946a00bSDag-Erling Smørgrav #define ORDERKEY_PRIO(a, b) do { \
1000e38035a5SDag-Erling Smørgrav 	int diff = (int)(b)->ki_pri.pri_level - (int)(a)->ki_pri.pri_level; \
10014946a00bSDag-Erling Smørgrav 	if (diff != 0) \
10024946a00bSDag-Erling Smørgrav 		return (diff > 0 ? 1 : -1); \
10034946a00bSDag-Erling Smørgrav } while (0)
1004f3b2c2d1SWolfram Schneider 
100532efd263SGiorgos Keramidas #define	ORDERKEY_THREADS(a, b) do { \
100632efd263SGiorgos Keramidas 	int diff = (int)(b)->ki_numthreads - (int)(a)->ki_numthreads; \
100732efd263SGiorgos Keramidas 	if (diff != 0) \
100832efd263SGiorgos Keramidas 		return (diff > 0 ? 1 : -1); \
100932efd263SGiorgos Keramidas } while (0)
101032efd263SGiorgos Keramidas 
10114946a00bSDag-Erling Smørgrav #define ORDERKEY_RSSIZE(a, b) do { \
1012e38035a5SDag-Erling Smørgrav 	long diff = (long)(b)->ki_rssize - (long)(a)->ki_rssize; \
10134946a00bSDag-Erling Smørgrav 	if (diff != 0) \
10144946a00bSDag-Erling Smørgrav 		return (diff > 0 ? 1 : -1); \
10154946a00bSDag-Erling Smørgrav } while (0)
1016f3b2c2d1SWolfram Schneider 
10174946a00bSDag-Erling Smørgrav #define ORDERKEY_MEM(a, b) do { \
1018e38035a5SDag-Erling Smørgrav 	long diff = (long)PROCSIZE((b)) - (long)PROCSIZE((a)); \
10194946a00bSDag-Erling Smørgrav 	if (diff != 0) \
10204946a00bSDag-Erling Smørgrav 		return (diff > 0 ? 1 : -1); \
10214946a00bSDag-Erling Smørgrav } while (0)
1022f3b2c2d1SWolfram Schneider 
10236000ced1SRong-En Fan #define ORDERKEY_JID(a, b) do { \
10246000ced1SRong-En Fan 	int diff = (int)(b)->ki_jid - (int)(a)->ki_jid; \
10256000ced1SRong-En Fan 	if (diff != 0) \
10266000ced1SRong-En Fan 		return (diff > 0 ? 1 : -1); \
10276000ced1SRong-En Fan } while (0)
10286000ced1SRong-En Fan 
1029f3b2c2d1SWolfram Schneider /* compare_cpu - the comparison function for sorting by cpu percentage */
1030f3b2c2d1SWolfram Schneider 
1031511d9c65SJoerg Wunsch int
1032f3b2c2d1SWolfram Schneider #ifdef ORDER
10334946a00bSDag-Erling Smørgrav compare_cpu(void *arg1, void *arg2)
1034f3b2c2d1SWolfram Schneider #else
10354946a00bSDag-Erling Smørgrav proc_compare(void *arg1, void *arg2)
1036f3b2c2d1SWolfram Schneider #endif
1037511d9c65SJoerg Wunsch {
10384946a00bSDag-Erling Smørgrav 	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
10394946a00bSDag-Erling Smørgrav 	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
1040511d9c65SJoerg Wunsch 
10414946a00bSDag-Erling Smørgrav 	ORDERKEY_PCTCPU(p1, p2);
10424946a00bSDag-Erling Smørgrav 	ORDERKEY_CPTICKS(p1, p2);
10434946a00bSDag-Erling Smørgrav 	ORDERKEY_STATE(p1, p2);
10444946a00bSDag-Erling Smørgrav 	ORDERKEY_PRIO(p1, p2);
10454946a00bSDag-Erling Smørgrav 	ORDERKEY_RSSIZE(p1, p2);
10464946a00bSDag-Erling Smørgrav 	ORDERKEY_MEM(p1, p2);
1047511d9c65SJoerg Wunsch 
10484946a00bSDag-Erling Smørgrav 	return (0);
1049511d9c65SJoerg Wunsch }
1050511d9c65SJoerg Wunsch 
1051f3b2c2d1SWolfram Schneider #ifdef ORDER
1052789e3877SBruce Evans /* "cpu" compare routines */
1053789e3877SBruce Evans int compare_size(), compare_res(), compare_time(), compare_prio(),
1054789e3877SBruce Evans     compare_threads();
1055789e3877SBruce Evans 
1056789e3877SBruce Evans /*
1057789e3877SBruce Evans  * "io" compare routines.  Context switches aren't i/o, but are displayed
1058789e3877SBruce Evans  * on the "io" display.
1059789e3877SBruce Evans  */
1060789e3877SBruce Evans int compare_iototal(), compare_ioread(), compare_iowrite(), compare_iofault(),
1061789e3877SBruce Evans     compare_vcsw(), compare_ivcsw();
1062f3b2c2d1SWolfram Schneider 
10635d320d4bSAlfred Perlstein int (*compares[])() = {
1064f3b2c2d1SWolfram Schneider 	compare_cpu,
1065f3b2c2d1SWolfram Schneider 	compare_size,
1066f3b2c2d1SWolfram Schneider 	compare_res,
1067f3b2c2d1SWolfram Schneider 	compare_time,
1068f3b2c2d1SWolfram Schneider 	compare_prio,
106932efd263SGiorgos Keramidas 	compare_threads,
10705d320d4bSAlfred Perlstein 	compare_iototal,
10715d320d4bSAlfred Perlstein 	compare_ioread,
10725d320d4bSAlfred Perlstein 	compare_iowrite,
10735d320d4bSAlfred Perlstein 	compare_iofault,
10745d320d4bSAlfred Perlstein 	compare_vcsw,
10755d320d4bSAlfred Perlstein 	compare_ivcsw,
10766000ced1SRong-En Fan 	compare_jid,
1077f3b2c2d1SWolfram Schneider 	NULL
1078f3b2c2d1SWolfram Schneider };
1079f3b2c2d1SWolfram Schneider 
1080f3b2c2d1SWolfram Schneider /* compare_size - the comparison function for sorting by total memory usage */
1081f3b2c2d1SWolfram Schneider 
1082f3b2c2d1SWolfram Schneider int
10834946a00bSDag-Erling Smørgrav compare_size(void *arg1, void *arg2)
1084f3b2c2d1SWolfram Schneider {
10854946a00bSDag-Erling Smørgrav 	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
10864946a00bSDag-Erling Smørgrav 	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
1087f3b2c2d1SWolfram Schneider 
10884946a00bSDag-Erling Smørgrav 	ORDERKEY_MEM(p1, p2);
10894946a00bSDag-Erling Smørgrav 	ORDERKEY_RSSIZE(p1, p2);
10904946a00bSDag-Erling Smørgrav 	ORDERKEY_PCTCPU(p1, p2);
10914946a00bSDag-Erling Smørgrav 	ORDERKEY_CPTICKS(p1, p2);
10924946a00bSDag-Erling Smørgrav 	ORDERKEY_STATE(p1, p2);
10934946a00bSDag-Erling Smørgrav 	ORDERKEY_PRIO(p1, p2);
1094f3b2c2d1SWolfram Schneider 
10954946a00bSDag-Erling Smørgrav 	return (0);
1096f3b2c2d1SWolfram Schneider }
1097f3b2c2d1SWolfram Schneider 
1098f3b2c2d1SWolfram Schneider /* compare_res - the comparison function for sorting by resident set size */
1099f3b2c2d1SWolfram Schneider 
1100f3b2c2d1SWolfram Schneider int
11014946a00bSDag-Erling Smørgrav compare_res(void *arg1, void *arg2)
1102f3b2c2d1SWolfram Schneider {
11034946a00bSDag-Erling Smørgrav 	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
11044946a00bSDag-Erling Smørgrav 	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
1105f3b2c2d1SWolfram Schneider 
11064946a00bSDag-Erling Smørgrav 	ORDERKEY_RSSIZE(p1, p2);
11074946a00bSDag-Erling Smørgrav 	ORDERKEY_MEM(p1, p2);
11084946a00bSDag-Erling Smørgrav 	ORDERKEY_PCTCPU(p1, p2);
11094946a00bSDag-Erling Smørgrav 	ORDERKEY_CPTICKS(p1, p2);
11104946a00bSDag-Erling Smørgrav 	ORDERKEY_STATE(p1, p2);
11114946a00bSDag-Erling Smørgrav 	ORDERKEY_PRIO(p1, p2);
1112f3b2c2d1SWolfram Schneider 
11134946a00bSDag-Erling Smørgrav 	return (0);
1114f3b2c2d1SWolfram Schneider }
1115f3b2c2d1SWolfram Schneider 
1116f3b2c2d1SWolfram Schneider /* compare_time - the comparison function for sorting by total cpu time */
1117f3b2c2d1SWolfram Schneider 
1118f3b2c2d1SWolfram Schneider int
11194946a00bSDag-Erling Smørgrav compare_time(void *arg1, void *arg2)
1120f3b2c2d1SWolfram Schneider {
11214946a00bSDag-Erling Smørgrav 	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
11224946a00bSDag-Erling Smørgrav 	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
1123f3b2c2d1SWolfram Schneider 
11244946a00bSDag-Erling Smørgrav 	ORDERKEY_CPTICKS(p1, p2);
11254946a00bSDag-Erling Smørgrav 	ORDERKEY_PCTCPU(p1, p2);
11264946a00bSDag-Erling Smørgrav 	ORDERKEY_STATE(p1, p2);
11274946a00bSDag-Erling Smørgrav 	ORDERKEY_PRIO(p1, p2);
11284946a00bSDag-Erling Smørgrav 	ORDERKEY_RSSIZE(p1, p2);
11294946a00bSDag-Erling Smørgrav 	ORDERKEY_MEM(p1, p2);
1130f3b2c2d1SWolfram Schneider 
11314946a00bSDag-Erling Smørgrav 	return (0);
1132f3b2c2d1SWolfram Schneider }
1133f3b2c2d1SWolfram Schneider 
11344946a00bSDag-Erling Smørgrav /* compare_prio - the comparison function for sorting by priority */
1135f3b2c2d1SWolfram Schneider 
1136f3b2c2d1SWolfram Schneider int
11374946a00bSDag-Erling Smørgrav compare_prio(void *arg1, void *arg2)
1138f3b2c2d1SWolfram Schneider {
11394946a00bSDag-Erling Smørgrav 	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
11404946a00bSDag-Erling Smørgrav 	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
1141f3b2c2d1SWolfram Schneider 
11424946a00bSDag-Erling Smørgrav 	ORDERKEY_PRIO(p1, p2);
11434946a00bSDag-Erling Smørgrav 	ORDERKEY_CPTICKS(p1, p2);
11444946a00bSDag-Erling Smørgrav 	ORDERKEY_PCTCPU(p1, p2);
11454946a00bSDag-Erling Smørgrav 	ORDERKEY_STATE(p1, p2);
11464946a00bSDag-Erling Smørgrav 	ORDERKEY_RSSIZE(p1, p2);
11474946a00bSDag-Erling Smørgrav 	ORDERKEY_MEM(p1, p2);
1148f3b2c2d1SWolfram Schneider 
11494946a00bSDag-Erling Smørgrav 	return (0);
1150f3b2c2d1SWolfram Schneider }
115132efd263SGiorgos Keramidas 
115232efd263SGiorgos Keramidas /* compare_threads - the comparison function for sorting by threads */
115332efd263SGiorgos Keramidas int
115432efd263SGiorgos Keramidas compare_threads(void *arg1, void *arg2)
115532efd263SGiorgos Keramidas {
115632efd263SGiorgos Keramidas 	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
115732efd263SGiorgos Keramidas 	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
115832efd263SGiorgos Keramidas 
115932efd263SGiorgos Keramidas 	ORDERKEY_THREADS(p1, p2);
116032efd263SGiorgos Keramidas 	ORDERKEY_PCTCPU(p1, p2);
116132efd263SGiorgos Keramidas 	ORDERKEY_CPTICKS(p1, p2);
116232efd263SGiorgos Keramidas 	ORDERKEY_STATE(p1, p2);
116332efd263SGiorgos Keramidas 	ORDERKEY_PRIO(p1, p2);
116432efd263SGiorgos Keramidas 	ORDERKEY_RSSIZE(p1, p2);
116532efd263SGiorgos Keramidas 	ORDERKEY_MEM(p1, p2);
116632efd263SGiorgos Keramidas 
116732efd263SGiorgos Keramidas 	return (0);
116832efd263SGiorgos Keramidas }
11696000ced1SRong-En Fan 
11706000ced1SRong-En Fan /* compare_jid - the comparison function for sorting by jid */
11716000ced1SRong-En Fan static int
11726000ced1SRong-En Fan compare_jid(const void *arg1, const void *arg2)
11736000ced1SRong-En Fan {
11746000ced1SRong-En Fan 	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
11756000ced1SRong-En Fan 	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
11766000ced1SRong-En Fan 
11776000ced1SRong-En Fan 	ORDERKEY_JID(p1, p2);
11786000ced1SRong-En Fan 	ORDERKEY_PCTCPU(p1, p2);
11796000ced1SRong-En Fan 	ORDERKEY_CPTICKS(p1, p2);
11806000ced1SRong-En Fan 	ORDERKEY_STATE(p1, p2);
11816000ced1SRong-En Fan 	ORDERKEY_PRIO(p1, p2);
11826000ced1SRong-En Fan 	ORDERKEY_RSSIZE(p1, p2);
11836000ced1SRong-En Fan 	ORDERKEY_MEM(p1, p2);
11846000ced1SRong-En Fan 
11856000ced1SRong-En Fan 	return (0);
11866000ced1SRong-En Fan }
1187789e3877SBruce Evans #endif /* ORDER */
1188511d9c65SJoerg Wunsch 
1189789e3877SBruce Evans /* assorted comparison functions for sorting by i/o */
119026b2243aSGiorgos Keramidas 
1191db6bb7fcSAlfred Perlstein int
119226b2243aSGiorgos Keramidas #ifdef ORDER
119326b2243aSGiorgos Keramidas compare_iototal(void *arg1, void *arg2)
119426b2243aSGiorgos Keramidas #else
11954946a00bSDag-Erling Smørgrav io_compare(void *arg1, void *arg2)
119626b2243aSGiorgos Keramidas #endif
1197db6bb7fcSAlfred Perlstein {
11984946a00bSDag-Erling Smørgrav 	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
11994946a00bSDag-Erling Smørgrav 	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
1200db6bb7fcSAlfred Perlstein 
12014946a00bSDag-Erling Smørgrav 	return (get_io_total(p2) - get_io_total(p1));
1202db6bb7fcSAlfred Perlstein }
120326b2243aSGiorgos Keramidas 
120426b2243aSGiorgos Keramidas #ifdef ORDER
120526b2243aSGiorgos Keramidas int
120626b2243aSGiorgos Keramidas compare_ioread(void *arg1, void *arg2)
120726b2243aSGiorgos Keramidas {
120826b2243aSGiorgos Keramidas 	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
120926b2243aSGiorgos Keramidas 	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
121026b2243aSGiorgos Keramidas 	long dummy, inp1, inp2;
121126b2243aSGiorgos Keramidas 
12125d320d4bSAlfred Perlstein 	(void) get_io_stats(p1, &inp1, &dummy, &dummy, &dummy, &dummy);
12135d320d4bSAlfred Perlstein 	(void) get_io_stats(p2, &inp2, &dummy, &dummy, &dummy, &dummy);
121426b2243aSGiorgos Keramidas 
121526b2243aSGiorgos Keramidas 	return (inp2 - inp1);
121626b2243aSGiorgos Keramidas }
121726b2243aSGiorgos Keramidas 
121826b2243aSGiorgos Keramidas int
121926b2243aSGiorgos Keramidas compare_iowrite(void *arg1, void *arg2)
122026b2243aSGiorgos Keramidas {
122126b2243aSGiorgos Keramidas 	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
122226b2243aSGiorgos Keramidas 	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
122326b2243aSGiorgos Keramidas 	long dummy, oup1, oup2;
122426b2243aSGiorgos Keramidas 
12255d320d4bSAlfred Perlstein 	(void) get_io_stats(p1, &dummy, &oup1, &dummy, &dummy, &dummy);
12265d320d4bSAlfred Perlstein 	(void) get_io_stats(p2, &dummy, &oup2, &dummy, &dummy, &dummy);
122726b2243aSGiorgos Keramidas 
122826b2243aSGiorgos Keramidas 	return (oup2 - oup1);
122926b2243aSGiorgos Keramidas }
123026b2243aSGiorgos Keramidas 
123126b2243aSGiorgos Keramidas int
123226b2243aSGiorgos Keramidas compare_iofault(void *arg1, void *arg2)
123326b2243aSGiorgos Keramidas {
123426b2243aSGiorgos Keramidas 	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
123526b2243aSGiorgos Keramidas 	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
123626b2243aSGiorgos Keramidas 	long dummy, flp1, flp2;
123726b2243aSGiorgos Keramidas 
12385d320d4bSAlfred Perlstein 	(void) get_io_stats(p1, &dummy, &dummy, &flp1, &dummy, &dummy);
12395d320d4bSAlfred Perlstein 	(void) get_io_stats(p2, &dummy, &dummy, &flp2, &dummy, &dummy);
12405d320d4bSAlfred Perlstein 
12415d320d4bSAlfred Perlstein 	return (flp2 - flp1);
12425d320d4bSAlfred Perlstein }
12435d320d4bSAlfred Perlstein 
12445d320d4bSAlfred Perlstein int
12455d320d4bSAlfred Perlstein compare_vcsw(void *arg1, void *arg2)
12465d320d4bSAlfred Perlstein {
12475d320d4bSAlfred Perlstein 	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
12485d320d4bSAlfred Perlstein 	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
12495d320d4bSAlfred Perlstein 	long dummy, flp1, flp2;
12505d320d4bSAlfred Perlstein 
12515d320d4bSAlfred Perlstein 	(void) get_io_stats(p1, &dummy, &dummy, &dummy, &flp1, &dummy);
12525d320d4bSAlfred Perlstein 	(void) get_io_stats(p2, &dummy, &dummy, &dummy, &flp2, &dummy);
12535d320d4bSAlfred Perlstein 
12545d320d4bSAlfred Perlstein 	return (flp2 - flp1);
12555d320d4bSAlfred Perlstein }
12565d320d4bSAlfred Perlstein 
12575d320d4bSAlfred Perlstein int
12585d320d4bSAlfred Perlstein compare_ivcsw(void *arg1, void *arg2)
12595d320d4bSAlfred Perlstein {
12605d320d4bSAlfred Perlstein 	struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1;
12615d320d4bSAlfred Perlstein 	struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2;
12625d320d4bSAlfred Perlstein 	long dummy, flp1, flp2;
12635d320d4bSAlfred Perlstein 
12645d320d4bSAlfred Perlstein 	(void) get_io_stats(p1, &dummy, &dummy, &dummy, &dummy, &flp1);
12655d320d4bSAlfred Perlstein 	(void) get_io_stats(p2, &dummy, &dummy, &dummy, &dummy, &flp2);
126626b2243aSGiorgos Keramidas 
126726b2243aSGiorgos Keramidas 	return (flp2 - flp1);
126826b2243aSGiorgos Keramidas }
126926b2243aSGiorgos Keramidas #endif /* ORDER */
127026b2243aSGiorgos Keramidas 
1271511d9c65SJoerg Wunsch /*
1272511d9c65SJoerg Wunsch  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
1273511d9c65SJoerg Wunsch  *		the process does not exist.
1274511d9c65SJoerg Wunsch  *		It is EXTREMLY IMPORTANT that this function work correctly.
1275511d9c65SJoerg Wunsch  *		If top runs setuid root (as in SVR4), then this function
1276511d9c65SJoerg Wunsch  *		is the only thing that stands in the way of a serious
1277511d9c65SJoerg Wunsch  *		security problem.  It validates requests for the "kill"
1278511d9c65SJoerg Wunsch  *		and "renice" commands.
1279511d9c65SJoerg Wunsch  */
1280511d9c65SJoerg Wunsch 
1281970636e9SAlfred Perlstein int
1282f6a10feaSDag-Erling Smørgrav proc_owner(int pid)
1283511d9c65SJoerg Wunsch {
1284970636e9SAlfred Perlstein 	int cnt;
1285970636e9SAlfred Perlstein 	struct kinfo_proc **prefp;
1286970636e9SAlfred Perlstein 	struct kinfo_proc *pp;
1287511d9c65SJoerg Wunsch 
1288511d9c65SJoerg Wunsch 	prefp = pref;
1289511d9c65SJoerg Wunsch 	cnt = pref_len;
12904946a00bSDag-Erling Smørgrav 	while (--cnt >= 0) {
1291511d9c65SJoerg Wunsch 		pp = *prefp++;
12921f7d2501SKirk McKusick 		if (pp->ki_pid == (pid_t)pid)
12931f7d2501SKirk McKusick 			return ((int)pp->ki_ruid);
1294511d9c65SJoerg Wunsch 	}
1295511d9c65SJoerg Wunsch 	return (-1);
1296511d9c65SJoerg Wunsch }
1297511d9c65SJoerg Wunsch 
1298de916c8bSBruce Evans static int
1299f6a10feaSDag-Erling Smørgrav swapmode(int *retavail, int *retfree)
1300511d9c65SJoerg Wunsch {
13017bb42db9SMatthew Dillon 	int n;
13027bb42db9SMatthew Dillon 	int pagesize = getpagesize();
13037bb42db9SMatthew Dillon 	struct kvm_swap swapary[1];
1304511d9c65SJoerg Wunsch 
13057bb42db9SMatthew Dillon 	*retavail = 0;
13067bb42db9SMatthew Dillon 	*retfree = 0;
1307511d9c65SJoerg Wunsch 
13087bb42db9SMatthew Dillon #define CONVERT(v)	((quad_t)(v) * pagesize / 1024)
13097bb42db9SMatthew Dillon 
13107bb42db9SMatthew Dillon 	n = kvm_getswapinfo(kd, swapary, 1, 0);
131147b370f5SMatthew Dillon 	if (n < 0 || swapary[0].ksw_total == 0)
1312511d9c65SJoerg Wunsch 		return (0);
1313511d9c65SJoerg Wunsch 
13147bb42db9SMatthew Dillon 	*retavail = CONVERT(swapary[0].ksw_total);
13157bb42db9SMatthew Dillon 	*retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used);
13167bb42db9SMatthew Dillon 
13174946a00bSDag-Erling Smørgrav 	n = (int)(swapary[0].ksw_used * 100.0 / swapary[0].ksw_total);
13187bb42db9SMatthew Dillon 	return (n);
1319511d9c65SJoerg Wunsch }
1320