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