Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 27 Nov 2007 03:40:25 GMT
From:      Peter Wemm <peter@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 129607 for review
Message-ID:  <200711270340.lAR3eP5x079261@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=129607

Change 129607 by peter@peter_melody on 2007/11/27 03:39:31

	Do bad things to vmstat to report per-cpu numbers.
	I'm unsure if I want to go wide or multi-line in per-cpu mode.
	For now, this goes wide with the -C (cpu?) flag.  This might change to
	sync with top.  Multi-line output is another possibility.  For now, just
	get *something*.
	
	Also, use humanize_number on memory columns when stdout is a tty. (bikeshed potential)
	
	Attempt to keep some sort of alignment in the cpu state columns.  The 100% overflow
	makes a real mess and it compounds.  Try to track when we overflowed and reduce padding
	in the next column when we can.
	
	doghouse# vmstat -C 1
	 procs      memory      page                   disk   faults         cpu0     cpu1     cpu2     cpu3
	 r b w     avm    fre   flt  re  pi  po    fr  sr ad0   in   sy   cs us sy id us sy id us sy id us sy id
	 1 0 0  64356K  1854M    45   0   0   0    44   0   0    8  195  395  0  0 100 3  1 97  8  2 90 13  3 84
	 1 0 0  64356K  1854M     0   0   0   0     0   0   0    6  410  363  0  0 100 67 16 17 0  0 100 14 3 83
	 1 0 0  64356K  1854M     0   0   0   0     0   0   0    4  411  359  0  0 100 81 19 0  0  0 100 0  0 100
	 1 0 0  64356K  1854M     0   0   0   0     0   0   0    5  403  360  1  2 96 76 14 10  5  2 93  0  0 100
	 1 0 0  64356K  1854M     0   0   0   0     0   0   0   11  403  375 14  2 83 60 14 26  0  0 100 8  2 90
	 1 0 0  64356K  1854M     0   0   0   0     0   0   3   10  407  384  0  0 100 71 16 13 0  0 100 11 2 87
	 1 0 0  64356K  1854M     0   0   0   0     0   0   0    6  403  351  0  0 100 0  0 100 0  0 100 80 20 0
	 1 0 0  64356K  1854M     0   0   0   0     0   0   0   13  413  367  0  0 100 0  0 100 0  0 100 81 19 0

Affected files ...

.. //depot/projects/hammer/usr.bin/vmstat/Makefile#5 edit
.. //depot/projects/hammer/usr.bin/vmstat/vmstat.c#26 edit

Differences ...

==== //depot/projects/hammer/usr.bin/vmstat/Makefile#5 (text+ko) ====

@@ -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>

==== //depot/projects/hammer/usr.bin/vmstat/vmstat.c#26 (text+ko) ====

@@ -76,6 +76,7 @@
 #include <sysexits.h>
 #include <time.h>
 #include <unistd.h>
+#include <libutil.h>
 
 static char da[] = "da";
 
@@ -137,6 +138,8 @@
 static int	winlines = 20;
 static int	aflag;
 static int	nflag;
+static int	Cflag;
+static int	hflag;
 
 static kvm_t   *kd;
 
@@ -149,6 +152,7 @@
 #define ZMEMSTAT	0x40
 
 static void	cpustats(void);
+static void	Cpustats(int, u_long, int);
 static void	devstats(void);
 static void	doforkst(void);
 static void	dointr(void);
@@ -160,7 +164,7 @@
 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 @@
 	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:CfhHiM:mN:n:p:stw:z")) != -1) {
 		switch (c) {
 		case 'a':
 			aflag++;
@@ -188,9 +193,18 @@
 		case 'c':
 			reps = atoi(optarg);
 			break;
+		case 'C':
+			Cflag++;
+			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 @@
 			warnx("kvm_nlist: %s", kvm_geterr(kd));
 		exit(1);
 	}
+	if (kd && Cflag)
+		errx(1, "Cannot use -C with crash dumps");
 
 	if (todo & VMSTAT) {
 		struct winsize winsize;
@@ -487,8 +503,71 @@
 	}
 }
 
+/* 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 @@
 	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 @@
 		hz = clockrate.hz;
 	}
 
+	if (Cflag) {
+		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 @@
 			if (size != sizeof(cur.cp_time))
 				errx(1, "cp_time size mismatch");
 		}
+		if (Cflag) {
+			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 @@
 				errx(1, "%s", devstat_errbuf);
 				break;
 			case 1:
-				printhdr();
+				printhdr(ncpus, cpumask);
 				break;
 			default:
 				break;
@@ -579,8 +674,16 @@
 		    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 @@
 		(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 (Cflag)
+			Cpustats(ncpus, cpumask, maxid);
+		else
+			cpustats();
 		(void)printf("\n");
 		(void)fflush(stdout);
 		if (reps >= 0 && --reps <= 0)
@@ -620,7 +726,7 @@
 }
 
 static void
-printhdr(void)
+printhdr(int ncpus, u_long cpumask)
 {
 	int i, num_shown;
 
@@ -630,7 +736,15 @@
 		(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 (Cflag) {
+		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 @@
 			(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 (Cflag) {
+		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 @@
 }
 
 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 @@
 		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
+Cpustats(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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200711270340.lAR3eP5x079261>