Commit 62284ba7 authored by Mohamed Heikal's avatar Mohamed Heikal Committed by Commit Bot

Upstreaming dskiba@ startup scripts

dskiba@ wrote some startup scripts to get startup performance metrics via
running chrome locally multiple times and capturing capturing/analyzing trace
events. These work when specific usecases are not implemented as benchmark
stories (eg: WebAPK startup)

Scripts were originally written for personal use so may not be the best quality
but they are useful so should be included in the chromium repo rather than only
on his personal git.

Change-Id: I04e711db61ed26e7f9d531756f6b4699476406d5
Reviewed-on: https://chromium-review.googlesource.com/1168156
Commit-Queue: Mohamed Heikal <mheikal@chromium.org>
Reviewed-by: default avatarYaron Friedman <yfriedman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#584795}
parent 033428c9
mheikal@chromium.org
yfriedman@chromium.org
Tracing related scripts
=======================
This folder contains two tracing related scripts. `profile-chrome-startup.sh` is
a wrapper around build/android/adb_profile_chrome_startup except that it allows
you to run the startup tracing with the same parameters multiple times (plus a
few other things). The output of `profile-chrome-startup.sh` (or
build/android/adb_profile_chrome_startup) can then be processed by
`systrace-extract-startup.py`. `systrace-extract-startup.py` takes a directory
and a name prefix of multiple tracing reports and extracts some events from them
and then print it out as a tab separated table for you to copy and paste into
sheets for further numerical analysys. Both of these scripts together allow you
to run startup tracing on a device multiple times, extract the startup trace
events you are tracking from all the trace files and output it in an easy way
for you to perform numerical analysis on the results.
profile-chrome-startup.sh
-------------------------
Some useful things that the script does:
- Numbers traces from repeated invocations. I.e. you can invoke
profile-chrome-startup.sh foo/bar 10 times, which would produce
foo/bar-10s.html, foo/bar-10s~1.html, foo/bar-10s~2.html …
foo/bar-10s~9.html. Note that default duration (10s) is appended to the path,
same is true for most other options.
- Captures logcat of the tracing duration, and greps for processes started /
killed. I added this option in early days, when Chrome was causing startup of
various GMS processes, which was severely affecting startup time (especially
on 512MiB). It's a good idea to keep an eye on "Processes started / died"
section of the script output. Generally you should see only browser/renderer
there. There might be some unrelated processes, but if you reliably see a
processes being started with Chrome, that's a problem. (There is also --killg
option, which causes the script to kill some GMS processes, but I'm not sure
if it's relevant anymore).
- Automatically grants READ_EXTERNAL_STORAGE / WRITE_EXTERNAL_STORAGE permissions.
- Parses resulting trace file and extracts various startup timings (see below).
- Has --repeat=N option, which causes script to do N measurements, and
Only the output_tag is required all other arguments would be set to reasonable
defaults.
```
usage: profile-chrome-startup.sh <output_tag> [arguments]
arguments:
output_tag
this is the directory+filename prefix for all the trace output starting from
the current working directory. eg: w/android_go_512/with_patch
--browser=BROWSER
one of canary, dev, beta, stable or chrome (default). chrome refers to clankium
--url=URL
start chrome with URL
--cold
cold start chrome ie. drop page caches
--warm
(default) the opposite of cold
--atrace=category1,category2
enable only these categories for tracing
--killg
kills gapps and gms processes before starting tracing
--trace-time=N
trace for the first N seconds (default 10)
--repeat=N
repeat the tracing N times
--analyze
instead of tracing analyse the trace files (and meminfo files if applicable)
of all trace runs with output_tag
--meminfo
runs dumpsys meminfo on the device before and after each trace
--print-trace-events=EVENTS
which events to extract from the tracefile to display
--webapk=PACKAGE_NAME
the WebAPK package name for WebAPK startup tracing
```
systrace-extract-startup.py
---------------------------
```
usage: systrace-extract-startup.py [-h] [--print-none-histograms]
[--print-events PRINT_EVENTS]
[--experimental] [--report] [--csv]
file_or_glob
positional arguments:
file_or_glob
optional arguments:
-h, --help show this help message and exit
--print-none-histograms
Print histograms with None values.
--print-events PRINT_EVENTS
Print events matching the specified regex.
--experimental Enable experimental stuff.
--report Present information as a tab-separated table.
--csv Separate report values by commas (not tabs).
```
#!/bin/bash
# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
set -e
shopt -s nullglob
shopt -s extglob
function kill_process() {
name=$1
pid=$($adb shell "pidof $name" || true)
if [ ! -z "$pid" ]; then
echo "Killing $name..."
$adb shell "kill $pid"
else
echo "$name is not running."
fi
}
function get_data_file() {
trace_file=$1
extension=$2
echo "${trace_file%.*}.$extension"
}
function get_logcat_file() {
trace_file=$1
get_data_file "$trace_file" "logcat"
}
function get_meminfo_file() {
trace_file=$1
tag=$2
get_data_file "$trace_file" "$tag.meminfo"
}
function analyze_trace_file() {
trace_file=$1
trace_events_to_print=$2
logcat_file="$(get_logcat_file "$trace_file")"
echo "Processes started / died:"
grep -E "Start proc|died|MY-DBG" "$logcat_file"
extractor_arguments="$trace_file"
if [ ! -z "$trace_events_to_print" ]; then
extractor_arguments="$extractor_arguments --print-events=$trace_events_to_print"
fi
"$this_path/systrace-extract-startup.py" $extractor_arguments
}
function analyze_meminfo_file() {
meminfo_file=$1
if [ -f "$meminfo_file" ]; then
echo "$meminfo_file"
grep -A 5 "Total RAM" "$meminfo_file"
fi
}
function capture_analyze_meminfo_file() {
meminfo_file=$1
$adb shell "dumpsys meminfo" > "$meminfo_file"
analyze_meminfo_file "$meminfo_file"
}
function echo_separator() {
s="----------"
echo
echo "$s$s$s$s$s$s$s$s" # 8*10
}
this_path="$(dirname "$0")"
adb="$ADB_PATH"
if [ -z "$adb" ]; then
adb="$(which adb)"
fi
if [ -z "$adb" ]; then
echo "Where's adb? Can't find it."
exit 1
fi
export ADB_PATH="$adb"
output_tag=
browser=chrome
trace_time=10
cold=false
url=
atrace_categories=
killg=false
repeat=
analyze=false
meminfo=false
checktabs=false
taburl=
trace_events_to_print=
webapk_package=
for i in "$@"; do
case $i in
--help)
echo "$(basename "$0") output-tag [options]"
exit 0
;;
--browser=*)
browser="${i#*=}"
;;
--url=*)
url="${i#*=}"
;;
--warm)
cold=false
;;
--cold)
cold=true
;;
--atrace=*)
atrace_categories="${i#*=}"
;;
--killg)
killg=true
;;
--trace-time=*)
trace_time="${i#*=}"
;;
--repeat=*)
repeat="${i#*=}"
;;
--analyze)
analyze=true
;;
--meminfo)
meminfo=true
;;
--checktabs)
checktabs=true
;;
--taburl=*)
taburl="${i#*=}"
;;
--print-trace-events=*)
trace_events_to_print="${i#*=}"
;;
--webapk=*)
webapk_package="${i#*=}"
;;
--*)
echo "Unknown option or missing option argument: $i"
exit 1
;;
*)
if [ -z "$output_tag" ]; then
output_tag="$i"
else
echo "Unknown option: $i"
exit 1
fi
;;
esac
if [ -z "$output_tag" ]; then
echo "First argument must be the output tag."
exit 1
fi
shift
done
if [ -d "$output_tag" ]; then
output_tag="${output_tag%%+(/)}/trace"
fi
specified_output_tag="$output_tag"
if [ $analyze = true ]; then
for file in $output_tag*.html; do
echo_separator
echo "$file"
analyze_meminfo_file "$(get_meminfo_file "$output_file" "before")"
analyze_meminfo_file "$(get_meminfo_file "$output_file" "after")"
echo
analyze_trace_file "$file" "$print_trace_events"
done
exit 0
fi
browser_package=
case $browser in
chrome)
browser_package="com.google.android.apps.chrome"
;;
canary)
browser_package="com.chrome.canary"
browser="chrome_canary"
;;
dev)
browser_package="com.chrome.dev"
;;
beta)
browser_package="com.chrome.beta"
;;
stable)
browser_package="com.android.chrome"
;;
*)
echo "Unknown browser $browser"
exit 1
esac
profile_options=
profile_options="$profile_options --browser=$browser"
if [ ! "$browser" = "chrome" ]; then
output_tag="$output_tag-$browser"
fi
profile_options="$profile_options --time=$trace_time"
if [ ! -z "$atrace_categories" ]; then
profile_options="$profile_options --atrace-categories=$atrace_categories"
output_tag="$output_tag-${atrace_categories//,/_}"
fi
if [ $cold = true ]; then
profile_options="$profile_options --cold"
output_tag="$output_tag-cold"
fi
profile_options="$profile_options --url=$url"
if [ ! -z "$url" ]; then
output_tag="$output_tag-url"
fi
if [ ! -z "$webapk_package" ]; then
output_tag="$output_tag-webapk"
profile_options="$profile_options --webapk-package=$webapk_package"
fi
if [ $killg = true ]; then
output_tag="$output_tag-killg"
fi
# Must be last for ease of globbing.
output_tag="$output_tag-${trace_time}s"
if [ $checktabs = true ] || [ $killg = true ] || [ ! -z "$taburl" ]; then
$adb root > /dev/null
fi
# Make sure Chrome can write the trace file.
$adb shell "pm grant $browser_package android.permission.READ_EXTERNAL_STORAGE"
$adb shell "pm grant $browser_package android.permission.WRITE_EXTERNAL_STORAGE"
if [ ! -z "$taburl" ]; then
echo "Opening $taburl in a single tab..."
$adb shell "am force-stop $browser_package"
$adb shell "rm -f /data/data/$browser_package/app_tabs/0/tab*"
$adb shell "am start -a android.intent.action.VIEW \
-n $browser_package/org.chromium.chrome.browser.ChromeTabbedActivity \
-d $taburl"
sleep 5
$adb shell "am start -a android.intent.action.MAIN -c android.intent.category.HOME"
sleep 1
$adb shell "am force-stop $browser_package"
echo
fi
repeat_count=1
if [ ! -z "$repeat" ]; then
repeat_count="$repeat"
fi
first_iteration=true
for iteration in $(seq "$repeat_count"); do
if [ $first_iteration = true ]; then
first_iteration=false
else
echo_separator
sleep 2
fi
if [ $killg = true ]; then
echo "Preemptively killing g* processes..."
$adb logcat -c
kill_process "com.google.process.gapps"
kill_process "com.google.android.gms"
sleep 1
$adb logcat -d | grep -E "Start proc|died" || true
fi
echo
if [ -z "$repeat" ]; then
output_file="$output_tag.html"
if [ -f "$output_file" ]; then
for i in {2..1000}; do
output_file="$output_tag~$i.html"
if [ ! -f "$output_file" ]; then
break;
fi
done
fi
if [ -f "$output_file" ]; then
echo "Failed to find unoccupied output file. Last was: $output_file"
exit 1
fi
else
output_file="$output_tag~${repeat_count}_$iteration.html"
if [ -f "$output_file" ]; then
echo "Output file already exists: $output_file"
echo "Please add something unique to the tag ($specified_output_tag)."
exit 1
fi
fi
echo "Output file: $output_file"
logcat_file="$(get_logcat_file "$output_file")"
echo "Logcat output file: $logcat_file"
if [ $meminfo = true ]; then
echo
capture_analyze_meminfo_file "$(get_meminfo_file "$output_file" "before")"
fi
echo
echo "Profiling with options: $profile_options"
./build/android/adb_profile_chrome_startup \
$profile_options \
"--output=$output_file"
if [ $meminfo = true ]; then
echo
capture_analyze_meminfo_file "$(get_meminfo_file "$output_file" "after")"
fi
$adb shell "am force-stop $browser_package"
$adb shell "killall logcat" > /dev/null 2>&1 || true
$adb logcat -d > "${logcat_file}"
rm -f chrome-profile-results-*
$adb shell "rm -f /sdcard/Download/chrome-profile-results-*"
echo
analyze_trace_file "$output_file" "$trace_events_to_print"
if [ $checktabs = true ]; then
# Yields empty string when value is -1
active_tab_id="$( \
$adb shell "cat /data/data/$browser_package/shared_prefs/${browser_package}_preferences.xml" \
| sed -n 's/^.*ACTIVE_TAB_ID" value="\([0-9]\{1,3\}\).*$/\1/p')"
# Yields empty string when there is no 'tab' file
tab_id="$( \
$adb shell ls /data/data/$browser_package/app_tabs/0 \
| sed -n 's/tab\([0-9]\{1,3\}\)\s*/\1/p')"
if [ "$active_tab_id" != "$tab_id" ]; then
echo "Tab IDs don't match (active_tab_id=$active_tab_id, tab_id=$tab_id), last result is not reliable."
exit 1
fi
fi
done
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment