Home | History | Annotate | Line # | Download | only in Bin
      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