blob: 75cb9a927eb7af47fd918f3e07b79821a6a81c61 [file] [log] [blame]
#!/bin/sh
#
# Copyright (C) 2017 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.
#
# Note: Requires $ANDROID_BUILD_TOP/build/envsetup.sh to have been run.
#
# This script takes in a logcat containing Sanitizer traces and outputs several
# files, prints information regarding the traces, and plots information as well.
USE_TEMP=true
DO_REDO=false
# EXACT_ARG and MIN_ARG are passed to prune_sanitizer_output.py
EXACT_ARG=""
MIN_ARG=""
usage() {
echo "Usage: $0 [options] [LOGCAT_FILE] [CATEGORIES...]"
echo " -d OUT_DIRECTORY"
echo " Puts all output in specified directory."
echo " If not given, output will be put in a local"
echo " temp folder which will be deleted after"
echo " execution."
echo
echo " -e"
echo " All traces will have exactly the same number"
echo " of categories which is specified by either"
echo " the -m argument or by prune_sanitizer_output.py"
echo
echo " -f"
echo " forces redo of all commands even if output"
echo " files exist. Steps are skipped if their output"
echo " exist already and this is not enabled."
echo
echo " -m [MINIMUM_CALLS_PER_TRACE]"
echo " Filters out all traces that do not have"
echo " at least MINIMUM_CALLS_PER_TRACE lines."
echo " default: specified by prune_sanitizer_output.py"
echo
echo " CATEGORIES are words that are expected to show in"
echo " a large subset of symbolized traces. Splits"
echo " output based on each word."
echo
echo " LOGCAT_FILE is the piped output from adb logcat."
echo
}
while [[ $# -gt 1 ]]; do
case $1 in
-d)
shift
USE_TEMP=false
OUT_DIR=$1
shift
break
;;
-e)
shift
EXACT_ARG='-e'
;;
-f)
shift
DO_REDO=true
;;
-m)
shift
MIN_ARG='-m '"$1"''
shift
;;
*)
usage
exit
esac
done
if [ $# -lt 1 ]; then
usage
exit
fi
LOGCAT_FILE=$1
NUM_CAT=$(($# - 1))
# Use a temp directory that will be deleted
if [ $USE_TEMP = true ]; then
OUT_DIR=$(mktemp -d --tmpdir=$PWD)
DO_REDO=true
fi
if [ ! -d "$OUT_DIR" ]; then
mkdir $OUT_DIR
DO_REDO=true
fi
# Note: Steps are skipped if their output exists until -f flag is enabled
# Step 1 - Only output lines related to Sanitizer
# Folder that holds all file output
echo "Output folder: $OUT_DIR"
ASAN_OUT=$OUT_DIR/asan_output
if [ ! -f $ASAN_OUT ] || [ $DO_REDO = true ]; then
DO_REDO=true
echo "Extracting ASAN output"
grep "app_process64" $LOGCAT_FILE > $ASAN_OUT
else
echo "Skipped: Extracting ASAN output"
fi
# Step 2 - Only output lines containing Dex File Start Addresses
DEX_START=$OUT_DIR/dex_start
if [ ! -f $DEX_START ] || [ $DO_REDO = true ]; then
DO_REDO=true
echo "Extracting Start of Dex File(s)"
grep "RegisterDexFile" $LOGCAT_FILE > $DEX_START
else
echo "Skipped: Extracting Start of Dex File(s)"
fi
# Step 3 - Clean Sanitizer output from Step 2 since logcat cannot
# handle large amounts of output.
ASAN_OUT_FILTERED=$OUT_DIR/asan_output_filtered
if [ ! -f $ASAN_OUT_FILTERED ] || [ $DO_REDO = true ]; then
DO_REDO=true
echo "Filtering/Cleaning ASAN output"
python $ANDROID_BUILD_TOP/art/tools/runtime_memusage/prune_sanitizer_output.py \
$EXACT_ARG $MIN_ARG -d $OUT_DIR $ASAN_OUT
else
echo "Skipped: Filtering/Cleaning ASAN output"
fi
# Step 4 - Retrieve symbolized stack traces from Step 3 output
SYM_FILTERED=$OUT_DIR/sym_filtered
if [ ! -f $SYM_FILTERED ] || [ $DO_REDO = true ]; then
DO_REDO=true
echo "Retrieving symbolized traces"
$ANDROID_BUILD_TOP/development/scripts/stack $ASAN_OUT_FILTERED > $SYM_FILTERED
else
echo "Skipped: Retrieving symbolized traces"
fi
# Step 5 - Using Steps 2, 3, 4 outputs in order to output graph data
# and trace data
# Only the category names are needed for the commands giving final output
shift
TIME_OUTPUT=($OUT_DIR/time_output_*.dat)
if [ ! -e ${TIME_OUTPUT[0]} ] || [ $DO_REDO = true ]; then
DO_REDO=true
echo "Creating Categorized Time Table"
python $ANDROID_BUILD_TOP/art/tools/runtime_memusage/symbol_trace_info.py \
-d $OUT_DIR $ASAN_OUT_FILTERED $SYM_FILTERED $DEX_START $@
else
echo "Skipped: Creating Categorized Time Table"
fi
# Step 6 - Use graph data from Step 5 to plot graph
# Contains the category names used for legend of gnuplot
PLOT_CATS=`echo \"Uncategorized $@\"`
echo "Plotting Categorized Time Table"
# Plots the information from logcat
gnuplot --persist -e \
'filename(n) = sprintf("'"$OUT_DIR"'/time_output_%d.dat", n);
catnames = '"$PLOT_CATS"';
set title "Dex File Offset vs. Time accessed since App Start";
set xlabel "Time (milliseconds)";
set ylabel "Dex File Offset (bytes)";
plot for [i=0:'"$NUM_CAT"'] filename(i) using 1:2 title word(catnames, i + 1);'
if [ $USE_TEMP = true ]; then
echo "Removing temp directory and files"
rm -rf $OUT_DIR
fi