#
# vopstat - Trace the vnode interface.
# Written using DTrace (Solaris 10 3/05)
#
# Author: Richard McDougall
#
# $Id: vopstat 3 2007-08-01 10:50:08Z brendan $
#
# USAGE: vopstat [-t] [/mountname]
#
# vopstat # default output, summary each 5 secs
# -t # trace activity as it occurs
#
# Example:
#
# ./vopstat
#
# VOP Physical IO Count
# fop_fsync 236
#
# VOP Count Count
# fop_create 1
# fop_fid 1
# fop_lookup 2
# fop_access 3
# fop_read 3
# fop_poll 11
# fop_fsync 31
# fop_putpage 32
# fop_ioctl 115
# fop_write 517
# fop_rwlock 520
# fop_rwunlock 520
# fop_inactive 529
# fop_getattr 1057
#
# VOP Wall Time mSeconds
# fop_fid 0
# fop_access 0
# fop_read 0
# fop_poll 0
# fop_lookup 0
# fop_create 0
# fop_ioctl 0
# fop_putpage 1
# fop_rwunlock 1
# fop_rwlock 1
# fop_inactive 1
# fop_getattr 2
# fop_write 22
# fop_fsync 504
#
# COPYRIGHT: Copyright (c) 2006 Richard McDougall
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License, Version 1.0 only
# (the "License"). You may not use this file except in compliance
# with the License.
#
# See the License for the specific language governing permissions
# and limitations under the License.
#
# CDDL HEADER END
#
# Shell Wrapper Concept by Brendan Gregg
#
# 08-Jan-2006 Richard McDougall Created this.
# 23-Apr-2006 Brendan Gregg Minor style tweaks.
# 23-Apr-2006 " " Last update.
##############################
# --- Process Arguments ---
#
### default variables
### process options
while getopts t name
do
t) opt_trace=1 ;;
h|?) cat <<-END >&2
USAGE: voptrace [-t] [/mountpoint]
voptrace # default output
-t # trace
eg,
voptrace -t # trace all file systems
voptrace -t /tmp # trace /tmp
voptrace /tmp # summary stats for /tmp
END
exit 1
esac
done
shift `expr $OPTIND - 1`
filesys="$1"
### option logic
if [ $opt_trace -eq 1 ]; then
opt_stats=0
fi
if [ -z "$filesys" ]; then
opt_all=1
fi
#################################
# --- Main Program, DTrace ---
#
/usr/sbin/dtrace -n '
/*
* Command line arguments
*/
inline int OPT_fs = '$opt_fs';
inline int OPT_all = '$opt_all';
inline int OPT_trace = '$opt_trace';
inline int OPT_stats = '$opt_stats';
inline string FILESYS = "'$filesys'";
#pragma D option quiet
/*
* Print header
*/
dtrace:::BEGIN
{
last_event[""] = 0;
/* print main headers */
OPT_stats == 1 ?
printf("\033[H\033[2J") : 1;
OPT_trace == 1 ?
printf("%2s %-15s %-10s %51s %2s %8s %8s\n",
"", "Event", "Device", "Path", "RW", "Size", "Offset") : 1;
self->path = "";
self->trace = 0;
}
dtrace:::BEGIN
/OPT_trace == 1/
{
/* make D compiler happy */
@vop_iocnt[""] = count();
@vop_cnt[""] = count();
@vop_time[""] = sum(0);
trunc(@vop_iocnt);
trunc(@vop_cnt);
trunc(@vop_time);
}
fbt::fop_*:entry
{
self->trace = 0;
/* Get vp: fop_open has a pointer to vp */
this->vpp = (vnode_t **)arg0;
self->vp = (vnode_t *)arg0;
self->vp = probefunc == "fop_open" ? (vnode_t *)*this->vpp : self->vp;
/* And the containing vfs */
this->vfsp = self->vp ? self->vp->v_vfsp : 0;
/* And the paths for the vp and containing vfs */
this->vfsvp = this->vfsp ?
(struct vnode *)((vfs_t *)this->vfsp)->vfs_vnodecovered : 0;
self->vfspath = this->vfsvp ? stringof(this->vfsvp->v_path) : "unknown";
/* Check if we should trace the root fs */
(OPT_all ||
(FILESYS == "/" && this->vfsp &&
(this->vfsp == `rootvfs))) ? self->trace = 1 : self->trace;
/* Check if we should trace the fs */
(OPT_all || (self->vfspath == FILESYS)) ? self->trace = 1 : self->trace;
self->vfspath = 0;
}
/*
* Trace the entry point to each fop
*/
fbt::fop_*:entry
/self->trace/
{
self->path = (self->vp != NULL && self->vp->v_path) ?
stringof(self->vp->v_path) : "unknown";
/* Some fops has the len in arg2 */
(probefunc == "fop_getpage" ||
probefunc == "fop_putpage" ||
probefunc == "fop_none") ? self->len = arg2 : 1;
/* Some fops has the len in arg3 */
(probefunc == "fop_pageio" ||
probefunc == "fop_none") ? self->len = arg3 : 1;
/* Some fops has the len in arg4 */
(probefunc == "fop_addmap" ||
probefunc == "fop_map" ||
probefunc == "fop_delmap") ? self->len = arg4 : 1;
/* Some fops has the offset in arg1 */
(probefunc == "fop_addmap" ||
probefunc == "fop_map" ||
probefunc == "fop_getpage" ||
probefunc == "fop_putpage" ||
probefunc == "fop_seek" ||
probefunc == "fop_delmap") ? self->off = arg1 : 1;
/* Some fops has the offset in arg3 */
(probefunc == "fop_close" ||
probefunc == "fop_pageio") ? self->off = arg3 : 1;
/* Some fops has the offset in arg4 */
probefunc == "fop_frlock" ? self->off = arg4 : 1;
/* Some fops has the pathname in arg1 */
self->path = (probefunc == "fop_create" ||
probefunc == "fop_mkdir" ||
probefunc == "fop_rmdir" ||
probefunc == "fop_remove" ||
probefunc == "fop_lookup") ?
strjoin(self->path, strjoin("/", stringof(arg1))) : self->path;
OPT_trace ?
printf("%2s %-15s %-10s %51s %2s %8d %8d\n",
"->", probefunc, "-", self->path, "-",
self->len, self->off) : 1;
self->type = probefunc;
self->vop_entry[probefunc] = timestamp;
}
fbt::fop_*:return
/self->trace == 1/
{
OPT_trace ?
printf("%2s %-15s %-10s %51s %2s %8d %8d\n",
"<-", probefunc, "-", self->path, "-",
self->len, self->off) : 1;
OPT_stats == 1 ?
@vop_time[probefunc] =
sum(timestamp - self->vop_entry[probefunc]) : 1;
OPT_stats == 1 ?
@vop_cnt[probefunc] = count() : 1;
self->path = 0;
self->len = 0;
self->off = 0;
}
fbt::fop_*:return
{
self->trace = 0;
self->type = 0;
self->vp = 0;
}
/* Capture any I/O within this fop */
io:::start
/self->trace/
{
OPT_stats == 1 ?
@vop_iocnt[self->type] = count() : 1;
OPT_trace == 1?
printf("%2s %-15s %-10s %51s %2s %8d %8u\n",
"--", self->type, args[1]->dev_statname,
self->path, args[0]->b_flags & B_READ ? "R" : "W",
args[0]->b_bcount, args[0]->b_blkno) : 1;
}
profile:::tick-5s
/OPT_stats == 1/
{
/* Print top 20 only */
trunc(@vop_iocnt, 20);
trunc(@vop_time, 20);
/* Display microseconds */
normalize(@vop_time, 1000000);
printf("\033[H\033[2J");
printf("%-60s %10s\n", "VOP Physical IO", "Count");
printa("%-60s %10@d\n", @vop_iocnt);
printf("\n");
printf("%-60s %10s\n", "VOP Count", "Count");
printa("%-60s %10@d\n", @vop_cnt);
printf("\n");
printf("%-60s %10s\n", "VOP Wall Time", "mSeconds");
printa("%-60s %10@d\n", @vop_time);
/* Clear data */
trunc(@vop_iocnt);
trunc(@vop_cnt);
trunc(@vop_time);
}
'