1#!/usr/bin/ksh 2# 3# iopattern - print disk I/O pattern. 4# Written using DTrace (Solaris 10 3/05). 5# 6# This prints details on the I/O access pattern for the disks, such as 7# percentage of events that were of a random or sequential nature. 8# By default totals for all disks are printed. 9# 10# $Id: iopattern,v 1.1.1.1 2015/09/30 22:01:06 christos Exp $ 11# 12# USAGE: iopattern [-v] [-d device] [-f filename] [-m mount_point] 13# [interval [count]] 14# 15# -v # print timestamp, string 16# -d device # instance name to snoop (eg, dad0) 17# -f filename # full pathname of file to snoop 18# -m mount_point # this FS only (will skip raw events) 19# eg, 20# iopattern # default output, 1 second intervals 21# iopattern 10 # 10 second samples 22# iopattern 5 12 # print 12 x 5 second samples 23# iopattern -m / # snoop events on filesystem / only 24# 25# FIELDS: 26# %RAN percentage of events of a random nature 27# %SEQ percentage of events of a sequential nature 28# COUNT number of I/O events 29# MIN minimum I/O event size 30# MAX maximum I/O event size 31# AVG average I/O event size 32# KR total kilobytes read during sample 33# KW total kilobytes written during sample 34# DEVICE device name 35# MOUNT mount point 36# FILE filename 37# TIME timestamp, string 38# 39# NOTES: 40# 41# An event is considered random when the heads seek. This program prints 42# the percentage of events that are random. The size of the seek is not 43# measured - it's either random or not. 44# 45# SEE ALSO: iosnoop, iotop 46# 47# IDEA: Ryan Matteson 48# 49# COPYRIGHT: Copyright (c) 2005 Brendan Gregg. 50# 51# CDDL HEADER START 52# 53# The contents of this file are subject to the terms of the 54# Common Development and Distribution License, Version 1.0 only 55# (the "License"). You may not use this file except in compliance 56# with the License. 57# 58# You can obtain a copy of the license at Docs/cddl1.txt 59# or http://www.opensolaris.org/os/licensing. 60# See the License for the specific language governing permissions 61# and limitations under the License. 62# 63# CDDL HEADER END 64# 65# Author: Brendan Gregg [Sydney, Australia] 66# 67# 25-Jul-2005 Brendan Gregg Created this. 68# 25-Jul-2005 " " Last update. 69# 70 71 72############################## 73# --- Process Arguments --- 74# 75 76### default variables 77opt_device=0; opt_file=0; opt_mount=0; opt_time=0 78filter=0; device=.; filename=.; mount=.; interval=1; count=-1 79 80### process options 81while getopts d:f:hm:v name 82do 83 case $name in 84 d) opt_device=1; device=$OPTARG ;; 85 f) opt_file=1; filename=$OPTARG ;; 86 m) opt_mount=1; mount=$OPTARG ;; 87 v) opt_time=1 ;; 88 h|?) cat <<-END >&2 89 USAGE: iopattern [-v] [-d device] [-f filename] [-m mount_point] 90 [interval [count]] 91 92 -v # print timestamp 93 -d device # instance name to snoop 94 -f filename # snoop this file only 95 -m mount_point # this FS only 96 eg, 97 iopattern # default output, 1 second samples 98 iopattern 10 # 10 second samples 99 iopattern 5 12 # print 12 x 5 second samples 100 iopattern -m / # snoop events on filesystem / only 101 END 102 exit 1 103 esac 104done 105 106shift $(( $OPTIND - 1 )) 107 108### option logic 109if [[ "$1" > 0 ]]; then 110 interval=$1; shift 111fi 112if [[ "$1" > 0 ]]; then 113 count=$1; shift 114fi 115if (( opt_device || opt_mount || opt_file )); then 116 filter=1 117fi 118 119 120################################# 121# --- Main Program, DTrace --- 122# 123/usr/sbin/dtrace -n ' 124 /* 125 * Command line arguments 126 */ 127 inline int OPT_time = '$opt_time'; 128 inline int OPT_device = '$opt_device'; 129 inline int OPT_mount = '$opt_mount'; 130 inline int OPT_file = '$opt_file'; 131 inline int INTERVAL = '$interval'; 132 inline int COUNTER = '$count'; 133 inline int FILTER = '$filter'; 134 inline string DEVICE = "'$device'"; 135 inline string FILENAME = "'$filename'"; 136 inline string MOUNT = "'$mount'"; 137 138 #pragma D option quiet 139 140 int last_loc[string]; 141 142 /* 143 * Program start 144 */ 145 dtrace:::BEGIN 146 { 147 /* starting values */ 148 diskcnt = 0; 149 diskmin = 0; 150 diskmax = 0; 151 diskran = 0; 152 diskr = 0; 153 diskw = 0; 154 counts = COUNTER; 155 secs = INTERVAL; 156 LINES = 20; 157 line = 0; 158 last_event[""] = 0; 159 } 160 161 /* 162 * Print header 163 */ 164 profile:::tick-1sec 165 /line <= 0 / 166 { 167 /* print optional headers */ 168 OPT_time ? printf("%-20s ", "TIME") : 1; 169 OPT_device ? printf("%-9s ", "DEVICE") : 1; 170 OPT_mount ? printf("%-12s ", "MOUNT") : 1; 171 OPT_file ? printf("%-12s ", "FILE") : 1; 172 173 /* print header */ 174 printf("%4s %4s %6s %6s %6s %6s %6s %6s\n", 175 "%RAN", "%SEQ", "COUNT", "MIN", "MAX", "AVG", "KR", "KW"); 176 177 line = LINES; 178 } 179 180 /* 181 * Check event is being traced 182 */ 183 io:genunix::done 184 { 185 /* default is to trace unless filtering */ 186 self->ok = FILTER ? 0 : 1; 187 188 /* check each filter */ 189 (OPT_device == 1 && DEVICE == args[1]->dev_statname)? self->ok = 1 : 1; 190 (OPT_file == 1 && FILENAME == args[2]->fi_pathname) ? self->ok = 1 : 1; 191 (OPT_mount == 1 && MOUNT == args[2]->fi_mount) ? self->ok = 1 : 1; 192 } 193 194 /* 195 * Process and Print completion 196 */ 197 io:genunix::done 198 /self->ok/ 199 { 200 /* 201 * Save details 202 */ 203 this->loc = args[0]->b_blkno * 512; 204 this->pre = last_loc[args[1]->dev_statname]; 205 diskr += args[0]->b_flags & B_READ ? args[0]->b_bcount : 0; 206 diskw += args[0]->b_flags & B_READ ? 0 : args[0]->b_bcount; 207 diskran += this->pre == this->loc ? 0 : 1; 208 diskcnt++; 209 diskmin = diskmin == 0 ? args[0]->b_bcount : 210 (diskmin > args[0]->b_bcount ? args[0]->b_bcount : diskmin); 211 diskmax = diskmax < args[0]->b_bcount ? args[0]->b_bcount : diskmax; 212 213 /* save disk location */ 214 last_loc[args[1]->dev_statname] = this->loc + args[0]->b_bcount; 215 216 /* cleanup */ 217 self->ok = 0; 218 } 219 220 /* 221 * Timer 222 */ 223 profile:::tick-1sec 224 { 225 secs--; 226 } 227 228 /* 229 * Print Output 230 */ 231 profile:::tick-1sec 232 /secs == 0/ 233 { 234 /* calculate diskavg */ 235 diskavg = diskcnt > 0 ? (diskr + diskw) / diskcnt : 0; 236 237 /* convert counters to Kbytes */ 238 diskr /= 1024; 239 diskw /= 1024; 240 241 /* convert to percentages */ 242 diskran = diskcnt == 0 ? 0 : (diskran * 100) / diskcnt; 243 diskseq = diskcnt == 0 ? 0 : 100 - diskran; 244 245 /* print optional fields */ 246 OPT_time ? printf("%-20Y ", walltimestamp) : 1; 247 OPT_device ? printf("%-9s ", DEVICE) : 1; 248 OPT_mount ? printf("%-12s ", MOUNT) : 1; 249 OPT_file ? printf("%-12s ", FILENAME) : 1; 250 251 /* print data */ 252 printf("%4d %4d %6d %6d %6d %6d %6d %6d\n", 253 diskran, diskseq, diskcnt, diskmin, diskmax, diskavg, 254 diskr, diskw); 255 256 /* clear data */ 257 diskmin = 0; 258 diskmax = 0; 259 diskcnt = 0; 260 diskran = 0; 261 diskr = 0; 262 diskw = 0; 263 264 secs = INTERVAL; 265 counts--; 266 line--; 267 } 268 269 /* 270 * End of program 271 */ 272 profile:::tick-1sec 273 /counts == 0/ 274 { 275 exit(0); 276 } 277' 278