55b5be
#!/bin/sh
55b5be
#
55b5be
# plugin for munin to monitor usage of unbound servers.
55b5be
#
55b5be
# (C) 2008 W.C.A. Wijngaards.  BSD Licensed.
55b5be
#
55b5be
# To install; enable statistics and unbound-control in unbound.conf
55b5be
#	server:		extended-statistics: yes
55b5be
#			statistics-cumulative: no
55b5be
#			statistics-interval: 0
55b5be
#	remote-control:	control-enable: yes
55b5be
# Run the command unbound-control-setup to generate the key files.
55b5be
#
55b5be
# Environment variables for this script
55b5be
#	statefile	- where to put temporary statefile.
55b5be
#	unbound_conf	- where the unbound.conf file is located.
55b5be
#	unbound_control	- where to find unbound-control executable.
55b5be
#	spoof_warn	- what level to warn about spoofing
55b5be
#	spoof_crit	- what level to crit about spoofing
55b5be
#
55b5be
# You can set them in your munin/plugin-conf.d/plugins.conf file
55b5be
# with:
55b5be
# [unbound*]
55b5be
# user root
55b5be
# env.statefile /usr/local/var/munin/plugin-state/unbound-state
55b5be
# env.unbound_conf /usr/local/etc/unbound/unbound.conf
55b5be
# env.unbound_control /usr/local/sbin/unbound-control
55b5be
# env.spoof_warn 1000
55b5be
# env.spoof_crit 100000
55b5be
#
55b5be
# This plugin can create different graphs depending on what name
55b5be
# you link it as (with ln -s) into the plugins directory
55b5be
# You can link it multiple times.
55b5be
# If you are only a casual user, the _hits and _by_type are most interesting,
55b5be
# possibly followed by _by_rcode.
55b5be
#
55b5be
#	unbound_munin_hits	- base volume, cache hits, unwanted traffic
55b5be
#	unbound_munin_queue	- to monitor the internal requestlist
55b5be
#	unbound_munin_memory	- memory usage
55b5be
#	unbound_munin_by_type	- incoming queries by type
55b5be
#	unbound_munin_by_class	- incoming queries by class
55b5be
#	unbound_munin_by_opcode	- incoming queries by opcode
55b5be
#	unbound_munin_by_rcode	- answers by rcode, validation status
55b5be
#	unbound_munin_by_flags	- incoming queries by flags
55b5be
#	unbound_munin_histogram	- histogram of query resolving times
55b5be
#
55b5be
# Magic markers - optional - used by installation scripts and
55b5be
# munin-config:
55b5be
#
55b5be
#%# family=contrib
55b5be
#%# capabilities=autoconf suggest
55b5be
55b5be
# POD documentation
55b5be
: <<=cut
55b5be
=head1 NAME
55b5be
55b5be
unbound_munin_ - Munin plugin to monitor the Unbound DNS resolver.
55b5be
55b5be
=head1 APPLICABLE SYSTEMS
55b5be
55b5be
System with unbound daemon.
55b5be
55b5be
=head1 CONFIGURATION
55b5be
55b5be
  [unbound*]
55b5be
  user root
55b5be
  env.statefile /var/lib/munin/plugin-state/unbound-state
55b5be
  env.unbound_conf /etc/unbound/unbound.conf
55b5be
  env.unbound_control /usr/sbin/unbound-control
55b5be
  env.spoof_warn 1000
55b5be
  env.spoof_crit 100000
55b5be
55b5be
Use the .env settings to override the defaults.
55b5be
55b5be
=head1 USAGE
55b5be
55b5be
Can be used to present different graphs. Use ln -s for that name in
55b5be
the plugins directory to enable the graph.
55b5be
unbound_munin_hits	- base volume, cache hits, unwanted traffic
55b5be
unbound_munin_queue	- to monitor the internal requestlist
55b5be
unbound_munin_memory	- memory usage
55b5be
unbound_munin_by_type	- incoming queries by type
55b5be
unbound_munin_by_class	- incoming queries by class
55b5be
unbound_munin_by_opcode	- incoming queries by opcode
55b5be
unbound_munin_by_rcode	- answers by rcode, validation status
55b5be
unbound_munin_by_flags	- incoming queries by flags
55b5be
unbound_munin_histogram - histogram of query resolving times
55b5be
55b5be
=head1 AUTHOR
55b5be
55b5be
Copyright 2008 W.C.A. Wijngaards
55b5be
55b5be
=head1 LICENSE
55b5be
55b5be
BSD
55b5be
55b5be
=cut
55b5be
55b5be
state=${statefile:-/var/lib/munin/plugin-state/unbound-state}
55b5be
conf=${unbound_conf:-/etc/unbound/unbound.conf}
55b5be
ctrl=${unbound_control:-/usr/sbin/unbound-control}
55b5be
warn=${spoof_warn:-1000}
55b5be
crit=${spoof_crit:-100000}
55b5be
lock=$state.lock
55b5be
55b5be
# number of seconds between polling attempts.
55b5be
# makes the statefile hang around for at least this many seconds,
55b5be
# so that multiple links of this script can share the results.
55b5be
lee=55
55b5be
55b5be
# to keep things within 19 characters
55b5be
ABBREV="-e s/total/t/ -e s/thread/t/ -e s/num/n/ -e s/query/q/ -e s/answer/a/ -e s/unwanted/u/ -e s/requestlist/ql/ -e s/type/t/ -e s/class/c/ -e s/opcode/o/ -e s/rcode/r/ -e s/edns/e/ -e s/mem/m/ -e s/cache/c/ -e s/mod/m/"
55b5be
55b5be
# get value from $1 into return variable $value
55b5be
get_value ( ) {
55b5be
	value="`grep '^'$1'=' $state | sed -e 's/^.*=//'`"
55b5be
	if test "$value"x = ""x; then
55b5be
		value="0"
55b5be
	fi
55b5be
}
55b5be
55b5be
# download the state from the unbound server.
55b5be
get_state ( ) {
55b5be
	# obtain lock for fetching the state
55b5be
	# because there is a race condition in fetching and writing to file
55b5be
55b5be
	# see if the lock is stale, if so, take it 
55b5be
	if test -f $lock ; then
55b5be
		pid="`cat $lock 2>&1`"
55b5be
		kill -0 "$pid" >/dev/null 2>&1
55b5be
		if test $? -ne 0 -a "$pid" != $$ ; then
55b5be
			echo $$ >$lock
55b5be
		fi
55b5be
	fi
55b5be
55b5be
	i=0
55b5be
	while test ! -f $lock || test "`cat $lock 2>&1`" != $$; do
55b5be
		while test -f $lock; do
55b5be
			# wait
55b5be
			i=`expr $i + 1`
55b5be
			if test $i -gt 1000; then
55b5be
				sleep 1;
55b5be
			fi
55b5be
			if test $i -gt 1500; then
55b5be
				echo "error locking $lock" "=" `cat $lock`
55b5be
				rm -f $lock
55b5be
				exit 1
55b5be
			fi
55b5be
		done
55b5be
		# try to get it
55b5be
		echo $$ >$lock
55b5be
	done
55b5be
	# do not refetch if the file exists and only LEE seconds old
55b5be
	if test -f $state; then
55b5be
		now=`date +%s`
55b5be
		get_value "time.now"
55b5be
		value="`echo $value | sed -e 's/\..*$//'`"
55b5be
		if test $now -lt `expr $value + $lee`; then
55b5be
			rm -f $lock
55b5be
			return
55b5be
		fi
55b5be
	fi
55b5be
	$ctrl -c $conf stats > $state
55b5be
	if test $? -ne 0; then
55b5be
		echo "error retrieving data from unbound server"
55b5be
		rm -f $lock
55b5be
		exit 1
55b5be
	fi
55b5be
	rm -f $lock
55b5be
}
55b5be
55b5be
if test "$1" = "autoconf" ; then
55b5be
	if test ! -f $conf; then
55b5be
		echo no "($conf does not exist)"
55b5be
		exit 1
55b5be
	fi
55b5be
	if test ! -d `dirname $state`; then
55b5be
		echo no "($state directory does not exist)"
55b5be
		exit 1
55b5be
	fi
55b5be
	echo yes
55b5be
	exit 0
55b5be
fi
55b5be
55b5be
if test "$1" = "suggest" ; then
55b5be
	echo "hits"
55b5be
	echo "queue"
55b5be
	echo "memory"
55b5be
	echo "by_type"
55b5be
	echo "by_class"
55b5be
	echo "by_opcode"
55b5be
	echo "by_rcode"
55b5be
	echo "by_flags"
55b5be
	echo "histogram"
55b5be
	exit 0
55b5be
fi
55b5be
55b5be
# determine my type, by name
55b5be
id=`echo $0 | sed -e 's/^.*unbound_munin_//'`
55b5be
if test "$id"x = ""x; then
55b5be
	# some default to keep people sane.
55b5be
	id="hits"
55b5be
fi
55b5be
55b5be
# if $1 exists in statefile, config is echoed with label $2
55b5be
exist_config ( ) {
55b5be
	mn=`echo $1 | sed $ABBREV | tr . _`
55b5be
	if grep '^'$1'=' $state >/dev/null 2>&1; then
55b5be
		echo "$mn.label $2"
55b5be
		echo "$mn.min 0"
55b5be
	fi
55b5be
}
55b5be
55b5be
# print label and min 0 for a name $1 in unbound format
55b5be
p_config ( ) {
55b5be
	mn=`echo $1 | sed $ABBREV | tr . _`
55b5be
	echo $mn.label "$2"
55b5be
	echo $mn.min 0
55b5be
}
55b5be
55b5be
if test "$1" = "config" ; then
55b5be
	if test ! -f $state; then
55b5be
		get_state
55b5be
	fi
55b5be
	case $id in
55b5be
	hits)
55b5be
		echo "graph_title Unbound DNS traffic and cache hits"
55b5be
		echo "graph_args --base 1000 -l 0"
55b5be
		echo "graph_vlabel queries / second"
55b5be
		echo "graph_category DNS"
55b5be
		for x in thread0.num.queries thread1.num.queries \
55b5be
		thread2.num.queries thread3.num.queries thread4.num.queries \
55b5be
		thread5.num.queries thread6.num.queries thread7.num.queries; do
55b5be
			exist_config $x "queries handled by `basename $x .num.queries`"
55b5be
		done
55b5be
		p_config "total.num.queries" "total queries from clients"
55b5be
		p_config "total.num.cachehits" "cache hits"
55b5be
		p_config "total.num.prefetch" "cache prefetch"
55b5be
		p_config "num.query.tcp" "TCP queries"
55b5be
		p_config "num.query.ipv6" "IPv6 queries"
55b5be
		p_config "unwanted.queries" "queries that failed acl"
55b5be
		p_config "unwanted.replies" "unwanted or unsolicited replies"
55b5be
		echo "u_replies.warning $warn"
55b5be
		echo "u_replies.critical $crit"
55b5be
		echo "graph_info DNS queries to the recursive resolver. The unwanted replies could be innocent duplicate packets, late replies, or spoof threats."
55b5be
		;;
55b5be
	queue)
55b5be
		echo "graph_title Unbound requestlist size"
55b5be
		echo "graph_args --base 1000 -l 0"
55b5be
		echo "graph_vlabel number of queries"
55b5be
		echo "graph_category DNS"
55b5be
		p_config "total.requestlist.avg" "Average size of queue on insert"
55b5be
		p_config "total.requestlist.max" "Max size of queue (in 5 min)"
55b5be
		p_config "total.requestlist.overwritten" "Number of queries replaced by new ones"
55b5be
		p_config "total.requestlist.exceeded" "Number of queries dropped due to lack of space"
55b5be
		echo "graph_info The queries that did not hit the cache and need recursion service take up space in the requestlist. If there are too many queries, first queries get overwritten, and at last resort dropped."
55b5be
		;;
55b5be
	memory)
55b5be
		echo "graph_title Unbound memory usage"
55b5be
		echo "graph_args --base 1024 -l 0"
55b5be
		echo "graph_vlabel memory used in bytes"
55b5be
		echo "graph_category DNS"
55b5be
		p_config "mem.total.sbrk" "Total memory"
55b5be
		p_config "mem.cache.rrset" "RRset cache memory"
55b5be
		p_config "mem.cache.message" "Message cache memory"
55b5be
		p_config "mem.mod.iterator" "Iterator module memory"
55b5be
		p_config "mem.mod.validator" "Validator module and key cache memory"
55b5be
		echo "graph_info The memory used by unbound."
55b5be
		;;
55b5be
	by_type)
55b5be
		echo "graph_title Unbound DNS queries by type"
55b5be
		echo "graph_args --base 1000 -l 0"
55b5be
		echo "graph_vlabel queries / second"
55b5be
		echo "graph_category DNS"
55b5be
		for x in `grep "^num.query.type" $state`; do
55b5be
			nm=`echo $x | sed -e 's/=.*$//'`
55b5be
			tp=`echo $nm | sed -e s/num.query.type.//`
55b5be
			p_config "$nm" "$tp"
55b5be
		done
55b5be
		echo "graph_info queries by DNS RR type queried for"
55b5be
		;;
55b5be
	by_class)
55b5be
		echo "graph_title Unbound DNS queries by class"
55b5be
		echo "graph_args --base 1000 -l 0"
55b5be
		echo "graph_vlabel queries / second"
55b5be
		echo "graph_category DNS"
55b5be
		for x in `grep "^num.query.class" $state`; do
55b5be
			nm=`echo $x | sed -e 's/=.*$//'`
55b5be
			tp=`echo $nm | sed -e s/num.query.class.//`
55b5be
			p_config "$nm" "$tp"
55b5be
		done
55b5be
		echo "graph_info queries by DNS RR class queried for."
55b5be
		;;
55b5be
	by_opcode)
55b5be
		echo "graph_title Unbound DNS queries by opcode"
55b5be
		echo "graph_args --base 1000 -l 0"
55b5be
		echo "graph_vlabel queries / second"
55b5be
		echo "graph_category DNS"
55b5be
		for x in `grep "^num.query.opcode" $state`; do
55b5be
			nm=`echo $x | sed -e 's/=.*$//'`
55b5be
			tp=`echo $nm | sed -e s/num.query.opcode.//`
55b5be
			p_config "$nm" "$tp"
55b5be
		done
55b5be
		echo "graph_info queries by opcode in the query packet."
55b5be
		;;
55b5be
	by_rcode)
55b5be
		echo "graph_title Unbound DNS answers by return code"
55b5be
		echo "graph_args --base 1000 -l 0"
55b5be
		echo "graph_vlabel answer packets / second"
55b5be
		echo "graph_category DNS"
55b5be
		for x in `grep "^num.answer.rcode" $state`; do
55b5be
			nm=`echo $x | sed -e 's/=.*$//'`
55b5be
			tp=`echo $nm | sed -e s/num.answer.rcode.//`
55b5be
			p_config "$nm" "$tp"
55b5be
		done
55b5be
		p_config "num.answer.secure" "answer secure"
55b5be
		p_config "num.answer.bogus" "answer bogus"
55b5be
		p_config "num.rrset.bogus" "num rrsets marked bogus"
55b5be
		echo "graph_info answers sorted by return value. rrsets bogus is the number of rrsets marked bogus per second by the validator"
55b5be
		;;
55b5be
	by_flags)
55b5be
		echo "graph_title Unbound DNS incoming queries by flags"
55b5be
		echo "graph_args --base 1000 -l 0"
55b5be
		echo "graph_vlabel queries / second"
55b5be
		echo "graph_category DNS"
55b5be
		p_config "num.query.flags.QR" "QR (query reply) flag"
55b5be
		p_config "num.query.flags.AA" "AA (auth answer) flag"
55b5be
		p_config "num.query.flags.TC" "TC (truncated) flag"
55b5be
		p_config "num.query.flags.RD" "RD (recursion desired) flag"
55b5be
		p_config "num.query.flags.RA" "RA (rec avail) flag"
55b5be
		p_config "num.query.flags.Z" "Z (zero) flag"
55b5be
		p_config "num.query.flags.AD" "AD (auth data) flag"
55b5be
		p_config "num.query.flags.CD" "CD (check disabled) flag"
55b5be
		p_config "num.query.edns.present" "EDNS OPT present"
55b5be
		p_config "num.query.edns.DO" "DO (DNSSEC OK) flag"
55b5be
		echo "graph_info This graphs plots the flags inside incoming queries. For example, if QR, AA, TC, RA, Z flags are set, the query can be rejected. RD, AD, CD and DO are legitimately set by some software."
55b5be
		;;
55b5be
	histogram)
55b5be
		echo "graph_title Unbound DNS histogram of reply time"
55b5be
		echo "graph_args --base 1000 -l 0"
55b5be
		echo "graph_vlabel queries / second"
55b5be
		echo "graph_category DNS"
55b5be
		echo hcache.label "cache hits"
55b5be
		echo hcache.min 0
55b5be
		echo hcache.draw AREA
55b5be
		echo hcache.colour 999999
55b5be
		echo h64ms.label "0 msec - 66 msec"
55b5be
		echo h64ms.min 0
55b5be
		echo h64ms.draw STACK
55b5be
		echo h64ms.colour 0000FF
55b5be
		echo h128ms.label "66 msec - 131 msec"
55b5be
		echo h128ms.min 0
55b5be
		echo h128ms.colour 1F00DF
55b5be
		echo h128ms.draw STACK
55b5be
		echo h256ms.label "131 msec - 262 msec"
55b5be
		echo h256ms.min 0
55b5be
		echo h256ms.draw STACK
55b5be
		echo h256ms.colour 3F00BF
55b5be
		echo h512ms.label "262 msec - 524 msec"
55b5be
		echo h512ms.min 0
55b5be
		echo h512ms.draw STACK
55b5be
		echo h512ms.colour 5F009F
55b5be
		echo h1s.label "524 msec - 1 sec"
55b5be
		echo h1s.min 0
55b5be
		echo h1s.draw STACK
55b5be
		echo h1s.colour 7F007F
55b5be
		echo h2s.label "1 sec - 2 sec"
55b5be
		echo h2s.min 0
55b5be
		echo h2s.draw STACK
55b5be
		echo h2s.colour 9F005F
55b5be
		echo h4s.label "2 sec - 4 sec"
55b5be
		echo h4s.min 0
55b5be
		echo h4s.draw STACK
55b5be
		echo h4s.colour BF003F
55b5be
		echo h8s.label "4 sec - 8 sec"
55b5be
		echo h8s.min 0
55b5be
		echo h8s.draw STACK
55b5be
		echo h8s.colour DF001F
55b5be
		echo h16s.label "8 sec - ..."
55b5be
		echo h16s.min 0
55b5be
		echo h16s.draw STACK
55b5be
		echo h16s.colour FF0000
55b5be
		echo "graph_info Histogram of the reply times for queries."
55b5be
		;;
55b5be
	esac
55b5be
55b5be
	exit 0
55b5be
fi
55b5be
55b5be
# do the stats itself
55b5be
get_state
55b5be
55b5be
# get the time elapsed
55b5be
get_value "time.elapsed"
55b5be
if test $value = 0 || test $value = "0.000000"; then
55b5be
	echo "error: time elapsed 0 or could not retrieve data"
55b5be
	exit 1
55b5be
fi
55b5be
elapsed="$value"
55b5be
55b5be
# print value for $1 / elapsed
55b5be
print_qps ( ) {
55b5be
	mn=`echo $1 | sed $ABBREV | tr . _`
55b5be
	get_value $1
55b5be
	echo "$mn.value" `echo scale=6';' $value / $elapsed | bc `
55b5be
}
55b5be
55b5be
# print qps if line already found in $2
55b5be
print_qps_line ( ) {
55b5be
	mn=`echo $1 | sed $ABBREV | tr . _`
55b5be
	value="`echo $2 | sed -e 's/^.*=//'`"
55b5be
	echo "$mn.value" `echo scale=6';' $value / $elapsed | bc `
55b5be
}
55b5be
55b5be
# print value for $1
55b5be
print_value ( ) {
55b5be
	mn=`echo $1 | sed $ABBREV | tr . _`
55b5be
	get_value $1
55b5be
	echo "$mn.value" $value
55b5be
}
55b5be
55b5be
case $id in
55b5be
hits)
55b5be
	for x in thread0.num.queries thread1.num.queries thread2.num.queries \
55b5be
		thread3.num.queries thread4.num.queries thread5.num.queries \
55b5be
		thread6.num.queries thread7.num.queries total.num.queries \
55b5be
		total.num.cachehits total.num.prefetch num.query.tcp \
55b5be
		num.query.ipv6 unwanted.queries unwanted.replies; do
55b5be
		if grep "^"$x"=" $state >/dev/null 2>&1; then
55b5be
			print_qps $x
55b5be
		fi
55b5be
	done
55b5be
	;;
55b5be
queue)
55b5be
	for x in total.requestlist.avg total.requestlist.max \
55b5be
		total.requestlist.overwritten total.requestlist.exceeded; do
55b5be
		print_value $x
55b5be
	done
55b5be
	;;
55b5be
memory)
55b5be
	mn=`echo mem.total.sbrk | sed $ABBREV | tr . _`
55b5be
	get_value 'mem.total.sbrk'
55b5be
	if test $value -eq 0; then
55b5be
		chk=`echo $ctrl | sed -e 's/-control$/-checkconf/'`
55b5be
		pidf=`$chk -o pidfile $conf 2>&1`
55b5be
		pid=`cat $pidf 2>&1`
55b5be
		value=`ps -p "$pid" -o rss= 2>&1`
55b5be
		if test "`expr $value + 1 - 1 2>&1`" -eq "$value" 2>&1; then
55b5be
			value=`expr $value \* 1024` 
55b5be
		else
55b5be
			value=0
55b5be
		fi
55b5be
	fi
55b5be
	echo "$mn.value" $value
55b5be
	for x in mem.cache.rrset mem.cache.message \
55b5be
		mem.mod.iterator mem.mod.validator; do
55b5be
		print_value $x
55b5be
	done
55b5be
	;;
55b5be
by_type)
55b5be
	for x in `grep "^num.query.type" $state`; do
55b5be
		nm=`echo $x | sed -e 's/=.*$//'`
55b5be
		print_qps_line $nm $x
55b5be
	done
55b5be
	;;
55b5be
by_class)
55b5be
	for x in `grep "^num.query.class" $state`; do
55b5be
		nm=`echo $x | sed -e 's/=.*$//'`
55b5be
		print_qps_line $nm $x
55b5be
	done
55b5be
	;;
55b5be
by_opcode)
55b5be
	for x in `grep "^num.query.opcode" $state`; do
55b5be
		nm=`echo $x | sed -e 's/=.*$//'`
55b5be
		print_qps_line $nm $x
55b5be
	done
55b5be
	;;
55b5be
by_rcode)
55b5be
	for x in `grep "^num.answer.rcode" $state`; do
55b5be
		nm=`echo $x | sed -e 's/=.*$//'`
55b5be
		print_qps_line $nm $x
55b5be
	done
55b5be
	print_qps "num.answer.secure"
55b5be
	print_qps "num.answer.bogus"
55b5be
	print_qps "num.rrset.bogus"
55b5be
	;;
55b5be
by_flags)
55b5be
	for x in num.query.flags.QR num.query.flags.AA num.query.flags.TC num.query.flags.RD num.query.flags.RA num.query.flags.Z num.query.flags.AD num.query.flags.CD num.query.edns.present num.query.edns.DO; do
55b5be
		print_qps $x
55b5be
	done
55b5be
	;;
55b5be
histogram)
55b5be
	get_value total.num.cachehits
55b5be
	echo hcache.value `echo scale=6';' $value / $elapsed | bc `
55b5be
	r=0
55b5be
	for x in histogram.000000.000000.to.000000.000001 \
55b5be
		histogram.000000.000001.to.000000.000002 \
55b5be
		histogram.000000.000002.to.000000.000004 \
55b5be
		histogram.000000.000004.to.000000.000008 \
55b5be
		histogram.000000.000008.to.000000.000016 \
55b5be
		histogram.000000.000016.to.000000.000032 \
55b5be
		histogram.000000.000032.to.000000.000064 \
55b5be
		histogram.000000.000064.to.000000.000128 \
55b5be
		histogram.000000.000128.to.000000.000256 \
55b5be
		histogram.000000.000256.to.000000.000512 \
55b5be
		histogram.000000.000512.to.000000.001024 \
55b5be
		histogram.000000.001024.to.000000.002048 \
55b5be
		histogram.000000.002048.to.000000.004096 \
55b5be
		histogram.000000.004096.to.000000.008192 \
55b5be
		histogram.000000.008192.to.000000.016384 \
55b5be
		histogram.000000.016384.to.000000.032768 \
55b5be
		histogram.000000.032768.to.000000.065536; do
55b5be
		get_value $x
55b5be
		r=`expr $r + $value`
55b5be
	done
55b5be
	echo h64ms.value `echo scale=6';' $r / $elapsed | bc `
55b5be
	get_value histogram.000000.065536.to.000000.131072
55b5be
	echo h128ms.value `echo scale=6';' $value / $elapsed | bc `
55b5be
	get_value histogram.000000.131072.to.000000.262144
55b5be
	echo h256ms.value `echo scale=6';' $value / $elapsed | bc `
55b5be
	get_value histogram.000000.262144.to.000000.524288
55b5be
	echo h512ms.value `echo scale=6';' $value / $elapsed | bc `
55b5be
	get_value histogram.000000.524288.to.000001.000000
55b5be
	echo h1s.value `echo scale=6';' $value / $elapsed | bc `
55b5be
	get_value histogram.000001.000000.to.000002.000000
55b5be
	echo h2s.value `echo scale=6';' $value / $elapsed | bc `
55b5be
	get_value histogram.000002.000000.to.000004.000000
55b5be
	echo h4s.value `echo scale=6';' $value / $elapsed | bc `
55b5be
	get_value histogram.000004.000000.to.000008.000000
55b5be
	echo h8s.value `echo scale=6';' $value / $elapsed | bc `
55b5be
	r=0
55b5be
	for x in histogram.000008.000000.to.000016.000000 \
55b5be
		histogram.000016.000000.to.000032.000000 \
55b5be
		histogram.000032.000000.to.000064.000000 \
55b5be
		histogram.000064.000000.to.000128.000000 \
55b5be
		histogram.000128.000000.to.000256.000000 \
55b5be
		histogram.000256.000000.to.000512.000000 \
55b5be
		histogram.000512.000000.to.001024.000000 \
55b5be
		histogram.001024.000000.to.002048.000000 \
55b5be
		histogram.002048.000000.to.004096.000000 \
55b5be
		histogram.004096.000000.to.008192.000000 \
55b5be
		histogram.008192.000000.to.016384.000000 \
55b5be
		histogram.016384.000000.to.032768.000000 \
55b5be
		histogram.032768.000000.to.065536.000000 \
55b5be
		histogram.065536.000000.to.131072.000000 \
55b5be
		histogram.131072.000000.to.262144.000000 \
55b5be
		histogram.262144.000000.to.524288.000000; do
55b5be
		get_value $x
55b5be
		r=`expr $r + $value`
55b5be
	done
55b5be
	echo h16s.value `echo scale=6';' $r / $elapsed | bc `
55b5be
	;;
55b5be
esac