| #!/bin/bash |
| # |
| # Copyright (C) 2019 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| # Analyze the output from Android Auto app launch test application. |
| |
| # ITERATION_COUNT decides how many times the test is repeated. |
| readonly ITERATION_COUNT=2 |
| # SCALE decides the precision of fractional part in bc. |
| readonly SCALE=9 |
| |
| #################################################### |
| # Calculate arithmetic mean and standard deviation. |
| # Globals: |
| # None |
| # Arguments: |
| # A sequence of numbers |
| # Returns: |
| # Count, average and stddev in space-saparated string |
| #################################################### |
| function calc_stat() { |
| local sum=0 |
| local count=0 |
| local mean=0 |
| local diff_sqrd_sum=0 |
| local stddev=0 |
| |
| # Calculate the mean. |
| for val in "$@"; do |
| sum=$(echo "scale=${SCALE};${sum} + ${val}" | bc) |
| ((count++)) |
| done |
| mean=$(echo "scale=${SCALE};${sum} / ${count}" | bc) |
| |
| # Calculate standard deviation. |
| for val in "$@"; do |
| diff_sqrd_sum=$(echo "scale=${SCALE};${diff_sqrd_sum} + (${mean} - ${val}) ^ 2" | bc) |
| done |
| stddev=$(echo "scale=${SCALE};sqrt(${diff_sqrd_sum} / ${count})" | bc) |
| |
| echo "${count} ${mean} ${stddev}" |
| } |
| |
| #################################################### |
| # Execute app launch performance test. |
| # Globals: |
| # None |
| # Arguments: |
| # Type of app launch, cold or hot |
| # Whether to press home button, boolean |
| # Whether to drop cache, boolean |
| # Whether to kill app, boolean |
| # Outputs: |
| # Writes the analysis result to stdout |
| #################################################### |
| function run_app_launch_test() { |
| local stat= |
| local package_pattern="INSTRUMENTATION_STATUS: $1_startup_([a-z]+(\.[a-z]+)+)=([0-9]+)" |
| local cmd="adb shell am instrument -w -r -e iterations ${ITERATION_COUNT}\ |
| -e listener android.device.collectors.AppStartupListener\ |
| -e class 'android.platform.test.scenario.dial.OpenAppMicrobenchmark,android.platform.test.scenario.googleplay.OpenAppMicrobenchmark,android.platform.test.scenario.maps.OpenAppMicrobenchmark,android.platform.test.scenario.radio.OpenAppMicrobenchmark,android.platform.test.scenario.settings.OpenAppMicrobenchmark'\ |
| -e favor-shell-commands true -e log false -e suite-timeout_msec 36000000\ |
| -e durationMs 30000 -e press-home $2 -e newRunListenerMode true\ |
| -e timeout_msec 300000 -e drop-cache $3 -e kill-app $4 android.platform.test.scenario/androidx.test.runner.AndroidJUnitRunner" |
| # Example output from ${cmd} |
| # |
| # INSTRUMENTATION_STATUS: class=android.platform.test.scenario.maps.OpenAppMicrobenchmark |
| # INSTRUMENTATION_STATUS: current=1 |
| # INSTRUMENTATION_STATUS: id=AndroidJUnitRunner |
| # INSTRUMENTATION_STATUS: numtests=25 |
| # INSTRUMENTATION_STATUS: stream= |
| # android.platform.test.scenario.maps.OpenAppMicrobenchmark: |
| # INSTRUMENTATION_STATUS: test=testOpen |
| # INSTRUMENTATION_STATUS_CODE: 1 |
| # INSTRUMENTATION_STATUS: cold_startup_com.google.android.apps.maps=2286 |
| # INSTRUMENTATION_STATUS: cold_startup_count_com.google.android.apps.maps=1 |
| # INSTRUMENTATION_STATUS: cold_startup_total_count=1 |
| # INSTRUMENTATION_STATUS_CODE: 2 |
| # INSTRUMENTATION_STATUS: class=android.platform.test.scenario.maps.OpenAppMicrobenchmark |
| # INSTRUMENTATION_STATUS: current=1 |
| # INSTRUMENTATION_STATUS: id=AndroidJUnitRunner |
| # INSTRUMENTATION_STATUS: numtests=25 |
| # INSTRUMENTATION_STATUS: stream=. |
| # INSTRUMENTATION_STATUS: test=testOpen |
| # INSTRUMENTATION_STATUS_CODE: 0 |
| |
| declare -A app_launch_map |
| printf "Testing $1 start performance....\n" |
| |
| while IFS= read -r line; do |
| if [[ ${line} =~ ${package_pattern} ]]; then |
| APP_PACKAGE="${BASH_REMATCH[1]}" |
| LAUNCH_TIME=${BASH_REMATCH[3]} |
| app_launch_map[${APP_PACKAGE}]+="${LAUNCH_TIME} " |
| fi |
| done < <(${cmd}) |
| |
| for key in "${!app_launch_map[@]}"; do |
| stat=($(calc_stat ${app_launch_map[${key}]})) |
| printf "[${key}]\n" |
| printf " Count: ${stat[0]}\n" |
| printf " Average: ${stat[1]}\n" |
| printf " StdDev: ${stat[2]}\n" |
| printf "\n" |
| done |
| } |
| |
| # We test two types of app launch performance: cold and hot. |
| # Cold start is to launch an app without cache support as if it is executed for the first time. |
| # Hot start is to make an app go into the foreground while the app is running in the background. |
| run_app_launch_test cold false true true |
| echo "" |
| run_app_launch_test hot true false false |