1N/A#!/usr/bin/ksh
1N/A#
1N/A# iopattern - print disk I/O pattern.
1N/A# Written using DTrace (Solaris 10 3/05).
1N/A#
1N/A# This prints details on the I/O access pattern for the disks, such as
1N/A# percentage of events that were of a random or sequential nature.
1N/A# By default totals for all disks are printed.
1N/A#
1N/A# $Id: iopattern 65 2007-10-04 11:09:40Z brendan $
1N/A#
1N/A# USAGE: iopattern [-v] [-d device] [-f filename] [-m mount_point]
1N/A# [interval [count]]
1N/A#
1N/A# -v # print timestamp, string
1N/A# -d device # instance name to snoop (eg, dad0)
1N/A# -f filename # full pathname of file to snoop
1N/A# -m mount_point # this FS only (will skip raw events)
1N/A# eg,
1N/A# iopattern # default output, 1 second intervals
1N/A# iopattern 10 # 10 second samples
1N/A# iopattern 5 12 # print 12 x 5 second samples
1N/A# iopattern -m / # snoop events on filesystem / only
1N/A#
1N/A# FIELDS:
1N/A# %RAN percentage of events of a random nature
1N/A# %SEQ percentage of events of a sequential nature
1N/A# COUNT number of I/O events
1N/A# MIN minimum I/O event size
1N/A# MAX maximum I/O event size
1N/A# AVG average I/O event size
1N/A# KR total kilobytes read during sample
1N/A# KW total kilobytes written during sample
1N/A# DEVICE device name
1N/A# MOUNT mount point
1N/A# FILE filename
1N/A# TIME timestamp, string
1N/A#
1N/A# NOTES:
1N/A#
1N/A# An event is considered random when the heads seek. This program prints
1N/A# the percentage of events that are random. The size of the seek is not
1N/A# measured - it's either random or not.
1N/A#
1N/A# SEE ALSO: iosnoop, iotop
1N/A#
1N/A# IDEA: Ryan Matteson
1N/A#
1N/A# COPYRIGHT: Copyright (c) 2005 Brendan Gregg.
1N/A#
1N/A# CDDL HEADER START
1N/A#
1N/A# The contents of this file are subject to the terms of the
1N/A# Common Development and Distribution License, Version 1.0 only
1N/A# (the "License"). You may not use this file except in compliance
1N/A# with the License.
1N/A#
1N/A# You can obtain a copy of the license at Docs/cddl1.txt
1N/A# or http://www.opensolaris.org/os/licensing.
1N/A# See the License for the specific language governing permissions
1N/A# and limitations under the License.
1N/A#
1N/A# CDDL HEADER END
1N/A#
1N/A# Author: Brendan Gregg [Sydney, Australia]
1N/A#
1N/A# 25-Jul-2005 Brendan Gregg Created this.
1N/A# 25-Jul-2005 " " Last update.
1N/A#
1N/A
1N/A
1N/A##############################
1N/A# --- Process Arguments ---
1N/A#
1N/A
1N/A### default variables
1N/Aopt_device=0; opt_file=0; opt_mount=0; opt_time=0
1N/Afilter=0; device=.; filename=.; mount=.; interval=1; count=-1
1N/A
1N/A### process options
1N/Awhile getopts d:f:hm:v name
1N/Ado
1N/A case $name in
1N/A d) opt_device=1; device=$OPTARG ;;
1N/A f) opt_file=1; filename=$OPTARG ;;
1N/A m) opt_mount=1; mount=$OPTARG ;;
1N/A v) opt_time=1 ;;
1N/A h|?) cat <<-END >&2
1N/A USAGE: iopattern [-v] [-d device] [-f filename] [-m mount_point]
1N/A [interval [count]]
1N/A
1N/A -v # print timestamp
1N/A -d device # instance name to snoop
1N/A -f filename # snoop this file only
1N/A -m mount_point # this FS only
1N/A eg,
1N/A iopattern # default output, 1 second samples
1N/A iopattern 10 # 10 second samples
1N/A iopattern 5 12 # print 12 x 5 second samples
1N/A iopattern -m / # snoop events on filesystem / only
1N/A END
1N/A exit 1
1N/A esac
1N/Adone
1N/A
1N/Ashift $(( $OPTIND - 1 ))
1N/A
1N/A### option logic
1N/Aif [[ "$1" > 0 ]]; then
1N/A interval=$1; shift
1N/Afi
1N/Aif [[ "$1" > 0 ]]; then
1N/A count=$1; shift
1N/Afi
1N/Aif (( opt_device || opt_mount || opt_file )); then
1N/A filter=1
1N/Afi
1N/A
1N/A
1N/A#################################
1N/A# --- Main Program, DTrace ---
1N/A#
1N/A/usr/sbin/dtrace -n '
1N/A /*
1N/A * Command line arguments
1N/A */
1N/A inline int OPT_time = '$opt_time';
1N/A inline int OPT_device = '$opt_device';
1N/A inline int OPT_mount = '$opt_mount';
1N/A inline int OPT_file = '$opt_file';
1N/A inline int INTERVAL = '$interval';
1N/A inline int COUNTER = '$count';
1N/A inline int FILTER = '$filter';
1N/A inline string DEVICE = "'$device'";
1N/A inline string FILENAME = "'$filename'";
1N/A inline string MOUNT = "'$mount'";
1N/A
1N/A #pragma D option quiet
1N/A
1N/A int last_loc[string];
1N/A
1N/A /*
1N/A * Program start
1N/A */
1N/A dtrace:::BEGIN
1N/A {
1N/A /* starting values */
1N/A diskcnt = 0;
1N/A diskmin = 0;
1N/A diskmax = 0;
1N/A diskran = 0;
1N/A diskr = 0;
1N/A diskw = 0;
1N/A counts = COUNTER;
1N/A secs = INTERVAL;
1N/A LINES = 20;
1N/A line = 0;
1N/A last_event[""] = 0;
1N/A }
1N/A
1N/A /*
1N/A * Print header
1N/A */
1N/A profile:::tick-1sec
1N/A /line <= 0 /
1N/A {
1N/A /* print optional headers */
1N/A OPT_time ? printf("%-20s ", "TIME") : 1;
1N/A OPT_device ? printf("%-9s ", "DEVICE") : 1;
1N/A OPT_mount ? printf("%-12s ", "MOUNT") : 1;
1N/A OPT_file ? printf("%-12s ", "FILE") : 1;
1N/A
1N/A /* print header */
1N/A printf("%4s %4s %6s %6s %6s %6s %6s %6s\n",
1N/A "%RAN", "%SEQ", "COUNT", "MIN", "MAX", "AVG", "KR", "KW");
1N/A
1N/A line = LINES;
1N/A }
1N/A
1N/A /*
1N/A * Check event is being traced
1N/A */
1N/A io:genunix::done
1N/A {
1N/A /* default is to trace unless filtering */
1N/A self->ok = FILTER ? 0 : 1;
1N/A
1N/A /* check each filter */
1N/A (OPT_device == 1 && DEVICE == args[1]->dev_statname)? self->ok = 1 : 1;
1N/A (OPT_file == 1 && FILENAME == args[2]->fi_pathname) ? self->ok = 1 : 1;
1N/A (OPT_mount == 1 && MOUNT == args[2]->fi_mount) ? self->ok = 1 : 1;
1N/A }
1N/A
1N/A /*
1N/A * Process and Print completion
1N/A */
1N/A io:genunix::done
1N/A /self->ok/
1N/A {
1N/A /*
1N/A * Save details
1N/A */
1N/A this->loc = args[0]->b_blkno * 512;
1N/A this->pre = last_loc[args[1]->dev_statname];
1N/A diskr += args[0]->b_flags & B_READ ? args[0]->b_bcount : 0;
1N/A diskw += args[0]->b_flags & B_READ ? 0 : args[0]->b_bcount;
1N/A diskran += this->pre == this->loc ? 0 : 1;
1N/A diskcnt++;
1N/A diskmin = diskmin == 0 ? args[0]->b_bcount :
1N/A (diskmin > args[0]->b_bcount ? args[0]->b_bcount : diskmin);
1N/A diskmax = diskmax < args[0]->b_bcount ? args[0]->b_bcount : diskmax;
1N/A
1N/A /* save disk location */
1N/A last_loc[args[1]->dev_statname] = this->loc + args[0]->b_bcount;
1N/A
1N/A /* cleanup */
1N/A self->ok = 0;
1N/A }
1N/A
1N/A /*
1N/A * Timer
1N/A */
1N/A profile:::tick-1sec
1N/A {
1N/A secs--;
1N/A }
1N/A
1N/A /*
1N/A * Print Output
1N/A */
1N/A profile:::tick-1sec
1N/A /secs == 0/
1N/A {
1N/A /* calculate diskavg */
1N/A diskavg = diskcnt > 0 ? (diskr + diskw) / diskcnt : 0;
1N/A
1N/A /* convert counters to Kbytes */
1N/A diskr /= 1024;
1N/A diskw /= 1024;
1N/A
1N/A /* convert to percentages */
1N/A diskran = diskcnt == 0 ? 0 : (diskran * 100) / diskcnt;
1N/A diskseq = diskcnt == 0 ? 0 : 100 - diskran;
1N/A
1N/A /* print optional fields */
1N/A OPT_time ? printf("%-20Y ", walltimestamp) : 1;
1N/A OPT_device ? printf("%-9s ", DEVICE) : 1;
1N/A OPT_mount ? printf("%-12s ", MOUNT) : 1;
1N/A OPT_file ? printf("%-12s ", FILENAME) : 1;
1N/A
1N/A /* print data */
1N/A printf("%4d %4d %6d %6d %6d %6d %6d %6d\n",
1N/A diskran, diskseq, diskcnt, diskmin, diskmax, diskavg,
1N/A diskr, diskw);
1N/A
1N/A /* clear data */
1N/A diskmin = 0;
1N/A diskmax = 0;
1N/A diskcnt = 0;
1N/A diskran = 0;
1N/A diskr = 0;
1N/A diskw = 0;
1N/A
1N/A secs = INTERVAL;
1N/A counts--;
1N/A line--;
1N/A }
1N/A
1N/A /*
1N/A * End of program
1N/A */
1N/A profile:::tick-1sec
1N/A /counts == 0/
1N/A {
1N/A exit(0);
1N/A }
1N/A'