summaryrefslogtreecommitdiffstats
path: root/usr.bin/vmstat
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2007-12-13 02:36:11 +0000
committerpeter <peter@FreeBSD.org>2007-12-13 02:36:11 +0000
commit8348a2e29463adaac848d62aca1ee994d4f6123f (patch)
tree818a91101a96ad0d531c3df1ffdc12b6268b28fe /usr.bin/vmstat
parent7e498012ab35abe310626f222edcbc2a067abfc9 (diff)
downloadFreeBSD-src-8348a2e29463adaac848d62aca1ee994d4f6123f.zip
FreeBSD-src-8348a2e29463adaac848d62aca1ee994d4f6123f.tar.gz
Add the -H, -h and -P flags to vmstat. -P causes per-cpu output of
user/system/idle stats. -h feeds the memory column through humanize_number() to reduce the amount of column overflowing. -H turns this off. -h is turned on by default if stdout is a tty.
Diffstat (limited to 'usr.bin/vmstat')
-rw-r--r--usr.bin/vmstat/Makefile4
-rw-r--r--usr.bin/vmstat/vmstat.810
-rw-r--r--usr.bin/vmstat/vmstat.c213
3 files changed, 207 insertions, 20 deletions
diff --git a/usr.bin/vmstat/Makefile b/usr.bin/vmstat/Makefile
index 21795e9..6e87a6a 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 <bsd.prog.mk>
diff --git a/usr.bin/vmstat/vmstat.8 b/usr.bin/vmstat/vmstat.8
index 29dde13..d810978 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.
@@ -114,6 +120,8 @@ Report on the usage of kernel dynamic memory allocated using
by type.
.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 28d45c0..0c7bd72 100644
--- a/usr.bin/vmstat/vmstat.c
+++ b/usr.bin/vmstat/vmstat.c
@@ -76,6 +76,7 @@ __FBSDID("$FreeBSD$");
#include <sysexits.h>
#include <time.h>
#include <unistd.h>
+#include <libutil.h>
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;
@@ -487,8 +503,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)
{
@@ -496,6 +575,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;
@@ -517,9 +598,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 {
@@ -528,6 +617,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;
@@ -563,7 +658,7 @@ dovmstat(unsigned int interval, int reps)
errx(1, "%s", devstat_errbuf);
break;
case 1:
- printhdr();
+ printhdr(ncpus, cpumask);
break;
default:
break;
@@ -579,8 +674,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("%5lu ",
(unsigned long)rate(sum.v_vm_faults - osum.v_vm_faults));
(void)printf("%3lu ",
@@ -596,11 +699,14 @@ dovmstat(unsigned int interval, int reps)
(void)printf("%3lu ",
(unsigned long)rate(sum.v_pdpages - osum.v_pdpages));
devstats();
- (void)printf("%4lu %4lu %4lu ",
+ (void)printf("%4lu %4lu %4lu",
(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)
@@ -620,7 +726,7 @@ dovmstat(unsigned int interval, int reps)
}
static void
-printhdr(void)
+printhdr(int ncpus, u_long cpumask)
{
int i, num_shown;
@@ -630,7 +736,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)
@@ -638,7 +752,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;
}
@@ -809,9 +929,25 @@ 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;
@@ -821,11 +957,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
OpenPOWER on IntegriCloud