#!/usr/bin/ksh
#
# iopending - Print a plot for the number of pending disk I/O events.
# Written using DTrace (Solaris 10 3/05).
#
# This is measuring disk events that have made it past system caches.
# By plotting a distribution graph of the number of pending events, the
# "serialness" or "parallelness" of disk behaviour can be distinguished.
#
# $Id: iopending,v 1.1.1.1 2015/09/30 22:01:07 christos Exp $
#
# USAGE: iopending [-c] [-d device] [-f filename]
# [-m mount_point] [interval [count]]
#
# -c # clear the screen
# -d device # instance name to snoop (eg, dad0)
# -f filename # full pathname of file to snoop
# -m mount_point # this FS only (will skip raw events)
# eg,
# iopending # default output, 5 second intervals
# iopending 1 # 1 second samples
# iopending -c # clear the screen
# iopending 5 12 # print 12 x 5 second samples
#
# FIELDS:
# value number of pending events, 0 == idle
# count number of samples @ 1000 Hz
# load 1 min load average
# disk_r total disk read Kbytes for sample
# disk_w total disk write Kbytes for sample
#
# SEE ALSO: iosnoop, iotop
#
# IDEA: Dr Rex di Bona (Sydney, Australia)
#
# COPYRIGHT: Copyright (c) 2005, 2006 Brendan Gregg.
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License, Version 1.0 only
# (the "License"). You may not use this file except in compliance
# with the License.
#
# You can obtain a copy of the license at Docs/cddl1.txt
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# CDDL HEADER END
#
# Author: Brendan Gregg [Sydney, Australia]
#
# 01-Nov-2005 Brendan Gregg Created this.
# 20-Apr-2006 " " Last update.
#
##############################
# --- Process Arguments ---
#
### default variables
opt_device=0; opt_file=0; opt_mount=0; opt_clear=0;
opt_def=1; filter=0; device=.; filename=.; mount=.
interval=5; count=-1
### process options
while getopts cd:f:hm: name
do
case $name in
c) opt_clear=1 ;;
d) opt_device=1; device=$OPTARG ;;
f) opt_file=1; filename=$OPTARG ;;
m) opt_mount=1; mount=$OPTARG ;;
h|?) cat <<-END >&2
USAGE: iopending [-c] [-d device] [-f filename]
[-m mount_point] [interval [count]]
-c # clear the screen
-d device # instance name to snoop
-f filename # snoop this file only
-m mount_point # this FS only
eg,
iopending # default output, 5 second samples
iopending 1 # 1 second samples
iopending -m / # snoop events on filesystem / only
iopending 5 12 # print 12 x 5 second samples
END
exit 1
esac
done
shift $(( $OPTIND - 1 ))
### option logic
if [[ "$1" > 0 ]]; then
interval=$1; shift
fi
if [[ "$1" > 0 ]]; then
count=$1; shift
fi
if (( opt_device || opt_mount || opt_file )); then
filter=1
fi
if (( opt_clear )); then
clearstr=`clear`
else
clearstr=.
fi
#################################
# --- Main Program, DTrace ---
#
/usr/sbin/dtrace -n '
/*
* Command line arguments
*/
inline int OPT_def = '$opt_def';
inline int OPT_clear = '$opt_clear';
inline int OPT_device = '$opt_device';
inline int OPT_mount = '$opt_mount';
inline int OPT_file = '$opt_file';
inline int INTERVAL = '$interval';
inline int COUNTER = '$count';
inline int FILTER = '$filter';
inline string DEVICE = "'$device'";
inline string FILENAME = "'$filename'";
inline string MOUNT = "'$mount'";
inline string CLEAR = "'$clearstr'";
inline int MAX_PENDING = 32; /* max pending value */
#pragma D option quiet
/*
* Print header
*/
dtrace:::BEGIN
{
/* starting values */
counts = COUNTER;
secs = INTERVAL;
disk_r = 0;
disk_w = 0;
pending = 0;
printf("Tracing... Please wait.\n");
}
/*
* Check event is being traced
*/
io:genunix::start,
io:genunix::done
{
/* default is to trace unless filtering, */
this->ok = FILTER ? 0 : 1;
/* check each filter, */
(OPT_device == 1 && DEVICE == args[1]->dev_statname)? this->ok = 1 : 1;
(OPT_file == 1 && FILENAME == args[2]->fi_pathname) ? this->ok = 1 : 1;
(OPT_mount == 1 && MOUNT == args[2]->fi_mount) ? this->ok = 1 : 1;
}
/*
* Store entry details
*/
io:genunix::start
/this->ok/
{
/* track bytes */
disk_r += args[0]->b_flags & B_READ ? args[0]->b_bcount : 0;
disk_w += args[0]->b_flags & B_READ ? 0 : args[0]->b_bcount;
/* increase event pending count */
pending++;
}
/*
* Process and Print completion
*/
io:genunix::done
/this->ok/
{
/* decrease event pending count */
pending--;
}
/*
* Prevent pending from underflowing
* this can happen if this program is started during disk events.
*/
io:genunix::done
/pending < 0/
{
pending = 0;
}
/*
* Timer
*/
profile:::tick-1sec
{
secs--;
}
profile:::profile-1000hz
{
@out = lquantize(pending, 0, MAX_PENDING, 1);
}
/*
* Print Report
*/
profile:::tick-1sec
/secs == 0/
{
/* fetch 1 min load average */
this->load1a = `hp_avenrun[0] / 65536;
this->load1b = ((`hp_avenrun[0] % 65536) * 100) / 65536;
/* convert counters to Kbytes */
disk_r /= 1024;
disk_w /= 1024;
/* print status */
OPT_clear ? printf("%s", CLEAR) : 1;
printf("%Y, load: %d.%02d, disk_r: %6d KB, disk_w: %6d KB",
walltimestamp, this->load1a, this->load1b, disk_r, disk_w);
/* print output */
printa(@out);
/* clear data */
trunc(@out);
disk_r = 0;
disk_w = 0;
secs = INTERVAL;
counts--;
}
/*
* End of program
*/
profile:::tick-1sec
/counts == 0/
{
exit(0);
}
/*
* Cleanup for Ctrl-C
*/
dtrace:::END
{
trunc(@out);
}
'