summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/top/top.X8
-rw-r--r--contrib/top/top.c51
-rw-r--r--contrib/top/top.h6
-rw-r--r--usr.bin/top/machine.c143
4 files changed, 195 insertions, 13 deletions
diff --git a/contrib/top/top.X b/contrib/top/top.X
index 4282f57..fb71060 100644
--- a/contrib/top/top.X
+++ b/contrib/top/top.X
@@ -20,6 +20,8 @@ top \- display and update information about the top cpu processes
] [
.BI \-U username
] [
+.BI \-m io | cpu
+] [
.I number
]
.SH DESCRIPTION
@@ -87,6 +89,9 @@ Do not display the
.I top
process.
.TP
+.BI \-m display
+Display either 'cpu' or 'io' statistics. Default is 'cpu'.
+.TP
.B \-n
Use \*(lqnon-interactive\*(rq mode. This is identical to \*(lqbatch\*(rq
mode.
@@ -214,6 +219,9 @@ will make
.I top
show one final display and then immediately exit.
.TP
+.B m
+Toggle the display between 'cpu' and 'io' modes.
+.TP
.B n or #
Change the number of processes to display (prompt for new number).
.TP
diff --git a/contrib/top/top.c b/contrib/top/top.c
index 5d30e66..8ee9b02 100644
--- a/contrib/top/top.c
+++ b/contrib/top/top.c
@@ -99,6 +99,7 @@ extern int (*proc_compares[])();
#else
extern int proc_compare();
#endif
+extern int io_compare();
time_t time();
caddr_t get_process_info();
@@ -192,9 +193,9 @@ char *argv[];
fd_set readfds;
#ifdef ORDER
- static char command_chars[] = "\f qh?en#sdkriIutHo";
+ static char command_chars[] = "\f qh?en#sdkriIutHmo";
#else
- static char command_chars[] = "\f qh?en#sdkriIutH";
+ static char command_chars[] = "\f qh?en#sdkriIutHm";
#endif
/* these defines enumerate the "strchr"s of the commands in command_chars */
#define CMD_redraw 0
@@ -215,8 +216,9 @@ char *argv[];
#define CMD_user 14
#define CMD_selftog 15
#define CMD_thrtog 16
+#define CMD_viewtog 17
#ifdef ORDER
-#define CMD_order 17
+#define CMD_order 18
#endif
/* set the buffer for stdout */
@@ -272,7 +274,7 @@ char *argv[];
optind = 1;
}
- while ((i = getopt(ac, av, "SIHbinquvs:d:U:o:t")) != EOF)
+ while ((i = getopt(ac, av, "SIHbinquvs:d:U:m:o:t")) != EOF)
{
switch(i)
{
@@ -352,6 +354,20 @@ char *argv[];
}
break;
+ case 'm': /* select sort order */
+ if (strcmp(optarg, "io") == 0) {
+ displaymode = DISP_IO;
+ } else if (strcmp(optarg, "cpu") == 0) {
+ displaymode = DISP_CPU;
+ } else {
+ fprintf(stderr,
+ "%s: warning: `-m' option can only take args "
+ "'io' or 'cpu'\n",
+ myname);
+ exit(1);
+ }
+ break;
+
case 'o': /* select sort order */
#ifdef ORDER
order_name = optarg;
@@ -545,18 +561,25 @@ restart:
while ((displays == -1) || (displays-- > 0))
{
+ int (*compare)();
+
+
/* get the current stats */
get_system_info(&system_info);
- /* get the current set of processes */
- processes =
- get_process_info(&system_info,
- &ps,
+ if (displaymode == DISP_CPU) {
#ifdef ORDER
- proc_compares[order_index]);
+ compare = proc_compares[order_index];
#else
- proc_compare);
+ compare = proc_compare;
#endif
+ } else {
+ compare = io_compare;
+ }
+
+ /* get the current set of processes */
+ processes =
+ get_process_info(&system_info, &ps, compare);
/* display the load averages */
(*d_loadave)(system_info.last_pid,
@@ -968,6 +991,14 @@ restart:
ps.thread ? "D" : "Not d");
putchar('\r');
break;
+ case CMD_viewtog:
+ if (++displaymode == DISP_MAX)
+ displaymode = 0;
+ header_text = format_header(uname_field);
+ display_header(Yes);
+ d_header = i_header;
+ reset_display();
+ break;
#ifdef ORDER
case CMD_order:
new_message(MT_standout,
diff --git a/contrib/top/top.h b/contrib/top/top.h
index aeed136..59cdeed 100644
--- a/contrib/top/top.h
+++ b/contrib/top/top.h
@@ -1,4 +1,7 @@
/*
+ * $FreeBSD$
+ */
+/*
* Top - a top users display for Berkeley Unix
*
* General (global) definitions
@@ -34,3 +37,6 @@ char *version_string();
#define NUM_AVERAGES 3
+enum displaymodes { DISP_CPU = 0, DISP_IO, DISP_MAX };
+
+extern enum displaymodes displaymode;
diff --git a/usr.bin/top/machine.c b/usr.bin/top/machine.c
index 7769650..b6ab1d1 100644
--- a/usr.bin/top/machine.c
+++ b/usr.bin/top/machine.c
@@ -63,11 +63,13 @@ static void getsysctl(char *, void *, size_t);
extern char* printable(char *);
int swapmode(int *retavail, int *retfree);
static int smpmode;
+enum displaymodes displaymode;
static int namelength;
static int cmdlengthdelta;
/* Prototypes for top internals */
void quit(int);
+int compare_pid(const void *a, const void *b);
/* get_process_info passes back a handle. This is what it looks like: */
@@ -87,12 +89,23 @@ struct handle
/* what we consider to be process size: */
#define PROCSIZE(pp) ((pp)->ki_size / 1024)
+#define RU(pp) (&(pp)->ki_rusage)
+#define RUTOT(pp) \
+ (RU(pp)->ru_inblock + RU(pp)->ru_oublock + RU(pp)->ru_majflt)
+
+
/* definitions for indices in the nlist array */
/*
* These definitions control the format of the per-process area
*/
+static char io_header[] =
+ " PID %-*.*s READ WRITE FAULT TOTAL COMMAND";
+
+#define io_Proc_format \
+ "%5d %-*.*s %6d %6d %6d %6d %.*s"
+
static char smp_header[] =
" PID %-*.*s PRI NICE SIZE RES STATE C TIME WCPU CPU COMMAND";
@@ -176,6 +189,10 @@ static int onproc = -1;
static int pref_len;
static struct kinfo_proc *pbase;
static struct kinfo_proc **pref;
+static struct kinfo_proc *previous_procs;
+static struct kinfo_proc **previous_pref;
+static int previous_proc_count = 0;
+static int previous_proc_count_max = 0;
/* these are for getting the memory statistics */
@@ -263,8 +280,18 @@ format_header(uname_field)
{
static char Header[128];
+ const char *prehead;
- snprintf(Header, sizeof(Header), smpmode ? smp_header : up_header,
+ switch (displaymode) {
+ case DISP_CPU:
+ prehead = smpmode ? smp_header : up_header;
+ break;
+ case DISP_IO:
+ prehead = io_header;
+ break;
+ }
+
+ snprintf(Header, sizeof(Header), prehead,
namelength, namelength, uname_field);
cmdlengthdelta = strlen(Header) - 7;
@@ -387,6 +414,43 @@ get_system_info(si)
}
}
+const struct kinfo_proc *
+get_old_proc(struct kinfo_proc *pp)
+{
+ struct kinfo_proc **oldpp, *oldp;
+
+ if (previous_proc_count == 0)
+ return (NULL);
+ oldpp = bsearch(&pp, previous_pref, previous_proc_count,
+ sizeof(struct kinfo_proc *), compare_pid);
+ if (oldpp == NULL)
+ return (NULL);
+ oldp = *oldpp;
+ if (bcmp(&oldp->ki_start, &pp->ki_start, sizeof(pp->ki_start)) != 0)
+ return (NULL);
+ return (oldp);
+}
+
+long
+get_io_total(struct kinfo_proc *pp)
+{
+ const struct kinfo_proc *oldp;
+ static struct kinfo_proc dummy;
+ long ret;
+
+ oldp = get_old_proc(pp);
+ if (oldp == NULL) {
+ bzero(&dummy, sizeof(dummy));
+ oldp = &dummy;
+ }
+
+ ret =
+ (RU(pp)->ru_inblock - RU(oldp)->ru_inblock) +
+ (RU(pp)->ru_oublock - RU(oldp)->ru_oublock) +
+ (RU(pp)->ru_majflt - RU(oldp)->ru_majflt);
+ return (ret);
+}
+
static struct handle handle;
caddr_t
@@ -409,6 +473,29 @@ get_process_info(si, sel, compare)
int show_uid;
int show_command;
+ /*
+ * Save the previous process info.
+ */
+ if (previous_proc_count_max < nproc) {
+ free(previous_procs);
+ previous_procs = malloc(nproc * sizeof(struct kinfo_proc));
+ free(previous_pref);
+ previous_pref = malloc(nproc * sizeof(struct kinfo_proc *));
+ if (previous_procs == NULL || previous_pref == NULL) {
+ (void) fprintf(stderr, "top: Out of memory.\n");
+ quit(23);
+ }
+ previous_proc_count_max = nproc;
+ }
+ if (nproc) {
+ for (i = 0; i < nproc; i++)
+ previous_pref[i] = &previous_procs[i];
+ bcopy(pbase, previous_procs, nproc * sizeof(struct kinfo_proc));
+ qsort(previous_pref, nproc,
+ sizeof(struct kinfo_proc *), compare_pid);
+ }
+ previous_proc_count = nproc;
+
pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc);
if (nproc > onproc)
pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *)
@@ -447,8 +534,9 @@ get_process_info(si, sel, compare)
total_procs++;
process_states[(unsigned char) pp->ki_stat]++;
if ((pp->ki_stat != SZOMB) &&
- (show_idle || (pp->ki_pctcpu != 0) ||
- (pp->ki_stat == SRUN)) &&
+ (displaymode == DISP_CPU &&
+ (show_idle || (pp->ki_pctcpu != 0) || pp->ki_stat == SRUN)) ||
+ (show_idle || (displaymode == DISP_IO && get_io_total(pp))) &&
(!show_uid || pp->ki_ruid == (uid_t)sel->uid))
{
/*
@@ -494,11 +582,13 @@ format_next_process(handle, get_userid)
char *(*get_userid)();
{
struct kinfo_proc *pp;
+ const struct kinfo_proc *oldp;
long cputime;
double pct;
struct handle *hp;
char status[16];
int state;
+ struct rusage ru, *rup;
/* find and remember the next proc structure */
hp = (struct handle *)handle;
@@ -561,6 +651,30 @@ format_next_process(handle, get_userid)
break;
}
+ if (displaymode == DISP_IO) {
+ oldp = get_old_proc(pp);
+ if (oldp != NULL) {
+ ru.ru_inblock = RU(pp)->ru_inblock - RU(oldp)->ru_inblock;
+ ru.ru_oublock = RU(pp)->ru_oublock - RU(oldp)->ru_oublock;
+ ru.ru_majflt = RU(pp)->ru_majflt - RU(oldp)->ru_majflt;
+ rup = &ru;
+ } else {
+ rup = RU(pp);
+ }
+
+ sprintf(fmt, io_Proc_format,
+ pp->ki_pid,
+ namelength, namelength,
+ (*get_userid)(pp->ki_ruid),
+ (int)rup->ru_inblock,
+ (int)rup->ru_oublock,
+ (int)rup->ru_majflt,
+ (int)(rup->ru_inblock + rup->ru_oublock + rup->ru_majflt),
+ screen_width > cmdlengthdelta ?
+ screen_width - cmdlengthdelta : 0,
+ printable(pp->ki_comm));
+ return (fmt);
+ }
/* format this entry */
sprintf(fmt,
smpmode ? smp_Proc_format : up_Proc_format,
@@ -617,6 +731,19 @@ getsysctl(name, ptr, len)
/* comparison routines for qsort */
+int
+compare_pid(p1, p2)
+ const void *p1, *p2;
+{
+ const struct kinfo_proc * const *pp1 = p1;
+ const struct kinfo_proc * const *pp2 = p2;
+
+ if ((*pp2)->ki_pid < 0 || (*pp1)->ki_pid < 0)
+ abort();
+
+ return ((*pp1)->ki_pid - (*pp2)->ki_pid);
+}
+
/*
* proc_compare - comparison function for "qsort"
* Compares the resource consumption of two processes using five
@@ -814,6 +941,16 @@ compare_prio(pp1, pp2)
}
#endif
+int
+io_compare(pp1, pp2)
+ struct kinfo_proc **pp1, **pp2;
+{
+ long t1, t2;
+
+ t1 = get_io_total(*pp1);
+ t2 = get_io_total(*pp2);
+ return (t2 - t1);
+}
/*
* proc_owner(pid) - returns the uid that owns process "pid", or -1 if
* the process does not exist.
OpenPOWER on IntegriCloud