diff options
Diffstat (limited to 'src/pmview/front-ends')
22 files changed, 4695 insertions, 0 deletions
diff --git a/src/pmview/front-ends/GNUmakefile b/src/pmview/front-ends/GNUmakefile new file mode 100644 index 0000000..c67f02b --- /dev/null +++ b/src/pmview/front-ends/GNUmakefile @@ -0,0 +1,25 @@ +TOPDIR = ../../.. +include $(TOPDIR)/src/include/builddefs + +#VIEWDIR = $(PCP_VAR_DIR)/config/pmview +VIEWDIR = $(PCP_BIN_DIR) +LOGDIR = $(PCP_VAR_DIR)/config/pmlogger +ARGSDIR = $(PCP_SHARE_DIR)/lib + +VIEWS = clustervis dkvis mpvis nfsvis osvis weblogvis webpingvis webvis +LOGGERS = config.dkvis config.mpvis config.nfsvis config.osvis \ + config.weblogvis config.webpingvis config.webvis + +LSRCFILES = $(VIEWS) $(LOGGERS) pmview-args + +default build-me: + +include $(BUILDRULES) + +install: default + #$(INSTALL) -m 755 -d $(VIEWDIR) + $(INSTALL) -m 755 $(VIEWS) $(VIEWDIR) + $(INSTALL) -m 755 -d $(LOGDIR) + $(INSTALL) -m 444 $(LOGGERS) $(LOGDIR) + $(INSTALL) -m 755 -d $(ARGSDIR) + $(INSTALL) -m 755 pmview-args $(ARGSDIR)/pmview-args diff --git a/src/pmview/front-ends/clustervis b/src/pmview/front-ends/clustervis new file mode 100755 index 0000000..6cab7aa --- /dev/null +++ b/src/pmview/front-ends/clustervis @@ -0,0 +1,331 @@ +#!/bin/sh +# +# Copyright (c) 2001 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.* +debug=false + +. $PCP_DIR/etc/pcp.env +. $PCP_SHARE_DIR/lib/pmview-args + +# --- scaling parameters --- +# + +# maximum packets per second +max=750 + +# maximum req rate (default: 5% of packet rate) +maxreq=`expr $max / 20` + +# milliseconds per CPU +maxcpu=1000 + +# +# clustervis tolerates multiple hosts or archives +_pmview_multiple_sources_are_ok + +# --- define usage message --- +# +_usage() +{ + echo >$tmp.msg 'Usage: '$prog' [options] + +Default hosts are specified in /etc/nodes (or /etc/ace/nodes) +or specify the file specifying cluster hosts with the -H flag. +The -h flag may be used to specify multiple hosts or the -a flag +may be used to specify multiple archives. The -h, -a and -H flags +are all mutually exclusive. + +options: + -H nodes file specifying hosts in cluster + [default $PCP_CLUSTER_CONFIG or /etc/nodes or /etc/ace/nodes] + -m max maximum expected packets sent or received per sec [default 750] + -V verbose/diagnostic output + +pmview(1) options:' + + _pmview_usage >> $tmp.msg + echo >> $tmp.msg + echo >> $tmp.msg 'Default title is: Web Server Activity' + echo >> $tmp.msg ' + By default all network interfaces are shown, with a maximum packet rate + of '$max' packets per second. The maximum request rate is 5% (of the + maximum packet rate) and the maximum error rate is 20% of the maximum + request rate. + + If given, the [interface ...] regular expressions restrict + the network statistics displayed to matching network interface names only.' + + _pmview_info -f $tmp.msg +} + +# --- build WM_COMMAND X(1) property for restart after login/logout --- +# +echo -n "pmview Version 2.1 \"$prog\"" > $tmp.pmview +for arg +do + echo -n " \"$arg\"" >>$tmp.pmview +done +echo >> $tmp.pmview + +# --- parse command line arguments --- +# +verbose=false +argInterfaces="" +hosts="" +interfaces="" +numsource=1 +if [ -z "$PCP_CLUSTER_CONFIG" ] +then + nodesfile=/etc/nodes + [ ! -f "$nodesfile" ] && nodesfile=/etc/ace/nodes +else + nodesfile="$PCP_CLUSTER_CONFIG" + if [ ! -f "$nodesfile" ] + then + echo "Error: \"$nodesfile\" specified in \$PCP_CLUSTER_CONFIG: file not found" + _usage + exit 1 + fi +fi + +livemode=false +for f in $* +do + [ $f = "-h" ] && livemode=true +done + +_pmview_args "$@" +$debug && echo "DEBUG msource=\"$msource\"" + +if [ -n "$otherArgs" ] +then + while getopts "?H:m:v:V" c $otherArgs + do + case $c + in + H) + nodesfile=$OPTARG + if [ ! -f "$nodesfile" ] + then + _pmview_error "$prog: \"$nodesfile\" for -H file not found" + #NOTREACHED + fi + ;; + m) + max=$OPTARG + if [ "X-$max" != "X`expr 0 + -$max 2>/dev/null`" ] + then + _pmview_error "$prog: -m must have a positive integral argument" + #NOTREACHED + fi + maxreq=`expr $max / 20` + ;; + + V) + verbose=true + ;; + + '?') + _usage + exit 1 + ;; + esac + done +fi + +if [ $numsource -eq 0 ] +then + if [ -f $nodesfile ] + then + livemode=true + sourcelist=`sed -e '/^#/d' $nodesfile` + numsource=`echo $sourcelist | wc -w` + else + _pmview_error "$prog: -H, -a or -h must be given" + fi +fi + +$debug && echo DEBUG sourcelist=\"$sourcelist\" +hostcols=`echo "sqrt($numsource)" | bc` +$debug && echo hostcols=$hostcols + + +# --- set the window title --- +# +if [ -z "$titleArg" ] +then + titleArg="SGI PCP : Cluster Node Activity" +fi + + +# ---- the real config starts here --- +# pmview Version 2.1 +# +cat << end-of-file >> $tmp.pmview + +_stackLength 26 +_marginWidth 4 +_marginDepth 4 + +_colorList net_colors ( + rgbi:0.8/0.0/0.0 + rgbi:0.0/0.8/0.8 + rgbi:1.0/0.5/0.0 +) + +_colorList cpu_colors ( red2 blue2 blue2 ) + +# main grid +_grid _show ( + +end-of-file + +hostrow=0 +hostcol=0 +for source in $sourcelist +do + if $livemode + then + host=$source + msource="-h $source" + else + host=`pmdumplog -l $source | $PCP_AWK_PROG '/^Performance/ {print $NF}'` + msource="-a $source" + fi + + nice=`pmprobe $msource -i kernel.all.cpu.nice | $PCP_AWK_PROG '{print $2; exit}'` + if [ "$nice" = 1 ] + then + nicemetric=kernel.percpu.cpu.nice + else + nicemetric="" + fi + + _pmview_cache_fetch -v \ + kernel.percpu.cpu.user $nicemetric \ + network.interface.in.packets \ + network.interface.out.packets + + # --- how many CPUs on this system? --- + # + if _pmview_fetch -I kernel.percpu.cpu.user + then + ncpu=`wc -l <$tmp.pmview_result` + else + _pmview_fetch_fail "get the number of CPUs" + fi + + _pmview_cache_fetch -I network.interface.total.bytes + + # --- how many network interfaces on this system? --- + # + if _pmview_fetch -I network.interface.in.packets + then + nnet=`grep -v '^lo' $tmp.pmview_result | wc -l` + else + _pmview_fetch_fail "get the number of network interfaces" + fi + + rows=`echo "sqrt($ncpu + $ncpu + $nnet + $nnet)" | bc` + [ $rows -lt 4 ] && rows=4 + row=0 + col=0 + + echo "# grid for host $host" >>$tmp.pmview + echo "_baseHeight 8" >>$tmp.pmview + echo "_grid $hostcol $hostrow _hide (" >>$tmp.pmview + + echo " _baseColor rgbi:0.4/0.4/0.6" >>$tmp.pmview + echo " _label 0 0 _down _large \"$host\"" >>$tmp.pmview + echo " _grid 1 0 _show (" >>$tmp.pmview + + _pmview_fetch -I kernel.percpu.cpu.user + for cpu in `cat $tmp.pmview_result` + do + echo " _label $row $col _west \"$cpu\"" >>$tmp.pmview + echo " _stack `expr $row + 1` $col _hide (" >>$tmp.pmview + echo " _metrics (" >>$tmp.pmview + echo " $host:kernel.percpu.cpu.sys[$cpu] $maxcpu" >>$tmp.pmview + if [ ! -z "$nicemetric" ] + then + echo " $host:kernel.percpu.cpu.nice[$cpu] $maxcpu" >>$tmp.pmview + fi + echo " $host:kernel.percpu.cpu.user[$cpu] $maxcpu" >>$tmp.pmview + echo " )" >>$tmp.pmview + echo " _colorlist cpu_colors" >>$tmp.pmview + echo " )" >>$tmp.pmview + + $debug && echo stack at row=`expr $row + 1` col=$col \"$cpu\" + $debug && echo label at row=$row col=$col + + col=`expr $col + 1` + if [ $col -ge $rows ] + then + col=0 + row=`expr $row + 2` + fi + done + + _pmview_fetch -I network.interface.in.packets + grep -v '^lo' $tmp.pmview_result >$tmp.net + for net in `cat $tmp.net` + do + echo " _label $row $col _west \"$net\"" >>$tmp.pmview + echo " _stack `expr $row + 1` $col _hide (" >>$tmp.pmview + echo " _metrics (" >>$tmp.pmview + echo " $host:network.interface.total.errors[$net] $max" >>$tmp.pmview + echo " $host:network.interface.in.packets[$net] $max" >>$tmp.pmview + echo " $host:network.interface.out.packets[$net] $max" >>$tmp.pmview + echo " )" >>$tmp.pmview + echo " _colorlist net_colors" >>$tmp.pmview + echo " )" >>$tmp.pmview + + $debug && echo stack at row=`expr $row + 1` col=$col \"$net\" + $debug && echo label at row=$row col=$col + + col=`expr $col + 1` + if [ $col -ge $rows ] + then + col=0 + row=`expr $row + 2` + fi + + done + echo " )" >>$tmp.pmview + row=`expr $row + 1` + echo "# end of host grid" >>$tmp.pmview + echo ")" >>$tmp.pmview + + hostcol=`expr $hostcol + 1` + if [ $hostcol -ge $hostcols ] + then + hostcol=0 + hostrow=`expr $hostrow + 1` + fi + +done + +echo "" >>$tmp.pmview +echo "# end of main grid" >>$tmp.pmview +echo ")" >>$tmp.pmview + +$verbose && cat $tmp.pmview + +eval $PMVIEW <$tmp.pmview $args -title "'$titleArg'" -xrm "'*iconName: $prog'" + +exit + diff --git a/src/pmview/front-ends/config.clustervis b/src/pmview/front-ends/config.clustervis new file mode 100644 index 0000000..118cb34 --- /dev/null +++ b/src/pmview/front-ends/config.clustervis @@ -0,0 +1,13 @@ +# +# pmlogger(1) configuration file suitable creating an archive to be +# used with clustervis(1) +# + +log advisory on default { + kernel.percpu.cpu.sys + kernel.percpu.cpu.user + network.interface.in.packets + network.interface.out.packets + network.interface.total.bytes + network.interface.total.errors +} diff --git a/src/pmview/front-ends/config.dkvis b/src/pmview/front-ends/config.dkvis new file mode 100755 index 0000000..03e0e31 --- /dev/null +++ b/src/pmview/front-ends/config.dkvis @@ -0,0 +1,14 @@ +# +# pmlogger(1) configuration file suitable creating an archive to be +# used with dkvis(1) +# + +log advisory on default { + disk.dev.total + disk.dev.read + disk.dev.write + disk.dev.bytes + disk.dev.read_bytes + disk.dev.write_bytes + disk.dev.total_bytes +} diff --git a/src/pmview/front-ends/config.mpvis b/src/pmview/front-ends/config.mpvis new file mode 100755 index 0000000..f28ce84 --- /dev/null +++ b/src/pmview/front-ends/config.mpvis @@ -0,0 +1,13 @@ +# +# pmlogger(1) configuration file suitable creating an archive to be +# used with mpvis(1) +# + +log advisory on default { + kernel.percpu.cpu.idle + kernel.percpu.cpu.intr + kernel.percpu.cpu.sys + kernel.percpu.cpu.sxbrk + kernel.percpu.cpu.user + kernel.percpu.cpu.wait.total +} diff --git a/src/pmview/front-ends/config.nfsvis b/src/pmview/front-ends/config.nfsvis new file mode 100755 index 0000000..f8ab0fb --- /dev/null +++ b/src/pmview/front-ends/config.nfsvis @@ -0,0 +1,12 @@ +# +# pmlogger(1) configuration file suitable creating an archive to be +# used with nfsvis(1) +# + +log advisory on default { + nfs +} + +log advisory on default { + nfs3 +} diff --git a/src/pmview/front-ends/config.osvis b/src/pmview/front-ends/config.osvis new file mode 100755 index 0000000..629a3a4 --- /dev/null +++ b/src/pmview/front-ends/config.osvis @@ -0,0 +1,31 @@ +# +# pmlogger(1) configuration file suitable creating an archive to be +# used with osvis(1) +# +log mandatory on once { + hinv.ncpu + hinv.ndisk + hinv.physmem + mem.physmem +} + +log advisory on default { + disk.all.avg_disk.active + disk.all.read + disk.all.write + disk.ctl.avg_disk.active + kernel.all.load + kernel.all.cpu.intr + kernel.all.cpu.sys + kernel.all.cpu.user + kernel.all.cpu.wait.total + mem.freemem + mem.util + network.interface.in.bytes + network.interface.in.packets + network.interface.in.errors + network.interface.out.bytes + network.interface.out.packets + network.interface.out.errors +} + diff --git a/src/pmview/front-ends/config.weblogvis b/src/pmview/front-ends/config.weblogvis new file mode 100755 index 0000000..1d3453f --- /dev/null +++ b/src/pmview/front-ends/config.weblogvis @@ -0,0 +1,20 @@ +# +# pmlogger(1) configuration file suitable creating an archive to be +# used with weblogvis(1) +# + +log advisory on default { + web.perserver.logidletime + web.perserver.requests.total + web.perserver.bytes.total + web.perserver.requests.size.unknown + web.perserver.requests.size.gt3m + web.perserver.requests.size.le3m + web.perserver.requests.size.le1m + web.perserver.requests.size.le300k + web.perserver.requests.size.le100k + web.perserver.requests.size.le30k + web.perserver.requests.size.le10k + web.perserver.requests.size.le3k + web.perserver.requests.size.zero +} diff --git a/src/pmview/front-ends/config.webpingvis b/src/pmview/front-ends/config.webpingvis new file mode 100755 index 0000000..078ab3c --- /dev/null +++ b/src/pmview/front-ends/config.webpingvis @@ -0,0 +1,8 @@ +# +# pmlogger(1) configuration file suitable creating an archive to be +# used with webpingvis(1) +# + +log advisory on default { + webpingvis +} diff --git a/src/pmview/front-ends/config.webvis b/src/pmview/front-ends/config.webvis new file mode 100644 index 0000000..08394fc --- /dev/null +++ b/src/pmview/front-ends/config.webvis @@ -0,0 +1,51 @@ +# +# pmlogger(1) configuration file suitable creating an archive to be +# used with webvis(1) +# + +# file system and hinv stats +# (log these once so they _definitely_ exist at start of archive) +log advisory on once { + hinv.ncpu + hinv.physmem + hinv.ndisk + mem.physmem + disk.dev.read +} + +log advisory on 60 seconds { + # Kernel, disk and swap and paging metrics + disk.all.read + disk.all.write + disk.all.avg_disk.active + kernel.all.cpu.idle + kernel.all.cpu.intr + kernel.all.cpu.sys + kernel.all.cpu.user + kernel.all.cpu.wait.total + mem.freemem + mem.util.kernel + mem.util.fs_ctl + mem.util.fs_dirty + mem.util.fs_clean + mem.util.user + swap.pagesout + network.interface.out.drops + network.interface.out.errors + network.interface.out.packets + network.interface.in.drops + network.interface.in.errors + network.interface.in.packets + network.interface.total.bytes + # Network data rates and error conditions + network.tcp.drops + network.tcp.conndrops + network.tcp.timeoutdrop + network.tcp.sndrexmitpack + network.tcp.rcvbadsum + network.tcp.rexmttimeo + network.mbuf.failed + network.mbuf.waited + # Web logs - both frequent and infrequent samples + web.allservers +} 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 diff --git a/src/pmview/front-ends/mpvis b/src/pmview/front-ends/mpvis new file mode 100755 index 0000000..dd7db78 --- /dev/null +++ b/src/pmview/front-ends/mpvis @@ -0,0 +1,452 @@ +#!/bin/sh +# Copyright (c) 1997-2001 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 + +gridspace=120 +cpuargs= + +algorithm="k" +default_layout=true +force=false +maxrowlen=16 +verbose=false +showinst=false +version=2 + +_usage() +{ + echo >$tmp.msg 'Usage: mpvis [options] [cpuid...] + +options: + -b use row:column ratio of 1:8 (soft limit) + [default, if 64 or more CPUs] + -i show CPU numbers + -r rowlen maximum number of CPUs per row (soft limit) + [default 16, if less than 64 CPUs] + -R rowlen force this number of CPUs per row + -V verbose/diagnostic output + +pmview(1) options:' + + _pmview_usage >>$tmp.msg + echo >>$tmp.msg + echo 'Default title is: CPU Utilization for Host' >>$tmp.msg + _pmview_info -f $tmp.msg +} + +# generate one row of the scene +# +_do_row() +{ +if [ "$1" = "$2" ] +then + msg="$titleArg\n$1 only" +else + msg="$titleArg\n$1 to $2" +fi + +cat <<End-of-File >>$tmp.conf + _grid 0 $3 show ( + _baseLabel "$msg" + _bar $group ( + _metrics ( +End-of-File +$have_idle && echo " kernel.percpu.cpu.idle[$rowlist] $max_util \"idle\"" >>$tmp.conf +$have_wait && echo " kernel.percpu.cpu.wait.total[$rowlist] $max_util \"wait\"" >>$tmp.conf +$have_intr && echo " kernel.percpu.cpu.intr[$rowlist] $max_util \"intr\"" >>$tmp.conf +$have_nice && echo " kernel.percpu.cpu.nice[$rowlist] $max_util \"nice\"" >>$tmp.conf +$have_sys && echo " kernel.percpu.cpu.sys[$rowlist] $max_util \"sys\"" >>$tmp.conf +$have_user && echo " kernel.percpu.cpu.user[$rowlist] $max_util \"user\"" >>$tmp.conf +cat <<End-of-File >>$tmp.conf + ) +End-of-File +$showinst && echo " _instlabels away ( $labels )" >>$tmp.conf +cat <<End-of-File >>$tmp.conf + _colorlist cpu + _baseLabel "$msg" + ) + ) +End-of-File +} + +# build WM_COMMAND X(1) property for restart after login/logout +# +echo -n "pmview Version 2.1 \"mpvis\"" >$tmp.conf +for arg +do + echo -n " \"$arg\"" >>$tmp.conf +done + +_pmview_args "$@" + +if [ "X$otherArgs" != X ] +then + while getopts "bir:R:v:V?" c $otherArgs + do + case $c + in + b) + algorithm="b" + default_layout=false + ;; + i) + showinst=true + gridspace=60 + ;; + r) + _pmview_unsigned $c + maxrowlen=$OPTARG + default_layout=false + ;; + R) + _pmview_unsigned $c + maxrowlen=$OPTARG + default_layout=false + force=true + ;; + + v) + version=$OPTARG + if [ $version = "1" ] + then + _pmview_warning "$prog: pmview version 1 no longer supported, using version 2" + version=2 + elif [ $version != "2" ] + then + _pmview_error "$prog: only version 2 supported for -v" + # NOTREACHED + fi + ;; + + V) + verbose=true + ;; + ?) + _usage + exit 1 + ;; + esac + done + set -- $otherArgs + shift `expr $OPTIND - 1` + + [ $# -gt 0 ] && cpuargs=$@ +fi + +[ -z "$titleArg" ] && titleArg="SGI PCP : CPU Utilization for Host $host" + +_pmview_cache_fetch -I kernel.percpu.cpu.user +_pmview_cache_fetch -v kernel.percpu.cpu.idle \ + kernel.percpu.cpu.wait.total \ + kernel.percpu.cpu.intr \ + kernel.percpu.cpu.nice \ + kernel.percpu.cpu.sys \ + kernel.percpu.cpu.user + + +# Check that we can get the metrics +# +if _pmview_fetch_indom kernel.percpu.cpu.user +then + if [ ! -s "$tmp.pmview_result" -o "$number" -lt 1 ] + then + _pmview_fetch_fail "get CPU inventory" + fi +else + _pmview_fetch_fail "get CPU inventory" + # NOTREACHED +fi + +if [ ! -z "$cpuargs" ] +then + # restrict based on command line args + # + rm -f $tmp.tmp $tmp.msg + ncpu=0 + for cpu in $cpuargs + do + if echo "$cpu" | grep '[.[^]' >/dev/null + then + # assume egrep(1) regular expression + # + if egrep "$cpu" $tmp.pmview_result >>$tmp.tmp + then + # found some matches + # + : + else + echo "$prog: pattern \"$cpu\" does not match any CPUs ..." >$tmp.msg + fi + elif grep "^$cpu\$" $tmp.pmview_result >/dev/null + then + echo $cpu >>$tmp.tmp + else + echo "$prog: CPU \"$cpu\" not in the CPU inventory" >$tmp.msg + fi + done + if [ -s $tmp.msg ] + then + echo "CPUs on host \"$host\" are:" >> $tmp.msg + tr < $tmp.pmview_result '\012' ' ' | fmt | sed -e "s/^/ /" >> $tmp.msg + _pmview_error -f $tmp.msg + # NOTREACHED + fi + sort $tmp.tmp | uniq > $tmp.pmview_result + ncpu=`wc -l $tmp.pmview_result | $PCP_AWK_PROG '{print $1}'` +else + ncpu=$number +fi + +if [ "$ncpu" -ge 64 -a "$default_layout" = true ] +then + # >= 64p, no -b, -r or -R options ... make -b the default + # + algorithm="b" +fi + +# sort list +# +if grep cpu: $tmp.pmview_result >/dev/null +then + # Origin series name style + sed -e 's/:/./' < $tmp.pmview_result \ + | sort -t. +1n -2 +2n -3 +3 -4 \ + | sed -e 's/\./:/' \ + > $tmp.cpulist +else + # CPU names for older systems + sed -e 's/cpu/cpu./' < $tmp.pmview_result \ + | sort -t. +1n -2 \ + | sed -e 's/\.//' \ + > $tmp.cpulist +fi + +scale='' +have_idle=false +if _pmview_fetch_values kernel.percpu.cpu.idle +then + have_idle=true + [ -z "$scale" ] && scale=`pminfo $namespace $msource -d kernel.percpu.cpu.idle| sed -n '/Semantics:/s/.*Units: //p'` +fi + +have_wait=false +if _pmview_fetch_values kernel.percpu.cpu.wait.total +then + have_wait=true + [ -z "$scale" ] && scale=`pminfo $namespace $msource -d kernel.percpu.cpu.wait.total | sed -n '/Semantics:/s/.*Units: //p'` +fi + +have_intr=false +if _pmview_fetch_values kernel.percpu.cpu.intr +then +# linux 2.6 has wait and intr, but 2.4 does not + have_intr=`$PCP_AWK_PROG -v found=false ' + $1 > 0 { found="true" } + END { print found }' $tmp.pmview_result` + have_wait=$have_intr + [ -z "$scale" ] && scale=`pminfo $namespace $msource -d kernel.percpu.cpu.intr | sed -n '/Semantics:/s/.*Units: //p'` +fi + +have_nice=false +if _pmview_fetch_values kernel.percpu.cpu.nice +then + have_nice=true + [ -z "$scale" ] && scale=`pminfo $namespace $msource -d kernel.percpu.cpu.nice | sed -n '/Semantics:/s/.*Units: //p'` +fi + +have_sys=false +if _pmview_fetch_values kernel.percpu.cpu.sys +then + have_sys=true + [ -z "$scale" ] && scale=`pminfo $namespace $msource -d kernel.percpu.cpu.sys | sed -n '/Semantics:/s/.*Units: //p'` +fi + +have_user=false +if _pmview_fetch_values kernel.percpu.cpu.user +then + have_user=true + [ -z "$scale" ] && scale=`pminfo $namespace $msource -d kernel.percpu.cpu.user | sed -n '/Semantics:/s/.*Units: //p'` +fi + +case $scale +in + microsec) + max_util=1000000 + ;; + millisec) + max_util=1000 + ;; + *) + _pmview_warning "$prog: cannot determine CPU time units, assuming milliseconds" + max_util=1000 + ;; +esac + +# shape the base geometry for the scene +# +if [ $ncpu -le "$maxrowlen" ] +then + nrows=1 + ncols=$ncpu +elif $force +then + nrows=`echo $ncpu $maxrowlen | $PCP_AWK_PROG ' \ + { x = $1 / $2; y = $1 % $2; if (y > 0) ++x; printf "%d\n", x; }'` + ncols=$maxrowlen +else + case $algorithm in + a) # this algorithm doesn't work at the moment + # (the exit condition is not robust enough) + nrows=1 + ncols=1 + bound=1 + num=0 + while [ $num -gt $ncols -o $num -lt $bound ] + do + nrows=`expr $nrows \* 2` + ncols=`expr $ncpu / $nrows` + bound=`expr $ncols / 2` + num=`expr $nrows \* 4` + done + ncols=`echo $ncpu $nrows | $PCP_AWK_PROG ' { x = $1 / $2; y = $1 % $2; \ + if (y > 0) ++x; printf "%d\n", x }'` + ;; + b) + # use a ratio for rows:columns of 1:8 + # + nrows=`echo $ncpu | $PCP_AWK_PROG ' { x = sqrt ($1 / 8.0); + y = int (x); if (y < x) ++y; print y }'` + ncols=`expr $ncpu + $nrows - 1` + ncols=`expr $ncols / $nrows` + ;; + k) + nrows=`expr $ncpu + $maxrowlen - 1` + nrows=`expr $nrows / $maxrowlen` + ncols=`expr $ncpu + $nrows - 1` + ncols=`expr $ncols / $nrows` + esac +fi + +if [ "$ncols" -gt 6 ] +then + group="_groupByMetric" +else + group="_groupByInst" +fi + +cat <<End-of-File >>$tmp.conf + +# +# mpvis +# +# ncpus = $ncpu +# nrows = $nrows +# ncols = $ncols +# +# List: +End-of-File + +col=0 +rowlist="" +cat $tmp.cpulist | while read cpu +do + if [ $col -eq 0 ] + then + echo -n "$cpu " > $tmp.rowlist + else + echo -n "$cpu " >> $tmp.rowlist + fi + col=`expr $col + 1` + if [ "$col" -eq $ncols ] + then + echo "# "`cat $tmp.rowlist` >>$tmp.conf + col=0 + rm -f $tmp.rowlist + fi +done + +[ -s $tmp.rowlist ] && echo "# "`cat $tmp.rowlist` >>$tmp.conf + +echo "_gridSpace $gridspace" >>$tmp.conf +echo >>$tmp.conf + +colorlist="_colorlist cpu (" +$have_idle && colorlist="$colorlist green2" +$have_wait && colorlist="$colorlist cyan2" +$have_intr && colorlist="$colorlist yellow2" +$have_nice && colorlist="$colorlist rgbi:0.6/1.0/0.7" +$have_sys && colorlist="$colorlist red2" +$have_user && colorlist="$colorlist blue2" +colorlist="$colorlist )" + +echo "$colorlist" >>$tmp.conf +echo "_grid 0 0 _hide ( # outer grid" >>$tmp.conf + +# build rows from front-to-back of scene +# fill rows with CPUs from left-to-right +# +y=`expr $nrows \* 2 - 2` +col=0 +rowlist="" +labels="" +cat $tmp.cpulist | while read cpu +do + if [ $col -eq 0 ] + then + rowlist=$cpu + start=$cpu + else + rowlist="$rowlist,$cpu" + fi + $showinst && labels="$labels \"`echo $cpu | sed -e 's/cpu:*//'`\"" + col=`expr $col + 1` + echo "$start $cpu $y $rowlist $labels" > $tmp.rowlist + if [ $col -eq $ncols ] + then + _do_row $start $cpu $y + col=0 + echo -n "" > $tmp.rowlist + labels="" + y=`expr $y - 2` + fi +done + +if [ -s $tmp.rowlist ] +then + read start cpu y rowlist labels < $tmp.rowlist + # cat $tmp.rowlist + _do_row $start $cpu $y +fi + +echo ")" >>$tmp.conf + +if [ $nrows -eq 1 ] +then + # remove unnecessary _grid for a single row + # + sed -e '/^ _grid/d' -e '/^ )/d' <$tmp.conf >$tmp.tmp + mv $tmp.tmp $tmp.conf +fi + +$verbose && cat $tmp.conf + +eval $PMVIEW <$tmp.conf $args -title "'$titleArg'" -xrm "'*iconName:mpvis'" + +exit diff --git a/src/pmview/front-ends/nfsvis b/src/pmview/front-ends/nfsvis new file mode 100755 index 0000000..26b87ae --- /dev/null +++ b/src/pmview/front-ends/nfsvis @@ -0,0 +1,244 @@ +#! /bin/sh +# Copyright (c) 1997-2001 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] + +options: + -c version Monitor NFS version (integer) client metrics [default 2] + -m maxrate maximum request rate expected (integer) [default 120] + -s version Monitor NFS version (integer) server metrics [default 2] + -V verbose/diagnostic output + +pmview(1) options:' + + _pmview_usage >>$tmp.msg + echo >>$tmp.msg + echo 'Default title is: NFS Version 2 Request Traffic for host' >>$tmp.msg + _pmview_info -f $tmp.msg +} + +max=120 +client=2 +server=2 +type=total +Type=Total +verbose=false +version=2 + +# build WM_COMMAND X(1) property for restart after login/logout +# +echo -n "pmview Version 2.1 \"nfsvis\"" >$tmp.conf +for arg +do + echo -n " \"$arg\"" >>$tmp.conf +done + +_pmview_args "$@" + +if [ -n "$otherArgs" ] +then + while getopts "?c:m:s:v:V" c $otherArgs + do + case $c + in + c) + client=$OPTARG + if [ "$client" != 2 -a "$client" != 3 ] + then + _pmview_error "$prog: only NFS 2 and NFS 3 client metrics supported" + # NOTREACHED + fi + ;; + m) + _pmview_unsigned $c + max=$OPTARG + ;; + s) + server=$OPTARG + if [ "$server" != 2 -a "$server" != 3 ] + then + _pmview_error "$prog: only NFS 2 and NFS 3 server metrics supported" + # NOTREACHED + fi + ;; + + v) + version=$OPTARG + if [ $version = "1" ] + then + _pmview_warning "$prog: pmview version 1 no longer supported, using version 2" + version=2 + elif [ $version != "2" ] + then + _pmview_error "$prog: only version 2 supported for -v" + # NOTREACHED + fi + ;; + + V) + verbose=true + ;; + ?) + _usage + exit 1 + ;; + esac + done + set - $otherArgs + shift `expr $OPTIND - 1` + if [ $# -gt 0 ] + then + _usage + exit 1 + fi +fi + +if [ "$client" = "2" ] +then + # NFS V2 client stats + # + if _pmview_fetch_indom nfs.client.reqs + then + : + else + _pmview_fetch_fail "get NFS Version 2 client metrics" + # NOTREACHED + fi +else + # NFS V3 client stats + # + if _pmview_fetch_indom nfs3.client.reqs + then + : + else + _pmview_fetch_fail "get NFS Version 3 client metrics" + # NOTREACHED + fi +fi + +# handle fsstat alias statfs +# +c_statfs=statfs +grep fsstat $tmp.pmview_result >/dev/null && c_statfs=fsstat + +if [ "$server" = "2" ] +then + # NFS V2 server stats + # + if _pmview_fetch_indom nfs.server.reqs + then + : + else + _pmview_fetch_fail "get NFS Version 2 server metrics" + # NOTREACHED + fi +else + # NFS V3 server stats + # + if _pmview_fetch_indom nfs3.server.reqs + then + : + else + _pmview_fetch_fail "get NFS Verion 3 server metrics" + # NOTREACHED + fi +fi + +# handle fsstat alias statfs +# +s_statfs=statfs +grep fsstat $tmp.pmview_result >/dev/null && s_statfs=fsstat + +if [ -z "$titleArg" ] +then + titleArg="SGI PCP : NFS Client V$client & Server V$server Request Traffic for host $host" +fi + + +cat << End-of-File >> $tmp.conf + +# +# nfsvis +# +_colorlist colors (red1 green1 blue1) +_grid hide ( + _label 2 0 _down _large "Client" + _bar 0 0 _east _groupByMetric ( + _metrics ( +End-of-File + +if [ "$client" = "2" ] +then + cat << End-of-File >> $tmp.conf + nfs.client.reqs[create,remove,rename,link,symlink,mkdir,rmdir] $max "dir" + nfs.client.reqs[getattr,setattr,lookup,readdir,$c_statfs,root] $max "attr" + nfs.client.reqs[readlink,read,write,wrcache] $max "data" + ) + _baseLabel "Requests by NFS2 Client\nNormalized to $max requests / second" +End-of-File +else + cat << End-of-File >> $tmp.conf + nfs3.client.reqs[create,remove,rename,link,symlink,mkdir,rmdir,mknod] $max "dir" + nfs3.client.reqs[getattr,setattr,lookup,readdir,$c_statfs,access,readdir+,fsinfo,pathconf] $max "attr" + nfs3.client.reqs[readlink,read,write,commit] $max "data" + ) + _baseLabel "Requests by NFS3 Client\nNormalized to $max requests / second" +End-of-File +fi +cat << End-of-File >> $tmp.conf + _colorlist colors + ) + _label 2 2 _down _large "Server" + _bar 0 2 _east ( + _metrics ( +End-of-File +if [ "$server" = "2" ] +then + cat << End-of-File >> $tmp.conf + nfs.server.reqs[create,remove,rename,link,symlink,mkdir,rmdir] $max "dir" + nfs.server.reqs[getattr,setattr,lookup,readdir,$s_statfs,root] $max "attr" + nfs.server.reqs[readlink,read,write,wrcache] $max "data" + ) + _baseLabel "Requests to NFS2 Server\nNormalized to $max requests / second" +End-of-File +else + cat << End-of-File >> $tmp.conf + nfs3.server.reqs[create,remove,rename,link,symlink,mkdir,rmdir,mknod] $max "dir" + nfs3.server.reqs[getattr,setattr,lookup,readdir,$s_statfs,access,readdir+,fsinfo,pathconf] $max "attr" + nfs3.server.reqs[readlink,read,write,commit] $max "data" + ) + _baseLabel "Requests to NFS3 Server\nNormalized to $max requests / second" +End-of-File +fi + +cat << End-of-File >> $tmp.conf + _colorlist colors + ) +) +End-of-File + +$verbose && cat $tmp.conf + +eval $PMVIEW <$tmp.conf $args -title "'$titleArg'" -xrm "'*iconName:nfsvis'" + +exit diff --git a/src/pmview/front-ends/osvis b/src/pmview/front-ends/osvis new file mode 100644 index 0000000..a704446 --- /dev/null +++ b/src/pmview/front-ends/osvis @@ -0,0 +1,651 @@ +#! /bin/sh +# Copyright (c) 1995-2003 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 + +# +# scaling parameters +# + +# maximum network packets per second +maxpack=750 + +# maximum error packets per second +maxerr=`expr $maxpack / 100` + +# maximum network bytes per second +maxbyte=65536 + +# maximum disk io rate (I/O operations per second) +maxio=100 + +# milliseconds per CPU +maxcpu=1000 + +# maximum disk activity +maxdisk=30 + +_usage() +{ + echo >$tmp.msg 'Usage: '$prog' [options] [interface [interface ...]] + +options: + -b bytes maximum expected network throughput [default 65536 bytes] + -d activity maximum expected disk activity as a percentage [default 30] + -i ops maximum expected I/O operations per seconds [default 100] + -m packets maximum expected packets sent or received per sec [default 750] + -V verbose/diagnostic output + +pmview(1) options:' + _pmview_usage >>$tmp.msg + echo >> $tmp.msg + echo 'Default title is: High-Level Activity for Host' >> $tmp.msg + + echo >>$tmp.msg ' + By default all network interfaces are shown, with a maximum packet rate + of '$maxpack' packets per second and error rate of '$maxerr' packets per second. + + If given, the [interface [interface ...]] regular expressions restrict + the network statistics displayed to matching network interface names only.' + + _pmview_info -f $tmp.msg +} + +argInterfaces="" +verbose=false +interfaces="" + +# build WM_COMMAND X(1) property for restart after login/logout +# +echo -n "pmview Version 2.1 \"osvis\"" >$tmp.conf +for arg +do + echo -n " \"$arg\"" >>$tmp.conf +done + +_pmview_args "$@" + +if [ -n "$otherArgs" ] +then + while getopts "?b:d:i:m:r:v:V" c $otherArgs + do + case $c + in + + b) + _pmview_unsigned $c + maxbyte=$OPTARG + ;; + + d) + _pmview_unsigned $c + maxdisk=$OPTARG + ;; + + i) + _pmview_unsigned $c + maxio=$OPTARG + ;; + + m) + _pmview_unsigned $c + maxpack=$OPTARG + ;; + + V) + verbose=true + ;; + + '?') + _usage + exit 1 + ;; + esac + done + + set -- $otherArgs + shift `expr $OPTIND - 1` + if [ $# -gt 0 ] + then + argInterfaces="$*" + fi +fi + +cat << end-of-file >> $tmp.conf + +# +# osvis +# +end-of-file + +# maximum req error rate (default: 1% of packet rate) +maxerr=`expr $maxpack / 100` +[ "$maxerr" -eq 0 ] && maxerr=1 + +_pmview_cache_fetch -v hinv.ncpu \ + hinv.ndisk \ + disk.all.avg_disk.active \ + mem.util \ + hinv.physmem \ + mem.physmem \ + kernel.all.cpu.wait.total \ + kernel.all.cpu.intr \ + kernel.all.cpu.nice \ + kernel.all.cpu.sys \ + kernel.all.cpu.user + +_pmview_cache_fetch -I network.interface.in.bytes \ + disk.ctl.avg_disk.active + +if _pmview_fetch_values hinv.ncpu +then + ncpu=`cat $tmp.pmview_result` + maxcpu=`expr $maxcpu \* $ncpu` + maxload=`expr $ncpu \* 2` +else + _pmview_fetch_fail "get the number of CPUs" +fi + +if [ $ncpu -eq 1 ] +then + cpudesc="1 CPU" +else + cpudesc="$ncpu CPUs" +fi + +$verbose && echo "# $cpudesc detected" >> $tmp.conf + +if _pmview_fetch_indom network.interface.in.bytes +then + ninterfaces=$number +else + _pmview_fetch_warn "get the number of network interfaces" + ninterfaces=0 +fi + +[ $ninterfaces -gt 0 ] && sed < $tmp.pmview_result -e 's/lo[0-9]*//g' -e 's/sl[0-9]*//g' -e 's/ppp[0-9]*//g' > $tmp.list + +[ ! -s $tmp.list ] && ninterfaces=0 + +if $verbose +then + echo "# Available Network Interfaces: "`cat $tmp.list | tr '\012' ' '` >> $tmp.conf +fi + +if [ $ninterfaces -gt 0 ] +then + if [ -z "$argInterfaces" ] + then + cp $tmp.list $tmp.chosen + else + touch $tmp.chosen + for i in $argInterfaces + do + egrep $i $tmp.list >> $tmp.chosen + done + fi + + interfaces_sp=`cat $tmp.chosen | sort | uniq` + interfaces=`echo $interfaces_sp | sed -e 's/ /,/g'` + ninterfaces=`echo $interfaces | wc -w` + + if $verbose + then + echo "# Network interfaces Matching \"$argInterfaces\": $interfaces" >> $tmp.conf + fi + + if [ $ninterfaces -eq 0 ] + then + echo "$prog: no matching network interfaces for \"$argInterfaces\"" > $tmp.msg + echo "Available network interfaces on host \"$host\" are: " >> $tmp.msg + tr < $tmp.list '\012' ' ' | fmt | sed -e "s/^/ /" >> $tmp.msg + _pmview_error -f $tmp.msg + #NOTREACHED + fi +fi + +if _pmview_fetch_values hinv.ndisk +then + ndisk=`cat $tmp.pmview_result` + maxdiskscale=`expr $maxdisk \* 10` +else + ndisk=0 + maxdiskscale=0 +fi + +if [ $ndisk -eq 1 ] +then + diskdesc="1 Disk" +else + diskdesc="$ndisk Disks" +fi + +$verbose && echo "# $diskdesc detected" >> $tmp.conf + +if [ "$ndisk" -gt 0 ] +then + + if _pmview_fetch_values disk.all.avg_disk.active + then + allAvg=true + else + allAvg=false + fi + + if _pmview_fetch_indom disk.ctl.avg_disk.active + then + nctrl=$number + cp $tmp.pmview_result $tmp.ctrls + else + nctrl=0 + fi + + if [ $nctrl -eq 1 ] + then + ctrldesc="1 Disk Controller" + else + ctrldesc="$nctrl Disk Controllers" + fi + + if [ "$nctrl" -gt 0 ] + then + + collen=`expr $ninterfaces + 3` + collensq=`expr $collen \* $collen` + + if [ $nctrl -le $collen ] + then + ctrlcols=$nctrl + elif [ $nctrl -le $collensq ] + then + ctrlcols=$collen + else + ctrlcols=`echo $nctrl \ + | $PCP_AWK_PROG '{x = sqrt($1); y = int(x); if (y < x) y++; print y }'` + fi + fi + + if $verbose + then + echo "# $ctrldesc detected: "`tr < $tmp.ctrls ' ' '\012'` >> $tmp.conf + echo "#" >> $tmp.conf + fi +fi + +linuxutilmem=false +utilmem=false +if _pmview_fetch_values mem.util.used +then + linuxutilmem=true + if $verbose + then + echo "# Linux memory utilization metrics supported" >> $tmp.conf + echo "#" >> $tmp.conf + fi +else + linuxutilmem=false + if _pmview_fetch_values mem.util + then + utilmem=true + if $verbose + then + echo "# Memory utilization metrics supported" >> $tmp.conf + echo "#" >> $tmp.conf + fi + else + utilmem=false + if $verbose + then + _pmview_warning "$prog: Memory utilization metrics not supported, showing free memory only" + echo "# Memory utilization metrics not supported, showing free memory only" >> $tmp.conf + echo "#" >> $tmp.conf + fi + fi +fi + +# Use mem.physmem if available, otherwise hinv.physmem will do. +if _pmview_fetch_values mem.physmem +then + realmem=`cat $tmp.pmview_result` +elif _pmview_fetch_values hinv.physmem +then + realmem=`cat $tmp.pmview_result` + realmem=`expr $realmem \* 1024` +else + realmem=0 + + if $utilmem + then + if $verbose + then + echo "# Unable to determine total real memory" >> $tmp.conf + echo "# Showing memory utilisation with free memory" >> $tmp.conf + fi + else + _pmview_warning "Unable to determine size of real memory on host \"$host\"" + fi +fi + +have_wait=false +if _pmview_fetch_values kernel.all.cpu.wait.total +then + have_wait=true +fi + +have_intr=false +if _pmview_fetch_values kernel.all.cpu.intr +then + have_intr=true +fi + +have_nice=false +if _pmview_fetch_values kernel.all.cpu.nice +then + have_nice=true +# linux hack !! +# these metrics are not actually supported in linux + have_intr=false + have_wait=false +fi + +have_sys=false +if _pmview_fetch_values kernel.all.cpu.sys +then + have_sys=true +fi + +have_user=false +if _pmview_fetch_values kernel.all.cpu.user +then + have_user=true +fi + +cpucolors="(" +$have_user && cpucolors="$cpucolors blue2" +$have_sys && cpucolors="$cpucolors red2" +$have_nice && cpucolors="$cpucolors rgbi:0.6/1.0/0.7" +$have_intr && cpucolors="$cpucolors yellow2" +$have_wait && cpucolors="$cpucolors cyan2" +cpucolors="$cpucolors )" + +if [ -z "$titleArg" ] +then + titleArg="SGI PCP : High-Level Activity for Host $host" +fi + +cat << end-of-file >> $tmp.conf + +_colorlist cpu_colors $cpucolors +_colorlist disk_colors ( violet yellow ) +_colorlist ctrl_colors ( green2 ) +_colorlist network_colors ( green2 blue2 red2 ) + +_colorlist memory_colors ( + rgbi:1.0/1.0/0.0 + rgbi:0.0/1.0/1.0 + rgbi:1.0/0.0/0.0 + rgbi:1.0/0.0/1.0 + rgbi:0.0/0.0/1.0 + rgbi:0.0/1.0/0.0 +) + +_grid hide ( + +# +# System level stuff +# +end-of-file + +if [ "$ndisk" -gt 0 ] +then + cat << end-of-file >> $tmp.conf + + _label 0 1 _down _large "Disk" + + _stack 1 1 _west _cylinder ( + _metrics ( + disk.all.write $maxio + disk.all.read $maxio + ) + _colorlist disk_colors + _baseLabel "Disk Operations\nNormalized to $maxio I/Os per second" + ) +end-of-file + + if $allAvg + then + cat << end-of-file >> $tmp.conf + + _bar 2 1 _west _cylinder ( + _metrics ( + disk.all.avg_disk.active $maxdiskscale + ) + _colorlist ctrl_colors + _baseLabel "Disk Activity\nNormalized to ${maxdisk}% for $ndisk disks" + ) +end-of-file + fi + + if [ "$nctrl" -gt 0 ] + then + cat << end-of-file >> $tmp.conf + + _label 4 0 _west "Disk Controllers" + + _bar 4 1 _west _cylinder ( + _metrics ( +end-of-file + + cat $tmp.ctrls | tr '\012' ' ' \ + | $PCP_AWK_PROG -v cols=$ctrlcols -v scale=$maxdiskscale >> $tmp.conf ' +BEGIN { str = ""; j = 0 } + { for (i = 1; i <= NF; i++) { + if (str == "") + str = $i; + else + str = str "," $i + if (j == cols) { + printf(" disk.ctl.avg_disk.active[%s] %d\n", str, scale); + str = ""; + j = 0; + } + else + j++; + } + } +END { if (str != "") + printf(" disk.ctl.avg_disk.active[%s] %d\n", str, scale); + }' + + cat << end-of-file >> $tmp.conf + ) + _colorlist ctrl_colors + _baseLabel "Disk Controller Activity\nNormalized to ${maxdisk}% for the disks on each controller" + ) +end-of-file + + fi +fi + +cat << end-of-file >> $tmp.conf + + _label 0 3 _west _down _large "Load" + + _bar 1 3 2 1 _west ( + _metrics ( + kernel.all.load[15] $maxload + kernel.all.load[5] $maxload + kernel.all.load[1] $maxload + ) + _metriclabels _away ( "15" "5" "1" ) + _colorlist ( blue2 blue2 blue2 ) + _baseLabel "Average System Load over the last 1, 5, and 15 minutes\nNormalized to $maxload" + ) + + _label 0 5 _west _down _large "Mem" + +end-of-file + +if [ $realmem -ne 0 ] +then + if $utilmem + then + cat << end-of-file >> $tmp.conf + _stack 1 5 _west ( + _metrics ( + mem.util.kernel $realmem + mem.util.fs_ctl $realmem + mem.util.fs_dirty $realmem + mem.util.fs_clean $realmem + mem.util.user $realmem + ) + _colorlist memory_colors + _baseLabel "Physical Memory Utilization\nNormalized to $realmem Kbytes" + ) +end-of-file + elif $linuxutilmem + then + cat << end-of-file >> $tmp.conf + _stack 1 5 _west ( + _metrics ( + mem.util.shared $realmem + mem.util.cached $realmem + mem.util.bufmem $realmem + mem.util.other $realmem + mem.util.free $realmem + ) + _colorlist memory_colors + _baseLabel "Physical Memory Utilization\nNormalized to `expr $realmem / 1024` Kbytes" + ) +end-of-file + else + cat << end-of-file >> $tmp.conf + _stack 1 5 _west _fillmod ( + _metrics ( + mem.freemem $realmem + ) + _colorlist ( blue2 ) + _baseLabel "Unallocated Physical Memory" + _stackLabel "Used Physical Memory\nNormalized to $realmem Kbytes" + ) +end-of-file +fi +elif $utilmem +then + cat << end-of-file >> $tmp.conf + _stack 1 5 _west _utilmod ( + _metrics ( + mem.util.kernel 0 + mem.util.fs_ctl 0 + mem.util.fs_dirty 0 + mem.util.fs_clean 0 + mem.util.user 0 + mem.util.free 0 + ) + _colorlist memory_colors + _baseLabel "Physical Memory Utilization" + ) +end-of-file +elif $linuxutilmem +then + cat << end-of-file >> $tmp.conf + _stack 1 5 _west _utilmod ( + _metrics ( + mem.util.shared 0 + mem.util.cached 0 + mem.util.bufmem 0 + mem.util.other 0 + mem.util.free 0 + ) + _colorlist memory_colors + _baseLabel "Physical Memory Utilization" + ) +end-of-file +fi + +cat << end-of-file >> $tmp.conf + + _label 0 7 _west _down _large "CPU" + + _stack 1 7 _west ( + _metrics ( +end-of-file +$have_user && echo " kernel.all.cpu.user $maxcpu" >> $tmp.conf +$have_sys && echo " kernel.all.cpu.sys $maxcpu" >> $tmp.conf +$have_nice && echo " kernel.all.cpu.nice $maxcpu" >> $tmp.conf +$have_intr && echo " kernel.all.cpu.intr $maxcpu" >> $tmp.conf +$have_wait && echo " kernel.all.cpu.wait.total $maxcpu" >> $tmp.conf +cat << end-of-file >> $tmp.conf + ) + _colorlist cpu_colors + _baseLabel "CPU Utilization\nSummed over $cpudesc" + ) +end-of-file + +if [ "$ninterfaces" -gt 0 ] +then + cat << end-of-file >> $tmp.conf + +# +# Network Stuff and Alarms +# + + _marginWidth 1 + + _grid 4 2 1 7 _nw ( + + _marginWidth 8 + + _label 0 0 _sw "Network Input" + + _bar 0 1 _nw _groupByMetric ( + _metrics ( + network.interface.in.bytes[$interfaces] $maxbyte + network.interface.in.packets[$interfaces] $maxpack + network.interface.in.errors[$interfaces] $maxerr + ) + _colorlist network_colors + _metricLabels _away ( "Bytes" "Packets" "Errors" ) + _baseLabel "Input on all Network Interfaces\nNormalized to $maxbyte bytes per second and $maxpack packets per second" + ) + + _label 0 2 _sw "Network Output" + + _bar 0 3 _nw ( + _metrics ( + network.interface.out.bytes[$interfaces] $maxbyte + network.interface.out.packets[$interfaces] $maxpack + network.interface.out.errors[$interfaces] $maxerr + ) + _instlabels _away ( $interfaces_sp ) + _metricLabels _away ( "Bytes" "Packets" "Errors" ) + _colorlist network_colors + _baseLabel "Output on all Network Interfaces\nNormalized to $maxbyte bytes per second and $maxpack packets per second" + ) + ) +end-of-file +fi + +echo ")" >> $tmp.conf + +$verbose && cat $tmp.conf + +eval $PMVIEW <$tmp.conf $args -title "'$titleArg'" -xrm "'*iconName:osvis'" -R $PCP_VAR_DIR/config/pmlogger/config.osvis + +exit diff --git a/src/pmview/front-ends/pmview-args b/src/pmview/front-ends/pmview-args new file mode 100644 index 0000000..31a7008 --- /dev/null +++ b/src/pmview/front-ends/pmview-args @@ -0,0 +1,625 @@ +# Copyright (c) 1995-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. +# + +prog=`basename $0` + +PMVIEW=pmview +PMPROBE=pmprobe +CONFIRM="$PCP_XCONFIRM_PROG" +ECHONL="echo -n" +_multiple_sources=false + +# +# Standard usage and command-line argument parsing for pmview front ends. +# This file should be included by pmview front end scripts to present a +# consistent interface. See pmview(1), dkvis(1), mpvis(1) and nfsvis(1) +# for more information on their respective interfaces. +# + +# +# The front end scripts should call _pmview_usage after their own usage +# information in a subroutine called _usage. The _usage subroutine may be +# called by either _pmview_note or _pmview_args. +# +_pmview_usage() +{ + if $_multiple_sources + then + echo -n ' + -A align align sample times on natural boundaries + -a archive[,archive...] + metrics source is one or more PCP archive logs + -C check configuration file and exit + -h host[,host...] metrics source is PMCD on one or more hosts' + + else + + echo -n ' + -A align align sample times on natural boundaries + -a archive metrics source is a PCP archive log + -C check configuration file and exit + -h host metrics source is PMCD on host' + + fi + + echo ' + -n pmnsfile use an alternative PMNS + -O offset initial offset into the time window + -p port port name for connection to existing time control + -S starttime start of the time window + -T endtime end of the time window + -t interval sample interval [default 2.0 seconds] + -x version use pmlaunch(5) version [default version 2.0] + -z set reporting timezone to local time of metrics source + -Z timezone set reporting timezone + + -display display-string + -geometry geometry-string + -name name-string + -title title-string + -xrm resource' +} + +# Most front-end scripts can handle input from only one source, and +# hence only one -h or -a option. +# +# For those than can handle multiple sources, they should call +# _pmview_multiple_sources_are_ok before calling _pmview_args to +# enable the following extensions to the -a and -h options: +# -a a1 -a a2 ... multiple -a options +# -h h1 -h h2 ... multiple -h options +# -a a1,a2,... multiple archives with the -a option +# -h h1,h2,... multiple hosts with the -h option +# +_pmview_multiple_sources_are_ok() +{ + _multiple_sources=true +} + +# check for magic numbers in a file that indicate it is a PCP archive +# +# if file(1) was reliable, this would be much easier, ... sigh +# +# if you need to change this, make consistent changes in all these +# places: +# _check_file() in src/pmafm/mkaf +# _is_archive() in src/pmafm/pmafm +# _is_archive() in src/pmview/front-ends/pmview-args +# +_is_archive() +{ + case "$PCP_PLATFORM" in + irix) + dd ibs=1 count=7 if="$1" 2>/dev/null | od -X | $PCP_AWK_PROG ' +NR == 1 && $2 == "00000084" && $3 == "50052600" { exit 0 } + { exit 1 }' + ;; + linux) + dd ibs=1 count=7 if="$1" 2>/dev/null | od -x | $PCP_AWK_PROG ' +NR == 1 && NF == 5 && $2 == "0000" && $3 == "0084" && $4 == "5005" && $5 == "2600" { exit 0 } +NR == 1 && NF == 5 && $2 == "0000" && $3 == "8400" && $4 == "0550" && $5 == "0026" { exit 0 } + + { exit 1 }' + ;; + esac + return $? +} + +# One of the first actions of a front end script should be to call +# _pmview_args. It sets the following variables: +# +# host the first host specified with -h (if any) in the format +# hostname +# else the host from the first archive in the format +# hostname (Archive archivename) +# arch the first archive specified with -a (if any). +# All archives are passed on to pmview with one -a +# argument per archive via $args +# numsource Number of metrics sources (hosts or archives) +# args The list of args that pmview will comprehend and use. +# otherArgs The arguments pmview will not understand and should be +# handled by the front end script. +# titleArg The title the user prefers. If empty, the title should be +# provided by the front end script. +# prog The name of the program. +# namespace The namespace (including the flag) if specified, else empty +# eg "-n foo" +# msource The default metrics source, whether live or an archive, +# including the flag. e.g. "-h blah" or "-a first_archive". +# Taken from the first encountered -a or -h option. +# +# sourcelist space separated list of hosts or archives +# +_pmview_args() +{ + +_seen_host=false +_seen_arch=false +host="" +arch="" +numsource=0 +args="" +otherArgs="" +titleArg="" +namespace="" +msource="" + +if [ $# -eq 1 -a '$1' = '-\?' ] +then + _usage + exit 0 +fi + +while [ $# -gt 0 ] +do + case $1 + in + -g*|-di*|-name|-xrm) + # assume an X11 argument + if [ $# -lt 2 ] + then + _pmview_note Usage-Error error "$prog: X-11 option $1 requires one argument" + #NOTREACHED + fi + args="$args $1 '$2'" + shift + ;; + + -title) + # assume an X11 argument + if [ $# -lt 2 ] + then + _pmview_note Usage-Error error "$prog: Option $1 requires one argument" + #NOTREACHED + exit 1 + fi + titleArg="$2" + shift + ;; + + -A|-D|-O|-p|-S|-T|-t|-x|-Z) + if [ $# -lt 2 ] + then + _pmview_note Usage-Error error "$prog: Option $1 requires one argument" + #NOTREACHED + fi + args="$args $1 '$2'" + shift + ;; + + -A*|-D*|-O*|-p*|-S*|-T*|-t*|-Z*|-C|-z) + args="$args $1" + ;; + + -a) + if $_seen_host + then + _pmview_note Usage-Error error "$prog: Only one of the -h or -a options may be specified" + #NOTREACHED + fi + if [ $# -lt 2 ] + then + _pmview_note Usage-Error error "$prog: Option $1 requires one argument" + #NOTREACHED + fi + for _archbase in `echo "$2" | sed -e 's/,/ /g'` + do + if [ $numsource -gt 0 -a $_multiple_sources = false ] + then + _pmview_note Usage-Error error "$prog: Only one -a option may be specified" + # NOTREACHED + fi + if _is_archive $_archbase 2>&1 + then + _archbase=`echo $_archbase | sed -e 's/\.[^.]*$//'` + fi + # at least $_archbase.0 and $_archbase.meta have to be here + # + if _is_archive $_archbase.0 && _is_archive $_archbase.meta + then + : + else + _pmview_note Error error "$prog: \"$_archbase\" is not the basename of a valid PCP archive" + #NOTREACHED + fi + if [ -z "$arch" ] + then + # first archive seen + # + arch=$_archbase + msource="-a $_archbase" + host=`pmdumplog -l $arch \ + | $PCP_AWK_PROG '/^Performance/ {print $5}' \ + | sed -e 's/,//g'` + [ "X$host" = X ] && host="unknown host" + host="$host (Archive $arch)" + fi + + # pmview(1) can handle multiple -a options, so + # pass _all_ archive names back to the caller both as + # -a options via $args and in $sourcelist (counted by + # $numsource). + # + # Note: multiple -h options are handled slightly + # differently, see also the comments for -h below. + # + + args="$args -a $_archbase" + if [ -z "$sourcelist" ]; then + sourcelist=$_archbase + else + sourcelist="$sourcelist $_archbase" + fi + numsource=`expr $numsource + 1` + done + _seen_arch=true + shift + ;; + + -h) + if $_seen_arch + then + _pmview_note Usage-Error error "$prog: Only one of the -h or -a options may be specified" + #NOTREACHED + fi + if [ $# -lt 2 ] + then + _pmview_note Usage-Error error "$prog: Option $1 requires one argument" + #NOTREACHED + fi + for _host in `echo "$2" | sed -e 's/,/ /g'` + do + if [ $numsource -gt 0 -a $_multiple_sources = false ] + then + _pmview_note Usage-Error error "$prog: Only one -h option may be specified" + # NOTREACHED + fi + if [ -z "$host" ] + then + host=$_host + msource="-h $_host" + + # pmview(1) can handle only one -h options, so + # pass the _first_ host name back to the caller as a + # -h option via $args and _all_ hostnames via + # $sourcelist (counted by $numsource). + # + # Note: multiple -a options are handled slightly + # differently, see also the comments for -a above. + # + + args="$args -h $_host" + fi + if [ -z "$sourcelist" ]; then + sourcelist=$_host + else + sourcelist="$sourcelist $_host" + fi + numsource=`expr $numsource + 1` + done + _seen_host=true + shift + ;; + + -n) + if [ $# -lt 2 ] + then + _pmview_note Usage-Error error "$prog: Option $1 requires one argument" + #NOTREACHED + fi + namespace="-n $2" + args="$args -n $2" + shift + ;; + + *) + otherArgs="$otherArgs $1" + ;; + + esac + shift + +done + +if [ -z "$host" ] +then + host=`pmhostname` + msource="-h $host" +fi +} + +# standard fatal error reporting +# Usage: _pmview_error message goes in here +# _pmview_error -f file +# +_pmview_error() +{ + _pmview_note Error error $* +} + +# standard warning +# Usage: _pmview_warning message goes in here +# _pmview_warning -f file +# +_pmview_warning() +{ + _pmview_note Warning warning $* +} + +# standard info +# Usage: _pmview_info message goes in here +# _pmview_info -f file +# +_pmview_info() +{ + _pmview_note Info info $* +} + +# generic notifier +# Usage: _pmview_note tag icon args ... +# +_pmview_note() +{ + tag=$1; shift + icon=$1; shift + button="" + [ $tag = Error ] && button="-B Quit" + [ $tag = Usage-Error ] && button="-B Quit -b Usage" + + [ X"$PCP_STDERR" = XDISPLAY -a -z "$DISPLAY" ] && unset PCP_STDERR + + if [ $# -eq 2 -a "X$1" = X-f ] + then + case "$PCP_STDERR" + in + DISPLAY) + ans=`$CONFIRM -icon $icon -file $2 -useslider -header "$tag $prog" $button 2>&1` + ;; + '') + echo "$tag:" >&2 + cat $2 >&2 + ans=Quit + ;; + *) + echo "$tag:" >>$PCP_STDERR + cat $2 >>$PCP_STDERR + ans=Quit + ;; + esac + else + case "$PCP_STDERR" + in + DISPLAY) + ans=`$CONFIRM -icon $icon -t "$*" -noframe -header "$tag $prog" $button 2>&1` + ;; + '') + echo "$tag: $*" >&2 + ans=Quit + ;; + *) + echo "$tag: $*" >>$PCP_STDERR + ans=Quit + ;; + esac + fi + + if [ $tag = Usage-Error ] + then + [ $ans = Usage ] && _usage + tag=Error + fi + + [ $tag = Error ] && exit 1 +} + +# used internally by _pmview_cache_fetch() and _pmview_fetch() +# +_pmview_probe() +{ + flag=$1 + shift + ( echo $* \ + ; echo "-----" \ + ; ( $PMPROBE $namespace $msource $flag $* 2>$tmp.pmview_err \ + | tee -a $tmp.pmview_fetch \ + ) \ + ) \ + | tr ' ' '\012' \ + | sed -e 's/"//g' \ + | $PCP_AWK_PROG ' +BEGIN { last = 0 } +$1 == "-----" { state = 1; next } +state == 0 { metric[last] = pat[last] = $1 + # deal with arguments that are non-terminals in the PMNS + # so pmprobe a.b => a.b.c a.b.c.x a.b.d etc + gsub("\\.", "\\.", pat[last]) + pat[last] = "^" pat[last] "\\." + last++ + next + } +state > 0 { for (i = 0; i < last; i++) { + if (metric[i] == $1 || match($1, pat[i]) > 0) { + # new matching metric name + name=$1 + state=2 + next + } + } + } +state == 2 { if ($1 > 0) state = 3 + else state = 1 + next + } +state == 3 { printf("%s%s|%s\n", "'"$flag|$msource|"'",name,$1) }' +} + +# Fetch metrics and cache result +# input +# $1 - pmprobe flag +# $* - 1 or more metrics +# output +# $tmp.pmview_cache - cached values, with this format +# pmprobe flag|metric source|metric name|pmprobe result +# +_pmview_cache_fetch() +{ + flag=$1 + shift + _pmview_probe $flag $* >>$tmp.pmview_cache + + return 0 +} + +# Fetch metrics +# +# input +# $1 - pmprobe flag +# $2 - metric name +# output +# $number - number of values +# $tmp.pmview_result - values +# +_pmview_fetch() +{ + flag=$1 + metric=$2 + rm -f $tmp.pmview_fetch $tmp.pmview_result + if [ -s $tmp.pmview_cache ] + then + $PCP_AWK_PROG -F\| \ + <$tmp.pmview_cache >$tmp.pmview_result \ +' +$1 == "'"$flag"'" && $2 == "'"$msource"'" && $3 == "'"$metric"'" { print $4 }' + fi + + if [ ! -s $tmp.pmview_result ] + then + # cache miss, forced to probe + # + _pmview_probe $flag $metric \ + | $PCP_AWK_PROG -F\| >$tmp.pmview_result '{print $4}' + fi + + if [ -s $tmp.pmview_result ] + then + number=`wc -l <$tmp.pmview_result | sed -e 's/ //g'` + else + if [ -s $tmp.pmview_fetch ] + then + check=`cut -d ' ' -f 2 $tmp.pmview_fetch` + if [ "$check" = "$metric" ] + then + # *.pmview_fetch looks valid, extract numval from 2nd field + # + number=`cut -d ' ' -f 2 $tmp.pmview_fetch` + else + # *.pmview_fetch exists, but does not contain + # pmprobe output, more than likely this is some + # sort of fatal error message ... but _real_ message + # is likely to be in *.pmview_err + # + [ -s $tmp.pmview_err ] && mv $tmp.pmview_err $tmp.pmview_fetch + number=-1 + fi + else + number=-1 + mv $tmp.pmview_err $tmp.pmview_fetch + fi + fi + if [ $number -le 0 ] + then + rm -f $tmp.pmview_result + return 1 + fi + + return 0 +} + +# Fetch the metric values +# +# input +# $1 - metric name +# output +# $number - number of values +# $tmp.pmview_result - values +# +_pmview_fetch_values() +{ + _pmview_fetch -v $1 + return $? +} + +# Fetch the metric instance list +# +# input +# $1 - metric name +# output +# $number - number of instances +# $tmp.pmview_result - instances +# +_pmview_fetch_indom() +{ + _pmview_fetch -I $1 + return $? +} + +# Convert pmprobe/pminfo error message into something useful and +# consistent +# +_pmview_fetch_mesg() +{ + $PCP_AWK_PROG ' +$1 == "pmprobe:" { $1 = "'$prog':"; print; exit } +$1 == "pminfo:" { $1 = "'$prog':"; print; exit } +$1 == "Error:" { $1 = ":"; + printf("%s: %s%s\n", "'$prog'", metric, $0); exit } +$1 == "inst" { exit } +NF == 1 { metric = $1; next } +NF == 0 { next } +NF == 2 && $2 == "0" { printf("%s: %s: No values available\n", "'$prog'", $1); exit} + { $2 = ":"; print "'$prog': " $0; exit}' \ + | sed "s/ : /: /" \ + | fmt +} + +# Generate error metric for failed fetch +# +_pmview_fetch_fail() +{ + cat $tmp.pmview_fetch | _pmview_fetch_mesg >> $tmp.msg + echo "$prog: Failed to $1 from host \"$host\"" | fmt >> $tmp.msg + _pmview_error -f $tmp.msg + # NOTREACHED +} + +# Generate warning message for failed fetch +# +_pmview_fetch_warn() +{ + cat $tmp.pmview_fetch | _pmview_fetch_mesg >> $tmp.msg + echo "$prog: Failed to $1 from host \"$host\"" | fmt >> $tmp.msg + _pmview_warning -f $tmp.msg + rm -f $tmp.msg +} + +# Check that $OPTARG for option $1 is a positive integer +# ...note the creative use of unary - to prevent leading signs +# +_pmview_unsigned() +{ + if [ "X-$OPTARG" != "X`expr 0 + -$OPTARG 2>/dev/null`" ] + then + _pmview_error "$prog: -$1 option must have a positive integral argument" + # NOTREACHED + fi +} diff --git a/src/pmview/front-ends/weblogvis b/src/pmview/front-ends/weblogvis new file mode 100755 index 0000000..5b570bd --- /dev/null +++ b/src/pmview/front-ends/weblogvis @@ -0,0 +1,451 @@ +#!/bin/sh +# Copyright (c) 1995-2000 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 + +# default idle time +# +defidle=3600 + +_usage() +{ + echo >$tmp.msg 'Usage: '$prog' [options] [server ...] + +Options + -b display byte rate, rather than request rate + -f display activity by function, rather than activity by + result size + -i show server names + -I time maximum expected idle time in seconds [default $defidle] + -m max maximum expected request rate (or maximum byte rate) + -V verbose/diagnostic output + +pmview(1) options:' + _pmview_usage >> $tmp.msg + echo ' +Default title is: Web Log Activity (request rate by result size) for Host' >> $tmp.msg + echo ' + The default is to display the request rate, grouped by result size, for all + Web servers on the target host.' | fmt >> $tmp.msg + _pmview_info -f $tmp.msg +} + +# --- build WM_COMMAND X(1) property for restart after login/logout --- +# +echo -n "pmview Version 2.1 \"$prog\"" >$tmp.pmview +for arg +do + echo -n " \"$arg\"" >>$tmp.pmview +done +echo >> $tmp.pmview + +# --- parse command line arguments --- +# +verbose=false +serverList="" +max=0 +idle=$defidle +class=size +show=request +showInst=false + +_pmview_args "$@" + +if [ -n "$otherArgs" ] +then + while getopts "?bfiI:m:v:V" c $otherArgs + do + case $c + in + b) # show bytes not requests + show=byte + ;; + + f) # classify by function (method) + class=method + ;; + i) + showInst=true + ;; + I) + idle=$OPTARG + # and now the obscure +ve integer checking bit + # ...note the creative use of unary - to prevent leading signs + if [ "X-$idle" != "X`expr 0 + -$idle 2>/dev/null`" ] + then + _pmview_error "$prog: -I must have a positive integral argument" + #NOTREACHED + fi + ;; + m) + max=$OPTARG + # and now the obscure +ve integer checking bit + # ...note the creative use of unary - to prevent leading signs + if [ "X-$max" != "X`expr 0 + -$max 2>/dev/null`" ] + then + _pmview_error "$prog: -m must have a positive integral argument" + #NOTREACHED + fi + ;; + 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 + ;; + '?') + _usage + exit 1 + ;; + esac + done + + set - $otherArgs + shift `expr $OPTIND - 1` + [ $# -gt 0 ] && serverList_sp=$* && serverList=`echo $* | sed -e 's/ /,/g'` +fi +[ -z "$titleArg" ] && titleArg="SGI PCP : Web Log Activity" + + +if [ $max = 0 ] +then + if [ $show = request ] + then + # requests per second + max=50 + else + # bytes per second + max=500000 + fi +fi + + +# maximum req error rate (default: 5% of request rate) +# +maxerr=`expr $max / 20` + + +# if metrics source is an archive, and find out name of host +# +if [ "X$arch" != X ] +then + host=`pmdumplog -l $arch | $PCP_AWK_PROG '/^Performance/ {print $5}' \ + | sed -e 's/,//g'` + [ "X$host" = X ] && host="unknown host" + host="$host (Archive $arch)" +fi + + +# get perserver instances +# in the default case use web.perserver.requests.total +# in the -b flag case use web.perserver.bytes.total +# +rm -f $tmp.int +if [ $show = request ] +then + pminfo -f $msource $namespace web.perserver.requests.total \ + > $tmp.int 2>/dev/null +else + pminfo -f $msource $namespace web.perserver.bytes.total \ + > $tmp.int 2>/dev/null +fi +if [ ! -s $tmp.int ] +then + if [ "X$arch" != "X" ] + then + _pmview_error "$prog: weblog metrics not included in the archive \"$arch\"" + #NOTREACHED + else + _pmview_error "$prog: weblog metrics not available for host \"$host\"" + #NOTREACHED + fi +fi + +sed -e 's/\]//' -e 's/"//g' $tmp.int \ + | $PCP_AWK_PROG '$1 == "inst" {print $4}' > $tmp.list + +if [ ! -s $tmp.list ] +then + if [ "X$arch" != X ] + then + _pmview_error "$prog: failed to get web servers from archive \"$arch\"" + #NOTREACHED + else + _pmview_error "$prog: failed to get web servers from host \"$host\"" + #NOTREACHED + fi +fi + +rm -f $tmp.chosen +if [ -z "$serverList" ] +then + cp $tmp.list $tmp.chosen +else + touch $tmp.chosen + for i in $serverList_sp + do + egrep $i $tmp.list >> $tmp.chosen + done +fi + +servers_sp=`cat $tmp.chosen | sort | uniq` +servers=`echo $servers_sp | sed -e 's/ /,/g'` +nservers=`echo $servers | wc -w` + +if [ $nservers = 0 ] +then + _usage + echo + echo "Error: $prog: no matching web servers" + echo " Available web servers are: " `cat $tmp.list` + exit 1 +fi + + +if [ $show = request ] +then + totalLabel="Total_Req_Rate" + label_sp="\"Request Rate\"" + met="requests" + titleArg="$titleArg (request rate" +else + totalLabel="Total_Data_Rate" + label_sp="\"Data Rate\"" + met="bytes" + titleArg="$titleArg (data rate" +fi + +# +# strings for base plane labels +# +basestr_idle="Elapsed time since the last request\nNormalized to $idle seconds" +if [ $show = request ] +then + basestr_total="Total number of HTTP requests processed by server\nNormalized to $max requests per second" + basestr_req="HTTP request rate by response size in bytes\nNormalized to $max hits per second" + basestr_type="HTTP request rate by HTTP method\nNormalized to $max hits per second" +else + basestr_total="Total number of bytes processed by server\nNormalized to $max bytes per second" + basestr_req="HTTP size rate by response size in bytes\nNormalized to $max bytes per second" + basestr_type="HTTP size rate by HTTP method\nNormalized to $max hits per second" +fi + + +#--- config file has already been created; continue writing to it --- +# + +cat << end-of-file >>$tmp.pmview +# +# $prog +# +# Servers: $servers +# +end-of-file + +if $verbose +then + if [ "X$serverList" != X ] + then + echo "# Matching servers for \"$serverList\": $servers" + fi +fi + +if [ $class = size ] +then + titleArg="$titleArg by result size)" +else + titleArg="$titleArg by request type)" +fi + + +# +# the real config starts here +# +cat << end-of-file >>$tmp.pmview + +_scale 1.2 + +_grid _hide ( + + _label 2 0 1 5 _down _large $label_sp + + _bar 0 0 east _col ( + _metrics ( + web.perserver.logidletime[$servers] $idle + ) + _metriclabels ( Idle ) + _colorList ( orange ) + _baseLabel "$basestr_idle" + ) + +end-of-file + +if [ $class = size ] +then + cat << end-of-file >>$tmp.pmview + + _bar 0 2 east _col ( + _metrics ( + web.perserver.$met.total[$servers] $max + ) + _metriclabels ( Total ) + _colorList ( rgbi:0.0/0.88/0.88 ) + _baseLabel "$basestr_total" + ) + + _bar 0 4 east _col _groupbyinst ( + _metrics ( +end-of-file + + if [ $show = request ] + then + cat <<end-of-file >>$tmp.pmview + web.perserver.$met.size.unknown[$servers] $max +end-of-file + fi + + cat << end-of-file >>$tmp.pmview + web.perserver.$met.size.gt3m[$servers] $max + web.perserver.$met.size.le3m[$servers] $max + web.perserver.$met.size.le1m[$servers] $max + web.perserver.$met.size.le300k[$servers] $max + web.perserver.$met.size.le100k[$servers] $max + web.perserver.$met.size.le30k[$servers] $max + web.perserver.$met.size.le10k[$servers] $max + web.perserver.$met.size.le3k[$servers] $max +end-of-file + + if [ $show = request ] + then + cat <<end-of-file >>$tmp.pmview + web.perserver.$met.size.zero[$servers] $max + ) + _metriclabels ( + "?" "> 3M" "1M < 3M" "300K < 1M" "100K < 300K" + "30K < 100K" "10K < 30K" "3K < 10K" "0 < 3K" "0K" + ) +end-of-file + else + cat <<end-of-file >>$tmp.pmview + ) + _metriclabels ( + "> 3M" "1M < 3M" "300K < 1M" "100K < 300K" + "30K < 100K" "10K < 30K" "3K < 10K" "0 < 3K" + ) +end-of-file + fi + + if $showInst + then + cat <<end-of-file >>$tmp.pmview + _instlabels _away ( $servers_sp ) +end-of-file + fi + + cat << end-of-file >>$tmp.pmview + _colorList ( + rgbi:1.0/0.35/0.0 + rgbi:0.6/0.0/0.9 + rgbi:0.0/1.0/0.0 + rgbi:1.0/0.5/0.0 + rgbi:0.65/0.3/1.0 + rgbi:0.3/1.0/0.3 + rgbi:1.0/0.65/0.3 + rgbi:0.8/0.6/1.0 + rgbi:0.6/1.0/0.6 + rgbi:1.0/0.8/0.6 + + ) + _baseLabel "$basestr_req" + ) + +end-of-file + +else + cat << end-of-file >>$tmp.pmview + + _bar 0 2 east _col ( + _metrics ( + web.perserver.$met.total[$servers] $max + ) + _metriclabels ( Total ) + _colorList ( rgbi:1.0/0.5/0.0 ) + _baseLabel "$basestr_total" + ) + + _bar 0 4 east _col ( + _metrics ( + web.perserver.$met.get[$servers] $max + web.perserver.$met.head[$servers] $max + web.perserver.$met.post[$servers] $max + web.perserver.$met.other[$servers] $max +end-of-file + + if [ $show = request ] + then + cat << end-of-file >>$tmp.pmview + web.perserver.errors[$servers] $maxerr +end-of-file + fi + + cat << end-of-file >>$tmp.pmview + ) + _metriclabels ( Get Head Post Other Error ) +end-of-file + + if $showInst + then + cat <<end-of-file >>$tmp.pmview + _instlabels _away ( $servers_sp ) +end-of-file + fi + + cat << end-of-file >>$tmp.pmview + _colorList ( + rgbi:1.0/1.0/0.0 + rgbi:0.0/1.0/1.0 + rgbi:1.0/0.0/1.0 + rgbi:1.0/1.0/0.6 + rgbi:0.8/0.0/0.0 + ) + _baseLabel "$basestr_type" + ) +end-of-file + +fi + +cat << end-of-file >>$tmp.pmview +) +end-of-file + +titleArg="$titleArg for Host $host" + +$verbose && cat $tmp.pmview + +eval $PMVIEW <$tmp.pmview $args -title "'$titleArg'" -xrm "'*iconName: $prog'" + +exit + diff --git a/src/pmview/front-ends/weblogvis.load b/src/pmview/front-ends/weblogvis.load new file mode 100755 index 0000000..a676124 --- /dev/null +++ b/src/pmview/front-ends/weblogvis.load @@ -0,0 +1,103 @@ +#!/bin/sh +# Copyright (c) 2001 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. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# Load up a Web server to show off/QA weblogvis +# + +tmp=/tmp/$$ +trap "rm -f $tmp.*; killall -9 load; exit" 0 1 2 3 15 + +i=0 + +# specular +# +cat >$tmp.$i <<End-of-File +GET http://155.11.225.108/file8k.html +GET http://155.11.225.108/file15k.html +End-of-File +webping -c $tmp.$i -I0 -q & +i=`expr $i + 1` + +cat >$tmp.$i <<End-of-File +GET http://155.11.225.108/file15k.html +End-of-File +webping -c $tmp.$i -I0 -q & +i=`expr $i + 1` + +# specular IP alias +# +cat >$tmp.$i <<End-of-File +GET http://155.11.225.118/file45k.html +End-of-File +webping -c $tmp.$i -I0 -q & +i=`expr $i + 1` + +cat >$tmp.$i <<End-of-File +GET http://155.11.225.118/file15k.html +GET http://155.11.225.118/file45k.html +End-of-File +webping -c $tmp.$i -I0 -q & +i=`expr $i + 1` + +cat >$tmp.$i <<End-of-File +GET http://155.11.225.118/file45k.html +End-of-File +webping -c $tmp.$i -I0 -q & +i=`expr $i + 1` + +# specular proxy +# +cat >$tmp.$i <<End-of-File +GET http://boing/file15k.html +End-of-File +webping -c $tmp.$i -I0 -q -P specular:8080 & +i=`expr $i + 1` + +cat >$tmp.$i <<End-of-File +GET http://boing/file0k.html +GET http://boing/file0k.html +GET http://boing/file115k.html +End-of-File +webping -c $tmp.$i -I0 -q -P specular:8080 & +i=`expr $i + 1` + +# specular socks +# +cat >$tmp.$i <<End-of-File +GET http://155.11.225.108/file500k.html +GET http://boing/file500k.html +End-of-File +webping -c $tmp.$i -I0 -q -S specular:8080 & +i=`expr $i + 1` + +# specular ftp-socks +# +cat >$tmp.$i <<End-of-File +GET ftp://155.11.225.108/pub/README +End-of-File +webping -c $tmp.$i -I0 -q -S specular:8080 & +i=`expr $i + 1` + +# specular ftp +# +cat >$tmp.$i <<End-of-File +GET ftp://155.11.225.108/pub/README +End-of-File +webping -c $tmp.$i -I0 -q & +i=`expr $i + 1` + +wait diff --git a/src/pmview/front-ends/weblogvis.rgb b/src/pmview/front-ends/weblogvis.rgb Binary files differnew file mode 100644 index 0000000..11c4712 --- /dev/null +++ b/src/pmview/front-ends/weblogvis.rgb diff --git a/src/pmview/front-ends/webpingvis b/src/pmview/front-ends/webpingvis new file mode 100644 index 0000000..a08aa81 --- /dev/null +++ b/src/pmview/front-ends/webpingvis @@ -0,0 +1,372 @@ +#! /bin/sh +# Copyright (c) 1995-2001 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] + +options: + -i show URL names + -m max maximum expected total ping response time (milliseconds) + -V verbose/diagnostic output + +pmview(1) options:' + + _pmview_usage >> $tmp.msg + echo >> $tmp.msg + echo 'Default title is: SGI PCP: Web PING Performance for Host' >> $tmp.msg + echo ' + The "max" parameter (used with -m) should be set to the maximum + expected ping response time for all URLs being monitored. The default + is 1000 milliseconds. This governs the height of the bar showing total + response time (at the far right of the scene). All bars showing + response times use "max" for height normalization.' >> $tmp.msg + _pmview_info -f $tmp.msg +} + +#--- build WM_COMMAND X(1) property for restart after login/logout --- +# +echo -n "pmview Version 2.1 \"$prog\"" > $tmp.pmview +for arg +do + echo -n " \"$arg\"" >> $tmp.pmview +done +echo >> $tmp.pmview + +# --- LOCAL FUNCTIONS : START ------------------------------------------------ +_sort_host_indom() +{ + sed <$1 \ + -e 's/instance\[\([0-9][0-9]*\)]:/\1/' \ + | $PCP_AWK_PROG ' +BEGIN { state = 0 } +/^samples:/ { state = 1; next } +state == 0 { next } +/^full label/ { label[$4] = $NF; next } +NF == 0 { state = 2; next } +state == 2 { for (i=1; i<=NF; i++) { + if (label[i-1] == "") + label[i-1] = $i + } + state = 3 + next + } +state == 3 { for (i=1; i<=NF; i++) + size[i-1] = $i + } +END { for (i in label) { + print label[i],size[i] + } + }' \ + | sort +1n -2 +0 -1 >$tmp.tmp + mv $tmp.tmp $1 +} + +_sort_arch_indom() +{ +metric=webping.perurl.kbytes +indom=`pminfo -d -a $arch $metric \ +| sed -n -e '/InDom:/{ +s/.*InDom: // +s/ .*//p +}'` + +if [ "X$indom" = XPM_INDOM_NULL ] +then + _pmview_error "$prog: $metric is singular" + #NOTREACHED +elif [ -z "$indom" ] +then + _pmview_error "$prog: cannot determine InDom for $metric" + #NOTREACHED +fi + +pmdumplog -z -i $arch 2>&1 \ +| $PCP_AWK_PROG ' +/^InDom: '$indom'$/ { state=1; next } +/^InDom: / { state=0; next } +state == 1 && /^[^ ]/ { print }' \ +| while read stamp junk +do + pminfo -f -a $arch -z -O "@$stamp" -f $metric +done \ +| sed -n \ + -e '/ value /{ +s/"] value// +s/.*"//p +}' \ +| sort -u >$tmp.known + +pmdumplog -z -i $arch 2>&1 \ +| $PCP_AWK_PROG ' +/^InDom: '$indom'$/ { state=1; next } +/^InDom: / { state=0; next } +state == 1 && /^[ ]/ { print }' \ +| sed -n \ + -e '/ or /{ +s/.* or "// +s/".*//p +}' \ +| sort -u \ +| join -a1 - $tmp.known \ +| sort +2n -3 +1 -2 \ +| $PCP_AWK_PROG ' +NF==1 { printf("%s ?\n",$0); next } + { print }' > $1 +} +# --- LOCAL FUNCTIONS : END -------------------------------------------------- + +verbose=false +max=1000 +showInst=false + +_pmview_args "$@" + +if [ -n "$otherArgs" ] +then + while getopts "?im:v:V" c $otherArgs + do + case $c + in + i) + showInst=true + ;; + m) + max=$OPTARG + # and now the obscure +ve integer checking bit + # ...note the creative use of unary - to prevent leading signs + if [ "X-$max" != "X`expr 0 + -$max 2>/dev/null`" ] + then + _pmview_error "$prog: -m must have a positive integral argument" + #NOTREACHED + fi + ;; + 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 + ;; + '?') + _usage + exit 1 + ;; + esac + done +fi +[ -z "$titleArg" ] && titleArg="SGI PCP: Web PING Performance for Host $host" + + +# check that webping metrics are available from metrics source +# +if pminfo $msource $namespace webping 2>&1 \ + | grep 'webping: Unknown metric name' >/dev/null +then + _pmview_error "$prog: webping metrics not defined in the name space" + #NOTREACHED +fi +# +# do a second check to make sure that we have webping.perurl metrics +# +if pminfo -f $msource $namespace webping.perurl.kbytes 2>&1 \ + | grep 'inst .* value' >/dev/null +then + : +else + if [ "X$arch" != "X" ] + then + _pmview_error "$prog: webping.perurl metrics not available from $arch" + #NOTREACHED + else + _pmview_error "$prog: webping.perurl metrics not available from $host" + #NOTREACHED + fi +fi + + +# if metrics source is an archive, and find out name of host +# get the instance domain and sort it +# +if [ "X$arch" != X ] +then + _sort_arch_indom $tmp.int + host=`pmdumplog -l $arch | $PCP_AWK_PROG '/^Performance/ {print $5}' | sed -e 's/,//g'` + [ "X$host" = X ] && host="unknown host" + host="$host (Archive $arch)" +else + pmval -h $host -s 1 webping.perurl.kbytes >$tmp.int + _sort_host_indom $tmp.int +fi + + +urlcount=`wc -l <$tmp.int | sed -e 's/ *//g'` +bytesmax=`tail -1 $tmp.int | $PCP_AWK_PROG '{print $2}'` + +if [ $urlcount -eq 0 ] +then + if [ "X$arch" != "X" ] + then + _pmview_error "$prog: there were no URLs monitored in archive \"$arch\"" + #NOTREACHED + else + _pmview_error "$prog: there are no URLs monitored on host \"$host\"" + #NOTREACHED + fi +fi + + +url_list=`$PCP_AWK_PROG <$tmp.int ' +NR>1 { printf "," } + { printf $1 } +END { print "" }'` + +url_list_sp=`$PCP_AWK_PROG <$tmp.int ' +NR>1 { printf " " } +/^GET_.*/ { printf "\"GET %s\"",substr($1,5) } +/^HEAD_.*/ { printf "\"HEAD %s\"",substr($1,6) } +/^POST_.*/ { printf "\"POST %s\"",substr($1,6) } +END { print "" }'` + + +# +# strings for base plane labels +# +basestr_size="URL size in kbytes\nNormalized to $bytesmax kbytes" +basestr_urltime="Time to fetch the URL\nNormalized to $max seconds" +basestr_tottime="Time to fetch all URLs\nNormalized to $max seconds" +basestr_err="Webing errors by error type\nNormalized to 1" + + +#--- config file has already been created ; continue writing to it --- +# + +cat << end-of-file >> $tmp.pmview +# +# $prog +# +# Largest URL = $bytesmax Kbytes +# Maximum fetch time = $max seconds +# +# URLs = $url_list_sp +# +end-of-file + + +# +# the real config starts here +# pmview Version 2.1 +# +cat <<end-of-file >> $tmp.pmview + +_scale 1.2 + +_colorList url_colors ( + rgbi:1.0/0.5/0.0 + rgbi:0.9/0.9/0.0 + rgbi:0.0/0.9/0.9 + rgbi:0.9/0.0/0.9 +) + +_grid _hide ( + + _bar 0 0 east _col ( + _metrics ( + webping.perurl.kbytes[$url_list] $bytesmax + ) + _metriclabels ( Size ) + _baseLabel "$basestr_size" +end-of-file + +if $showInst +then + cat <<end-of-file >>$tmp.pmview + _instlabels _towards ( $url_list_sp ) +end-of-file +fi + +cat <<end-of-file >>$tmp.pmview + _colorList ( rgbi:0.0/0.9/0.0 ) + ) + + _bar 0 2 ne _col _groupbyinst ( + _metrics ( + webping.perurl.time.total[$url_list] $max + webping.perurl.time.body[$url_list] $max + webping.perurl.time.head[$url_list] $max + webping.perurl.time.connect[$url_list] $max + ) + _metriclabels ( Total Body Head Connect ) + _baseLabel "$basestr_urltime" + _colorList url_colors + ) + + _bar 0 4 east _row _groupbyrow ( + _metrics ( + webping.errors.sockerr 1 + webping.errors.httperr 1 + webping.errors.htmlerr 1 + webping.errors.othererr 1 + ) + _instlabels ( Errors ) + _baseLabel "$basestr_err" + _colorList ( red1 red1 red1 red1 ) + ) + +end-of-file + +# +# Only show row totals if there is more than one URL being monitored +# +if [ $urlcount -gt 1 ] +then + totoff=`expr $urlcount + 1` + cat <<end-of-file >> $tmp.pmview + _bar 2 2 north _col _groupbycol ( + _metrics ( + webping.time.total $max + webping.time.body $max + webping.time.head $max + webping.time.connect $max + ) + _colorList url_colors + _baseLabel "$basestr_tottime" + ) +end-of-file + +fi + +cat <<end-of-file >> $tmp.pmview +) +end-of-file + +$verbose && cat $tmp.pmview + +#eval pmview <$tmp.pmview $args -title "'$titleArg'" -xrm "'*iconName: $prog'" -geometry 560x515 +eval pmview <$tmp.pmview $args -title "'$titleArg'" -xrm "'*iconName: $prog'" + +exit diff --git a/src/pmview/front-ends/webpingvis.rgb b/src/pmview/front-ends/webpingvis.rgb Binary files differnew file mode 100644 index 0000000..a444bec --- /dev/null +++ b/src/pmview/front-ends/webpingvis.rgb diff --git a/src/pmview/front-ends/webvis b/src/pmview/front-ends/webvis new file mode 100755 index 0000000..7969aec --- /dev/null +++ b/src/pmview/front-ends/webvis @@ -0,0 +1,707 @@ +#!/bin/sh +# Copyright (c) 1995-2001 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 + +# --- scaling parameters --- +# + +# maximum packets per second +max=750 + +# maximum req rate (default: 5% of packet rate) +maxreq=`expr $max / 20` + +# maximum disk io rate (I/O operations per second) +maxio=100 + +# maximum average disk business (percent) +maxbusy=30 + +# milliseconds per CPU +maxcpu=1000 + +# maximum TCP output queue length +maxq=5 + +# --- define usage message --- +# +_usage() +{ + echo >$tmp.msg 'Usage: '$prog' [options] [interface ...] + +options: + -b maxbusy maximum average disk active (percent) [default 30] + -i maxio maximum total I/Os per second [default 100] + -m max maximum expected packets sent or received per sec [default 750] + -r maxreq maximum expected Web requests per second [default 35] + -V verbose/diagnostic output + +pmview(1) options:' + + _pmview_usage >> $tmp.msg + echo >> $tmp.msg + echo >> $tmp.msg 'Default title is: Web Server Activity for Host' + echo >> $tmp.msg ' + By default all network interfaces are shown, with a maximum packet rate + of '$max' packets per second. The maximum request rate is 5% (of the + maximum packet rate) and the maximum error rate is 20% of the maximum + request rate. + + If given, the [interface ...] regular expressions restrict + the network statistics displayed to matching network interface names only.' + + _pmview_info -f $tmp.msg +} + +# --- build WM_COMMAND X(1) property for restart after login/logout --- +# +echo -n "pmview Version 2.1 \"$prog\"" > $tmp.pmview +for arg +do + echo -n " \"$arg\"" >>$tmp.pmview +done +echo >> $tmp.pmview + +# --- parse command line arguments --- +# +verbose=false +argInterfaces="" +interfaces="" + +_pmview_args "$@" + +if [ -n "$otherArgs" ] +then + while getopts "?b:i:m:r:v:V" c $otherArgs + do + case $c + in + b) + # and now the obscure +ve integer checking bit + # ...note the creative use of unary - to prevent leading signs + maxbusy=$OPTARG + if [ "X-$maxbusy" != "X`expr 0 + -$maxbusy 2>/dev/null`" ] + then + _pmview_error "$prog: -b must have a positive integral argument" + #NOTREACHED + fi + ;; + + i) + maxio=$OPTARG + if [ "X-$maxio" != "X`expr 0 + -$maxio 2>/dev/null`" ] + then + _pmview_error "$prog: -i must have a positive integral argument" + #NOTREACHED + fi + ;; + + m) + max=$OPTARG + if [ "X-$max" != "X`expr 0 + -$max 2>/dev/null`" ] + then + _pmview_error "$prog: -m must have a positive integral argument" + #NOTREACHED + fi + maxreq=`expr $max / 20` + ;; + + r) + maxreq=$OPTARG + if [ "X-$maxreq" != "X`expr 0 + -$maxreq 2>/dev/null`" ] + then + _pmview_error "$prog: -r must have a positive integral argument" + #NOTREACHED + fi + ;; + + 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 + ;; + + '?') + _usage + exit 1 + ;; + esac + done + + set - $otherArgs + shift `expr $OPTIND - 1` + [ $# -gt 0 ] && argInterfaces="$*" +fi + +# maximum average active for disks, percent -> msec/sec +maxactive=`expr $maxbusy \* 1000 / 100` + + +# maximum req error rate (default: 20% of packet rate) +maxerr=`expr $maxreq / 5` +[ "$maxerr" -eq 0 ] && maxerr=1 + + +# --- check that web metrics are available from metrics source --- +# +if _pmview_fetch web.allservers.errors +then + : +else + _pmview_error "$prog: weblog metrics not defined in the name space" + #NOTREACHED +fi + + +# --- if metrics source is an archive, and find out name of host --- +# +if [ "X$arch" != X ] +then + host=`pmdumplog -l $arch | $PCP_AWK_PROG '/^Performance/ {print $5}' | sed -e 's/,//g'` + [ "X$host" = X ] && host="unknown host" + host="$host (Archive $arch)" +fi + + +# --- get network interfaces --- +# +pminfo -f $msource network.interface.total.bytes >$tmp.int +sed -e 's/\]//' -e 's/"//g' $tmp.int \ + | $PCP_AWK_PROG '$1 == "inst" {print $4}' > $tmp.list +if [ ! -s $tmp.list ] +then + if [ "X$arch" != X ] + then + _pmview_error "$prog: failed to get network interface list from archive \"$arch\"" + #NOTREACHED + else + _pmview_error "$prog: failed to get network interface list from host \"$host\"" + #NOTREACHED + fi +fi + + +# --- pmview config file has already been created; keep writing to it --- +# + +cat << end-of-file >> $tmp.pmview +# +# $prog +# +end-of-file + +if $verbose +then + echo "# Available Network Interfaces: " `cat $tmp.list` >> $tmp.pmview +fi + +if [ -z "$argInterfaces" ] +then + cp $tmp.list $tmp.chosen +else + touch $tmp.chosen + for i in $argInterfaces + do + egrep $i $tmp.list >> $tmp.chosen + done +fi + +interfaces_sp=`cat $tmp.chosen | sort | uniq` +loflag=false +for iface in $interfaces_sp +do + if [ "X$iface" = "Xlo0" ] + then + loflag=true + else + interfaces="$interfaces $iface" + fi +done +$loflag && interfaces="$interfaces lo0" +ninterfaces=`echo $interfaces | wc -w` + +if $verbose +then + echo "# Network interfaces Matching \"$argInterfaces\": $interfaces" >> $tmp.pmview +fi + +if [ $ninterfaces = 0 ] +then + echo "$prog: no matching network interfaces" + echo "Available interfaces on host \"$host\" are: " `cat $tmp.list` + echo "" + _usage + exit 1 +fi + +net_grid1=`expr $ninterfaces + 2` + +# --- how many CPUs on this system? --- +# +numcpu=`pminfo $msource -f $namespace hinv.ncpu 2>&1 | $PCP_AWK_PROG ' +BEGIN { num = 0 } +$1 == "value" { if (NF == 2) num = $2 } +END { print num }'` + +if [ $numcpu -lt 1 ] +then + _pmview_fetch_indom kernel.percpu.cpu.user && numcpu=$number + if [ $numcpu -lt 1 ] + then + _pmview_error "$prog: Unable to determine the number of CPUs on host $host" + #NOTREACHED + fi +fi + +maxcpu=`expr $maxcpu \* $numcpu` + +if $verbose +then + if [ $numcpu = 1 ] + then + echo "# 1 CPU detected" >> $tmp.pmview + echo "#" >> $tmp.pmview + else + echo "# $numcpu CPUs detected" >> $tmp.pmview + echo "#" >> $tmp.pmview + fi +fi + +# --- how much memory on this system? --- +# +realmem=0 +if pminfo -v $msource $namespace hinv.physmem > /dev/null 2>&1 +then + realmem=`pminfo -f $msource $namespace hinv.physmem | $PCP_AWK_PROG '/value/ { print $2 }'` + if [ -z "$realmem" ] + then + realmem=0 + else + realmem=`expr $realmem \* 1024` + fi +fi +[ $realmem = 0 ] && echo "$prog: Warning: Unable to determine size of real memory for $host" + + +# --- how many disks on this system? --- +# +numdisk=`pminfo $msource -f $namespace hinv.ndisk 2>&1 | $PCP_AWK_PROG ' +BEGIN { num = 0 } +$1 == "value" { if (NF == 2) num = $2 } +END { print num }'` + +if [ $numdisk -lt 0 ] +then + _pmview_fetch_indom disk.dev.read && numdisk=$number + [ $numdisk -lt 0 ] && _pmview_warning "$prog: Unable to determine the number of disks for $host" +fi + +if $verbose +then + if [ $numdisk = 1 ] + then + echo "# 1 disk detected" >> $tmp.pmview + echo "#" >> $tmp.pmview + else + echo "# $numdisk disks detected" >> $tmp.pmview + echo "#" >> $tmp.pmview + fi +fi + + +# --- set the window title --- +# +if [ -z "$titleArg" ] +then + titleArg="SGI PCP : Web Server Activity for Host $host" +fi + + +# --- set base strings for base plane objects --- +# +if [ $numcpu = 1 ] +then + basestr_cpu="CPU Utilization\nSummed over 1 CPU" +else + basestr_cpu="CPU Utilization\nSummed over $numcpu CPUs" +fi + +basestr_mem="Physical Memory Utilization\nNormalized to `pminfo -f $msource mem.physmem | grep value | sed -e 's/ *value //'` Kbytes" + +basestr_disk="Read and Write activity for all Disks\nNormalized to $maxio I/Os per second" +basestr_diskact="Average Disk Utilization\nNormalized to $maxbusy% across $numdisk disks" + +basestr_net="Input and Output on Network Interfaces\nPackets are normalized to $max packets per second" + +basestr_amem="Memory metrics which may indicate a problem\nNormalized to $maxerr events per second" +basestr_atcp="TCP metrics which may indicate a problem\nNormalized to $maxerr events per second" + +basestr_size="HTTP request rate by response size in bytes\nNormalized to $maxreq hits per second" +basestr_type="HTTP request rate by HTTP method\nNormalized to $maxreq hits per second" + + +# ---- the real config starts here --- +# pmview Version 2.1 +# +cat << end-of-file >> $tmp.pmview + +_stackLength 26 +_marginWidth 8 +_marginDepth 8 + +_colorList cpu_colors ( blue2 red2 yellow2 cyan2 ) +_colorList disk_colors ( violet yellow ) +_colorList memory_colors ( + rgbi:1.0/1.0/0.0 + rgbi:0.0/1.0/1.0 + rgbi:1.0/0.0/0.0 + rgbi:1.0/0.0/1.0 + rgbi:0.0/0.0/1.0 + rgbi:0.0/1.0/0.0 +) +_colorList network_colors ( + rgbi:0.8/0.0/0.0 + rgbi:1.0/0.5/0.0 + rgbi:0.0/0.8/0.0 +) +_colorList type_colors ( + rgbi:0.8/0.0/0.0 + rgbi:1.0/1.0/0.6 + rgbi:1.0/0.0/1.0 + rgbi:0.0/1.0/1.0 + rgbi:1.0/1.0/0.0 +) + +_colorList size_colors ( + rgbi:1.0/0.35/0.0 + rgbi:0.6/0.0/0.9 + rgbi:0.0/1.0/0.0 + rgbi:1.0/0.5/0.0 + rgbi:0.65/0.3/1.0 + rgbi:0.3/1.0/0.3 + rgbi:1.0/0.65/0.3 + rgbi:0.8/0.6/1.0 + rgbi:0.6/1.0/0.6 + rgbi:1.0/0.8/0.6 +) + +_grid _hide ( + +# +# Alarms +# + _grid 1 0 6 2 south _hide ( + _bar 0 1 6 1 west _row _groupbyrow ( + _metrics ( +end-of-file + +for m in drops conndrops timeoutdrop rcvbadsum rexmttime sndrexmitpack attemptfails inerrs retranssegs +do + if _pmview_fetch network.tcp.$m + then + echo " network.tcp.$m $maxerr" >> $tmp.pmview + fi +done + +cat << end-of-file >> $tmp.pmview + ) + _colorList ( + red1 red1 red1 red1 red1 red1 + ) + _baseLabel "$basestr_atcp" + ) + _bar 0 0 3 1 west _row _groupbyrow ( + _metrics ( +end-of-file + +for m in swap.pagesout network.mbuf.failed network.mbuf.waited +do + if _pmview_fetch $m + then + echo " $m $maxerr" >> $tmp.pmview + fi +done + +cat << end-of-file >> $tmp.pmview + ) + _colorList ( + yellow rgbi:1.0/0.5/0.0 rgbi:1.0/0.5/0.0 + ) + _baseLabel "$basestr_amem" + ) + _label 3 0 west _right _medium "Alarms" + ) + +# +# Size +# + _bar 0 1 1 10 south _groupbycol ( + _metrics ( + web.allservers.requests.size.unknown $maxreq + web.allservers.requests.size.gt3m $maxreq + web.allservers.requests.size.le3m $maxreq + web.allservers.requests.size.le1m $maxreq + web.allservers.requests.size.le300k $maxreq + web.allservers.requests.size.le100k $maxreq + web.allservers.requests.size.le30k $maxreq + web.allservers.requests.size.le10k $maxreq + web.allservers.requests.size.le3k $maxreq + web.allservers.requests.size.zero $maxreq + ) + _metriclabels _towards ( + "?" ">3M" "3M" "1M" "300k" + "100k" "30k" "10k" "3k" "0k" + ) + _colorList size_colors + _baseLabel "$basestr_size" + ) + + _label 0 11 northeast _right _medium "Size" + +# +# Type +# + _bar 1 6 1 5 south _groupbycol ( + _metrics ( + web.allservers.errors $maxerr + web.allservers.requests.other $maxreq + web.allservers.requests.post $maxreq + web.allservers.requests.head $maxreq + web.allservers.requests.get $maxreq + ) + _colorList type_colors + _baseLabel "$basestr_type" + ) + + _label 1 11 north _right _medium "Type" + +# +# System level stuff +# + _grid 1 3 5 3 southwest ( + _stack 0 0 ( + _metrics ( + kernel.all.cpu.user $maxcpu + kernel.all.cpu.sys $maxcpu + kernel.all.cpu.intr $maxcpu + kernel.all.cpu.wait.total $maxcpu + ) + _colorList cpu_colors + _baseLabel "$basestr_cpu" + ) + _label 0 1 north _right _medium "CPU" + +# 2 levels of base plane, halve the margin size and increase the height +# for the inner one +# +_marginWidth 4 +_marginDepth 4 +_baseHeight 4 + + _grid 1 0 2 1 _show ( + _baseColor rgbi:0.30/0.30/0.30 + _stack 0 0 south _cylinder ( + _metrics ( + disk.all.write $maxio + disk.all.read $maxio + ) + _colorList disk_colors + _baseLabel "$basestr_disk" + ) +end-of-file + + # disk.all.avg_disk.active metric is not available from pcp 1.x + # + if _pmview_fetch disk.all.avg_disk.active + then + cat << end-of-file >> $tmp.pmview + _bar 1 0 _cylinder ( + _metrics ( + disk.all.avg_disk.active $maxactive + ) + _colorList ( green2 ) + _baseLabel "$basestr_diskact" + ) +end-of-file + fi + + cat << end-of-file >> $tmp.pmview + _baseColor rgbi:0.15/0.15/0.15 + ) + _label 1 1 2 1 north _medium "Disk" + +end-of-file + + if [ "X$realmem" != X0 -a "X$realmem" != X ] + then + xcoord=0 + + cat << end-of-file >> $tmp.pmview + _grid 3 0 2 1 _show ( + _baseColor rgbi:0.30/0.30/0.30 +end-of-file + + if _pmview_fetch mem.freemem + then + cat << end-of-file >> $tmp.pmview + _stack $xcoord 0 ( + _metrics ( + mem.freemem $realmem + ) + _colorList ( rgbi:0.0/0.8/0.0 ) + _baseLabel "Free memory" + ) +end-of-file + xcoord=`expr $xcoord + 1` + fi + + if _pmview_fetch mem.util.kernel + then + cat << end-of-file >> $tmp.pmview + + _stack $xcoord 0 ( + _metrics ( +end-of-file + # Use all the metrics we have + for m in kernel fs_ctl fs_dirty fs_clean user ; do + if _pmview_fetch mem.util.$m + then + echo " mem.util.$m $realmem" >> $tmp.pmview + fi + done + + cat << end-of-file >> $tmp.pmview + ) + _colorList memory_colors + _baseLabel "$basestr_mem" + ) +end-of-file + xcoord=`expr $xcoord + 1` + fi + + cat << end-of-file >> $tmp.pmview + _baseColor rgbi:0.15/0.15/0.15 + ) + _label 3 1 2 1 north _medium "Mem" +end-of-file + fi + + cat << end-of-file >> $tmp.pmview + +# restore defaults +# + _marginWidth 8 + _marginDepth 8 + _baseHeight 2 + ) + +# +# Network Stuff +# + _grid 2 6 $net_grid1 5 south _hide ( + _grid 0 0 1 2 west _hide ( + _label 0 0 east _right _medium "In" + _label 0 1 east _right _medium "Out" + ) +# 2 levels of base plane, halve the margin size and increase the height +# for the inner one +# +_marginWidth 4 +_marginDepth 4 +_baseHeight 4 + + _grid 1 0 $ninterfaces 2 _show ( + _baseColor rgbi:0.30/0.30/0.30 + +end-of-file + + xcoord=0 + yin=0 + yout=1 + for iface in $interfaces + do + cat << end-of-file >> $tmp.pmview + + _stack $xcoord $yin ( + _metrics ( + network.interface.in.errors[$iface] $maxerr + network.interface.in.drops[$iface] $maxerr + network.interface.in.packets[$iface] $max + ) + _colorList network_colors + _baseLabel "$basestr_net" + ) + _stack $xcoord $yout ( + _metrics ( + network.interface.out.errors[$iface] $maxerr + network.interface.out.drops[$iface] $maxerr + network.interface.out.packets[$iface] $max + ) + _colorList network_colors + _baseLabel "$basestr_net" + ) +end-of-file + xcoord=`expr $xcoord + 1` + done + + cat << end-of-file >> $tmp.pmview + _baseLabel "$basestr_net" +_baseColor rgbi:0.15/0.15/0.15 + ) +# restore defaults +# +_marginWidth 8 +_marginDepth 8 +_baseHeight 2 + _grid 1 2 $ninterfaces 2 _hide ( +end-of-file + + xcoord=0 + ylabel=0 + for iface in $interfaces + do + cat << end-of-file >> $tmp.pmview + _label $xcoord $ylabel north _down _medium "$iface" +end-of-file + xcoord=`expr $xcoord + 1` + done + + cat << end-of-file >> $tmp.pmview + ) + ) + _label 3 11 northwest _right _medium "Network" +) +end-of-file + +$verbose && cat $tmp.pmview + +eval $PMVIEW <$tmp.pmview $args -title "'$titleArg'" -xrm "'*iconName: $prog'" + +exit + diff --git a/src/pmview/front-ends/webvis.rgb b/src/pmview/front-ends/webvis.rgb Binary files differnew file mode 100644 index 0000000..5bd1482 --- /dev/null +++ b/src/pmview/front-ends/webvis.rgb |