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# 23-Apr-2006, ver 0.70 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 75 76############################## 77# --- Process Arguments --- 78# 79 80### default variables 81opt_trace=0; opt_fs=0; opt_stats=1; opt_all=0 82 83### process options 84while getopts t name 85do 86 case $name in 87 t) opt_trace=1 ;; 88 h|?) cat <<-END >&2 89 USAGE: voptrace [-t] [/mountpoint] 90 voptrace # default output 91 -t # trace 92 eg, 93 voptrace -t # trace all file systems 94 voptrace -t /tmp # trace /tmp 95 voptrace /tmp # summary stats for /tmp 96 END 97 exit 1 98 esac 99done 100shift `expr $OPTIND - 1` 101filesys="$1" 102 103### option logic 104if [ $opt_trace -eq 1 ]; then 105 opt_stats=0 106fi 107if [ -z "$filesys" ]; then 108 opt_all=1 109fi 110 111################################# 112# --- Main Program, DTrace --- 113# 114/usr/sbin/dtrace -n ' 115 /* 116 * Command line arguments 117 */ 118 inline int OPT_fs = '$opt_fs'; 119 inline int OPT_all = '$opt_all'; 120 inline int OPT_trace = '$opt_trace'; 121 inline int OPT_stats = '$opt_stats'; 122 inline string FILESYS = "'$filesys'"; 123 124 #pragma D option quiet 125 126 /* 127 * Print header 128 */ 129 dtrace:::BEGIN 130 { 131 last_event[""] = 0; 132 133 /* print main headers */ 134 OPT_stats == 1 ? 135 printf("\033[H\033[2J") : 1; 136 137 OPT_trace == 1 ? 138 printf("%2s %-15s %-10s %51s %2s %8s %8s\n", 139 "", "Event", "Device", "Path", "RW", "Size", "Offset") : 1; 140 self->path = ""; 141 self->trace = 0; 142 } 143 144 dtrace:::BEGIN 145 /OPT_trace == 1/ 146 { 147 /* make D compiler happy */ 148 @vop_iocnt[""] = count(); 149 @vop_cnt[""] = count(); 150 @vop_time[""] = sum(0); 151 trunc(@vop_iocnt); 152 trunc(@vop_cnt); 153 trunc(@vop_time); 154 } 155 156 fbt::fop_*:entry 157 { 158 self->trace = 0; 159 160 /* Get vp: fop_open has a pointer to vp */ 161 this->vpp = (vnode_t **)arg0; 162 self->vp = (vnode_t *)arg0; 163 self->vp = probefunc == "fop_open" ? (vnode_t *)*this->vpp : self->vp; 164 165 /* And the containing vfs */ 166 this->vfsp = self->vp ? self->vp->v_vfsp : 0; 167 168 /* And the paths for the vp and containing vfs */ 169 this->vfsvp = this->vfsp ? 170 (struct vnode *)((vfs_t *)this->vfsp)->vfs_vnodecovered : 0; 171 self->vfspath = this->vfsvp ? stringof(this->vfsvp->v_path) : "unknown"; 172 173 /* Check if we should trace the root fs */ 174 (OPT_all || 175 (FILESYS == "/" && this->vfsp && 176 (this->vfsp == `rootvfs))) ? self->trace = 1 : self->trace; 177 178 /* Check if we should trace the fs */ 179 (OPT_all || (self->vfspath == FILESYS)) ? self->trace = 1 : self->trace; 180 181 self->vfspath = 0; 182 } 183 184 /* 185 * Trace the entry point to each fop 186 */ 187 fbt::fop_*:entry 188 /self->trace/ 189 { 190 self->path = (self->vp != NULL && self->vp->v_path) ? 191 stringof(self->vp->v_path) : "unknown"; 192 193 /* Some fops has the len in arg2 */ 194 (probefunc == "fop_getpage" || 195 probefunc == "fop_putpage" || 196 probefunc == "fop_none") ? self->len = arg2 : 1; 197 198 /* Some fops has the len in arg3 */ 199 (probefunc == "fop_pageio" || 200 probefunc == "fop_none") ? self->len = arg3 : 1; 201 202 /* Some fops has the len in arg4 */ 203 (probefunc == "fop_addmap" || 204 probefunc == "fop_map" || 205 probefunc == "fop_delmap") ? self->len = arg4 : 1; 206 207 /* Some fops has the offset in arg1 */ 208 (probefunc == "fop_addmap" || 209 probefunc == "fop_map" || 210 probefunc == "fop_getpage" || 211 probefunc == "fop_putpage" || 212 probefunc == "fop_seek" || 213 probefunc == "fop_delmap") ? self->off = arg1 : 1; 214 215 /* Some fops has the offset in arg3 */ 216 (probefunc == "fop_close" || 217 probefunc == "fop_pageio") ? self->off = arg3 : 1; 218 219 /* Some fops has the offset in arg4 */ 220 probefunc == "fop_frlock" ? self->off = arg4 : 1; 221 222 /* Some fops has the pathname in arg1 */ 223 self->path = (probefunc == "fop_create" || 224 probefunc == "fop_mkdir" || 225 probefunc == "fop_rmdir" || 226 probefunc == "fop_remove" || 227 probefunc == "fop_lookup") ? 228 strjoin(self->path, strjoin("/", stringof(arg1))) : self->path; 229 230 OPT_trace ? 231 printf("%2s %-15s %-10s %51s %2s %8d %8d\n", 232 "->", probefunc, "-", self->path, "-", 233 self->len, self->off) : 1; 234 235 self->type = probefunc; 236 self->vop_entry[probefunc] = timestamp; 237 } 238 239 fbt::fop_*:return 240 /self->trace == 1/ 241 { 242 OPT_trace ? 243 printf("%2s %-15s %-10s %51s %2s %8d %8d\n", 244 "<-", probefunc, "-", self->path, "-", 245 self->len, self->off) : 1; 246 247 OPT_stats == 1 ? 248 @vop_time[probefunc] = 249 sum(timestamp - self->vop_entry[probefunc]) : 1; 250 OPT_stats == 1 ? 251 @vop_cnt[probefunc] = count() : 1; 252 253 self->path = 0; 254 self->len = 0; 255 self->off = 0; 256 } 257 258 fbt::fop_*:return 259 { 260 self->trace = 0; 261 self->type = 0; 262 self->vp = 0; 263 } 264 265 /* Capture any I/O within this fop */ 266 io:::start 267 /self->trace/ 268 { 269 OPT_stats == 1 ? 270 @vop_iocnt[self->type] = count() : 1; 271 272 OPT_trace == 1? 273 printf("%2s %-15s %-10s %51s %2s %8d %8u\n", 274 "--", self->type, args[1]->dev_statname, 275 self->path, args[0]->b_flags & B_READ ? "R" : "W", 276 args[0]->b_bcount, args[0]->b_blkno) : 1; 277 } 278 279 profile:::tick-5s 280 /OPT_stats == 1/ 281 { 282 /* Print top 20 only */ 283 trunc(@vop_iocnt, 20); 284 trunc(@vop_time, 20); 285 286 /* Display microseconds */ 287 normalize(@vop_time, 1000000); 288 printf("\033[H\033[2J"); 289 printf("%-60s %10s\n", "VOP Physical IO", "Count"); 290 printa("%-60s %10@d\n", @vop_iocnt); 291 printf("\n"); 292 printf("%-60s %10s\n", "VOP Count", "Count"); 293 printa("%-60s %10@d\n", @vop_cnt); 294 printf("\n"); 295 printf("%-60s %10s\n", "VOP Wall Time", "mSeconds"); 296 printa("%-60s %10@d\n", @vop_time); 297 298 /* Clear data */ 299 trunc(@vop_iocnt); 300 trunc(@vop_cnt); 301 trunc(@vop_time); 302 } 303' 304