Index: tools-webrtc/android/profiling/perf_setup.sh |
diff --git a/tools-webrtc/android/profiling/perf_setup.sh b/tools-webrtc/android/profiling/perf_setup.sh |
deleted file mode 100755 |
index 810c4860896c55a8f12922edc6ccbbff95eceb31..0000000000000000000000000000000000000000 |
--- a/tools-webrtc/android/profiling/perf_setup.sh |
+++ /dev/null |
@@ -1,470 +0,0 @@ |
-#!/bin/bash |
- |
-# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
-# |
-# Use of this source code is governed by a BSD-style license |
-# that can be found in the LICENSE file in the root of the source |
-# tree. An additional intellectual property rights grant can be found |
-# in the file PATENTS. All contributing project authors may |
-# be found in the AUTHORS file in the root of the source tree. |
-# |
-# Usage: |
-# |
-# It is assumed that a release build of AppRTCMobile exists and has been |
-# installed on an Android device which supports USB debugging. |
-# |
-# Source this script once from the WebRTC src/ directory and resolve any |
-# reported issues. Add relative path to build directory as parameter. |
-# Required tools will be downloaded if they don't already exist. |
-# |
-# Once all tests are passed, a list of available functions will be given. |
-# Use these functions to do the actual profiling and visualization of the |
-# results. |
-# |
-# Note that, using a rooted device is recommended since it allows us to |
-# resolve kernel symbols (kallsyms) as well. |
-# |
-# Example usage: |
-# |
-# > . tools-webrtc/android/profiling/perf_setup.sh out/Release |
-# > perf_record 120 |
-# > flame_graph |
-# > plot_flame_graph |
-# > perf_cleanup |
- |
-if [ -n "$ZSH_VERSION" ]; then |
- # Running inside zsh. |
- SCRIPT_PATH="${(%):-%N}" |
-else |
- # Running inside something else (most likely bash). |
- SCRIPT_PATH="${BASH_SOURCE[0]}" |
-fi |
-SCRIPT_DIR="$(cd $(dirname "$SCRIPT_PATH") && pwd -P)" |
-source "${SCRIPT_DIR}/utilities.sh" |
- |
-# Root directory for local symbol cache. |
-SYMBOL_DIR="${TMPDIR:-/tmp}/android_symbols" |
-# Used as a temporary folder on the Android device for data storage. |
-DEV_TMP_DIR="/data/local/tmp" |
-# Relative path to native shared library containing symbols. |
-NATIVE_LIB_PATH="/lib.unstripped/libjingle_peerconnection_so.so" |
-# Name of application package for the AppRTCMobile demo. |
-APP_NAME="org.appspot.apprtc" |
- |
-# Make sure we're being sourced. |
-if [[ -n "${BASH_VERSION}" && "${BASH_SOURCE:-$0}" == "$0" ]]; then |
- error "perf_setup must be sourced" |
- exit 1 |
-fi |
- |
-function usage() { |
- printf "usage: . perf_setup.sh <build_dir>\n" |
-} |
- |
-# Ensure that user includes name of build directory (e.g. out/Release) as |
-# input parameter. Store path in BUILD_DIR. |
-if [[ "$#" -eq 1 ]]; then |
- if is_not_dir "$1"; then |
- error "$1 is invalid" |
- return 1 |
- fi |
- BUILD_DIR="$1" |
-else |
- error "Missing required parameter". |
- usage |
- return 1 |
-fi |
- |
-# Full (relative) path to the libjingle_peerconnection_so.so file. |
-function native_shared_lib_path() { |
- echo "${BUILD_DIR}${NATIVE_LIB_PATH}" |
-} |
- |
-# Target CPU architecture for the native shared library. |
-# Example: AArch64. |
-function native_shared_lib_arch() { |
- readelf -h $(native_shared_lib_path) | grep Machine | awk '{print $2}' |
-} |
- |
-# Returns true if the device architecture and the build target are the same. |
-function arch_is_ok() { |
- if [[ "$(dev_arch)" == "aarch64" ]] \ |
- && [[ "$(native_shared_lib_arch)" == "AArch64" ]]; then |
- return 0 |
- elif [[ "$(dev_arch)" == "aarch32" ]] \ |
- && [[ "$(native_shared_lib_arch)" == "AArch32" ]]; then |
- return 0 |
- else |
- return 1 |
- fi |
-} |
- |
-# Copies the native shared library from the local host to the symbol cache |
-# which is used by simpleperf as base when searching for symbols. |
-function copy_native_shared_library_to_symbol_cache() { |
- local arm_lib="arm" |
- if [[ "$(native_shared_lib_arch)" == "AArch64" ]]; then |
- arm_lib="arm64" |
- fi |
- for num in 1 2; do |
- local dir="${SYMBOL_DIR}/data/app/${APP_NAME}-${num}/lib/${arm_lib}" |
- mkdir -p "${dir}" |
- cp -u $(native_shared_lib_path) "${dir}" |
- done |
-} |
- |
-# Copy kernel symbols from device to symbol cache in tmp. |
-function copy_kernel_symbols_from_device_to_symbol_cache() { |
- local symbol_cache="${SYMBOL_DIR}/kallsyms" |
- adb pull /proc/kallsyms "${symbol_cache}" |
-} 1> /dev/null |
- |
-# Download the correct version of 'simpleperf' to $DEV_TMP_DIR |
-# on the device and enable profiling. |
-function copy_simpleperf_to_device() { |
- local perf_binary |
- [[ $(dev_arch) == "aarch64" ]] \ |
- && perf_binary="/arm64/simpleperf" \ |
- || perf_binary="/arm/simpleperf" |
- # Copy the simpleperf binary from local host to temp folder on device. |
- adb push "${SCRIPT_DIR}/simpleperf/bin/android${perf_binary}" \ |
- "${DEV_TMP_DIR}" 1> /dev/null |
- # Copy simpleperf from temp folder to the application package. |
- adb shell run-as "${APP_NAME}" cp "${DEV_TMP_DIR}/simpleperf" . |
- adb shell run-as "${APP_NAME}" chmod a+x simpleperf |
- # Enable profiling on the device. |
- enable_profiling |
- # Allows usage of running report commands on the device. |
- if image_is_root; then |
- enable_report_symbols |
- fi |
-} |
- |
-# Copy the recorded 'perf.data' file from the device to the current directory. |
-# TODO(henrika): add support for specifying the destination. |
-function pull_perf_data_from_device() { |
- adb shell run-as "${APP_NAME}" cp perf.data /sdcard/perf.data |
- adb pull sdcard/perf.data . |
-} 1> /dev/null |
- |
- |
-# Wraps calls to simpleperf report. Used by e.g. perf_report_threads. |
-# A valid profile input file must exist in the current folder. |
-# TODO(henrika): possibly add support to add path to alternative input file. |
-function perf_report() { |
- local perf_data="perf.data" |
- is_file "${perf_data}" \ |
- && simpleperf report \ |
- -n \ |
- -i "${perf_data}" \ |
- "$@" \ |
- || error "$(pwd)/${perf_data} is invalid" |
-} |
- |
-# Removes the folder specified as input parameter. Mainly intended for removal |
-# of simpleperf and Flame Graph tools. |
-function remove_tool() { |
- local tool_dir="$1" |
- if is_dir "${tool_dir}"; then |
- echo "Removing ${tool_dir}..." |
- rm -rf "${tool_dir}" |
- path_remove "${tool_dir}" |
- fi |
-} |
- |
-# Utility method which deletes the downloaded simpleperf tool from the repo. |
-# It also removes the simpleperf root folder from PATH. |
-function rm_simpleperf() { |
- remove_tool "${SCRIPT_DIR}/simpleperf" |
-} |
- |
-# Utility method which deletes the downloaded Flame Graph tool from the repo. |
-# It also removes the Flame Graph root folder from PATH. |
-function rm_flame_graph() { |
- remove_tool "${SCRIPT_DIR}/flamegraph" |
-} |
- |
-# Lists the main available functions after sourcing this script. |
-function print_function_help() { |
- printf "\nAvailable functions in this shell:\n" |
- printf " perf_record [duration, default=60sec]\n" |
- printf " perf_report_threads\n" |
- printf " perf_report_bins\n" |
- printf " perf_report_symbols\n" |
- printf " perf_report_graph\n" |
- printf " perf_report_graph_callee\n" |
- printf " perf_update\n" |
- printf " perf_cleanup\n" |
- printf " flame_graph\n" |
- printf " plot_flame_graph\n" |
-} |
- |
-function cleanup() { |
- unset -f main |
-} |
- |
-# ----------------------------------------------------------------------------- |
-# Main methods to be used after sourcing the main script. |
-# ----------------------------------------------------------------------------- |
- |
-# Call this method after the application as been rebuilt and installed on the |
-# device to ensure that symbols are up-to-date. |
-function perf_update() { |
- copy_native_shared_library_to_symbol_cache |
- if image_is_root; then |
- copy_kernel_symbols_from_device_to_symbol_cache |
- fi |
-} |
- |
-# Record stack frame based call graphs while using the application. |
-# We use default events (cpu-cycles), and write records to 'perf.data' in the |
-# tmp folder on the device. Default duration is 60 seconds but it can be changed |
-# by adding one parameter. As soon as the recording is done, 'perf.data' is |
-# copied to the directory from which this method is called and a summary of |
-# the load distribution per thread is printed. |
-function perf_record() { |
- if app_is_running "${APP_NAME}"; then |
- # Ensure that the latest native shared library exists in the local cache. |
- copy_native_shared_library_to_symbol_cache |
- local duration=60 |
- if [ "$#" -eq 1 ]; then |
- duration="$1" |
- fi |
- local pid=$(find_app_pid "${APP_NAME}") |
- echo "Profiling PID $pid for $duration seconds (media must be is active)..." |
- adb shell run-as "${APP_NAME}" ./simpleperf record \ |
- --call-graph fp \ |
- -p "${pid}" \ |
- -f 1000 \ |
- --duration "${duration}" \ |
- --log error |
- # Copy profile results from device to current directory. |
- pull_perf_data_from_device |
- # Print out a summary report (load per thread). |
- perf_report_threads | tail -n +6 |
- else |
- # AppRTCMobile was not enabled. Start it up automatically and ask the user |
- # to start media and then call this method again. |
- warning "AppRTCMobile must be active" |
- app_start "${APP_NAME}" |
- echo "Start media and then call perf_record again..." |
- fi |
-} |
- |
-# Analyze the profile report and show samples per threads. |
-function perf_report_threads() { |
- perf_report --sort comm |
-} 2> /dev/null |
- |
-# Analyze the profile report and show samples per binary. |
-function perf_report_bins() { |
- perf_report --sort dso |
-} 2> /dev/null |
- |
-# Analyze the profile report and show samples per symbol. |
-function perf_report_symbols() { |
- perf_report --sort symbol --symfs "${SYMBOL_DIR}" |
-} |
- |
-# Print call graph showing how functions call others. |
-function perf_report_graph() { |
- perf_report -g caller --symfs "${SYMBOL_DIR}" |
-} |
- |
-# Print call graph showing how functions are called from others. |
-function perf_report_graph_callee() { |
- perf_report -g callee --symfs "${SYMBOL_DIR}" |
-} |
- |
-# Plots the default Flame Graph file if no parameter is provided. |
-# If a parameter is given, it will be used as file name instead of the default. |
-function plot_flame_graph() { |
- local file_name="flame_graph.svg" |
- if [[ "$#" -eq 1 ]]; then |
- file_name="$1" |
- fi |
- # Open up the SVG file in Chrome. Try unstable first and revert to stable |
- # if unstable fails. |
- google-chrome-unstable "${file_name}" \ |
- || google-chrome-stable "${file_name}" \ |
- || error "failed to find any Chrome instance" |
-} 2> /dev/null |
- |
-# Generate Flame Graph in interactive SVG format. |
-# First input parameter corresponds to output file name and second input |
-# parameter is the heading of the plot. |
-# Defaults will be utilized if parameters are not provided. |
-# See https://github.com/brendangregg/FlameGraph for details on Flame Graph. |
-function flame_graph() { |
- local perf_data="perf.data" |
- if is_not_file $perf_data; then |
- error "$(pwd)/${perf_data} is invalid" |
- return 1 |
- fi |
- local file_name="flame_graph.svg" |
- local title="WebRTC Flame Graph" |
- if [[ "$#" -eq 1 ]]; then |
- file_name="$1" |
- fi |
- if [[ "$#" -eq 2 ]]; then |
- file_name="$1" |
- title="$2" |
- fi |
- if image_is_not_root; then |
- report_sample.py \ |
- --symfs "${SYMBOL_DIR}" \ |
- perf.data >out.perf |
- else |
- report_sample.py \ |
- --symfs "${SYMBOL_DIR}" \ |
- --kallsyms "${SYMBOL_DIR}/kallsyms" \ |
- perf.data >out.perf |
- fi |
- stackcollapse-perf.pl out.perf >out.folded |
- flamegraph.pl --title="${title}" out.folded >"${file_name}" |
- rm out.perf |
- rm out.folded |
-} |
- |
-# Remove all downloaded third-party tools. |
-function perf_cleanup () { |
- rm_simpleperf |
- rm_flame_graph |
-} |
- |
-main() { |
- printf "%s\n" "Preparing profiling of AppRTCMobile on Android:" |
- # Verify that this script is called from the root folder of WebRTC, |
- # i.e., the src folder one step below where the .gclient file exists. |
- local -r project_root_dir=$(pwd) |
- local dir=${project_root_dir##*/} |
- if [[ "${dir}" != "src" ]]; then |
- error "script must be called from the WebRTC project root (src) folder" |
- return 1 |
- fi |
- ok "project root: ${project_root_dir}" |
- |
- # Verify that user has sourced envsetup.sh. |
- # TODO(henrika): might be possible to remove this check. |
- if [[ -z "$ENVSETUP_GYP_CHROME_SRC" ]]; then |
- error "must source envsetup script first" |
- return 1 |
- fi |
- ok "envsetup script has been sourced" |
- |
- # Given that envsetup is sourced, the adb tool should be accessible but |
- # do one extra check just in case. |
- local adb_full_path=$(which adb); |
- if [[ ! -x "${adb_full_path}" ]]; then |
- error "unable to find the Android Debug Bridge (adb) tool" |
- return 1 |
- fi |
- ok "adb tool is working" |
- |
- # Exactly one Android device must be connected. |
- if ! one_device_connected; then |
- error "one device must be connected" |
- return 1 |
- fi |
- ok "one device is connected via USB" |
- |
- # Restart adb with root permissions if needed. |
- if image_is_root && adb_has_no_root_permissions; then |
- adb root |
- ok "adb is running as root" |
- fi |
- |
- # Create an empty symbol cache in the tmp folder. |
- # TODO(henrika): it might not be required to start from a clean cache. |
- is_dir "${SYMBOL_DIR}" && rm -rf "${SYMBOL_DIR}" |
- mkdir "${SYMBOL_DIR}" \ |
- && ok "empty symbol cache created at ${SYMBOL_DIR}" \ |
- || error "failed to create symbol cache" |
- |
- # Ensure that path to the native library with symbols is valid. |
- local native_lib=$(native_shared_lib_path) |
- if is_not_file ${native_lib}; then |
- error "${native_lib} is not a valid file" |
- return 1 |
- fi |
- ok "native library: "${native_lib}"" |
- |
- # Verify that the architechture of the device matches the architecture |
- # of the native library. |
- if ! arch_is_ok; then |
- error "device is $(dev_arch) and lib is $(native_shared_lib_arch)" |
- return 1 |
- fi |
- ok "device is $(dev_arch) and lib is $(native_shared_lib_arch)" |
- |
- # Copy native shared library to symbol cache after creating an |
- # application specific tree structure under ${SYMBOL_DIR}/data. |
- copy_native_shared_library_to_symbol_cache |
- ok "native library copied to ${SYMBOL_DIR}/data/app/${APP_NAME}" |
- |
- # Verify that the application is installed on the device. |
- if ! app_is_installed "${APP_NAME}"; then |
- error "${APP_NAME} is not installed on the device" |
- return 1 |
- fi |
- ok "${APP_NAME} is installed on the device" |
- |
- # Download simpleperf to <src>/tools-webrtc/android/profiling/simpleperf/. |
- # Cloning will only take place if the target does not already exist. |
- # The PATH variable will also be updated. |
- # TODO(henrika): would it be better to use a target outside the WebRTC repo? |
- local simpleperf_dir="${SCRIPT_DIR}/simpleperf" |
- if is_not_dir "${simpleperf_dir}"; then |
- echo "Dowloading simpleperf..." |
- git clone https://android.googlesource.com/platform/prebuilts/simpleperf \ |
- "${simpleperf_dir}" |
- chmod u+x "${simpleperf_dir}/report_sample.py" |
- fi |
- path_add "${simpleperf_dir}" |
- ok "${simpleperf_dir}" is added to PATH |
- |
- # Update the PATH variable with the path to the Linux version of simpleperf. |
- local simpleperf_linux_dir="${SCRIPT_DIR}/simpleperf/bin/linux/x86_64/" |
- if is_not_dir "${simpleperf_linux_dir}"; then |
- error "${simpleperf_linux_dir} is invalid" |
- return 1 |
- fi |
- path_add "${simpleperf_linux_dir}" |
- ok "${simpleperf_linux_dir}" is added to PATH |
- |
- # Copy correct version (arm or arm64) of simpleperf to the device |
- # and enable profiling at the same time. |
- if ! copy_simpleperf_to_device; then |
- error "failed to install simpleperf on the device" |
- return 1 |
- fi |
- ok "simpleperf is installed on the device" |
- |
- # Refresh the symbol cache and read kernal symbols from device if not |
- # already done. |
- perf_update |
- ok "symbol cache is updated" |
- |
- # Download Flame Graph to <src>/tools-webrtc/android/profiling/flamegraph/. |
- # Cloning will only take place if the target does not already exist. |
- # The PATH variable will also be updated. |
- # TODO(henrika): would it be better to use a target outside the WebRTC repo? |
- local flamegraph_dir="${SCRIPT_DIR}/flamegraph" |
- if is_not_dir "${flamegraph_dir}"; then |
- echo "Dowloading Flame Graph visualization tool..." |
- git clone https://github.com/brendangregg/FlameGraph.git "${flamegraph_dir}" |
- fi |
- path_add "${flamegraph_dir}" |
- ok "${flamegraph_dir}" is added to PATH |
- |
- print_function_help |
- |
- cleanup |
- |
- return 0 |
-} |
- |
-# Only call main() if proper input parameter has been provided. |
-if is_set $BUILD_DIR; then |
- main "$@" |
-fi |