| 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
|
|
|