1 1.1 christos #!/bin/ksh 2 1.1 christos # 3 1.1 christos # iotop - display top disk I/O events by process. 4 1.1 christos # Written using DTrace (Solaris 10 3/05). 5 1.1 christos # 6 1.1 christos # This is measuring disk events that have made it past system caches. 7 1.1 christos # 8 1.1 christos # $Id: iotop,v 1.1.1.1 2015/09/30 22:01:06 christos Exp $ 9 1.1 christos # 10 1.1 christos # USAGE: iotop [-C] [-D|-o|-P] [-j|-Z] [-d device] [-f filename] 11 1.1 christos # [-m mount_point] [-t top] [interval [count]] 12 1.1 christos # 13 1.1 christos # iotop # default output, 5 second intervals 14 1.1 christos # 15 1.1 christos # -C # don't clear the screen 16 1.1 christos # -D # print delta times, elapsed, us 17 1.1 christos # -j # print project ID 18 1.1 christos # -o # print disk delta times, us 19 1.1 christos # -P # print %I/O (disk delta times) 20 1.1 christos # -Z # print zone ID 21 1.1 christos # -d device # instance name to snoop (eg, dad0) 22 1.1 christos # -f filename # full pathname of file to snoop 23 1.1 christos # -m mount_point # this FS only (will skip raw events) 24 1.1 christos # -t top # print top number only 25 1.1 christos # eg, 26 1.1 christos # iotop 1 # 1 second samples 27 1.1 christos # iotop -C # don't clear the screen 28 1.1 christos # iotop -P # print %I/O (time based) 29 1.1 christos # iotop -j # print project IDs 30 1.1 christos # iotop -Z # print zone IDs 31 1.1 christos # iotop -t 20 # print top 20 lines only 32 1.1 christos # iotop -C 5 12 # print 12 x 5 second samples 33 1.1 christos # 34 1.1 christos # FIELDS: 35 1.1 christos # UID user ID 36 1.1 christos # PID process ID 37 1.1 christos # PPID parent process ID 38 1.1 christos # PROJ project ID 39 1.1 christos # ZONE zone ID 40 1.1 christos # CMD process command name 41 1.1 christos # DEVICE device name 42 1.1 christos # MAJ device major number 43 1.1 christos # MIN device minor number 44 1.1 christos # D direction, Read or Write 45 1.1 christos # BYTES total size of operations, bytes 46 1.1 christos # ELAPSED total elapsed from request to completion, us 47 1.1 christos # DISKTIME total time for disk to complete request, us 48 1.1 christos # %I/O percent disk I/O, based on time (DISKTIME) 49 1.1 christos # load 1 min load average 50 1.1 christos # disk_r total disk read Kbytes for sample 51 1.1 christos # disk_w total disk write Kbytes for sample 52 1.1 christos # 53 1.1 christos # NOTE: 54 1.1 christos # * There are two different delta times reported. -D prints the 55 1.1 christos # elapsed time from the disk request (strategy) to the disk completion 56 1.1 christos # (iodone); -o prints the time for the disk to complete that event 57 1.1 christos # since it's last event (time between iodones), or, the time to the 58 1.1 christos # strategy if the disk had been idle. 59 1.1 christos # * The %I/O value can exceed 100%. It represents how busy a process is 60 1.1 christos # making the disks, in terms of a single disk. A value of 200% could 61 1.1 christos # mean 2 disks are busy at 100%, or 4 disks at 50%... 62 1.1 christos # 63 1.1 christos # SEE ALSO: iosnoop 64 1.1 christos # BigAdmin: DTrace, http://www.sun.com/bigadmin/content/dtrace 65 1.1 christos # Solaris Dynamic Tracing Guide, http://docs.sun.com 66 1.1 christos # DTrace Tools, http://www.brendangregg.com/dtrace.html 67 1.1 christos # 68 1.1 christos # INSPIRATION: top(1) by William LeFebvre 69 1.1 christos # 70 1.1 christos # COPYRIGHT: Copyright (c) 2005, 2006 Brendan Gregg. 71 1.1 christos # 72 1.1 christos # CDDL HEADER START 73 1.1 christos # 74 1.1 christos # The contents of this file are subject to the terms of the 75 1.1 christos # Common Development and Distribution License, Version 1.0 only 76 1.1 christos # (the "License"). You may not use this file except in compliance 77 1.1 christos # with the License. 78 1.1 christos # 79 1.1 christos # You can obtain a copy of the license at Docs/cddl1.txt 80 1.1 christos # or http://www.opensolaris.org/os/licensing. 81 1.1 christos # See the License for the specific language governing permissions 82 1.1 christos # and limitations under the License. 83 1.1 christos # 84 1.1 christos # CDDL HEADER END 85 1.1 christos # 86 1.1 christos # KNOWN BUGS: 87 1.1 christos # - This can print errors while running on servers with Veritas volumes. 88 1.1 christos # 89 1.1 christos # Author: Brendan Gregg [Sydney, Australia] 90 1.1 christos # 91 1.1 christos # 15-Jul-2005 Brendan Gregg Created this. 92 1.1 christos # 20-Apr-2006 " " Last update. 93 1.1 christos # 94 1.1 christos 95 1.1 christos 96 1.1 christos ############################## 97 1.1 christos # --- Process Arguments --- 98 1.1 christos # 99 1.1 christos 100 1.1 christos ### default variables 101 1.1 christos opt_device=0; opt_file=0; opt_mount=0; opt_clear=1; opt_proj=0; opt_zone=0 102 1.1 christos opt_percent=0; opt_def=1; opt_bytes=1; filter=0; device=.; filename=.; mount=. 103 1.1 christos opt_top=0; opt_elapsed=0; opt_dtime=0; interval=5; count=-1; top=0 104 1.1 christos 105 1.1 christos ### process options 106 1.1 christos while getopts CDd:f:hjm:oPt:Z name 107 1.1 christos do 108 1.1 christos case $name in 109 1.1 christos C) opt_clear=0 ;; 110 1.1 christos D) opt_elapsed=1; opt_bytes=0 ;; 111 1.1 christos d) opt_device=1; device=$OPTARG ;; 112 1.1 christos f) opt_file=1; filename=$OPTARG ;; 113 1.1 christos j) opt_proj=1; opt_def=0 ;; 114 1.1 christos m) opt_mount=1; mount=$OPTARG ;; 115 1.1 christos o) opt_dtime=1; opt_bytes=0 ;; 116 1.1 christos P) opt_percent=1; opt_dtime=1; opt_bytes=0 ;; 117 1.1 christos t) opt_top=1; top=$OPTARG ;; 118 1.1 christos Z) opt_zone=1; opt_def=0 ;; 119 1.1 christos h|?) cat <<-END >&2 120 1.1 christos USAGE: iotop [-C] [-D|-o|-P] [-j|-Z] [-d device] [-f filename] 121 1.1 christos [-m mount_point] [-t top] [interval [count]] 122 1.1 christos 123 1.1 christos -C # don't clear the screen 124 1.1 christos -D # print delta times, elapsed, us 125 1.1 christos -j # print project ID 126 1.1 christos -o # print disk delta times, us 127 1.1 christos -P # print %I/O (disk delta times) 128 1.1 christos -Z # print zone ID 129 1.1 christos -d device # instance name to snoop 130 1.1 christos -f filename # snoop this file only 131 1.1 christos -m mount_point # this FS only 132 1.1 christos -t top # print top number only 133 1.1 christos eg, 134 1.1 christos iotop # default output, 5 second samples 135 1.1 christos iotop 1 # 1 second samples 136 1.1 christos iotop -P # print %I/O (time based) 137 1.1 christos iotop -m / # snoop events on filesystem / only 138 1.1 christos iotop -t 20 # print top 20 lines only 139 1.1 christos iotop -C 5 12 # print 12 x 5 second samples 140 1.1 christos END 141 1.1 christos exit 1 142 1.1 christos esac 143 1.1 christos done 144 1.1 christos 145 1.1 christos shift $(( $OPTIND - 1 )) 146 1.1 christos 147 1.1 christos ### option logic 148 1.1 christos if [[ "$1" > 0 ]]; then 149 1.1 christos interval=$1; shift 150 1.1 christos fi 151 1.1 christos if [[ "$1" > 0 ]]; then 152 1.1 christos count=$1; shift 153 1.1 christos fi 154 1.1 christos if (( opt_proj && opt_zone )); then 155 1.1 christos opt_proj=0 156 1.1 christos fi 157 1.1 christos if (( opt_elapsed && opt_dtime )); then 158 1.1 christos opt_elapsed=0 159 1.1 christos fi 160 1.1 christos if (( opt_device || opt_mount || opt_file )); then 161 1.1 christos filter=1 162 1.1 christos fi 163 1.1 christos if (( opt_clear )); then 164 1.1 christos clearstr=`clear` 165 1.1 christos else 166 1.1 christos clearstr=. 167 1.1 christos fi 168 1.1 christos 169 1.1 christos 170 1.1 christos 171 1.1 christos ################################# 172 1.1 christos # --- Main Program, DTrace --- 173 1.1 christos # 174 1.1 christos /usr/sbin/dtrace -n ' 175 1.1 christos /* 176 1.1 christos * Command line arguments 177 1.1 christos */ 178 1.1 christos inline int OPT_def = '$opt_def'; 179 1.1 christos inline int OPT_proj = '$opt_proj'; 180 1.1 christos inline int OPT_zone = '$opt_zone'; 181 1.1 christos inline int OPT_clear = '$opt_clear'; 182 1.1 christos inline int OPT_bytes = '$opt_bytes'; 183 1.1 christos inline int OPT_elapsed = '$opt_elapsed'; 184 1.1 christos inline int OPT_dtime = '$opt_dtime'; 185 1.1 christos inline int OPT_percent = '$opt_percent'; 186 1.1 christos inline int OPT_device = '$opt_device'; 187 1.1 christos inline int OPT_mount = '$opt_mount'; 188 1.1 christos inline int OPT_file = '$opt_file'; 189 1.1 christos inline int OPT_top = '$opt_top'; 190 1.1 christos inline int INTERVAL = '$interval'; 191 1.1 christos inline int COUNTER = '$count'; 192 1.1 christos inline int FILTER = '$filter'; 193 1.1 christos inline int TOP = '$top'; 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 CLEAR = "'$clearstr'"; 198 1.1 christos 199 1.1 christos #pragma D option quiet 200 1.1 christos 201 1.1 christos /* boost the following if you get "dynamic variable drops" */ 202 1.1 christos #pragma D option dynvarsize=8m 203 1.1 christos 204 1.1 christos /* 205 1.1 christos * Print header 206 1.1 christos */ 207 1.1 christos dtrace:::BEGIN 208 1.1 christos { 209 1.1 christos last_event[""] = 0; 210 1.1 christos 211 1.1 christos /* starting values */ 212 1.1 christos counts = COUNTER; 213 1.1 christos secs = INTERVAL; 214 1.1 christos disk_r = 0; 215 1.1 christos disk_w = 0; 216 1.1 christos 217 1.1 christos printf("Tracing... Please wait.\n"); 218 1.1 christos } 219 1.1 christos 220 1.1 christos /* 221 1.1 christos * Check event is being traced 222 1.1 christos */ 223 1.1 christos io:genunix::start, 224 1.1 christos io:genunix::done 225 1.1 christos { 226 1.1 christos /* default is to trace unless filtering, */ 227 1.1 christos this->ok = FILTER ? 0 : 1; 228 1.1 christos 229 1.1 christos /* check each filter, */ 230 1.1 christos (OPT_device == 1 && DEVICE == args[1]->dev_statname)? this->ok = 1 : 1; 231 1.1 christos (OPT_file == 1 && FILENAME == args[2]->fi_pathname) ? this->ok = 1 : 1; 232 1.1 christos (OPT_mount == 1 && MOUNT == args[2]->fi_mount) ? this->ok = 1 : 1; 233 1.1 christos } 234 1.1 christos 235 1.1 christos /* 236 1.1 christos * Reset last_event for disk idle -> start 237 1.1 christos * this prevents idle time being counted as disk time. 238 1.1 christos */ 239 1.1 christos io:genunix::start 240 1.1 christos /! pending[args[1]->dev_statname]/ 241 1.1 christos { 242 1.1 christos /* save last disk event */ 243 1.1 christos last_event[args[1]->dev_statname] = timestamp; 244 1.1 christos } 245 1.1 christos 246 1.1 christos /* 247 1.1 christos * Store entry details 248 1.1 christos */ 249 1.1 christos io:genunix::start 250 1.1 christos /this->ok/ 251 1.1 christos { 252 1.1 christos /* these are used as a unique disk event key, */ 253 1.1 christos this->dev = args[0]->b_edev; 254 1.1 christos this->blk = args[0]->b_blkno; 255 1.1 christos 256 1.1 christos /* save disk event details, */ 257 1.1 christos start_uid[this->dev, this->blk] = uid; 258 1.1 christos start_pid[this->dev, this->blk] = pid; 259 1.1 christos start_ppid[this->dev, this->blk] = ppid; 260 1.1 christos start_comm[this->dev, this->blk] = execname; 261 1.1 christos start_time[this->dev, this->blk] = timestamp; 262 1.1 christos start_proj[this->dev, this->blk] = curpsinfo->pr_projid; 263 1.1 christos start_zone[this->dev, this->blk] = curpsinfo->pr_zoneid; 264 1.1 christos start_rw[this->dev, this->blk] = args[0]->b_flags & B_READ ? "R" : "W"; 265 1.1 christos disk_r += args[0]->b_flags & B_READ ? args[0]->b_bcount : 0; 266 1.1 christos disk_w += args[0]->b_flags & B_READ ? 0 : args[0]->b_bcount; 267 1.1 christos 268 1.1 christos /* increase disk event pending count */ 269 1.1 christos pending[args[1]->dev_statname]++; 270 1.1 christos } 271 1.1 christos 272 1.1 christos /* 273 1.1 christos * Process and Print completion 274 1.1 christos */ 275 1.1 christos io:genunix::done 276 1.1 christos /this->ok/ 277 1.1 christos { 278 1.1 christos /* decrease disk event pending count */ 279 1.1 christos pending[args[1]->dev_statname]--; 280 1.1 christos 281 1.1 christos /* 282 1.1 christos * Process details 283 1.1 christos */ 284 1.1 christos 285 1.1 christos /* fetch entry values */ 286 1.1 christos this->dev = args[0]->b_edev; 287 1.1 christos this->blk = args[0]->b_blkno; 288 1.1 christos this->suid = start_uid[this->dev, this->blk]; 289 1.1 christos this->spid = start_pid[this->dev, this->blk]; 290 1.1 christos this->sppid = start_ppid[this->dev, this->blk]; 291 1.1 christos this->sproj = start_proj[this->dev, this->blk]; 292 1.1 christos this->szone = start_zone[this->dev, this->blk]; 293 1.1 christos self->scomm = start_comm[this->dev, this->blk]; 294 1.1 christos this->stime = start_time[this->dev, this->blk]; 295 1.1 christos this->etime = timestamp; /* endtime */ 296 1.1 christos this->elapsed = this->etime - this->stime; 297 1.1 christos self->rw = start_rw[this->dev, this->blk]; 298 1.1 christos this->dtime = last_event[args[1]->dev_statname] == 0 ? 0 : 299 1.1 christos timestamp - last_event[args[1]->dev_statname]; 300 1.1 christos 301 1.1 christos /* memory cleanup */ 302 1.1 christos start_uid[this->dev, this->blk] = 0; 303 1.1 christos start_pid[this->dev, this->blk] = 0; 304 1.1 christos start_ppid[this->dev, this->blk] = 0; 305 1.1 christos start_time[this->dev, this->blk] = 0; 306 1.1 christos start_comm[this->dev, this->blk] = 0; 307 1.1 christos start_zone[this->dev, this->blk] = 0; 308 1.1 christos start_proj[this->dev, this->blk] = 0; 309 1.1 christos start_rw[this->dev, this->blk] = 0; 310 1.1 christos 311 1.1 christos /* 312 1.1 christos * Choose statistic to track 313 1.1 christos */ 314 1.1 christos OPT_bytes ? this->value = args[0]->b_bcount : 1; 315 1.1 christos OPT_elapsed ? this->value = this->elapsed / 1000 : 1; 316 1.1 christos OPT_dtime ? this->value = this->dtime / 1000 : 1; 317 1.1 christos 318 1.1 christos /* 319 1.1 christos * Save details 320 1.1 christos */ 321 1.1 christos OPT_def ? @out[this->suid, this->spid, this->sppid, self->scomm, 322 1.1 christos args[1]->dev_statname, args[1]->dev_major, args[1]->dev_minor, 323 1.1 christos self->rw] = sum(this->value) : 1; 324 1.1 christos OPT_proj ? @out[this->sproj, this->spid, this->sppid, self->scomm, 325 1.1 christos args[1]->dev_statname, args[1]->dev_major, args[1]->dev_minor, 326 1.1 christos self->rw] = sum(this->value) : 1; 327 1.1 christos OPT_zone ? @out[this->szone, this->spid, this->sppid, self->scomm, 328 1.1 christos args[1]->dev_statname, args[1]->dev_major, args[1]->dev_minor, 329 1.1 christos self->rw] = sum(this->value) : 1; 330 1.1 christos 331 1.1 christos /* save last disk event */ 332 1.1 christos last_event[args[1]->dev_statname] = timestamp; 333 1.1 christos 334 1.1 christos self->scomm = 0; 335 1.1 christos self->rw = 0; 336 1.1 christos } 337 1.1 christos 338 1.1 christos /* 339 1.1 christos * Prevent pending from underflowing 340 1.1 christos * this can happen if this program is started during disk events. 341 1.1 christos */ 342 1.1 christos io:genunix::done 343 1.1 christos /pending[args[1]->dev_statname] < 0/ 344 1.1 christos { 345 1.1 christos pending[args[1]->dev_statname] = 0; 346 1.1 christos } 347 1.1 christos 348 1.1 christos /* 349 1.1 christos * Timer 350 1.1 christos */ 351 1.1 christos profile:::tick-1sec 352 1.1 christos { 353 1.1 christos secs--; 354 1.1 christos } 355 1.1 christos 356 1.1 christos /* 357 1.1 christos * Print Report 358 1.1 christos */ 359 1.1 christos profile:::tick-1sec 360 1.1 christos /secs == 0/ 361 1.1 christos { 362 1.1 christos /* fetch 1 min load average */ 363 1.1 christos this->load1a = `hp_avenrun[0] / 65536; 364 1.1 christos this->load1b = ((`hp_avenrun[0] % 65536) * 100) / 65536; 365 1.1 christos 366 1.1 christos /* convert counters to Kbytes */ 367 1.1 christos disk_r /= 1024; 368 1.1 christos disk_w /= 1024; 369 1.1 christos 370 1.1 christos /* print status */ 371 1.1 christos OPT_clear ? printf("%s", CLEAR) : 1; 372 1.1 christos printf("%Y, load: %d.%02d, disk_r: %6d KB, disk_w: %6d KB\n\n", 373 1.1 christos walltimestamp, this->load1a, this->load1b, disk_r, disk_w); 374 1.1 christos 375 1.1 christos /* print headers */ 376 1.1 christos OPT_def ? printf(" UID ") : 1; 377 1.1 christos OPT_proj ? printf(" PROJ ") : 1; 378 1.1 christos OPT_zone ? printf(" ZONE ") : 1; 379 1.1 christos printf("%6s %6s %-16s %-7s %3s %3s %1s", 380 1.1 christos "PID", "PPID", "CMD", "DEVICE", "MAJ", "MIN", "D"); 381 1.1 christos OPT_bytes ? printf(" %16s\n", "BYTES") : 1; 382 1.1 christos OPT_elapsed ? printf(" %16s\n", "ELAPSED") : 1; 383 1.1 christos OPT_dtime && ! OPT_percent ? printf(" %16s\n", "DISKTIME") : 1; 384 1.1 christos OPT_dtime && OPT_percent ? printf(" %6s\n", "%I/O") : 1; 385 1.1 christos 386 1.1 christos /* truncate to top lines if needed */ 387 1.1 christos OPT_top ? trunc(@out, TOP) : 1; 388 1.1 christos 389 1.1 christos /* normalise to percentage if needed */ 390 1.1 christos OPT_percent ? normalize(@out, INTERVAL * 10000) : 1; 391 1.1 christos 392 1.1 christos /* print data */ 393 1.1 christos ! OPT_percent ? 394 1.1 christos printa("%5d %6d %6d %-16s %-7s %3d %3d %1s %16@d\n", @out) : 395 1.1 christos printa("%5d %6d %6d %-16s %-7s %3d %3d %1s %6@d\n", @out); 396 1.1 christos printf("\n"); 397 1.1 christos 398 1.1 christos /* clear data */ 399 1.1 christos trunc(@out); 400 1.1 christos disk_r = 0; 401 1.1 christos disk_w = 0; 402 1.1 christos secs = INTERVAL; 403 1.1 christos counts--; 404 1.1 christos } 405 1.1 christos 406 1.1 christos /* 407 1.1 christos * End of program 408 1.1 christos */ 409 1.1 christos profile:::tick-1sec 410 1.1 christos /counts == 0/ 411 1.1 christos { 412 1.1 christos exit(0); 413 1.1 christos } 414 1.1 christos 415 1.1 christos /* 416 1.1 christos * Cleanup for Ctrl-C 417 1.1 christos */ 418 1.1 christos dtrace:::END 419 1.1 christos { 420 1.1 christos trunc(@out); 421 1.1 christos } 422 1.1 christos ' 423