summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2013-09-07 11:43:51 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2013-09-07 11:43:51 +0000
commit3f2b05ece98cb51c205aa9ddaa18957e235744ea (patch)
tree4639f84177d63c675b15ec0494c2a3ab6c0736e9 /usr.bin
parent1b6027ea77f1a272eea3af02ca4721d6a05dbfa5 (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/Makefile4
-rw-r--r--usr.bin/systat/cpu.c269
-rw-r--r--usr.bin/systat/engine.c7
-rw-r--r--usr.bin/systat/engine.h3
-rw-r--r--usr.bin/systat/main.c12
-rw-r--r--usr.bin/systat/systat.122
-rw-r--r--usr.bin/systat/systat.h3
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 []);