- Allow a single process to be selected by pid.
- Add a 'thread mode' that displays LWPs.
This commit is contained in:
parent
35d9d3fddf
commit
009dcab90b
@ -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)
|
||||
|
@ -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 *));
|
||||
|
@ -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 **)));
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user