- Allow a single process to be selected by pid.

- Add a 'thread mode' that displays LWPs.
This commit is contained in:
ad 2007-05-24 20:04:04 +00:00
parent 35d9d3fddf
commit 009dcab90b
6 changed files with 525 additions and 128 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: display.c,v 1.15 2006/09/23 19:46:57 elad Exp $ */
/* $NetBSD: display.c,v 1.16 2007/05/24 20:04:04 ad Exp $ */
/*
* Top users/processes display for Unix
@ -47,7 +47,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: display.c,v 1.15 2006/09/23 19:46:57 elad Exp $");
__RCSID("$NetBSD: display.c,v 1.16 2007/05/24 20:04:04 ad Exp $");
#endif
#include "os.h"
@ -334,16 +334,17 @@ static char procstates_buffer[MAX_COLS];
*/
void
i_procstates(total, brkdn)
i_procstates(total, brkdn, threads)
int total;
int *brkdn;
int threads;
{
register int i;
/* write current number of processes and remember the value */
printf("%d processes:", total);
printf("%d %s", total, (threads ? "threads: " : "processes:"));
ltotal = total;
/* put out enough spaces to get to column 15 */
@ -362,10 +363,11 @@ int *brkdn;
}
void
u_procstates(total, brkdn)
u_procstates(total, brkdn, threads)
int total;
int *brkdn;
int threads;
{
static char new[MAX_COLS];
@ -386,7 +388,7 @@ int *brkdn;
/* if number of digits differs, rewrite the label */
if (digits(total) != digits(ltotal))
{
fputs(" processes:", stdout);
printf("%d %s", total, (threads ? "threads: " : "processes:"));
/* put out enough spaces to get to column 15 */
i = digits(total);
while (i++ < 4)

View File

@ -1,4 +1,4 @@
/* $NetBSD: display.h,v 1.7 2005/10/03 05:34:51 christos Exp $ */
/* $NetBSD: display.h,v 1.8 2007/05/24 20:04:04 ad Exp $ */
/*
* Top users/processes display for Unix
@ -41,8 +41,8 @@ int display_init __P((struct statics *));
void i_loadave __P((int, double *));
void u_loadave __P((int, double *));
void i_timeofday __P((time_t *, time_t *));
void i_procstates __P((int, int *));
void u_procstates __P((int, int *));
void i_procstates __P((int, int *, int));
void u_procstates __P((int, int *, int));
char *cpustates_tag __P((void));
void i_cpustates __P((int *));
void u_cpustates __P((int *));

View File

@ -1,4 +1,4 @@
/* $NetBSD: machine.h,v 1.9 2005/10/03 05:34:51 christos Exp $ */
/* $NetBSD: machine.h,v 1.10 2007/05/24 20:04:04 ad Exp $ */
/*
* Top users/processes display for Unix
@ -86,6 +86,8 @@ struct process_select
int idle; /* show idle processes */
int system; /* show system processes */
int uid; /* only this uid (unless uid == -1) */
int threads; /* show threads */
int pid; /* show only this pid */
char *command; /* only this command (unless == NULL) */
};
@ -95,7 +97,7 @@ struct proc;
extern int (*proc_compares[]) __P((struct proc **, struct proc **));
int machine_init __P((struct statics *));
char *format_header __P((char *));
char *format_header __P((char *, struct process_select *));
void get_system_info __P((struct system_info *));
caddr_t get_process_info __P((struct system_info *, struct process_select *,
int (*)(struct proc **, struct proc **)));

View File

@ -1,4 +1,4 @@
/* $NetBSD: m_netbsd15.c,v 1.28 2007/02/17 22:49:56 pavel Exp $ */
/* $NetBSD: m_netbsd15.c,v 1.29 2007/05/24 20:04:05 ad Exp $ */
/*
* top - a top users display for Unix
@ -34,14 +34,15 @@
* matthew green <mrg@eterna.com.au>
* Simon Burge <simonb@NetBSD.org>
* Tomas Svensson <ts@unix1.net>
* Andrew Doran <ad@NetBSD.org>
*
*
* $Id: m_netbsd15.c,v 1.28 2007/02/17 22:49:56 pavel Exp $
* $Id: m_netbsd15.c,v 1.29 2007/05/24 20:04:05 ad Exp $
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: m_netbsd15.c,v 1.28 2007/02/17 22:49:56 pavel Exp $");
__RCSID("$NetBSD: m_netbsd15.c,v 1.29 2007/05/24 20:04:05 ad Exp $");
#endif
#include <sys/param.h>
@ -81,8 +82,8 @@ struct handle {
};
/* define what weighted CPU is. */
#define weighted_cpu(pct, pp) ((pp)->p_swtime == 0 ? 0.0 : \
((pct) / (1.0 - exp((pp)->p_swtime * logcpu))))
#define weighted_cpu(pfx, pct, pp) ((pp)->pfx ## swtime == 0 ? 0.0 : \
((pct) / (1.0 - exp((pp)->pfx ## swtime * logcpu))))
/* what we consider to be process size: */
#define PROCSIZE(pp) \
@ -93,21 +94,26 @@ struct handle {
* These definitions control the format of the per-process area
*/
static char header[] =
static char Proc_header[] =
" PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND";
/* 0123456 -- field to fill in starts at header+6 */
#define UNAME_START 6
#define PROC_UNAME_START 6
#define Proc_format \
"%5d %-8.8s %3d %4d%7s %5s %-8.8s%7s %5.2f%% %5.2f%% %.12s"
static char Thread_header[] =
" PID LID X PRI STATE TIME WCPU CPU COMMAND NAME";
/* 0123456 -- field to fill in starts at header+6 */
#define THREAD_UNAME_START 12
#define Thread_format \
"%5d %5d %-8.8s %3d %-8.8s%7s %5.2f%% %5.2f%% %-12.12s %.12s"
/*
* Process state names for the "STATE" column of the display.
*/
const char *state_abbrev[] = {
"", "START", "RUN", "SLEEP", "STOP", "ZOMB", "DEAD", "CPU"
"", "IDLE", "RUN", "SLEEP", "STOP", "ZOMB", "DEAD", "CPU"
};
static kvm_t *kd;
@ -130,7 +136,7 @@ static u_int64_t *cp_diff;
int process_states[8];
char *procstatenames[] = {
"", " starting, ", " runnable, ", " sleeping, ", " stopped, ",
"", " idle, ", " runnable, ", " sleeping, ", " stopped, ",
" zombie, ", " dead, ", " on processor, ",
NULL
};
@ -187,21 +193,39 @@ int (*proc_compares[]) __P((struct proc **, struct proc **)) = {
NULL
};
static char *format_next_lwp(caddr_t, char *(*)(int));
static char *format_next_proc(caddr_t, char *(*)(int));
static caddr_t get_proc_info(struct system_info *, struct process_select *,
int (*)(struct proc **, struct proc **));
static caddr_t get_lwp_info(struct system_info *, struct process_select *,
int (*)(struct proc **, struct proc **));
/* these are for keeping track of the proc array */
static int nproc;
static int onproc = -1;
static int nlwp;
static int onlwp = -1;
static int pref_len;
static int lref_len;
static struct kinfo_proc2 *pbase;
static struct kinfo_lwp *lbase;
static struct kinfo_proc2 **pref;
static struct kinfo_lwp **lref;
static int maxswap;
static void *swapp;
static int procgen;
static int thread_nproc;
static int thread_onproc = -1;
static struct kinfo_proc2 *thread_pbase;
/* these are for getting the memory statistics */
static int pageshift; /* log base 2 of the pagesize */
int threadmode;
/* define pagetok in terms of pageshift */
#define pagetok(size) ((size) << pageshift)
@ -293,9 +317,12 @@ machine_init(statics)
logcpu = log(loaddouble(ccpu));
pbase = NULL;
lbase = NULL;
pref = NULL;
nproc = 0;
onproc = -1;
nlwp = 0;
onlwp = -1;
/* get the page size with "getpagesize" and calculate pageshift from it */
pagesize = getpagesize();
pageshift = 0;
@ -320,12 +347,18 @@ machine_init(statics)
}
char *
format_header(uname_field)
char *uname_field;
format_header(char *uname_field, struct process_select *sel)
{
char *header;
char *ptr;
ptr = header + UNAME_START;
if (sel->threads) {
header = Thread_header;
ptr = header + THREAD_UNAME_START;
} else {
header = Proc_header;
ptr = header + PROC_UNAME_START;
}
while (*uname_field != '\0') {
*ptr++ = *uname_field++;
}
@ -440,18 +473,49 @@ get_system_info(si)
si->uptime = 0;
}
static struct kinfo_proc2 *
proc_from_thread(struct kinfo_lwp *pl)
{
struct kinfo_proc2 *pp = thread_pbase;
int i;
for (i = 0; i < thread_nproc; i++, pp++)
if (pp->p_pid == pl->l_pid)
return pp;
return NULL;
}
static int
uid_from_thread(struct kinfo_lwp *pl)
{
struct kinfo_proc2 *pp;
if ((pp = proc_from_thread(pl)) == NULL)
return -1;
return pp->p_ruid;
}
caddr_t
get_process_info(si, sel, compare)
struct system_info *si;
struct process_select *sel;
int (*compare) __P((struct proc **, struct proc **));
get_process_info(struct system_info *si, struct process_select *sel,
int (*compare)(struct proc **, struct proc **))
{
if ((threadmode = sel->threads) != 0)
return get_lwp_info(si, sel, compare);
else
return get_proc_info(si, sel, compare);
}
static caddr_t
get_proc_info(struct system_info *si, struct process_select *sel,
int (*compare)(struct proc **, struct proc **))
{
int i;
int total_procs;
int active_procs;
struct kinfo_proc2 **prefp, **n;
struct kinfo_proc2 *pp;
int op, arg;
/* these are copied out of sel for speed */
int show_idle;
@ -461,11 +525,24 @@ get_process_info(si, sel, compare)
static struct handle handle;
procgen++;
pbase = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2), &nproc);
if (sel->pid == -1) {
op = KERN_PROC_ALL;
arg = 0;
} else {
op = KERN_PROC_PID;
arg = sel->pid;
}
pbase = kvm_getproc2(kd, op, arg, sizeof(struct kinfo_proc2), &nproc);
if (pbase == NULL) {
(void) fprintf(stderr, "top: Out of memory.\n");
quit(23);
if (sel->pid != -1) {
nproc = 0;
} else {
(void) fprintf(stderr, "top: Out of memory.\n");
quit(23);
}
}
if (nproc > onproc) {
n = (struct kinfo_proc2 **) realloc(pref,
@ -515,7 +592,7 @@ get_process_info(si, sel, compare)
/* if requested, sort the "interesting" processes */
if (compare != NULL) {
qsort((char *)pref, active_procs, sizeof(struct kinfo_proc2 *),
(int (*) __P((const void *, const void *)))compare);
(int (*)(const void *, const void *))compare);
}
/* remember active and total counts */
@ -528,11 +605,126 @@ get_process_info(si, sel, compare)
return((caddr_t)&handle);
}
static caddr_t
get_lwp_info(struct system_info *si, struct process_select *sel,
int (*compare)(struct proc **, struct proc **))
{
int i;
int total_lwps;
int active_lwps;
struct kinfo_lwp **lrefp, **n;
struct kinfo_lwp *lp;
struct kinfo_proc2 *pp;
/* these are copied out of sel for speed */
int show_idle;
int show_system;
int show_uid;
int show_command;
static struct handle handle;
pp = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2),
&thread_nproc);
if (pp == NULL) {
(void) fprintf(stderr, "top: Out of memory.\n");
quit(23);
}
if (thread_pbase == NULL || thread_nproc != thread_onproc) {
free(thread_pbase);
thread_onproc = thread_nproc;
thread_pbase = calloc(sizeof(struct kinfo_proc2), thread_nproc);
if (thread_pbase == NULL) {
(void) fprintf(stderr, "top: Out of memory.\n");
quit(23);
}
}
memcpy(thread_pbase, pp, sizeof(struct kinfo_proc2) * thread_nproc);
lbase = kvm_getlwps(kd, sel->pid, 0, sizeof(struct kinfo_lwp), &nlwp);
if (lbase == NULL) {
if (sel->pid != -1) {
nproc = 0;
} else {
(void) fprintf(stderr, "top: Out of memory.\n");
quit(23);
}
}
if (nlwp > onlwp) {
n = (struct kinfo_lwp **) realloc(lref,
sizeof(struct kinfo_lwp *) * nlwp);
if (n == NULL) {
(void) fprintf(stderr, "top: Out of memory.\n");
quit(23);
}
lref = n;
onlwp = nlwp;
}
/* get a pointer to the states summary array */
si->procstates = process_states;
/* set up flags which define what we are going to select */
show_idle = sel->idle;
show_system = sel->system;
show_uid = sel->uid != -1;
show_command = sel->command != NULL;
/* count up thread states and get pointers to interesting threads */
total_lwps = 0;
active_lwps = 0;
memset((char *)process_states, 0, sizeof(process_states));
lrefp = lref;
for (lp = lbase, i = 0; i < nlwp; lp++, i++) {
/*
* Place pointers to each valid lwp structure in lref[].
* thread slots that are actually in use have a non-zero
* status field. threads with L_SYSTEM set are system
* threads---these get ignored unless show_sysprocs is set.
*/
if (lp->l_stat != 0 && (show_system || ((lp->l_flag & P_SYSTEM) == 0))) {
total_lwps++;
process_states[(unsigned char) lp->l_stat]++;
if (lp->l_stat != LSZOMB &&
(show_idle || (lp->l_pctcpu != 0) ||
(lp->l_stat == LSRUN || lp->l_stat == LSONPROC)) &&
(!show_uid || uid_from_thread(lp) == (uid_t)sel->uid)) {
*lrefp++ = lp;
active_lwps++;
}
}
}
/* if requested, sort the "interesting" threads */
if (compare != NULL) {
qsort((char *)lref, active_lwps, sizeof(struct kinfo_lwp *),
(int (*)(const void *, const void *))compare);
}
/* remember active and total counts */
si->p_total = total_lwps;
si->p_active = lref_len = active_lwps;
/* pass back a handle */
handle.next_proc = (struct kinfo_proc2 **)lref;
handle.remaining = active_lwps;
return((caddr_t)&handle);
}
char *
format_next_process(handle, get_userid)
caddr_t handle;
char *(*get_userid) __P((int));
format_next_process(caddr_t handle, char *(*get_userid)(int))
{
if (threadmode)
return format_next_lwp(handle, get_userid);
else
return format_next_proc(handle, get_userid);
}
char *
format_next_proc(caddr_t handle, char *(*get_userid)(int))
{
struct kinfo_proc2 *pp;
long cputime;
@ -595,7 +787,8 @@ format_next_process(handle, get_userid)
switch (pp->p_stat) {
case LSONPROC:
case LSRUN:
case LSSLEEP:
case LSSLEEP:
case LSIDL:
(void)snprintf(state, sizeof(state), "%.6s/%d",
statep, get_cpunum(pp->p_cpuid));
statep = state;
@ -614,7 +807,7 @@ format_next_process(handle, get_userid)
format_k(pagetok(pp->p_vm_rssize)),
statep,
format_time(cputime),
100.0 * weighted_cpu(pct, pp),
100.0 * weighted_cpu(p_, pct, pp),
100.0 * pct,
printable(pp->p_comm));
@ -622,6 +815,112 @@ format_next_process(handle, get_userid)
return(fmt);
}
static char *
format_next_lwp(caddr_t handle, char *(*get_userid)(int))
{
struct kinfo_proc2 *pp;
struct kinfo_lwp *pl;
long cputime;
double pct;
struct handle *hp;
const char *statep;
#ifdef KI_NOCPU
char state[10];
#endif
char wmesg[KI_WMESGLEN + 1];
static char fmt[128]; /* static area where result is built */
char *pretty = "";
char *comm;
int uid;
/* find and remember the next proc structure */
hp = (struct handle *)handle;
pl = (struct kinfo_lwp *)*(hp->next_proc++);
hp->remaining--;
pp = proc_from_thread(pl);
/* get the process's user struct and set cputime */
if (pp) {
comm = pp->p_comm;
#if 0
/* XXX needs to be per thread but is not. just ignore for now. */
if ((pp->p_flag & L_INMEM) == 0)
pretty = "<>";
else
#endif
if ((pp->p_flag & P_SYSTEM) != 0)
pretty = "[]";
if (pretty[0] != '\0' && comm[0] != pretty[0]) {
/*
* Print swapped processes as <pname> and
* system processes as [pname]
*/
#define COMSIZ sizeof(pp->p_comm)
char buf[COMSIZ];
(void) strncpy(buf, comm, COMSIZ);
comm[0] = pretty[0];
(void) strncpy(&comm[1], buf, COMSIZ - 2);
comm[COMSIZ - 2] = '\0';
(void) strncat(comm, &pretty[1], COMSIZ - 1);
comm[COMSIZ - 1] = '\0';
}
uid = pp->p_ruid;
} else {
comm = "<gone>";
uid = 0;
}
cputime = pl->l_rtime_sec;
/* calculate the base for CPU percentages */
pct = pctdouble(pl->l_pctcpu);
if (pl->l_stat == LSSLEEP) {
strlcpy(wmesg, pl->l_wmesg, sizeof(wmesg));
statep = wmesg;
} else
statep = state_abbrev[(unsigned)pl->l_stat];
#ifdef KI_NOCPU
/* Post-1.5 change: add CPU number if appropriate */
if (pl->l_cpuid != KI_NOCPU) {
switch (pl->l_stat) {
case LSONPROC:
case LSRUN:
case LSSLEEP:
case LSIDL:
(void)snprintf(state, sizeof(state), "%.6s/%d",
statep, get_cpunum(pl->l_cpuid));
statep = state;
break;
}
}
#endif
if (pl->l_name[0] == '\0') {
pl->l_name[0] = '-';
pl->l_name[1] = '\0';
}
/* format this entry */
sprintf(fmt,
Thread_format,
pl->l_pid,
pl->l_lid,
(*get_userid)(uid),
pl->l_priority - PZERO,
statep,
format_time(cputime),
100.0 * weighted_cpu(l_, pct, pl),
100.0 * pct,
printable(comm),
printable(pl->l_name));
/* return the result */
return(fmt);
}
/* comparison routines for qsort */
/*
@ -642,27 +941,29 @@ format_next_process(handle, get_userid)
* desired ordering.
*/
#define ORDERKEY_PCTCPU \
if (lresult = (pctcpu)(p2)->p_pctcpu - (pctcpu)(p1)->p_pctcpu,\
#define ORDERKEY_PCTCPU(pfx) \
if (lresult = (pctcpu)(p2)->pfx ## pctcpu - (pctcpu)(p1)->pfx ## pctcpu,\
(result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
#define ORDERKEY_CPTICKS \
if (lresult = (pctcpu)(p2)->p_rtime_sec \
- (pctcpu)(p1)->p_rtime_sec,\
#define ORDERKEY_CPTICKS(pfx) \
if (lresult = (pctcpu)(p2)->pfx ## rtime_sec \
- (pctcpu)(p1)->pfx ## rtime_sec,\
(result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
#define ORDERKEY_STATE \
if ((result = sorted_state[(int)(p2)->p_stat] - \
sorted_state[(int)(p1)->p_stat] ) == 0)
#define ORDERKEY_STATE(pfx) \
if ((result = sorted_state[(int)(p2)->pfx ## stat] - \
sorted_state[(int)(p1)->pfx ## stat] ) == 0)
#define ORDERKEY_PRIO \
if ((result = (p2)->p_priority - (p1)->p_priority) == 0)
#define ORDERKEY_PRIO(pfx) \
if ((result = (p2)->pfx ## priority - (p1)->pfx ## priority) == 0)
#define ORDERKEY_RSSIZE \
if ((result = p2->p_vm_rssize - p1->p_vm_rssize) == 0)
#define ORDERKEY_MEM \
if ((result = (PROCSIZE(p2) - PROCSIZE(p1))) == 0)
#define ORDERKEY_SIZE(v1, v2) \
if ((result = (v2 - v1)) == 0)
/*
* Now the array that maps process state to a weight.
@ -686,22 +987,30 @@ static int
compare_cpu(pp1, pp2)
struct proc **pp1, **pp2;
{
struct kinfo_proc2 *p1;
struct kinfo_proc2 *p2;
int result;
pctcpu lresult;
/* remove one level of indirection */
p1 = *(struct kinfo_proc2 **) pp1;
p2 = *(struct kinfo_proc2 **) pp2;
if (threadmode) {
struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
ORDERKEY_PCTCPU
ORDERKEY_CPTICKS
ORDERKEY_STATE
ORDERKEY_PRIO
ORDERKEY_RSSIZE
ORDERKEY_MEM
;
ORDERKEY_PCTCPU(l_)
ORDERKEY_CPTICKS(l_)
ORDERKEY_STATE(l_)
ORDERKEY_PRIO(l_)
;
} else {
struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
ORDERKEY_PCTCPU(p_)
ORDERKEY_CPTICKS(p_)
ORDERKEY_STATE(p_)
ORDERKEY_PRIO(p_)
ORDERKEY_RSSIZE
ORDERKEY_MEM
;
}
return (result);
}
@ -712,22 +1021,30 @@ static int
compare_prio(pp1, pp2)
struct proc **pp1, **pp2;
{
struct kinfo_proc2 *p1;
struct kinfo_proc2 *p2;
int result;
pctcpu lresult;
/* remove one level of indirection */
p1 = *(struct kinfo_proc2 **) pp1;
p2 = *(struct kinfo_proc2 **) pp2;
if (threadmode) {
struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
ORDERKEY_PRIO
ORDERKEY_PCTCPU
ORDERKEY_CPTICKS
ORDERKEY_STATE
ORDERKEY_RSSIZE
ORDERKEY_MEM
;
ORDERKEY_PRIO(l_)
ORDERKEY_PCTCPU(l_)
ORDERKEY_CPTICKS(l_)
ORDERKEY_STATE(l_)
;
} else {
struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
ORDERKEY_PRIO(p_)
ORDERKEY_PCTCPU(p_)
ORDERKEY_CPTICKS(p_)
ORDERKEY_STATE(p_)
ORDERKEY_RSSIZE
ORDERKEY_MEM
;
}
return (result);
}
@ -738,22 +1055,30 @@ static int
compare_res(pp1, pp2)
struct proc **pp1, **pp2;
{
struct kinfo_proc2 *p1;
struct kinfo_proc2 *p2;
int result;
pctcpu lresult;
/* remove one level of indirection */
p1 = *(struct kinfo_proc2 **) pp1;
p2 = *(struct kinfo_proc2 **) pp2;
if (threadmode) {
struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
ORDERKEY_RSSIZE
ORDERKEY_MEM
ORDERKEY_PCTCPU
ORDERKEY_CPTICKS
ORDERKEY_STATE
ORDERKEY_PRIO
;
ORDERKEY_PCTCPU(l_)
ORDERKEY_CPTICKS(l_)
ORDERKEY_STATE(l_)
ORDERKEY_PRIO(l_)
;
} else {
struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
ORDERKEY_RSSIZE
ORDERKEY_MEM
ORDERKEY_PCTCPU(p_)
ORDERKEY_CPTICKS(p_)
ORDERKEY_STATE(p_)
ORDERKEY_PRIO(p_)
;
}
return (result);
}
@ -764,22 +1089,30 @@ static int
compare_size(pp1, pp2)
struct proc **pp1, **pp2;
{
struct kinfo_proc2 *p1;
struct kinfo_proc2 *p2;
int result;
pctcpu lresult;
/* remove one level of indirection */
p1 = *(struct kinfo_proc2 **) pp1;
p2 = *(struct kinfo_proc2 **) pp2;
if (threadmode) {
struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
ORDERKEY_MEM
ORDERKEY_RSSIZE
ORDERKEY_PCTCPU
ORDERKEY_CPTICKS
ORDERKEY_STATE
ORDERKEY_PRIO
;
ORDERKEY_PCTCPU(l_)
ORDERKEY_CPTICKS(l_)
ORDERKEY_STATE(l_)
ORDERKEY_PRIO(l_)
;
} else {
struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
ORDERKEY_MEM
ORDERKEY_RSSIZE
ORDERKEY_PCTCPU(p_)
ORDERKEY_CPTICKS(p_)
ORDERKEY_STATE(p_)
ORDERKEY_PRIO(p_)
;
}
return (result);
}
@ -790,22 +1123,30 @@ static int
compare_state(pp1, pp2)
struct proc **pp1, **pp2;
{
struct kinfo_proc2 *p1;
struct kinfo_proc2 *p2;
int result;
pctcpu lresult;
/* remove one level of indirection */
p1 = *(struct kinfo_proc2 **) pp1;
p2 = *(struct kinfo_proc2 **) pp2;
if (threadmode) {
struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
ORDERKEY_STATE
ORDERKEY_PCTCPU
ORDERKEY_CPTICKS
ORDERKEY_PRIO
ORDERKEY_RSSIZE
ORDERKEY_MEM
;
ORDERKEY_STATE(l_)
ORDERKEY_PCTCPU(l_)
ORDERKEY_CPTICKS(l_)
ORDERKEY_PRIO(l_)
;
} else {
struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
ORDERKEY_STATE(p_)
ORDERKEY_PCTCPU(p_)
ORDERKEY_CPTICKS(p_)
ORDERKEY_PRIO(p_)
ORDERKEY_RSSIZE
ORDERKEY_MEM
;
}
return (result);
}
@ -816,22 +1157,30 @@ static int
compare_time(pp1, pp2)
struct proc **pp1, **pp2;
{
struct kinfo_proc2 *p1;
struct kinfo_proc2 *p2;
int result;
pctcpu lresult;
/* remove one level of indirection */
p1 = *(struct kinfo_proc2 **) pp1;
p2 = *(struct kinfo_proc2 **) pp2;
if (threadmode) {
struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
ORDERKEY_CPTICKS
ORDERKEY_PCTCPU
ORDERKEY_STATE
ORDERKEY_PRIO
ORDERKEY_MEM
ORDERKEY_RSSIZE
;
ORDERKEY_CPTICKS(l_)
ORDERKEY_PCTCPU(l_)
ORDERKEY_STATE(l_)
ORDERKEY_PRIO(l_)
;
} else {
struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
ORDERKEY_CPTICKS(p_)
ORDERKEY_PCTCPU(p_)
ORDERKEY_STATE(p_)
ORDERKEY_PRIO(p_)
ORDERKEY_MEM
ORDERKEY_RSSIZE
;
}
return (result);
}
@ -855,6 +1204,9 @@ proc_owner(pid)
struct kinfo_proc2 **prefp;
struct kinfo_proc2 *pp;
if (threadmode)
return(-1);
prefp = pref;
cnt = pref_len;
while (--cnt >= 0) {

View File

@ -9,7 +9,7 @@ top \- display and update information about the top CPU processes
.SH SYNOPSIS
.B top
[
.B \-bIinqSuv
.B \-bIinqStuv
] [
.BI \-d count
] [
@ -92,6 +92,10 @@ to -20 so that it will run faster. This can be used when the system is
being very sluggish to improve the possibility of discovering the problem.
This option can only be used by root.
.TP
.B \-t
Display threads (lightweight processes). The default is to display
processes.
.TP
.B \-u
Do not take the time to map UID numbers to usernames. Normally,
.I top
@ -217,6 +221,9 @@ Change the number of seconds to delay between displays
.B S
Toggle between showing and not showing system processes.
.TP
.B t
Toggle between showing threads and showing processes.
.TP
.B k
Send a signal (\*(lqkill\*(rq by default) to a list of processes. This
acts similarly to the command
@ -238,6 +245,9 @@ available on all systems. The sort key names vary from system to system
but usually include: \*(lqcpu\*(rq, \*(lqres\*(rq, \*(lqsize\*(rq,
\*(lqtime\*(rq. The default is cpu.
.TP
.B p
Select a single process to display. Useful when showing threads.
.TP
.B e
Display a list of system errors (if any) generated by the last
.BR k ill

View File

@ -1,4 +1,4 @@
/* $NetBSD: top.c,v 1.25 2006/11/24 19:47:00 christos Exp $ */
/* $NetBSD: top.c,v 1.26 2007/05/24 20:04:04 ad Exp $ */
const char copyright[] = "Copyright (c) 1984 through 1996, William LeFebvre";
@ -49,7 +49,7 @@ const char copyright[] = "Copyright (c) 1984 through 1996, William LeFebvre";
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: top.c,v 1.25 2006/11/24 19:47:00 christos Exp $");
__RCSID("$NetBSD: top.c,v 1.26 2007/05/24 20:04:04 ad Exp $");
#endif
#include "os.h"
@ -95,7 +95,7 @@ jmp_buf jmp_int;
/* pointers to display routines */
void (*d_loadave) __P((int, double *)) = i_loadave;
void (*d_procstates) __P((int, int *)) = i_procstates;
void (*d_procstates) __P((int, int *, int)) = i_procstates;
void (*d_cpustates) __P((int *)) = i_cpustates;
void (*d_memory) __P((int *)) = i_memory;
void (*d_swap) __P((int *)) = i_swap;
@ -153,9 +153,9 @@ char *argv[];
struct pollfd set[1];
#ifdef ORDER
static char command_chars[] = "\f qh?en#sdkrSiIuo";
static char command_chars[] = "\f qh?en#sdkrSiIuotp";
#else
static char command_chars[] = "\f qh?en#sdkrSiIu";
static char command_chars[] = "\f qh?en#sdkrSiIutp";
#endif
/* these defines enumerate the "strchr"s of the commands in command_chars */
#define CMD_redraw 0
@ -178,6 +178,8 @@ char *argv[];
#ifdef ORDER
#define CMD_order 16
#endif
#define CMD_threads 17
#define CMD_pid 18
/* set the buffer for stdout */
#ifdef DEBUG
@ -206,6 +208,8 @@ char *argv[];
ps.system = Yes;
ps.uid = -1;
ps.command = NULL;
ps.threads = No;
ps.pid = -1;
/* get preset options from the environment */
if ((env_top = getenv("TOP")) != NULL)
@ -230,7 +234,7 @@ char *argv[];
optind = 1;
}
while ((i = getopt(ac, av, "SIbinquvs:d:U:o:")) != -1)
while ((i = getopt(ac, av, "SIbinquvs:td:U:o:")) != -1)
{
switch(i)
{
@ -293,6 +297,10 @@ char *argv[];
warnings++;
}
break;
case 't':
ps.threads = !ps.threads;
break;
case 'q': /* be quick about it */
/* only allow this if user is really root */
@ -402,7 +410,7 @@ Usage: %s [-bIinqSuv] [-d count] [-o field] [-s time] [-U username] [number]\n",
init_termcap(interactive);
/* get the string to use for the process area header */
header_text = format_header(uname_field);
header_text = format_header(uname_field, &ps);
/* initialize display interface */
if ((max_topn = display_init(&statics)) == -1)
@ -524,7 +532,8 @@ Usage: %s [-bIinqSuv] [-d count] [-o field] [-s time] [-U username] [number]\n",
/* display process state breakdown */
(*d_procstates)(system_info.p_total,
system_info.procstates);
system_info.procstates,
ps.threads == Yes);
/* display the CPU state percentage breakdown */
if (dostates) /* but not the first time */
@ -809,6 +818,19 @@ Usage: %s [-bIinqSuv] [-d count] [-o field] [-s time] [-U username] [number]\n",
}
break;
case CMD_pid: /* one process */
new_message(0, "select pid ");
if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
{
ps.pid = atoi(tempbuf2);
}
else
{
ps.pid = -1;
clear_message();
}
break;
case CMD_system:
ps.system = !ps.system;
new_message(MT_standout | MT_delayed,
@ -816,6 +838,15 @@ Usage: %s [-bIinqSuv] [-d count] [-o field] [-s time] [-U username] [number]\n",
ps.system ? "D" : "Not d");
break;
case CMD_threads:
ps.threads = !ps.threads;
new_message(MT_standout | MT_delayed,
" Displaying %s.",
ps.threads ? "threads" : "processes");
header_text = format_header(uname_field, &ps);
reset_display();
break;
case CMD_idletog:
case CMD_idletog2:
ps.idle = !ps.idle;