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