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