#!/usr/bin/env bash

function error() {
	echo $*
	exit 1
}

source $EXP_ROOT/configs/nic.sh

cfgfile=$HOME/.irq.sh.config
cntfile=$HOME/.irq.sh.count

# use tilly01 as default...
if ! [ -f $cfgfile ]; then
	cat > $cfgfile <<EOF
mod: $NET_IF_MOD
nic: $NET_IF
EOF
	echo -n "async irq:" >> $cfgfile
	echo -n " 69" >> $cfgfile
	echo >> $cfgfile
	echo -n "rxirq:" >> $cfgfile
	for ((i=104;i<112;i++)); do echo -n " $i" >> $cfgfile; done
	for ((i=120;i<128;i++)); do echo -n " $i" >> $cfgfile; done
	for ((i=112;i<120;i++)); do echo -n " $i" >> $cfgfile; done
	for ((i=128;i<136;i++)); do echo -n " $i" >> $cfgfile; done
	echo >> $cfgfile
	echo -n "txirq:" >> $cfgfile
  for i in 70 71; do echo -n " $i" >> $cfgfile; done
	for ((i=74;i<80;i++)); do echo -n " $i" >> $cfgfile; done
	for ((i=88;i<96;i++)); do echo -n " $i" >> $cfgfile; done
	for ((i=80;i<88;i++)); do echo -n " $i" >> $cfgfile; done
	for ((i=96;i<104;i++)); do echo -n " $i" >> $cfgfile; done
	echo >> $cfgfile
fi

if [ "$1" = "print" ]; then
	mod=$(fgrep "mod:" $cfgfile|cut -f2 -d' ')
	[ -z "$mod" ] && error cannot find kernel name in $cfgfile
	fgrep $mod /proc/interrupts|awk '{print $1, $NF}'
	exit 0
fi

nic=$(fgrep "nic:" $cfgfile|cut -f2 -d' ')
[ -z "$nic" ] && error cannot find nic in $cfgfile

rxirq=($(fgrep rxirq: $cfgfile|cut -f2 -d:))
txirq=($(fgrep txirq: $cfgfile|cut -f2 -d:))
rxcnt=${#rxirq[@]}
txcnt=${#txirq[@]}
rqcnt=$(ethtool -l $nic|fgrep RX:|tail -1|awk '{print $2}')
tqcnt=$(ethtool -l $nic|fgrep TX:|tail -1|awk '{print $2}')

allirq=("${rxirq[@]}" "${txirq[@]}")
allcnt=${#allirq[@]}

idx=0
for ((i=0;i<$rxcnt;i++)); do
	irqtype[$idx]="RX"
	idx=$(expr $idx + 1)
done
for ((i=0;i<$txcnt;i++)); do
  irqtype[$idx]="TX"
	idx=$(expr $idx + 1)
done

if [ "$1" = "-a" ]; then
	shift
	all=1
else
	all=0
fi

if [ "$1" = "set" ]; then
	shift
	if [ "$1" = "rx" ]; then 
		shift
		maxidx=$rxcnt
	else
		maxidx=$allcnt
	fi
	[ $# -lt 1 ] && error "usage $0 set <low> [<high>]"
	[ $# -lt 2 ] && num=1 || num=$(expr 1 + $2 - $1)
	for ((idx=0;idx<$maxidx;idx++)); do
		irq=${allirq[$idx]}
		cpu=$(expr $1 + $idx % $num)
		sudo -s sh -c "echo $cpu > /proc/irq/$irq/smp_affinity_list"
#		echo $cpu | sudo tee /proc/irq/$irq/smp_affinity_list > /dev/null
	done
	exit 0
fi

[ -f $cntfile ] || touch $cntfile

idx=0
[ "$1" = "clear" ] || for x in $(fgrep irqs: $cntfile|cut -f2 -d:); do
	irqcntprev[$idx]=$x
	idx=$(expr $idx + 1)
done
for ((;idx<$allcnt;idx++)); do
	irqcntprev[$idx]=0
done

idx=0
[ "$1" = "clear" ] || for x in $(fgrep pkts: $cntfile|cut -f2 -d:); do
	pktcntprev[$idx]=$x
	idx=$(expr $idx + 1)
done
for ((;idx<$allcnt;idx++)); do
	pktcntprev[$idx]=0
done

[ "$1" = "clear" ] && {
	rxdropsprev=0
	txdropsprev=0
} || {
	fgrep -q rxdrops: $cntfile && {
		rxdropsprev=$(fgrep rxdrops: $cntfile|cut -f2 -d:)
	} || {
		rxdropsprev=0
	}
	fgrep -q txdrops: $cntfile && {
		txdropsprev=$(fgrep txdrops: $cntfile|cut -f2 -d:)
	} || {
		txdropsprev=0
	}
}

echo -n "irqs:" > $cntfile
irqline=($(fgrep intr /proc/stat|cut -f3- -d' '))
for ((idx=0;idx<$allcnt;idx++)); do
	x=${irqline[${allirq[$idx]}]}
	echo -n " $x" >> $cntfile
	irqcntnow[$idx]=$x
done
echo >> $cntfile

echo -n "pkts:" >> $cntfile
idx=0
for x in $(ethtool -S $nic|fgrep packet|fgrep rx|fgrep -v rx_|cut -f2 -d:); do
	echo -n " $x" >> $cntfile
	pktcntnow[$idx]=$x
  idx=$(expr $idx + 1)
done
for ((;idx<$rxcnt;idx++)); do
	echo -n " 0" >> $cntfile
	pktcntnow[$idx]=0
done
for x in $(ethtool -S $nic|fgrep packet|fgrep tx|fgrep -v tx_|cut -f2 -d:); do
	echo -n " $x" >> $cntfile
	pktcntnow[$idx]=$x
  idx=$(expr $idx + 1)
done
for ((;idx<$allcnt;idx++)); do
	echo -n " 0" >> $cntfile
	pktcntnow[$idx]=0
done
echo >> $cntfile

rxdropsnow=$(ethtool -S $nic|fgrep rx_dropped:|cut -f2 -d:)
txdropsnow=$(ethtool -S $nic|fgrep tx_dropped:|cut -f2 -d:)
echo "rxdrops: $rxdropsnow" >> $cntfile
echo "txdrops: $txdropsnow" >> $cntfile
rxdrops=$(expr $rxdropsnow - $rxdropsprev)
txdrops=$(expr $txdropsnow - $txdropsprev)

irqsum=0
pktsum=0
printf "%5s    %10s %10s %5s name\n" num irqs pkts cpus
for ((idx=0;idx<$allcnt;idx++)); do
	irqs[$idx]=$(expr ${irqcntnow[$idx]} - ${irqcntprev[$idx]})
	pkts[$idx]=$(expr ${pktcntnow[$idx]} - ${pktcntprev[$idx]})
	irqsum=$(expr $irqsum + ${irqs[$idx]})
	pktsum=$(expr $pktsum + ${pkts[$idx]})
done
for ((idx=0;idx<$allcnt;idx++)); do
	irq=${allirq[$idx]}
	cpus=$(cat /proc/irq/$irq/smp_affinity_list)
	name=$(fgrep " $irq:" /proc/interrupts|awk '{print $NF}')
	if [ $all -gt 0 ] || [ ${irqs[$idx]} -gt 0 -o ${pkts[$idx]} -gt 0 ]; then
		printf "%5d %2s %10d %10d %5s %s\n" $irq ${irqtype[$idx]} ${irqs[$idx]} ${pkts[$idx]} $cpus $name
	fi
done|sort -g -k1
printf "total    %10d %10d\n" $irqsum $pktsum
[ $rxdrops -gt 0 ] && printf "drops RX %10d\n" $rxdrops
[ $txdrops -gt 0 ] && printf "drops TX %10d\n" $txdrops
exit 0