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