1#!/usr/bin/sh
2#
3# vopstat - Trace the vnode interface.
4#           Written using DTrace (Solaris 10 3/05)
5#
6# Author: Richard McDougall
7#
8# $Id: vopstat,v 1.1.1.1 2015/09/30 22:01:07 christos Exp $
9#
10# USAGE:	vopstat [-t] [/mountname]
11#
12#		vopstat		# default output, summary each 5 secs
13#		-t 		# trace activity as it occurs
14#
15# Example:
16#
17# ./vopstat
18# 
19# VOP Physical IO                                                   Count
20# fop_fsync                                                           236
21# 
22# VOP Count                                                         Count
23# fop_create                                                            1
24# fop_fid                                                               1
25# fop_lookup                                                            2
26# fop_access                                                            3
27# fop_read                                                              3
28# fop_poll                                                             11
29# fop_fsync                                                            31
30# fop_putpage                                                          32
31# fop_ioctl                                                           115
32# fop_write                                                           517
33# fop_rwlock                                                          520
34# fop_rwunlock                                                        520
35# fop_inactive                                                        529
36# fop_getattr                                                        1057
37# 
38# VOP Wall Time                                                  mSeconds
39# fop_fid                                                               0
40# fop_access                                                            0
41# fop_read                                                              0
42# fop_poll                                                              0
43# fop_lookup                                                            0
44# fop_create                                                            0
45# fop_ioctl                                                             0
46# fop_putpage                                                           1
47# fop_rwunlock                                                          1
48# fop_rwlock                                                            1
49# fop_inactive                                                          1
50# fop_getattr                                                           2
51# fop_write                                                            22
52# fop_fsync                                                           504
53# 
54# COPYRIGHT: Copyright (c) 2006 Richard McDougall
55#
56# CDDL HEADER START
57#
58#  The contents of this file are subject to the terms of the
59#  Common Development and Distribution License, Version 1.0 only
60#  (the "License").  You may not use this file except in compliance
61#  with the License.
62#
63#  You can obtain a copy of the license at Docs/cddl1.txt
64#  or http://www.opensolaris.org/os/licensing.
65#  See the License for the specific language governing permissions
66#  and limitations under the License.
67#
68# CDDL HEADER END
69#
70# Shell Wrapper Concept by Brendan Gregg
71#
72# 08-Jan-2006	Richard McDougall	Created this.
73# 23-Apr-2006	Brendan Gregg		Minor style tweaks.
74# 23-Apr-2006	   "      "		Last update.
75
76
77##############################
78# --- Process Arguments ---
79#
80
81### default variables
82opt_trace=0; opt_fs=0; opt_stats=1; opt_all=0
83
84### process options
85while getopts t name
86do
87	case $name in
88	t)	opt_trace=1 ;;
89	h|?)	cat <<-END >&2
90		USAGE: voptrace [-t] [/mountpoint]
91		        voptrace         # default output
92		                 -t      # trace
93		   eg,
94		        voptrace -t      # trace all file systems
95		        voptrace -t /tmp # trace /tmp
96		        voptrace  /tmp   # summary stats for /tmp
97		END
98		exit 1
99	esac
100done
101shift `expr $OPTIND - 1`
102filesys="$1"
103
104### option logic
105if [ $opt_trace -eq 1 ]; then
106	opt_stats=0
107fi
108if [ -z "$filesys" ]; then
109	opt_all=1
110fi
111
112#################################
113# --- Main Program, DTrace ---
114#
115/usr/sbin/dtrace -n '
116 /*
117  * Command line arguments
118  */
119 inline int OPT_fs 	= '$opt_fs';
120 inline int OPT_all 	= '$opt_all';
121 inline int OPT_trace 	= '$opt_trace';
122 inline int OPT_stats 	= '$opt_stats';
123 inline string FILESYS 	= "'$filesys'";
124 
125 #pragma D option quiet
126
127 /*
128  * Print header
129  */
130 dtrace:::BEGIN 
131 {
132	last_event[""] = 0;
133
134	/* print main headers */
135	OPT_stats == 1 ?
136		printf("\033[H\033[2J") : 1;
137
138	OPT_trace == 1 ?
139		printf("%2s %-15s %-10s %51s %2s %8s %8s\n", 
140		    "", "Event", "Device", "Path", "RW", "Size", "Offset") : 1;
141	self->path = "";
142	self->trace = 0;
143 }
144
145 dtrace:::BEGIN
146 /OPT_trace == 1/
147 {
148	/* make D compiler happy */
149	@vop_iocnt[""] = count();
150	@vop_cnt[""]   = count();
151	@vop_time[""]  = sum(0);
152	trunc(@vop_iocnt);
153	trunc(@vop_cnt);
154	trunc(@vop_time);
155 }
156 
157 fbt::fop_*:entry
158 {
159 	self->trace = 0;
160
161 	/* Get vp: fop_open has a pointer to vp */
162 	this->vpp = (vnode_t **)arg0;
163 	self->vp = (vnode_t *)arg0;
164 	self->vp = probefunc == "fop_open" ? (vnode_t *)*this->vpp : self->vp;
165
166 	/* And the containing vfs */
167         this->vfsp = self->vp ? self->vp->v_vfsp : 0;
168
169 	/* And the paths for the vp and containing vfs */
170 	this->vfsvp = this->vfsp ?
171	    (struct vnode *)((vfs_t *)this->vfsp)->vfs_vnodecovered : 0;
172 	self->vfspath = this->vfsvp ? stringof(this->vfsvp->v_path) : "unknown";
173 
174 	/* Check if we should trace the root fs */
175 	(OPT_all || 
176 	    (FILESYS == "/" && this->vfsp &&
177 	    (this->vfsp == `rootvfs))) ? self->trace = 1 : self->trace;
178 
179 	/* Check if we should trace the fs */
180 	(OPT_all || (self->vfspath == FILESYS)) ? self->trace = 1 : self->trace;
181
182	self->vfspath = 0;
183 }
184 
185 /*
186  * Trace the entry point to each fop
187  */ 
188 fbt::fop_*:entry
189 /self->trace/
190 {
191 	self->path = (self->vp != NULL && self->vp->v_path) ?
192	    stringof(self->vp->v_path) : "unknown";
193 
194 	/* Some fops has the len in arg2 */
195 	(probefunc == "fop_getpage" ||
196 	 probefunc == "fop_putpage" ||
197 	 probefunc == "fop_none") ? self->len = arg2 : 1; 
198 
199 	/* Some fops has the len in arg3 */
200 	(probefunc == "fop_pageio" ||
201 	 probefunc == "fop_none") ? self->len = arg3 : 1; 
202 
203 	/* Some fops has the len in arg4 */
204 	(probefunc == "fop_addmap" ||
205 	 probefunc == "fop_map" ||
206 	 probefunc == "fop_delmap") ? self->len = arg4 : 1; 
207 
208 	/* Some fops has the offset in arg1 */
209 	(probefunc == "fop_addmap" ||
210 	 probefunc == "fop_map" ||
211 	 probefunc == "fop_getpage" ||
212 	 probefunc == "fop_putpage" ||
213 	 probefunc == "fop_seek" ||
214 	 probefunc == "fop_delmap") ? self->off = arg1 : 1; 
215 
216 	/* Some fops has the offset in arg3 */
217 	(probefunc == "fop_close" ||
218 	 probefunc == "fop_pageio") ? self->off = arg3 : 1; 
219 
220 	/* Some fops has the offset in arg4 */
221 	probefunc == "fop_frlock" ? self->off = arg4 : 1; 
222 
223 	/* Some fops has the pathname in arg1 */
224 	self->path = (probefunc == "fop_create" ||
225 	 probefunc == "fop_mkdir" ||
226 	 probefunc == "fop_rmdir" ||
227 	 probefunc == "fop_remove" ||
228 	 probefunc == "fop_lookup") ?
229 	    strjoin(self->path, strjoin("/", stringof(arg1))) : self->path;
230 
231	OPT_trace ?
232 		printf("%2s %-15s %-10s %51s %2s %8d %8d\n", 
233 		    "->", probefunc, "-", self->path, "-",
234		    self->len, self->off) : 1;
235
236 	self->type = probefunc;
237 	self->vop_entry[probefunc] = timestamp;
238 }
239 
240 fbt::fop_*:return
241 /self->trace == 1/
242 {
243	OPT_trace ?
244 		printf("%2s %-15s %-10s %51s %2s %8d %8d\n", 
245		    "<-", probefunc, "-", self->path, "-",
246		    self->len, self->off) : 1;
247
248	OPT_stats == 1 ?
249 		@vop_time[probefunc] =
250			sum(timestamp - self->vop_entry[probefunc]) : 1;
251	OPT_stats == 1 ?
252 		@vop_cnt[probefunc] = count() : 1;
253
254	self->path = 0;
255	self->len = 0;
256	self->off = 0;
257 }
258
259 fbt::fop_*:return
260 {
261	self->trace = 0;
262	self->type = 0;
263	self->vp = 0;
264 }
265 
266 /* Capture any I/O within this fop */
267 io:::start
268 /self->trace/
269 {
270	OPT_stats == 1 ?
271 		@vop_iocnt[self->type] = count() : 1;
272
273	OPT_trace == 1?
274	 	printf("%2s %-15s %-10s %51s %2s %8d %8u\n",
275		    "--", self->type, args[1]->dev_statname,
276		    self->path, args[0]->b_flags & B_READ ? "R" : "W",
277		    args[0]->b_bcount, args[0]->b_blkno) : 1;
278 }
279 
280 profile:::tick-5s
281 /OPT_stats == 1/
282 {
283	/* Print top 20 only */
284 	trunc(@vop_iocnt, 20);
285 	trunc(@vop_time, 20);
286
287	/* Display microseconds */
288 	normalize(@vop_time, 1000000);
289 	printf("\033[H\033[2J");
290 	printf("%-60s %10s\n", "VOP Physical IO", "Count");
291 	printa("%-60s %10@d\n", @vop_iocnt);
292 	printf("\n");
293 	printf("%-60s %10s\n", "VOP Count", "Count");
294 	printa("%-60s %10@d\n", @vop_cnt);
295 	printf("\n");
296 	printf("%-60s %10s\n", "VOP Wall Time", "mSeconds");
297 	printa("%-60s %10@d\n", @vop_time);
298
299	/* Clear data */
300 	trunc(@vop_iocnt);
301 	trunc(@vop_cnt);
302 	trunc(@vop_time);
303 }
304'
305