#!/bin/bash

CPUACCT_ROOT_PATH="/sys/fs/cgroup/cpu,cpuacct"
RANDOMPATH="$$-$RANDOM"


rm_test_files()
{
	if [ -f /tmp/report$RANDOMPATH.log ]; then
		rm -rf /tmp/report$RANDOMPATH.log
	fi

	if [ -f /tmp/perf.data ]; then
		rm -rf /tmp/perf.data
	fi
}

warn() {
        echo "ERROR: $1" >&2
}

get_ctn_path() {
	CTN_PATH=`find $CPUACCT_ROOT_PATH -name *$CTN_ID* | grep -v mount`
	POD_PATH=${CTN_PATH}/..
	PPOD_PATH=${POD_PATH}/..
	K8S_DIR=/sys/fs/cgroup/cpu,cpuacct/kubepods
}

get_init_bilistat() {
        if [ -d "$CTN_PATH" ]; then
		CPUACCT_BILISTAT=`cat ${CTN_PATH}/cpuacct.bili_stat`
	else
		echo "check whether the container is die or kernel has capuacct.bili_stat interface?"
		exit 1
	fi

	unset array
	while read -r line; do
		array+=("$line")
	done <<< "${CPUACCT_BILISTAT}"
}

cpuacct_bilistat_extract() {
	CA_CPU_USAGE=${array[0]}
	CA_TASK_STATE_NR=${array[1]}
	CA_LOAD_AVG=${array[2]}
	CA_WILL_THROTTLE=${array[3]}
	CA_WAIT_LAT=${array[4]}
	CA_PWAIT_LAT=${array[5]}
	CA_BLOCK_LAT=${array[6]}
	CA_IOBLOCK_LAT=${array[7]}
}

display_bili_stat() {
	echo "      cpu_usage: $CA_CPU_USAGE" >> /tmp/report$RANDOMPATH.log
	echo "  task_state_nr: $CA_TASK_STATE_NR" >> /tmp/report$RANDOMPATH.log
	echo "        loadavg: $CA_LOAD_AVG" >> /tmp/report$RANDOMPATH.log
	echo "  will_throttle: $CA_WILL_THROTTLE" >> /tmp/report$RANDOMPATH.log
	echo "   wait_latency: $CA_WAIT_LAT" >> /tmp/report$RANDOMPATH.log
	echo "  pwait_latency: $CA_PWAIT_LAT" >> /tmp/report$RANDOMPATH.log
	echo "  block_latency: $CA_BLOCK_LAT" >> /tmp/report$RANDOMPATH.log
	echo "ioblock_latency: $CA_IOBLOCK_LAT" >> /tmp/report$RANDOMPATH.log
	cat /tmp/report$RANDOMPATH.log | column -t
	rm /tmp/report$RANDOMPATH.log
}

test_bili() {
	if [ ! -z "${CTN_ID}" ]; then
		get_ctn_path
	else
		echo "please enter the container name!"
		exit 1
	fi
	CPUACCT_BILISTAT="CPUACCT_CTN_BILISTAT CPUACCT_POD_BILISTAT CPUACCT_PPOD_BILISTAT CPUACCT_K8S_BILISTAT"
	for i in $CPUACCT_BILISTAT; do
		if [ $i = CPUACCT_CTN_BILISTAT ]; then
			echo "-------------------------------------------------------------------container statistics-------------------------------------------------------------------"
		elif [ $i = CPUACCT_POD_BILISTAT ]; then
			echo "----------------------------------------------------------------------pod statistics----------------------------------------------------------------------"
			CTN_PATH=$POD_PATH
		elif [ $i = CPUACCT_PPOD_BILISTAT ]; then
			echo "-------------------------------------------------------------------pod parent statistics------------------------------------------------------------------"
			CTN_PATH=$POD_PATH/..
		else
			echo "---------------------------------------------------------------------k8s statistics-----------------------------------------------------------------------"
			CTN_PATH=$K8S_DIR
		fi
		report_bilistat_compare
	done
	exit 0
}

report_bilistat_compare() {
	echo "---------------------------------------------------------------start collect statistics-------------------------------------------------------------------"
	get_init_bilistat
	cpuacct_bilistat_extract
	display_bili_stat
	CPU_USAGE_START=(${CA_CPU_USAGE})
	TASK_STATE_NR_START=(${CA_TASK_STATE_NR})
	LOAD_AVG_START=(${CA_LOAD_AVG})
	WILL_THROTTLE_START=(${CA_WILL_THROTTLE})
	WAIT_LAT_START=(${CA_WAIT_LAT})
	PWAIT_LAT_START=(${CA_PWAIT_LAT})
	BLOCK_LAT_START=(${CA_BLOCK_LAT})
	IOBLOCK_LAT_START=(${CA_IOBLOCK_LAT})

	sleep $SLEEP_TIME

	echo "-------------------------------------------------------------------- after ${SLEEP_TIME}s ------------------------------------------------------------------------"
	get_init_bilistat
	cpuacct_bilistat_extract
	display_bili_stat
	CPU_USAGE_END=(${CA_CPU_USAGE})
	TASK_STATE_NR_END=(${CA_TASK_STATE_NR})
	LOAD_AVG_END=(${CA_LOAD_AVG})
	WILL_THROTTLE_END=(${CA_WILL_THROTTLE})
	WAIT_LAT_END=(${CA_WAIT_LAT})
	PWAIT_LAT_END=(${CA_PWAIT_LAT})
	BLOCK_LAT_END=(${CA_BLOCK_LAT})
	IOBLOCK_LAT_END=(${CA_IOBLOCK_LAT})

	CPU_USAGE_SUM=0
	for i in `seq 0 8`
	do
		CPU_USAGE_DIFF[$i]=$((${CPU_USAGE_END[$i]}-${CPU_USAGE_START[$i]}))
		CPU_USAGE_SUM=`expr $CPU_USAGE_SUM + ${CPU_USAGE_DIFF[$i]}`
	done

	echo $CPU_USAGE_SUM
	for i in `seq 0 8`
	do
		CPU_USAGE_RES[$i]=`awk 'BEGIN{printf "%.2f%%\n",('${CPU_USAGE_DIFF[$i]}'/'${CPU_USAGE_SUM}')*100}'`
	done

	for i in `seq 0 15`
	do
		WAIT_LAT_DIFF[$i]=$((${WAIT_LAT_END[$i]}-${WAIT_LAT_START[$i]}))
		PWAIT_LAT_DIFF[$i]=$((${PWAIT_LAT_END[$i]}-${PWAIT_LAT_START[$i]}))
		BLOCK_LAT_DIFF[$i]=$((${BLOCK_LAT_END[$i]}-${BLOCK_LAT_START[$i]}))
		IOBLOCK_LAT_DIFF[$i]=$((${IOBLOCK_LAT_END[$i]}-${IOBLOCK_LAT_START[$i]}))
	done

	if [ ${WAIT_LAT_DIFF[15]} -eq 0 ]; then
		WAIT_LAT_DIFF[16]=0
	else
		WAIT_LAT_DIFF[16]=`echo "scale=2;${WAIT_LAT_DIFF[14]}/${WAIT_LAT_DIFF[15]}" | bc -l`
	fi

	if [ ${PWAIT_LAT_DIFF[15]} -eq 0 ]; then
		PWAIT_LAT_DIFF[16]=0
	else
		PWAIT_LAT_DIFF[16]=`echo "scale=2;${PWAIT_LAT_DIFF[14]}/${PWAIT_LAT_DIFF[15]}" | bc -l`
	fi

	if [ ${BLOCK_LAT_DIFF[15]} -eq 0 ]; then
		BLOCK_LAT_DIFF[16]=0
	else
		BLOCK_LAT_DIFF[16]=`echo "scale=2;${BLOCK_LAT_DIFF[14]}/${BLOCK_LAT_DIFF[15]}" | bc -l`
	fi

	if [ ${IOBLOCK_LAT_DIFF[15]} -eq 0 ]; then
		IOBLOCK_LAT_DIFF[16]=0
	else
		IOBLOCK_LAT_DIFF[16]=`echo "scale=2;${IOBLOCK_LAT_DIFF[14]}/${IOBLOCK_LAT_DIFF[15]}" | bc -l`
	fi
	echo "-------------------------------------------------------------------- final report ------------------------------------------------------------------------"
	echo "    cpu_usage: ${CPU_USAGE_RES[*]}" >> /tmp/report$RANDOMPATH.log
	echo "   old_task_state: ${TASK_STATE_NR_START[*]}" >> /tmp/report$RANDOMPATH.log
	echo "   new_task_state: ${TASK_STATE_NR_END[*]}" >> /tmp/report$RANDOMPATH.log
	echo "      old_loadavg: ${LOAD_AVG_START[*]}" >> /tmp/report$RANDOMPATH.log
	echo "      new_loadavg: ${LOAD_AVG_END[*]}" >> /tmp/report$RANDOMPATH.log
	echo "old_will_throttle: ${WILL_THROTTLE_START[*]}" >> /tmp/report$RANDOMPATH.log
	echo "new_will_throttle: ${WILL_THROTTLE_END[*]}" >> /tmp/report$RANDOMPATH.log
	echo "type: 0-2 2-4 4-8 8-16 16-32 32-64 64-128 128-256 256-512 512-1024 1024-2048 2048-4096 4096-8192 >=8192 total(ms) nr avg" >> /tmp/report$RANDOMPATH.log
	echo "    wait_lat_diff: ${WAIT_LAT_DIFF[*]}" >> /tmp/report$RANDOMPATH.log
	echo "   pwait_lat_diff: ${PWAIT_LAT_DIFF[*]}" >> /tmp/report$RANDOMPATH.log
	echo "   block_lat_diff: ${BLOCK_LAT_DIFF[*]}" >> /tmp/report$RANDOMPATH.log
	echo " ioblock_lat_diff: ${IOBLOCK_LAT_DIFF[*]}" >> /tmp/report$RANDOMPATH.log
	cat /tmp/report$RANDOMPATH.log | column -t
	rm_test_files
}

report_perf_data() {
	if [ "$APPNAME" = "" ];then
	        echo "Please input the name of services, like: php, steampunk，etc."
		exit
	fi
	cd /tmp
	if [ "$SLEEP_TIMEE" = "" ];then
		echo "WARNNING: You dont specify the sleep time!"
	fi
	perf sched record -- sleep $SLEEP_TIME
	perf sched latency | grep $APPNAME
	rm_test_files
}

check_num_workers() {
	if [ "$APPNAME" = "" ];then
	        echo "Please input the name of services, like: php, steampunk，etc."
		exit
	fi

	if [ "$NUMBER" = "" ];then
	        echo "Please input the lowest number that you want to trace"
		exit
	fi

	while true;do
	        NR_RUN=`ps -eLo pid,state,comm | grep $APPNAME | grep R | wc -l`
		if [ $NR_RUN -lt $NUMBER ];then
			continue
		fi
	        echo "catch $NR_RUN running"
	done
}

check_lat_higher() {
	if [ "$SLEEP_TIME" = "" ];then
		echo "Default 10000us, you'd better enter a latency threshold with -t !!"
		sleep 10
	fi

	if [ "$PID" = "" ];then
		echo "No pid was set, you will tracing all tasks..."
		/usr/share/bcc/tools/runqslower $SLEEP_TIME -P
	else
		/usr/share/bcc/tools/runqslower -p $PID $SLEEP_TIME -P
	fi
}

usage() {
	echo "usage: $(basename "$0") [options]" >&2
	echo "Options:" >&2
	echo "          -h, --help                       Show this help message" >&2
	echo "          -T, --tool                       Specify the tool to use, like bili_stat, nr_workers, etc." >&2
	echo "          -d, --id                         Specify the container id" >&2
	echo "          -t, --time                       Specify the time for your purpose" >&2
	echo "          -a, --appname                    Specify the service for checking" >&2
	echo "          -n, --number                     Specify the number you want to tracing" >&2
	echo "          -p, --pid                        Specify the pid for your tracing" >&2
}

options="$(getopt -o hT:d:t:a:n:p: -l "help,tool:,id:,time:,appname:,number:,pid" -- "$@")" || die "getopt failed"

eval set -- "$options"

while [[ $# -gt 0 ]]; do
	case "$1" in
	-h|--help)
		usage
		exit 0
		;;
	-d|--id)
		CTN_ID="$2"
		shift
		;;
	-T|--tool)
		TOOL="$2"
		shift
		;;
	-t|--time)
		SLEEP_TIME="$2"
		shift
		;;
	-a|--appname)
		APPNAME="$2"
		shift
		;;
	-n|--number)
		NUMBER="$2"
		shift
		;;
	-p|--pid)
		PID="$2"
		shift
		;;
	*)
		[[ "$1" = "--" ]] && shift && continue
		;;
	esac
	shift
done

if [[ $TOOL = "bili_stat" ]]; then
	test_bili
fi

if [[ $TOOL = "perf" ]]; then
	report_perf_data
fi

if [[ $TOOL = "nr_workers" ]]; then
	check_num_workers
fi

if [[ $TOOL = "lat_threshold" ]]; then
	check_lat_higher
fi
