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 77 opt_device=0; opt_file=0; opt_mount=0; opt_time=0 78 filter=0; device=.; filename=.; mount=.; interval=1; count=-1 79 80 ### process options 81 while getopts d:f:hm:v name 82 do 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 104 done 105 106 shift $(( $OPTIND - 1 )) 107 108 ### option logic 109 if [[ "$1" > 0 ]]; then 110 interval=$1; shift 111 fi 112 if [[ "$1" > 0 ]]; then 113 count=$1; shift 114 fi 115 if (( opt_device || opt_mount || opt_file )); then 116 filter=1 117 fi 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