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