Enhance disk metrics by calculating a weighted sum that is incremented
by the number of concurrent I/O requests. Also introduce a new disk_wait() function to measure requests waiting in a bufq. iostat -y now reports data about waiting and active requests. So far only drivers using dksubr and dk, ccd, wd and xbd collect data about waiting requests.
This commit is contained in:
parent
3ffd56c5a6
commit
ba576b71a7
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: disk.9,v 1.43 2017/01/23 11:42:03 abhinav Exp $
|
||||
.\" $NetBSD: disk.9,v 1.44 2017/03/05 23:07:12 mlelstv Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1995, 1996 Jason R. Thorpe.
|
||||
.\" All rights reserved.
|
||||
@ -40,6 +40,7 @@
|
||||
.Nm disk_begindetach ,
|
||||
.Nm disk_detach ,
|
||||
.Nm disk_destroy ,
|
||||
.Nm disk_wait ,
|
||||
.Nm disk_busy ,
|
||||
.Nm disk_unbusy ,
|
||||
.Nm disk_isbusy ,
|
||||
@ -61,6 +62,8 @@
|
||||
.Ft void
|
||||
.Fn disk_destroy "struct disk *"
|
||||
.Ft void
|
||||
.Fn disk_wait "struct disk *"
|
||||
.Ft void
|
||||
.Fn disk_busy "struct disk *"
|
||||
.Ft void
|
||||
.Fn disk_unbusy "struct disk *" "long bcount" "int read"
|
||||
@ -167,19 +170,25 @@ If the count drops below zero, panic.
|
||||
.It Fn disk_destroy
|
||||
Release resources used by the disk structure when it is no longer
|
||||
required.
|
||||
.It Fn disk_wait
|
||||
Disk timings are measured by counting the number of queued
|
||||
requests (wait counter) and requests issued to the hardware (busy counter)
|
||||
and keeping timestamp when the counters change. The time interval between
|
||||
two changes of a counter is accumulated into a total and also multiplied
|
||||
by the counter value and the accumulated into a sum. Both values can be
|
||||
used to determine how much time is spent in the driver queue or in-flight
|
||||
to the hardware as well as the average number of requests in either state.
|
||||
.Fn disk_wait
|
||||
increment the disk's wait counter and handles the accumulation.
|
||||
.It Fn disk_busy
|
||||
Increment the disk's
|
||||
.Dq busy counter .
|
||||
If this counter goes from 0 to 1, set the timestamp corresponding to
|
||||
this transfer.
|
||||
Decrements the disk's wait counter and increments the disk's
|
||||
.Dq busy counter ,
|
||||
and handles either accumulation. If the wait counter is still zero, it
|
||||
is assumed that the driver hasn't been updated to call
|
||||
.Fn disk_wait ,
|
||||
then only the values from the busy counter are available.
|
||||
.It Fn disk_unbusy
|
||||
Decrement a disk's busy counter.
|
||||
If the count drops below zero, panic.
|
||||
Get the current time, subtract it from the disk's timestamp, and add
|
||||
the difference to the disk's running total.
|
||||
Set the disk's timestamp to the current time.
|
||||
If the provided byte count is greater than 0, add it to the disk's
|
||||
running total and increment the number of transfers performed by the disk.
|
||||
Decrement the disk's busy counter and handles the accumulation.
|
||||
The third argument
|
||||
.Ar read
|
||||
specifies the direction of I/O;
|
||||
@ -212,6 +221,7 @@ The functions typically called by device drivers are
|
||||
.Fn disk_begindetach ,
|
||||
.Fn disk_detach ,
|
||||
.Fn disk_destroy ,
|
||||
.Fn disk_wait ,
|
||||
.Fn disk_busy ,
|
||||
.Fn disk_unbusy ,
|
||||
and
|
||||
@ -403,8 +413,9 @@ const struct dkdriver foodkdriver = {
|
||||
.Pp
|
||||
Once the disk is attached, metrics may be gathered on that disk.
|
||||
In order to gather metrics data, the driver must tell the framework when
|
||||
the disk starts and stops operations.
|
||||
the disk queues, starts and stops operations.
|
||||
This functionality is provided by the
|
||||
.Fn disk_wait ,
|
||||
.Fn disk_busy
|
||||
and
|
||||
.Fn disk_unbusy
|
||||
@ -413,6 +424,7 @@ Because
|
||||
.Nm struct disk
|
||||
is part of device driver private data it needs to be guarded.
|
||||
Mutual exclusion must be done by driver
|
||||
.Fn disk_wait ,
|
||||
.Fn disk_busy
|
||||
and
|
||||
.Fn disk_unbusy
|
||||
@ -423,8 +435,22 @@ routine should be called immediately before a command to the disk is
|
||||
sent, e.g.:
|
||||
.Bd -literal
|
||||
void
|
||||
foostart(sc)
|
||||
struct foo_softc *sc;
|
||||
foostrategy(struct buf *bp)
|
||||
{
|
||||
[ . . . ]
|
||||
|
||||
mutex_enter(\*[Am]sc-\*[Gt]sc_dk_mtx);
|
||||
disk_wait(\*[Am]sc-\*[Gt]sc_dk);
|
||||
|
||||
/* Put buffer onto drive's transfer queue */
|
||||
|
||||
mutex_exit(\*[Am]sc-\*[Gt]sc_dk_mtx);
|
||||
|
||||
foostart(sc);
|
||||
}
|
||||
|
||||
void
|
||||
foostart(struct foo_softc *sc)
|
||||
{
|
||||
[ . . . ]
|
||||
|
||||
@ -444,26 +470,15 @@ foostart(sc)
|
||||
}
|
||||
.Ed
|
||||
.Pp
|
||||
When
|
||||
.Fn disk_busy
|
||||
is called, a timestamp is taken if the disk's busy counter moves from
|
||||
0 to 1, indicating the disk has gone from an idle to non-idle state.
|
||||
At the end of a transaction, the
|
||||
The routine
|
||||
.Fn disk_unbusy
|
||||
routine should be called.
|
||||
This routine performs some consistency checks,
|
||||
such as ensuring that the calls to
|
||||
performs some consistency checks, such as ensuring that the calls to
|
||||
.Fn disk_busy
|
||||
and
|
||||
.Fn disk_unbusy
|
||||
are balanced.
|
||||
This routine also performs the actual metrics calculation.
|
||||
A timestamp is taken and the difference from the timestamp taken in
|
||||
.Fn disk_busy
|
||||
is added to the disk's total running time.
|
||||
The disk's timestamp is then updated in case there is more than one
|
||||
pending transfer on the disk.
|
||||
A byte count is also added to the disk's running total, and if greater than
|
||||
It also performs the final steps of the metrics calcuation.
|
||||
A byte count is added to the disk's running total, and if greater than
|
||||
zero, the number of transfers the disk has performed is incremented.
|
||||
The third argument
|
||||
.Ar read
|
||||
@ -506,6 +521,7 @@ foodone(xfer)
|
||||
is used to get status of disk device it returns true if device is
|
||||
currently busy and false if it is not.
|
||||
Like
|
||||
.Fn disk_wait ,
|
||||
.Fn disk_busy
|
||||
and
|
||||
.Fn disk_unbusy
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: xbd_xenbus.c,v 1.75 2015/10/25 07:51:16 maxv Exp $ */
|
||||
/* $NetBSD: xbd_xenbus.c,v 1.76 2017/03/05 23:07:12 mlelstv Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Manuel Bouyer.
|
||||
@ -50,7 +50,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: xbd_xenbus.c,v 1.75 2015/10/25 07:51:16 maxv Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: xbd_xenbus.c,v 1.76 2017/03/05 23:07:12 mlelstv Exp $");
|
||||
|
||||
#include "opt_xen.h"
|
||||
|
||||
@ -327,7 +327,7 @@ xbd_xenbus_detach(device_t dev, int flags)
|
||||
sc->sc_shutdown = BLKIF_SHUTDOWN_LOCAL;
|
||||
/* wait for requests to complete */
|
||||
while (sc->sc_backend_status == BLKIF_STATE_CONNECTED &&
|
||||
sc->sc_dksc.sc_dkdev.dk_stats->io_busy > 0)
|
||||
disk_isbusy(&sc->sc_dksc.sc_dkdev))
|
||||
tsleep(xbd_xenbus_detach, PRIBIO, "xbddetach", hz/2);
|
||||
|
||||
xenbus_switch_state(sc->sc_xbusd, NULL, XenbusStateClosing);
|
||||
@ -392,7 +392,7 @@ xbd_xenbus_suspend(device_t dev, const pmf_qual_t *qual) {
|
||||
s = splbio();
|
||||
/* wait for requests to complete, then suspend device */
|
||||
while (sc->sc_backend_status == BLKIF_STATE_CONNECTED &&
|
||||
sc->sc_dksc.sc_dkdev.dk_stats->io_busy > 0)
|
||||
disk_isbusy(&sc->sc_dksc.sc_dkdev))
|
||||
tsleep(xbd_xenbus_suspend, PRIBIO, "xbdsuspend", hz/2);
|
||||
|
||||
hypervisor_mask_event(sc->sc_evtchn);
|
||||
@ -530,7 +530,7 @@ static void xbd_backend_changed(void *arg, XenbusState new_state)
|
||||
sc->sc_shutdown = BLKIF_SHUTDOWN_REMOTE;
|
||||
/* wait for requests to complete */
|
||||
while (sc->sc_backend_status == BLKIF_STATE_CONNECTED &&
|
||||
sc->sc_dksc.sc_dkdev.dk_stats->io_busy > 0)
|
||||
disk_isbusy(&sc->sc_dksc.sc_dkdev))
|
||||
tsleep(xbd_xenbus_detach, PRIBIO, "xbddetach", hz/2);
|
||||
splx(s);
|
||||
xenbus_switch_state(sc->sc_xbusd, NULL, XenbusStateClosed);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: wd.c,v 1.427 2016/11/20 02:35:19 pgoyette Exp $ */
|
||||
/* $NetBSD: wd.c,v 1.428 2017/03/05 23:07:12 mlelstv Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
|
||||
@ -54,7 +54,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.427 2016/11/20 02:35:19 pgoyette Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428 2017/03/05 23:07:12 mlelstv Exp $");
|
||||
|
||||
#include "opt_ata.h"
|
||||
|
||||
@ -605,6 +605,7 @@ wdstrategy(struct buf *bp)
|
||||
|
||||
/* Queue transfer on drive, activate drive and controller if idle. */
|
||||
s = splbio();
|
||||
disk_wait(&wd->sc_dk);
|
||||
bufq_put(wd->sc_q, bp);
|
||||
wdstart(wd);
|
||||
splx(s);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ccd.c,v 1.168 2016/11/20 02:35:19 pgoyette Exp $ */
|
||||
/* $NetBSD: ccd.c,v 1.169 2017/03/05 23:07:12 mlelstv Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996, 1997, 1998, 1999, 2007, 2009 The NetBSD Foundation, Inc.
|
||||
@ -88,7 +88,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ccd.c,v 1.168 2016/11/20 02:35:19 pgoyette Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ccd.c,v 1.169 2017/03/05 23:07:12 mlelstv Exp $");
|
||||
|
||||
#if defined(_KERNEL_OPT)
|
||||
#include "opt_compat_netbsd.h"
|
||||
@ -815,10 +815,11 @@ ccdstart(struct ccd_softc *cs)
|
||||
|
||||
KASSERT(mutex_owned(cs->sc_iolock));
|
||||
|
||||
disk_busy(&cs->sc_dkdev);
|
||||
bp = bufq_get(cs->sc_bufq);
|
||||
KASSERT(bp != NULL);
|
||||
|
||||
disk_busy(&cs->sc_dkdev);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ccddebug & CCDB_FOLLOW)
|
||||
printf("ccdstart(%s, %p)\n", cs->sc_xname, bp);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: dksubr.c,v 1.95 2017/02/25 15:19:00 mlelstv Exp $ */
|
||||
/* $NetBSD: dksubr.c,v 1.96 2017/03/05 23:07:12 mlelstv Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996, 1997, 1998, 1999, 2002, 2008 The NetBSD Foundation, Inc.
|
||||
@ -30,7 +30,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: dksubr.c,v 1.95 2017/02/25 15:19:00 mlelstv Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: dksubr.c,v 1.96 2017/03/05 23:07:12 mlelstv Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -339,6 +339,7 @@ dk_strategy_defer(struct dk_softc *dksc, struct buf *bp)
|
||||
* Queue buffer only
|
||||
*/
|
||||
mutex_enter(&dksc->sc_iolock);
|
||||
disk_wait(&dksc->sc_dkdev);
|
||||
bufq_put(dksc->sc_bufq, bp);
|
||||
mutex_exit(&dksc->sc_iolock);
|
||||
|
||||
@ -375,8 +376,10 @@ dk_start(struct dk_softc *dksc, struct buf *bp)
|
||||
|
||||
mutex_enter(&dksc->sc_iolock);
|
||||
|
||||
if (bp != NULL)
|
||||
if (bp != NULL) {
|
||||
disk_wait(&dksc->sc_dkdev);
|
||||
bufq_put(dksc->sc_bufq, bp);
|
||||
}
|
||||
|
||||
/*
|
||||
* If another thread is running the queue, increment
|
||||
@ -417,6 +420,7 @@ dk_start(struct dk_softc *dksc, struct buf *bp)
|
||||
if (error == EAGAIN) {
|
||||
dksc->sc_deferred = bp;
|
||||
disk_unbusy(&dksc->sc_dkdev, 0, (bp->b_flags & B_READ));
|
||||
disk_wait(&dksc->sc_dkdev);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: dk.c,v 1.95 2017/02/27 21:27:07 jdolecek Exp $ */
|
||||
/* $NetBSD: dk.c,v 1.96 2017/03/05 23:07:12 mlelstv Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2004, 2005, 2006, 2007 The NetBSD Foundation, Inc.
|
||||
@ -30,7 +30,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.95 2017/02/27 21:27:07 jdolecek Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.96 2017/03/05 23:07:12 mlelstv Exp $");
|
||||
|
||||
#ifdef _KERNEL_OPT
|
||||
#include "opt_dkwedge.h"
|
||||
@ -1249,6 +1249,7 @@ dkstrategy(struct buf *bp)
|
||||
/* Place it in the queue and start I/O on the unit. */
|
||||
mutex_enter(&sc->sc_iolock);
|
||||
sc->sc_iopend++;
|
||||
disk_wait(&sc->sc_dk);
|
||||
bufq_put(sc->sc_bufq, bp);
|
||||
mutex_exit(&sc->sc_iolock);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: subr_disk.c,v 1.117 2017/02/28 00:33:36 jakllsch Exp $ */
|
||||
/* $NetBSD: subr_disk.c,v 1.118 2017/03/05 23:07:12 mlelstv Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996, 1997, 1999, 2000, 2009 The NetBSD Foundation, Inc.
|
||||
@ -67,7 +67,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: subr_disk.c,v 1.117 2017/02/28 00:33:36 jakllsch Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: subr_disk.c,v 1.118 2017/03/05 23:07:12 mlelstv Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -274,6 +274,16 @@ disk_destroy(struct disk *diskp)
|
||||
mutex_destroy(&diskp->dk_rawlock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the disk as having work queued for metrics collection.
|
||||
*/
|
||||
void
|
||||
disk_wait(struct disk *diskp)
|
||||
{
|
||||
|
||||
iostat_wait(diskp->dk_stats);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the disk as busy for metrics collection.
|
||||
*/
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: subr_iostat.c,v 1.21 2014/10/18 08:33:29 snj Exp $ */
|
||||
/* $NetBSD: subr_iostat.c,v 1.22 2017/03/05 23:07:12 mlelstv Exp $ */
|
||||
/* NetBSD: subr_disk.c,v 1.69 2005/05/29 22:24:15 christos Exp */
|
||||
|
||||
/*-
|
||||
@ -68,7 +68,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: subr_iostat.c,v 1.21 2014/10/18 08:33:29 snj Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: subr_iostat.c,v 1.22 2017/03/05 23:07:12 mlelstv Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -183,37 +183,106 @@ iostat_free(struct io_stats *stats)
|
||||
}
|
||||
|
||||
/*
|
||||
* Increment a iostat busy counter. If the counter is going from
|
||||
* 0 to 1, set the timestamp.
|
||||
* multiply timeval by unsigned integer and add to result
|
||||
*/
|
||||
static void
|
||||
timermac(struct timeval *a, uint64_t count, struct timeval *res)
|
||||
{
|
||||
struct timeval part = *a;
|
||||
|
||||
while (count) {
|
||||
if (count & 1)
|
||||
timeradd(res, &part, res);
|
||||
timeradd(&part, &part, &part);
|
||||
count >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Increment the iostat wait counter.
|
||||
* Accumulate wait time and timesum.
|
||||
*
|
||||
* Wait time is spent in the device bufq.
|
||||
*/
|
||||
void
|
||||
iostat_wait(struct io_stats *stats)
|
||||
{
|
||||
struct timeval dv_time, diff_time;
|
||||
int32_t count;
|
||||
|
||||
KASSERT(stats->io_wait >= 0);
|
||||
|
||||
getmicrouptime(&dv_time);
|
||||
|
||||
timersub(&dv_time, &stats->io_waitstamp, &diff_time);
|
||||
count = stats->io_wait++;
|
||||
if (count != 0) {
|
||||
timermac(&diff_time, count, &stats->io_waitsum);
|
||||
timeradd(&stats->io_waittime, &diff_time, &stats->io_waittime);
|
||||
}
|
||||
stats->io_waitstamp = dv_time;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrement the iostat wait counter.
|
||||
* Increment the iostat busy counter.
|
||||
* Accumulate wait and busy times and timesums.
|
||||
*
|
||||
* Busy time is spent being processed by the device.
|
||||
*
|
||||
* Old devices do not yet measure wait time, so skip
|
||||
* processing it if the counter is still zero.
|
||||
*/
|
||||
void
|
||||
iostat_busy(struct io_stats *stats)
|
||||
{
|
||||
struct timeval dv_time, diff_time;
|
||||
int32_t count;
|
||||
|
||||
if (stats->io_busy++ == 0)
|
||||
getmicrouptime(&stats->io_timestamp);
|
||||
KASSERT(stats->io_wait >= 0); /* > 0 when iostat_wait is used */
|
||||
KASSERT(stats->io_busy >= 0);
|
||||
|
||||
getmicrouptime(&dv_time);
|
||||
|
||||
timersub(&dv_time, &stats->io_waitstamp, &diff_time);
|
||||
if (stats->io_wait != 0) {
|
||||
count = stats->io_wait--;
|
||||
timermac(&diff_time, count, &stats->io_waitsum);
|
||||
timeradd(&stats->io_waittime, &diff_time, &stats->io_waittime);
|
||||
}
|
||||
stats->io_waitstamp = dv_time;
|
||||
|
||||
timersub(&dv_time, &stats->io_busystamp, &diff_time);
|
||||
count = stats->io_busy++;
|
||||
if (count != 0) {
|
||||
timermac(&diff_time, count, &stats->io_busysum);
|
||||
timeradd(&stats->io_busytime, &diff_time, &stats->io_busytime);
|
||||
}
|
||||
stats->io_busystamp = dv_time;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrement a iostat busy counter, increment the byte count, total busy
|
||||
* time, and reset the timestamp.
|
||||
* Decrement the iostat busy counter, increment the byte count.
|
||||
* Accumulate busy time and timesum.
|
||||
*/
|
||||
void
|
||||
iostat_unbusy(struct io_stats *stats, long bcount, int read)
|
||||
{
|
||||
struct timeval dv_time, diff_time;
|
||||
int32_t count;
|
||||
|
||||
if (stats->io_busy-- == 0) {
|
||||
printf("%s: busy < 0\n", stats->io_name);
|
||||
panic("iostat_unbusy");
|
||||
}
|
||||
KASSERT(stats->io_busy > 0);
|
||||
|
||||
getmicrouptime(&dv_time);
|
||||
|
||||
timersub(&dv_time, &stats->io_timestamp, &diff_time);
|
||||
timeradd(&stats->io_time, &diff_time, &stats->io_time);
|
||||
|
||||
stats->io_timestamp = dv_time;
|
||||
|
||||
/* any op */
|
||||
timersub(&dv_time, &stats->io_busystamp, &diff_time);
|
||||
count = stats->io_busy--;
|
||||
timermac(&diff_time, count, &stats->io_busysum);
|
||||
timeradd(&stats->io_busytime, &diff_time, &stats->io_busytime);
|
||||
stats->io_busystamp = dv_time;
|
||||
|
||||
if (bcount > 0) {
|
||||
if (read) {
|
||||
stats->io_rbytes += bcount;
|
||||
@ -352,20 +421,38 @@ sysctl_hw_iostats(SYSCTLFN_ARGS)
|
||||
TAILQ_FOREACH(stats, &iostatlist, io_link) {
|
||||
if (left < tocopy)
|
||||
break;
|
||||
|
||||
strncpy(sdrive.name, stats->io_name, sizeof(sdrive.name));
|
||||
sdrive.xfer = stats->io_rxfer + stats->io_wxfer;
|
||||
sdrive.rxfer = stats->io_rxfer;
|
||||
sdrive.wxfer = stats->io_wxfer;
|
||||
sdrive.seek = stats->io_seek;
|
||||
sdrive.bytes = stats->io_rbytes + stats->io_wbytes;
|
||||
sdrive.rbytes = stats->io_rbytes;
|
||||
sdrive.wbytes = stats->io_wbytes;
|
||||
sdrive.attachtime_sec = stats->io_attachtime.tv_sec;
|
||||
sdrive.attachtime_usec = stats->io_attachtime.tv_usec;
|
||||
sdrive.timestamp_sec = stats->io_timestamp.tv_sec;
|
||||
sdrive.timestamp_usec = stats->io_timestamp.tv_usec;
|
||||
sdrive.time_sec = stats->io_time.tv_sec;
|
||||
sdrive.time_usec = stats->io_time.tv_usec;
|
||||
sdrive.timestamp_sec = stats->io_busystamp.tv_sec;
|
||||
sdrive.timestamp_usec = stats->io_busystamp.tv_usec;
|
||||
|
||||
sdrive.time_sec = stats->io_busytime.tv_sec;
|
||||
sdrive.time_usec = stats->io_busytime.tv_usec;
|
||||
|
||||
sdrive.seek = stats->io_seek;
|
||||
|
||||
sdrive.rxfer = stats->io_rxfer;
|
||||
sdrive.wxfer = stats->io_wxfer;
|
||||
sdrive.xfer = stats->io_rxfer + stats->io_wxfer;
|
||||
|
||||
sdrive.rbytes = stats->io_rbytes;
|
||||
sdrive.wbytes = stats->io_wbytes;
|
||||
sdrive.bytes = stats->io_rbytes + stats->io_wbytes;
|
||||
|
||||
sdrive.wait_sec = stats->io_waittime.tv_sec;
|
||||
sdrive.wait_usec = stats->io_waittime.tv_usec;
|
||||
|
||||
sdrive.time_sec = stats->io_busytime.tv_sec;
|
||||
sdrive.time_usec = stats->io_busytime.tv_usec;
|
||||
|
||||
sdrive.waitsum_sec = stats->io_waitsum.tv_sec;
|
||||
sdrive.waitsum_usec = stats->io_waitsum.tv_usec;
|
||||
|
||||
sdrive.busysum_sec = stats->io_busysum.tv_sec;
|
||||
sdrive.busysum_usec = stats->io_busysum.tv_usec;
|
||||
|
||||
sdrive.busy = stats->io_busy;
|
||||
|
||||
error = copyout(&sdrive, where, min(tocopy, sizeof(sdrive)));
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: disk.h,v 1.69 2016/12/08 12:21:54 mlelstv Exp $ */
|
||||
/* $NetBSD: disk.h,v 1.70 2017/03/05 23:07:12 mlelstv Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996, 1997, 2004 The NetBSD Foundation, Inc.
|
||||
@ -534,6 +534,7 @@ int disk_begindetach(struct disk *, int (*)(device_t), device_t, int);
|
||||
void disk_detach(struct disk *);
|
||||
void disk_init(struct disk *, const char *, const struct dkdriver *);
|
||||
void disk_destroy(struct disk *);
|
||||
void disk_wait(struct disk *);
|
||||
void disk_busy(struct disk *);
|
||||
void disk_unbusy(struct disk *, long, int);
|
||||
bool disk_isbusy(struct disk *);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: iostat.h,v 1.10 2009/04/04 07:30:09 ad Exp $ */
|
||||
/* $NetBSD: iostat.h,v 1.11 2017/03/05 23:07:12 mlelstv Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996, 1997, 2004, 2009 The NetBSD Foundation, Inc.
|
||||
@ -66,6 +66,18 @@ struct io_sysctl {
|
||||
u_int64_t rbytes;
|
||||
u_int64_t wxfer;
|
||||
u_int64_t wbytes;
|
||||
/*
|
||||
* New queue stats
|
||||
* accumulated wait time (iostat_wait .. iostat_busy)
|
||||
* accumulated wait sum (wait time * count)
|
||||
* accumulated busy sum (busy time * count)
|
||||
*/
|
||||
u_int32_t wait_sec;
|
||||
u_int32_t wait_usec;
|
||||
u_int32_t waitsum_sec;
|
||||
u_int32_t waitsum_usec;
|
||||
u_int32_t busysum_sec;
|
||||
u_int32_t busysum_usec;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -78,6 +90,7 @@ struct io_stats {
|
||||
void *io_parent; /* pointer to what we are attached to */
|
||||
int io_type; /* type of device the state belong to */
|
||||
int io_busy; /* busy counter */
|
||||
int io_wait; /* wait counter */
|
||||
u_int64_t io_rxfer; /* total number of read transfers */
|
||||
u_int64_t io_wxfer; /* total number of write transfers */
|
||||
u_int64_t io_seek; /* total independent seek operations */
|
||||
@ -85,7 +98,12 @@ struct io_stats {
|
||||
u_int64_t io_wbytes; /* total bytes written */
|
||||
struct timeval io_attachtime; /* time disk was attached */
|
||||
struct timeval io_timestamp; /* timestamp of last unbusy */
|
||||
struct timeval io_time; /* total time spent busy */
|
||||
struct timeval io_busystamp; /* timestamp of last busy */
|
||||
struct timeval io_waitstamp; /* timestamp of last wait */
|
||||
struct timeval io_busysum; /* accumulated wait * time */
|
||||
struct timeval io_waitsum; /* accumulated busy * time */
|
||||
struct timeval io_busytime; /* accumlated time busy */
|
||||
struct timeval io_waittime; /* accumlated time waiting */
|
||||
TAILQ_ENTRY(io_stats) io_link;
|
||||
};
|
||||
|
||||
@ -96,6 +114,7 @@ TAILQ_HEAD(iostatlist_head, io_stats); /* the iostatlist is a TAILQ */
|
||||
|
||||
#ifdef _KERNEL
|
||||
void iostat_init(void);
|
||||
void iostat_wait(struct io_stats *);
|
||||
void iostat_busy(struct io_stats *);
|
||||
void iostat_unbusy(struct io_stats *, long, int);
|
||||
bool iostat_isbusy(struct io_stats *);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: drvstats.c,v 1.9 2014/06/13 11:26:37 joerg Exp $ */
|
||||
/* $NetBSD: drvstats.c,v 1.10 2017/03/05 23:07:12 mlelstv Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996 John M. Vinopal
|
||||
@ -83,6 +83,14 @@ drvswap(void)
|
||||
last.fld = tmp; \
|
||||
} while (/* CONSTCOND */0)
|
||||
|
||||
#define DELTA(x) do { \
|
||||
timerclear(&tmp_timer); \
|
||||
timerset(&(cur.x), &tmp_timer); \
|
||||
timersub(&tmp_timer, &(last.x), &(cur.x)); \
|
||||
timerclear(&(last.x)); \
|
||||
timerset(&tmp_timer, &(last.x)); \
|
||||
} while (/* CONSTCOND */0)
|
||||
|
||||
for (i = 0; i < ndrive; i++) {
|
||||
struct timeval tmp_timer;
|
||||
|
||||
@ -96,12 +104,10 @@ drvswap(void)
|
||||
SWAP(rbytes[i]);
|
||||
SWAP(wbytes[i]);
|
||||
|
||||
/* Delta Time. */
|
||||
timerclear(&tmp_timer);
|
||||
timerset(&(cur.time[i]), &tmp_timer);
|
||||
timersub(&tmp_timer, &(last.time[i]), &(cur.time[i]));
|
||||
timerclear(&(last.time[i]));
|
||||
timerset(&tmp_timer, &(last.time[i]));
|
||||
DELTA(wait[i]);
|
||||
DELTA(time[i]);
|
||||
DELTA(waitsum[i]);
|
||||
DELTA(busysum[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,6 +141,7 @@ cpuswap(void)
|
||||
|
||||
cur.cp_etime = etime;
|
||||
}
|
||||
#undef DELTA
|
||||
#undef SWAP
|
||||
|
||||
/*
|
||||
@ -154,17 +161,28 @@ drvreadstats(void)
|
||||
size = ndrive * sizeof(struct io_sysctl);
|
||||
if (sysctl(mib, 3, drives, &size, NULL, 0) < 0)
|
||||
err(1, "sysctl hw.iostats failed");
|
||||
|
||||
#define COPYF(x,k) cur.x[k] = drives[k].x
|
||||
#define COPYT(x,k) do { \
|
||||
cur.x[k].tv_sec = drives[k].x##_sec; \
|
||||
cur.x[k].tv_usec = drives[k].x##_usec; \
|
||||
} while (/* CONSTCOND */0)
|
||||
|
||||
for (i = 0; i < ndrive; i++) {
|
||||
cur.rxfer[i] = drives[i].rxfer;
|
||||
cur.wxfer[i] = drives[i].wxfer;
|
||||
cur.seek[i] = drives[i].seek;
|
||||
cur.rbytes[i] = drives[i].rbytes;
|
||||
cur.wbytes[i] = drives[i].wbytes;
|
||||
cur.time[i].tv_sec = drives[i].time_sec;
|
||||
cur.time[i].tv_usec = drives[i].time_usec;
|
||||
|
||||
COPYF(rxfer, i);
|
||||
COPYF(wxfer, i);
|
||||
COPYF(seek, i);
|
||||
COPYF(rbytes, i);
|
||||
COPYF(wbytes, i);
|
||||
|
||||
COPYT(wait, i);
|
||||
COPYT(time, i);
|
||||
COPYT(waitsum, i);
|
||||
COPYT(busysum, i);
|
||||
}
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_TKSTAT;
|
||||
mib[2] = KERN_TKSTAT_NIN;
|
||||
size = sizeof(cur.tk_nin);
|
||||
@ -183,6 +201,8 @@ drvreadstats(void)
|
||||
if (sysctl(mib, 2, cur.cp_time, &size, NULL, 0) < 0)
|
||||
(void)memset(cur.cp_time, 0, sizeof(cur.cp_time));
|
||||
}
|
||||
#undef COPYT
|
||||
#undef COPYF
|
||||
|
||||
/*
|
||||
* Read collect statistics for tty i/o.
|
||||
@ -272,12 +292,18 @@ drvinit(int selected)
|
||||
|
||||
/* Allocate space for the statistics. */
|
||||
cur.time = calloc(ndrive, sizeof(struct timeval));
|
||||
cur.wait = calloc(ndrive, sizeof(struct timeval));
|
||||
cur.waitsum = calloc(ndrive, sizeof(struct timeval));
|
||||
cur.busysum = calloc(ndrive, sizeof(struct timeval));
|
||||
cur.rxfer = calloc(ndrive, sizeof(u_int64_t));
|
||||
cur.wxfer = calloc(ndrive, sizeof(u_int64_t));
|
||||
cur.seek = calloc(ndrive, sizeof(u_int64_t));
|
||||
cur.rbytes = calloc(ndrive, sizeof(u_int64_t));
|
||||
cur.wbytes = calloc(ndrive, sizeof(u_int64_t));
|
||||
last.time = calloc(ndrive, sizeof(struct timeval));
|
||||
last.wait = calloc(ndrive, sizeof(struct timeval));
|
||||
last.waitsum = calloc(ndrive, sizeof(struct timeval));
|
||||
last.busysum = calloc(ndrive, sizeof(struct timeval));
|
||||
last.rxfer = calloc(ndrive, sizeof(u_int64_t));
|
||||
last.wxfer = calloc(ndrive, sizeof(u_int64_t));
|
||||
last.seek = calloc(ndrive, sizeof(u_int64_t));
|
||||
@ -286,12 +312,16 @@ drvinit(int selected)
|
||||
cur.select = calloc(ndrive, sizeof(int));
|
||||
cur.name = calloc(ndrive, sizeof(char *));
|
||||
|
||||
if (cur.time == NULL || cur.rxfer == NULL ||
|
||||
cur.wxfer == NULL || cur.seek == NULL ||
|
||||
cur.rbytes == NULL || cur.wbytes == NULL ||
|
||||
last.time == NULL || last.rxfer == NULL ||
|
||||
last.wxfer == NULL || last.seek == NULL ||
|
||||
last.rbytes == NULL || last.wbytes == NULL ||
|
||||
if (cur.time == NULL || cur.wait == NULL ||
|
||||
cur.waitsum == NULL || cur.busysum == NULL ||
|
||||
cur.rxfer == NULL || cur.wxfer == NULL ||
|
||||
cur.seek == NULL || cur.rbytes == NULL ||
|
||||
cur.wbytes == NULL ||
|
||||
last.time == NULL || last.wait == NULL ||
|
||||
last.waitsum == NULL || last.busysum == NULL ||
|
||||
last.rxfer == NULL || last.wxfer == NULL ||
|
||||
last.seek == NULL || last.rbytes == NULL ||
|
||||
last.wbytes == NULL ||
|
||||
cur.select == NULL || cur.name == NULL)
|
||||
errx(1, "Memory allocation failure.");
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: drvstats.h,v 1.3 2006/10/17 15:13:08 christos Exp $ */
|
||||
/* $NetBSD: drvstats.h,v 1.4 2017/03/05 23:07:12 mlelstv Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996 John M. Vinopal
|
||||
@ -45,7 +45,10 @@ struct _drive {
|
||||
u_int64_t *seek; /* # of seeks (currently unused). */
|
||||
u_int64_t *rbytes; /* # of bytes read. */
|
||||
u_int64_t *wbytes; /* # of bytes written. */
|
||||
struct timeval *time; /* Time spent in disk i/o. */
|
||||
struct timeval *time; /* Time spent in disk i/o. */
|
||||
struct timeval *wait; /* Time spent in queue waiting. */
|
||||
struct timeval *busysum; /* Time busy * queue length */
|
||||
struct timeval *waitsum; /* Time waiting * queue length */
|
||||
u_int64_t tk_nin; /* TTY Chars in. */
|
||||
u_int64_t tk_nout; /* TTY Chars out. */
|
||||
u_int64_t cp_time[CPUSTATES]; /* System timer ticks. */
|
||||
|
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: iostat.8,v 1.24 2015/07/09 13:26:52 mrg Exp $
|
||||
.\" $NetBSD: iostat.8,v 1.25 2017/03/05 23:07:12 mlelstv Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1985, 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@ -39,7 +39,7 @@
|
||||
statistics
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl CdDITx
|
||||
.Op Fl CdDITxy
|
||||
.Op Fl c Ar count
|
||||
.Op Fl w Ar wait
|
||||
.Op Ar drives
|
||||
@ -127,6 +127,8 @@ This option overrides all other display options, and all
|
||||
disks are displayed unless specific disks
|
||||
are provided as arguments.
|
||||
Additionally, separate read and write statistics are displayed.
|
||||
.It Fl y
|
||||
Shows the extended statistics and additional queuing statistics.
|
||||
.El
|
||||
.Pp
|
||||
.Nm
|
||||
@ -172,6 +174,24 @@ Kilobytes transferred
|
||||
Disk transfers
|
||||
.It time
|
||||
Seconds spent in disk activity
|
||||
.Pp
|
||||
.El
|
||||
With the
|
||||
.Fl y
|
||||
flag, the following queuing measurements are added
|
||||
.Bl -tag -width indent -compact
|
||||
.It wait
|
||||
Number of I/O requests queued up
|
||||
.It actv
|
||||
Number of currently active I/O requests
|
||||
.It wsvc_t
|
||||
Average waiting time of an I/O request in milliseconds
|
||||
.It asvc_t
|
||||
Average duration of an I/O request in milliseconds
|
||||
.It wtime
|
||||
Seconds spent in the waiting queue.
|
||||
Queuing data might not be available from all drivers
|
||||
and is then shown as zeros.
|
||||
.El
|
||||
.It cpu
|
||||
.Bl -tag -width indent -compact
|
||||
@ -205,3 +225,7 @@ The
|
||||
.Fl x
|
||||
option was added in
|
||||
.Nx 1.4 .
|
||||
Collection of queueing values and the
|
||||
.Fl y
|
||||
option were added in
|
||||
.Nx 8.0 .
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: iostat.c,v 1.63 2015/10/25 02:47:17 mrg Exp $ */
|
||||
/* $NetBSD: iostat.c,v 1.64 2017/03/05 23:07:12 mlelstv Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996 John M. Vinopal
|
||||
@ -71,7 +71,7 @@ __COPYRIGHT("@(#) Copyright (c) 1986, 1991, 1993\
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)iostat.c 8.3 (Berkeley) 4/28/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: iostat.c,v 1.63 2015/10/25 02:47:17 mrg Exp $");
|
||||
__RCSID("$NetBSD: iostat.c,v 1.64 2017/03/05 23:07:12 mlelstv Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
@ -107,13 +107,17 @@ static int wincols = 80;
|
||||
#define SHOW_STATS_1 (1<<2)
|
||||
#define SHOW_STATS_2 (1<<3)
|
||||
#define SHOW_STATS_X (1<<4)
|
||||
#define SHOW_STATS_Y (1<<5)
|
||||
#define SHOW_TOTALS (1<<7)
|
||||
#define SHOW_STATS_ALL (SHOW_STATS_1 | SHOW_STATS_2 | SHOW_STATS_X)
|
||||
#define SHOW_STATS_ALL (SHOW_STATS_1 | SHOW_STATS_2 | SHOW_STATS_X | SHOW_STATS_Y)
|
||||
|
||||
static void cpustats(void);
|
||||
static void drive_stats(double);
|
||||
static void drive_stats2(double);
|
||||
static void drive_statsx(double);
|
||||
static void drive_statsy(double);
|
||||
static void drive_statsy_io(double, double, double);
|
||||
static void drive_statsy_q(double, double, double, double, double, double);
|
||||
static void sig_header(int);
|
||||
static volatile int do_header;
|
||||
static void header(void);
|
||||
@ -128,7 +132,7 @@ main(int argc, char *argv[])
|
||||
struct timespec tv;
|
||||
struct ttysize ts;
|
||||
|
||||
while ((ch = getopt(argc, argv, "Cc:dDITw:x")) != -1)
|
||||
while ((ch = getopt(argc, argv, "Cc:dDITw:xy")) != -1)
|
||||
switch (ch) {
|
||||
case 'c':
|
||||
if ((reps = atoi(optarg)) <= 0)
|
||||
@ -159,6 +163,10 @@ main(int argc, char *argv[])
|
||||
todo &= ~SHOW_STATS_ALL;
|
||||
todo |= SHOW_STATS_X;
|
||||
break;
|
||||
case 'y':
|
||||
todo &= ~SHOW_STATS_ALL;
|
||||
todo |= SHOW_STATS_Y;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
@ -172,6 +180,10 @@ main(int argc, char *argv[])
|
||||
todo &= ~(SHOW_CPU | SHOW_TTY | SHOW_STATS_ALL);
|
||||
todo |= SHOW_STATS_X;
|
||||
}
|
||||
if (ISSET(todo, SHOW_STATS_Y)) {
|
||||
todo &= ~(SHOW_CPU | SHOW_TTY | SHOW_STATS_ALL | SHOW_TOTALS);
|
||||
todo |= SHOW_STATS_Y;
|
||||
}
|
||||
|
||||
if (ioctl(STDOUT_FILENO, TIOCGSIZE, &ts) != -1) {
|
||||
if (ts.ts_lines)
|
||||
@ -197,7 +209,7 @@ main(int argc, char *argv[])
|
||||
if (todo == 0)
|
||||
errx(1, "no drives");
|
||||
}
|
||||
if (ISSET(todo, SHOW_STATS_X))
|
||||
if (ISSET(todo, SHOW_STATS_X | SHOW_STATS_Y))
|
||||
lines = ndrives;
|
||||
else
|
||||
lines = 1;
|
||||
@ -257,6 +269,13 @@ header(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ISSET(todo, SHOW_STATS_Y)) {
|
||||
(void)printf("device read KB/t r/s MB/s write KB/t w/s MB/s");
|
||||
(void)printf(" wait actv wsvc_t asvc_t wtime time");
|
||||
(void)printf("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ISSET(todo, SHOW_TTY))
|
||||
(void)printf(" tty");
|
||||
|
||||
@ -422,6 +441,77 @@ drive_statsx(double etime)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drive_statsy_io(double elapsed, double count, double volume)
|
||||
{
|
||||
double kbps;
|
||||
|
||||
/* average Kbytes per transfer */
|
||||
if (count)
|
||||
kbps = (volume / 1024.0) / count;
|
||||
else
|
||||
kbps = 0.0;
|
||||
(void)printf(" %8.2f", kbps);
|
||||
|
||||
/* average transfers (per second) */
|
||||
(void)printf(" %6.0f", count / elapsed);
|
||||
|
||||
/* average megabytes (per second) */
|
||||
(void)printf(" %8.2f", volume / (1024.0 * 1024) / elapsed);
|
||||
}
|
||||
|
||||
static void
|
||||
drive_statsy_q(double elapsed, double busy, double wait, double busysum, double waitsum, double count)
|
||||
{
|
||||
/* average wait queue length */
|
||||
(void)printf(" %6.1f", waitsum / elapsed);
|
||||
|
||||
/* average busy queue length */
|
||||
(void)printf(" %6.1f", busysum / elapsed);
|
||||
|
||||
/* average wait time */
|
||||
(void)printf(" %7.2f", count > 0 ? waitsum / count * 1000.0 : 0.0);
|
||||
|
||||
/* average service time */
|
||||
(void)printf(" %7.2f", count > 0 ? busysum / count * 1000.0 : 0.0);
|
||||
|
||||
/* time waiting for drive activity */
|
||||
(void)printf(" %6.2f", wait / elapsed);
|
||||
|
||||
/* time busy in drive activity */
|
||||
(void)printf(" %6.2f", busy / elapsed);
|
||||
}
|
||||
|
||||
static void
|
||||
drive_statsy(double etime)
|
||||
{
|
||||
size_t dn;
|
||||
double atime, await, abusysum, awaitsum;
|
||||
|
||||
for (dn = 0; dn < ndrive; ++dn) {
|
||||
if (!cur.select[dn])
|
||||
continue;
|
||||
|
||||
(void)printf("%-8.8s", cur.name[dn]);
|
||||
|
||||
atime = (double)cur.time[dn].tv_sec +
|
||||
((double)cur.time[dn].tv_usec / (double)1000000);
|
||||
await = (double)cur.wait[dn].tv_sec +
|
||||
((double)cur.wait[dn].tv_usec / (double)1000000);
|
||||
abusysum = (double)cur.busysum[dn].tv_sec +
|
||||
((double)cur.busysum[dn].tv_usec / (double)1000000);
|
||||
awaitsum = (double)cur.waitsum[dn].tv_sec +
|
||||
((double)cur.waitsum[dn].tv_usec / (double)1000000);
|
||||
|
||||
drive_statsy_io(etime, cur.rxfer[dn], cur.rbytes[dn]);
|
||||
(void)printf(" ");
|
||||
drive_statsy_io(etime, cur.wxfer[dn], cur.wbytes[dn]);
|
||||
drive_statsy_q(etime, atime, await, abusysum, awaitsum, cur.rxfer[dn]+cur.wxfer[dn]);
|
||||
|
||||
(void)printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cpustats(void)
|
||||
{
|
||||
@ -442,7 +532,7 @@ static void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
(void)fprintf(stderr, "usage: iostat [-CdDITx] [-c count] "
|
||||
(void)fprintf(stderr, "usage: iostat [-CdDITxy] [-c count] "
|
||||
"[-w wait] [drives]\n");
|
||||
exit(1);
|
||||
}
|
||||
@ -467,6 +557,11 @@ display(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ISSET(todo, SHOW_STATS_Y)) {
|
||||
drive_statsy(etime);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ISSET(todo, SHOW_TTY))
|
||||
printf("%4.0f %5.0f", cur.tk_nin / etime, cur.tk_nout / etime);
|
||||
|
||||
@ -525,14 +620,15 @@ selectdrives(int argc, char *argv[])
|
||||
* Pick up to defdrives (or all if -x is given) drives
|
||||
* if none specified.
|
||||
*/
|
||||
maxdrives = (ISSET(todo, SHOW_STATS_X) ||
|
||||
maxdrives = (ISSET(todo, SHOW_STATS_X | SHOW_STATS_Y) ||
|
||||
(int)ndrive < defdrives)
|
||||
? (int)(ndrive) : defdrives;
|
||||
for (i = 0; i < maxdrives; i++) {
|
||||
cur.select[i] = 1;
|
||||
|
||||
++ndrives;
|
||||
if (!ISSET(todo, SHOW_STATS_X) && ndrives == defdrives)
|
||||
if (!ISSET(todo, SHOW_STATS_X | SHOW_STATS_Y) &&
|
||||
ndrives == defdrives)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user