From c7bd46983f7dc33656e767b24b27bd3a8d6d67ab Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 9 Apr 2008 19:48:06 +0000 Subject: [PATCH] MFC: backport -P (per-cpu) stats for %user/%system/%idle etc. --- contrib/top/display.c | 86 ++++++++++++---- contrib/top/layout.h | 42 ++++---- contrib/top/machine.h | 3 + contrib/top/top.c | 14 ++- contrib/top/top.h | 4 +- usr.bin/top/machine.c | 100 ++++++++++++++++++- usr.bin/vmstat/Makefile | 4 +- usr.bin/vmstat/vmstat.8 | 10 +- usr.bin/vmstat/vmstat.c | 213 ++++++++++++++++++++++++++++++++++++---- 9 files changed, 412 insertions(+), 64 deletions(-) diff --git a/contrib/top/display.c b/contrib/top/display.c index 9de895200644..0b1226ce03d3 100644 --- a/contrib/top/display.c +++ b/contrib/top/display.c @@ -78,8 +78,10 @@ static int *lcpustates; static int *lmemory; static int *lswap; +static int num_cpus; static int *cpustate_columns; static int cpustate_total_length; +static int cpustates_column; static enum { OFF, ON, ERASE } header_status = ON; @@ -87,6 +89,29 @@ static int string_count(); static void summary_format(); static void line_update(); +int x_lastpid = 10; +int y_lastpid = 0; +int x_loadave = 33; +int x_loadave_nompid = 15; +int y_loadave = 0; +int x_procstate = 0; +int y_procstate = 1; +int x_brkdn = 15; +int y_brkdn = 1; +int x_mem = 5; +int y_mem = 3; +int x_swap = 6; +int y_swap = 4; +int y_message = 5; +int x_header = 0; +int y_header = 6; +int x_idlecursor = 0; +int y_idlecursor = 5; +int y_procs = 7; + +int y_cpustates = 2; +int Header_lines = 7; + int display_resize() { @@ -138,6 +163,12 @@ struct statics *statics; /* call resize to do the dirty work */ lines = display_resize(); + num_cpus = statics->ncpus; + cpustates_column = 5; /* CPU: */ + if (num_cpus != 1) + cpustates_column += 2; /* CPU 0: */ + for (i = num_cpus; i > 9; i /= 10) + cpustates_column++; /* only do the rest if we need to */ if (lines > -1) @@ -153,7 +184,7 @@ struct statics *statics; num_swap = string_count(swap_names); lswap = (int *)malloc(num_swap * sizeof(int)); num_cpustates = string_count(cpustate_names); - lcpustates = (int *)malloc(num_cpustates * sizeof(int)); + lcpustates = (int *)malloc(num_cpustates * sizeof(int) * num_cpus); cpustate_columns = (int *)malloc(num_cpustates * sizeof(int)); memory_names = statics->memory_names; @@ -365,14 +396,13 @@ int *brkdn; } } +#ifdef no_more /* * *_cpustates(states, names) - print the cpu state percentages * * Assumptions: cursor is on the PREVIOUS line */ -static int cpustates_column; - /* cpustates_tag() calculates the correct tag to use to label the line */ char *cpustates_tag() @@ -398,6 +428,7 @@ char *cpustates_tag() cpustates_column = strlen(use); return(use); } +#endif i_cpustates(states) @@ -406,11 +437,18 @@ register int *states; { register int i = 0; register int value; - register char **names = cpustate_names; + register char **names; register char *thisname; + int cpu; + +for (cpu = 0; cpu < num_cpus; cpu++) { + names = cpustate_names; /* print tag and bump lastline */ - printf("\n%s", cpustates_tag()); + if (num_cpus == 1) + printf("\nCPU: "); + else + printf("\nCPU %d: ", cpu); lastline++; /* now walk thru the names and print the line */ @@ -423,14 +461,15 @@ register int *states; /* if percentage is >= 1000, print it as 100% */ printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"), - i++ == 0 ? "" : ", ", + (i++ % num_cpustates) == 0 ? "" : ", ", ((float)value)/10., thisname); } } +} /* copy over values into "last" array */ - memcpy(lcpustates, states, num_cpustates * sizeof(int)); + memcpy(lcpustates, states, num_cpustates * sizeof(int) * num_cpus); } u_cpustates(states) @@ -439,14 +478,18 @@ register int *states; { register int value; - register char **names = cpustate_names; + register char **names; register char *thisname; register int *lp; register int *colp; + int cpu; - Move_to(cpustates_column, y_cpustates); - lastline = y_cpustates; - lp = lcpustates; +for (cpu = 0; cpu < num_cpus; cpu++) { + names = cpustate_names; + + Move_to(cpustates_column, y_cpustates + cpu); + lastline = y_cpustates + cpu; + lp = lcpustates + (cpu * num_cpustates); colp = cpustate_columns; /* we could be much more optimal about this */ @@ -458,8 +501,8 @@ register int *states; if (*lp != *states) { /* yes, move and change */ - Move_to(cpustates_column + *colp, y_cpustates); - lastline = y_cpustates; + Move_to(cpustates_column + *colp, y_cpustates + cpu); + lastline = y_cpustates + cpu; /* retrieve value and remember it */ value = *states; @@ -479,30 +522,39 @@ register int *states; colp++; } } +} z_cpustates() { register int i = 0; - register char **names = cpustate_names; + register char **names; register char *thisname; register int *lp; + int cpu; + +for (cpu = 0; cpu < num_cpus; cpu++) { + names = cpustate_names; /* show tag and bump lastline */ - printf("\n%s", cpustates_tag()); + if (num_cpus == 1) + printf("\nCPU: "); + else + printf("\nCPU %d: ", cpu); lastline++; while ((thisname = *names++) != NULL) { if (*thisname != '\0') { - printf("%s %% %s", i++ == 0 ? "" : ", ", thisname); + printf("%s %% %s", (i++ % num_cpustates) == 0 ? "" : ", ", thisname); } } +} /* fill the "last" array with all -1s, to insure correct updating */ lp = lcpustates; - i = num_cpustates; + i = num_cpustates * num_cpus; while (--i >= 0) { *lp++ = -1; diff --git a/contrib/top/layout.h b/contrib/top/layout.h index 5db383f87e4d..1b2564e0a657 100644 --- a/contrib/top/layout.h +++ b/contrib/top/layout.h @@ -4,26 +4,28 @@ * This file defines the locations on tne screen for various parts of the * display. These definitions are used by the routines in "display.c" for * cursor addressing. + * + * $FreeBSD$ */ -#define x_lastpid 10 -#define y_lastpid 0 -#define x_loadave 33 -#define x_loadave_nompid 15 -#define y_loadave 0 -#define x_procstate 0 -#define y_procstate 1 -#define x_brkdn 15 -#define y_brkdn 1 -#define x_mem 5 -#define y_mem 3 -#define x_swap 6 -#define y_swap 4 -#define y_message 5 -#define x_header 0 -#define y_header 6 -#define x_idlecursor 0 -#define y_idlecursor 5 -#define y_procs 7 +extern int x_lastpid; /* 10 */ +extern int y_lastpid; /* 0 */ +extern int x_loadave; /* 33 */ +extern int x_loadave_nompid; /* 15 */ +extern int y_loadave; /* 0 */ +extern int x_procstate; /* 0 */ +extern int y_procstate; /* 1 */ +extern int x_brkdn; /* 15 */ +extern int y_brkdn; /* 1 */ +extern int x_mem; /* 5 */ +extern int y_mem; /* 3 */ +extern int x_swap; /* 6 */ +extern int y_swap; /* 4 */ +extern int y_message; /* 5 */ +extern int x_header; /* 0 */ +extern int y_header; /* 6 */ +extern int x_idlecursor; /* 0 */ +extern int y_idlecursor; /* 5 */ +extern int y_procs; /* 7 */ -#define y_cpustates 2 +extern int y_cpustates; /* 2 */ diff --git a/contrib/top/machine.h b/contrib/top/machine.h index 10c69ca4e3f0..4584650c8ee4 100644 --- a/contrib/top/machine.h +++ b/contrib/top/machine.h @@ -20,6 +20,7 @@ struct statics #ifdef ORDER char **order_names; #endif + int ncpus; }; /* @@ -43,6 +44,8 @@ struct system_info int *memory; int *swap; struct timeval boottime; + unsigned long cpumask; /* bitfield of cpu states represented */ + int ncpus; }; /* cpu_states is an array of percentages * 10. For example, diff --git a/contrib/top/top.c b/contrib/top/top.c index e8e99ffe2889..52d8517f2b49 100644 --- a/contrib/top/top.c +++ b/contrib/top/top.c @@ -1,3 +1,5 @@ + + char *copyright = "Copyright (c) 1984 through 1996, William LeFebvre"; @@ -65,6 +67,8 @@ extern char *optarg; /* imported from screen.c */ extern int overstrike; +int pcpu_stats = No; + /* signal handling routines */ sigret_t leave(); sigret_t onalrm(); @@ -279,7 +283,7 @@ char *argv[]; optind = 1; } - while ((i = getopt(ac, av, "CSIHbijnquvs:d:U:m:o:t")) != EOF) + while ((i = getopt(ac, av, "CSIHPbijnpquvs:d:U:m:o:t")) != EOF) { switch(i) { @@ -400,6 +404,14 @@ char *argv[]; ps.jail = !ps.jail; break; + case 'P': + pcpu_stats = Yes; + break; + + case 'p': + pcpu_stats = No; + break; + default: fprintf(stderr, "Top version %s\n" diff --git a/contrib/top/top.h b/contrib/top/top.h index 59cdeed2d7d7..c0099a158e37 100644 --- a/contrib/top/top.h +++ b/contrib/top/top.h @@ -11,7 +11,7 @@ #define VERSION 3 /* Number of lines of header information on the standard screen */ -#define Header_lines 7 +extern int Header_lines; /* 7 */ /* Maximum number of columns allowed for display */ #define MAX_COLS 128 @@ -40,3 +40,5 @@ char *version_string(); enum displaymodes { DISP_CPU = 0, DISP_IO, DISP_MAX }; extern enum displaymodes displaymode; + +extern int pcpu_stats; diff --git a/usr.bin/top/machine.c b/usr.bin/top/machine.c index 6684c52ef96d..d5db8b771be3 100644 --- a/usr.bin/top/machine.c +++ b/usr.bin/top/machine.c @@ -50,6 +50,7 @@ #include "machine.h" #include "screen.h" #include "utils.h" +#include "layout.h" static void getsysctl(char *, void *, size_t); @@ -65,6 +66,17 @@ enum displaymodes displaymode; static int namelength = 8; static int cmdlengthdelta; +/* Per-cpu time states */ +static int maxcpu; +static int maxid; +static int ncpus; +static u_long cpumask; +static long *times; +static long *pcpu_cp_time; +static long *pcpu_cp_old; +static long *pcpu_cp_diff; +static int *pcpu_cpu_states; + /* Prototypes for top internals */ void quit(int); int compare_jid(const void *a, const void *b); @@ -279,6 +291,56 @@ machine_init(struct statics *statics) statics->order_names = ordernames; #endif + /* Adjust display based on ncpus */ + if (pcpu_stats) { + int i, j, empty; + size_t size; + + cpumask = 0; + ncpus = 0; + GETSYSCTL("kern.smp.maxcpus", maxcpu); + size = sizeof(long) * maxcpu * CPUSTATES; + times = malloc(size); + if (times == NULL) + err(1, "malloc %zd bytes", size); + if (sysctlbyname("kern.cp_times", times, &size, NULL, 0) == -1) + err(1, "sysctlbyname kern.cp_times"); + maxid = (size / CPUSTATES / sizeof(long)) - 1; + for (i = 0; i <= maxid; i++) { + empty = 1; + for (j = 0; empty && j < CPUSTATES; j++) { + if (times[i * CPUSTATES + j] != 0) + empty = 0; + } + if (!empty) { + cpumask |= (1ul << i); + ncpus++; + } + } + + if (ncpus > 1) { + y_mem += ncpus - 1; /* 3 */ + y_swap += ncpus - 1; /* 4 */ + y_idlecursor += ncpus - 1; /* 5 */ + y_message += ncpus - 1; /* 5 */ + y_header += ncpus - 1; /* 6 */ + y_procs += ncpus - 1; /* 7 */ + Header_lines += ncpus - 1; /* 7 */ + } + size = sizeof(long) * ncpus * CPUSTATES; + pcpu_cp_time = malloc(size); + pcpu_cp_old = malloc(size); + pcpu_cp_diff = malloc(size); + pcpu_cpu_states = malloc(size); + bzero(pcpu_cp_time, size); + bzero(pcpu_cp_old, size); + bzero(pcpu_cp_diff, size); + bzero(pcpu_cpu_states, size); + statics->ncpus = ncpus; + } else { + statics->ncpus = 1; + } + /* all done! */ return (0); } @@ -320,6 +382,7 @@ static int swappgsin = -1; static int swappgsout = -1; extern struct timeval timeout; + void get_system_info(struct system_info *si) { @@ -328,10 +391,17 @@ get_system_info(struct system_info *si) int mib[2]; struct timeval boottime; size_t bt_size; - int i; + int i, j; + size_t size; /* get the cp_time array */ - GETSYSCTL("kern.cp_time", cp_time); + if (pcpu_stats) { + size = (maxid + 1) * CPUSTATES * sizeof(long); + if (sysctlbyname("kern.cp_times", pcpu_cp_time, &size, NULL, 0) == -1) + err(1, "sysctlbyname kern.cp_times"); + } else { + GETSYSCTL("kern.cp_time", cp_time); + } GETSYSCTL("vm.loadavg", sysload); GETSYSCTL("kern.lastpid", lastpid); @@ -339,8 +409,20 @@ get_system_info(struct system_info *si) for (i = 0; i < 3; i++) si->load_avg[i] = (double)sysload.ldavg[i] / sysload.fscale; - /* convert cp_time counts to percentages */ - total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); + if (pcpu_stats) { + for (i = j = 0; i <= maxid; i++, j++) { + if (cpumask && (1ul << i) == 0) + continue; + /* convert cp_time counts to percentages */ + percentages(CPUSTATES, &pcpu_cpu_states[j * CPUSTATES], + &pcpu_cp_time[j * CPUSTATES], + &pcpu_cp_old[j * CPUSTATES], + &pcpu_cp_diff[j * CPUSTATES]); + } + } else { + /* convert cp_time counts to percentages */ + percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); + } /* sum memory & swap statistics */ { @@ -394,7 +476,15 @@ get_system_info(struct system_info *si) } /* set arrays and strings */ - si->cpustates = cpu_states; + if (pcpu_stats) { + si->cpustates = pcpu_cpu_states; + si->cpumask = cpumask; + si->ncpus = ncpus; + } else { + si->cpustates = cpu_states; + si->cpumask = 1; + si->ncpus = 1; + } si->memory = memory_stats; si->swap = swap_stats; diff --git a/usr.bin/vmstat/Makefile b/usr.bin/vmstat/Makefile index 21795e9ac09f..6e87a6a6f8e5 100644 --- a/usr.bin/vmstat/Makefile +++ b/usr.bin/vmstat/Makefile @@ -3,7 +3,7 @@ PROG= vmstat MAN= vmstat.8 -DPADD= ${LIBDEVSTAT} ${LIBKVM} ${LIBMEMSTAT} -LDADD= -ldevstat -lkvm -lmemstat +DPADD= ${LIBDEVSTAT} ${LIBKVM} ${LIBMEMSTAT} ${LIBUTIL} +LDADD= -ldevstat -lkvm -lmemstat -lutil .include diff --git a/usr.bin/vmstat/vmstat.8 b/usr.bin/vmstat/vmstat.8 index 24afc7d25adc..21a4568ff43b 100644 --- a/usr.bin/vmstat/vmstat.8 +++ b/usr.bin/vmstat/vmstat.8 @@ -41,7 +41,7 @@ .Sh SYNOPSIS .Nm .\" .Op Fl fimst -.Op Fl afimsz +.Op Fl afHhimPsz .Op Fl c Ar count .Op Fl M Ar core Op Fl N Ar system .Op Fl w Ar wait @@ -94,6 +94,12 @@ and .Xr rfork 2 system calls since system startup, and the number of pages of virtual memory involved in each. +.It Fl h +Changes memory columns into more easily human readable form. Default if +standard output is a terminal device. +.It Fl H +Changes memory columns into straight numbers. Default if standard output +is not a terminal device (such as a script). .It Fl i Report on the number of interrupts taken by each device since system startup. @@ -113,6 +119,8 @@ Report on the usage of kernel dynamic memory listed first by size of allocation and then by type of usage. .It Fl n Change the maximum number of disks to display from the default of 2. +.It Fl P +Report per-cpu system/user/idle cpu statistics. .It Fl p Specify which types of devices to display. There are three different diff --git a/usr.bin/vmstat/vmstat.c b/usr.bin/vmstat/vmstat.c index 59a4f2234203..904cef953f3b 100644 --- a/usr.bin/vmstat/vmstat.c +++ b/usr.bin/vmstat/vmstat.c @@ -76,6 +76,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include static char da[] = "da"; @@ -137,6 +138,8 @@ static struct vmmeter sum, osum; static int winlines = 20; static int aflag; static int nflag; +static int Pflag; +static int hflag; static kvm_t *kd; @@ -149,6 +152,7 @@ static kvm_t *kd; #define ZMEMSTAT 0x40 static void cpustats(void); +static void pcpustats(int, u_long, int); static void devstats(void); static void doforkst(void); static void dointr(void); @@ -160,7 +164,7 @@ static void kread(int, void *, size_t); static void kreado(int, void *, size_t, size_t); static char *kgetstr(const char *); static void needhdr(int); -static void printhdr(void); +static void printhdr(int, u_long); static void usage(void); static long pct(long, long); @@ -180,7 +184,8 @@ main(int argc, char *argv[]) memf = nlistf = NULL; interval = reps = todo = 0; maxshowdevs = 2; - while ((c = getopt(argc, argv, "ac:fiM:mN:n:p:stw:z")) != -1) { + hflag = isatty(1); + while ((c = getopt(argc, argv, "ac:fhHiM:mN:n:Pp:stw:z")) != -1) { switch (c) { case 'a': aflag++; @@ -188,9 +193,18 @@ main(int argc, char *argv[]) case 'c': reps = atoi(optarg); break; + case 'P': + Pflag++; + break; case 'f': todo |= FORKSTAT; break; + case 'h': + hflag = 1; + break; + case 'H': + hflag = 0; + break; case 'i': todo |= INTRSTAT; break; @@ -261,6 +275,8 @@ main(int argc, char *argv[]) warnx("kvm_nlist: %s", kvm_geterr(kd)); exit(1); } + if (kd && Pflag) + errx(1, "Cannot use -P with crash dumps"); if (todo & VMSTAT) { struct winsize winsize; @@ -498,8 +514,71 @@ fill_vmtotal(struct vmtotal *vmtp) } } +/* Determine how many cpu columns, and what index they are in kern.cp_times */ +static int +getcpuinfo(u_long *maskp, int *maxidp) +{ + int maxcpu; + int maxid; + int ncpus; + int i, j; + int empty; + size_t size; + long *times; + u_long mask; + + if (kd != NULL) + errx(1, "not implemented"); + mask = 0; + ncpus = 0; + size = sizeof(maxcpu); + mysysctl("kern.smp.maxcpus", &maxcpu, &size, NULL, 0); + if (size != sizeof(maxcpu)) + errx(1, "sysctl kern.smp.maxcpus"); + size = sizeof(long) * maxcpu * CPUSTATES; + times = malloc(size); + if (times == NULL) + err(1, "malloc %zd bytes", size); + mysysctl("kern.cp_times", times, &size, NULL, 0); + maxid = (size / CPUSTATES / sizeof(long)) - 1; + for (i = 0; i <= maxid; i++) { + empty = 1; + for (j = 0; empty && j < CPUSTATES; j++) { + if (times[i * CPUSTATES + j] != 0) + empty = 0; + } + if (!empty) { + mask |= (1ul << i); + ncpus++; + } + } + if (maskp) + *maskp = mask; + if (maxidp) + *maxidp = maxid; + return (ncpus); +} + + +static void +prthuman(u_int64_t val, int size) +{ + char buf[10]; + int flags; + + if (size < 5 || size > 9) + errx(1, "doofus"); + flags = HN_B | HN_NOSPACE | HN_DECIMAL; + humanize_number(buf, size, val, "", HN_AUTOSCALE, flags); + printf("%*s", size, buf); +} + static int hz, hdrcnt; +static long *cur_cp_times; +static long *last_cp_times; +static size_t size_cp_times; + static void dovmstat(unsigned int interval, int reps) { @@ -507,6 +586,8 @@ dovmstat(unsigned int interval, int reps) time_t uptime, halfuptime; struct devinfo *tmp_dinfo; size_t size; + int ncpus, maxid; + u_long cpumask; uptime = getuptime(); halfuptime = uptime / 2; @@ -528,9 +609,17 @@ dovmstat(unsigned int interval, int reps) hz = clockrate.hz; } + if (Pflag) { + ncpus = getcpuinfo(&cpumask, &maxid); + size_cp_times = sizeof(long) * (maxid + 1) * CPUSTATES; + cur_cp_times = malloc(size_cp_times); + last_cp_times = malloc(size_cp_times); + bzero(cur_cp_times, size_cp_times); + bzero(last_cp_times, size_cp_times); + } for (hdrcnt = 1;;) { if (!--hdrcnt) - printhdr(); + printhdr(ncpus, cpumask); if (kd != NULL) { kread(X_CPTIME, cur.cp_time, sizeof(cur.cp_time)); } else { @@ -539,6 +628,12 @@ dovmstat(unsigned int interval, int reps) if (size != sizeof(cur.cp_time)) errx(1, "cp_time size mismatch"); } + if (Pflag) { + size = size_cp_times; + mysysctl("kern.cp_times", cur_cp_times, &size, NULL, 0); + if (size != size_cp_times) + errx(1, "cp_times mismatch"); + } tmp_dinfo = last.dinfo; last.dinfo = cur.dinfo; @@ -574,7 +669,7 @@ dovmstat(unsigned int interval, int reps) errx(1, "%s", devstat_errbuf); break; case 1: - printhdr(); + printhdr(ncpus, cpumask); break; default: break; @@ -590,8 +685,16 @@ dovmstat(unsigned int interval, int reps) total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw); #define vmstat_pgtok(a) ((a) * (sum.v_page_size >> 10)) #define rate(x) (((x) + halfuptime) / uptime) /* round */ - (void)printf(" %7d %6d ", vmstat_pgtok(total.t_avm), - vmstat_pgtok(total.t_free)); + if (hflag) { + printf(" "); + prthuman(total.t_avm * (u_int64_t)sum.v_page_size, 7); + printf(" "); + prthuman(total.t_free * (u_int64_t)sum.v_page_size, 6); + printf(" "); + } else { + printf(" %7d ", vmstat_pgtok(total.t_avm)); + printf(" %6d ", vmstat_pgtok(total.t_free)); + } (void)printf("%4lu ", (unsigned long)rate(sum.v_vm_faults - osum.v_vm_faults)); (void)printf("%3lu ", @@ -607,11 +710,14 @@ dovmstat(unsigned int interval, int reps) (void)printf("%3lu ", (unsigned long)rate(sum.v_pdpages - osum.v_pdpages)); devstats(); - (void)printf("%4lu %4lu %3lu ", + (void)printf("%4lu %4lu %3lu", (unsigned long)rate(sum.v_intr - osum.v_intr), (unsigned long)rate(sum.v_syscall - osum.v_syscall), (unsigned long)rate(sum.v_swtch - osum.v_swtch)); - cpustats(); + if (Pflag) + pcpustats(ncpus, cpumask, maxid); + else + cpustats(); (void)printf("\n"); (void)fflush(stdout); if (reps >= 0 && --reps <= 0) @@ -631,7 +737,7 @@ dovmstat(unsigned int interval, int reps) } static void -printhdr(void) +printhdr(int ncpus, u_long cpumask) { int i, num_shown; @@ -641,7 +747,15 @@ printhdr(void) (void)printf(" disks %*s", num_shown * 4 - 7, ""); else if (num_shown == 1) (void)printf("disk"); - (void)printf(" faults cpu\n"); + (void)printf(" faults "); + if (Pflag) { + for (i = 0; i < ncpus; i++) { + if (cpumask & (1ul << i)) + printf("cpu%-2d ", i); + } + printf("\n"); + } else + printf("cpu\n"); (void)printf(" r b w avm fre flt re pi po fr sr "); for (i = 0; i < num_devices; i++) if ((dev_select[i].selected) @@ -649,7 +763,13 @@ printhdr(void) (void)printf("%c%c%d ", dev_select[i].device_name[0], dev_select[i].device_name[1], dev_select[i].unit_number); - (void)printf(" in sy cs us sy id\n"); + (void)printf(" in sy cs"); + if (Pflag) { + for (i = 0; i < ncpus; i++) + printf(" us sy id"); + printf("\n"); + } else + printf(" us sy id\n"); hdrcnt = winlines - 2; } @@ -818,10 +938,26 @@ devstats(void) } } +static void +percent(double pct, int *over) +{ + char buf[10]; + int l; + + l = snprintf(buf, sizeof(buf), "%.0f", pct); + if (l == 1 && *over) { + printf("%s", buf); + (*over)--; + } else + printf("%2s", buf); + if (l > 2) + (*over)++; +} + static void cpustats(void) { - int state; + int state, over; double lpct, total; total = 0; @@ -831,11 +967,54 @@ cpustats(void) lpct = 100.0 / total; else lpct = 0.0; - (void)printf("%2.0f ", (cur.cp_time[CP_USER] + - cur.cp_time[CP_NICE]) * lpct); - (void)printf("%2.0f ", (cur.cp_time[CP_SYS] + - cur.cp_time[CP_INTR]) * lpct); - (void)printf("%2.0f", cur.cp_time[CP_IDLE] * lpct); + over = 0; + printf(" "); + percent((cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * lpct, &over); + printf(" "); + percent((cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * lpct, &over); + printf(" "); + percent(cur.cp_time[CP_IDLE] * lpct, &over); +} + +static void +pcpustats(int ncpus, u_long cpumask, int maxid) +{ + int state, i; + double lpct, total; + long tmp; + int over; + + /* devstats does this for cp_time */ + for (i = 0; i <= maxid; i++) { + if ((cpumask & (1ul << i)) == 0) + continue; + for (state = 0; state < CPUSTATES; ++state) { + tmp = cur_cp_times[i * CPUSTATES + state]; + cur_cp_times[i * CPUSTATES + state] -= last_cp_times[i * CPUSTATES + state]; + last_cp_times[i * CPUSTATES + state] = tmp; + } + } + + over = 0; + for (i = 0; i <= maxid; i++) { + if ((cpumask & (1ul << i)) == 0) + continue; + total = 0; + for (state = 0; state < CPUSTATES; ++state) + total += cur_cp_times[i * CPUSTATES + state]; + if (total) + lpct = 100.0 / total; + else + lpct = 0.0; + printf(" "); + percent((cur_cp_times[i * CPUSTATES + CP_USER] + + cur_cp_times[i * CPUSTATES + CP_NICE]) * lpct, &over); + printf(" "); + percent((cur_cp_times[i * CPUSTATES + CP_SYS] + + cur_cp_times[i * CPUSTATES + CP_INTR]) * lpct, &over); + printf(" "); + percent(cur_cp_times[i * CPUSTATES + CP_IDLE] * lpct, &over); + } } static void