#!/usr/bin/sh
opt_trace=0; opt_fs=0; opt_stats=1; opt_all=0
while getopts t name
do
case $name in
t) opt_trace=1 ;;
h|?) cat <<-END >&2
USAGE: voptrace [-t] [/mountpoint]
voptrace -t eg,
voptrace -t voptrace -t /tmp voptrace /tmp END
exit 1
esac
done
shift `expr $OPTIND - 1`
filesys="$1"
if [ $opt_trace -eq 1 ]; then
opt_stats=0
fi
if [ -z "$filesys" ]; then
opt_all=1
fi
/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'";
/*
* 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);
}
'