#!/bin/sh
#
# Plugin to measure average CPU frequency for each CPU/core.
#
# Contributed by Mark Edwards
#
# Usage: Place in /etc/munin/plugins (or link it there  using ln -s)
#
# Parameters understood:
#
#       config   (required)
#       autoconf (optional - used by munin-config)
#
# $Log$
#
# Revision 0.2  2010/01/04 16:37:00  medwards
# Minor bugfixes in config section
#
# Revision 0.1  2010/01/04 16:13:00  medwards
# First version
#
#
#
# Magic markers - optional - used by installation scripts and
# munin-config:
#
#%# family=auto
#%# capabilities=autoconf

if [ "$1" = "autoconf" ]; then
		if [ -r /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state ]; then
			echo yes
			exit 0
		else
			echo no
			exit 1
		fi
fi

cpu_count=`grep -c "^processor" /proc/cpuinfo`

if [ "$1" = "config" ]; then

		echo 'graph_title Average CPU Frequency'
		up_lim=`cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq`
		low_lim=`cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq`
		up_lim=`expr $up_lim \* 1000` # Convert to Hz
		low_lim=`expr $low_lim \* 1000` # Convert to Hz
		echo "graph_args -u $up_lim -l $low_lim -r --base 1000"
		echo 'graph_vlabel Hz'
		echo 'graph_category system'
		cpu=0
		while [ $cpu -lt $cpu_count ]
		do
			echo "cpu_$cpu.label CPU $cpu"
			echo "cpu_$cpu.type GAUGE"
			echo "cpu_$cpu.info Hz"
			cpu=`expr $cpu + 1`
		done
		exit 0
fi

# Run measurements
cpu=0
while [ $cpu -lt $cpu_count ]
do

	time_in_state=`cat /sys/devices/system/cpu/cpu$cpu/cpufreq/stats/time_in_state`

	# Check/create statefile(s)
	statefile="/var/lib/munin/plugin-state/cpufreq-avg_cpu$cpu.state"
	if [ ! -r "$statefile" ]
	then
		echo "$time_in_state" > $statefile
		if [ "$?" -ne "0" ]
		then
			exit ${1}
		else
			cpu=`expr $cpu + 1`
			continue
		fi
	fi
	state=`cat $statefile`
	
	# Calculated total time since last state
	total_time=0
	total_time=$(
		echo "$time_in_state" | { 
			i=0
			while read line
			do
				this_freq=`echo $line | awk '{ print $1; }'`
				this_time=`echo $line | awk '{ print $2; }'`
				this_time_state=`echo "$state" | grep $this_freq | awk '{ print $2; }'`
				if [ $this_time -ge $this_time_state ] # Only measure if state is valid
				then
					time_diff=`expr $this_time - $this_time_state` # Calculate time since last state
					total_time=`expr $total_time + $time_diff`
				fi
				i=`expr $i + 1`
			done
			echo $total_time
		}
	)
	
	# Measure average CPU frequency if total time calculation was successful

	frequency=0
	frequency=$(
		echo "$time_in_state" | {
			i=0
			while read line
			do
				this_freq=`echo $line | awk '{ print $1; }'`
				this_time=`echo $line | awk '{ print $2; }'`
				this_time_state=`echo "$state" | grep $this_freq | awk '{ print $2; }'`
				this_freq=`expr $this_freq \* 1000` # Convert to Hz
				this_time=`expr $this_time - $this_time_state` # Calculate time since last state
				if [ $total_time -gt 0 ]
				then
					calc=`echo "($this_time / $total_time) * $this_freq" | bc -l`
					frequency=`echo "$frequency + $calc" | bc -l`
				fi
				i=`expr $i + 1`
			done
			echo $frequency
		}
	)

	# Round result to an integer and return it
	frequency=`echo "scale=0 ; ($frequency+0.5)/1" | bc -l`
	if [ $frequency -gt 0 ]
	then
		echo "cpu_$cpu.value $frequency"
	fi
	
	# Update statefile
	echo "$time_in_state" > $statefile
	
	cpu=`expr $cpu + 1`

done

exit 0