iosnoop revision 1.1 1 1.1 christos #!/usr/bin/sh
2 1.1 christos #
3 1.1 christos # iosnoop - A program to print disk I/O events as they happen, with useful
4 1.1 christos # details such as UID, PID, filename, command, etc.
5 1.1 christos # Written using DTrace (Solaris 10 3/05).
6 1.1 christos #
7 1.1 christos # This is measuring disk events that have made it past system caches.
8 1.1 christos #
9 1.1 christos # $Id: iosnoop,v 1.1 2015/09/30 22:01:06 christos Exp $
10 1.1 christos #
11 1.1 christos # USAGE: iosnoop [-a|-A|-DeghiNostv] [-d device] [-f filename]
12 1.1 christos # [-m mount_point] [-n name] [-p PID]
13 1.1 christos #
14 1.1 christos # iosnoop # default output
15 1.1 christos #
16 1.1 christos # -a # print all data (mostly)
17 1.1 christos # -A # dump all data, space delimited
18 1.1 christos # -D # print time delta, us (elapsed)
19 1.1 christos # -e # print device name
20 1.1 christos # -g # print command arguments
21 1.1 christos # -i # print device instance
22 1.1 christos # -N # print major and minor numbers
23 1.1 christos # -o # print disk delta time, us
24 1.1 christos # -s # print start time, us
25 1.1 christos # -t # print completion time, us
26 1.1 christos # -v # print completion time, string
27 1.1 christos # -d device # instance name to snoop (eg, dad0)
28 1.1 christos # -f filename # full pathname of file to snoop
29 1.1 christos # -m mount_point # this FS only (will skip raw events)
30 1.1 christos # -n name # this process name only
31 1.1 christos # -p PID # this PID only
32 1.1 christos # eg,
33 1.1 christos # iosnoop -v # human readable timestamps
34 1.1 christos # iosnoop -N # print major and minor numbers
35 1.1 christos # iosnoop -m / # snoop events on the root filesystem only
36 1.1 christos #
37 1.1 christos # FIELDS:
38 1.1 christos # UID user ID
39 1.1 christos # PID process ID
40 1.1 christos # PPID parennt process ID
41 1.1 christos # COMM command name for the process
42 1.1 christos # ARGS argument listing for the process
43 1.1 christos # SIZE size of operation, bytes
44 1.1 christos # BLOCK disk block for the operation (location)
45 1.1 christos # STIME timestamp for the disk request, us
46 1.1 christos # TIME timestamp for the disk completion, us
47 1.1 christos # DELTA elapsed time from request to completion, us
48 1.1 christos # DTIME time for disk to complete request, us
49 1.1 christos # STRTIME timestamp for the disk completion, string
50 1.1 christos # DEVICE device name
51 1.1 christos # INS device instance number
52 1.1 christos # D direction, Read or Write
53 1.1 christos # MOUNT mount point
54 1.1 christos # FILE filename (basename) for io operation
55 1.1 christos #
56 1.1 christos # NOTE:
57 1.1 christos # - There are two different delta times reported. -D prints the
58 1.1 christos # elapsed time from the disk request (strategy) to the disk completion
59 1.1 christos # (iodone); -o prints the time for the disk to complete that event
60 1.1 christos # since it's last event (time between iodones), or, the time to the
61 1.1 christos # strategy if the disk had been idle.
62 1.1 christos # - When filtering on PID or process name, be aware that poor disk event
63 1.1 christos # times may be due to events that have been filtered away, for example
64 1.1 christos # another process that may be seeking the disk heads elsewhere.
65 1.1 christos #
66 1.1 christos # SEE ALSO: BigAdmin: DTrace, http://www.sun.com/bigadmin/content/dtrace
67 1.1 christos # Solaris Dynamic Tracing Guide, http://docs.sun.com
68 1.1 christos # DTrace Tools, http://www.brendangregg.com/dtrace.html
69 1.1 christos #
70 1.1 christos # COPYRIGHT: Copyright (c) 2005 Brendan Gregg.
71 1.1 christos #
72 1.1 christos # CDDL HEADER START
73 1.1 christos #
74 1.1 christos # The contents of this file are subject to the terms of the
75 1.1 christos # Common Development and Distribution License, Version 1.0 only
76 1.1 christos # (the "License"). You may not use this file except in compliance
77 1.1 christos # with the License.
78 1.1 christos #
79 1.1 christos # You can obtain a copy of the license at Docs/cddl1.txt
80 1.1 christos # or http://www.opensolaris.org/os/licensing.
81 1.1 christos # See the License for the specific language governing permissions
82 1.1 christos # and limitations under the License.
83 1.1 christos #
84 1.1 christos # CDDL HEADER END
85 1.1 christos #
86 1.1 christos # Author: Brendan Gregg [Sydney, Australia]
87 1.1 christos #
88 1.1 christos # 12-Mar-2004 Brendan Gregg Created this, build 51.
89 1.1 christos # 23-May-2004 " " Fixed mntpt bug.
90 1.1 christos # 10-Oct-2004 " " Rewritten to use the io provider, build 63.
91 1.1 christos # 04-Jan-2005 " " Wrapped in sh to provide options.
92 1.1 christos # 08-May-2005 " " Rewritten for perfromance.
93 1.1 christos # 15-Jul-2005 " " Improved DTIME calculation.
94 1.1 christos # 25-Jul-2005 " " Added -p, -n. Improved code.
95 1.1 christos # 17-Sep-2005 " " Increased switchrate.
96 1.1 christos # 17-Sep-2005 " " Last update.
97 1.1 christos #
98 1.1 christos
99 1.1 christos
100 1.1 christos ##############################
101 1.1 christos # --- Process Arguments ---
102 1.1 christos #
103 1.1 christos
104 1.1 christos ### default variables
105 1.1 christos opt_dump=0; opt_device=0; opt_delta=0; opt_devname=0; opt_file=0; opt_args=0;
106 1.1 christos opt_mount=0; opt_start=0 opt_end=0; opt_endstr=0; opt_ins=0; opt_nums=0
107 1.1 christos opt_dtime=0; filter=0; device=.; filename=.; mount=.; pname=.; pid=0
108 1.1 christos opt_name=0; opt_pid=0
109 1.1 christos
110 1.1 christos ### process options
111 1.1 christos while getopts aAd:Def:ghim:Nn:op:stv name
112 1.1 christos do
113 1.1 christos case $name in
114 1.1 christos a) opt_devname=1; opt_args=1; opt_endstr=1; opt_nums=1 ;;
115 1.1 christos A) opt_dump=1 ;;
116 1.1 christos d) opt_device=1; device=$OPTARG ;;
117 1.1 christos D) opt_delta=1 ;;
118 1.1 christos e) opt_devname=1 ;;
119 1.1 christos f) opt_file=1; filename=$OPTARG ;;
120 1.1 christos g) opt_args=1 ;;
121 1.1 christos i) opt_ins=1 ;;
122 1.1 christos N) opt_nums=1 ;;
123 1.1 christos n) opt_name=1; pname=$OPTARG ;;
124 1.1 christos o) opt_dtime=1 ;;
125 1.1 christos p) opt_pid=1; pid=$OPTARG ;;
126 1.1 christos m) opt_mount=1; mount=$OPTARG ;;
127 1.1 christos s) opt_start=1 ;;
128 1.1 christos t) opt_end=1 ;;
129 1.1 christos v) opt_endstr=1 ;;
130 1.1 christos h|?) cat <<-END >&2
131 1.1 christos USAGE: iosnoop [-a|-A|-DeghiNostv] [-d device] [-f filename]
132 1.1 christos [-m mount_point] [-n name] [-p PID]
133 1.1 christos iosnoop # default output
134 1.1 christos -a # print all data (mostly)
135 1.1 christos -A # dump all data, space delimited
136 1.1 christos -D # print time delta, us (elapsed)
137 1.1 christos -e # print device name
138 1.1 christos -g # print command arguments
139 1.1 christos -i # print device instance
140 1.1 christos -N # print major and minor numbers
141 1.1 christos -o # print disk delta time, us
142 1.1 christos -s # print start time, us
143 1.1 christos -t # print completion time, us
144 1.1 christos -v # print completion time, string
145 1.1 christos -d device # instance name to snoop
146 1.1 christos -f filename # snoop this file only
147 1.1 christos -m mount_point # this FS only
148 1.1 christos -n name # this process name only
149 1.1 christos -p PID # this PID only
150 1.1 christos eg,
151 1.1 christos iosnoop -v # human readable timestamps
152 1.1 christos iosnoop -N # print major and minor numbers
153 1.1 christos iosnoop -m / # snoop events on filesystem / only
154 1.1 christos END
155 1.1 christos exit 1
156 1.1 christos esac
157 1.1 christos done
158 1.1 christos
159 1.1 christos ### option logic
160 1.1 christos if [ $opt_dump -eq 1 ]; then
161 1.1 christos opt_delta=0; opt_devname=0; opt_args=2; opt_start=0;
162 1.1 christos opt_end=0; opt_endstr=0; opt_nums=0; opt_ins=0; opt_dtime=0
163 1.1 christos fi
164 1.1 christos if [ $opt_device -eq 1 -o $opt_file -eq 1 -o $opt_mount -eq 1 -o \
165 1.1 christos $opt_name -eq 1 -o $opt_pid -eq 1 ]; then
166 1.1 christos filter=1
167 1.1 christos fi
168 1.1 christos
169 1.1 christos
170 1.1 christos #################################
171 1.1 christos # --- Main Program, DTrace ---
172 1.1 christos #
173 1.1 christos /usr/sbin/dtrace -n '
174 1.1 christos /*
175 1.1 christos * Command line arguments
176 1.1 christos */
177 1.1 christos inline int OPT_dump = '$opt_dump';
178 1.1 christos inline int OPT_device = '$opt_device';
179 1.1 christos inline int OPT_delta = '$opt_delta';
180 1.1 christos inline int OPT_devname = '$opt_devname';
181 1.1 christos inline int OPT_file = '$opt_file';
182 1.1 christos inline int OPT_args = '$opt_args';
183 1.1 christos inline int OPT_ins = '$opt_ins';
184 1.1 christos inline int OPT_nums = '$opt_nums';
185 1.1 christos inline int OPT_dtime = '$opt_dtime';
186 1.1 christos inline int OPT_mount = '$opt_mount';
187 1.1 christos inline int OPT_start = '$opt_start';
188 1.1 christos inline int OPT_pid = '$opt_pid';
189 1.1 christos inline int OPT_name = '$opt_name';
190 1.1 christos inline int OPT_end = '$opt_end';
191 1.1 christos inline int OPT_endstr = '$opt_endstr';
192 1.1 christos inline int FILTER = '$filter';
193 1.1 christos inline int PID = '$pid';
194 1.1 christos inline string DEVICE = "'$device'";
195 1.1 christos inline string FILENAME = "'$filename'";
196 1.1 christos inline string MOUNT = "'$mount'";
197 1.1 christos inline string NAME = "'$pname'";
198 1.1 christos
199 1.1 christos #pragma D option quiet
200 1.1 christos #pragma D option switchrate=10hz
201 1.1 christos
202 1.1 christos /*
203 1.1 christos * Print header
204 1.1 christos */
205 1.1 christos dtrace:::BEGIN
206 1.1 christos {
207 1.1 christos last_event[""] = 0;
208 1.1 christos
209 1.1 christos /* print optional headers */
210 1.1 christos OPT_start ? printf("%-14s ","STIME") : 1;
211 1.1 christos OPT_end ? printf("%-14s ","TIME") : 1;
212 1.1 christos OPT_endstr ? printf("%-20s ","STRTIME") : 1;
213 1.1 christos OPT_devname ? printf("%-7s ","DEVICE") : 1;
214 1.1 christos OPT_ins ? printf("%-3s ","INS") : 1;
215 1.1 christos OPT_nums ? printf("%-3s %-3s ","MAJ","MIN") : 1;
216 1.1 christos OPT_delta ? printf("%-10s ","DELTA") : 1;
217 1.1 christos OPT_dtime ? printf("%-10s ","DTIME") : 1;
218 1.1 christos
219 1.1 christos /* print main headers */
220 1.1 christos OPT_dump ?
221 1.1 christos printf("%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n",
222 1.1 christos "TIME", "STIME", "DELTA", "DEVICE", "INS", "MAJ", "MIN", "UID",
223 1.1 christos "PID", "PPID", "D", "BLOCK", "SIZE", "MOUNT", "FILE", "PATH",
224 1.1 christos "COMM","ARGS") :
225 1.1 christos printf("%5s %5s %1s %8s %6s ", "UID", "PID", "D", "BLOCK", "SIZE");
226 1.1 christos OPT_args == 0 ? printf("%10s %s\n", "COMM", "PATHNAME") : 1;
227 1.1 christos OPT_args == 1 ? printf("%28s %s\n", "PATHNAME", "ARGS") : 1;
228 1.1 christos }
229 1.1 christos
230 1.1 christos /*
231 1.1 christos * Check event is being traced
232 1.1 christos */
233 1.1 christos io:genunix::start
234 1.1 christos {
235 1.1 christos /* default is to trace unless filtering, */
236 1.1 christos self->ok = FILTER ? 0 : 1;
237 1.1 christos
238 1.1 christos /* check each filter, */
239 1.1 christos (OPT_device == 1 && DEVICE == args[1]->dev_statname)? self->ok = 1 : 1;
240 1.1 christos (OPT_file == 1 && FILENAME == args[2]->fi_pathname) ? self->ok = 1 : 1;
241 1.1 christos (OPT_mount == 1 && MOUNT == args[2]->fi_mount) ? self->ok = 1 : 1;
242 1.1 christos (OPT_name == 1 && NAME == execname) ? self->ok = 1 : 1;
243 1.1 christos (OPT_pid == 1 && PID == pid) ? self->ok = 1 : 1;
244 1.1 christos }
245 1.1 christos
246 1.1 christos /*
247 1.1 christos * Reset last_event for disk idle -> start
248 1.1 christos * this prevents idle time being counted as disk time.
249 1.1 christos */
250 1.1 christos io:genunix::start
251 1.1 christos /! pending[args[1]->dev_statname]/
252 1.1 christos {
253 1.1 christos /* save last disk event */
254 1.1 christos last_event[args[1]->dev_statname] = timestamp;
255 1.1 christos }
256 1.1 christos
257 1.1 christos /*
258 1.1 christos * Store entry details
259 1.1 christos */
260 1.1 christos io:genunix::start
261 1.1 christos /self->ok/
262 1.1 christos {
263 1.1 christos /* these are used as a unique disk event key, */
264 1.1 christos this->dev = args[0]->b_edev;
265 1.1 christos this->blk = args[0]->b_blkno;
266 1.1 christos
267 1.1 christos /* save disk event details, */
268 1.1 christos start_uid[this->dev, this->blk] = uid;
269 1.1 christos start_pid[this->dev, this->blk] = pid;
270 1.1 christos start_ppid[this->dev, this->blk] = ppid;
271 1.1 christos start_args[this->dev, this->blk] = (char *)curpsinfo->pr_psargs;
272 1.1 christos start_comm[this->dev, this->blk] = execname;
273 1.1 christos start_time[this->dev, this->blk] = timestamp;
274 1.1 christos
275 1.1 christos /* increase disk event pending count */
276 1.1 christos pending[args[1]->dev_statname]++;
277 1.1 christos
278 1.1 christos self->ok = 0;
279 1.1 christos }
280 1.1 christos
281 1.1 christos /*
282 1.1 christos * Process and Print completion
283 1.1 christos */
284 1.1 christos io:genunix::done
285 1.1 christos /start_time[args[0]->b_edev, args[0]->b_blkno]/
286 1.1 christos {
287 1.1 christos /* decrease disk event pending count */
288 1.1 christos pending[args[1]->dev_statname]--;
289 1.1 christos
290 1.1 christos /*
291 1.1 christos * Process details
292 1.1 christos */
293 1.1 christos
294 1.1 christos /* fetch entry values */
295 1.1 christos this->dev = args[0]->b_edev;
296 1.1 christos this->blk = args[0]->b_blkno;
297 1.1 christos this->suid = start_uid[this->dev, this->blk];
298 1.1 christos this->spid = start_pid[this->dev, this->blk];
299 1.1 christos this->sppid = start_ppid[this->dev, this->blk];
300 1.1 christos self->sargs = (int)start_args[this->dev, this->blk] == 0 ?
301 1.1 christos "" : start_args[this->dev, this->blk];
302 1.1 christos self->scomm = start_comm[this->dev, this->blk];
303 1.1 christos this->stime = start_time[this->dev, this->blk];
304 1.1 christos this->etime = timestamp; /* endtime */
305 1.1 christos this->delta = this->etime - this->stime;
306 1.1 christos this->dtime = last_event[args[1]->dev_statname] == 0 ? 0 :
307 1.1 christos timestamp - last_event[args[1]->dev_statname];
308 1.1 christos
309 1.1 christos /* memory cleanup */
310 1.1 christos start_uid[this->dev, this->blk] = 0;
311 1.1 christos start_pid[this->dev, this->blk] = 0;
312 1.1 christos start_ppid[this->dev, this->blk] = 0;
313 1.1 christos start_args[this->dev, this->blk] = 0;
314 1.1 christos start_time[this->dev, this->blk] = 0;
315 1.1 christos start_comm[this->dev, this->blk] = 0;
316 1.1 christos start_rw[this->dev, this->blk] = 0;
317 1.1 christos
318 1.1 christos /*
319 1.1 christos * Print details
320 1.1 christos */
321 1.1 christos
322 1.1 christos /* print optional fields */
323 1.1 christos OPT_start ? printf("%-14d ", this->stime/1000) : 1;
324 1.1 christos OPT_end ? printf("%-14d ", this->etime/1000) : 1;
325 1.1 christos OPT_endstr ? printf("%-20Y ", walltimestamp) : 1;
326 1.1 christos OPT_devname ? printf("%-7s ", args[1]->dev_statname) : 1;
327 1.1 christos OPT_ins ? printf("%3d ", args[1]->dev_instance) : 1;
328 1.1 christos OPT_nums ? printf("%3d %3d ",
329 1.1 christos args[1]->dev_major, args[1]->dev_minor) : 1;
330 1.1 christos OPT_delta ? printf("%-10d ", this->delta/1000) : 1;
331 1.1 christos OPT_dtime ? printf("%-10d ", this->dtime/1000) : 1;
332 1.1 christos
333 1.1 christos /* print main fields */
334 1.1 christos OPT_dump ?
335 1.1 christos printf("%d %d %d %s %d %d %d %d %d %d %s %d %d %s %s %s %s %S\n",
336 1.1 christos this->etime/1000, this->stime/1000, this->delta/1000,
337 1.1 christos args[1]->dev_statname, args[1]->dev_instance, args[1]->dev_major,
338 1.1 christos args[1]->dev_minor, this->suid, this->spid, this->sppid,
339 1.1 christos args[0]->b_flags & B_READ ? "R" : "W",
340 1.1 christos args[0]->b_blkno, args[0]->b_bcount, args[2]->fi_mount,
341 1.1 christos args[2]->fi_name, args[2]->fi_pathname, self->scomm, self->sargs) :
342 1.1 christos printf("%5d %5d %1s %8d %6d ",
343 1.1 christos this->suid, this->spid, args[0]->b_flags & B_READ ? "R" : "W",
344 1.1 christos args[0]->b_blkno, args[0]->b_bcount);
345 1.1 christos OPT_args == 0 ? printf("%10s %s\n", self->scomm, args[2]->fi_pathname)
346 1.1 christos : 1;
347 1.1 christos OPT_args == 1 ? printf("%28s %S\n",
348 1.1 christos args[2]->fi_pathname, self->sargs) : 1;
349 1.1 christos
350 1.1 christos /* save last disk event */
351 1.1 christos last_event[args[1]->dev_statname] = timestamp;
352 1.1 christos
353 1.1 christos /* cleanup */
354 1.1 christos self->scomm = 0;
355 1.1 christos self->sargs = 0;
356 1.1 christos }
357 1.1 christos
358 1.1 christos /*
359 1.1 christos * Prevent pending from underflowing
360 1.1 christos * this can happen if this program is started during disk events.
361 1.1 christos */
362 1.1 christos io:genunix::done
363 1.1 christos /pending[args[1]->dev_statname] < 0/
364 1.1 christos {
365 1.1 christos pending[args[1]->dev_statname] = 0;
366 1.1 christos }
367 1.1 christos '
368