File s390-tools-sles11sp3-dasd-enhanced-statistics.patch of Package s390-tools
Subject: [PATCH] [FEAT 82722] dasdstat: Add new zconf tool dasdstat
From: Stefan Weinhuber <wein@de.ibm.com>
Summary: dasdstat: Add new zconf tool dasdstat
Description: The dasdstat command provides easy access to the debugfs based
statistics of the DASD device driver.
Problem-ID: 82722
---
README | 1
zconf/Makefile | 4
zconf/dasdstat | 464 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
zconf/dasdstat.8 | 97 +++++++++++
4 files changed, 564 insertions(+), 2 deletions(-)
--- a/README
+++ b/README
@@ -115,6 +115,7 @@ s390-tools (1.15.0)
blacklist.
- lsmem: Display the online status of the available memory.
- chmem: Set hotplug memory online or offline.
+ - dasdstat: Configure and format the debugfs based DASD statistics data.
* dumpconf:
Allows to configure the dump device used for system dump in case a kernel
--- /dev/null
+++ b/zconf/dasdstat
@@ -0,0 +1,464 @@
+#!/bin/bash
+#
+# Copyright IBM Corp. 2011
+#
+# dasdstat
+# Reads dasd statistics data from debugfs and prints it as formatted table
+#
+# Author(s): Stefan Weinhuber <wein@de.ibm.com>
+#
+
+function print_usage() {
+ cat <<-EOD
+Usage: $CMD <options> [<statistic>]
+
+<options> ::=
+ -e|--enable
+ Enable the statistics.
+ -d|--disable
+ Disable the statistics.
+ -r|--reset
+ Reset the statistics.
+ -i|--directory <directory>
+ Specify the directory in which the statistics can be found.
+ -h|--help
+ Print this text and exit.
+ -l|--long
+ Print more detailed information, e.g differentiate between
+ read and write requests.
+ -c|--columns <number>
+ Format the output in a table with the given number of columns.
+ -w|--column-width <width>
+ Set the minimum width of the columns in the output table.
+ -V|--verbose
+ Print more verbose information.
+ -v|--version
+ Show tools and command version.
+
+<statistic>
+ Limit operation to one or more statistic.
+ EOD
+}
+
+function print_version()
+{
+ echo "$CMD: version %S390_TOOLS_VERSION%"
+ echo "Copyright IBM Corp. 2011"
+}
+
+function unset_known_variables() {
+ unset start_time
+ unset total_requests
+ unset total_sectors
+ unset total_pav
+ unset total_hpf
+ unset histogram_sectors
+ unset histogram_io_times
+ unset histogram_io_times_weighted
+ unset histogram_time_build_to_ssch
+ unset histogram_time_ssch_to_irq
+ unset histogram_time_ssch_to_irq_weighted
+ unset histogram_time_irq_to_end
+ unset histogram_ccw_queue_length
+ unset total_read_requests
+ unset total_read_sectors
+ unset total_read_pav
+ unset total_read_hpf
+ unset histogram_read_sectors
+ unset histogram_read_times
+ unset histogram_read_time_build_to_ssch
+ unset histogram_read_time_ssch_to_irq
+ unset histogram_read_time_irq_to_end
+ unset histogram_read_ccw_queue_length
+}
+
+function print_array()
+{
+ local width=$1
+ shift
+ local linebreak=$1
+ shift
+ local i=1
+ for element in $*
+ do
+ printf "%${width}s" $element
+ (( 0 == i++ % linebreak )) && printf "\n"
+ done
+ # add an extra line break if we do not already have one
+ (( 0 != (i - 1) % linebreak )) && printf "\n"
+}
+
+function subtract_array()
+{
+ local -a a=( $1 )
+ local -a b=( $2 )
+ local -a c
+ local i
+ local cnt=${#a[@]}
+ for (( i = 0 ; i < cnt ; i++ ))
+ do
+ (( c[i] = a[i] - b[i] ))
+ done
+ echo -n ${c[*]}
+}
+
+function print_line()
+{
+ local i
+ for (( i = 0 ; i < $1 ; i++ ))
+ do
+ echo -n '-'
+ done
+ echo
+}
+
+HEADERSEXP=" __<4 ___8 __16 __32 __64 _128 _256 _512 \
+ __1k __2k __4k __8k _16k _32k _64k 128k \
+ _256 _512 __1M __2M __4M __8M _16M _32M \
+ _64M 128M 256M 512M __1G __2G __4G _>4G"
+
+HEADERSLIN=" ___0 ___1 ___2 ___3 ___4 ___5 ___6 ___7 \
+ ___8 ___9 __10 __11 __12 __13 __14 __15 \
+ __16 __17 __18 __19 __20 __21 __22 __23 \
+ __24 __25 __26 __27 __28 __29 __30 __31"
+
+
+function print_format_standard()
+{
+ local converted_time=$(date -d @$start_time)
+ # all numbers in the histograms below are smaller or equal to the
+ # total_requests. So we use that number to determine the column width.
+ local width=${#total_requests}
+ (( width++ ))
+ (( width < 5 )) && width=5
+
+ if [[ -n $COLUMN_WIDTH ]] && [[ $width -lt $COLUMN_WIDTH ]]
+ then
+ width=$COLUMN_WIDTH
+ fi
+
+ local linebreak=$NUMBER_COLUMNS
+ local statname="$1"
+ local tablewidth
+ (( tablewidth = width * linebreak ))
+
+ # Note: This function does not print the histogram_io_times_weighted
+ # and histogram_time_ssch_to_irq_weighted because the interpretation
+ # of these histograms is not intuitive and may lead to confusion.
+ print_line $tablewidth
+ printf "statistics data for statistic: %s\n" "$statname"
+ printf "start time of data collection: %s\n\n" "$converted_time"
+
+ printf "%d dasd I/O requests\n" ${total_requests[*]}
+ printf "with %u sectors(512B each)\n" ${total_sectors[*]}
+ printf "%d requests used a PAV alias device\n" ${total_pav[*]}
+ printf "%d requests used HPF\n" ${total_hpf[*]}
+ print_array $width $linebreak $HEADERSEXP
+ printf "Histogram of sizes (512B secs)\n"
+ print_array $width $linebreak ${histogram_sectors[*]}
+ printf "Histogram of I/O times (microseconds)\n"
+ print_array $width $linebreak ${histogram_io_times[*]}
+ printf "Histogram of I/O time till ssch\n"
+ print_array $width $linebreak ${histogram_time_build_to_ssch[*]}
+ printf "Histogram of I/O time between ssch and irq\n"
+ print_array $width $linebreak ${histogram_time_ssch_to_irq[*]}
+ printf "Histogram of I/O time between irq and end\n"
+ print_array $width $linebreak ${histogram_time_irq_to_end[*]}
+ printf "# of req in chanq at enqueuing (0..31) \n"
+ print_array $width $linebreak $HEADERSLIN
+ print_array $width $linebreak ${histogram_ccw_queue_length[*]}
+
+ if [[ $OUTPUT == "short" ]]
+ then
+ print_line $tablewidth
+ return
+ fi
+
+ printf "\n%d dasd I/O read requests\n" ${total_read_requests[*]}
+ printf "with %u sectors(512B each)\n" ${total_read_sectors[*]}
+ printf "%d requests used a PAV alias device\n" ${total_read_pav[*]}
+ printf "%d requests used HPF\n" ${total_read_hpf[*]}
+ print_array $width $linebreak $HEADERSEXP
+ printf "Histogram of sizes (512B secs)\n"
+ print_array $width $linebreak ${histogram_read_sectors[*]}
+ printf "Histogram of I/O times (microseconds)\n"
+ print_array $width $linebreak ${histogram_read_times[*]}
+ printf "Histogram of I/O time till ssch\n"
+ print_array $width $linebreak ${histogram_read_time_build_to_ssch[*]}
+ printf "Histogram of I/O time between ssch and irq\n"
+ print_array $width $linebreak ${histogram_read_time_ssch_to_irq[*]}
+ printf "Histogram of I/O time between irq and end\n"
+ print_array $width $linebreak ${histogram_read_time_irq_to_end[*]}
+ printf "# of req in chanq at enqueuing (0..31) \n"
+ print_array $width $linebreak $HEADERSLIN
+ print_array $width $linebreak ${histogram_read_ccw_queue_length[*]}
+
+ printf "\n%d dasd I/O write requests\n" $(( total_requests[0] - total_read_requests[0] ))
+ printf "with %u sectors(512B each)\n" $(( total_sectors[0] - total_read_sectors[0] ))
+ printf "%d requests used a PAV alias device\n" $(( total_pav[0] - total_read_pav[0] ))
+ printf "%d requests used HPF\n" $(( total_hpf[0] - total_read_hpf[0] ))
+ print_array $width $linebreak $HEADERSEXP
+ printf "Histogram of sizes (512B secs)\n"
+ print_array $width $linebreak $(subtract_array "${histogram_sectors[*]}" "${histogram_read_sectors[*]}")
+ printf "Histogram of I/O times (microseconds)\n"
+ print_array $width $linebreak $(subtract_array "${histogram_io_times[*]}" "${histogram_read_times[*]}")
+ printf "Histogram of I/O time till ssch\n"
+ print_array $width $linebreak $(subtract_array "${histogram_time_build_to_ssch[*]}" "${histogram_read_time_build_to_ssch[*]}")
+ printf "Histogram of I/O time between ssch and irq\n"
+ print_array $width $linebreak $(subtract_array "${histogram_time_ssch_to_irq[*]}" "${histogram_read_time_ssch_to_irq[*]}")
+ printf "Histogram of I/O time between irq and end\n"
+ print_array $width $linebreak $(subtract_array "${histogram_time_irq_to_end[*]}" "${histogram_read_time_irq_to_end[*]}")
+ printf "# of req in chanq at enqueuing (0..31) \n"
+ print_array $width $linebreak $HEADERSLIN
+ print_array $width $linebreak $(subtract_array "${histogram_ccw_queue_length[*]}" "${histogram_read_ccw_queue_length[*]}")
+
+ print_line $tablewidth
+}
+
+function read_stat_data() {
+ myfile="$1"
+ while read -d ' ' token
+ do
+ read -a $token
+ done < $myfile
+ # differentiate I/O error from disabled statistic
+ if [[ -n $total_requests ]] || [[ "$token" == "disabled" ]]
+ then
+ return 0
+ else
+ return 1
+ fi
+}
+
+function print_stat() {
+ myfile="$1"
+ if [[ ! -f "$myfile" ]]
+ then
+ print_line 80
+ echo "$CMD: Statistic \"$myfile\" does not exist" >&2
+ print_line 80
+ echo
+ return
+ fi
+ unset_known_variables
+ if read_stat_data "$myfile"
+ then
+ if [[ -z "$total_requests" ]]
+ then
+ if [[ "$VERBOSE" == "true" ]]
+ then
+ print_line 80
+ echo "statistics \"$f\" are disabled"
+ print_line 80
+ echo
+ fi
+ else
+ print_format_standard $f
+ echo
+ fi
+ else
+ print_line 80
+ echo "$CMD: Could not read statistic \"$myfile\" " >&2
+ print_line 80
+ echo
+ fi
+}
+
+function enable_stat() {
+ myfile="$1"
+ if [[ ! -f "$myfile" ]]
+ then
+ echo "$CMD: Statistic \"$myfile\" does not exist" >&2
+ return
+ fi
+ if echo on > "$myfile"
+ then
+ echo "enable statistic \"$myfile\""
+ else
+ echo "$CMD: Failed to enable statistic \"$myfile\"" >&2
+ fi
+}
+
+function disable_stat() {
+ myfile="$1"
+ if [[ ! -f "$myfile" ]]
+ then
+ echo "$CMD: Statistic \"$myfile\" does not exist" >&2
+ return
+ fi
+ if echo off > "$myfile"
+ then
+ echo "disable statistic \"$myfile\""
+ else
+ echo "$CMD: Failed to disable statistic \"$myfile\""
+ fi
+}
+
+function reset_stat() {
+ myfile="$1"
+ if [[ ! -f "$myfile" ]]
+ then
+ echo "$CMD: Statistic \"$myfile\" does not exist" >&2
+ return
+ fi
+ if echo reset > "$myfile"
+ then
+ echo "reset statistic \"$myfile\""
+ else
+ echo "$CMD: Failed to reset statistic \"$myfile\"" >&2
+ fi
+}
+
+function verbose_msg() {
+ if [[ "$VERBOSE" == "true" ]]
+ then
+ echo "$*"
+ fi
+}
+
+
+# Evaluating command line options
+CMD=$(basename $0)
+DASD_STATISTICS_DIR=""
+ALLFILES=""
+VERBOSE=false
+OUTPUT="short"
+NUMBER_COLUMNS=16
+COLUMN_WIDTH=
+ACTION="print"
+while [ $# -gt 0 ]; do
+ case $1 in
+ --help|-h)
+ print_usage
+ exit 0
+ ;;
+ --enable|-e)
+ ACTION="enable"
+ ;;
+ --disable|-d)
+ ACTION="disable"
+ ;;
+ --reset|-r)
+ ACTION="reset"
+ ;;
+ --directory|-i)
+ DASD_STATISTICS_DIR="$2"
+ shift
+ if [[ ! -d $DASD_STATISTICS_DIR ]]
+ then
+ echo "$CMD: $DASD_STATISTICS_DIR is not a directory" >&2
+ exit 1
+ fi
+ ;;
+ --long|-l)
+ OUTPUT="extended"
+ ;;
+ --columns|-c)
+ NUMBER_COLUMNS="$2"
+ if [[ ! "$NUMBER_COLUMNS" -gt 0 ]]
+ then
+ echo "$CMD: $NUMBER_COLUMNS is not a positive integer number" >&2
+ exit 1
+ fi
+ shift
+ ;;
+ --column-width|-w)
+ COLUMN_WIDTH="$2"
+ if [[ ! "$COLUMN_WIDTH" -gt 0 ]]
+ then
+ echo "$CMD: $COLUMN_WIDTH is not a positive integer number" >&2
+ exit 1
+ fi
+ shift
+ ;;
+ --verbose|-V)
+ VERBOSE=true
+ ;;
+ --version|-v)
+ print_version
+ exit 0
+ ;;
+ -*)
+ echo "$CMD: Invalid option $1" >&2
+ echo "Try '$CMD --help' for more information." >&2
+ exit 1
+ ;;
+ *)
+ ALLFILES="$ALLFILES $1"
+ ;;
+ esac
+ shift
+done
+
+# if no directory is given on command line, find dasd directory in debugfs
+if [[ "$DASD_STATISTICS_DIR" == "" ]]
+then
+ while read -a mntentries
+ do
+ if [[ "${mntentries[2]}" == "debugfs" ]]
+ then
+ DASD_STATISTICS_DIR="${mntentries[1]}"
+ verbose_msg "found debugfs mount point $DASD_STATISTICS_DIR"
+ break;
+ fi
+ done < /etc/mtab
+ if [[ "$DASD_STATISTICS_DIR" == "" ]]
+ then
+ echo "$CMD: No debugfs mount point found" >&2
+ exit 1
+ fi
+ DASD_STATISTICS_DIR="$DASD_STATISTICS_DIR/dasd"
+ if [[ ! -d "$DASD_STATISTICS_DIR" ]]
+ then
+ echo "$CMD: Default DASD debugfs directory $DASD_STATISTICS_DIR does not exist" >&2
+ exit 1
+ fi
+fi
+
+# look for directories that contain statistics
+if [[ "$ALLFILES" == "" ]]
+then
+ ALLFILES=$(ls -x $DASD_STATISTICS_DIR)
+ explicitstats="false"
+else
+ explicitstats="true"
+fi
+ALLSTATS=""
+for f in $ALLFILES
+do
+ if [[ -f "$DASD_STATISTICS_DIR/$f/statistics" ]]
+ then
+ ALLSTATS="$ALLSTATS $f"
+ elif [[ $explicitstats == "true" ]]
+ then
+ echo "$CMD: No statistics found for $f" >&2
+ fi
+done
+
+verbose_msg "found the following statistics in directory $DASD_STATISTICS_DIR:"
+verbose_msg "$ALLSTATS"
+
+# execute the required operation
+for f in $ALLSTATS
+do
+ case $ACTION in
+ "enable")
+ enable_stat "$DASD_STATISTICS_DIR/$f/statistics"
+ ;;
+ "disable")
+ disable_stat "$DASD_STATISTICS_DIR/$f/statistics"
+ ;;
+ "reset")
+ reset_stat "$DASD_STATISTICS_DIR/$f/statistics"
+ ;;
+ "print")
+ print_stat "$DASD_STATISTICS_DIR/$f/statistics"
+ ;;
+ *)
+ echo "error"
+ exit 1
+ ;;
+ esac
+done
+
+
--- /dev/null
+++ b/zconf/dasdstat.8
@@ -0,0 +1,97 @@
+.TH LSDASD 8 "Feb 2011" "s390-tools"
+
+.SH NAME
+dasdstat \- read or modify the statistics of the DASD device driver.
+
+.SH SYNOPSIS
+.TP 8
+.B dasdstat
+.RB [ -h ]
+.TP 8
+.B dasdstat
+.RB [ -e ]
+.RB [ -d ]
+.RB [ -r ]
+.RB [ -i ]
+.RB [ -l ]
+.RB [ -c ]
+.RB [ -w ]
+.RB [ -V ]
+.RB [ -v ]
+.RI [ <statistic> " [" <statistic> "] ...]]"
+
+.SH DESCRIPTION
+The dasdstat command provides easy access to the debugfs based
+statistics of the DASD device driver.
+
+The DASD statistics feature allows to gather statistical data for the
+I/O requests processed by the DASD device driver. This data can be
+collected for individual DASD CCW devices (including PAV base and
+alias devices), DASD block devices, or globally for all requests
+handled by the DASD device driver.
+
+When no other options are specified, then the default operation is to
+print the statistics data in a formatted table. When no specific list
+of statistics is given, then the operation will be performed on all
+available statistics.
+
+.SH OPTIONS
+.TP 8
+.BR -h | --help
+Print help text.
+.TP
+.BR -e | --enable
+Enable the statistics.
+.TP
+.BR -d | --disable
+Disable the statistics.
+.TP
+.BR -r | --reset
+Reset the statistics.
+.TP
+.BR -i | --directory
+Specify the directory in which the statistics can be found.
+.TP
+.BR -l | --long
+Print more detailed information, e.g differentiate between read and
+write requests.
+.TP
+.BR -c | --columns " \fI<number>\fR"
+Format the output in a table with the given number of columns.
+.TP
+.BR -w | --column-width " \fI<width>\fR"
+Set the minimum width of the columns in the output table.
+.TP
+.BR -V | --verbose
+Print more verbose information.
+.TP
+.BR -v | --version
+Print the version of the s390-tools package and the command.
+.TP
+\fB<statistic>\fR =
+Name of a statistic that the command should work on.
+
+.SH EXAMPLES
+\fBdasdstat\fR
+.RS
+Print a statistics table for each enabled statistic.
+.RE
+
+\fBdasdstat -e\fR
+.RS
+Enable all DASD statistics.
+.RE
+
+\fBdasdstat -l dasda 0.0.1800 0.0.18fe 0.0.18ff\fR
+.RS
+Print a detailed statistics table for DASD block device dasda and CCW
+devices 0.0.1800, 0.0.18fe and 0.0.18ff. A typical scenario for this
+example would be that dasda is the block device that belongs to
+PAV base device 0.0.1800, and CCW devices 0.0.18fe and 0.0.18ff are the
+associated alias devices.
+.RE
+
+.SH AUTHOR
+.nf
+This man-page was written by Stefan Weinhuber <wein@de.ibm.com>.
+.fi
--- a/zconf/Makefile
+++ b/zconf/Makefile
@@ -4,11 +4,11 @@
include ../common.mak
SCRIPTS = lsdasd lstape lscss chccwdev lsqeth lszfcp lschp chchp lszcrypt \
- chzcrypt cio_ignore znetconf
+ chzcrypt cio_ignore znetconf dasdstat
USRSBIN_SCRIPTS = lsmem chmem lsluns
MANPAGES= lsdasd.8 lstape.8 lscss.8 chccwdev.8 lsqeth.8 lszfcp.8 lschp.8 \
chchp.8 lszcrypt.8 chzcrypt.8 lsluns.8 cio_ignore.8 znetconf.8 \
- chmem.8 lsmem.8
+ chmem.8 lsmem.8 dasdstat.8
all: