Bring in some iostat fixes that bde reminded me about. These fixes were
originally written in January, 2000, but have been substantially updated. - No longer use hz/stathz and the CPU times in computing the TTY stats, but rather use etime, like the disk stats. - Clean up malloc/realloc failure tests. - Use a new integrated routine to fetch devstat information via sysctl or KVM. - Get rid of the X() macro for calculating CPU stats - Use rint() on the CPU state display to avoid truncation errors. (this requires libm) - Clean up flag usage somewhat. Reviewed by: bde
This commit is contained in:
parent
499147571e
commit
5dc445bf4a
@ -4,9 +4,8 @@
|
||||
MAINTAINER= ken@FreeBSD.ORG
|
||||
|
||||
PROG= iostat
|
||||
DPADD= ${LIBKVM} ${LIBDEVSTAT} ${LIBM}
|
||||
LDADD= -lkvm -ldevstat -lm
|
||||
MAN= iostat.8
|
||||
|
||||
DPADD= ${LIBKVM} ${LIBDEVSTAT}
|
||||
LDADD= -lkvm -ldevstat
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 1998 Kenneth D. Merry.
|
||||
* Copyright (c) 1997, 1998, 2000, 2001 Kenneth D. Merry
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -115,6 +115,7 @@
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <devstat.h>
|
||||
#include <math.h>
|
||||
|
||||
struct nlist namelist[] = {
|
||||
#define X_TK_NIN 0
|
||||
@ -123,11 +124,9 @@ struct nlist namelist[] = {
|
||||
{ "_tk_nout" },
|
||||
#define X_CP_TIME 2
|
||||
{ "_cp_time" },
|
||||
#define X_HZ 3
|
||||
{ "_hz" },
|
||||
#define X_STATHZ 4
|
||||
{ "_stathz" },
|
||||
#define X_END 4
|
||||
#define X_BOOTTIME 3
|
||||
{ "_boottime" },
|
||||
#define X_END 3
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
@ -137,15 +136,13 @@ struct device_selection *dev_select;
|
||||
int maxshowdevs;
|
||||
int dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0;
|
||||
|
||||
#define nlread(x, v) \
|
||||
kvm_read(kd, namelist[x].n_value, &(v), sizeof(v))
|
||||
|
||||
/* local function declarations */
|
||||
static void usage(void);
|
||||
static void phdr(int signo);
|
||||
static void devstats(int perf_select,double etime, int havelast);
|
||||
static void devstats(int perf_select, long double etime, int havelast);
|
||||
static void cpustats(void);
|
||||
static void getsysctl(const char *, void *, size_t);
|
||||
static int readvar(kvm_t *kd, const char *name, int nlid, void *ptr,
|
||||
size_t len);
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
@ -173,7 +170,6 @@ main(int argc, char **argv)
|
||||
int num_matches = 0;
|
||||
char errbuf[_POSIX2_LINE_MAX];
|
||||
kvm_t *kd = NULL;
|
||||
int hz, stathz;
|
||||
int headercount;
|
||||
long generation;
|
||||
int num_devices_specified;
|
||||
@ -181,8 +177,7 @@ main(int argc, char **argv)
|
||||
long select_generation;
|
||||
char **specified_devices;
|
||||
devstat_select_mode select_mode;
|
||||
int use_kvm, havelast = 0;
|
||||
struct clockinfo clkinfo;
|
||||
int havelast = 0;
|
||||
|
||||
matches = NULL;
|
||||
maxshowdevs = 3;
|
||||
@ -251,24 +246,14 @@ main(int argc, char **argv)
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (nlistf == NULL && memf == NULL) {
|
||||
use_kvm = 0;
|
||||
getsysctl("kern.clockrate", &clkinfo, sizeof(clkinfo));
|
||||
hz = clkinfo.hz;
|
||||
} else {
|
||||
use_kvm = 1;
|
||||
if (nlistf != NULL || memf != NULL) {
|
||||
kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
|
||||
|
||||
if (kd == 0)
|
||||
if (kd == NULL)
|
||||
errx(1, "kvm_openfiles: %s", errbuf);
|
||||
|
||||
if (kvm_nlist(kd, namelist) == -1)
|
||||
errx(1, "kvm_nlist: %s", kvm_geterr(kd));
|
||||
|
||||
(void)nlread(X_HZ, hz);
|
||||
(void)nlread(X_STATHZ, stathz);
|
||||
if (stathz)
|
||||
hz = stathz;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -279,6 +264,15 @@ main(int argc, char **argv)
|
||||
if (devstat_checkversion(kd) < 0)
|
||||
errx(1, "%s", devstat_errbuf);
|
||||
|
||||
/*
|
||||
* Make sure Tflag and/or Cflag are set if dflag == 0. If dflag is
|
||||
* greater than 0, they may be 0 or non-zero.
|
||||
*/
|
||||
if (dflag == 0) {
|
||||
Cflag = 1;
|
||||
Tflag = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Figure out how many devices we should display.
|
||||
*/
|
||||
@ -302,12 +296,14 @@ main(int argc, char **argv)
|
||||
if ((num_devices = devstat_getnumdevs(kd)) < 0)
|
||||
err(1, "can't get number of devices");
|
||||
|
||||
if ((cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo))) ==
|
||||
NULL)
|
||||
err(1, "devinfo malloc failed");
|
||||
if ((last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo))) ==
|
||||
NULL)
|
||||
err(1, "devinfo malloc failed");
|
||||
cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
|
||||
if (cur.dinfo == NULL)
|
||||
err(1, "malloc failed");
|
||||
|
||||
last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
|
||||
if (last.dinfo == NULL)
|
||||
err(1, "malloc failed");
|
||||
|
||||
bzero(cur.dinfo, sizeof(struct devinfo));
|
||||
bzero(last.dinfo, sizeof(struct devinfo));
|
||||
|
||||
@ -326,8 +322,10 @@ main(int argc, char **argv)
|
||||
* If the user specified any devices on the command line, see if
|
||||
* they are in the list of devices we have now.
|
||||
*/
|
||||
if ((specified_devices = (char **)malloc(sizeof(char *))) == NULL)
|
||||
err(1, "specified_devices malloc failed");
|
||||
specified_devices = (char **)malloc(sizeof(char *));
|
||||
if (specified_devices == NULL)
|
||||
err(1, "malloc failed");
|
||||
|
||||
for (num_devices_specified = 0; *argv; ++argv) {
|
||||
if (isdigit(**argv))
|
||||
break;
|
||||
@ -335,6 +333,9 @@ main(int argc, char **argv)
|
||||
specified_devices = (char **)realloc(specified_devices,
|
||||
sizeof(char *) *
|
||||
num_devices_specified);
|
||||
if (specified_devices == NULL)
|
||||
err(1, "realloc failed");
|
||||
|
||||
specified_devices[num_devices_specified - 1] = *argv;
|
||||
|
||||
}
|
||||
@ -399,6 +400,18 @@ main(int argc, char **argv)
|
||||
if ((wflag > 0) && (cflag == 0))
|
||||
count = -1;
|
||||
|
||||
bzero(&cur.cp_time, sizeof(cur.cp_time));
|
||||
cur.tk_nout = 0;
|
||||
cur.tk_nin = 0;
|
||||
|
||||
/*
|
||||
* Set the busy time to the system boot time, so the stats are
|
||||
* calculated since system boot.
|
||||
*/
|
||||
if (readvar(kd, "kern.boottime", X_BOOTTIME, &cur.busy_time,
|
||||
sizeof(cur.busy_time)) != 0)
|
||||
exit(1);
|
||||
|
||||
/*
|
||||
* If the user stops the program (control-Z) and then resumes it,
|
||||
* print out the header again.
|
||||
@ -408,27 +421,30 @@ main(int argc, char **argv)
|
||||
for (headercount = 1;;) {
|
||||
struct devinfo *tmp_dinfo;
|
||||
long tmp;
|
||||
double etime;
|
||||
long double etime;
|
||||
|
||||
if (Tflag > 0) {
|
||||
if ((readvar(kd, "kern.tty_nin", X_TK_NIN, &cur.tk_nin,
|
||||
sizeof(cur.tk_nin)) != 0)
|
||||
|| (readvar(kd, "kern.tty_nout", X_TK_NOUT,
|
||||
&cur.tk_nout, sizeof(cur.tk_nout))!= 0)) {
|
||||
Tflag = 0;
|
||||
warnx("disabling TTY statistics");
|
||||
}
|
||||
}
|
||||
|
||||
if (Cflag > 0) {
|
||||
if (readvar(kd, "kern.cp_time", X_CP_TIME,
|
||||
&cur.cp_time, sizeof(cur.cp_time)) != 0) {
|
||||
Cflag = 0;
|
||||
warnx("disabling CPU time statistics");
|
||||
}
|
||||
}
|
||||
|
||||
if (!--headercount) {
|
||||
phdr(0);
|
||||
headercount = 20;
|
||||
}
|
||||
if (use_kvm) {
|
||||
(void)kvm_read(kd, namelist[X_TK_NIN].n_value,
|
||||
&cur.tk_nin, sizeof(cur.tk_nin));
|
||||
(void)kvm_read(kd, namelist[X_TK_NOUT].n_value,
|
||||
&cur.tk_nout, sizeof(cur.tk_nout));
|
||||
(void)kvm_read(kd, namelist[X_CP_TIME].n_value,
|
||||
cur.cp_time, sizeof(cur.cp_time));
|
||||
} else {
|
||||
getsysctl("kern.tty_nin", &cur.tk_nin,
|
||||
sizeof(cur.tk_nin));
|
||||
getsysctl("kern.tty_nout", &cur.tk_nout,
|
||||
sizeof(cur.tk_nout));
|
||||
getsysctl("kern.cp_time", &cur.cp_time,
|
||||
sizeof(cur.cp_time));
|
||||
}
|
||||
|
||||
tmp_dinfo = last.dinfo;
|
||||
last.dinfo = cur.dinfo;
|
||||
@ -511,30 +527,35 @@ main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
tmp = cur.tk_nin;
|
||||
cur.tk_nin -= last.tk_nin;
|
||||
last.tk_nin = tmp;
|
||||
tmp = cur.tk_nout;
|
||||
cur.tk_nout -= last.tk_nout;
|
||||
last.tk_nout = tmp;
|
||||
|
||||
etime = 0.0;
|
||||
|
||||
#define X(fld) tmp = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = tmp
|
||||
|
||||
for (i = 0; i < CPUSTATES; i++) {
|
||||
X(cp_time);
|
||||
etime += cur.cp_time[i];
|
||||
if (Tflag > 0) {
|
||||
tmp = cur.tk_nin;
|
||||
cur.tk_nin -= last.tk_nin;
|
||||
last.tk_nin = tmp;
|
||||
tmp = cur.tk_nout;
|
||||
cur.tk_nout -= last.tk_nout;
|
||||
last.tk_nout = tmp;
|
||||
}
|
||||
etime /= (float)hz;
|
||||
|
||||
etime = devstat_compute_etime(cur.busy_time, last.busy_time);
|
||||
|
||||
if (etime == 0.0)
|
||||
etime = 1.0;
|
||||
if ((dflag == 0) || (Tflag > 0))
|
||||
printf("%4.0f%5.0f", cur.tk_nin / etime,
|
||||
|
||||
for (i = 0; i < CPUSTATES; i++) {
|
||||
tmp = cur.cp_time[i];
|
||||
cur.cp_time[i] -= last.cp_time[i];
|
||||
last.cp_time[i] = tmp;
|
||||
}
|
||||
|
||||
if (Tflag > 0)
|
||||
printf("%4.0Lf%5.0Lf", cur.tk_nin / etime,
|
||||
cur.tk_nout/etime);
|
||||
|
||||
devstats(hflag, etime, havelast);
|
||||
if ((dflag == 0) || (Cflag > 0))
|
||||
|
||||
if (Cflag > 0)
|
||||
cpustats();
|
||||
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
|
||||
@ -554,7 +575,7 @@ phdr(int signo)
|
||||
register int i;
|
||||
int printed;
|
||||
|
||||
if ((dflag == 0) || (Tflag > 0))
|
||||
if (Tflag > 0)
|
||||
(void)printf(" tty");
|
||||
for (i = 0, printed=0;(i < num_devices) && (printed < maxshowdevs);i++){
|
||||
int di;
|
||||
@ -572,12 +593,12 @@ phdr(int signo)
|
||||
printed++;
|
||||
}
|
||||
}
|
||||
if ((dflag == 0) || (Cflag > 0))
|
||||
if (Cflag > 0)
|
||||
(void)printf(" cpu\n");
|
||||
else
|
||||
(void)printf("\n");
|
||||
|
||||
if ((dflag == 0) || (Tflag > 0))
|
||||
if (Tflag > 0)
|
||||
(void)printf(" tin tout");
|
||||
|
||||
for (i=0, printed = 0;(i < num_devices) && (printed < maxshowdevs);i++){
|
||||
@ -597,7 +618,7 @@ phdr(int signo)
|
||||
printed++;
|
||||
}
|
||||
}
|
||||
if ((dflag == 0) || (Cflag > 0))
|
||||
if (Cflag > 0)
|
||||
(void)printf(" us ni sy in id\n");
|
||||
else
|
||||
printf("\n");
|
||||
@ -605,26 +626,15 @@ phdr(int signo)
|
||||
}
|
||||
|
||||
static void
|
||||
devstats(int perf_select, double etime, int havelast)
|
||||
devstats(int perf_select, long double etime, int havelast)
|
||||
{
|
||||
register int dn;
|
||||
long double transfers_per_second;
|
||||
long double kb_per_transfer, mb_per_second;
|
||||
u_int64_t total_bytes, total_transfers, total_blocks;
|
||||
long double busy_seconds;
|
||||
long double total_mb;
|
||||
long double blocks_per_second, ms_per_transaction;
|
||||
|
||||
/*
|
||||
* Calculate elapsed time up front, since it's the same for all
|
||||
* devices.
|
||||
*/
|
||||
if (havelast)
|
||||
busy_seconds = devstat_compute_etime(cur.busy_time,
|
||||
last.busy_time);
|
||||
else
|
||||
busy_seconds = etime;
|
||||
|
||||
for (dn = 0; dn < num_devices; dn++) {
|
||||
int di;
|
||||
|
||||
@ -635,7 +645,7 @@ devstats(int perf_select, double etime, int havelast)
|
||||
di = dev_select[dn].position;
|
||||
|
||||
if (devstat_compute_statistics(&cur.dinfo->devices[di],
|
||||
havelast ? &last.dinfo->devices[di] : NULL, busy_seconds,
|
||||
havelast ? &last.dinfo->devices[di] : NULL, etime,
|
||||
DSM_TOTAL_BYTES, &total_bytes,
|
||||
DSM_TOTAL_TRANSFERS, &total_transfers,
|
||||
DSM_TOTAL_BLOCKS, &total_blocks,
|
||||
@ -706,17 +716,38 @@ cpustats(void)
|
||||
time += cur.cp_time[state];
|
||||
for (state = 0; state < CPUSTATES; ++state)
|
||||
printf("%3.0f",
|
||||
100. * cur.cp_time[state] / (time ? time : 1));
|
||||
rint(100. * cur.cp_time[state] / (time ? time : 1)));
|
||||
}
|
||||
|
||||
static void
|
||||
getsysctl(const char *name, void *ptr, size_t len)
|
||||
static int
|
||||
readvar(kvm_t *kd, const char *name, int nlid, void *ptr, size_t len)
|
||||
{
|
||||
size_t nlen = len;
|
||||
if (kd != NULL) {
|
||||
ssize_t nbytes;
|
||||
|
||||
nbytes = kvm_read(kd, nlid, ptr, len);
|
||||
|
||||
if (nbytes == 0) {
|
||||
warnx("kvm_read(%s): %s", name, kvm_geterr(kd));
|
||||
return (1);
|
||||
}
|
||||
if (nbytes != len) {
|
||||
warnx("kvm_read(%s): expected %lu bytes, got %ld bytes",
|
||||
name, (unsigned long)len, (long)nbytes);
|
||||
return (1);
|
||||
}
|
||||
} else {
|
||||
size_t nlen = len;
|
||||
|
||||
if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)
|
||||
err(1, "sysctl(%s...) failed", name);
|
||||
if (nlen != len)
|
||||
errx(1, "sysctl(%s...): expected %lu, got %lu", name,
|
||||
(unsigned long)len, (unsigned long)nlen);
|
||||
if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
|
||||
warn("sysctl(%s...) failed", name);
|
||||
return (1);
|
||||
}
|
||||
if (nlen != len) {
|
||||
warnx("sysctl(%s...): expected %lu, got %lu", name,
|
||||
(unsigned long)len, (unsigned long)nlen);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user