c29d517558
unmodified. For others we'll need to add the missing probes and adjust. This is not attached to the build.
368 lines
12 KiB
Bash
Executable File
368 lines
12 KiB
Bash
Executable File
#!/usr/bin/sh
|
|
#
|
|
# iosnoop - A program to print disk I/O events as they happen, with useful
|
|
# details such as UID, PID, filename, command, etc.
|
|
# Written using DTrace (Solaris 10 3/05).
|
|
#
|
|
# This is measuring disk events that have made it past system caches.
|
|
#
|
|
# $Id: iosnoop,v 1.1.1.1 2015/09/30 22:01:06 christos Exp $
|
|
#
|
|
# USAGE: iosnoop [-a|-A|-DeghiNostv] [-d device] [-f filename]
|
|
# [-m mount_point] [-n name] [-p PID]
|
|
#
|
|
# iosnoop # default output
|
|
#
|
|
# -a # print all data (mostly)
|
|
# -A # dump all data, space delimited
|
|
# -D # print time delta, us (elapsed)
|
|
# -e # print device name
|
|
# -g # print command arguments
|
|
# -i # print device instance
|
|
# -N # print major and minor numbers
|
|
# -o # print disk delta time, us
|
|
# -s # print start time, us
|
|
# -t # print completion time, us
|
|
# -v # print completion time, string
|
|
# -d device # instance name to snoop (eg, dad0)
|
|
# -f filename # full pathname of file to snoop
|
|
# -m mount_point # this FS only (will skip raw events)
|
|
# -n name # this process name only
|
|
# -p PID # this PID only
|
|
# eg,
|
|
# iosnoop -v # human readable timestamps
|
|
# iosnoop -N # print major and minor numbers
|
|
# iosnoop -m / # snoop events on the root filesystem only
|
|
#
|
|
# FIELDS:
|
|
# UID user ID
|
|
# PID process ID
|
|
# PPID parennt process ID
|
|
# COMM command name for the process
|
|
# ARGS argument listing for the process
|
|
# SIZE size of operation, bytes
|
|
# BLOCK disk block for the operation (location)
|
|
# STIME timestamp for the disk request, us
|
|
# TIME timestamp for the disk completion, us
|
|
# DELTA elapsed time from request to completion, us
|
|
# DTIME time for disk to complete request, us
|
|
# STRTIME timestamp for the disk completion, string
|
|
# DEVICE device name
|
|
# INS device instance number
|
|
# D direction, Read or Write
|
|
# MOUNT mount point
|
|
# FILE filename (basename) for io operation
|
|
#
|
|
# NOTE:
|
|
# - There are two different delta times reported. -D prints the
|
|
# elapsed time from the disk request (strategy) to the disk completion
|
|
# (iodone); -o prints the time for the disk to complete that event
|
|
# since it's last event (time between iodones), or, the time to the
|
|
# strategy if the disk had been idle.
|
|
# - When filtering on PID or process name, be aware that poor disk event
|
|
# times may be due to events that have been filtered away, for example
|
|
# another process that may be seeking the disk heads elsewhere.
|
|
#
|
|
# SEE ALSO: BigAdmin: DTrace, http://www.sun.com/bigadmin/content/dtrace
|
|
# Solaris Dynamic Tracing Guide, http://docs.sun.com
|
|
# DTrace Tools, http://www.brendangregg.com/dtrace.html
|
|
#
|
|
# COPYRIGHT: Copyright (c) 2005 Brendan Gregg.
|
|
#
|
|
# 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.
|
|
#
|
|
# You can obtain a copy of the license at Docs/cddl1.txt
|
|
# or http://www.opensolaris.org/os/licensing.
|
|
# See the License for the specific language governing permissions
|
|
# and limitations under the License.
|
|
#
|
|
# CDDL HEADER END
|
|
#
|
|
# Author: Brendan Gregg [Sydney, Australia]
|
|
#
|
|
# 12-Mar-2004 Brendan Gregg Created this, build 51.
|
|
# 23-May-2004 " " Fixed mntpt bug.
|
|
# 10-Oct-2004 " " Rewritten to use the io provider, build 63.
|
|
# 04-Jan-2005 " " Wrapped in sh to provide options.
|
|
# 08-May-2005 " " Rewritten for perfromance.
|
|
# 15-Jul-2005 " " Improved DTIME calculation.
|
|
# 25-Jul-2005 " " Added -p, -n. Improved code.
|
|
# 17-Sep-2005 " " Increased switchrate.
|
|
# 17-Sep-2005 " " Last update.
|
|
#
|
|
|
|
|
|
##############################
|
|
# --- Process Arguments ---
|
|
#
|
|
|
|
### default variables
|
|
opt_dump=0; opt_device=0; opt_delta=0; opt_devname=0; opt_file=0; opt_args=0;
|
|
opt_mount=0; opt_start=0 opt_end=0; opt_endstr=0; opt_ins=0; opt_nums=0
|
|
opt_dtime=0; filter=0; device=.; filename=.; mount=.; pname=.; pid=0
|
|
opt_name=0; opt_pid=0
|
|
|
|
### process options
|
|
while getopts aAd:Def:ghim:Nn:op:stv name
|
|
do
|
|
case $name in
|
|
a) opt_devname=1; opt_args=1; opt_endstr=1; opt_nums=1 ;;
|
|
A) opt_dump=1 ;;
|
|
d) opt_device=1; device=$OPTARG ;;
|
|
D) opt_delta=1 ;;
|
|
e) opt_devname=1 ;;
|
|
f) opt_file=1; filename=$OPTARG ;;
|
|
g) opt_args=1 ;;
|
|
i) opt_ins=1 ;;
|
|
N) opt_nums=1 ;;
|
|
n) opt_name=1; pname=$OPTARG ;;
|
|
o) opt_dtime=1 ;;
|
|
p) opt_pid=1; pid=$OPTARG ;;
|
|
m) opt_mount=1; mount=$OPTARG ;;
|
|
s) opt_start=1 ;;
|
|
t) opt_end=1 ;;
|
|
v) opt_endstr=1 ;;
|
|
h|?) cat <<-END >&2
|
|
USAGE: iosnoop [-a|-A|-DeghiNostv] [-d device] [-f filename]
|
|
[-m mount_point] [-n name] [-p PID]
|
|
iosnoop # default output
|
|
-a # print all data (mostly)
|
|
-A # dump all data, space delimited
|
|
-D # print time delta, us (elapsed)
|
|
-e # print device name
|
|
-g # print command arguments
|
|
-i # print device instance
|
|
-N # print major and minor numbers
|
|
-o # print disk delta time, us
|
|
-s # print start time, us
|
|
-t # print completion time, us
|
|
-v # print completion time, string
|
|
-d device # instance name to snoop
|
|
-f filename # snoop this file only
|
|
-m mount_point # this FS only
|
|
-n name # this process name only
|
|
-p PID # this PID only
|
|
eg,
|
|
iosnoop -v # human readable timestamps
|
|
iosnoop -N # print major and minor numbers
|
|
iosnoop -m / # snoop events on filesystem / only
|
|
END
|
|
exit 1
|
|
esac
|
|
done
|
|
|
|
### option logic
|
|
if [ $opt_dump -eq 1 ]; then
|
|
opt_delta=0; opt_devname=0; opt_args=2; opt_start=0;
|
|
opt_end=0; opt_endstr=0; opt_nums=0; opt_ins=0; opt_dtime=0
|
|
fi
|
|
if [ $opt_device -eq 1 -o $opt_file -eq 1 -o $opt_mount -eq 1 -o \
|
|
$opt_name -eq 1 -o $opt_pid -eq 1 ]; then
|
|
filter=1
|
|
fi
|
|
|
|
|
|
#################################
|
|
# --- Main Program, DTrace ---
|
|
#
|
|
/usr/sbin/dtrace -n '
|
|
/*
|
|
* Command line arguments
|
|
*/
|
|
inline int OPT_dump = '$opt_dump';
|
|
inline int OPT_device = '$opt_device';
|
|
inline int OPT_delta = '$opt_delta';
|
|
inline int OPT_devname = '$opt_devname';
|
|
inline int OPT_file = '$opt_file';
|
|
inline int OPT_args = '$opt_args';
|
|
inline int OPT_ins = '$opt_ins';
|
|
inline int OPT_nums = '$opt_nums';
|
|
inline int OPT_dtime = '$opt_dtime';
|
|
inline int OPT_mount = '$opt_mount';
|
|
inline int OPT_start = '$opt_start';
|
|
inline int OPT_pid = '$opt_pid';
|
|
inline int OPT_name = '$opt_name';
|
|
inline int OPT_end = '$opt_end';
|
|
inline int OPT_endstr = '$opt_endstr';
|
|
inline int FILTER = '$filter';
|
|
inline int PID = '$pid';
|
|
inline string DEVICE = "'$device'";
|
|
inline string FILENAME = "'$filename'";
|
|
inline string MOUNT = "'$mount'";
|
|
inline string NAME = "'$pname'";
|
|
|
|
#pragma D option quiet
|
|
#pragma D option switchrate=10hz
|
|
|
|
/*
|
|
* Print header
|
|
*/
|
|
dtrace:::BEGIN
|
|
{
|
|
last_event[""] = 0;
|
|
|
|
/* print optional headers */
|
|
OPT_start ? printf("%-14s ","STIME") : 1;
|
|
OPT_end ? printf("%-14s ","TIME") : 1;
|
|
OPT_endstr ? printf("%-20s ","STRTIME") : 1;
|
|
OPT_devname ? printf("%-7s ","DEVICE") : 1;
|
|
OPT_ins ? printf("%-3s ","INS") : 1;
|
|
OPT_nums ? printf("%-3s %-3s ","MAJ","MIN") : 1;
|
|
OPT_delta ? printf("%-10s ","DELTA") : 1;
|
|
OPT_dtime ? printf("%-10s ","DTIME") : 1;
|
|
|
|
/* print main headers */
|
|
OPT_dump ?
|
|
printf("%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n",
|
|
"TIME", "STIME", "DELTA", "DEVICE", "INS", "MAJ", "MIN", "UID",
|
|
"PID", "PPID", "D", "BLOCK", "SIZE", "MOUNT", "FILE", "PATH",
|
|
"COMM","ARGS") :
|
|
printf("%5s %5s %1s %8s %6s ", "UID", "PID", "D", "BLOCK", "SIZE");
|
|
OPT_args == 0 ? printf("%10s %s\n", "COMM", "PATHNAME") : 1;
|
|
OPT_args == 1 ? printf("%28s %s\n", "PATHNAME", "ARGS") : 1;
|
|
}
|
|
|
|
/*
|
|
* Check event is being traced
|
|
*/
|
|
io:genunix::start
|
|
{
|
|
/* default is to trace unless filtering, */
|
|
self->ok = FILTER ? 0 : 1;
|
|
|
|
/* check each filter, */
|
|
(OPT_device == 1 && DEVICE == args[1]->dev_statname)? self->ok = 1 : 1;
|
|
(OPT_file == 1 && FILENAME == args[2]->fi_pathname) ? self->ok = 1 : 1;
|
|
(OPT_mount == 1 && MOUNT == args[2]->fi_mount) ? self->ok = 1 : 1;
|
|
(OPT_name == 1 && NAME == execname) ? self->ok = 1 : 1;
|
|
(OPT_pid == 1 && PID == pid) ? self->ok = 1 : 1;
|
|
}
|
|
|
|
/*
|
|
* Reset last_event for disk idle -> start
|
|
* this prevents idle time being counted as disk time.
|
|
*/
|
|
io:genunix::start
|
|
/! pending[args[1]->dev_statname]/
|
|
{
|
|
/* save last disk event */
|
|
last_event[args[1]->dev_statname] = timestamp;
|
|
}
|
|
|
|
/*
|
|
* Store entry details
|
|
*/
|
|
io:genunix::start
|
|
/self->ok/
|
|
{
|
|
/* these are used as a unique disk event key, */
|
|
this->dev = args[0]->b_edev;
|
|
this->blk = args[0]->b_blkno;
|
|
|
|
/* save disk event details, */
|
|
start_uid[this->dev, this->blk] = uid;
|
|
start_pid[this->dev, this->blk] = pid;
|
|
start_ppid[this->dev, this->blk] = ppid;
|
|
start_args[this->dev, this->blk] = (char *)curpsinfo->pr_psargs;
|
|
start_comm[this->dev, this->blk] = execname;
|
|
start_time[this->dev, this->blk] = timestamp;
|
|
|
|
/* increase disk event pending count */
|
|
pending[args[1]->dev_statname]++;
|
|
|
|
self->ok = 0;
|
|
}
|
|
|
|
/*
|
|
* Process and Print completion
|
|
*/
|
|
io:genunix::done
|
|
/start_time[args[0]->b_edev, args[0]->b_blkno]/
|
|
{
|
|
/* decrease disk event pending count */
|
|
pending[args[1]->dev_statname]--;
|
|
|
|
/*
|
|
* Process details
|
|
*/
|
|
|
|
/* fetch entry values */
|
|
this->dev = args[0]->b_edev;
|
|
this->blk = args[0]->b_blkno;
|
|
this->suid = start_uid[this->dev, this->blk];
|
|
this->spid = start_pid[this->dev, this->blk];
|
|
this->sppid = start_ppid[this->dev, this->blk];
|
|
self->sargs = (int)start_args[this->dev, this->blk] == 0 ?
|
|
"" : start_args[this->dev, this->blk];
|
|
self->scomm = start_comm[this->dev, this->blk];
|
|
this->stime = start_time[this->dev, this->blk];
|
|
this->etime = timestamp; /* endtime */
|
|
this->delta = this->etime - this->stime;
|
|
this->dtime = last_event[args[1]->dev_statname] == 0 ? 0 :
|
|
timestamp - last_event[args[1]->dev_statname];
|
|
|
|
/* memory cleanup */
|
|
start_uid[this->dev, this->blk] = 0;
|
|
start_pid[this->dev, this->blk] = 0;
|
|
start_ppid[this->dev, this->blk] = 0;
|
|
start_args[this->dev, this->blk] = 0;
|
|
start_time[this->dev, this->blk] = 0;
|
|
start_comm[this->dev, this->blk] = 0;
|
|
start_rw[this->dev, this->blk] = 0;
|
|
|
|
/*
|
|
* Print details
|
|
*/
|
|
|
|
/* print optional fields */
|
|
OPT_start ? printf("%-14d ", this->stime/1000) : 1;
|
|
OPT_end ? printf("%-14d ", this->etime/1000) : 1;
|
|
OPT_endstr ? printf("%-20Y ", walltimestamp) : 1;
|
|
OPT_devname ? printf("%-7s ", args[1]->dev_statname) : 1;
|
|
OPT_ins ? printf("%3d ", args[1]->dev_instance) : 1;
|
|
OPT_nums ? printf("%3d %3d ",
|
|
args[1]->dev_major, args[1]->dev_minor) : 1;
|
|
OPT_delta ? printf("%-10d ", this->delta/1000) : 1;
|
|
OPT_dtime ? printf("%-10d ", this->dtime/1000) : 1;
|
|
|
|
/* print main fields */
|
|
OPT_dump ?
|
|
printf("%d %d %d %s %d %d %d %d %d %d %s %d %d %s %s %s %s %S\n",
|
|
this->etime/1000, this->stime/1000, this->delta/1000,
|
|
args[1]->dev_statname, args[1]->dev_instance, args[1]->dev_major,
|
|
args[1]->dev_minor, this->suid, this->spid, this->sppid,
|
|
args[0]->b_flags & B_READ ? "R" : "W",
|
|
args[0]->b_blkno, args[0]->b_bcount, args[2]->fi_mount,
|
|
args[2]->fi_name, args[2]->fi_pathname, self->scomm, self->sargs) :
|
|
printf("%5d %5d %1s %8d %6d ",
|
|
this->suid, this->spid, args[0]->b_flags & B_READ ? "R" : "W",
|
|
args[0]->b_blkno, args[0]->b_bcount);
|
|
OPT_args == 0 ? printf("%10s %s\n", self->scomm, args[2]->fi_pathname)
|
|
: 1;
|
|
OPT_args == 1 ? printf("%28s %S\n",
|
|
args[2]->fi_pathname, self->sargs) : 1;
|
|
|
|
/* save last disk event */
|
|
last_event[args[1]->dev_statname] = timestamp;
|
|
|
|
/* cleanup */
|
|
self->scomm = 0;
|
|
self->sargs = 0;
|
|
}
|
|
|
|
/*
|
|
* Prevent pending from underflowing
|
|
* this can happen if this program is started during disk events.
|
|
*/
|
|
io:genunix::done
|
|
/pending[args[1]->dev_statname] < 0/
|
|
{
|
|
pending[args[1]->dev_statname] = 0;
|
|
}
|
|
'
|