Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Unified Diff: tools-webrtc/android/profiling/perf_setup.sh

Issue 2705063002: Adding support for native profiling of AppRTCMobile (Closed)
Patch Set: nit Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
new file mode 100755
index 0000000000000000000000000000000000000000..735787aca69aae84df1273f293502d0067be5143
--- /dev/null
+++ b/tools-webrtc/android/profiling/perf_setup.sh
@@ -0,0 +1,364 @@
+#!/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 a rooted and attached Android device.
+#
+# Source this script once from the WebRTC source directory and resolve any
+# reported issues. Add relative path to build directory as parameter.
+#
+# Once all tests are passed, a list of available functions will be listed.
+# Use these functions to do the actual profiling and visualization of the
+# results.
+#
+# Example:
+#
+# >> . tools-webrtc/android/profiling/perf_setup.sh out/Release
+# >> perf_record 60
+# >> perf_report_symbols
+#
+# TODO(henrika): add more here for Flame Graph plots...
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
+source "${SCRIPT_DIR}/utilities.sh"
+
+# Root directory for local symbol cache.
+SYMBOL_DIR="${TMPDIR:-/tmp}/android_symbols"
+# Root directory to prebuilt (Android and Linux) versions of simpleperf.
+SIMPLE_PERF_ROOT_DIR="${SCRIPT_DIR}/simpleperf/bin"
+# 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"
+ printf "Example: . perf_setup.sh out/Release\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
+ BUILD_DIR="$1"
+else
+ unset BUILD_DIR
kjellander_webrtc 2017/02/22 14:46:57 Why unset it?
henrika_webrtc 2017/02/22 15:47:11 Long story. But essentially. If I don't do it, we
kjellander_webrtc 2017/02/24 11:02:25 Acknowledged.
+ error "Missing required parameter".
+ usage
+fi
+
+# Helper method to simpify usage of the simpleperf binary on the device.
+function simpleperf_android() {
+ local simpleperf="${DEV_TMP_DIR}/simpleperf"
+ if [ ! -z "$1" ]; then
+ adb shell "${simpleperf}" "$@"
+ else
+ adb shell $simpleperf --help
+ 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 kernal symbols from device to symbol cache in tmp.
+function copy_kernal_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"
+ local simpleperf="${DEV_TMP_DIR}/simpleperf"
+ # Avoid copying to device if simpleperf already exists.
+ if [[ ! $(dev_ls "${simpleperf}") ]]; then
+ adb push "${SIMPLE_PERF_DIR}${perf_binary}" "${DEV_TMP_DIR}"
+ adb shell chmod a+x $simpleperf
+ fi
+ # Enable profiling on the device.
+ enable_profiling
+ # Allows usgage of running report commands on the device.
kjellander_webrtc 2017/02/22 14:46:57 usgage -> usage?
henrika_webrtc 2017/02/22 15:47:11 Done.
+ enable_report_symbols
+}
+
+# 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 pull "${DEV_TMP_DIR}/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!"
+}
+
+# Lists the main available functions after sourcing this script.
+function print_function_help() {
+ printf "\nAvailable functions:\n"
+ printf " perf_record [duration, default=30sec]\n"
+ printf " perf_report_threads\n"
+ printf " perf_report_bins\n"
+ printf " perf_report_symbols\n"
+ printf " perf_update\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
+ copy_kernal_symbols_from_device_to_symbol_cache
+}
+
+# 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 30 seconds but it can be changed
+# by adding one parameter. As soon as the recording is done, 'perf.data' is
+# copied to the directoty from which this method is called.
+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=30
+ 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)..."
+ local output_file="${DEV_TMP_DIR}/perf.data"
+ simpleperf_android record \
+ --call-graph fp \
+ -p "${pid}" \
+ -o $output_file \
+ -f 1000 \
+ --duration "${duration}" \
+ --log error
+ app_stop "${APP_NAME}"
+ # 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 2> /dev/null
+}
+
+# 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}"
+}
+
+# -----------------------------------------------------------------------------
+# TODO(henrika): add comments...
kjellander_webrtc 2017/02/22 14:46:57 Which ones are you referring to? I think it's pret
henrika_webrtc 2017/02/22 15:47:10 Removed.
+# -----------------------------------------------------------------------------
+
+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
kjellander_webrtc 2017/02/22 14:46:57 This sounds like something that might go away. May
henrika_webrtc 2017/02/22 15:47:11 I have not found any other way actually. It works
+ 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"
+
+ # Ensure that the device is rooted.
+ if image_is_not_root; then
+ error "device is not rooted!"
+ return 1
+ fi
+ ok "device is rooted"
+
+ # Restart adb with root permissions if needed.
+ if adb_has_no_root_permissions; then
+ adb root
+ fi
+ ok "adbd is running as root"
+
+ # 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"
+
+ # Ensure that folder for simpleperf executables (Android and Linux) exist
+ # as it should relative to the working directory (source of WebRTC).
+ if is_not_dir "${SIMPLE_PERF_ROOT_DIR}"; then
+ error "${SIMPLE_PERF_ROOT_DIR} is invalid"
+ return 1
+ fi
+ ok "${SIMPLE_PERF_ROOT_DIR} is valid"
+
+ # 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_update "${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 as last step. Now also reading kernal symbols
+ # from device if not already done.
+ perf_update
+ ok "symbol cache is updated"
+
+ print_function_help
+
+ cleanup
+
+ return 0
+}
+
+# Only call main() if proper input parameter has been provided.
+if is_set $BUILD_DIR; then
+ main "$@"
+fi
« no previous file with comments | « no previous file | tools-webrtc/android/profiling/utilities.sh » ('j') | tools-webrtc/android/profiling/utilities.sh » ('J')

Powered by Google App Engine
This is Rietveld 408576698