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