xref: /netbsd-src/external/bsd/top/dist/machine/m_netbsd.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: m_netbsd.c,v 1.25 2021/04/16 13:02:47 christos Exp $	*/
2 
3 /*
4  * top - a top users display for Unix
5  *
6  * SYNOPSIS:  For a NetBSD-1.5 (or later) system
7  *
8  * DESCRIPTION:
9  * Originally written for BSD4.4 system by Christos Zoulas.
10  * Based on the FreeBSD 2.0 version by Steven Wallace and Wolfram Schneider.
11  * NetBSD-1.0 port by Arne Helme. Process ordering by Luke Mewburn.
12  * NetBSD-1.3 port by Luke Mewburn, based on code by Matthew Green.
13  * NetBSD-1.4/UVM port by matthew green.
14  * NetBSD-1.5 port by Simon Burge.
15  * NetBSD-1.6/UBC port by Tomas Svensson.
16  * -
17  * This is the machine-dependent module for NetBSD-1.5 and later
18  * works for:
19  *	NetBSD-1.6ZC
20  * and should work for:
21  *	NetBSD-2.0	(when released)
22  * -
23  * top does not need to be installed setuid or setgid with this module.
24  *
25  * LIBS: -lkvm
26  *
27  * CFLAGS: -DHAVE_GETOPT -DORDER -DHAVE_STRERROR
28  *
29  * AUTHORS:	Christos Zoulas <christos@ee.cornell.edu>
30  *		Steven Wallace <swallace@freebsd.org>
31  *		Wolfram Schneider <wosch@cs.tu-berlin.de>
32  *		Arne Helme <arne@acm.org>
33  *		Luke Mewburn <lukem@NetBSD.org>
34  *		matthew green <mrg@eterna.com.au>
35  *		Simon Burge <simonb@NetBSD.org>
36  *		Tomas Svensson <ts@unix1.net>
37  *		Andrew Doran <ad@NetBSD.org>
38  *
39  *
40  * $Id: m_netbsd.c,v 1.25 2021/04/16 13:02:47 christos Exp $
41  */
42 #include <sys/cdefs.h>
43 
44 #ifndef lint
45 __RCSID("$NetBSD: m_netbsd.c,v 1.25 2021/04/16 13:02:47 christos Exp $");
46 #endif
47 
48 #include <sys/param.h>
49 #include <sys/resource.h>
50 #include <sys/sysctl.h>
51 #include <sys/sched.h>
52 #include <sys/swap.h>
53 
54 #include <uvm/uvm_extern.h>
55 
56 #include <err.h>
57 #include <errno.h>
58 #include <kvm.h>
59 #include <math.h>
60 #include <ctype.h>
61 #include <nlist.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <unistd.h>
66 
67 #include "os.h"
68 #include "top.h"
69 #include "machine.h"
70 #include "utils.h"
71 #include "display.h"
72 #include "loadavg.h"
73 #include "username.h"
74 
75 static void percentages64(int, int *, u_int64_t *, u_int64_t *,
76     u_int64_t *);
77 
78 /* get_process_info passes back a handle.  This is what it looks like: */
79 
80 struct handle {
81 	struct process_select *sel;
82 	struct kinfo_proc2 **next_proc;	/* points to next valid proc pointer */
83 	int remaining;		/* number of pointers remaining */
84 };
85 
86 /* define what weighted CPU is. */
87 #define weighted_cpu(pfx, pct, pp) ((pp)->pfx ## swtime == 0 ? 0.0 : \
88 			 ((pct) / (1.0 - exp((pp)->pfx ## swtime * logcpu))))
89 
90 /* what we consider to be process size: */
91 /* NetBSD introduced p_vm_msize with RLIMIT_AS */
92 #ifdef RLIMIT_AS
93 #define PROCSIZE(pp) \
94     ((pp)->p_vm_msize)
95 #else
96 #define PROCSIZE(pp) \
97     ((pp)->p_vm_tsize + (pp)->p_vm_dsize + (pp)->p_vm_ssize)
98 #endif
99 
100 
101 /*
102  * These definitions control the format of the per-process area
103  */
104 
105 static char Proc_header[] =
106   "  PID X        PRI NICE   SIZE   RES STATE       TIME   WCPU    CPU COMMAND";
107 /* 0123456   -- field to fill in starts at header+6 */
108 #define PROC_UNAME_START 6
109 #define Proc_format \
110 	"%5d %-8.8s %3d %4d%7s %5s %-9.9s%7s %5.*f%% %5.*f%% %s"
111 
112 static char Thread_header[] =
113   "  PID   LID X        PRI STATE       TIME   WCPU    CPU NAME      COMMAND";
114 /* 0123456   -- field to fill in starts at header+6 */
115 #define THREAD_UNAME_START 12
116 #define Thread_format \
117         "%5d %5d %-8.8s %3d %-9.9s%7s %5.2f%% %5.2f%% %-9.9s %s"
118 
119 /*
120  * Process state names for the "STATE" column of the display.
121  */
122 
123 const char *state_abbrev[] = {
124 	"", "IDLE", "RUN", "SLEEP", "STOP", "ZOMB", "DEAD", "CPU"
125 };
126 
127 static kvm_t *kd;
128 
129 static char *(*userprint)(int);
130 
131 /* these are retrieved from the kernel in _init */
132 
133 static double logcpu;
134 static int hz;
135 static int ccpu;
136 
137 /* these are for calculating CPU state percentages */
138 
139 static int ncpu = 0;
140 static u_int64_t *cp_time;
141 static u_int64_t *cp_old;
142 static u_int64_t *cp_diff;
143 
144 /* these are for detailing the process states */
145 
146 int process_states[8];
147 const char *procstatenames[] = {
148 	"", " idle, ", " runnable, ", " sleeping, ", " stopped, ",
149 	" zombie, ", " dead, ", " on CPU, ",
150 	NULL
151 };
152 
153 /* these are for detailing the CPU states */
154 
155 int *cpu_states;
156 const char *cpustatenames[] = {
157 	"user", "nice", "system", "interrupt", "idle", NULL
158 };
159 
160 /* these are for detailing the memory statistics */
161 
162 long memory_stats[7];
163 const char *memorynames[] = {
164 	"K Act, ", "K Inact, ", "K Wired, ", "K Exec, ", "K File, ",
165 	"K Free, ",
166 	NULL
167 };
168 
169 long swap_stats[4];
170 const char *swapnames[] = {
171 	"K Total, ", "K Used, ", "K Free, ",
172 	NULL
173 };
174 
175 
176 /* these are names given to allowed sorting orders -- first is default */
177 const char *ordernames[] = {
178 	"cpu",
179 	"pri",
180 	"res",
181 	"size",
182 	"state",
183 	"time",
184 	"pid",
185 	"command",
186 	"username",
187 	NULL
188 };
189 
190 /* forward definitions for comparison functions */
191 static int compare_cpu(struct proc **, struct proc **);
192 static int compare_prio(struct proc **, struct proc **);
193 static int compare_res(struct proc **, struct proc **);
194 static int compare_size(struct proc **, struct proc **);
195 static int compare_state(struct proc **, struct proc **);
196 static int compare_time(struct proc **, struct proc **);
197 static int compare_pid(struct proc **, struct proc **);
198 static int compare_command(struct proc **, struct proc **);
199 static int compare_username(struct proc **, struct proc **);
200 
201 int (*proc_compares[])(struct proc **, struct proc **) = {
202 	compare_cpu,
203 	compare_prio,
204 	compare_res,
205 	compare_size,
206 	compare_state,
207 	compare_time,
208 	compare_pid,
209 	compare_command,
210 	compare_username,
211 	NULL
212 };
213 
214 static char *format_next_lwp(caddr_t, char *(*)(int));
215 static char *format_next_proc(caddr_t, char *(*)(int));
216 
217 static caddr_t get_proc_info(struct system_info *, struct process_select *,
218 			     int (*)(struct proc **, struct proc **));
219 static caddr_t get_lwp_info(struct system_info *, struct process_select *,
220 			    int (*)(struct proc **, struct proc **));
221 
222 /* these are for keeping track of the proc array */
223 
224 static int nproc;
225 static int onproc = -1;
226 static int nlwp;
227 static int onlwp = -1;
228 static int pref_len;
229 static int lref_len;
230 static struct kinfo_proc2 *pbase;
231 static struct kinfo_lwp *lbase;
232 static struct kinfo_proc2 **pref;
233 static struct kinfo_lwp **lref;
234 static int maxswap;
235 static void *swapp;
236 static int procgen;
237 static int thread_nproc;
238 static int thread_onproc = -1;
239 static struct kinfo_proc2 *thread_pbase;
240 
241 /* these are for getting the memory statistics */
242 
243 static int pageshift;		/* log base 2 of the pagesize */
244 
245 int threadmode;
246 
247 /* define pagetok in terms of pageshift */
248 
249 #define pagetok(size) ((size) << pageshift)
250 
251 /*
252  * Print swapped processes as <pname> and
253  * system processes as [pname]
254  */
255 static const char *
256 get_pretty(const struct kinfo_proc2 *pp)
257 {
258 	if ((pp->p_flag & P_SYSTEM) != 0)
259 		return "[]";
260 	if ((pp->p_flag & P_INMEM) == 0)
261 		return "<>";
262 	return "";
263 }
264 
265 static const char *
266 get_command(const struct process_select *sel, struct kinfo_proc2 *pp)
267 {
268 	static char cmdbuf[128];
269 	const char *pretty;
270 	char **argv;
271 	if (pp == NULL)
272 		return "<gone>";
273 	pretty = get_pretty(pp);
274 
275 	if (sel->fullcmd == 0 || kd == NULL || (argv = kvm_getargv2(kd, pp,
276 	    sizeof(cmdbuf))) == NULL) {
277 		if (pretty[0] != '\0' && pp->p_comm[0] != pretty[0])
278 			snprintf(cmdbuf, sizeof(cmdbuf), "%c%s%c", pretty[0],
279 			    printable(pp->p_comm), pretty[1]);
280 		else
281 			strlcpy(cmdbuf, printable(pp->p_comm), sizeof(cmdbuf));
282 	} else {
283 		char *d = cmdbuf;
284 		if (pretty[0] != '\0' && argv[0][0] != pretty[0])
285 			*d++ = pretty[0];
286 		while (*argv) {
287 			const char *s = printable(*argv++);
288 			while (d < cmdbuf + sizeof(cmdbuf) - 2 &&
289 			    (*d++ = *s++) != '\0')
290 				continue;
291 			if (d > cmdbuf && d < cmdbuf + sizeof(cmdbuf) - 2 &&
292 			    d[-1] == '\0')
293 				d[-1] = ' ';
294 		}
295 		if (pretty[0] != '\0' && pretty[0] == cmdbuf[0])
296 			*d++ = pretty[1];
297 		*d++ = '\0';
298 	}
299 	return cmdbuf;
300 }
301 
302 int
303 machine_init(statics)
304 	struct statics *statics;
305 {
306 	int pagesize;
307 	int mib[2];
308 	size_t size;
309 	struct clockinfo clockinfo;
310 	struct timespec boottime;
311 
312 	if ((kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL)
313 		return -1;
314 
315 	mib[0] = CTL_HW;
316 	mib[1] = HW_NCPU;
317 	size = sizeof(ncpu);
318 	if (sysctl(mib, 2, &ncpu, &size, NULL, 0) == -1) {
319 		fprintf(stderr, "top: sysctl hw.ncpu failed: %s\n",
320 		    strerror(errno));
321 		return(-1);
322 	}
323 	statics->ncpu = ncpu;
324 	cp_time = malloc(sizeof(cp_time[0]) * CPUSTATES * ncpu);
325 	mib[0] = CTL_KERN;
326 	mib[1] = KERN_CP_TIME;
327 	size = sizeof(cp_time[0]) * CPUSTATES * ncpu;
328 	if (sysctl(mib, 2, cp_time, &size, NULL, 0) < 0) {
329 		fprintf(stderr, "top: sysctl kern.cp_time failed: %s\n",
330 		    strerror(errno));
331 		return(-1);
332 	}
333 
334 	/* Handle old call that returned only aggregate */
335 	if (size == sizeof(cp_time[0]) * CPUSTATES)
336 		ncpu = 1;
337 
338 	cpu_states = malloc(sizeof(cpu_states[0]) * CPUSTATES * ncpu);
339 	cp_old = calloc(CPUSTATES * ncpu, sizeof(cp_old[0]));
340 	cp_diff = malloc(sizeof(cp_diff[0]) * CPUSTATES * ncpu);
341 	if (cpu_states == NULL || cp_time == NULL || cp_old == NULL ||
342 	    cp_diff == NULL) {
343 		fprintf(stderr, "top: machine_init: %s\n",
344 		    strerror(errno));
345 		return(-1);
346 	}
347 
348 	mib[0] = CTL_KERN;
349 	mib[1] = KERN_CCPU;
350 	size = sizeof(ccpu);
351 	if (sysctl(mib, 2, &ccpu, &size, NULL, 0) == -1) {
352 		fprintf(stderr, "top: sysctl kern.ccpu failed: %s\n",
353 		    strerror(errno));
354 		return(-1);
355 	}
356 
357 	mib[0] = CTL_KERN;
358 	mib[1] = KERN_CLOCKRATE;
359 	size = sizeof(clockinfo);
360 	if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) == -1) {
361 		fprintf(stderr, "top: sysctl kern.clockrate failed: %s\n",
362 		    strerror(errno));
363 		return(-1);
364 	}
365 	hz = clockinfo.stathz;
366 
367 	/* this is used in calculating WCPU -- calculate it ahead of time */
368 	logcpu = log(loaddouble(ccpu));
369 
370 	pbase = NULL;
371 	lbase = NULL;
372 	pref = NULL;
373 	nproc = 0;
374 	onproc = -1;
375 	nlwp = 0;
376 	onlwp = -1;
377 	/* get the page size with "getpagesize" and calculate pageshift from it */
378 	pagesize = getpagesize();
379 	pageshift = 0;
380 	while (pagesize > 1) {
381 		pageshift++;
382 		pagesize >>= 1;
383 	}
384 
385 	/* we only need the amount of log(2)1024 for our conversion */
386 	pageshift -= LOG1024;
387 
388 	/* fill in the statics information */
389 #ifdef notyet
390 	statics->ncpu = ncpu;
391 #endif
392 	statics->procstate_names = procstatenames;
393 	statics->cpustate_names = cpustatenames;
394 	statics->memory_names = memorynames;
395 	statics->swap_names = swapnames;
396 	statics->order_names = ordernames;
397 	statics->flags.threads = 1;
398 	statics->flags.fullcmds = 1;
399 
400 	mib[0] = CTL_KERN;
401 	mib[1] = KERN_BOOTTIME;
402 	size = sizeof(boottime);
403 	if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
404     	    boottime.tv_sec != 0)
405 		statics->boottime = boottime.tv_sec;
406 	else
407 		statics->boottime = 0;
408 	/* all done! */
409 	return(0);
410 }
411 
412 char *
413 format_process_header(struct process_select *sel, caddr_t handle, int count)
414 
415 {
416 	char *header;
417 	char *ptr;
418 	const char *uname_field = sel->usernames ? "USERNAME" : "    UID ";
419 
420 	if (sel->threads) {
421 		header = Thread_header;
422 		ptr = header + THREAD_UNAME_START;
423 	} else {
424 		header = Proc_header;
425 		ptr = header + PROC_UNAME_START;
426 	}
427 
428 	while (*uname_field != '\0') {
429 		*ptr++ = *uname_field++;
430 	}
431 
432 	return(header);
433 }
434 
435 char *
436 format_header(char *uname_field)
437 {
438 	char *header = Proc_header;
439 	char *ptr = header + PROC_UNAME_START;
440 
441 	while (*uname_field != '\0') {
442 		*ptr++ = *uname_field++;
443 	}
444 
445 	return(header);
446 }
447 
448 void
449 get_system_info(struct system_info *si)
450 {
451 	size_t ssize;
452 	int mib[2];
453 	struct uvmexp_sysctl uvmexp;
454 	struct swapent *sep;
455 	u_int64_t totalsize, totalinuse;
456 	int size, inuse, ncounted, i;
457 	int rnswap, nswap;
458 
459 	mib[0] = CTL_KERN;
460 	mib[1] = KERN_CP_TIME;
461 	ssize = sizeof(cp_time[0]) * CPUSTATES * ncpu;
462 	if (sysctl(mib, 2, cp_time, &ssize, NULL, 0) < 0) {
463 		fprintf(stderr, "top: sysctl kern.cp_time failed: %s\n",
464 		    strerror(errno));
465 		quit(23);
466 	}
467 
468 	if (getloadavg(si->load_avg, NUM_AVERAGES) < 0) {
469 		int j;
470 
471 		warn("can't getloadavg");
472 		for (j = 0; j < NUM_AVERAGES; j++)
473 			si->load_avg[j] = 0.0;
474 	}
475 
476 	/* convert cp_time counts to percentages */
477 	for (i = 0; i < ncpu; i++) {
478 	    int j = i * CPUSTATES;
479 	    percentages64(CPUSTATES, cpu_states + j, cp_time + j, cp_old + j,
480 		cp_diff + j);
481 	}
482 
483 	mib[0] = CTL_VM;
484 	mib[1] = VM_UVMEXP2;
485 	ssize = sizeof(uvmexp);
486 	if (sysctl(mib, 2, &uvmexp, &ssize, NULL, 0) < 0) {
487 		fprintf(stderr, "top: sysctl vm.uvmexp2 failed: %s\n",
488 		    strerror(errno));
489 		quit(23);
490 	}
491 
492 	/* convert memory stats to Kbytes */
493 	memory_stats[0] = pagetok(uvmexp.active);
494 	memory_stats[1] = pagetok(uvmexp.inactive);
495 	memory_stats[2] = pagetok(uvmexp.wired);
496 	memory_stats[3] = pagetok(uvmexp.execpages);
497 	memory_stats[4] = pagetok(uvmexp.filepages);
498 	memory_stats[5] = pagetok(uvmexp.free);
499 
500 	swap_stats[0] = swap_stats[1] = swap_stats[2] = 0;
501 
502 	do {
503 		nswap = swapctl(SWAP_NSWAP, 0, 0);
504 		if (nswap < 1)
505 			break;
506 		if (nswap > maxswap) {
507 			if (swapp)
508 				free(swapp);
509 			swapp = sep = malloc(nswap * sizeof(*sep));
510 			if (sep == NULL)
511 				break;
512 			maxswap = nswap;
513 		} else
514 			sep = swapp;
515 		rnswap = swapctl(SWAP_STATS, (void *)sep, nswap);
516 		if (nswap != rnswap)
517 			break;
518 
519 		totalsize = totalinuse = ncounted = 0;
520 		for (; rnswap-- > 0; sep++) {
521 			ncounted++;
522 			size = sep->se_nblks;
523 			inuse = sep->se_inuse;
524 			totalsize += size;
525 			totalinuse += inuse;
526 		}
527 		swap_stats[0] = dbtob(totalsize) / 1024;
528 		swap_stats[1] = dbtob(totalinuse) / 1024;
529 		swap_stats[2] = dbtob(totalsize) / 1024 - swap_stats[1];
530 	} while (0);
531 
532 	memory_stats[6] = -1;
533 	swap_stats[3] = -1;
534 
535 	/* set arrays and strings */
536 	si->cpustates = cpu_states;
537 	si->memory = memory_stats;
538 	si->swap = swap_stats;
539 	si->last_pid = -1;
540 
541 }
542 
543 static struct kinfo_proc2 *
544 proc_from_thread(struct kinfo_lwp *pl)
545 {
546 	struct kinfo_proc2 *pp = thread_pbase;
547 	int i;
548 
549 	for (i = 0; i < thread_nproc; i++, pp++)
550 		if ((pid_t)pp->p_pid == (pid_t)pl->l_pid)
551 			return pp;
552 	return NULL;
553 }
554 
555 static int
556 uid_from_thread(struct kinfo_lwp *pl)
557 {
558 	struct kinfo_proc2 *pp;
559 
560 	if ((pp = proc_from_thread(pl)) == NULL)
561 		return -1;
562 	return pp->p_ruid;
563 }
564 
565 caddr_t
566 get_process_info(struct system_info *si, struct process_select *sel, int c)
567 {
568 	userprint = sel->usernames ? username : itoa7;
569 
570 	if ((threadmode = sel->threads) != 0)
571 		return get_lwp_info(si, sel, proc_compares[c]);
572 	else
573 		return get_proc_info(si, sel, proc_compares[c]);
574 }
575 
576 static caddr_t
577 get_proc_info(struct system_info *si, struct process_select *sel,
578 	      int (*compare)(struct proc **, struct proc **))
579 {
580 	int i;
581 	int total_procs;
582 	int active_procs;
583 	struct kinfo_proc2 **prefp, **n;
584 	struct kinfo_proc2 *pp;
585 	int op, arg;
586 
587 	/* these are copied out of sel for speed */
588 	int show_idle;
589 	int show_system;
590 	int show_uid;
591 	char *show_command;
592 
593 	static struct handle handle;
594 
595 	procgen++;
596 
597 	if (sel->pid == (pid_t)-1) {
598 		op = KERN_PROC_ALL;
599 		arg = 0;
600 	} else {
601 		op = KERN_PROC_PID;
602 		arg = sel->pid;
603 	}
604 
605 	pbase = kvm_getproc2(kd, op, arg, sizeof(struct kinfo_proc2), &nproc);
606 	if (pbase == NULL) {
607 		if (sel->pid != (pid_t)-1) {
608 			nproc = 0;
609 		} else {
610 			(void) fprintf(stderr, "top: Out of memory.\n");
611 			quit(23);
612 		}
613 	}
614 	if (nproc > onproc) {
615 		n = (struct kinfo_proc2 **) realloc(pref,
616 		    sizeof(struct kinfo_proc2 *) * nproc);
617 		if (n == NULL) {
618 			(void) fprintf(stderr, "top: Out of memory.\n");
619 			quit(23);
620 		}
621 		pref = n;
622 		onproc = nproc;
623 	}
624 	/* get a pointer to the states summary array */
625 	si->procstates = process_states;
626 
627 	/* set up flags which define what we are going to select */
628 	show_idle = sel->idle;
629 	show_system = sel->system;
630 	show_uid = sel->uid != -1;
631 	show_command = sel->command;
632 
633 	/* count up process states and get pointers to interesting procs */
634 	total_procs = 0;
635 	active_procs = 0;
636 	memset((char *)process_states, 0, sizeof(process_states));
637 	prefp = pref;
638 	for (pp = pbase, i = 0; i < nproc; pp++, i++) {
639 
640 		/*
641 		 * Place pointers to each valid proc structure in pref[].
642 		 * Process slots that are actually in use have a non-zero
643 		 * status field.  Processes with P_SYSTEM set are system
644 		 * processes---these get ignored unless show_sysprocs is set.
645 		 */
646 		if (pp->p_stat != 0 && (show_system || ((pp->p_flag & P_SYSTEM) == 0))) {
647 			total_procs++;
648 			process_states[(unsigned char) pp->p_stat]++;
649 			if (pp->p_stat != LSZOMB &&
650 			    (show_idle || (pp->p_pctcpu != 0) ||
651 			    (pp->p_stat == LSRUN || pp->p_stat == LSONPROC)) &&
652 			    (!show_uid || pp->p_ruid == (uid_t)sel->uid) &&
653 			    (!show_command ||
654 			     strstr(get_command(sel, pp),
655 				 show_command) != NULL)) {
656 					*prefp++ = pp;
657 					active_procs++;
658 			}
659 		}
660 	}
661 
662 	/* if requested, sort the "interesting" processes */
663 	if (compare != NULL) {
664 		qsort((char *)pref, active_procs, sizeof(struct kinfo_proc2 *),
665 		    (int (*)(const void *, const void *))compare);
666 	}
667 
668 	/* remember active and total counts */
669 	si->p_total = total_procs;
670 	si->p_active = pref_len = active_procs;
671 
672 	/* pass back a handle */
673 	handle.next_proc = pref;
674 	handle.remaining = active_procs;
675 	handle.sel = sel;
676 	return((caddr_t)&handle);
677 }
678 
679 static caddr_t
680 get_lwp_info(struct system_info *si, struct process_select *sel,
681 	     int (*compare)(struct proc **, struct proc **))
682 {
683 	int i;
684 	int total_lwps;
685 	int active_lwps;
686 	struct kinfo_lwp **lrefp, **n;
687 	struct kinfo_lwp *lp;
688 	struct kinfo_proc2 *pp;
689 
690 	/* these are copied out of sel for speed */
691 	int show_idle;
692 	int show_system;
693 	int show_uid;
694 	char *show_command;
695 
696 	static struct handle handle;
697 
698 	pp = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2),
699 	    &thread_nproc);
700 	if (pp == NULL) {
701 		(void) fprintf(stderr, "top: Out of memory.\n");
702 		quit(23);
703 	}
704 	if (thread_pbase == NULL || thread_nproc != thread_onproc) {
705 		free(thread_pbase);
706 		thread_onproc = thread_nproc;
707 		thread_pbase = calloc(sizeof(struct kinfo_proc2), thread_nproc);
708 		if (thread_pbase == NULL) {
709 			(void) fprintf(stderr, "top: Out of memory.\n");
710 			quit(23);
711 		}
712 	}
713 	memcpy(thread_pbase, pp, sizeof(struct kinfo_proc2) * thread_nproc);
714 
715 	lbase = kvm_getlwps(kd, -1, 0, sizeof(struct kinfo_lwp), &nlwp);
716 	if (lbase == NULL) {
717 #ifdef notyet
718 		if (sel->pid != (pid_t)-1) {
719 			nproc = 0;
720 			nlwp = 0;
721 		}
722 		else
723 #endif
724 		{
725 			(void) fprintf(stderr, "top: Out of memory.\n");
726 			quit(23);
727 		}
728 	}
729 	if (nlwp > onlwp) {
730 		n = (struct kinfo_lwp **) realloc(lref,
731 		    sizeof(struct kinfo_lwp *) * nlwp);
732 		if (n == NULL) {
733 			(void) fprintf(stderr, "top: Out of memory.\n");
734 			quit(23);
735 		}
736 		lref = n;
737 		onlwp = nlwp;
738 	}
739 	/* get a pointer to the states summary array */
740 	si->procstates = process_states;
741 
742 	/* set up flags which define what we are going to select */
743 	show_idle = sel->idle;
744 	show_system = sel->system;
745 	show_uid = sel->uid != -1;
746 	show_command = sel->command;
747 
748 	/* count up thread states and get pointers to interesting threads */
749 	total_lwps = 0;
750 	active_lwps = 0;
751 	memset((char *)process_states, 0, sizeof(process_states));
752 	lrefp = lref;
753 	for (lp = lbase, i = 0; i < nlwp; lp++, i++) {
754 		if (sel->pid != (pid_t)-1 && sel->pid != (pid_t)lp->l_pid)
755 			continue;
756 
757 		/*
758 		 * Place pointers to each valid lwp structure in lref[].
759 		 * thread slots that are actually in use have a non-zero
760 		 * status field.  threads with L_SYSTEM set are system
761 		 * threads---these get ignored unless show_sysprocs is set.
762 		 */
763 		if (lp->l_stat != 0 && (show_system || ((lp->l_flag & LW_SYSTEM) == 0))) {
764 			total_lwps++;
765 			process_states[(unsigned char) lp->l_stat]++;
766 			if (lp->l_stat != LSZOMB &&
767 			    (show_idle || (lp->l_pctcpu != 0) ||
768 			    (lp->l_stat == LSRUN || lp->l_stat == LSONPROC)) &&
769 			    (!show_uid || uid_from_thread(lp) == sel->uid) &&
770 			    (!show_command ||
771 			     strstr(get_command(sel, proc_from_thread(lp)),
772 				 show_command) != NULL)) {
773 					*lrefp++ = lp;
774 					active_lwps++;
775 			}
776 		}
777 	}
778 
779 	/* if requested, sort the "interesting" threads */
780 	if (compare != NULL) {
781 		qsort((char *)lref, active_lwps, sizeof(struct kinfo_lwp *),
782 		    (int (*)(const void *, const void *))compare);
783 	}
784 
785 	/* remember active and total counts */
786 	si->p_total = total_lwps;
787 	si->p_active = lref_len = active_lwps;
788 
789 	/* pass back a handle */
790 	handle.next_proc = (struct kinfo_proc2 **)lref;
791 	handle.remaining = active_lwps;
792 	handle.sel = sel;
793 
794 	return((caddr_t)&handle);
795 }
796 
797 char *
798 format_next_process(caddr_t handle, char *(*get_userid)(int))
799 {
800 
801 	if (threadmode)
802 		return format_next_lwp(handle, get_userid);
803 	else
804 		return format_next_proc(handle, get_userid);
805 }
806 
807 
808 char *
809 format_next_proc(caddr_t handle, char *(*get_userid)(int))
810 {
811 	struct kinfo_proc2 *pp;
812 	long cputime;
813 	double pct, wcpu, cpu;
814 	struct handle *hp;
815 	const char *statep;
816 #ifdef KI_NOCPU
817 	char state[10];
818 #endif
819 	char wmesg[KI_WMESGLEN + 1];
820 	static char fmt[MAX_COLS];		/* static area where result is built */
821 
822 	/* find and remember the next proc structure */
823 	hp = (struct handle *)handle;
824 	pp = *(hp->next_proc++);
825 	hp->remaining--;
826 
827 	/* get the process's user struct and set cputime */
828 
829 #if 0
830 	/* This does not produce the correct results */
831 	cputime = pp->p_uticks + pp->p_sticks + pp->p_iticks;
832 #else
833 	cputime = pp->p_rtime_sec;	/* This does not count interrupts */
834 #endif
835 
836 	/* calculate the base for CPU percentages */
837 	pct = pctdouble(pp->p_pctcpu);
838 
839 	if (pp->p_stat == LSSLEEP) {
840 		strlcpy(wmesg, pp->p_wmesg, sizeof(wmesg));
841 		statep = wmesg;
842 	} else
843 		statep = state_abbrev[(unsigned)pp->p_stat];
844 
845 #ifdef KI_NOCPU
846 	/* Post-1.5 change: add CPU number if appropriate */
847 	if (pp->p_cpuid != KI_NOCPU && ncpu > 1) {
848 		switch (pp->p_stat) {
849 		case LSONPROC:
850 		case LSRUN:
851 		case LSSLEEP:
852 		case LSIDL:
853 			(void)snprintf(state, sizeof(state), "%.6s/%u",
854 			     statep, (unsigned int)pp->p_cpuid);
855 			statep = state;
856 			break;
857 		}
858 	}
859 #endif
860 	wcpu = 100.0 * weighted_cpu(p_, pct, pp);
861 	cpu = 100.0 * pct;
862 
863 	/* format this entry */
864 	sprintf(fmt,
865 	    Proc_format,
866 	    pp->p_pid,
867 	    (*userprint)(pp->p_ruid),
868 	    pp->p_priority,
869 	    pp->p_nice - NZERO,
870 	    format_k(pagetok(PROCSIZE(pp))),
871 	    format_k(pagetok(pp->p_vm_rssize)),
872 	    statep,
873 	    format_time(cputime),
874 	    (wcpu >= 100.0) ? 0 : 2, wcpu,
875 	    (cpu >= 100.0) ? 0 : 2, cpu,
876 	    get_command(hp->sel, pp));
877 
878 	/* return the result */
879 	return(fmt);
880 }
881 
882 static char *
883 countable(char *p, size_t width)
884 {
885 	size_t len = strlen(p);
886 	if (len < width) {		// shorter than width, ok
887 		return p;
888 	}
889 	size_t first, last = len - 1;
890 	for (first = len - 1; isdigit((unsigned char)p[first]); first--) {
891 		continue;
892 	}
893 	if (first == len - 1) {		// no digits, ok
894 		return p;
895 	}
896 	first++;
897 	last = len - first;
898 	if (width < last + 1) {		// if not enough for digits, done
899 		return p;
900 	}
901 	size_t start = width - last - 1;	// compute starting point
902 	p[start] = '*';			// put a star
903 	memmove(p + start + 1, p + first, last + 1);	// move digits and NUL
904 	return p;
905 }
906 
907 static char *
908 format_next_lwp(caddr_t handle, char *(*get_userid)(int))
909 {
910 	struct kinfo_proc2 *pp;
911 	struct kinfo_lwp *pl;
912 	long cputime;
913 	double pct;
914 	struct handle *hp;
915 	const char *statep;
916 #ifdef KI_NOCPU
917 	char state[10];
918 #endif
919 	char wmesg[KI_WMESGLEN + 1];
920 	static char fmt[MAX_COLS];		/* static area where result is built */
921 	int uid;
922 
923 	/* find and remember the next proc structure */
924 	hp = (struct handle *)handle;
925 	pl = (struct kinfo_lwp *)*(hp->next_proc++);
926 	hp->remaining--;
927 	pp = proc_from_thread(pl);
928 
929 	/* get the process's user struct and set cputime */
930 	uid = pp ? pp->p_ruid : 0;
931 
932 	cputime = pl->l_rtime_sec;
933 
934 	/* calculate the base for CPU percentages */
935 	pct = pctdouble(pl->l_pctcpu);
936 
937 	if (pl->l_stat == LSSLEEP) {
938 		strlcpy(wmesg, pl->l_wmesg, sizeof(wmesg));
939 		statep = wmesg;
940 	} else
941 		statep = state_abbrev[(unsigned)pl->l_stat];
942 
943 #ifdef KI_NOCPU
944 	/* Post-1.5 change: add CPU number if appropriate */
945 	if (pl->l_cpuid != KI_NOCPU && ncpu > 1) {
946 		switch (pl->l_stat) {
947 		case LSONPROC:
948 		case LSRUN:
949 		case LSSLEEP:
950 		case LSIDL:
951 			(void)snprintf(state, sizeof(state), "%.6s/%u",
952 			     statep, (unsigned int)pl->l_cpuid);
953 			statep = state;
954 			break;
955 		}
956 	}
957 #endif
958 
959 	if (pl->l_name[0] == '\0') {
960 		pl->l_name[0] = '-';
961 		pl->l_name[1] = '\0';
962 	}
963 
964 	/* format this entry */
965 	sprintf(fmt,
966 	    Thread_format,
967 	    pl->l_pid,
968 	    pl->l_lid,
969 	    (*userprint)(uid),
970 	    pl->l_priority,
971 	    statep,
972 	    format_time(cputime),
973 	    100.0 * weighted_cpu(l_, pct, pl),
974 	    100.0 * pct,
975 	    countable(printable(pl->l_name), 9),
976 	    get_command(hp->sel, pp));
977 
978 	/* return the result */
979 	return(fmt);
980 }
981 
982 /* comparison routines for qsort */
983 
984 /*
985  * There are currently four possible comparison routines.  main selects
986  * one of these by indexing in to the array proc_compares.
987  *
988  * Possible keys are defined as macros below.  Currently these keys are
989  * defined:  percent CPU, CPU ticks, process state, resident set size,
990  * total virtual memory usage.  The process states are ordered as follows
991  * (from least to most important):  WAIT, zombie, sleep, stop, start, run.
992  * The array declaration below maps a process state index into a number
993  * that reflects this ordering.
994  */
995 
996 /*
997  * First, the possible comparison keys.  These are defined in such a way
998  * that they can be merely listed in the source code to define the actual
999  * desired ordering.
1000  */
1001 
1002 #define ORDERKEY_PCTCPU(pfx) \
1003 	if (lresult = (pctcpu)(p2)->pfx ## pctcpu - (pctcpu)(p1)->pfx ## pctcpu,\
1004 	    (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
1005 
1006 #define ORDERKEY_CPTICKS(pfx) \
1007 	if (lresult = (pctcpu)(p2)->pfx ## rtime_sec \
1008 		    - (pctcpu)(p1)->pfx ## rtime_sec,\
1009 	    (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
1010 
1011 #define ORDERKEY_STATE(pfx) \
1012 	if ((result = sorted_state[(int)(p2)->pfx ## stat] - \
1013 		      sorted_state[(int)(p1)->pfx ## stat] ) == 0)
1014 
1015 #define ORDERKEY_PRIO(pfx) \
1016 	if ((result = (p2)->pfx ## priority - (p1)->pfx ## priority) == 0)
1017 
1018 #define ORDERKEY_RSSIZE \
1019 	if ((result = p2->p_vm_rssize - p1->p_vm_rssize) == 0)
1020 
1021 #define ORDERKEY_MEM	\
1022 	if ((result = (PROCSIZE(p2) - PROCSIZE(p1))) == 0)
1023 #define ORDERKEY_SIZE(v1, v2)	\
1024 	if ((result = (v2 - v1)) == 0)
1025 
1026 /*
1027  * Now the array that maps process state to a weight.
1028  * The order of the elements should match those in state_abbrev[]
1029  */
1030 
1031 static int sorted_state[] = {
1032 	0,	/*  (not used)	  ?	*/
1033 	1,	/* "start"	SIDL	*/
1034 	4,	/* "run"	SRUN	*/
1035 	3,	/* "sleep"	SSLEEP	*/
1036 	3,	/* "stop"	SSTOP	*/
1037 	2,	/* "dead"	SDEAD	*/
1038 	1,	/* "zomb"	SZOMB	*/
1039 	5,	/* "onproc"	SONPROC	*/
1040 };
1041 
1042 /* compare_cpu - the comparison function for sorting by CPU percentage */
1043 
1044 static int
1045 compare_cpu(pp1, pp2)
1046 	struct proc **pp1, **pp2;
1047 {
1048 	int result;
1049 	pctcpu lresult;
1050 
1051 	if (threadmode) {
1052 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
1053 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
1054 
1055 		ORDERKEY_PCTCPU(l_)
1056 		ORDERKEY_CPTICKS(l_)
1057 		ORDERKEY_STATE(l_)
1058 		ORDERKEY_PRIO(l_)
1059 		return result;
1060 	} else {
1061 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1062 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1063 
1064 		ORDERKEY_PCTCPU(p_)
1065 		ORDERKEY_CPTICKS(p_)
1066 		ORDERKEY_STATE(p_)
1067 		ORDERKEY_PRIO(p_)
1068 		ORDERKEY_RSSIZE
1069 		ORDERKEY_MEM
1070 		return result;
1071 	}
1072 
1073 	return (result);
1074 }
1075 
1076 /* compare_prio - the comparison function for sorting by process priority */
1077 
1078 static int
1079 compare_prio(pp1, pp2)
1080 	struct proc **pp1, **pp2;
1081 {
1082 	int result;
1083 	pctcpu lresult;
1084 
1085 	if (threadmode) {
1086 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
1087 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
1088 
1089 		ORDERKEY_PRIO(l_)
1090 		ORDERKEY_PCTCPU(l_)
1091 		ORDERKEY_CPTICKS(l_)
1092 		ORDERKEY_STATE(l_)
1093 		return result;
1094 	} else {
1095 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1096 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1097 
1098 		ORDERKEY_PRIO(p_)
1099 		ORDERKEY_PCTCPU(p_)
1100 		ORDERKEY_CPTICKS(p_)
1101 		ORDERKEY_STATE(p_)
1102 		ORDERKEY_RSSIZE
1103 		ORDERKEY_MEM
1104 		return result;
1105 	}
1106 
1107 	return (result);
1108 }
1109 
1110 /* compare_res - the comparison function for sorting by resident set size */
1111 
1112 static int
1113 compare_res(pp1, pp2)
1114 	struct proc **pp1, **pp2;
1115 {
1116 	int result;
1117 	pctcpu lresult;
1118 
1119 	if (threadmode) {
1120 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
1121 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
1122 
1123 		ORDERKEY_PCTCPU(l_)
1124 		ORDERKEY_CPTICKS(l_)
1125 		ORDERKEY_STATE(l_)
1126 		ORDERKEY_PRIO(l_)
1127 		return result;
1128 	} else {
1129 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1130 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1131 
1132 		ORDERKEY_RSSIZE
1133 		ORDERKEY_MEM
1134 		ORDERKEY_PCTCPU(p_)
1135 		ORDERKEY_CPTICKS(p_)
1136 		ORDERKEY_STATE(p_)
1137 		ORDERKEY_PRIO(p_)
1138 		return result;
1139 	}
1140 
1141 	return (result);
1142 }
1143 
1144 static int
1145 compare_pid(pp1, pp2)
1146 	struct proc **pp1, **pp2;
1147 {
1148 	if (threadmode) {
1149 		struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1;
1150 		struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2;
1151 		struct kinfo_proc2 *p1 = proc_from_thread(l1);
1152 		struct kinfo_proc2 *p2 = proc_from_thread(l2);
1153 		return p2->p_pid - p1->p_pid;
1154 	} else {
1155 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1156 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1157 		return p2->p_pid - p1->p_pid;
1158 	}
1159 }
1160 
1161 static int
1162 compare_command(pp1, pp2)
1163 	struct proc **pp1, **pp2;
1164 {
1165 	if (threadmode) {
1166 		struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1;
1167 		struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2;
1168 		struct kinfo_proc2 *p1 = proc_from_thread(l1);
1169 		struct kinfo_proc2 *p2 = proc_from_thread(l2);
1170 		return strcmp(p2->p_comm, p1->p_comm);
1171 	} else {
1172 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1173 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1174 		return strcmp(p2->p_comm, p1->p_comm);
1175 	}
1176 }
1177 
1178 static int
1179 compare_username(pp1, pp2)
1180 	struct proc **pp1, **pp2;
1181 {
1182 	if (threadmode) {
1183 		struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1;
1184 		struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2;
1185 		struct kinfo_proc2 *p1 = proc_from_thread(l1);
1186 		struct kinfo_proc2 *p2 = proc_from_thread(l2);
1187 		return strcmp(p2->p_login, p1->p_login);
1188 	} else {
1189 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1190 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1191 		return strcmp(p2->p_login, p1->p_login);
1192 	}
1193 }
1194 /* compare_size - the comparison function for sorting by total memory usage */
1195 
1196 static int
1197 compare_size(pp1, pp2)
1198 	struct proc **pp1, **pp2;
1199 {
1200 	int result;
1201 	pctcpu lresult;
1202 
1203 	if (threadmode) {
1204 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
1205 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
1206 
1207 		ORDERKEY_PCTCPU(l_)
1208 		ORDERKEY_CPTICKS(l_)
1209 		ORDERKEY_STATE(l_)
1210 		ORDERKEY_PRIO(l_)
1211 		return result;
1212 	} else {
1213 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1214 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1215 
1216 		ORDERKEY_MEM
1217 		ORDERKEY_RSSIZE
1218 		ORDERKEY_PCTCPU(p_)
1219 		ORDERKEY_CPTICKS(p_)
1220 		ORDERKEY_STATE(p_)
1221 		ORDERKEY_PRIO(p_)
1222 		return result;
1223 	}
1224 
1225 	return (result);
1226 }
1227 
1228 /* compare_state - the comparison function for sorting by process state */
1229 
1230 static int
1231 compare_state(pp1, pp2)
1232 	struct proc **pp1, **pp2;
1233 {
1234 	int result;
1235 	pctcpu lresult;
1236 
1237 	if (threadmode) {
1238 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
1239 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
1240 
1241 		ORDERKEY_STATE(l_)
1242 		ORDERKEY_PCTCPU(l_)
1243 		ORDERKEY_CPTICKS(l_)
1244 		ORDERKEY_PRIO(l_)
1245 		return result;
1246 	} else {
1247 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1248 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1249 
1250 		ORDERKEY_STATE(p_)
1251 		ORDERKEY_PCTCPU(p_)
1252 		ORDERKEY_CPTICKS(p_)
1253 		ORDERKEY_PRIO(p_)
1254 		ORDERKEY_RSSIZE
1255 		ORDERKEY_MEM
1256 		return result;
1257 	}
1258 
1259 	return (result);
1260 }
1261 
1262 /* compare_time - the comparison function for sorting by total CPU time */
1263 
1264 static int
1265 compare_time(pp1, pp2)
1266 	struct proc **pp1, **pp2;
1267 {
1268 	int result;
1269 	pctcpu lresult;
1270 
1271 	if (threadmode) {
1272 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
1273 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
1274 
1275 		ORDERKEY_CPTICKS(l_)
1276 		ORDERKEY_PCTCPU(l_)
1277 		ORDERKEY_STATE(l_)
1278 		ORDERKEY_PRIO(l_)
1279 		return result;
1280 	} else {
1281 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1282 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1283 
1284 		ORDERKEY_CPTICKS(p_)
1285 		ORDERKEY_PCTCPU(p_)
1286 		ORDERKEY_STATE(p_)
1287 		ORDERKEY_PRIO(p_)
1288 		ORDERKEY_MEM
1289 		ORDERKEY_RSSIZE
1290 		return result;
1291 	}
1292 
1293 	return (result);
1294 }
1295 
1296 
1297 /*
1298  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
1299  *		the process does not exist.
1300  *		It is EXTREMLY IMPORTANT that this function work correctly.
1301  *		If top runs setuid root (as in SVR4), then this function
1302  *		is the only thing that stands in the way of a serious
1303  *		security problem.  It validates requests for the "kill"
1304  *		and "renice" commands.
1305  */
1306 
1307 int
1308 proc_owner(pid)
1309 	int pid;
1310 {
1311 	int cnt;
1312 	struct kinfo_proc2 **prefp;
1313 	struct kinfo_proc2 *pp;
1314 
1315 	if (threadmode)
1316 		return(-1);
1317 
1318 	prefp = pref;
1319 	cnt = pref_len;
1320 	while (--cnt >= 0) {
1321 		pp = *prefp++;
1322 		if (pp->p_pid == (pid_t)pid)
1323 			return(pp->p_ruid);
1324 	}
1325 	return(-1);
1326 }
1327 
1328 /*
1329  *  percentages(cnt, out, new, old, diffs) - calculate percentage change
1330  *	between array "old" and "new", putting the percentages i "out".
1331  *	"cnt" is size of each array and "diffs" is used for scratch space.
1332  *	The array "old" is updated on each call.
1333  *	The routine assumes modulo arithmetic.  This function is especially
1334  *	useful on BSD mchines for calculating CPU state percentages.
1335  */
1336 
1337 static void
1338 percentages64(cnt, out, new, old, diffs)
1339 	int cnt;
1340 	int *out;
1341 	u_int64_t *new;
1342 	u_int64_t *old;
1343 	u_int64_t *diffs;
1344 {
1345 	int i;
1346 	u_int64_t change;
1347 	u_int64_t total_change;
1348 	u_int64_t *dp;
1349 	u_int64_t half_total;
1350 
1351 	/* initialization */
1352 	total_change = 0;
1353 	dp = diffs;
1354 
1355 	/* calculate changes for each state and the overall change */
1356 	for (i = 0; i < cnt; i++) {
1357 		/*
1358 		 * Don't worry about wrapping - even at hz=1GHz, a
1359 		 * u_int64_t will last at least 544 years.
1360 		 */
1361 		change = *new - *old;
1362 		total_change += (*dp++ = change);
1363 		*old++ = *new++;
1364 	}
1365 
1366 	/* avoid divide by zero potential */
1367 	if (total_change == 0)
1368 		total_change = 1;
1369 
1370 	/* calculate percentages based on overall change, rounding up */
1371 	half_total = total_change / 2;
1372 	for (i = 0; i < cnt; i++)
1373 		*out++ = (int)((*diffs++ * 1000 + half_total) / total_change);
1374 }
1375