summaryrefslogtreecommitdiff
path: root/usr.bin/top
diff options
context:
space:
mode:
authorcheloha <cheloha@cvs.openbsd.org>2018-11-17 23:10:09 +0000
committercheloha <cheloha@cvs.openbsd.org>2018-11-17 23:10:09 +0000
commitd6136e8d27d8e31ad8c702cddb7486fa7d975c9c (patch)
tree143e3f6ea14c3cb78d3bd6928e2df80f77f7133f /usr.bin/top
parent660a8098742488fed8eaed56e3428d66271ab342 (diff)
Add new KERN_CPUSTATS sysctl(2) so we can identify offline CPUs.
Because of hw.smt we need a way to determine whether a given CPU is "online" or "offline" from userspace. KERN_CPTIME2 is an array, and so cannot be cleanly extended for this purpose, so add a new sysctl(2) KERN_CPUSTATS with an extensible struct. At the moment it's just KERN_CPTIME2 with a flags member, but it can grow as needed. KERN_CPUSTATS appears to have been defined by BSDi long ago, but there are few (if any) packages in the wild still using the symbol so breakage in ports should be near zero. No other system inherited the symbol from BSDi, either. Then, use the new sysctl(2) in systat(1) and top(1): - systat(1) draws placeholder marks ('-') instead of percentages for offline CPUs in the cpu view. - systat(1) omits offline CPU ticks when drawing the "big bar" in the vmstat view. The upshot is that the bar isn't half idle when half your logical CPUs are disabled. - top(1) does not draw lines for offline CPUs; if CPUs toggle on or offline in interactive mode we redraw the display to expand/reduce space for the new/missing CPUs. This is consistent with what some top(1) implementations do on Linux. - top(1) omits offline CPUs from the totals when CPU totals are combined into a single line (the '-1' flag). Originally prompted by deraadt@. Discussed endlessly with deraadt@, ketennis@, and sthen@. Tested by jmc@ and jca@. Earlier versions also discussed with jca@. Earlier versions tested by jmc@, tb@, and many others. docs ok jmc@, kernel bits ok ketennis@, everything ok sthen@, "Is your stuff in yet?" deraadt@
Diffstat (limited to 'usr.bin/top')
-rw-r--r--usr.bin/top/display.c31
-rw-r--r--usr.bin/top/display.h4
-rw-r--r--usr.bin/top/machine.c83
-rw-r--r--usr.bin/top/machine.h4
-rw-r--r--usr.bin/top/top.c26
5 files changed, 89 insertions, 59 deletions
diff --git a/usr.bin/top/display.c b/usr.bin/top/display.c
index e2bd611e638..78d42793fed 100644
--- a/usr.bin/top/display.c
+++ b/usr.bin/top/display.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: display.c,v 1.56 2018/10/05 18:56:57 cheloha Exp $ */
+/* $OpenBSD: display.c,v 1.57 2018/11/17 23:10:08 cheloha Exp $ */
/*
* Top users/processes display for Unix
@@ -100,6 +100,7 @@ int y_header;
int y_idlecursor;
int y_procs;
extern int ncpu;
+extern int ncpuonline;
extern int combine_cpus;
extern struct process_select ps;
@@ -125,9 +126,10 @@ static int (*standendp)(void);
int
display_resize(void)
{
- int display_lines;
- int cpu_lines = (combine_cpus ? 1 : ncpu);
+ int cpu_lines, display_lines;
+ ncpuonline = getncpuonline();
+ cpu_lines = (combine_cpus ? 1 : ncpuonline);
y_mem = 2 + cpu_lines;
y_header = 4 + cpu_lines;
y_procs = 5 + cpu_lines;
@@ -136,7 +138,7 @@ display_resize(void)
/* if operating in "dumb" mode, we only need one line */
display_lines = smart_terminal ? screen_length - y_procs : 1;
- y_idlecursor = y_message = 3 + (combine_cpus ? 1 : ncpu);
+ y_idlecursor = y_message = 3 + (combine_cpus ? 1 : ncpuonline);
if (screen_length <= y_message)
y_idlecursor = y_message = screen_length - 1;
@@ -377,9 +379,9 @@ cpustates_tag(int cpu)
}
void
-i_cpustates(int64_t *ostates)
+i_cpustates(int64_t *ostates, int *online)
{
- int i, first, cpu;
+ int i, first, cpu, cpu_line;
double value;
int64_t *states;
char **names, *thisname;
@@ -393,6 +395,8 @@ i_cpustates(int64_t *ostates)
}
memset(values, 0, num_cpustates * sizeof(*values));
for (cpu = 0; cpu < ncpu; cpu++) {
+ if (!online[cpu])
+ continue;
names = cpustate_names;
states = ostates + (CPUSTATES * cpu);
i = 0;
@@ -409,11 +413,11 @@ i_cpustates(int64_t *ostates)
first = 0;
move(2, 0);
clrtoeol();
- printwp("%-3d CPUs: ", ncpu);
+ printwp("%-3d CPUs: ", ncpuonline);
while ((thisname = *names++) != NULL) {
if (*thisname != '\0') {
- value = values[i++] / ncpu;
+ value = values[i++] / ncpuonline;
/* if percentage is >= 1000, print it as 100% */
printwp((value >= 1000 ? "%s%4.0f%% %s" :
"%s%4.1f%% %s"), first++ == 0 ? "" : ", ",
@@ -424,14 +428,18 @@ i_cpustates(int64_t *ostates)
}
return;
}
- for (cpu = 0; cpu < ncpu; cpu++) {
+ for (cpu = cpu_line = 0; cpu < ncpu; cpu++) {
+ /* skip if offline */
+ if (!online[cpu])
+ continue;
+
/* now walk thru the names and print the line */
names = cpustate_names;
first = 0;
states = ostates + (CPUSTATES * cpu);
- if (screen_length > 2 + cpu || !smart_terminal) {
- move(2 + cpu, 0);
+ if (screen_length > 2 + cpu_line || !smart_terminal) {
+ move(2 + cpu_line, 0);
clrtoeol();
addstrp(cpustates_tag(cpu));
@@ -447,6 +455,7 @@ i_cpustates(int64_t *ostates)
}
}
putn();
+ cpu_line++;
}
}
}
diff --git a/usr.bin/top/display.h b/usr.bin/top/display.h
index b146b04a0c6..60374d8ddbc 100644
--- a/usr.bin/top/display.h
+++ b/usr.bin/top/display.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: display.h,v 1.14 2018/10/05 18:56:57 cheloha Exp $ */
+/* $OpenBSD: display.h,v 1.15 2018/11/17 23:10:08 cheloha Exp $ */
/*
* Top users/processes display for Unix
@@ -40,7 +40,7 @@ void u_loadave(int, double *);
void i_timeofday(time_t *);
void i_procstates(int, int *, int);
void u_procstates(int, int *);
-void i_cpustates(int64_t *);
+void i_cpustates(int64_t *, int *);
void u_cpustates(int64_t *);
void i_memory(int *);
void u_memory(int *);
diff --git a/usr.bin/top/machine.c b/usr.bin/top/machine.c
index fcf6da95869..201e6d81674 100644
--- a/usr.bin/top/machine.c
+++ b/usr.bin/top/machine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machine.c,v 1.94 2018/10/05 18:56:57 cheloha Exp $ */
+/* $OpenBSD: machine.c,v 1.95 2018/11/17 23:10:08 cheloha Exp $ */
/*-
* Copyright (c) 1994 Thorsten Lockert <tholo@sigmasoft.com>
@@ -93,9 +93,9 @@ char *state_abbrev[] = {
};
/* these are for calculating cpu state percentages */
-static int64_t **cp_time;
-static int64_t **cp_old;
-static int64_t **cp_diff;
+static struct cpustats *cp_time;
+static struct cpustats *cp_old;
+static struct cpustats *cp_diff;
/* these are for detailing the process states */
int process_states[8];
@@ -111,6 +111,9 @@ char *cpustatenames[] = {
"user", "nice", "sys", "spin", "intr", "idle", NULL
};
+/* this is for tracking which cpus are online */
+int *cpu_online;
+
/* these are for detailing the memory statistics */
int memory_stats[10];
char *memorynames[] = {
@@ -139,6 +142,7 @@ static int pageshift; /* log base 2 of the pagesize */
#define pagetok(size) ((size) << pageshift)
int ncpu;
+int ncpuonline;
int fscale;
unsigned int maxslp;
@@ -170,9 +174,23 @@ getncpu(void)
}
int
+getncpuonline(void)
+{
+ int mib[] = { CTL_HW, HW_NCPUONLINE };
+ int numcpu;
+ size_t size = sizeof(numcpu);
+
+ if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
+ &numcpu, &size, NULL, 0) == -1)
+ return (-1);
+
+ return (numcpu);
+}
+
+int
machine_init(struct statics *statics)
{
- int pagesize, cpu;
+ int pagesize;
ncpu = getncpu();
if (ncpu == -1)
@@ -182,19 +200,14 @@ machine_init(struct statics *statics)
cpu_states = calloc(ncpu, CPUSTATES * sizeof(int64_t));
if (cpu_states == NULL)
err(1, NULL);
- cp_time = calloc(ncpu, sizeof(int64_t *));
- cp_old = calloc(ncpu, sizeof(int64_t *));
- cp_diff = calloc(ncpu, sizeof(int64_t *));
+ cp_time = calloc(ncpu, sizeof(*cp_time));
+ cp_old = calloc(ncpu, sizeof(*cp_old));
+ cp_diff = calloc(ncpu, sizeof(*cp_diff));
if (cp_time == NULL || cp_old == NULL || cp_diff == NULL)
err(1, NULL);
- for (cpu = 0; cpu < ncpu; cpu++) {
- cp_time[cpu] = calloc(CPUSTATES, sizeof(int64_t));
- cp_old[cpu] = calloc(CPUSTATES, sizeof(int64_t));
- cp_diff[cpu] = calloc(CPUSTATES, sizeof(int64_t));
- if (cp_time[cpu] == NULL || cp_old[cpu] == NULL ||
- cp_diff[cpu] == NULL)
- err(1, NULL);
- }
+ cpu_online = calloc(ncpu, sizeof(*cpu_online));
+ if (cpu_online == NULL)
+ err(1, NULL);
pbase = NULL;
pref = NULL;
@@ -243,6 +256,7 @@ format_header(char *second_field, int show_threads)
void
get_system_info(struct system_info *si)
{
+ static int cpustats_mib[] = {CTL_KERN, KERN_CPUSTATS, /*fillme*/0};
static int sysload_mib[] = {CTL_VM, VM_LOADAVG};
static int uvmexp_mib[] = {CTL_VM, VM_UVMEXP};
static int bcstats_mib[] = {CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT};
@@ -254,31 +268,17 @@ get_system_info(struct system_info *si)
int i;
int64_t *tmpstate;
- if (ncpu > 1) {
- int cp_time_mib[] = {CTL_KERN, KERN_CPTIME2, /*fillme*/0};
-
- size = CPUSTATES * sizeof(int64_t);
- for (i = 0; i < ncpu; i++) {
- cp_time_mib[2] = i;
- tmpstate = cpu_states + (CPUSTATES * i);
- if (sysctl(cp_time_mib, 3, cp_time[i], &size, NULL, 0) < 0)
- warn("sysctl kern.cp_time2 failed");
- /* convert cp_time2 counts to percentages */
- (void) percentages(CPUSTATES, tmpstate, cp_time[i],
- cp_old[i], cp_diff[i]);
- }
- } else {
- int cp_time_mib[] = {CTL_KERN, KERN_CPTIME};
- long cp_time_tmp[CPUSTATES];
-
- size = sizeof(cp_time_tmp);
- if (sysctl(cp_time_mib, 2, cp_time_tmp, &size, NULL, 0) < 0)
- warn("sysctl kern.cp_time failed");
- for (i = 0; i < CPUSTATES; i++)
- cp_time[0][i] = cp_time_tmp[i];
- /* convert cp_time counts to percentages */
- (void) percentages(CPUSTATES, cpu_states, cp_time[0],
- cp_old[0], cp_diff[0]);
+ size = sizeof(*cp_time);
+ for (i = 0; i < ncpu; i++) {
+ cpustats_mib[2] = i;
+ tmpstate = cpu_states + (CPUSTATES * i);
+ if (sysctl(cpustats_mib, 3, &cp_time[i], &size, NULL, 0) < 0)
+ warn("sysctl kern.cpustats failed");
+ /* convert cpustats counts to percentages */
+ (void) percentages(CPUSTATES, tmpstate, cp_time[i].cs_time,
+ cp_old[i].cs_time, cp_diff[i].cs_time);
+ /* note whether the cpu is online */
+ cpu_online[i] = (cp_time[i].cs_flags & CPUSTATS_ONLINE) != 0;
}
size = sizeof(sysload);
@@ -317,6 +317,7 @@ get_system_info(struct system_info *si)
/* set arrays and strings */
si->cpustates = cpu_states;
+ si->cpuonline = cpu_online;
si->memory = memory_stats;
si->last_pid = -1;
}
diff --git a/usr.bin/top/machine.h b/usr.bin/top/machine.h
index 5cfe8d18266..df683780745 100644
--- a/usr.bin/top/machine.h
+++ b/usr.bin/top/machine.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: machine.h,v 1.24 2018/10/05 18:56:57 cheloha Exp $ */
+/* $OpenBSD: machine.h,v 1.25 2018/11/17 23:10:08 cheloha Exp $ */
/*
* Top users/processes display for Unix
@@ -56,6 +56,7 @@ struct system_info {
* "active" */
int *procstates;
int64_t *cpustates;
+ int *cpuonline;
int *memory;
};
@@ -95,4 +96,5 @@ extern uid_t proc_owner(pid_t);
extern struct kinfo_proc *getprocs(int, int, int *);
int getncpu(void);
+int getncpuonline(void);
int getfscale(void);
diff --git a/usr.bin/top/top.c b/usr.bin/top/top.c
index 55e498103a0..c63aa4d2003 100644
--- a/usr.bin/top/top.c
+++ b/usr.bin/top/top.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: top.c,v 1.96 2018/11/02 12:46:10 kn Exp $ */
+/* $OpenBSD: top.c,v 1.97 2018/11/17 23:10:08 cheloha Exp $ */
/*
* Top users/processes display for Unix
@@ -69,6 +69,9 @@ int rundisplay(void);
static int max_topn; /* maximum displayable processes */
+extern int ncpu;
+extern int ncpuonline;
+
extern int (*proc_compares[])(const void *, const void *);
int order_index;
@@ -286,7 +289,7 @@ parseargs(int ac, char **av)
}
}
- i = getncpu();
+ i = getncpuonline();
if (i == -1)
err(1, NULL);
@@ -317,7 +320,7 @@ main(int argc, char *argv[])
char *uname_field = "USERNAME", *header_text, *env_top;
const char *(*get_userid)(uid_t, int) = user_from_uid;
char **preset_argv = NULL, **av = argv;
- int preset_argc = 0, ac = argc, active_procs, i;
+ int preset_argc = 0, ac = argc, active_procs, i, ncpuonline_now;
sigset_t mask, oldmask;
time_t curr_time;
caddr_t processes;
@@ -485,6 +488,21 @@ restart:
/* get the current stats */
get_system_info(&system_info);
+ /*
+ * don't display stats for offline CPUs: resize if we're
+ * interactive and CPUs have toggled on or offline
+ */
+ if (interactive && !combine_cpus) {
+ for (i = ncpuonline_now = 0; i < ncpu; i++)
+ if (system_info.cpuonline[i])
+ ncpuonline_now++;
+ if (ncpuonline_now != ncpuonline) {
+ max_topn = display_resize();
+ reset_display();
+ continue;
+ }
+ }
+
/* get the current set of processes */
processes = get_process_info(&system_info, &ps,
proc_compares[order_index]);
@@ -502,7 +520,7 @@ restart:
ps.threads);
/* display the cpu state percentage breakdown */
- i_cpustates(system_info.cpustates);
+ i_cpustates(system_info.cpustates, system_info.cpuonline);
/* display memory stats */
i_memory(system_info.memory);