diff options
-rw-r--r-- | contrib/top/top.X | 8 | ||||
-rw-r--r-- | contrib/top/top.c | 51 | ||||
-rw-r--r-- | contrib/top/top.h | 6 | ||||
-rw-r--r-- | usr.bin/top/machine.c | 143 |
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. |