1235368Sgnn#!/usr/bin/ksh 2235368Sgnn# 3235368Sgnn# iopattern - print disk I/O pattern. 4235368Sgnn# Written using DTrace (Solaris 10 3/05). 5235368Sgnn# 6235368Sgnn# This prints details on the I/O access pattern for the disks, such as 7235368Sgnn# percentage of events that were of a random or sequential nature. 8235368Sgnn# By default totals for all disks are printed. 9235368Sgnn# 10235368Sgnn# $Id: iopattern 65 2007-10-04 11:09:40Z brendan $ 11235368Sgnn# 12235368Sgnn# USAGE: iopattern [-v] [-d device] [-f filename] [-m mount_point] 13235368Sgnn# [interval [count]] 14235368Sgnn# 15235368Sgnn# -v # print timestamp, string 16235368Sgnn# -d device # instance name to snoop (eg, dad0) 17235368Sgnn# -f filename # full pathname of file to snoop 18235368Sgnn# -m mount_point # this FS only (will skip raw events) 19235368Sgnn# eg, 20235368Sgnn# iopattern # default output, 1 second intervals 21235368Sgnn# iopattern 10 # 10 second samples 22235368Sgnn# iopattern 5 12 # print 12 x 5 second samples 23235368Sgnn# iopattern -m / # snoop events on filesystem / only 24235368Sgnn# 25235368Sgnn# FIELDS: 26235368Sgnn# %RAN percentage of events of a random nature 27235368Sgnn# %SEQ percentage of events of a sequential nature 28235368Sgnn# COUNT number of I/O events 29235368Sgnn# MIN minimum I/O event size 30235368Sgnn# MAX maximum I/O event size 31235368Sgnn# AVG average I/O event size 32235368Sgnn# KR total kilobytes read during sample 33235368Sgnn# KW total kilobytes written during sample 34235368Sgnn# DEVICE device name 35235368Sgnn# MOUNT mount point 36235368Sgnn# FILE filename 37235368Sgnn# TIME timestamp, string 38235368Sgnn# 39235368Sgnn# NOTES: 40235368Sgnn# 41235368Sgnn# An event is considered random when the heads seek. This program prints 42235368Sgnn# the percentage of events that are random. The size of the seek is not 43235368Sgnn# measured - it's either random or not. 44235368Sgnn# 45235368Sgnn# SEE ALSO: iosnoop, iotop 46235368Sgnn# 47235368Sgnn# IDEA: Ryan Matteson 48235368Sgnn# 49235368Sgnn# COPYRIGHT: Copyright (c) 2005 Brendan Gregg. 50235368Sgnn# 51235368Sgnn# CDDL HEADER START 52235368Sgnn# 53235368Sgnn# The contents of this file are subject to the terms of the 54235368Sgnn# Common Development and Distribution License, Version 1.0 only 55235368Sgnn# (the "License"). You may not use this file except in compliance 56235368Sgnn# with the License. 57235368Sgnn# 58235368Sgnn# You can obtain a copy of the license at Docs/cddl1.txt 59235368Sgnn# or http://www.opensolaris.org/os/licensing. 60235368Sgnn# See the License for the specific language governing permissions 61235368Sgnn# and limitations under the License. 62235368Sgnn# 63235368Sgnn# CDDL HEADER END 64235368Sgnn# 65235368Sgnn# Author: Brendan Gregg [Sydney, Australia] 66235368Sgnn# 67235368Sgnn# 25-Jul-2005 Brendan Gregg Created this. 68235368Sgnn# 25-Jul-2005 " " Last update. 69235368Sgnn# 70235368Sgnn 71235368Sgnn 72235368Sgnn############################## 73235368Sgnn# --- Process Arguments --- 74235368Sgnn# 75235368Sgnn 76235368Sgnn### default variables 77235368Sgnnopt_device=0; opt_file=0; opt_mount=0; opt_time=0 78235368Sgnnfilter=0; device=.; filename=.; mount=.; interval=1; count=-1 79235368Sgnn 80235368Sgnn### process options 81235368Sgnnwhile getopts d:f:hm:v name 82235368Sgnndo 83235368Sgnn case $name in 84235368Sgnn d) opt_device=1; device=$OPTARG ;; 85235368Sgnn f) opt_file=1; filename=$OPTARG ;; 86235368Sgnn m) opt_mount=1; mount=$OPTARG ;; 87235368Sgnn v) opt_time=1 ;; 88235368Sgnn h|?) cat <<-END >&2 89235368Sgnn USAGE: iopattern [-v] [-d device] [-f filename] [-m mount_point] 90235368Sgnn [interval [count]] 91235368Sgnn 92235368Sgnn -v # print timestamp 93235368Sgnn -d device # instance name to snoop 94235368Sgnn -f filename # snoop this file only 95235368Sgnn -m mount_point # this FS only 96235368Sgnn eg, 97235368Sgnn iopattern # default output, 1 second samples 98235368Sgnn iopattern 10 # 10 second samples 99235368Sgnn iopattern 5 12 # print 12 x 5 second samples 100235368Sgnn iopattern -m / # snoop events on filesystem / only 101235368Sgnn END 102235368Sgnn exit 1 103235368Sgnn esac 104235368Sgnndone 105235368Sgnn 106235368Sgnnshift $(( $OPTIND - 1 )) 107235368Sgnn 108235368Sgnn### option logic 109235368Sgnnif [[ "$1" > 0 ]]; then 110235368Sgnn interval=$1; shift 111235368Sgnnfi 112235368Sgnnif [[ "$1" > 0 ]]; then 113235368Sgnn count=$1; shift 114235368Sgnnfi 115235368Sgnnif (( opt_device || opt_mount || opt_file )); then 116235368Sgnn filter=1 117235368Sgnnfi 118235368Sgnn 119235368Sgnn 120235368Sgnn################################# 121235368Sgnn# --- Main Program, DTrace --- 122235368Sgnn# 123235368Sgnn/usr/sbin/dtrace -n ' 124235368Sgnn /* 125235368Sgnn * Command line arguments 126235368Sgnn */ 127235368Sgnn inline int OPT_time = '$opt_time'; 128235368Sgnn inline int OPT_device = '$opt_device'; 129235368Sgnn inline int OPT_mount = '$opt_mount'; 130235368Sgnn inline int OPT_file = '$opt_file'; 131235368Sgnn inline int INTERVAL = '$interval'; 132235368Sgnn inline int COUNTER = '$count'; 133235368Sgnn inline int FILTER = '$filter'; 134235368Sgnn inline string DEVICE = "'$device'"; 135235368Sgnn inline string FILENAME = "'$filename'"; 136235368Sgnn inline string MOUNT = "'$mount'"; 137235368Sgnn 138235368Sgnn #pragma D option quiet 139235368Sgnn 140235368Sgnn int last_loc[string]; 141235368Sgnn 142235368Sgnn /* 143235368Sgnn * Program start 144235368Sgnn */ 145235368Sgnn dtrace:::BEGIN 146235368Sgnn { 147235368Sgnn /* starting values */ 148235368Sgnn diskcnt = 0; 149235368Sgnn diskmin = 0; 150235368Sgnn diskmax = 0; 151235368Sgnn diskran = 0; 152235368Sgnn diskr = 0; 153235368Sgnn diskw = 0; 154235368Sgnn counts = COUNTER; 155235368Sgnn secs = INTERVAL; 156235368Sgnn LINES = 20; 157235368Sgnn line = 0; 158235368Sgnn last_event[""] = 0; 159235368Sgnn } 160235368Sgnn 161235368Sgnn /* 162235368Sgnn * Print header 163235368Sgnn */ 164235368Sgnn profile:::tick-1sec 165235368Sgnn /line <= 0 / 166235368Sgnn { 167235368Sgnn /* print optional headers */ 168235368Sgnn OPT_time ? printf("%-20s ", "TIME") : 1; 169235368Sgnn OPT_device ? printf("%-9s ", "DEVICE") : 1; 170235368Sgnn OPT_mount ? printf("%-12s ", "MOUNT") : 1; 171235368Sgnn OPT_file ? printf("%-12s ", "FILE") : 1; 172235368Sgnn 173235368Sgnn /* print header */ 174235368Sgnn printf("%4s %4s %6s %6s %6s %6s %6s %6s\n", 175235368Sgnn "%RAN", "%SEQ", "COUNT", "MIN", "MAX", "AVG", "KR", "KW"); 176235368Sgnn 177235368Sgnn line = LINES; 178235368Sgnn } 179235368Sgnn 180235368Sgnn /* 181235368Sgnn * Check event is being traced 182235368Sgnn */ 183235368Sgnn io:genunix::done 184235368Sgnn { 185235368Sgnn /* default is to trace unless filtering */ 186235368Sgnn self->ok = FILTER ? 0 : 1; 187235368Sgnn 188235368Sgnn /* check each filter */ 189235368Sgnn (OPT_device == 1 && DEVICE == args[1]->dev_statname)? self->ok = 1 : 1; 190235368Sgnn (OPT_file == 1 && FILENAME == args[2]->fi_pathname) ? self->ok = 1 : 1; 191235368Sgnn (OPT_mount == 1 && MOUNT == args[2]->fi_mount) ? self->ok = 1 : 1; 192235368Sgnn } 193235368Sgnn 194235368Sgnn /* 195235368Sgnn * Process and Print completion 196235368Sgnn */ 197235368Sgnn io:genunix::done 198235368Sgnn /self->ok/ 199235368Sgnn { 200235368Sgnn /* 201235368Sgnn * Save details 202235368Sgnn */ 203235368Sgnn this->loc = args[0]->b_blkno * 512; 204235368Sgnn this->pre = last_loc[args[1]->dev_statname]; 205235368Sgnn diskr += args[0]->b_flags & B_READ ? args[0]->b_bcount : 0; 206235368Sgnn diskw += args[0]->b_flags & B_READ ? 0 : args[0]->b_bcount; 207235368Sgnn diskran += this->pre == this->loc ? 0 : 1; 208235368Sgnn diskcnt++; 209235368Sgnn diskmin = diskmin == 0 ? args[0]->b_bcount : 210235368Sgnn (diskmin > args[0]->b_bcount ? args[0]->b_bcount : diskmin); 211235368Sgnn diskmax = diskmax < args[0]->b_bcount ? args[0]->b_bcount : diskmax; 212235368Sgnn 213235368Sgnn /* save disk location */ 214235368Sgnn last_loc[args[1]->dev_statname] = this->loc + args[0]->b_bcount; 215235368Sgnn 216235368Sgnn /* cleanup */ 217235368Sgnn self->ok = 0; 218235368Sgnn } 219235368Sgnn 220235368Sgnn /* 221235368Sgnn * Timer 222235368Sgnn */ 223235368Sgnn profile:::tick-1sec 224235368Sgnn { 225235368Sgnn secs--; 226235368Sgnn } 227235368Sgnn 228235368Sgnn /* 229235368Sgnn * Print Output 230235368Sgnn */ 231235368Sgnn profile:::tick-1sec 232235368Sgnn /secs == 0/ 233235368Sgnn { 234235368Sgnn /* calculate diskavg */ 235235368Sgnn diskavg = diskcnt > 0 ? (diskr + diskw) / diskcnt : 0; 236235368Sgnn 237235368Sgnn /* convert counters to Kbytes */ 238235368Sgnn diskr /= 1024; 239235368Sgnn diskw /= 1024; 240235368Sgnn 241235368Sgnn /* convert to percentages */ 242235368Sgnn diskran = diskcnt == 0 ? 0 : (diskran * 100) / diskcnt; 243235368Sgnn diskseq = diskcnt == 0 ? 0 : 100 - diskran; 244235368Sgnn 245235368Sgnn /* print optional fields */ 246235368Sgnn OPT_time ? printf("%-20Y ", walltimestamp) : 1; 247235368Sgnn OPT_device ? printf("%-9s ", DEVICE) : 1; 248235368Sgnn OPT_mount ? printf("%-12s ", MOUNT) : 1; 249235368Sgnn OPT_file ? printf("%-12s ", FILENAME) : 1; 250235368Sgnn 251235368Sgnn /* print data */ 252235368Sgnn printf("%4d %4d %6d %6d %6d %6d %6d %6d\n", 253235368Sgnn diskran, diskseq, diskcnt, diskmin, diskmax, diskavg, 254235368Sgnn diskr, diskw); 255235368Sgnn 256235368Sgnn /* clear data */ 257235368Sgnn diskmin = 0; 258235368Sgnn diskmax = 0; 259235368Sgnn diskcnt = 0; 260235368Sgnn diskran = 0; 261235368Sgnn diskr = 0; 262235368Sgnn diskw = 0; 263235368Sgnn 264235368Sgnn secs = INTERVAL; 265235368Sgnn counts--; 266235368Sgnn line--; 267235368Sgnn } 268235368Sgnn 269235368Sgnn /* 270235368Sgnn * End of program 271235368Sgnn */ 272235368Sgnn profile:::tick-1sec 273235368Sgnn /counts == 0/ 274235368Sgnn { 275235368Sgnn exit(0); 276235368Sgnn } 277235368Sgnn' 278