# Script to start a set of apps in order and then in each iteration
# switch the focus to each one. For each iteration, the time to start
# the app is reported as measured using atrace events and via am ThisTime.
# The output also reports if applications are restarted (eg, killed by
# LMK since previous iteration) or if there were any direct reclaim
# events.
#
# Variation: the "-T" option skips all of the atrace instramentation and
# attempts to start the apps as quickly as possible.
#
# Example 1: start all default apps. 2 iterations
#
# ./systemapps.sh -i 2
#
# Example 2: just start chrome, feedly, and the home screen in a loop
#
# ./systemapps.sh -L "chrome feedly home" -i 5
#
# Example 3: just start the default apps as quickly as possible
#
# ./systemapps.sh -T
#
# Other options are described below.
#
iterations=1
tracecategories="gfx am memreclaim"
totaltimetest=0
forcecoldstart=0
waitTime=3.0
memstats=0

appList="gmail maps chrome youtube play home"

function processLocalOption {
	ret=0
	case "$1" in
	(-A) unset appList;;
	(-F) forcecoldstart=1;;
	(-L) appList=$2; shift; ret=1;;
	(-T) totaltimetest=1;;
	(-W) waitTime=$2; shift; ret=1;;
	(-M) memstats=1;;
	(*)
		echo "$0: unrecognized option: $1"
		echo; echo "Usage: $0 [options]"
		echo "-A : use all known applications"
		echo "-F : force cold-start for all apps"
		echo "-L applist : list of applications"
		echo "   default: $appList"
		echo "-T : total time to start all apps"
		echo "-W : time to wait between apps"
		echo "-g : generate activity strings"
		echo "-i iterations"
		echo "-n : keep trace files"
		echo "-o output file"
		echo "-s : stop on error"
		echo "-t trace categories"
		exit 1;;
	esac
	return $ret
}

CMDDIR=$(dirname $0 2>/dev/null)
CMDDIR=${CMDDIR:=.}
. $CMDDIR/defs.sh

tmpTraceOutBase=./tmptrace

if [ $user !=  "root" -a $totaltimetest -eq 0 ]; then
	handleError Must be root on device
	exit 1
fi
doKeyevent HOME

function computeStats {
	label=$1
	t=$2
	restart=$3
	reclaim=$4
	frames=$5
	janks=$6
	l90=$7
	l95=$8
	l99=$9
	curMax=$(eval "echo \$${label}max")
	curMax=${curMax:=0}
	curMin=$(eval "echo \$${label}min")
	curMin=${curMin:=100000}
	curSum=$(eval "echo \$${label}sum")
	curSum=${curSum:=0}
	curRestart=$(eval "echo \$${label}restart")
	curRestart=${curRestart:=0}
	curReclaim=$(eval "echo \$${label}reclaim")
	curReclaim=${curReclaim:=0}
	curFrames=$(eval "echo \$${label}frames")
	curFrames=${curFrames:=0}
	curJanks=$(eval "echo \$${label}janks")
	curJanks=${curJanks:=0}
	cur90=$(eval "echo \$${label}90")
	cur90=${cur90:=0}
	cur95=$(eval "echo \$${label}95")
	cur95=${cur95:=0}
	cur99=$(eval "echo \$${label}99")
	cur99=${cur99:=0}
	if [ $curMax -lt $t ]; then
		eval "${label}max=$t"
	fi
	if [ $curMin -gt $t ]; then
		eval "${label}min=$t"
	fi
	((curSum=curSum+t))
	eval "${label}sum=$curSum"

	((curRestart=curRestart+${restart:=0}))
	eval "${label}restart=$curRestart"
	((curReclaim=curReclaim+${reclaim:=0}))
	eval "${label}reclaim=$curReclaim"
	((curFrames=curFrames+${frames:=0}))
	eval "${label}frames=$curFrames"
	((curJanks=curJanks+${janks:=0}))
	eval "${label}janks=$curJanks"
	((cur90=cur90+${l90:=0}))
	eval "${label}90=$cur90"
	((cur95=cur95+${l95:=0}))
	eval "${label}95=$cur95"
	((cur99=cur99+${l99:=0}))
	eval "${label}99=$cur99"
}
function getStats {
	label=$1
	echo $(eval "echo \$${label}max") $(eval "echo \$${label}min") $(eval "echo \$${label}sum") \
		$(eval "echo \$${label}restart") $(eval "echo \$${label}reclaim") \
		$(eval "echo \$${label}frames") $(eval "echo \$${label}janks") \
		$(eval "echo \$${label}90") $(eval "echo \$${label}95") $(eval "echo \$${label}99")
}

cur=1
totaltime=0
startTimestamp=$(date +"%s %N")

while [ $cur -le $iterations ]
do
	if [ $iterations -gt 1 ]; then
		echo =========================================
		echo Iteration $cur of $iterations
		date
		echo =========================================
	fi
	if [ $iterations -gt 1 -o $cur -eq 1 ]; then
		if [ $totaltimetest -eq 0 ]; then
			printf "%-6s    %7s(ms)  %6s(ms) %s %s %s     %s\n" App  Time AmTime Restart DirReclaim Jank Latency
		fi
	fi

	appnum=-1
	for app in $appList
	do
		vout Starting $app...
		((appnum=appnum+1))
		loopTimestamp=$(date +"%s %N")
		resetJankyFrames
		resetJankyFrames $(getPackageName $app)
		if [ $totaltimetest -eq 0 ]; then
			tmpTraceOut="$tmpTraceOutBase-$app.out"
			>$tmpTraceOut
			startInstramentation "$app-$cur"
		else
			if [ "$memstats" -gt 0 ]; then
				startInstramentation "$app-$cur" 0
			fi
			if [ $appnum -eq 0 ]; then
				printf "%-8s %5s(ms) %3s(ms) %s      %s\n" App Start Iter Jank Latency
			fi
		fi
		if [ $forcecoldstart -eq 0 ]; then
			t=$(startActivity $app)
		else
			t=$(forceStartActivity $app)
		fi

		# let app finish drawing before checking janks
		sleep $waitTime
		set -- $(getJankyFrames $(getPackageName $app))
		frames=$1
		janks=$2
		l90=$3
		l95=$4
		l99=$5
		set -- $(getJankyFrames)
		systemFrames=$1
		systemJanks=$2
		s90=$3
		s95=$4
		s99=$5
		((frames=frames+systemFrames))
		((janks=janks+systemJanks))
		((l90=l90+s90))
		((l95=l95+s95))
		((l99=l99+s99))

		loopEndTimestamp=$(date +"%s %N")
		diffTime=$(computeTimeDiff $loopTimestamp $loopEndTimestamp)

		if [ $frames -eq 0 ]; then
			janks=0
			jankPct=0
		else
			((jankPct=100*janks/frames))
		fi
		if [ $totaltimetest -gt 0 ]; then
			# Note: using %f since %d doesn't work correctly
			# when running on lollipop
			printf "%-10s %5.0f   %5.0f    %4.0f(%2.0f%%) %2.0f/%2.0f/%2.0f\n" $app $t $diffTime $janks $jankPct $l90 $l95 $l99
			((totaltime=totaltime+t))
			continue
		else
			stopAndDumpInstramentation $tmpTraceOut
			actName=$(getActivityName $app)
			pkgName=$(getPackageName $app)
			stime=$(getStartTime $actName $tmpTraceOut)
			relaunch=$?
			etime=$(getEndTime $pkgName $tmpTraceOut)
			((tdiff=$etime-$stime))
			if [ $etime -eq 0 -o $stime -eq 0 ]; then
				handleError $app : could not compute start time stime=$stime  etime=$etime
				# use AmTime so statistics make sense
				tdiff=$t
			fi
			checkForDirectReclaim $actName $tmpTraceOut
			directReclaim=$?

			printf "%-12s %5d     %5d     %5d    %5d    %5d(%d%%) %d/%d/%d\n" "$app" "$tdiff" "$t" "$relaunch" "$directReclaim" "$janks" "$jankPct" $l90 $l95 $l99
			computeStats "$app" "$tdiff" "$relaunch" "$directReclaim" "$frames" "$janks" $l90 $l95 $l99

			if [ $savetmpfiles -eq 0 ]; then
				rm -f $tmpTraceOut
			fi
		fi
	done
	((cur=cur+1))
done
endTimestamp=$(date +"%s %N")
diffTime=$(computeTimeDiff $startTimestamp $endTimestamp)
if [ $totaltimetest -gt 0 ]; then
	printf "%-10s %5.0f   %5.0f\n" TOTAL $totaltime $diffTime
fi

overallSum=0
appCount=0
if [ $iterations -gt 1 -a $totaltimetest -eq 0 ]; then
	echo
	echo =========================================
	printf "Stats after $iterations iterations:\n"
	echo =========================================
	printf "%-6s    %7s(ms) %6s(ms) %6s(ms)    %s    %s %s     %s\n" App Max Ave Min Restart DirReclaim Jank Latency
	for app in $appList
	do
		set -- $(getStats $app)
		sum=$3
		((ave=sum/iterations))
		frames=$6
		janks=$7
		l90=$8
		l95=$9
		l99=${10}
		((ave90=l90/iterations))
		((ave95=l95/iterations))
		((ave99=l99/iterations))
		if [ $frames -gt 0 ]; then
			((jankPct=100*janks/frames))
		fi
		printf "%-12s %5d      %5d      %5d      %5d      %5d     %5d(%d%%) %d/%d/%d\n" $app $1 $ave $2 $4 $5 $janks $jankPct $ave90 $ave95 $ave99
		((overallSum=overallSum+ave))
		((appCount=appCount+1))
	done
	if [ $appCount -gt 0 ]; then
		printf "Average Start Time: %.2f\n", $(echo $overallSum $appCount | awk '{ printf "%.2f\n", $1/$2 }')
	fi
fi
