MFC: backport -P (per-cpu) stats for %user/%system/%idle etc.
This commit is contained in:
parent
fe5794c1d5
commit
c7bd46983f
@ -78,8 +78,10 @@ static int *lcpustates;
|
||||
static int *lmemory;
|
||||
static int *lswap;
|
||||
|
||||
static int num_cpus;
|
||||
static int *cpustate_columns;
|
||||
static int cpustate_total_length;
|
||||
static int cpustates_column;
|
||||
|
||||
static enum { OFF, ON, ERASE } header_status = ON;
|
||||
|
||||
@ -87,6 +89,29 @@ static int string_count();
|
||||
static void summary_format();
|
||||
static void line_update();
|
||||
|
||||
int x_lastpid = 10;
|
||||
int y_lastpid = 0;
|
||||
int x_loadave = 33;
|
||||
int x_loadave_nompid = 15;
|
||||
int y_loadave = 0;
|
||||
int x_procstate = 0;
|
||||
int y_procstate = 1;
|
||||
int x_brkdn = 15;
|
||||
int y_brkdn = 1;
|
||||
int x_mem = 5;
|
||||
int y_mem = 3;
|
||||
int x_swap = 6;
|
||||
int y_swap = 4;
|
||||
int y_message = 5;
|
||||
int x_header = 0;
|
||||
int y_header = 6;
|
||||
int x_idlecursor = 0;
|
||||
int y_idlecursor = 5;
|
||||
int y_procs = 7;
|
||||
|
||||
int y_cpustates = 2;
|
||||
int Header_lines = 7;
|
||||
|
||||
int display_resize()
|
||||
|
||||
{
|
||||
@ -138,6 +163,12 @@ struct statics *statics;
|
||||
|
||||
/* call resize to do the dirty work */
|
||||
lines = display_resize();
|
||||
num_cpus = statics->ncpus;
|
||||
cpustates_column = 5; /* CPU: */
|
||||
if (num_cpus != 1)
|
||||
cpustates_column += 2; /* CPU 0: */
|
||||
for (i = num_cpus; i > 9; i /= 10)
|
||||
cpustates_column++;
|
||||
|
||||
/* only do the rest if we need to */
|
||||
if (lines > -1)
|
||||
@ -153,7 +184,7 @@ struct statics *statics;
|
||||
num_swap = string_count(swap_names);
|
||||
lswap = (int *)malloc(num_swap * sizeof(int));
|
||||
num_cpustates = string_count(cpustate_names);
|
||||
lcpustates = (int *)malloc(num_cpustates * sizeof(int));
|
||||
lcpustates = (int *)malloc(num_cpustates * sizeof(int) * num_cpus);
|
||||
cpustate_columns = (int *)malloc(num_cpustates * sizeof(int));
|
||||
|
||||
memory_names = statics->memory_names;
|
||||
@ -365,14 +396,13 @@ int *brkdn;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef no_more
|
||||
/*
|
||||
* *_cpustates(states, names) - print the cpu state percentages
|
||||
*
|
||||
* Assumptions: cursor is on the PREVIOUS line
|
||||
*/
|
||||
|
||||
static int cpustates_column;
|
||||
|
||||
/* cpustates_tag() calculates the correct tag to use to label the line */
|
||||
|
||||
char *cpustates_tag()
|
||||
@ -398,6 +428,7 @@ char *cpustates_tag()
|
||||
cpustates_column = strlen(use);
|
||||
return(use);
|
||||
}
|
||||
#endif
|
||||
|
||||
i_cpustates(states)
|
||||
|
||||
@ -406,11 +437,18 @@ register int *states;
|
||||
{
|
||||
register int i = 0;
|
||||
register int value;
|
||||
register char **names = cpustate_names;
|
||||
register char **names;
|
||||
register char *thisname;
|
||||
int cpu;
|
||||
|
||||
for (cpu = 0; cpu < num_cpus; cpu++) {
|
||||
names = cpustate_names;
|
||||
|
||||
/* print tag and bump lastline */
|
||||
printf("\n%s", cpustates_tag());
|
||||
if (num_cpus == 1)
|
||||
printf("\nCPU: ");
|
||||
else
|
||||
printf("\nCPU %d: ", cpu);
|
||||
lastline++;
|
||||
|
||||
/* now walk thru the names and print the line */
|
||||
@ -423,14 +461,15 @@ register int *states;
|
||||
|
||||
/* if percentage is >= 1000, print it as 100% */
|
||||
printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"),
|
||||
i++ == 0 ? "" : ", ",
|
||||
(i++ % num_cpustates) == 0 ? "" : ", ",
|
||||
((float)value)/10.,
|
||||
thisname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* copy over values into "last" array */
|
||||
memcpy(lcpustates, states, num_cpustates * sizeof(int));
|
||||
memcpy(lcpustates, states, num_cpustates * sizeof(int) * num_cpus);
|
||||
}
|
||||
|
||||
u_cpustates(states)
|
||||
@ -439,14 +478,18 @@ register int *states;
|
||||
|
||||
{
|
||||
register int value;
|
||||
register char **names = cpustate_names;
|
||||
register char **names;
|
||||
register char *thisname;
|
||||
register int *lp;
|
||||
register int *colp;
|
||||
int cpu;
|
||||
|
||||
Move_to(cpustates_column, y_cpustates);
|
||||
lastline = y_cpustates;
|
||||
lp = lcpustates;
|
||||
for (cpu = 0; cpu < num_cpus; cpu++) {
|
||||
names = cpustate_names;
|
||||
|
||||
Move_to(cpustates_column, y_cpustates + cpu);
|
||||
lastline = y_cpustates + cpu;
|
||||
lp = lcpustates + (cpu * num_cpustates);
|
||||
colp = cpustate_columns;
|
||||
|
||||
/* we could be much more optimal about this */
|
||||
@ -458,8 +501,8 @@ register int *states;
|
||||
if (*lp != *states)
|
||||
{
|
||||
/* yes, move and change */
|
||||
Move_to(cpustates_column + *colp, y_cpustates);
|
||||
lastline = y_cpustates;
|
||||
Move_to(cpustates_column + *colp, y_cpustates + cpu);
|
||||
lastline = y_cpustates + cpu;
|
||||
|
||||
/* retrieve value and remember it */
|
||||
value = *states;
|
||||
@ -479,30 +522,39 @@ register int *states;
|
||||
colp++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
z_cpustates()
|
||||
|
||||
{
|
||||
register int i = 0;
|
||||
register char **names = cpustate_names;
|
||||
register char **names;
|
||||
register char *thisname;
|
||||
register int *lp;
|
||||
int cpu;
|
||||
|
||||
for (cpu = 0; cpu < num_cpus; cpu++) {
|
||||
names = cpustate_names;
|
||||
|
||||
/* show tag and bump lastline */
|
||||
printf("\n%s", cpustates_tag());
|
||||
if (num_cpus == 1)
|
||||
printf("\nCPU: ");
|
||||
else
|
||||
printf("\nCPU %d: ", cpu);
|
||||
lastline++;
|
||||
|
||||
while ((thisname = *names++) != NULL)
|
||||
{
|
||||
if (*thisname != '\0')
|
||||
{
|
||||
printf("%s %% %s", i++ == 0 ? "" : ", ", thisname);
|
||||
printf("%s %% %s", (i++ % num_cpustates) == 0 ? "" : ", ", thisname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* fill the "last" array with all -1s, to insure correct updating */
|
||||
lp = lcpustates;
|
||||
i = num_cpustates;
|
||||
i = num_cpustates * num_cpus;
|
||||
while (--i >= 0)
|
||||
{
|
||||
*lp++ = -1;
|
||||
|
@ -4,26 +4,28 @@
|
||||
* This file defines the locations on tne screen for various parts of the
|
||||
* display. These definitions are used by the routines in "display.c" for
|
||||
* cursor addressing.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#define x_lastpid 10
|
||||
#define y_lastpid 0
|
||||
#define x_loadave 33
|
||||
#define x_loadave_nompid 15
|
||||
#define y_loadave 0
|
||||
#define x_procstate 0
|
||||
#define y_procstate 1
|
||||
#define x_brkdn 15
|
||||
#define y_brkdn 1
|
||||
#define x_mem 5
|
||||
#define y_mem 3
|
||||
#define x_swap 6
|
||||
#define y_swap 4
|
||||
#define y_message 5
|
||||
#define x_header 0
|
||||
#define y_header 6
|
||||
#define x_idlecursor 0
|
||||
#define y_idlecursor 5
|
||||
#define y_procs 7
|
||||
extern int x_lastpid; /* 10 */
|
||||
extern int y_lastpid; /* 0 */
|
||||
extern int x_loadave; /* 33 */
|
||||
extern int x_loadave_nompid; /* 15 */
|
||||
extern int y_loadave; /* 0 */
|
||||
extern int x_procstate; /* 0 */
|
||||
extern int y_procstate; /* 1 */
|
||||
extern int x_brkdn; /* 15 */
|
||||
extern int y_brkdn; /* 1 */
|
||||
extern int x_mem; /* 5 */
|
||||
extern int y_mem; /* 3 */
|
||||
extern int x_swap; /* 6 */
|
||||
extern int y_swap; /* 4 */
|
||||
extern int y_message; /* 5 */
|
||||
extern int x_header; /* 0 */
|
||||
extern int y_header; /* 6 */
|
||||
extern int x_idlecursor; /* 0 */
|
||||
extern int y_idlecursor; /* 5 */
|
||||
extern int y_procs; /* 7 */
|
||||
|
||||
#define y_cpustates 2
|
||||
extern int y_cpustates; /* 2 */
|
||||
|
@ -20,6 +20,7 @@ struct statics
|
||||
#ifdef ORDER
|
||||
char **order_names;
|
||||
#endif
|
||||
int ncpus;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -43,6 +44,8 @@ struct system_info
|
||||
int *memory;
|
||||
int *swap;
|
||||
struct timeval boottime;
|
||||
unsigned long cpumask; /* bitfield of cpu states represented */
|
||||
int ncpus;
|
||||
};
|
||||
|
||||
/* cpu_states is an array of percentages * 10. For example,
|
||||
|
@ -1,3 +1,5 @@
|
||||
|
||||
|
||||
char *copyright =
|
||||
"Copyright (c) 1984 through 1996, William LeFebvre";
|
||||
|
||||
@ -65,6 +67,8 @@ extern char *optarg;
|
||||
/* imported from screen.c */
|
||||
extern int overstrike;
|
||||
|
||||
int pcpu_stats = No;
|
||||
|
||||
/* signal handling routines */
|
||||
sigret_t leave();
|
||||
sigret_t onalrm();
|
||||
@ -279,7 +283,7 @@ char *argv[];
|
||||
optind = 1;
|
||||
}
|
||||
|
||||
while ((i = getopt(ac, av, "CSIHbijnquvs:d:U:m:o:t")) != EOF)
|
||||
while ((i = getopt(ac, av, "CSIHPbijnpquvs:d:U:m:o:t")) != EOF)
|
||||
{
|
||||
switch(i)
|
||||
{
|
||||
@ -400,6 +404,14 @@ char *argv[];
|
||||
ps.jail = !ps.jail;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
pcpu_stats = Yes;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
pcpu_stats = No;
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"Top version %s\n"
|
||||
|
@ -11,7 +11,7 @@
|
||||
#define VERSION 3
|
||||
|
||||
/* Number of lines of header information on the standard screen */
|
||||
#define Header_lines 7
|
||||
extern int Header_lines; /* 7 */
|
||||
|
||||
/* Maximum number of columns allowed for display */
|
||||
#define MAX_COLS 128
|
||||
@ -40,3 +40,5 @@ char *version_string();
|
||||
enum displaymodes { DISP_CPU = 0, DISP_IO, DISP_MAX };
|
||||
|
||||
extern enum displaymodes displaymode;
|
||||
|
||||
extern int pcpu_stats;
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "machine.h"
|
||||
#include "screen.h"
|
||||
#include "utils.h"
|
||||
#include "layout.h"
|
||||
|
||||
static void getsysctl(char *, void *, size_t);
|
||||
|
||||
@ -65,6 +66,17 @@ enum displaymodes displaymode;
|
||||
static int namelength = 8;
|
||||
static int cmdlengthdelta;
|
||||
|
||||
/* Per-cpu time states */
|
||||
static int maxcpu;
|
||||
static int maxid;
|
||||
static int ncpus;
|
||||
static u_long cpumask;
|
||||
static long *times;
|
||||
static long *pcpu_cp_time;
|
||||
static long *pcpu_cp_old;
|
||||
static long *pcpu_cp_diff;
|
||||
static int *pcpu_cpu_states;
|
||||
|
||||
/* Prototypes for top internals */
|
||||
void quit(int);
|
||||
int compare_jid(const void *a, const void *b);
|
||||
@ -279,6 +291,56 @@ machine_init(struct statics *statics)
|
||||
statics->order_names = ordernames;
|
||||
#endif
|
||||
|
||||
/* Adjust display based on ncpus */
|
||||
if (pcpu_stats) {
|
||||
int i, j, empty;
|
||||
size_t size;
|
||||
|
||||
cpumask = 0;
|
||||
ncpus = 0;
|
||||
GETSYSCTL("kern.smp.maxcpus", maxcpu);
|
||||
size = sizeof(long) * maxcpu * CPUSTATES;
|
||||
times = malloc(size);
|
||||
if (times == NULL)
|
||||
err(1, "malloc %zd bytes", size);
|
||||
if (sysctlbyname("kern.cp_times", times, &size, NULL, 0) == -1)
|
||||
err(1, "sysctlbyname kern.cp_times");
|
||||
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) {
|
||||
cpumask |= (1ul << i);
|
||||
ncpus++;
|
||||
}
|
||||
}
|
||||
|
||||
if (ncpus > 1) {
|
||||
y_mem += ncpus - 1; /* 3 */
|
||||
y_swap += ncpus - 1; /* 4 */
|
||||
y_idlecursor += ncpus - 1; /* 5 */
|
||||
y_message += ncpus - 1; /* 5 */
|
||||
y_header += ncpus - 1; /* 6 */
|
||||
y_procs += ncpus - 1; /* 7 */
|
||||
Header_lines += ncpus - 1; /* 7 */
|
||||
}
|
||||
size = sizeof(long) * ncpus * CPUSTATES;
|
||||
pcpu_cp_time = malloc(size);
|
||||
pcpu_cp_old = malloc(size);
|
||||
pcpu_cp_diff = malloc(size);
|
||||
pcpu_cpu_states = malloc(size);
|
||||
bzero(pcpu_cp_time, size);
|
||||
bzero(pcpu_cp_old, size);
|
||||
bzero(pcpu_cp_diff, size);
|
||||
bzero(pcpu_cpu_states, size);
|
||||
statics->ncpus = ncpus;
|
||||
} else {
|
||||
statics->ncpus = 1;
|
||||
}
|
||||
|
||||
/* all done! */
|
||||
return (0);
|
||||
}
|
||||
@ -320,6 +382,7 @@ static int swappgsin = -1;
|
||||
static int swappgsout = -1;
|
||||
extern struct timeval timeout;
|
||||
|
||||
|
||||
void
|
||||
get_system_info(struct system_info *si)
|
||||
{
|
||||
@ -328,10 +391,17 @@ get_system_info(struct system_info *si)
|
||||
int mib[2];
|
||||
struct timeval boottime;
|
||||
size_t bt_size;
|
||||
int i;
|
||||
int i, j;
|
||||
size_t size;
|
||||
|
||||
/* get the cp_time array */
|
||||
GETSYSCTL("kern.cp_time", cp_time);
|
||||
if (pcpu_stats) {
|
||||
size = (maxid + 1) * CPUSTATES * sizeof(long);
|
||||
if (sysctlbyname("kern.cp_times", pcpu_cp_time, &size, NULL, 0) == -1)
|
||||
err(1, "sysctlbyname kern.cp_times");
|
||||
} else {
|
||||
GETSYSCTL("kern.cp_time", cp_time);
|
||||
}
|
||||
GETSYSCTL("vm.loadavg", sysload);
|
||||
GETSYSCTL("kern.lastpid", lastpid);
|
||||
|
||||
@ -339,8 +409,20 @@ get_system_info(struct system_info *si)
|
||||
for (i = 0; i < 3; i++)
|
||||
si->load_avg[i] = (double)sysload.ldavg[i] / sysload.fscale;
|
||||
|
||||
/* convert cp_time counts to percentages */
|
||||
total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
|
||||
if (pcpu_stats) {
|
||||
for (i = j = 0; i <= maxid; i++, j++) {
|
||||
if (cpumask && (1ul << i) == 0)
|
||||
continue;
|
||||
/* convert cp_time counts to percentages */
|
||||
percentages(CPUSTATES, &pcpu_cpu_states[j * CPUSTATES],
|
||||
&pcpu_cp_time[j * CPUSTATES],
|
||||
&pcpu_cp_old[j * CPUSTATES],
|
||||
&pcpu_cp_diff[j * CPUSTATES]);
|
||||
}
|
||||
} else {
|
||||
/* convert cp_time counts to percentages */
|
||||
percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
|
||||
}
|
||||
|
||||
/* sum memory & swap statistics */
|
||||
{
|
||||
@ -394,7 +476,15 @@ get_system_info(struct system_info *si)
|
||||
}
|
||||
|
||||
/* set arrays and strings */
|
||||
si->cpustates = cpu_states;
|
||||
if (pcpu_stats) {
|
||||
si->cpustates = pcpu_cpu_states;
|
||||
si->cpumask = cpumask;
|
||||
si->ncpus = ncpus;
|
||||
} else {
|
||||
si->cpustates = cpu_states;
|
||||
si->cpumask = 1;
|
||||
si->ncpus = 1;
|
||||
}
|
||||
si->memory = memory_stats;
|
||||
si->swap = swap_stats;
|
||||
|
||||
|
@ -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>
|
||||
|
@ -41,7 +41,7 @@
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.\" .Op Fl fimst
|
||||
.Op Fl afimsz
|
||||
.Op Fl afHhimPsz
|
||||
.Op Fl c Ar count
|
||||
.Op Fl M Ar core Op Fl N Ar system
|
||||
.Op Fl w Ar wait
|
||||
@ -94,6 +94,12 @@ and
|
||||
.Xr rfork 2
|
||||
system calls since system startup, and the number of pages of virtual memory
|
||||
involved in each.
|
||||
.It Fl h
|
||||
Changes memory columns into more easily human readable form. Default if
|
||||
standard output is a terminal device.
|
||||
.It Fl H
|
||||
Changes memory columns into straight numbers. Default if standard output
|
||||
is not a terminal device (such as a script).
|
||||
.It Fl i
|
||||
Report on the number of interrupts taken by each device since system
|
||||
startup.
|
||||
@ -113,6 +119,8 @@ Report on the usage of kernel dynamic memory listed first by size of
|
||||
allocation and then by type of usage.
|
||||
.It Fl n
|
||||
Change the maximum number of disks to display from the default of 2.
|
||||
.It Fl P
|
||||
Report per-cpu system/user/idle cpu statistics.
|
||||
.It Fl p
|
||||
Specify which types of devices to display.
|
||||
There are three different
|
||||
|
@ -76,6 +76,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sysexits.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <libutil.h>
|
||||
|
||||
static char da[] = "da";
|
||||
|
||||
@ -137,6 +138,8 @@ static struct vmmeter sum, osum;
|
||||
static int winlines = 20;
|
||||
static int aflag;
|
||||
static int nflag;
|
||||
static int Pflag;
|
||||
static int hflag;
|
||||
|
||||
static kvm_t *kd;
|
||||
|
||||
@ -149,6 +152,7 @@ static kvm_t *kd;
|
||||
#define ZMEMSTAT 0x40
|
||||
|
||||
static void cpustats(void);
|
||||
static void pcpustats(int, u_long, int);
|
||||
static void devstats(void);
|
||||
static void doforkst(void);
|
||||
static void dointr(void);
|
||||
@ -160,7 +164,7 @@ static void kread(int, void *, size_t);
|
||||
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 @@ main(int argc, char *argv[])
|
||||
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:fhHiM:mN:n:Pp:stw:z")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
aflag++;
|
||||
@ -188,9 +193,18 @@ main(int argc, char *argv[])
|
||||
case 'c':
|
||||
reps = atoi(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
Pflag++;
|
||||
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 @@ main(int argc, char *argv[])
|
||||
warnx("kvm_nlist: %s", kvm_geterr(kd));
|
||||
exit(1);
|
||||
}
|
||||
if (kd && Pflag)
|
||||
errx(1, "Cannot use -P with crash dumps");
|
||||
|
||||
if (todo & VMSTAT) {
|
||||
struct winsize winsize;
|
||||
@ -498,8 +514,71 @@ fill_vmtotal(struct vmtotal *vmtp)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
@ -507,6 +586,8 @@ dovmstat(unsigned int interval, int reps)
|
||||
time_t uptime, halfuptime;
|
||||
struct devinfo *tmp_dinfo;
|
||||
size_t size;
|
||||
int ncpus, maxid;
|
||||
u_long cpumask;
|
||||
|
||||
uptime = getuptime();
|
||||
halfuptime = uptime / 2;
|
||||
@ -528,9 +609,17 @@ dovmstat(unsigned int interval, int reps)
|
||||
hz = clockrate.hz;
|
||||
}
|
||||
|
||||
if (Pflag) {
|
||||
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 {
|
||||
@ -539,6 +628,12 @@ dovmstat(unsigned int interval, int reps)
|
||||
if (size != sizeof(cur.cp_time))
|
||||
errx(1, "cp_time size mismatch");
|
||||
}
|
||||
if (Pflag) {
|
||||
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;
|
||||
@ -574,7 +669,7 @@ dovmstat(unsigned int interval, int reps)
|
||||
errx(1, "%s", devstat_errbuf);
|
||||
break;
|
||||
case 1:
|
||||
printhdr();
|
||||
printhdr(ncpus, cpumask);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -590,8 +685,16 @@ dovmstat(unsigned int interval, int reps)
|
||||
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("%4lu ",
|
||||
(unsigned long)rate(sum.v_vm_faults - osum.v_vm_faults));
|
||||
(void)printf("%3lu ",
|
||||
@ -607,11 +710,14 @@ dovmstat(unsigned int interval, int reps)
|
||||
(void)printf("%3lu ",
|
||||
(unsigned long)rate(sum.v_pdpages - osum.v_pdpages));
|
||||
devstats();
|
||||
(void)printf("%4lu %4lu %3lu ",
|
||||
(void)printf("%4lu %4lu %3lu",
|
||||
(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 (Pflag)
|
||||
pcpustats(ncpus, cpumask, maxid);
|
||||
else
|
||||
cpustats();
|
||||
(void)printf("\n");
|
||||
(void)fflush(stdout);
|
||||
if (reps >= 0 && --reps <= 0)
|
||||
@ -631,7 +737,7 @@ dovmstat(unsigned int interval, int reps)
|
||||
}
|
||||
|
||||
static void
|
||||
printhdr(void)
|
||||
printhdr(int ncpus, u_long cpumask)
|
||||
{
|
||||
int i, num_shown;
|
||||
|
||||
@ -641,7 +747,15 @@ printhdr(void)
|
||||
(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 (Pflag) {
|
||||
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)
|
||||
@ -649,7 +763,13 @@ printhdr(void)
|
||||
(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 (Pflag) {
|
||||
for (i = 0; i < ncpus; i++)
|
||||
printf(" us sy id");
|
||||
printf("\n");
|
||||
} else
|
||||
printf(" us sy id\n");
|
||||
hdrcnt = winlines - 2;
|
||||
}
|
||||
|
||||
@ -818,10 +938,26 @@ devstats(void)
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@ -831,11 +967,54 @@ cpustats(void)
|
||||
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
|
||||
pcpustats(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
|
||||
|
Loading…
x
Reference in New Issue
Block a user