vopstat revision 1.1.1.1 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
82 opt_trace=0; opt_fs=0; opt_stats=1; opt_all=0
83
84 ### process options
85 while getopts t name
86 do
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
100 done
101 shift `expr $OPTIND - 1`
102 filesys="$1"
103
104 ### option logic
105 if [ $opt_trace -eq 1 ]; then
106 opt_stats=0
107 fi
108 if [ -z "$filesys" ]; then
109 opt_all=1
110 fi
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