1 /* $NetBSD: m_netbsd.c,v 1.10 2009/07/27 16:26:48 njoly Exp $ */
4 * top - a top users display for Unix
6 * SYNOPSIS: For a NetBSD-1.5 (or later) system
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.
17 * This is the machine-dependent module for NetBSD-1.5 and later
20 * and should work for:
21 * NetBSD-2.0 (when released)
23 * top does not need to be installed setuid or setgid with this module.
27 * CFLAGS: -DHAVE_GETOPT -DORDER -DHAVE_STRERROR
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>
40 * $Id: m_netbsd.c,v 1.11 2009/10/21 21:11:57 rmind Exp $
42 #include <sys/cdefs.h>
45 __RCSID("$NetBSD: m_netbsd.c,v 1.10 2009/07/27 16:26:48 njoly Exp $");
48 #include <sys/param.h>
49 #include <sys/sysctl.h>
50 #include <sys/sched.h>
53 #include <uvm/uvm_extern.h>
73 static void percentages64
__P((int, int *, u_int64_t
*, u_int64_t
*,
75 static int get_cpunum
__P((u_int64_t
));
78 /* get_process_info passes back a handle. This is what it looks like: */
81 struct kinfo_proc2
**next_proc
; /* points to next valid proc pointer */
82 int remaining
; /* number of pointers remaining */
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))))
89 /* what we consider to be process size: */
90 /* NetBSD introduced p_vm_msize with RLIMIT_AS */
92 #define PROCSIZE(pp) \
95 #define PROCSIZE(pp) \
96 ((pp)->p_vm_tsize + (pp)->p_vm_dsize + (pp)->p_vm_ssize)
101 * These definitions control the format of the per-process area
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"
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"
119 * Process state names for the "STATE" column of the display.
122 const char *state_abbrev
[] = {
123 "", "IDLE", "RUN", "SLEEP", "STOP", "ZOMB", "DEAD", "CPU"
128 static char *(*userprint
)(int);
130 /* these are retrieved from the kernel in _init */
132 static double logcpu
;
136 /* these are for calculating CPU state percentages */
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
;
144 /* these are for detailing the process states */
146 int process_states
[8];
147 const char *procstatenames
[] = {
148 "", " idle, ", " runnable, ", " sleeping, ", " stopped, ",
149 " zombie, ", " dead, ", " on CPU, ",
153 /* these are for detailing the CPU states */
156 const char *cpustatenames
[] = {
157 "user", "nice", "system", "interrupt", "idle", NULL
160 /* these are for detailing the memory statistics */
162 long memory_stats
[7];
163 const char *memorynames
[] = {
164 "K Act, ", "K Inact, ", "K Wired, ", "K Exec, ", "K File, ",
170 const char *swapnames
[] = {
171 "K Total, ", "K Used, ", "K Free, ",
176 /* these are names given to allowed sorting orders -- first is default */
177 const char *ordernames
[] = {
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
**));
201 int (*proc_compares
[]) __P((struct proc
**, struct proc
**)) = {
214 static char *format_next_lwp(caddr_t
, char *(*)(int));
215 static char *format_next_proc(caddr_t
, char *(*)(int));
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
**));
222 /* these are for keeping track of the proc array */
225 static int onproc
= -1;
227 static int onlwp
= -1;
230 static struct kinfo_proc2
*pbase
;
231 static struct kinfo_lwp
*lbase
;
232 static struct kinfo_proc2
**pref
;
233 static struct kinfo_lwp
**lref
;
237 static int thread_nproc
;
238 static int thread_onproc
= -1;
239 static struct kinfo_proc2
*thread_pbase
;
241 /* these are for getting the memory statistics */
243 static int pageshift
; /* log base 2 of the pagesize */
247 /* define pagetok in terms of pageshift */
249 #define pagetok(size) ((size) << pageshift)
256 for (i
= 0; i
< ncpu
; i
++)
263 machine_init(statics
)
264 struct statics
*statics
;
269 struct clockinfo clockinfo
;
270 struct timeval boottime
;
272 if ((kd
= kvm_open(NULL
, NULL
, NULL
, KVM_NO_FILES
, "kvm_open")) == NULL
)
278 if (sysctl(mib
, 2, &ncpu
, &size
, NULL
, 0) == -1) {
279 fprintf(stderr
, "top: sysctl hw.ncpu failed: %s\n",
283 statics
->ncpu
= ncpu
;
284 cp_time
= malloc(sizeof(cp_time
[0]) * CPUSTATES
* ncpu
);
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",
294 /* Handle old call that returned only aggregate */
295 if (size
== sizeof(cp_time
[0]) * CPUSTATES
)
298 cp_id
= malloc(sizeof(cp_id
[0]) * ncpu
);
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",
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
||
312 fprintf(stderr
, "top: machine_init: %s\n",
320 if (sysctl(mib
, 2, &ccpu
, &size
, NULL
, 0) == -1) {
321 fprintf(stderr
, "top: sysctl kern.ccpu failed: %s\n",
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",
334 hz
= clockinfo
.stathz
;
336 /* this is used in calculating WCPU -- calculate it ahead of time */
337 logcpu
= log(loaddouble(ccpu
));
346 /* get the page size with "getpagesize" and calculate pageshift from it */
347 pagesize
= getpagesize();
349 while (pagesize
> 1) {
354 /* we only need the amount of log(2)1024 for our conversion */
355 pageshift
-= LOG1024
;
357 /* fill in the statics information */
359 statics
->ncpu
= ncpu
;
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;
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
;
375 statics
->boottime
= 0;
381 format_process_header(struct process_select
*sel
, caddr_t handle
, int count
)
386 const char *uname_field
= sel
->usernames
? "USERNAME" : " UID ";
389 header
= Thread_header
;
390 ptr
= header
+ THREAD_UNAME_START
;
392 header
= Proc_header
;
393 ptr
= header
+ PROC_UNAME_START
;
396 while (*uname_field
!= '\0') {
397 *ptr
++ = *uname_field
++;
404 format_header(char *uname_field
)
406 char *header
= Proc_header
;
407 char *ptr
= header
+ PROC_UNAME_START
;
409 while (*uname_field
!= '\0') {
410 *ptr
++ = *uname_field
++;
417 get_system_info(struct system_info
*si
)
421 struct uvmexp_sysctl uvmexp
;
423 u_int64_t totalsize
, totalinuse
;
424 int size
, inuse
, ncounted
, i
;
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",
436 if (getloadavg(si
->load_avg
, NUM_AVERAGES
) < 0) {
439 warn("can't getloadavg");
440 for (j
= 0; j
< NUM_AVERAGES
; j
++)
441 si
->load_avg
[j
] = 0.0;
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
,
453 ssize
= sizeof(uvmexp
);
454 if (sysctl(mib
, 2, &uvmexp
, &ssize
, NULL
, 0) < 0) {
455 fprintf(stderr
, "top: sysctl vm.uvmexp2 failed: %s\n",
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
);
468 swap_stats
[0] = swap_stats
[1] = swap_stats
[2] = 0;
471 nswap
= swapctl(SWAP_NSWAP
, 0, 0);
474 if (nswap
> maxswap
) {
477 swapp
= sep
= malloc(nswap
* sizeof(*sep
));
483 rnswap
= swapctl(SWAP_STATS
, (void *)sep
, nswap
);
487 totalsize
= totalinuse
= ncounted
= 0;
488 for (; rnswap
-- > 0; sep
++) {
490 size
= sep
->se_nblks
;
491 inuse
= sep
->se_inuse
;
495 swap_stats
[0] = dbtob(totalsize
) / 1024;
496 swap_stats
[1] = dbtob(totalinuse
) / 1024;
497 swap_stats
[2] = dbtob(totalsize
) / 1024 - swap_stats
[1];
500 memory_stats
[6] = -1;
503 /* set arrays and strings */
504 si
->cpustates
= cpu_states
;
505 si
->memory
= memory_stats
;
506 si
->swap
= swap_stats
;
511 static struct kinfo_proc2
*
512 proc_from_thread(struct kinfo_lwp
*pl
)
514 struct kinfo_proc2
*pp
= thread_pbase
;
517 for (i
= 0; i
< thread_nproc
; i
++, pp
++)
518 if ((pid_t
)pp
->p_pid
== (pid_t
)pl
->l_pid
)
524 uid_from_thread(struct kinfo_lwp
*pl
)
526 struct kinfo_proc2
*pp
;
528 if ((pp
= proc_from_thread(pl
)) == NULL
)
534 get_process_info(struct system_info
*si
, struct process_select
*sel
, int c
)
536 userprint
= sel
->usernames
? username
: itoa7
;
538 if ((threadmode
= sel
->threads
) != 0)
539 return get_lwp_info(si
, sel
, proc_compares
[c
]);
541 return get_proc_info(si
, sel
, proc_compares
[c
]);
545 get_proc_info(struct system_info
*si
, struct process_select
*sel
,
546 int (*compare
)(struct proc
**, struct proc
**))
551 struct kinfo_proc2
**prefp
, **n
;
552 struct kinfo_proc2
*pp
;
555 /* these are copied out of sel for speed */
561 static struct handle handle
;
565 if (sel
->pid
== (pid_t
)-1) {
573 pbase
= kvm_getproc2(kd
, op
, arg
, sizeof(struct kinfo_proc2
), &nproc
);
575 if (sel
->pid
!= (pid_t
)-1) {
578 (void) fprintf(stderr
, "top: Out of memory.\n");
582 if (nproc
> onproc
) {
583 n
= (struct kinfo_proc2
**) realloc(pref
,
584 sizeof(struct kinfo_proc2
*) * nproc
);
586 (void) fprintf(stderr
, "top: Out of memory.\n");
592 /* get a pointer to the states summary array */
593 si
->procstates
= process_states
;
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
;
601 /* count up process states and get pointers to interesting procs */
604 memset((char *)process_states
, 0, sizeof(process_states
));
606 for (pp
= pbase
, i
= 0; i
< nproc
; pp
++, i
++) {
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.
614 if (pp
->p_stat
!= 0 && (show_system
|| ((pp
->p_flag
& P_SYSTEM
) == 0))) {
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
)) {
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
);
633 /* remember active and total counts */
634 si
->p_total
= total_procs
;
635 si
->p_active
= pref_len
= active_procs
;
637 /* pass back a handle */
638 handle
.next_proc
= pref
;
639 handle
.remaining
= active_procs
;
640 return((caddr_t
)&handle
);
644 get_lwp_info(struct system_info
*si
, struct process_select
*sel
,
645 int (*compare
)(struct proc
**, struct proc
**))
650 struct kinfo_lwp
**lrefp
, **n
;
651 struct kinfo_lwp
*lp
;
652 struct kinfo_proc2
*pp
;
654 /* these are copied out of sel for speed */
660 static struct handle handle
;
662 pp
= kvm_getproc2(kd
, KERN_PROC_ALL
, 0, sizeof(struct kinfo_proc2
),
665 (void) fprintf(stderr
, "top: Out of memory.\n");
668 if (thread_pbase
== NULL
|| thread_nproc
!= thread_onproc
) {
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");
677 memcpy(thread_pbase
, pp
, sizeof(struct kinfo_proc2
) * thread_nproc
);
679 lbase
= kvm_getlwps(kd
, -1, 0, sizeof(struct kinfo_lwp
), &nlwp
);
682 if (sel
->pid
!= (pid_t
)-1) {
689 (void) fprintf(stderr
, "top: Out of memory.\n");
694 n
= (struct kinfo_lwp
**) realloc(lref
,
695 sizeof(struct kinfo_lwp
*) * nlwp
);
697 (void) fprintf(stderr
, "top: Out of memory.\n");
703 /* get a pointer to the states summary array */
704 si
->procstates
= process_states
;
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
;
712 /* count up thread states and get pointers to interesting threads */
715 memset((char *)process_states
, 0, sizeof(process_states
));
717 for (lp
= lbase
, i
= 0; i
< nlwp
; lp
++, i
++) {
718 if (sel
->pid
!= (pid_t
)-1 && sel
->pid
!= (pid_t
)lp
->l_pid
)
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.
727 if (lp
->l_stat
!= 0 && (show_system
|| ((lp
->l_flag
& LW_SYSTEM
) == 0))) {
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
)) {
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
);
746 /* remember active and total counts */
747 si
->p_total
= total_lwps
;
748 si
->p_active
= lref_len
= active_lwps
;
750 /* pass back a handle */
751 handle
.next_proc
= (struct kinfo_proc2
**)lref
;
752 handle
.remaining
= active_lwps
;
754 return((caddr_t
)&handle
);
758 format_next_process(caddr_t handle
, char *(*get_userid
)(int))
762 return format_next_lwp(handle
, get_userid
);
764 return format_next_proc(handle
, get_userid
);
769 format_next_proc(caddr_t handle
, char *(*get_userid
)(int))
771 struct kinfo_proc2
*pp
;
773 double pct
, wcpu
, cpu
;
779 char wmesg
[KI_WMESGLEN
+ 1];
780 static char fmt
[MAX_COLS
]; /* static area where result is built */
781 const char *pretty
= "";
783 /* find and remember the next proc structure */
784 hp
= (struct handle
*)handle
;
785 pp
= *(hp
->next_proc
++);
788 /* get the process's user struct and set cputime */
789 if ((pp
->p_flag
& P_SYSTEM
) != 0)
792 if (pretty
[0] != '\0') {
794 * Print swapped processes as <pname> and
795 * system processes as [pname]
797 char *comm
= pp
->p_comm
;
798 #define COMSIZ sizeof(pp->p_comm)
800 (void) strncpy(buf
, comm
, COMSIZ
);
802 (void) strncpy(&comm
[1], buf
, COMSIZ
- 2);
803 comm
[COMSIZ
- 2] = '\0';
804 (void) strncat(comm
, &pretty
[1], COMSIZ
- 1);
805 comm
[COMSIZ
- 1] = '\0';
809 /* This does not produce the correct results */
810 cputime
= pp
->p_uticks
+ pp
->p_sticks
+ pp
->p_iticks
;
812 cputime
= pp
->p_rtime_sec
; /* This does not count interrupts */
815 /* calculate the base for CPU percentages */
816 pct
= pctdouble(pp
->p_pctcpu
);
818 if (pp
->p_stat
== LSSLEEP
) {
819 strlcpy(wmesg
, pp
->p_wmesg
, sizeof(wmesg
));
822 statep
= state_abbrev
[(unsigned)pp
->p_stat
];
825 /* Post-1.5 change: add CPU number if appropriate */
826 if (pp
->p_cpuid
!= KI_NOCPU
&& ncpu
> 1) {
827 switch (pp
->p_stat
) {
832 (void)snprintf(state
, sizeof(state
), "%.6s/%d",
833 statep
, get_cpunum(pp
->p_cpuid
));
839 wcpu
= 100.0 * weighted_cpu(p_
, pct
, pp
);
842 /* format this entry */
846 (*userprint
)(pp
->p_ruid
),
849 format_k(pagetok(PROCSIZE(pp
))),
850 format_k(pagetok(pp
->p_vm_rssize
)),
852 format_time(cputime
),
853 (wcpu
>= 100.0) ? 0 : 2, wcpu
,
854 (cpu
>= 100.0) ? 0 : 2, cpu
,
855 printable(pp
->p_comm
));
857 /* return the result */
862 format_next_lwp(caddr_t handle
, char *(*get_userid
)(int))
864 struct kinfo_proc2
*pp
;
865 struct kinfo_lwp
*pl
;
870 static char gone
[] = "<gone>";
874 char wmesg
[KI_WMESGLEN
+ 1];
875 static char fmt
[MAX_COLS
]; /* static area where result is built */
876 const char *pretty
= "";
880 /* find and remember the next proc structure */
881 hp
= (struct handle
*)handle
;
882 pl
= (struct kinfo_lwp
*)*(hp
->next_proc
++);
884 pp
= proc_from_thread(pl
);
886 /* get the process's user struct and set cputime */
889 if ((pp
->p_flag
& P_SYSTEM
) != 0)
892 if (pretty
[0] != '\0' && comm
[0] != pretty
[0]) {
894 * Print swapped processes as <pname> and
895 * system processes as [pname]
897 #define COMSIZ sizeof(pp->p_comm)
899 (void) strncpy(buf
, comm
, COMSIZ
);
901 (void) strncpy(&comm
[1], buf
, COMSIZ
- 2);
902 comm
[COMSIZ
- 2] = '\0';
903 (void) strncat(comm
, &pretty
[1], COMSIZ
- 1);
904 comm
[COMSIZ
- 1] = '\0';
912 cputime
= pl
->l_rtime_sec
;
914 /* calculate the base for CPU percentages */
915 pct
= pctdouble(pl
->l_pctcpu
);
917 if (pl
->l_stat
== LSSLEEP
) {
918 strlcpy(wmesg
, pl
->l_wmesg
, sizeof(wmesg
));
921 statep
= state_abbrev
[(unsigned)pl
->l_stat
];
924 /* Post-1.5 change: add CPU number if appropriate */
925 if (pl
->l_cpuid
!= KI_NOCPU
&& ncpu
> 1) {
926 switch (pl
->l_stat
) {
931 (void)snprintf(state
, sizeof(state
), "%.6s/%d",
932 statep
, get_cpunum(pl
->l_cpuid
));
939 if (pl
->l_name
[0] == '\0') {
941 pl
->l_name
[1] = '\0';
944 /* format this entry */
952 format_time(cputime
),
953 100.0 * weighted_cpu(l_
, pct
, pl
),
956 printable(pl
->l_name
));
958 /* return the result */
962 /* comparison routines for qsort */
965 * There are currently four possible comparison routines. main selects
966 * one of these by indexing in to the array proc_compares.
968 * Possible keys are defined as macros below. Currently these keys are
969 * defined: percent CPU, CPU ticks, process state, resident set size,
970 * total virtual memory usage. The process states are ordered as follows
971 * (from least to most important): WAIT, zombie, sleep, stop, start, run.
972 * The array declaration below maps a process state index into a number
973 * that reflects this ordering.
977 * First, the possible comparison keys. These are defined in such a way
978 * that they can be merely listed in the source code to define the actual
982 #define ORDERKEY_PCTCPU(pfx) \
983 if (lresult = (pctcpu)(p2)->pfx ## pctcpu - (pctcpu)(p1)->pfx ## pctcpu,\
984 (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
986 #define ORDERKEY_CPTICKS(pfx) \
987 if (lresult = (pctcpu)(p2)->pfx ## rtime_sec \
988 - (pctcpu)(p1)->pfx ## rtime_sec,\
989 (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
991 #define ORDERKEY_STATE(pfx) \
992 if ((result = sorted_state[(int)(p2)->pfx ## stat] - \
993 sorted_state[(int)(p1)->pfx ## stat] ) == 0)
995 #define ORDERKEY_PRIO(pfx) \
996 if ((result = (p2)->pfx ## priority - (p1)->pfx ## priority) == 0)
998 #define ORDERKEY_RSSIZE \
999 if ((result = p2->p_vm_rssize - p1->p_vm_rssize) == 0)
1001 #define ORDERKEY_MEM \
1002 if ((result = (PROCSIZE(p2) - PROCSIZE(p1))) == 0)
1003 #define ORDERKEY_SIZE(v1, v2) \
1004 if ((result = (v2 - v1)) == 0)
1007 * Now the array that maps process state to a weight.
1008 * The order of the elements should match those in state_abbrev[]
1011 static int sorted_state
[] = {
1012 0, /* (not used) ? */
1013 1, /* "start" SIDL */
1015 3, /* "sleep" SSLEEP */
1016 3, /* "stop" SSTOP */
1017 2, /* "dead" SDEAD */
1018 1, /* "zomb" SZOMB */
1019 5, /* "onproc" SONPROC */
1022 /* compare_cpu - the comparison function for sorting by CPU percentage */
1025 compare_cpu(pp1
, pp2
)
1026 struct proc
**pp1
, **pp2
;
1032 struct kinfo_lwp
*p1
= *(struct kinfo_lwp
**) pp1
;
1033 struct kinfo_lwp
*p2
= *(struct kinfo_lwp
**) pp2
;
1036 ORDERKEY_CPTICKS(l_
)
1041 struct kinfo_proc2
*p1
= *(struct kinfo_proc2
**) pp1
;
1042 struct kinfo_proc2
*p2
= *(struct kinfo_proc2
**) pp2
;
1045 ORDERKEY_CPTICKS(p_
)
1056 /* compare_prio - the comparison function for sorting by process priority */
1059 compare_prio(pp1
, pp2
)
1060 struct proc
**pp1
, **pp2
;
1066 struct kinfo_lwp
*p1
= *(struct kinfo_lwp
**) pp1
;
1067 struct kinfo_lwp
*p2
= *(struct kinfo_lwp
**) pp2
;
1071 ORDERKEY_CPTICKS(l_
)
1075 struct kinfo_proc2
*p1
= *(struct kinfo_proc2
**) pp1
;
1076 struct kinfo_proc2
*p2
= *(struct kinfo_proc2
**) pp2
;
1080 ORDERKEY_CPTICKS(p_
)
1090 /* compare_res - the comparison function for sorting by resident set size */
1093 compare_res(pp1
, pp2
)
1094 struct proc
**pp1
, **pp2
;
1100 struct kinfo_lwp
*p1
= *(struct kinfo_lwp
**) pp1
;
1101 struct kinfo_lwp
*p2
= *(struct kinfo_lwp
**) pp2
;
1104 ORDERKEY_CPTICKS(l_
)
1109 struct kinfo_proc2
*p1
= *(struct kinfo_proc2
**) pp1
;
1110 struct kinfo_proc2
*p2
= *(struct kinfo_proc2
**) pp2
;
1115 ORDERKEY_CPTICKS(p_
)
1125 compare_pid(pp1
, pp2
)
1126 struct proc
**pp1
, **pp2
;
1129 struct kinfo_lwp
*l1
= *(struct kinfo_lwp
**) pp1
;
1130 struct kinfo_lwp
*l2
= *(struct kinfo_lwp
**) pp2
;
1131 struct kinfo_proc2
*p1
= proc_from_thread(l1
);
1132 struct kinfo_proc2
*p2
= proc_from_thread(l2
);
1133 return p2
->p_pid
- p1
->p_pid
;
1135 struct kinfo_proc2
*p1
= *(struct kinfo_proc2
**) pp1
;
1136 struct kinfo_proc2
*p2
= *(struct kinfo_proc2
**) pp2
;
1137 return p2
->p_pid
- p1
->p_pid
;
1142 compare_command(pp1
, pp2
)
1143 struct proc
**pp1
, **pp2
;
1146 struct kinfo_lwp
*l1
= *(struct kinfo_lwp
**) pp1
;
1147 struct kinfo_lwp
*l2
= *(struct kinfo_lwp
**) pp2
;
1148 struct kinfo_proc2
*p1
= proc_from_thread(l1
);
1149 struct kinfo_proc2
*p2
= proc_from_thread(l2
);
1150 return strcmp(p2
->p_comm
, p1
->p_comm
);
1152 struct kinfo_proc2
*p1
= *(struct kinfo_proc2
**) pp1
;
1153 struct kinfo_proc2
*p2
= *(struct kinfo_proc2
**) pp2
;
1154 return strcmp(p2
->p_comm
, p1
->p_comm
);
1159 compare_username(pp1
, pp2
)
1160 struct proc
**pp1
, **pp2
;
1163 struct kinfo_lwp
*l1
= *(struct kinfo_lwp
**) pp1
;
1164 struct kinfo_lwp
*l2
= *(struct kinfo_lwp
**) pp2
;
1165 struct kinfo_proc2
*p1
= proc_from_thread(l1
);
1166 struct kinfo_proc2
*p2
= proc_from_thread(l2
);
1167 return strcmp(p2
->p_login
, p1
->p_login
);
1169 struct kinfo_proc2
*p1
= *(struct kinfo_proc2
**) pp1
;
1170 struct kinfo_proc2
*p2
= *(struct kinfo_proc2
**) pp2
;
1171 return strcmp(p2
->p_login
, p1
->p_login
);
1174 /* compare_size - the comparison function for sorting by total memory usage */
1177 compare_size(pp1
, pp2
)
1178 struct proc
**pp1
, **pp2
;
1184 struct kinfo_lwp
*p1
= *(struct kinfo_lwp
**) pp1
;
1185 struct kinfo_lwp
*p2
= *(struct kinfo_lwp
**) pp2
;
1188 ORDERKEY_CPTICKS(l_
)
1193 struct kinfo_proc2
*p1
= *(struct kinfo_proc2
**) pp1
;
1194 struct kinfo_proc2
*p2
= *(struct kinfo_proc2
**) pp2
;
1199 ORDERKEY_CPTICKS(p_
)
1208 /* compare_state - the comparison function for sorting by process state */
1211 compare_state(pp1
, pp2
)
1212 struct proc
**pp1
, **pp2
;
1218 struct kinfo_lwp
*p1
= *(struct kinfo_lwp
**) pp1
;
1219 struct kinfo_lwp
*p2
= *(struct kinfo_lwp
**) pp2
;
1223 ORDERKEY_CPTICKS(l_
)
1227 struct kinfo_proc2
*p1
= *(struct kinfo_proc2
**) pp1
;
1228 struct kinfo_proc2
*p2
= *(struct kinfo_proc2
**) pp2
;
1232 ORDERKEY_CPTICKS(p_
)
1242 /* compare_time - the comparison function for sorting by total CPU time */
1245 compare_time(pp1
, pp2
)
1246 struct proc
**pp1
, **pp2
;
1252 struct kinfo_lwp
*p1
= *(struct kinfo_lwp
**) pp1
;
1253 struct kinfo_lwp
*p2
= *(struct kinfo_lwp
**) pp2
;
1255 ORDERKEY_CPTICKS(l_
)
1261 struct kinfo_proc2
*p1
= *(struct kinfo_proc2
**) pp1
;
1262 struct kinfo_proc2
*p2
= *(struct kinfo_proc2
**) pp2
;
1264 ORDERKEY_CPTICKS(p_
)
1278 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
1279 * the process does not exist.
1280 * It is EXTREMLY IMPORTANT that this function work correctly.
1281 * If top runs setuid root (as in SVR4), then this function
1282 * is the only thing that stands in the way of a serious
1283 * security problem. It validates requests for the "kill"
1284 * and "renice" commands.
1292 struct kinfo_proc2
**prefp
;
1293 struct kinfo_proc2
*pp
;
1300 while (--cnt
>= 0) {
1302 if (pp
->p_pid
== (pid_t
)pid
)
1309 * percentages(cnt, out, new, old, diffs) - calculate percentage change
1310 * between array "old" and "new", putting the percentages i "out".
1311 * "cnt" is size of each array and "diffs" is used for scratch space.
1312 * The array "old" is updated on each call.
1313 * The routine assumes modulo arithmetic. This function is especially
1314 * useful on BSD mchines for calculating CPU state percentages.
1318 percentages64(cnt
, out
, new, old
, diffs
)
1327 u_int64_t total_change
;
1329 u_int64_t half_total
;
1331 /* initialization */
1335 /* calculate changes for each state and the overall change */
1336 for (i
= 0; i
< cnt
; i
++) {
1338 * Don't worry about wrapping - even at hz=1GHz, a
1339 * u_int64_t will last at least 544 years.
1341 change
= *new - *old
;
1342 total_change
+= (*dp
++ = change
);
1346 /* avoid divide by zero potential */
1347 if (total_change
== 0)
1350 /* calculate percentages based on overall change, rounding up */
1351 half_total
= total_change
/ 2;
1352 for (i
= 0; i
< cnt
; i
++)
1353 *out
++ = (int)((*diffs
++ * 1000 + half_total
) / total_change
);