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