#!/bin/bash # # Copyright 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. DIR_IORAP_COMMON="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" APP_STARTUP_DIR="$DIR_IORAP_COMMON/../app_startup/" source "$APP_STARTUP_DIR/lib/common" IORAPD_DATA_PATH="/data/misc/iorapd" iorapd_start() { verbose_print 'iorapd_start' adb shell start iorapd sleep 1 # TODO: block until logcat prints successfully connecting } iorapd_stop() { verbose_print 'iorapd_stop' adb shell stop iorapd } iorapd_reset() { iorapd_stop iorapd_start } # Enable perfetto tracing. # Subsequent launches of an application will record a perfetto trace protobuf. iorapd_perfetto_enable() { verbose_print 'enable perfetto' adb shell setprop iorapd.perfetto.enable true iorapd_reset # iorapd only reads this flag when initializing } # Disable perfetto tracing. # Subsequent launches of applications will no longer record perfetto trace protobufs. iorapd_perfetto_disable() { verbose_print 'disable perfetto' adb shell setprop iorapd.perfetto.enable false iorapd_reset # iorapd only reads this flag when initializing } # Enable readahead # Subsequent launches of an application will be sped up by iorapd readahead prefetching # (Provided an appropriate compiled trace exists for that application) iorapd_readahead_enable() { if [[ "$(adb shell getprop iorapd.readahead.enable)" == true ]]; then verbose_print 'enable readahead [already enabled]' return 0 fi verbose_print 'enable readahead [reset iorapd]' adb shell setprop iorapd.readahead.enable true iorapd_reset # iorapd only reads this flag when initializing } # Disable readahead # Subsequent launches of an application will be not be sped up by iorapd readahead prefetching. iorapd_readahead_disable() { if [[ "$(adb shell getprop iorapd.readahead.enable)" == false ]]; then verbose_print 'disable readahead [already disabled]' return 0 fi verbose_print 'disable readahead [reset iorapd]' adb shell setprop iorapd.readahead.enable false iorapd_reset # iorapd only reads this flag when initializing } _iorapd_path_to_data_file() { local package="$1" local activity="$2" local suffix="$3" # Match logic of 'AppComponentName' in iorap::compiler C++ code. echo "${IORAPD_DATA_PATH}/${package}%2F${activity}.${suffix}" } iorapd_perfetto_wait_for_app_trace() { local package="$1" local activity="$2" local timeout="$3" local timestamp="$4" local remote_path="$(_iorapd_path_to_data_file "$package" "$activity" "perfetto_trace.pb")" verbose_print "iorapd_perfetto_wait_for_app_trace on file '$remote_path'" # see event_manager.cc local pattern="Perfetto TraceBuffer saved to file: $remote_path" logcat_wait_for_pattern "$timeout" "$timestamp" "$pattern" } # Purge all perfetto traces for a given application. iorapd_perfetto_purge_app_trace() { local package="$1" local activity="$2" local remote_path="$(_iorapd_path_to_data_file "$package" "$activity" "perfetto_trace.pb")" verbose_print 'iorapd-perfetto: purge app trace in ' "$remote_path" adb shell "[[ -f '$remote_path' ]] && rm -f '$remote_path' || exit 0" } # Pull the remote perfetto trace file into a local file. iorapd_perfetto_pull_trace_file() { local package="$1" local activity="$2" local output_file="$3" # local path local compiled_path="$(_iorapd_path_to_data_file "$package" "$activity" "perfetto_trace.pb")" if ! adb shell "[[ -f '$compiled_path' ]]"; then echo "Error: Remote path '$compiled_path' invalid" >&2 return 1 fi if ! mkdir -p "$(dirname "$output_file")"; then echo "Error: Fail to make output directory for '$output_file'" >&2 return 1 fi verbose_print adb pull "$compiled_path" "$output_file" adb pull "$compiled_path" "$output_file" } # Compile a perfetto trace for a given application. # This requires the app has run at least once with perfetto tracing enabled. iorapd_compiler_for_app_trace() { local package="$1" local activity="$2" local inodes="$3" # local path # remote path calculations local input_path="$(_iorapd_path_to_data_file "$package" "$activity" "perfetto_trace.pb")" local compiled_path="$(_iorapd_path_to_data_file "$package" "$activity" "compiled_trace.tmp.pb")" local compiled_path_final="$(_iorapd_path_to_data_file "$package" "$activity" "compiled_trace.pb")" if ! adb shell "[[ -f '$input_path' ]]"; then echo "Error: Missing perfetto traces; nothing to compile. Expected: '$input_path'" >&2 return 1 fi if ! [[ -f $inodes ]]; then # We could compile using 'diskscan' but it's non-deterministic, so refuse instead. echo "Error: Missing inodes textcache at '$inodes'; refusing to compile." >&2 return 1 fi # inodes file needs to be on the device for iorap.cmd.compiler to access it local remote_inodes=/data/local/tmp/prefetch/inodes.txt adb shell "mkdir -p \"$(dirname "$remote_inodes")\"" || return 1 verbose_print adb push "$inodes" "$remote_inodes" adb push "$inodes" "$remote_inodes" verbose_print 'iorapd-compiler: compile app trace in ' "$input_path" verbose_print adb shell "iorap.cmd.compiler '$input_path' --inode-textcache '$remote_inodes' --output-proto '$compiled_path'" adb shell "iorap.cmd.compiler '$input_path' --inode-textcache '$remote_inodes' --output-proto '$compiled_path'" retcode=$? # Don't overwrite the true 'compiled_trace.pb' unless the compiler completed without error. # TODO: The native compiler code should be handling its own transaction-safety. if [[ $retcode -eq 0 ]]; then adb shell "mv '$compiled_path' '$compiled_path_final'" else adb shell "[[ -f '$compiled_path' ]] && rm -f '$compiled_path'" fi # Clean up inodes file we just pushed. # adb shell "[[ -f '$remote_inodes' ]] && rm -f '$remote_inodes'" return $retcode } # Pull the remote compiled trace file into a local file. iorapd_compiler_pull_trace_file() { local package="$1" local activity="$2" local output_file="$3" # local path local compiled_path="$(_iorapd_path_to_data_file "$package" "$activity" "compiled_trace.pb")" if ! adb shell "[[ -f '$compiled_path' ]]"; then echo "Error: Remote path '$compiled_path' invalid" >&2 return 1 fi if ! mkdir -p "$(dirname "$output_file")"; then echo "Error: Fail to make output directory for '$output_file'" >&2 return 1 fi verbose_print adb pull "$compiled_path" "$output_file" adb pull "$compiled_path" "$output_file" } # Install a compiled trace file. iorapd_compiler_install_trace_file() { local package="$1" local activity="$2" local input_file="$3" # local path # remote path calculations local compiled_path="$(_iorapd_path_to_data_file "$package" "$activity" "compiled_trace.pb")" if ! [[ -f $input_file ]]; then echo "Error: File '$input_file' does not exist." >&2 return 1 fi adb shell "mkdir -p \"$(dirname "$compiled_path")\"" || return 1 verbose_print adb push "$input_file" "$compiled_path" adb push "$input_file" "$compiled_path" } iorapd_compiler_purge_trace_file() { local package="$1" local activity="$2" local input_file="$3" # local path local remote_path="$(_iorapd_path_to_data_file "$package" "$activity" "compiled_trace.pb")" adb shell "[[ -f '$remote_path' ]] && rm -f '$remote_path' || exit 0" } # Blocks until the readahead for the requested package/activity has finished. # This assumes that the trace file was already installed, and also that # the application launched but not completed yet. iorapd_readahead_wait_until_finished() { local package="$1" local activity="$2" local timestamp="$3" local timeout="$4" if [[ $# -lt 4 ]]; then echo "FATAL: Expected 4 arguments (actual $# $@)" >&2 exit 1 fi local remote_path="$(_iorapd_path_to_data_file "$package" "$activity" "compiled_trace.pb")" # See 'read_ahead.cc' LOG(INFO). local pattern="Description = $remote_path" logcat_wait_for_pattern "$timeout" "$timestamp" "$pattern" }