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