diff options
Diffstat (limited to 'src/pmview/front-ends/dkvis')
-rwxr-xr-x | src/pmview/front-ends/dkvis | 572 |
1 files changed, 572 insertions, 0 deletions
diff --git a/src/pmview/front-ends/dkvis b/src/pmview/front-ends/dkvis new file mode 100755 index 0000000..5cf7267 --- /dev/null +++ b/src/pmview/front-ends/dkvis @@ -0,0 +1,572 @@ +#! /bin/sh +# +# Copyright (c) 1997-2005 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# + +tmp=/tmp/$$ +trap "rm -f $tmp.*; exit" 0 1 2 3 15 +rm -f $tmp.* + +. $PCP_DIR/etc/pcp.env +. $PCP_SHARE_DIR/lib/pmview-args + +_usage() +{ + echo >$tmp.msg 'Usage: '$prog' [options] [diskid ...] + +options: + -b display data throughput (Kbytes/sec) rather than IOPs + -m maxrate maximum activity expected (integer) + [default 150 IOPs (without -b) or 2048 Kbytes/sec (with -b)] + -r display only the read activity + -V verbose/diagnostic output + -w display only the write activity + -X ndisk limit layout to at most this many disks per row, set + to 0 for no limit [default 12] + -Y nctl limit layout to at most this many controllers per column + before starting a new group of controllers, set to 0 + for no limit [default 16] + +pmview(1) options:' + + _pmview_usage >> $tmp.msg + echo >> $tmp.msg + echo 'Default title is: Total Disk Activity (IOPS) for Host' >> $tmp.msg + _pmview_info -f $tmp.msg +} + +verbose=false +type=total +Type=Total +Thru=IOPS +max='' +force=false +maxnctl=16 +maxndisk=12 +diskargs= +debug=false + +# build WM_COMMAND X(1) property for restart after login/logout +# +echo -n "pmview Version 2.1 \"dkvis\"" >$tmp.conf +for arg +do + echo -n " \"$arg\"" >>$tmp.conf +done + +_pmview_args "$@" + +if [ -n "$otherArgs" ] +then + while getopts "?bdm:R:rv:VX:Y:w" c $otherArgs + do + case $c + in + b) + Thru="Kbytes/sec" + ;; + d) + debug=true + ;; + m) + _pmview_unsigned $c + max=$OPTARG + ;; + r) + if [ $type != total ] + then + _pmview_error "$prog: only one -r or -w option may be specified" + # NOTREACHED + fi + type=read + Type=Read + ;; + + v) + if [ $OPTARG = "1" ] + then + _pmview_warning "$prog: pmview version 1 no longer supported, using version 2" + elif [ $OPTARG != "2" ] + then + _pmview_error "$prog: only version 2 supported for -v" + # NOTREACHED + fi + ;; + + V) + verbose=true + ;; + w) + if [ $type != total ] + then + _pmview_error "$prog: only one -r or -w option may be specified" + # NOTREACHED + fi + type=write + Type=Write + ;; + X) + _pmview_unsigned $c + maxndisk=$OPTARG + ;; + [YR]) + # used to be -R, so support both for backwards compatibility + _pmview_unsigned $c + maxnctl=$OPTARG + force=true + ;; + ?) + _usage + exit 1 + ;; + + esac + done + set -- $otherArgs + shift `expr $OPTIND - 1` + + [ $# -gt 0 ] && diskargs=$@ +fi + +if [ "$Thru" != "IOPS" ] +then + case $type + in + read) + type=read_bytes + ;; + write) + type=write_bytes + ;; + *) + if pminfo $msource disk.dev.total_bytes >/dev/null 2>&1 + then + type=total_bytes + else + type=bytes + fi + ;; + esac +fi + +# default max depends on -b or not +# +if [ "$Thru" != "IOPS" ] +then + [ -z "$max" ] && max=2048 +else + [ -z "$max" ] && max=150 +fi + +pminfo -f $msource $namespace disk.dev.$type >$tmp.info 2>$tmp.err +if [ -s $tmp.err ] +then + cat $tmp.err | _pmview_fetch_mesg >> $tmp.msg + echo "$prog: Failed to get disk inventory from host \"$host\"" | fmt >> $tmp.msg + _pmview_error -f $tmp.msg + # NOTREACHED +fi + +$PCP_AWK_PROG < $tmp.info -F'"' '/inst/ { print $2 }' > $tmp.disks + +if [ ! -s $tmp.disks ] +then + cat $tmp.info | _pmview_fetch_mesg >> $tmp.msg + echo "$prog: Failed to get disk inventory from host \"$host\"" | fmt >> $tmp.msg + _pmview_error -f $tmp.msg + # NOTREACHED +fi + +if [ ! -z "$diskargs" ] +then + rm -f $tmp.tmp $tmp.msg + for dk in $diskargs + do + if echo "$dk" | grep '[.[^]' >/dev/null + then + # assume egrep(1) regular expression + # + if egrep "$dk" $tmp.disks >>$tmp.tmp + then + # found some matches + # + : + else + echo "$prog: pattern \"$dk\" does not match any disks ..." >$tmp.msg + fi + elif grep "^$dk\$" $tmp.disks >/dev/null + then + echo $dk >>$tmp.tmp + else + echo "$prog: disk \"$dk\" not in the disk inventory ..." >$tmp.msg + fi + done + if [ -s $tmp.msg ] + then + echo "Disks on host \"$host\" are:" >> $tmp.msg + fmt $tmp.disks | sed -e 's/^/ /' >> $tmp.msg + _pmview_error -f $tmp.msg + # NOTREACHED + fi + mv $tmp.tmp $tmp.disks +fi + +if $debug +then + echo "Disks ..." + cat $tmp.disks +fi + +ndisk=`wc -l <$tmp.disks | sed -e 's/ //g'` + +if [ "$ndisk" -lt 1 ] +then + echo "$prog: Cannot get disk inventory for host \"$host\"\n" > $tmp.msg + cat $tmp.info >> $tmp.msg + _pmview_error -f $tmp.msg + # NOTREACHED +fi + +cat << end-of-file >> $tmp.conf + +# +# dkvis +# +end-of-file + +if $verbose +then + echo "# Disk Inventory:" >> $tmp.conf + fmt <$tmp.disks | sed -e 's/^/# /' >> $tmp.conf +fi +cp $tmp.disks $tmp.in + +# get controller-based order +# +# the mapping is controlled by the here-is document below, where each +# (non-comment) line contains three fields separated by tabs: +# 1. pattern to match disk names (must match the start of a disk indom name) +# - don't bother escaping / (fixed up later) +# - <n> is expanded to \([0-9][0-9]*\) later +# - <h> is expanded to \([0-9a-f][0-9a-f]*\) later +# 2. controller-tag ... construction from literals and substrings (in sed +# syntax, so \1, \2, etc) from the pattern +# 3. sort field order ... constructed from the ordinal labels of the +# substrings in the pattern (comma separated) ... "n" is appended +# for numerical sorting +# +# so the control line +# dks<n>d<n>l*\([0-9]*\) dks\1 1n,2n,3n +# +# will first turn disk indom names like dks14d3, dks14d3l2, dks14d3l10, +# dks14d2, dks10d7, dks10d10 and dks10d1 into records like +# +# dks14 14 3 dks14d3 +# dks14 14 3 2 dks14d3l2 +# dks14 14 3 10 dks14d3l10 +# dks14 14 2 dks14d2 +# dks10 10 7 dks10d7 +# dks10 10 1 10 dks10d110 +# dks10 10 1 dks10d1 +# --+-- -+ -+ -+ ----+---- +# | | | | | +# | | | | +-- full disk name +# | | | +-- 3rd sort key (lun, may be missing) +# | | +-- 2nd sort key (target) +# | +-- 1st sort key (controller) +# +-- controller-tag for dkvis scene and used for grouping "related" +# disks +# +# and generate a sort(1) key of the form "+1n -2 +2n -3 +3n -4" +# +# after sorting this list becomes +# +# dks10 10 1 dks10d1 +# dks10 10 1 10 dks10d110 +# dks10 10 7 dks10d7 +# dks14 14 2 dks14d2 +# dks14 14 3 dks14d3 +# dks14 14 3 2 dks14d3l2 +# dks14 14 3 10 dks14d3l10 +# +# and after grouping based on the common controller-tag and stripping +# the sort fields this becomes +# +# dks10 dks10d1 dks10d110 dks10d7 +# dks14 dks14d2 dks14d3 dks14d3l2 dks14d3l10 +# +sed >$tmp.ctl <<'End-of-File' \ + -e '/^#/d' \ + -e 's/ */ /g' \ + -e 's/\//\\\//g' \ + -e 's/<n>/\\([0-9][0-9]*\\)/g' \ + -e 's/<h>/\\([0-9a-f][0-9a-f]*\\)/g' \ + -e 's/^/^/' +# Linux 2.2, no sard, IDE and SCSI +sd\([a-z]\)+hd\([abcd]\) sd+hd 1 +# Linux IDE, no devfs +hd\([abcd]\) hd 1 +# Linux IDE, with devfs +ide/host<n>/bus<n>/target<n>/lun<n> ide\1b\2 1n,2n,3n,4n +# Linux SCSI, no devfs +sd\([a-z]\) sd 1 +# Linux XSCSI, dual port HBA, with devfs +# e.g. xscsi/pci00.01.0-1/target2/lun0/disc (and similar for fabric device) +xscsi/pci<h>\.<h>\.<n>-<n>/target<n>/lun<n> xscsi\1.\2 1,2,3n,4n,5n,6n +xscsi/pci<h>\.<h>\.<n>-<n>/node<h>/lun<n> xscsi\1.\2 1,2,3n,4n,5,6n +# Linux XSCSI, single port HBA, with devfs +# e.g. xscsi/pci05.01.0/target2/lun0/disc (and similar for fabric device) +xscsi/pci<h>\.<h>\.<n>/target<n>/lun<n> xscsi\1.\2 1,2,3n,4n,5n +xscsi/pci<h>\.<h>\.<n>/node<h>/lun<n> xscsi\1.\2 1,2,3n,4,5n +# Linux SCSI, with devfs +scsi/host<n>/bus<n>/target<n>/lun<n> scsi\1b\2 1n,2n,3n,4n +# Linux Mylex RAID, no devfs +rd/c<n>d<n> dac 1n,2n +# Linux Mylex RAID, with devfs (old style) +dac960/c<n>d<n> dac 1n,2n +# Linux Mylex RAID, with devfs (new style) +dac960/host<n>/disc<n> dac 1n,2n +# IRIX Firewire +# two name formats: first is IRIX before 6.5.11, second is 6.5.11 or later +/hw/rdisk/1394/\([^/]*\)/lun<n>vol/c<n>p<n> 1394c\3 3n,2n,1,2n +1394/\([^/]*\)/lun<n>vol/c<n>p<n> 1394c\3 3n,2n,1,2n +# IRIX SCSI, note l<n> is missing for LUN 0, so pattern is a little different +# at the end +dks<n>d<n>l*\([0-9]*\) dks\1 1n,2n,3n +# IRIX FC +\(................\)/lun<n>/c<n>p<n> fc\3p\4 3n,4n,1,2n +# Linux direct attach xscsi +# e.g. xscsi/pci15.01.0-2/target4/lun0/disc +xscsi/pci<n>\.\(..\)\.\(.*\)/target<n>/lun<n> xscsi\1b\2 1n,2,3,4n,5n +# Linux fabric attach xscsi +# e.g. xscsi/pci04.01.0/node50060946700083e9/port1/lun0/disc +xscsi/pci<n>\.\(..\)\.\(.*\)/node\(................\)/port<n>/lun<n> xfc\1b\2 1n,2,3,4,5n,6n +# Linux IDA, with devfs +ida/disc<n> ida 1n +# Old style IRIX Jaguar drives +jag<n>d<n> jag\1 1n,2n +# Old style IRIX RAID drives +rad<n>d<n> rad\1 1n,2n +End-of-File + +if $debug +then + echo "Control lines ..." + cat $tmp.ctl +fi + +nctl=`wc -l <$tmp.ctl | sed -e 's/ //g'` +i=1 + +# loop once per contol line in $tmp.ctl ... +# - select matching disks +# - generate the sort keys with the disk names +# - sort and group by the controller-tag +# - remove the matching lists from consideration +# +while [ $i -le $nctl ] +do + $PCP_AWK_PROG -F' ' <$tmp.ctl ' +NR == '$i' { print "/" $1 "/p" >"'$tmp.sed-in'" + print "/" $1 "/!p" >"'$tmp.sed-out'" + nfld = split($3,fld,/,/) + maxfld = 1 + for (i = 1; i <= nfld; i++) { + if (fld[i] > maxfld) maxfld = fld[i] + printf "+%s -%d ",fld[i],fld[i]+1 >"'$tmp.sort-arg'" + } + print "" >"'$tmp.sort-arg'" + printf "%s","s/" $1 "/" $2 >"'$tmp.sed-key'" + for (i = 1; i <= maxfld; i++) { + printf " \\%d",i >"'$tmp.sed-key'" + } + print " &/" >"'$tmp.sed-key'" + exit + }' + + sed -n -f $tmp.sed-in <$tmp.in \ + | sed -f $tmp.sed-key >$tmp.key + sort `cat $tmp.sort-arg` $tmp.key \ + | $PCP_AWK_PROG >>$tmp.order ' +BEGIN { ctl = "" } +$1 != ctl { if (NR > 1) print "" + ctl = $1 + ndisk = 0 + printf "%s",ctl + } + { ndisk++ + if ('"$maxndisk"' > 0 && ndisk > '"$maxndisk"') { + print "" + printf "%s",ctl + ndisk = 1 + } + printf " %s",$NF + } +END { if (NR > 0) print "" }' + sed -n -f $tmp.sed-out <$tmp.in >$tmp.out + mv $tmp.out $tmp.in + + i=`expr $i + 1` +done + +# any leftovers do not match any control pattern +# +if [ -s $tmp.in ] +then + echo "$prog: The following disk names do not match a known controller pattern," >$tmp.warn + echo "and they will be ungrouped in the scene:" >>$tmp.warn + fmt <$tmp.in | sed -e 's/^/ /' >>$tmp.warn + _pmview_warning -f $tmp.warn + sed -e 's/.*/& &/' <$tmp.in >>$tmp.order +fi + +nctl=`wc -l <$tmp.order | sed -e 's/ //g'` + +# shape the base geometry for the scene ... there are groups, each with +# $maxnctl controller rows, and the groups are arranged in a grid that +# is $nrow groups deep and $ncol groups across +# +if [ $nctl -le $maxnctl ] +then + # less than $maxnctl controller rows, so just one group + # + ncol=1 + nrow=1 +else + # have some shaping to do ... assume each group is $maxnctl controller + # rows deep and as wide as the maximum number of disks per controller + # row, then square up the scene and maybe adjust $maxnctl + # + eval `$PCP_AWK_PROG <$tmp.order ' +START { maxdk = 0 } + { if (NF - 1 > maxdk) maxdk = NF - 1 } +END { + if ('"$nctl"' % "'$maxnctl'" == 0) + ngrp = '"$nctl"' / "'$maxnctl'" + else + ngrp = int('"$nctl"' / "'$maxnctl'") + 1 + # add 2 to maxdk as an estimate of the label length in units of + # displayed blocks, i.e. the label is about as long as the width + # of 2 blocks + ncol = int(0.5 + sqrt(ngrp)*'"$maxnctl"'/(maxdk + 2)) + if (ncol < 1) ncol = 1 + if (ngrp % ncol == 0) + nrow = ngrp / ncol + else + nrow = int(ngrp / ncol) + 1 + # use all of the space in the base layout + ngrp = nrow * ncol + # make all the groups have the same number of controller rows + if ('"$nctl"' % ngrp == 0) + maxnctl = '"$nctl"' / ngrp + else + maxnctl = int('"$nctl"' / ngrp) + 1 + print "ncol=" ncol " nrow=" nrow " maxnctl=" maxnctl + }'` +fi + +#DEBUG echo "nctl=$nctl maxnctl=$maxnctl ncol=$ncol nrow=$nrow" + +# heuristic hack for pmlaunch +# +if [ "$nctl" -gt 6 ] +then + group="_groupByInst" +else + group="_groupByMetric" +fi + +if [ -z "$titleArg" ] +then + titleArg="$Type Disk Activity ($Thru) for Host $host" +fi + +# +# pmview 2.0 +# + +echo ' +_grid (' >> $tmp.conf + +$PCP_AWK_PROG -v io=$Type -v max=$max -v group=$group -v thru="$Thru" <$tmp.order ' +BEGIN { row = 0; col = 0; cnt = 0; type = ""; ctl = "" + start_ctl = ""; label = ""; last_label = ""; last_ctl = "" + color[0] = "green" + color[1] = "blue" + color[2] = "red" + color[3] = "cyan" + color[4] = "violet" + color[5] = "yellow" + ncol = 5 + colorlist = "" + } + +function dumpLabel(start, last) +{ + printf(" _baseLabel \"%s Activity for Disks on ", io) + if (start != last) + printf("Controllers %s to %s", start, last) + else + printf("Controller %s", start) + printf("\\nNormalized to %s %s\"\n", max, thru) + printf(" _colorlist (%s )\n", colorlist ) + colorlist = "" +} + + { if (cnt % '"$maxnctl"' == 0) { + if (cnt > 0) { + print " )" + dumpLabel(start_ctl, last_ctl) + print " )" + } + printf("\n _bar %d %d north %s (\n", 2*col, 2*row, group) + print " _metrics (" + start_ctl = $1 + row++ + if (row >= '"$nrow"') { + col++ + row = 0 + } + } + printf(" disk.dev.'$type'[") + + for (d = 2; d <= NF; d++) { + if (d == 2) + printf("%s", $d) + else + printf(",%s", $d) + } + printf("] %s \"%s\"\n", max, $1) + if ($1 != last_ctl) { + # new controller, change colors + ncol++ + if (ncol > 5) + ncol = 0 + } + colorlist = colorlist " " color[ncol] + last_ctl = $1 + cnt++ + } +END { if (cnt > 0) { + print " )" + dumpLabel(start_ctl, last_ctl) + print " )" + } + print ")" + }' >> $tmp.conf + +$verbose && cat $tmp.conf + +eval $PMVIEW <$tmp.conf $args -title "'$titleArg'" # -xrm "'*iconName:dkvis'" + +exit |