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