xref: /netbsd-src/external/cddl/dtracetoolkit/dist/iopattern (revision c29d51755812ace2e87aeefdb06cb2b4dac7087a)
1*c29d5175Schristos#!/usr/bin/ksh
2*c29d5175Schristos#
3*c29d5175Schristos# iopattern - print disk I/O pattern.
4*c29d5175Schristos#             Written using DTrace (Solaris 10 3/05).
5*c29d5175Schristos#
6*c29d5175Schristos# This prints details on the I/O access pattern for the disks, such as
7*c29d5175Schristos# percentage of events that were of a random or sequential nature.
8*c29d5175Schristos# By default totals for all disks are printed.
9*c29d5175Schristos#
10*c29d5175Schristos# $Id: iopattern,v 1.1.1.1 2015/09/30 22:01:06 christos Exp $
11*c29d5175Schristos#
12*c29d5175Schristos# USAGE:	iopattern [-v] [-d device] [-f filename] [-m mount_point]
13*c29d5175Schristos#			  [interval [count]]
14*c29d5175Schristos#
15*c29d5175Schristos#		       -v       	# print timestamp, string
16*c29d5175Schristos#		       -d device	# instance name to snoop (eg, dad0)
17*c29d5175Schristos#		       -f filename	# full pathname of file to snoop
18*c29d5175Schristos#		       -m mount_point	# this FS only (will skip raw events)
19*c29d5175Schristos#  eg,
20*c29d5175Schristos#		iopattern   	# default output, 1 second intervals
21*c29d5175Schristos#		iopattern 10  	# 10 second samples
22*c29d5175Schristos#		iopattern 5 12	# print 12 x 5 second samples
23*c29d5175Schristos#	        iopattern -m /  # snoop events on filesystem / only
24*c29d5175Schristos#
25*c29d5175Schristos# FIELDS:
26*c29d5175Schristos#		%RAN  		percentage of events of a random nature
27*c29d5175Schristos#		%SEQ 	 	percentage of events of a sequential nature
28*c29d5175Schristos#		COUNT		number of I/O events
29*c29d5175Schristos#		MIN		minimum I/O event size
30*c29d5175Schristos#		MAX		maximum I/O event size
31*c29d5175Schristos#		AVG		average I/O event size
32*c29d5175Schristos#		KR		total kilobytes read during sample
33*c29d5175Schristos#		KW		total kilobytes written during sample
34*c29d5175Schristos#		DEVICE		device name
35*c29d5175Schristos#		MOUNT		mount point
36*c29d5175Schristos#		FILE		filename
37*c29d5175Schristos#		TIME		timestamp, string
38*c29d5175Schristos#
39*c29d5175Schristos# NOTES:
40*c29d5175Schristos#
41*c29d5175Schristos#  An event is considered random when the heads seek. This program prints
42*c29d5175Schristos#  the percentage of events that are random. The size of the seek is not
43*c29d5175Schristos#  measured - it's either random or not.
44*c29d5175Schristos#
45*c29d5175Schristos# SEE ALSO: iosnoop, iotop
46*c29d5175Schristos#
47*c29d5175Schristos# IDEA: Ryan Matteson
48*c29d5175Schristos#
49*c29d5175Schristos# COPYRIGHT: Copyright (c) 2005 Brendan Gregg.
50*c29d5175Schristos#
51*c29d5175Schristos# CDDL HEADER START
52*c29d5175Schristos#
53*c29d5175Schristos#  The contents of this file are subject to the terms of the
54*c29d5175Schristos#  Common Development and Distribution License, Version 1.0 only
55*c29d5175Schristos#  (the "License").  You may not use this file except in compliance
56*c29d5175Schristos#  with the License.
57*c29d5175Schristos#
58*c29d5175Schristos#  You can obtain a copy of the license at Docs/cddl1.txt
59*c29d5175Schristos#  or http://www.opensolaris.org/os/licensing.
60*c29d5175Schristos#  See the License for the specific language governing permissions
61*c29d5175Schristos#  and limitations under the License.
62*c29d5175Schristos#
63*c29d5175Schristos# CDDL HEADER END
64*c29d5175Schristos#
65*c29d5175Schristos# Author: Brendan Gregg  [Sydney, Australia]
66*c29d5175Schristos#
67*c29d5175Schristos# 25-Jul-2005	Brendan Gregg	Created this.
68*c29d5175Schristos# 25-Jul-2005	   "      "	Last update.
69*c29d5175Schristos#
70*c29d5175Schristos
71*c29d5175Schristos
72*c29d5175Schristos##############################
73*c29d5175Schristos# --- Process Arguments ---
74*c29d5175Schristos#
75*c29d5175Schristos
76*c29d5175Schristos### default variables
77*c29d5175Schristosopt_device=0; opt_file=0; opt_mount=0; opt_time=0
78*c29d5175Schristosfilter=0; device=.; filename=.; mount=.; interval=1; count=-1
79*c29d5175Schristos
80*c29d5175Schristos### process options
81*c29d5175Schristoswhile getopts d:f:hm:v name
82*c29d5175Schristosdo
83*c29d5175Schristos	case $name in
84*c29d5175Schristos	d)	opt_device=1; device=$OPTARG ;;
85*c29d5175Schristos	f)	opt_file=1; filename=$OPTARG ;;
86*c29d5175Schristos	m)	opt_mount=1; mount=$OPTARG ;;
87*c29d5175Schristos	v)	opt_time=1 ;;
88*c29d5175Schristos	h|?)	cat <<-END >&2
89*c29d5175Schristos		USAGE: iopattern [-v] [-d device] [-f filename] [-m mount_point]
90*c29d5175Schristos		                 [interval [count]]
91*c29d5175Schristos 
92*c29d5175Schristos		                -v              # print timestamp
93*c29d5175Schristos		                -d device       # instance name to snoop 
94*c29d5175Schristos		                -f filename     # snoop this file only
95*c29d5175Schristos		                -m mount_point  # this FS only 
96*c29d5175Schristos		   eg,
97*c29d5175Schristos		        iopattern         # default output, 1 second samples
98*c29d5175Schristos		        iopattern 10      # 10 second samples
99*c29d5175Schristos		        iopattern 5 12    # print 12 x 5 second samples
100*c29d5175Schristos		        iopattern -m /    # snoop events on filesystem / only
101*c29d5175Schristos		END
102*c29d5175Schristos		exit 1
103*c29d5175Schristos	esac
104*c29d5175Schristosdone
105*c29d5175Schristos
106*c29d5175Schristosshift $(( $OPTIND - 1 ))
107*c29d5175Schristos
108*c29d5175Schristos### option logic
109*c29d5175Schristosif [[ "$1" > 0 ]]; then
110*c29d5175Schristos        interval=$1; shift
111*c29d5175Schristosfi
112*c29d5175Schristosif [[ "$1" > 0 ]]; then
113*c29d5175Schristos        count=$1; shift
114*c29d5175Schristosfi
115*c29d5175Schristosif (( opt_device || opt_mount || opt_file )); then
116*c29d5175Schristos	filter=1
117*c29d5175Schristosfi
118*c29d5175Schristos
119*c29d5175Schristos
120*c29d5175Schristos#################################
121*c29d5175Schristos# --- Main Program, DTrace ---
122*c29d5175Schristos#
123*c29d5175Schristos/usr/sbin/dtrace -n '
124*c29d5175Schristos /*
125*c29d5175Schristos  * Command line arguments
126*c29d5175Schristos  */
127*c29d5175Schristos inline int OPT_time 	= '$opt_time';
128*c29d5175Schristos inline int OPT_device 	= '$opt_device';
129*c29d5175Schristos inline int OPT_mount 	= '$opt_mount';
130*c29d5175Schristos inline int OPT_file 	= '$opt_file';
131*c29d5175Schristos inline int INTERVAL 	= '$interval';
132*c29d5175Schristos inline int COUNTER 	= '$count';
133*c29d5175Schristos inline int FILTER 	= '$filter';
134*c29d5175Schristos inline string DEVICE 	= "'$device'";
135*c29d5175Schristos inline string FILENAME = "'$filename'";
136*c29d5175Schristos inline string MOUNT 	= "'$mount'";
137*c29d5175Schristos
138*c29d5175Schristos #pragma D option quiet
139*c29d5175Schristos
140*c29d5175Schristos int last_loc[string];
141*c29d5175Schristos
142*c29d5175Schristos /*
143*c29d5175Schristos  * Program start
144*c29d5175Schristos  */
145*c29d5175Schristos dtrace:::BEGIN
146*c29d5175Schristos {
147*c29d5175Schristos        /* starting values */
148*c29d5175Schristos	diskcnt = 0;
149*c29d5175Schristos	diskmin = 0;
150*c29d5175Schristos	diskmax = 0;
151*c29d5175Schristos	diskran = 0;
152*c29d5175Schristos	diskr = 0;
153*c29d5175Schristos	diskw = 0;
154*c29d5175Schristos        counts = COUNTER;
155*c29d5175Schristos        secs = INTERVAL;
156*c29d5175Schristos	LINES = 20;
157*c29d5175Schristos	line = 0;
158*c29d5175Schristos	last_event[""] = 0;
159*c29d5175Schristos }
160*c29d5175Schristos
161*c29d5175Schristos /*
162*c29d5175Schristos  * Print header
163*c29d5175Schristos  */
164*c29d5175Schristos profile:::tick-1sec
165*c29d5175Schristos /line <= 0 /
166*c29d5175Schristos {
167*c29d5175Schristos	/* print optional headers */
168*c29d5175Schristos	OPT_time   ? printf("%-20s ", "TIME")  : 1;
169*c29d5175Schristos	OPT_device ? printf("%-9s ", "DEVICE") : 1;
170*c29d5175Schristos	OPT_mount  ? printf("%-12s ", "MOUNT") : 1;
171*c29d5175Schristos	OPT_file   ? printf("%-12s ", "FILE") : 1;
172*c29d5175Schristos
173*c29d5175Schristos	/* print header */
174*c29d5175Schristos	printf("%4s %4s %6s %6s %6s %6s %6s %6s\n",
175*c29d5175Schristos	    "%RAN", "%SEQ", "COUNT", "MIN", "MAX", "AVG", "KR", "KW");
176*c29d5175Schristos
177*c29d5175Schristos	line = LINES;
178*c29d5175Schristos }
179*c29d5175Schristos
180*c29d5175Schristos /*
181*c29d5175Schristos  * Check event is being traced
182*c29d5175Schristos  */
183*c29d5175Schristos io:genunix::done
184*c29d5175Schristos {
185*c29d5175Schristos	/* default is to trace unless filtering */
186*c29d5175Schristos	self->ok = FILTER ? 0 : 1;
187*c29d5175Schristos
188*c29d5175Schristos	/* check each filter */
189*c29d5175Schristos	(OPT_device == 1 && DEVICE == args[1]->dev_statname)? self->ok = 1 : 1;
190*c29d5175Schristos	(OPT_file == 1 && FILENAME == args[2]->fi_pathname) ? self->ok = 1 : 1;
191*c29d5175Schristos	(OPT_mount == 1 && MOUNT == args[2]->fi_mount)  ? self->ok = 1 : 1;
192*c29d5175Schristos }
193*c29d5175Schristos
194*c29d5175Schristos /*
195*c29d5175Schristos  * Process and Print completion
196*c29d5175Schristos  */
197*c29d5175Schristos io:genunix::done
198*c29d5175Schristos /self->ok/
199*c29d5175Schristos {
200*c29d5175Schristos	/*
201*c29d5175Schristos	 * Save details
202*c29d5175Schristos	 */
203*c29d5175Schristos	this->loc = args[0]->b_blkno * 512;
204*c29d5175Schristos	this->pre = last_loc[args[1]->dev_statname];
205*c29d5175Schristos	diskr += args[0]->b_flags & B_READ ? args[0]->b_bcount : 0;
206*c29d5175Schristos	diskw += args[0]->b_flags & B_READ ? 0 : args[0]->b_bcount;
207*c29d5175Schristos	diskran += this->pre == this->loc ? 0 : 1;
208*c29d5175Schristos	diskcnt++;
209*c29d5175Schristos	diskmin = diskmin == 0 ? args[0]->b_bcount :
210*c29d5175Schristos	    (diskmin > args[0]->b_bcount ? args[0]->b_bcount : diskmin);
211*c29d5175Schristos	diskmax = diskmax < args[0]->b_bcount ? args[0]->b_bcount : diskmax;
212*c29d5175Schristos
213*c29d5175Schristos	/* save disk location */
214*c29d5175Schristos	last_loc[args[1]->dev_statname] = this->loc + args[0]->b_bcount;
215*c29d5175Schristos
216*c29d5175Schristos	/* cleanup */
217*c29d5175Schristos	self->ok = 0;
218*c29d5175Schristos }
219*c29d5175Schristos
220*c29d5175Schristos /*
221*c29d5175Schristos  * Timer
222*c29d5175Schristos  */
223*c29d5175Schristos profile:::tick-1sec
224*c29d5175Schristos {
225*c29d5175Schristos	secs--;
226*c29d5175Schristos }
227*c29d5175Schristos
228*c29d5175Schristos /*
229*c29d5175Schristos  * Print Output
230*c29d5175Schristos  */
231*c29d5175Schristos profile:::tick-1sec
232*c29d5175Schristos /secs == 0/
233*c29d5175Schristos {
234*c29d5175Schristos	/* calculate diskavg */
235*c29d5175Schristos	diskavg = diskcnt > 0 ? (diskr + diskw) / diskcnt : 0;
236*c29d5175Schristos
237*c29d5175Schristos	/* convert counters to Kbytes */
238*c29d5175Schristos	diskr /= 1024;
239*c29d5175Schristos	diskw /= 1024;
240*c29d5175Schristos
241*c29d5175Schristos	/* convert to percentages */
242*c29d5175Schristos	diskran = diskcnt == 0 ? 0 : (diskran * 100) / diskcnt;
243*c29d5175Schristos	diskseq = diskcnt == 0 ? 0 : 100 - diskran;
244*c29d5175Schristos
245*c29d5175Schristos	/* print optional fields */
246*c29d5175Schristos	OPT_time   ? printf("%-20Y ", walltimestamp) : 1;
247*c29d5175Schristos	OPT_device ? printf("%-9s ", DEVICE) : 1;
248*c29d5175Schristos	OPT_mount  ? printf("%-12s ", MOUNT) : 1;
249*c29d5175Schristos	OPT_file   ? printf("%-12s ", FILENAME) : 1;
250*c29d5175Schristos
251*c29d5175Schristos	/* print data */
252*c29d5175Schristos	printf("%4d %4d %6d %6d %6d %6d %6d %6d\n",
253*c29d5175Schristos	    diskran, diskseq, diskcnt, diskmin, diskmax, diskavg,
254*c29d5175Schristos	    diskr, diskw);
255*c29d5175Schristos
256*c29d5175Schristos	/* clear data */
257*c29d5175Schristos	diskmin = 0;
258*c29d5175Schristos	diskmax = 0;
259*c29d5175Schristos	diskcnt = 0;
260*c29d5175Schristos	diskran = 0;
261*c29d5175Schristos	diskr = 0;
262*c29d5175Schristos	diskw = 0;
263*c29d5175Schristos
264*c29d5175Schristos	secs = INTERVAL;
265*c29d5175Schristos	counts--;
266*c29d5175Schristos	line--;
267*c29d5175Schristos }
268*c29d5175Schristos
269*c29d5175Schristos /*
270*c29d5175Schristos  * End of program
271*c29d5175Schristos  */
272*c29d5175Schristos profile:::tick-1sec
273*c29d5175Schristos /counts == 0/
274*c29d5175Schristos {
275*c29d5175Schristos	exit(0);
276*c29d5175Schristos }
277*c29d5175Schristos'
278