1*c29d5175Schristos#!/usr/bin/sh 2*c29d5175Schristos# 3*c29d5175Schristos# iosnoop - A program to print disk I/O events as they happen, with useful 4*c29d5175Schristos# details such as UID, PID, filename, command, etc. 5*c29d5175Schristos# Written using DTrace (Solaris 10 3/05). 6*c29d5175Schristos# 7*c29d5175Schristos# This is measuring disk events that have made it past system caches. 8*c29d5175Schristos# 9*c29d5175Schristos# $Id: iosnoop,v 1.1.1.1 2015/09/30 22:01:07 christos Exp $ 10*c29d5175Schristos# 11*c29d5175Schristos# USAGE: iosnoop [-a|-A|-DeghiNostv] [-d device] [-f filename] 12*c29d5175Schristos# [-m mount_point] [-n name] [-p PID] 13*c29d5175Schristos# 14*c29d5175Schristos# iosnoop # default output 15*c29d5175Schristos# 16*c29d5175Schristos# -a # print all data (mostly) 17*c29d5175Schristos# -A # dump all data, space delimited 18*c29d5175Schristos# -D # print time delta, us (elapsed) 19*c29d5175Schristos# -e # print device name 20*c29d5175Schristos# -g # print command arguments 21*c29d5175Schristos# -i # print device instance 22*c29d5175Schristos# -N # print major and minor numbers 23*c29d5175Schristos# -o # print disk delta time, us 24*c29d5175Schristos# -s # print start time, us 25*c29d5175Schristos# -t # print completion time, us 26*c29d5175Schristos# -v # print completion time, string 27*c29d5175Schristos# -d device # instance name to snoop (eg, dad0) 28*c29d5175Schristos# -f filename # full pathname of file to snoop 29*c29d5175Schristos# -m mount_point # this FS only (will skip raw events) 30*c29d5175Schristos# -n name # this process name only 31*c29d5175Schristos# -p PID # this PID only 32*c29d5175Schristos# eg, 33*c29d5175Schristos# iosnoop -v # human readable timestamps 34*c29d5175Schristos# iosnoop -N # print major and minor numbers 35*c29d5175Schristos# iosnoop -m / # snoop events on the root filesystem only 36*c29d5175Schristos# 37*c29d5175Schristos# FIELDS: 38*c29d5175Schristos# UID user ID 39*c29d5175Schristos# PID process ID 40*c29d5175Schristos# PPID parennt process ID 41*c29d5175Schristos# COMM command name for the process 42*c29d5175Schristos# ARGS argument listing for the process 43*c29d5175Schristos# SIZE size of operation, bytes 44*c29d5175Schristos# BLOCK disk block for the operation (location) 45*c29d5175Schristos# STIME timestamp for the disk request, us 46*c29d5175Schristos# TIME timestamp for the disk completion, us 47*c29d5175Schristos# DELTA elapsed time from request to completion, us 48*c29d5175Schristos# DTIME time for disk to complete request, us 49*c29d5175Schristos# STRTIME timestamp for the disk completion, string 50*c29d5175Schristos# DEVICE device name 51*c29d5175Schristos# INS device instance number 52*c29d5175Schristos# D direction, Read or Write 53*c29d5175Schristos# MOUNT mount point 54*c29d5175Schristos# FILE filename (basename) for io operation 55*c29d5175Schristos# 56*c29d5175Schristos# NOTE: 57*c29d5175Schristos# - There are two different delta times reported. -D prints the 58*c29d5175Schristos# elapsed time from the disk request (strategy) to the disk completion 59*c29d5175Schristos# (iodone); -o prints the time for the disk to complete that event 60*c29d5175Schristos# since it's last event (time between iodones), or, the time to the 61*c29d5175Schristos# strategy if the disk had been idle. 62*c29d5175Schristos# - When filtering on PID or process name, be aware that poor disk event 63*c29d5175Schristos# times may be due to events that have been filtered away, for example 64*c29d5175Schristos# another process that may be seeking the disk heads elsewhere. 65*c29d5175Schristos# 66*c29d5175Schristos# SEE ALSO: BigAdmin: DTrace, http://www.sun.com/bigadmin/content/dtrace 67*c29d5175Schristos# Solaris Dynamic Tracing Guide, http://docs.sun.com 68*c29d5175Schristos# DTrace Tools, http://www.brendangregg.com/dtrace.html 69*c29d5175Schristos# 70*c29d5175Schristos# COPYRIGHT: Copyright (c) 2005 Brendan Gregg. 71*c29d5175Schristos# 72*c29d5175Schristos# CDDL HEADER START 73*c29d5175Schristos# 74*c29d5175Schristos# The contents of this file are subject to the terms of the 75*c29d5175Schristos# Common Development and Distribution License, Version 1.0 only 76*c29d5175Schristos# (the "License"). You may not use this file except in compliance 77*c29d5175Schristos# with the License. 78*c29d5175Schristos# 79*c29d5175Schristos# You can obtain a copy of the license at Docs/cddl1.txt 80*c29d5175Schristos# or http://www.opensolaris.org/os/licensing. 81*c29d5175Schristos# See the License for the specific language governing permissions 82*c29d5175Schristos# and limitations under the License. 83*c29d5175Schristos# 84*c29d5175Schristos# CDDL HEADER END 85*c29d5175Schristos# 86*c29d5175Schristos# Author: Brendan Gregg [Sydney, Australia] 87*c29d5175Schristos# 88*c29d5175Schristos# 12-Mar-2004 Brendan Gregg Created this, build 51. 89*c29d5175Schristos# 23-May-2004 " " Fixed mntpt bug. 90*c29d5175Schristos# 10-Oct-2004 " " Rewritten to use the io provider, build 63. 91*c29d5175Schristos# 04-Jan-2005 " " Wrapped in sh to provide options. 92*c29d5175Schristos# 08-May-2005 " " Rewritten for perfromance. 93*c29d5175Schristos# 15-Jul-2005 " " Improved DTIME calculation. 94*c29d5175Schristos# 25-Jul-2005 " " Added -p, -n. Improved code. 95*c29d5175Schristos# 17-Sep-2005 " " Increased switchrate. 96*c29d5175Schristos# 17-Sep-2005 " " Last update. 97*c29d5175Schristos# 98*c29d5175Schristos 99*c29d5175Schristos 100*c29d5175Schristos############################## 101*c29d5175Schristos# --- Process Arguments --- 102*c29d5175Schristos# 103*c29d5175Schristos 104*c29d5175Schristos### default variables 105*c29d5175Schristosopt_dump=0; opt_device=0; opt_delta=0; opt_devname=0; opt_file=0; opt_args=0; 106*c29d5175Schristosopt_mount=0; opt_start=0 opt_end=0; opt_endstr=0; opt_ins=0; opt_nums=0 107*c29d5175Schristosopt_dtime=0; filter=0; device=.; filename=.; mount=.; pname=.; pid=0 108*c29d5175Schristosopt_name=0; opt_pid=0 109*c29d5175Schristos 110*c29d5175Schristos### process options 111*c29d5175Schristoswhile getopts aAd:Def:ghim:Nn:op:stv name 112*c29d5175Schristosdo 113*c29d5175Schristos case $name in 114*c29d5175Schristos a) opt_devname=1; opt_args=1; opt_endstr=1; opt_nums=1 ;; 115*c29d5175Schristos A) opt_dump=1 ;; 116*c29d5175Schristos d) opt_device=1; device=$OPTARG ;; 117*c29d5175Schristos D) opt_delta=1 ;; 118*c29d5175Schristos e) opt_devname=1 ;; 119*c29d5175Schristos f) opt_file=1; filename=$OPTARG ;; 120*c29d5175Schristos g) opt_args=1 ;; 121*c29d5175Schristos i) opt_ins=1 ;; 122*c29d5175Schristos N) opt_nums=1 ;; 123*c29d5175Schristos n) opt_name=1; pname=$OPTARG ;; 124*c29d5175Schristos o) opt_dtime=1 ;; 125*c29d5175Schristos p) opt_pid=1; pid=$OPTARG ;; 126*c29d5175Schristos m) opt_mount=1; mount=$OPTARG ;; 127*c29d5175Schristos s) opt_start=1 ;; 128*c29d5175Schristos t) opt_end=1 ;; 129*c29d5175Schristos v) opt_endstr=1 ;; 130*c29d5175Schristos h|?) cat <<-END >&2 131*c29d5175Schristos USAGE: iosnoop [-a|-A|-DeghiNostv] [-d device] [-f filename] 132*c29d5175Schristos [-m mount_point] [-n name] [-p PID] 133*c29d5175Schristos iosnoop # default output 134*c29d5175Schristos -a # print all data (mostly) 135*c29d5175Schristos -A # dump all data, space delimited 136*c29d5175Schristos -D # print time delta, us (elapsed) 137*c29d5175Schristos -e # print device name 138*c29d5175Schristos -g # print command arguments 139*c29d5175Schristos -i # print device instance 140*c29d5175Schristos -N # print major and minor numbers 141*c29d5175Schristos -o # print disk delta time, us 142*c29d5175Schristos -s # print start time, us 143*c29d5175Schristos -t # print completion time, us 144*c29d5175Schristos -v # print completion time, string 145*c29d5175Schristos -d device # instance name to snoop 146*c29d5175Schristos -f filename # snoop this file only 147*c29d5175Schristos -m mount_point # this FS only 148*c29d5175Schristos -n name # this process name only 149*c29d5175Schristos -p PID # this PID only 150*c29d5175Schristos eg, 151*c29d5175Schristos iosnoop -v # human readable timestamps 152*c29d5175Schristos iosnoop -N # print major and minor numbers 153*c29d5175Schristos iosnoop -m / # snoop events on filesystem / only 154*c29d5175Schristos END 155*c29d5175Schristos exit 1 156*c29d5175Schristos esac 157*c29d5175Schristosdone 158*c29d5175Schristos 159*c29d5175Schristos### option logic 160*c29d5175Schristosif [ $opt_dump -eq 1 ]; then 161*c29d5175Schristos opt_delta=0; opt_devname=0; opt_args=2; opt_start=0; 162*c29d5175Schristos opt_end=0; opt_endstr=0; opt_nums=0; opt_ins=0; opt_dtime=0 163*c29d5175Schristosfi 164*c29d5175Schristosif [ $opt_device -eq 1 -o $opt_file -eq 1 -o $opt_mount -eq 1 -o \ 165*c29d5175Schristos $opt_name -eq 1 -o $opt_pid -eq 1 ]; then 166*c29d5175Schristos filter=1 167*c29d5175Schristosfi 168*c29d5175Schristos 169*c29d5175Schristos 170*c29d5175Schristos################################# 171*c29d5175Schristos# --- Main Program, DTrace --- 172*c29d5175Schristos# 173*c29d5175Schristos/usr/sbin/dtrace -n ' 174*c29d5175Schristos /* 175*c29d5175Schristos * Command line arguments 176*c29d5175Schristos */ 177*c29d5175Schristos inline int OPT_dump = '$opt_dump'; 178*c29d5175Schristos inline int OPT_device = '$opt_device'; 179*c29d5175Schristos inline int OPT_delta = '$opt_delta'; 180*c29d5175Schristos inline int OPT_devname = '$opt_devname'; 181*c29d5175Schristos inline int OPT_file = '$opt_file'; 182*c29d5175Schristos inline int OPT_args = '$opt_args'; 183*c29d5175Schristos inline int OPT_ins = '$opt_ins'; 184*c29d5175Schristos inline int OPT_nums = '$opt_nums'; 185*c29d5175Schristos inline int OPT_dtime = '$opt_dtime'; 186*c29d5175Schristos inline int OPT_mount = '$opt_mount'; 187*c29d5175Schristos inline int OPT_start = '$opt_start'; 188*c29d5175Schristos inline int OPT_pid = '$opt_pid'; 189*c29d5175Schristos inline int OPT_name = '$opt_name'; 190*c29d5175Schristos inline int OPT_end = '$opt_end'; 191*c29d5175Schristos inline int OPT_endstr = '$opt_endstr'; 192*c29d5175Schristos inline int FILTER = '$filter'; 193*c29d5175Schristos inline int PID = '$pid'; 194*c29d5175Schristos inline string DEVICE = "'$device'"; 195*c29d5175Schristos inline string FILENAME = "'$filename'"; 196*c29d5175Schristos inline string MOUNT = "'$mount'"; 197*c29d5175Schristos inline string NAME = "'$pname'"; 198*c29d5175Schristos 199*c29d5175Schristos #pragma D option quiet 200*c29d5175Schristos #pragma D option switchrate=10hz 201*c29d5175Schristos 202*c29d5175Schristos /* 203*c29d5175Schristos * Print header 204*c29d5175Schristos */ 205*c29d5175Schristos dtrace:::BEGIN 206*c29d5175Schristos { 207*c29d5175Schristos last_event[""] = 0; 208*c29d5175Schristos 209*c29d5175Schristos /* print optional headers */ 210*c29d5175Schristos OPT_start ? printf("%-14s ","STIME") : 1; 211*c29d5175Schristos OPT_end ? printf("%-14s ","TIME") : 1; 212*c29d5175Schristos OPT_endstr ? printf("%-20s ","STRTIME") : 1; 213*c29d5175Schristos OPT_devname ? printf("%-7s ","DEVICE") : 1; 214*c29d5175Schristos OPT_ins ? printf("%-3s ","INS") : 1; 215*c29d5175Schristos OPT_nums ? printf("%-3s %-3s ","MAJ","MIN") : 1; 216*c29d5175Schristos OPT_delta ? printf("%-10s ","DELTA") : 1; 217*c29d5175Schristos OPT_dtime ? printf("%-10s ","DTIME") : 1; 218*c29d5175Schristos 219*c29d5175Schristos /* print main headers */ 220*c29d5175Schristos OPT_dump ? 221*c29d5175Schristos printf("%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s\n", 222*c29d5175Schristos "TIME", "STIME", "DELTA", "DEVICE", "INS", "MAJ", "MIN", "UID", 223*c29d5175Schristos "PID", "PPID", "D", "BLOCK", "SIZE", "MOUNT", "FILE", "PATH", 224*c29d5175Schristos "COMM","ARGS") : 225*c29d5175Schristos printf("%5s %5s %1s %8s %6s ", "UID", "PID", "D", "BLOCK", "SIZE"); 226*c29d5175Schristos OPT_args == 0 ? printf("%10s %s\n", "COMM", "PATHNAME") : 1; 227*c29d5175Schristos OPT_args == 1 ? printf("%28s %s\n", "PATHNAME", "ARGS") : 1; 228*c29d5175Schristos } 229*c29d5175Schristos 230*c29d5175Schristos /* 231*c29d5175Schristos * Check event is being traced 232*c29d5175Schristos */ 233*c29d5175Schristos io:genunix::start 234*c29d5175Schristos { 235*c29d5175Schristos /* default is to trace unless filtering, */ 236*c29d5175Schristos self->ok = FILTER ? 0 : 1; 237*c29d5175Schristos 238*c29d5175Schristos /* check each filter, */ 239*c29d5175Schristos (OPT_device == 1 && DEVICE == args[1]->dev_statname)? self->ok = 1 : 1; 240*c29d5175Schristos (OPT_file == 1 && FILENAME == args[2]->fi_pathname) ? self->ok = 1 : 1; 241*c29d5175Schristos (OPT_mount == 1 && MOUNT == args[2]->fi_mount) ? self->ok = 1 : 1; 242*c29d5175Schristos (OPT_name == 1 && NAME == execname) ? self->ok = 1 : 1; 243*c29d5175Schristos (OPT_pid == 1 && PID == pid) ? self->ok = 1 : 1; 244*c29d5175Schristos } 245*c29d5175Schristos 246*c29d5175Schristos /* 247*c29d5175Schristos * Reset last_event for disk idle -> start 248*c29d5175Schristos * this prevents idle time being counted as disk time. 249*c29d5175Schristos */ 250*c29d5175Schristos io:genunix::start 251*c29d5175Schristos /! pending[args[1]->dev_statname]/ 252*c29d5175Schristos { 253*c29d5175Schristos /* save last disk event */ 254*c29d5175Schristos last_event[args[1]->dev_statname] = timestamp; 255*c29d5175Schristos } 256*c29d5175Schristos 257*c29d5175Schristos /* 258*c29d5175Schristos * Store entry details 259*c29d5175Schristos */ 260*c29d5175Schristos io:genunix::start 261*c29d5175Schristos /self->ok/ 262*c29d5175Schristos { 263*c29d5175Schristos /* these are used as a unique disk event key, */ 264*c29d5175Schristos this->dev = args[0]->b_edev; 265*c29d5175Schristos this->blk = args[0]->b_blkno; 266*c29d5175Schristos 267*c29d5175Schristos /* save disk event details, */ 268*c29d5175Schristos start_uid[this->dev, this->blk] = uid; 269*c29d5175Schristos start_pid[this->dev, this->blk] = pid; 270*c29d5175Schristos start_ppid[this->dev, this->blk] = ppid; 271*c29d5175Schristos start_args[this->dev, this->blk] = (char *)curpsinfo->pr_psargs; 272*c29d5175Schristos start_comm[this->dev, this->blk] = execname; 273*c29d5175Schristos start_time[this->dev, this->blk] = timestamp; 274*c29d5175Schristos 275*c29d5175Schristos /* increase disk event pending count */ 276*c29d5175Schristos pending[args[1]->dev_statname]++; 277*c29d5175Schristos 278*c29d5175Schristos self->ok = 0; 279*c29d5175Schristos } 280*c29d5175Schristos 281*c29d5175Schristos /* 282*c29d5175Schristos * Process and Print completion 283*c29d5175Schristos */ 284*c29d5175Schristos io:genunix::done 285*c29d5175Schristos /start_time[args[0]->b_edev, args[0]->b_blkno]/ 286*c29d5175Schristos { 287*c29d5175Schristos /* decrease disk event pending count */ 288*c29d5175Schristos pending[args[1]->dev_statname]--; 289*c29d5175Schristos 290*c29d5175Schristos /* 291*c29d5175Schristos * Process details 292*c29d5175Schristos */ 293*c29d5175Schristos 294*c29d5175Schristos /* fetch entry values */ 295*c29d5175Schristos this->dev = args[0]->b_edev; 296*c29d5175Schristos this->blk = args[0]->b_blkno; 297*c29d5175Schristos this->suid = start_uid[this->dev, this->blk]; 298*c29d5175Schristos this->spid = start_pid[this->dev, this->blk]; 299*c29d5175Schristos this->sppid = start_ppid[this->dev, this->blk]; 300*c29d5175Schristos self->sargs = (int)start_args[this->dev, this->blk] == 0 ? 301*c29d5175Schristos "" : start_args[this->dev, this->blk]; 302*c29d5175Schristos self->scomm = start_comm[this->dev, this->blk]; 303*c29d5175Schristos this->stime = start_time[this->dev, this->blk]; 304*c29d5175Schristos this->etime = timestamp; /* endtime */ 305*c29d5175Schristos this->delta = this->etime - this->stime; 306*c29d5175Schristos this->dtime = last_event[args[1]->dev_statname] == 0 ? 0 : 307*c29d5175Schristos timestamp - last_event[args[1]->dev_statname]; 308*c29d5175Schristos 309*c29d5175Schristos /* memory cleanup */ 310*c29d5175Schristos start_uid[this->dev, this->blk] = 0; 311*c29d5175Schristos start_pid[this->dev, this->blk] = 0; 312*c29d5175Schristos start_ppid[this->dev, this->blk] = 0; 313*c29d5175Schristos start_args[this->dev, this->blk] = 0; 314*c29d5175Schristos start_time[this->dev, this->blk] = 0; 315*c29d5175Schristos start_comm[this->dev, this->blk] = 0; 316*c29d5175Schristos start_rw[this->dev, this->blk] = 0; 317*c29d5175Schristos 318*c29d5175Schristos /* 319*c29d5175Schristos * Print details 320*c29d5175Schristos */ 321*c29d5175Schristos 322*c29d5175Schristos /* print optional fields */ 323*c29d5175Schristos OPT_start ? printf("%-14d ", this->stime/1000) : 1; 324*c29d5175Schristos OPT_end ? printf("%-14d ", this->etime/1000) : 1; 325*c29d5175Schristos OPT_endstr ? printf("%-20Y ", walltimestamp) : 1; 326*c29d5175Schristos OPT_devname ? printf("%-7s ", args[1]->dev_statname) : 1; 327*c29d5175Schristos OPT_ins ? printf("%3d ", args[1]->dev_instance) : 1; 328*c29d5175Schristos OPT_nums ? printf("%3d %3d ", 329*c29d5175Schristos args[1]->dev_major, args[1]->dev_minor) : 1; 330*c29d5175Schristos OPT_delta ? printf("%-10d ", this->delta/1000) : 1; 331*c29d5175Schristos OPT_dtime ? printf("%-10d ", this->dtime/1000) : 1; 332*c29d5175Schristos 333*c29d5175Schristos /* print main fields */ 334*c29d5175Schristos OPT_dump ? 335*c29d5175Schristos printf("%d %d %d %s %d %d %d %d %d %d %s %d %d %s %s %s %s %S\n", 336*c29d5175Schristos this->etime/1000, this->stime/1000, this->delta/1000, 337*c29d5175Schristos args[1]->dev_statname, args[1]->dev_instance, args[1]->dev_major, 338*c29d5175Schristos args[1]->dev_minor, this->suid, this->spid, this->sppid, 339*c29d5175Schristos args[0]->b_flags & B_READ ? "R" : "W", 340*c29d5175Schristos args[0]->b_blkno, args[0]->b_bcount, args[2]->fi_mount, 341*c29d5175Schristos args[2]->fi_name, args[2]->fi_pathname, self->scomm, self->sargs) : 342*c29d5175Schristos printf("%5d %5d %1s %8d %6d ", 343*c29d5175Schristos this->suid, this->spid, args[0]->b_flags & B_READ ? "R" : "W", 344*c29d5175Schristos args[0]->b_blkno, args[0]->b_bcount); 345*c29d5175Schristos OPT_args == 0 ? printf("%10s %s\n", self->scomm, args[2]->fi_pathname) 346*c29d5175Schristos : 1; 347*c29d5175Schristos OPT_args == 1 ? printf("%28s %S\n", 348*c29d5175Schristos args[2]->fi_pathname, self->sargs) : 1; 349*c29d5175Schristos 350*c29d5175Schristos /* save last disk event */ 351*c29d5175Schristos last_event[args[1]->dev_statname] = timestamp; 352*c29d5175Schristos 353*c29d5175Schristos /* cleanup */ 354*c29d5175Schristos self->scomm = 0; 355*c29d5175Schristos self->sargs = 0; 356*c29d5175Schristos } 357*c29d5175Schristos 358*c29d5175Schristos /* 359*c29d5175Schristos * Prevent pending from underflowing 360*c29d5175Schristos * this can happen if this program is started during disk events. 361*c29d5175Schristos */ 362*c29d5175Schristos io:genunix::done 363*c29d5175Schristos /pending[args[1]->dev_statname] < 0/ 364*c29d5175Schristos { 365*c29d5175Schristos pending[args[1]->dev_statname] = 0; 366*c29d5175Schristos } 367*c29d5175Schristos' 368