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