From owner-p4-projects@FreeBSD.ORG Tue Nov 27 03:40:26 2007 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 3004516A418; Tue, 27 Nov 2007 03:40:26 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id AE64A16A419 for ; Tue, 27 Nov 2007 03:40:25 +0000 (UTC) (envelope-from peter@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 99A5D13C458 for ; Tue, 27 Nov 2007 03:40:25 +0000 (UTC) (envelope-from peter@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id lAR3ePw1079264 for ; Tue, 27 Nov 2007 03:40:25 GMT (envelope-from peter@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id lAR3eP5x079261 for perforce@freebsd.org; Tue, 27 Nov 2007 03:40:25 GMT (envelope-from peter@freebsd.org) Date: Tue, 27 Nov 2007 03:40:25 GMT Message-Id: <200711270340.lAR3eP5x079261@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to peter@freebsd.org using -f From: Peter Wemm To: Perforce Change Reviews Cc: Subject: PERFORCE change 129607 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 27 Nov 2007 03:40:26 -0000 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 ==== //depot/projects/hammer/usr.bin/vmstat/vmstat.c#26 (text+ko) ==== @@ -76,6 +76,7 @@ #include #include #include +#include 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