diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2013-09-07 11:43:51 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2013-09-07 11:43:51 +0000 |
commit | 3f2b05ece98cb51c205aa9ddaa18957e235744ea (patch) | |
tree | 4639f84177d63c675b15ec0494c2a3ab6c0736e9 /usr.bin | |
parent | 1b6027ea77f1a272eea3af02ca4721d6a05dbfa5 (diff) |
Add a new screen "cpu" that simply lists the usage of each CPU core.
Also add a new -B command line flag that works like -b but waits some
cycles before dumping anything to the console.
With much help from jmc@
OK jj@ lambert@ jmc@
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/systat/Makefile | 4 | ||||
-rw-r--r-- | usr.bin/systat/cpu.c | 269 | ||||
-rw-r--r-- | usr.bin/systat/engine.c | 7 | ||||
-rw-r--r-- | usr.bin/systat/engine.h | 3 | ||||
-rw-r--r-- | usr.bin/systat/main.c | 12 | ||||
-rw-r--r-- | usr.bin/systat/systat.1 | 22 | ||||
-rw-r--r-- | usr.bin/systat/systat.h | 3 |
7 files changed, 307 insertions, 13 deletions
diff --git a/usr.bin/systat/Makefile b/usr.bin/systat/Makefile index b8424d5bffc..0baf9c6f3da 100644 --- a/usr.bin/systat/Makefile +++ b/usr.bin/systat/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.24 2010/07/22 12:33:29 giovanni Exp $ +# $OpenBSD: Makefile,v 1.25 2013/09/07 11:43:49 reyk Exp $ PROG= systat @@ -9,7 +9,7 @@ CPPFLAGS+=-I${.CURDIR}/../../usr.bin/vmstat CPPFLAGS+=-I${.CURDIR}/../../sbin/pfctl SRCS= dkstats.c engine.c if.c inetname.c iostat.c main.c mbufs.c netstat.c \ nfs.c pigs.c sensors.c swap.c vmstat.c pftop.c cache.c pf.c \ - pool.c malloc.c + pool.c malloc.c cpu.c DPADD= ${LIBCURSES} ${LIBM} ${LIBKVM} LDADD= -lcurses -lm -lkvm diff --git a/usr.bin/systat/cpu.c b/usr.bin/systat/cpu.c new file mode 100644 index 00000000000..716f1478019 --- /dev/null +++ b/usr.bin/systat/cpu.c @@ -0,0 +1,269 @@ +/* $OpenBSD: cpu.c,v 1.1 2013/09/07 11:43:49 reyk Exp $ */ + +/* + * Copyright (c) 2013 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* CPU percentages() function from usr.bin/top/util.c: + * + * Top users/processes display for Unix + * Version 3 + * + * Copyright (c) 1984, 1989, William LeFebvre, Rice University + * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR OR HIS EMPLOYER BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/dkstat.h> +#include <sys/sysctl.h> + +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include "systat.h" + +void print_cpu(void); +int read_cpu(void); +int select_cpu(void); +static void cpu_info(void); +static void print_fld_percentage(field_def *, double); +static int percentages(int, int64_t *, int64_t *, int64_t *, int64_t *); + +field_def fields_cpu[] = { + { "CPU", 4, 8, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0 }, + { "User", 10, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0 }, + { "Nice", 10, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0 }, + { "System", 10, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0 }, + { "Interrupt", 10, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0 }, + { "Idle", 10, 20, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0 }, +}; + +#define FLD_CPU_CPU FIELD_ADDR(fields_cpu, 0) +#define FLD_CPU_INT FIELD_ADDR(fields_cpu, 1) +#define FLD_CPU_SYS FIELD_ADDR(fields_cpu, 2) +#define FLD_CPU_USR FIELD_ADDR(fields_cpu, 3) +#define FLD_CPU_NIC FIELD_ADDR(fields_cpu, 4) +#define FLD_CPU_IDLE FIELD_ADDR(fields_cpu, 5) + +/* Define views */ +field_def *view_cpu_0[] = { + FLD_CPU_CPU, + FLD_CPU_INT, FLD_CPU_SYS, FLD_CPU_USR, FLD_CPU_NIC, FLD_CPU_IDLE +}; + +/* Define view managers */ +struct view_manager cpu_mgr = { + "cpu", select_cpu, read_cpu, NULL, print_header, + print_cpu, keyboard_callback, NULL, NULL +}; + +field_view views_cpu[] = { + { view_cpu_0, "cpu", 'C', &cpu_mgr }, + { NULL, NULL, 0, NULL } +}; + +int cpu_count; +int64_t *cpu_states; +int64_t **cpu_tm; +int64_t **cpu_old; +int64_t **cpu_diff; + +/* + * percentages(cnt, out, new, old, diffs) - calculate percentage change + * between array "old" and "new", putting the percentages in "out". + * "cnt" is size of each array and "diffs" is used for scratch space. + * The array "old" is updated on each call. + * The routine assumes modulo arithmetic. This function is especially + * useful on BSD machines for calculating cpu state percentages. + */ +static int +percentages(int cnt, int64_t *out, int64_t *new, int64_t *old, int64_t *diffs) +{ + int64_t change, total_change, *dp, half_total; + int i; + + /* initialization */ + total_change = 0; + dp = diffs; + + /* calculate changes for each state and the overall change */ + for (i = 0; i < cnt; i++) { + if ((change = *new - *old) < 0) { + /* this only happens when the counter wraps */ + change = INT64_MAX - *old + *new; + } + total_change += (*dp++ = change); + *old++ = *new++; + } + + /* avoid divide by zero potential */ + if (total_change == 0) + total_change = 1; + + /* calculate percentages based on overall change, rounding up */ + half_total = total_change / 2l; + for (i = 0; i < cnt; i++) + *out++ = ((*diffs++ * 1000 + half_total) / total_change); + + /* return the total in case the caller wants to use it */ + return (total_change); +} + +static void +cpu_info(void) +{ + int cpu_time_mib[] = { CTL_KERN, KERN_CPTIME2, 0 }, i; + int64_t *tmpstate; + size_t size; + + size = CPUSTATES * sizeof(int64_t); + for (i = 0; i < cpu_count; i++) { + cpu_time_mib[2] = i; + tmpstate = cpu_states + (CPUSTATES * i); + if (sysctl(cpu_time_mib, 3, cpu_tm[i], &size, NULL, 0) < 0) + error("sysctl KERN_CPTIME2"); + percentages(CPUSTATES, tmpstate, cpu_tm[i], + cpu_old[i], cpu_diff[i]); + } +} + +static void +print_fld_percentage(field_def *fld, double val) +{ + if (fld == NULL) + return; + + tb_start(); + tbprintf(val >= 1000 ? "%4.0f%%" : "%4.1f%%", val / 10.); + print_fld_tb(fld); + tb_end(); +} + +int +select_cpu(void) +{ + return (0); +} + +int +read_cpu(void) +{ + cpu_info(); + num_disp = cpu_count; + return (0); +} + +int +initcpu(void) +{ + field_view *v; + size_t size = sizeof(cpu_count); + int mib[2], i; + + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + if (sysctl(mib, 2, &cpu_count, &size, NULL, 0) == -1) + return (-1); + if ((cpu_states = calloc(cpu_count, + CPUSTATES * sizeof(int64_t))) == NULL) + return (-1); + if ((cpu_tm = calloc(cpu_count, sizeof(int64_t *))) == NULL || + (cpu_old = calloc(cpu_count, sizeof(int64_t *))) == NULL || + (cpu_diff = calloc(cpu_count, sizeof(int64_t *))) == NULL) + return (-1); + for (i = 0; i < cpu_count; i++) { + if ((cpu_tm[i] = calloc(CPUSTATES, sizeof(int64_t))) == NULL || + (cpu_old[i] = calloc(CPUSTATES, sizeof(int64_t))) == NULL || + (cpu_diff[i] = calloc(CPUSTATES, sizeof(int64_t))) == NULL) + return (-1); + } + + for (v = views_cpu; v->name != NULL; v++) + add_view(v); + + read_cpu(); + + return(1); +} + +#define ADD_EMPTY_LINE \ + do { \ + if (cur >= dispstart && cur < end) \ + end_line(); \ + if (++cur >= end) \ + return; \ + } while (0) + +#define ADD_LINE_CPU(v, cs) \ + do { \ + if (cur >= dispstart && cur < end) { \ + print_fld_size(FLD_CPU_CPU, (v)); \ + print_fld_percentage(FLD_CPU_INT, (cs[0])); \ + print_fld_percentage(FLD_CPU_SYS, (cs[1])); \ + print_fld_percentage(FLD_CPU_USR, (cs[2])); \ + print_fld_percentage(FLD_CPU_NIC, (cs[3])); \ + print_fld_percentage(FLD_CPU_IDLE, (cs[4])); \ + end_line(); \ + } \ + if (++cur >= end) \ + return; \ + } while (0) + +void +print_cpu(void) +{ + time_t tm; + int cur = 0, c, i; + int end = dispstart + maxprint; + int64_t *states; + double value[CPUSTATES]; + tm = time(NULL); + + if (end > num_disp) + end = num_disp; + + for (c = 0; c < cpu_count; c++) { + states = cpu_states + (CPUSTATES * c); + + for (i = 0; i < CPUSTATES; i++) + value[i] = *states++; + + ADD_LINE_CPU(c, value); + } + + ADD_EMPTY_LINE; +} diff --git a/usr.bin/systat/engine.c b/usr.bin/systat/engine.c index ed00c638976..6a8cd97ad41 100644 --- a/usr.bin/systat/engine.c +++ b/usr.bin/systat/engine.c @@ -1,4 +1,4 @@ -/* $Id: engine.c,v 1.14 2011/04/05 07:35:32 mpf Exp $ */ +/* $Id: engine.c,v 1.15 2013/09/07 11:43:49 reyk Exp $ */ /* * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org> * @@ -55,6 +55,7 @@ struct view_ent { useconds_t udelay = 5000000; int dispstart = 0; int interactive = 1; +int averageonly = 0; int maxprint = 0; int paused = 0; int rawmode = 0; @@ -1351,7 +1352,9 @@ engine_loop(int countmax) if (need_update) { erase(); - disp_update(); + if (!averageonly || + (averageonly && count == countmax - 1)) + disp_update(); end_page(); need_update = 0; if (countmax && ++count >= countmax) diff --git a/usr.bin/systat/engine.h b/usr.bin/systat/engine.h index 8ca071f8bcc..18c9edcb324 100644 --- a/usr.bin/systat/engine.h +++ b/usr.bin/systat/engine.h @@ -1,4 +1,4 @@ -/* $Id: engine.h,v 1.7 2011/04/05 07:35:32 mpf Exp $ */ +/* $Id: engine.h,v 1.8 2013/09/07 11:43:49 reyk Exp $ */ /* * Copyright (c) 2001, 2007 Can Erkin Acar <canacar@openbsd.org> * @@ -148,6 +148,7 @@ extern int sortdir; extern useconds_t udelay; extern int dispstart; extern int interactive; +extern int averageonly; extern int maxprint; extern int paused; extern int rawmode; diff --git a/usr.bin/systat/main.c b/usr.bin/systat/main.c index 44461697171..258603a5adb 100644 --- a/usr.bin/systat/main.c +++ b/usr.bin/systat/main.c @@ -1,4 +1,4 @@ -/* $Id: main.c,v 1.59 2011/04/05 07:35:32 mpf Exp $ */ +/* $Id: main.c,v 1.60 2013/09/07 11:43:50 reyk Exp $ */ /* * Copyright (c) 2001, 2007 Can Erkin Acar * Copyright (c) 2001 Daniel Hartmeier @@ -208,7 +208,7 @@ void usage(void) { extern char *__progname; - fprintf(stderr, "usage: %s [-abiNn] [-d count] " + fprintf(stderr, "usage: %s [-aBbiNn] [-d count] " "[-s delay] [-w width] [view] [delay]\n", __progname); exit(1); } @@ -359,6 +359,7 @@ initialize(void) initpool(); initmalloc(); initnfs(); + initcpu(); } void @@ -403,11 +404,16 @@ main(int argc, char *argv[]) if (setresgid(gid, gid, gid) == -1) err(1, "setresgid"); - while ((ch = getopt(argc, argv, "Nabd:ins:w:")) != -1) { + while ((ch = getopt(argc, argv, "BNabd:ins:w:")) != -1) { switch (ch) { case 'a': maxlines = -1; break; + case 'B': + averageonly = 1; + if (countmax < 2) + countmax = 2; + /* FALLTHROUGH */ case 'b': rawmode = 1; interactive = 0; diff --git a/usr.bin/systat/systat.1 b/usr.bin/systat/systat.1 index 2f728072ae8..f7c02c7122e 100644 --- a/usr.bin/systat/systat.1 +++ b/usr.bin/systat/systat.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: systat.1,v 1.95 2012/12/23 17:01:27 jmc Exp $ +.\" $OpenBSD: systat.1,v 1.96 2013/09/07 11:43:50 reyk Exp $ .\" $NetBSD: systat.1,v 1.6 1996/05/10 23:16:39 thorpej Exp $ .\" .\" Copyright (c) 1985, 1990, 1993 @@ -30,7 +30,7 @@ .\" .\" @(#)systat.1 8.2 (Berkeley) 12/30/93 .\" -.Dd $Mdocdate: December 23 2012 $ +.Dd $Mdocdate: September 7 2013 $ .Dt SYSTAT 1 .Os .Sh NAME @@ -38,7 +38,7 @@ .Nd display system statistics .Sh SYNOPSIS .Nm systat -.Op Fl abiNn +.Op Fl aBbiNn .Op Fl d Ar count .Op Fl s Ar delay .Op Fl w Ar width @@ -86,8 +86,17 @@ The options are as follows: .Bl -tag -width Ds .It Fl a Display all lines. +.It Fl B +Raw, non-interactive mode. +The default is to exit after two screen updates, +with statistics only ever displayed once. +Useful for views such as +.Ic cpu , +where initial calculations are useless. .It Fl b Raw, non-interactive mode. +The default is to exit after one screen update, +with statistics displayed every update. .It Fl d Ar count Exit after .Ar count @@ -130,8 +139,9 @@ argument expects to be one of: .Ic malloc , .Ic buckets , .Ic nfsclient , +.Ic nfsserver , or -.Ic nfsserver . +.Ic cpu . These displays can also be requested interactively and are described in full detail below. .Ar view @@ -236,6 +246,10 @@ Display kernel .Xr malloc 9 bucket statistics similar to the output of .Cm vmstat Fl m . +.It Ic cpu +Display information about the average usage of each CPU, +similar to the output provided by +.Xr top 1 . .It Ic ifstat Display interface statistics. The diff --git a/usr.bin/systat/systat.h b/usr.bin/systat/systat.h index c9de08920e2..229faf75f68 100644 --- a/usr.bin/systat/systat.h +++ b/usr.bin/systat/systat.h @@ -1,4 +1,4 @@ -/* $OpenBSD: systat.h,v 1.18 2012/12/05 23:20:26 deraadt Exp $ */ +/* $OpenBSD: systat.h,v 1.19 2013/09/07 11:43:50 reyk Exp $ */ /* $NetBSD: systat.h,v 1.2 1995/01/20 08:52:14 jtc Exp $ */ /*- @@ -89,6 +89,7 @@ int initpf(void); int initpool(void); int initmalloc(void); int initnfs(void); +int initcpu(void); void error(const char *fmt, ...); void nlisterr(struct nlist []); |