#$dirput: round app start_time(ms) start_type rss(MB) pss(MB) ratio pagefault minorfaults majorfaults itlbmiss dtlbmiss cpustalled

cycle=3
WAIT=3
clear_background=0
mthp_stat=0
cleancache=0
REBOOT=0

while getopts ":s:c:w:h:kTCR" opt
do
	case $opt in
		s)
			export ANDROID_SERIAL=$OPTARG
		;;
		c)
			cycle=$OPTARG
		;;
		k)
			clear_background=1
		;;
		w)
			WAIT=$OPTARG
		;;
		R)
			REBOOT=1
		;;
		T)
			mthp_stat=1
		;;
		C)
			cleancache=1
		;;
		h)
			echo "usage: run.sh -s sid -c cycle -w wait_seconds"
			exit 1
		;;
		?)
			echo "unrecognized parameters" $opt
			echo "usage: run.sh -s sid -c cycle -w wait_time [-C]"
			echo "-s: specify serial id of device"
			echo "-c: specify applist startup cycle"
			echo "-C: drop cache before start app"
			echo "-w: specify wait time after app start, before start next app, default 10 s"
			echo "-k: if to kill all background apps before start app"
			echo "-T: if check app's mTHP status"
			exit 1
		;;
	esac
done

# 检查多个设备
# 如果有多台设备需要先手动export ANDROID_SERIAL=xxx运作这个脚本
nr_dev=$(adb devices | grep -v "List of devices" | grep device -c)
if [ $nr_dev -gt 1 ] && [ -z "$ANDROID_SERIAL" ] ; then
	echo "adb: more than one device/emulator"
	exit
fi

# 如果只有1台设备默认测试该设备
if [ -z "$ANDROID_SERIAL" ]; then
	sid=$(adb devices | grep -v "List of devices" | grep device | awk '{print $1}')
	export ANDROID_SERIAL=$sid
fi


# adb root并推送perfetto配置文件
adb root
adb push perfconf.txt /data/misc/perfetto-configs

dir=$ANDROID_SERIAL/$(/usr/bin/date +%Y-%m%d-%H%M)
mkdir -p $dir
mkdir $dir/system_mem
mkdir $dir/battery
mkdir $dir/traces
mkdir $dir/meminfo
mkdir $dir/simpleperf
mkdir $dir/thpmaps

echo "round app start_type start_time rss pss pagefaults minorfaults majorfaults itlbmiss dtlbmiss cpustall inc_ratio inc_total order4_ratio order4_cont nr_inc_direct_reclaim" >> $dir/result

for round in $(seq 1 $cycle); do
	if [ $REBOOT -eq 1 ]; then
		# 重启并等待重启完成
		echo "rebooting"
		adb reboot
		sleep 30

		# 重启后等待adb
		# 如果10min还未成功则判断失败
		for w in $(seq 1 600); do
			if [ $(adb devices | grep $ANDROID_SERIAL -c) -eq 0 ]; then
				echo waiting device $w
				sleep 1
				continue
			fi
			adb root
			break
		done

		sleep 10
	fi

	adb root
	adb shell cat /sys/kernel/mm/transparent_hugepage/hugepages-64kB/enabled > 	$dir/hugepages-64kB_enabled
	adb shell cat /sys/kernel/mm/mthp_compact/enabled			 > 	$dir/mthp_compact_enabled

	# 解锁手机
	~/.scripts/android/unlock.sh
	# 等待降温
	for f in $(seq 1 900); do
		temp=$(adb shell dumpsys battery | grep temperature | awk '{print $2}')
		if [ $temp -gt 300 ]; then
			echo [$f] now temperature is $temp
			sleep 1
			continue
		fi
		break
	done

	for app in `cat applist`; do
		sleep 3

		if [ $clear_background -ne 0 ]; then
			./clearapp.sh
		fi

		if [ $cleancache -ne 0 ]; then
			adb shell "echo 3 > /proc/sys/vm/drop_caches"
		fi

		# 抓内存相关信息
		adb shell free -h > 			$dir/system_mem/before_free-$app-$round
		adb shell cat /proc/meminfo > 		$dir/system_mem/before_meminfo-$app-$round
		adb shell cat /proc/zoneinfo > 		$dir/system_mem/before_zoneinfo-$app-$round
		adb shell cat /proc/buddyinfo > 	$dir/system_mem/before_buddyinfo-$app-$round
		adb shell cat /proc/pagetypeinfo > 	$dir/system_mem/before_pagetypeinfo-$app-$round
		adb shell cat /proc/vmstat > 		$dir/system_mem/before_vmstat-$app-$round

		# 开始抓simpleperf和perfetto
		adb shell "simpleperf stat -e dTLB-loads,dTLB-load-misses,iTLB-loads,iTLB-load-misses,page-faults,raw-stall-backend-mem,minor-faults,major-faults --app $app --duration 3 -o /data/local/tmp/simpleperf-"$app"-"$round".txt" &
		adb shell "perfetto -c /data/misc/perfetto-configs/perfconf.txt --txt -o /data/misc/perfetto-traces/trace-"$app"-"$round".ptrace" &
		perfetto_pid=$!

		# 获取应用activity
		if [ "$app" == "com.qiyi.video" ]; then
			activity="com.qiyi.video/com.qiyi.video.WelcomeActivity"
		elif [ "$app" == "com.netease.cloudmusic" ]; then
			activity="com.netease.cloudmusic/com.netease.cloudmusic.activity.IconChangeDefaultAlias"
		elif [ "$app" == "com.ss.android.ugc.aweme" ]; then
			activity="com.ss.android.ugc.aweme/com.ss.android.ugc.aweme.splash.SplashActivity"
		elif [ "$app" == "com.ss.android.ugc.aweme.lite" ]; then
			activity="com.ss.android.ugc.aweme.lite/com.ss.android.ugc.aweme.splash.SplashActivity"
		else
			activity=$(adb shell dumpsys package $app | grep -A 1 -w "android.intent.action.MAIN:" | head -n 2 | tail -n 1 | awk '{print $2}')
		fi
		
		if [ -z "$activity" ]; then
			continue
		fi

		# 睡眠1s并准备抓大页数据
		sleep 1
		echo "starting $activity"

		# 抓电池信息
		adb shell "dumpsys battery" > $dir/battery/battery-$app-$round

		prev_alloc=$(adb shell cat /sys/kernel/mm/transparent_hugepage/hugepages-64kB/stats/anon_fault_alloc)
		prev_alloc_fallback=$(adb shell cat /sys/kernel/mm/transparent_hugepage/hugepages-64kB/stats/anon_fault_fallback)

		# 启动应用
		adb shell am start -n $activity
		
		# 睡眠15s并等待perfetto退出
		sleep 10
		wait
		
		# 后面的dumpsys meminfo也会分配大页
		# 所以先看分配大页数
		alloc=$(adb shell cat /sys/kernel/mm/transparent_hugepage/hugepages-64kB/stats/anon_fault_alloc)
		alloc_fallback=$(adb shell cat /sys/kernel/mm/transparent_hugepage/hugepages-64kB/stats/anon_fault_fallback)

		# dump内存占用
		adb shell "dumpsys meminfo --package $app" > $dir/meminfo/meminfo-"$app"-"$round".txt

		# 抓启动后的内存信息
		adb shell free -h > 			$dir/system_mem/after_free-$app-$round
		adb shell cat /proc/meminfo > 		$dir/system_mem/after_meminfo-$app-$round
		adb shell cat /proc/zoneinfo > 		$dir/system_mem/after_zoneinfo-$app-$round
		adb shell cat /proc/buddyinfo > 	$dir/system_mem/after_buddyinfo-$app-$round
		adb shell cat /proc/pagetypeinfo > 	$dir/system_mem/after_pagetypeinfo-$app-$round
		adb shell cat /proc/vmstat > 		$dir/system_mem/after_vmstat-$app-$round

		# 睡眠3s后拉simpleperf和perfetto数据
		sleep $WAIT
		adb pull /data/misc/perfetto-traces/trace-"$app"-"$round".ptrace $dir/traces
		adb pull /data/local/tmp/simpleperf-"$app"-"$round".txt $dir/simpleperf/
		adb shell "rm /data/misc/perfetto-traces/trace-"$app"-"$round".ptrace"
		adb shell "rm /data/local/tmp/simpleperf-"$app"-"$round".txt"

		# 回到桌面，应用退后台
		adb shell input keyevent 3

		# 计算启动耗时
		python3 handle_perfetto.py $dir/traces/trace-"$app"-"$round".ptrace mm > tmp.txt
		if [ $(cat tmp.txt | wc -l) -ne 1 ]; then
			start_time=0
			start_type="NONE"
		else
			start_time=$(cat tmp.txt | awk '{print $1}')
			start_type=$(cat tmp.txt | awk '{print $2}')
		fi

		start_time=$((start_time/10000))
		start_time=$(echo "scale=2; $start_time / 100" | bc)
		
		# 计算PSS RSS
		if [ $(cat $dir/meminfo/meminfo-"$app"-"$round".txt | grep "MEMINFO in pid" -c) -ne 1 ]; then
			cat $dir/meminfo/meminfo-"$app"-"$round".txt | grep "TOTAL PSS" | tail -n 1 > tmp.txt
			pss=$(cat tmp.txt | awk '{print $3}')
			rss=$(cat tmp.txt | awk '{print $6}')
		else
			cat $dir/meminfo/meminfo-"$app"-"$round".txt | grep "TOTAL PSS" > tmp.txt
			pss=$(cat tmp.txt | awk '{print $3}')
			rss=$(cat tmp.txt | awk '{print $6}')
		fi

		pss=$(echo "scale=2; $pss / 1024" | bc)
		rss=$(echo "scale=2; $rss / 1024" | bc)

		# 计算大页分配成功率
		inc_alloc=$((alloc-prev_alloc))
		inc_alloc_fallback=$((alloc_fallback-prev_alloc_fallback))
		inc_total=$((inc_alloc+inc_alloc_fallback))
		if [ $inc_total -ne 0 ]; then
			inc_ratio=$(echo "scale=4; $inc_alloc / $inc_total" | bc)
		else
			inc_ratio=1
		fi

		# 计算大页占比
		if [ $mthp_stat -eq 1 ]; then
			app_pid=$(adb shell "ps -ef" | grep $app | head -n 1 | awk '{print $2}')
			python3 thpmaps_v3_vir_cont.py --pid $app_pid --rollup --inc-empty --cont 64k > $dir/thpmaps/thp-$app-$round
			order4_ratio=$(cat $dir/thpmaps/thp-$app-$round | grep "anon-thp-pte-aligned-64kB" | awk -F '(' '{print $2}' | sed 's/)//g')
			order4_cont=$(cat $dir/thpmaps/thp-$app-$round | grep "anon-cont-pte-aligned-64kB" | awk -F '(' '{print $2}' | sed 's/)//g')
		else
			order4_ratio=0
			order4_cont=0
		fi
		
		pagefaults=$(cat $dir/simpleperf/simpleperf-"$app"-"$round".txt | grep 'page-faults' | awk '{print $4}')
		itlbmiss=$(cat $dir/simpleperf/simpleperf-"$app"-"$round".txt | grep 'iTLB-load-misses' | awk '{print $4}')
		dtlbmiss=$(cat $dir/simpleperf/simpleperf-"$app"-"$round".txt | grep 'dTLB-load-misses' | awk '{print $4}')
		cpustall=$(cat $dir/simpleperf/simpleperf-"$app"-"$round".txt | grep 'raw-stall-backend-mem' | awk '{print $4}')
		minorfaults=$(cat $dir/simpleperf/simpleperf-"$app"-"$round".txt | grep 'minor-faults' | awk '{print $1}' | sed s/,//)
		majorfaults=$(cat $dir/simpleperf/simpleperf-"$app"-"$round".txt | grep 'major-faults' | awk '{print $1}' | sed s/,//)

		# 计算直接内存回收次数
		nr_init_direct_reclaim=$(cat $dir/system_mem/after_vmstat-$app-$round | grep pgscan_direct_throttle | awk '{print $2}')
		nr_direct_reclaim=$(cat $dir/system_mem/before_vmstat-$app-$round | grep pgscan_direct_throttle | awk '{print $2}')
		nr_inc_direct_reclaim=$((nr_direct_reclaim-nr_init_direct_reclaim))

		echo $round $app $start_type $start_time $rss $pss $pagefaults $minorfaults $majorfaults $itlbmiss $dtlbmiss $cpustall $inc_ratio $inc_total $order4_ratio $order4_cont $nr_inc_direct_reclaim >> $dir/result

		rm tmp.txt
	done
done
