blob: 75cb9a927eb7af47fd918f3e07b79821a6a81c61 [file] [log] [blame]
Bharadwaj Kalandhabhatta9e1c45d2017-06-13 08:56:51 -07001#!/bin/sh
2#
3# Copyright (C) 2017 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17# Note: Requires $ANDROID_BUILD_TOP/build/envsetup.sh to have been run.
18#
19# This script takes in a logcat containing Sanitizer traces and outputs several
20# files, prints information regarding the traces, and plots information as well.
21USE_TEMP=true
22DO_REDO=false
23# EXACT_ARG and MIN_ARG are passed to prune_sanitizer_output.py
24EXACT_ARG=""
25MIN_ARG=""
26usage() {
27 echo "Usage: $0 [options] [LOGCAT_FILE] [CATEGORIES...]"
28 echo " -d OUT_DIRECTORY"
29 echo " Puts all output in specified directory."
30 echo " If not given, output will be put in a local"
31 echo " temp folder which will be deleted after"
32 echo " execution."
33 echo
34 echo " -e"
35 echo " All traces will have exactly the same number"
36 echo " of categories which is specified by either"
37 echo " the -m argument or by prune_sanitizer_output.py"
38 echo
39 echo " -f"
40 echo " forces redo of all commands even if output"
41 echo " files exist. Steps are skipped if their output"
42 echo " exist already and this is not enabled."
43 echo
44 echo " -m [MINIMUM_CALLS_PER_TRACE]"
45 echo " Filters out all traces that do not have"
46 echo " at least MINIMUM_CALLS_PER_TRACE lines."
47 echo " default: specified by prune_sanitizer_output.py"
48 echo
49 echo " CATEGORIES are words that are expected to show in"
50 echo " a large subset of symbolized traces. Splits"
51 echo " output based on each word."
52 echo
53 echo " LOGCAT_FILE is the piped output from adb logcat."
54 echo
55}
56
57
58while [[ $# -gt 1 ]]; do
59case $1 in
60 -d)
61 shift
62 USE_TEMP=false
63 OUT_DIR=$1
64 shift
65 break
66 ;;
67 -e)
68 shift
69 EXACT_ARG='-e'
70 ;;
71 -f)
72 shift
73 DO_REDO=true
74 ;;
75 -m)
76 shift
77 MIN_ARG='-m '"$1"''
78 shift
79 ;;
80 *)
81 usage
82 exit
83esac
84done
85
86if [ $# -lt 1 ]; then
87 usage
88 exit
89fi
90
91LOGCAT_FILE=$1
92NUM_CAT=$(($# - 1))
93
94# Use a temp directory that will be deleted
95if [ $USE_TEMP = true ]; then
96 OUT_DIR=$(mktemp -d --tmpdir=$PWD)
97 DO_REDO=true
98fi
99
100if [ ! -d "$OUT_DIR" ]; then
101 mkdir $OUT_DIR
102 DO_REDO=true
103fi
104
105# Note: Steps are skipped if their output exists until -f flag is enabled
106# Step 1 - Only output lines related to Sanitizer
107# Folder that holds all file output
108echo "Output folder: $OUT_DIR"
109ASAN_OUT=$OUT_DIR/asan_output
110if [ ! -f $ASAN_OUT ] || [ $DO_REDO = true ]; then
111 DO_REDO=true
112 echo "Extracting ASAN output"
113 grep "app_process64" $LOGCAT_FILE > $ASAN_OUT
114else
115 echo "Skipped: Extracting ASAN output"
116fi
117
118# Step 2 - Only output lines containing Dex File Start Addresses
119DEX_START=$OUT_DIR/dex_start
120if [ ! -f $DEX_START ] || [ $DO_REDO = true ]; then
121 DO_REDO=true
122 echo "Extracting Start of Dex File(s)"
123 grep "RegisterDexFile" $LOGCAT_FILE > $DEX_START
124else
125 echo "Skipped: Extracting Start of Dex File(s)"
126fi
127
128# Step 3 - Clean Sanitizer output from Step 2 since logcat cannot
129# handle large amounts of output.
130ASAN_OUT_FILTERED=$OUT_DIR/asan_output_filtered
131if [ ! -f $ASAN_OUT_FILTERED ] || [ $DO_REDO = true ]; then
132 DO_REDO=true
133 echo "Filtering/Cleaning ASAN output"
134 python $ANDROID_BUILD_TOP/art/tools/runtime_memusage/prune_sanitizer_output.py \
135 $EXACT_ARG $MIN_ARG -d $OUT_DIR $ASAN_OUT
136else
137 echo "Skipped: Filtering/Cleaning ASAN output"
138fi
139
140# Step 4 - Retrieve symbolized stack traces from Step 3 output
141SYM_FILTERED=$OUT_DIR/sym_filtered
142if [ ! -f $SYM_FILTERED ] || [ $DO_REDO = true ]; then
143 DO_REDO=true
144 echo "Retrieving symbolized traces"
145 $ANDROID_BUILD_TOP/development/scripts/stack $ASAN_OUT_FILTERED > $SYM_FILTERED
146else
147 echo "Skipped: Retrieving symbolized traces"
148fi
149
150# Step 5 - Using Steps 2, 3, 4 outputs in order to output graph data
151# and trace data
152# Only the category names are needed for the commands giving final output
153shift
154TIME_OUTPUT=($OUT_DIR/time_output_*.dat)
155if [ ! -e ${TIME_OUTPUT[0]} ] || [ $DO_REDO = true ]; then
156 DO_REDO=true
157 echo "Creating Categorized Time Table"
158 python $ANDROID_BUILD_TOP/art/tools/runtime_memusage/symbol_trace_info.py \
159 -d $OUT_DIR $ASAN_OUT_FILTERED $SYM_FILTERED $DEX_START $@
160else
161 echo "Skipped: Creating Categorized Time Table"
162fi
163
164# Step 6 - Use graph data from Step 5 to plot graph
165# Contains the category names used for legend of gnuplot
166PLOT_CATS=`echo \"Uncategorized $@\"`
167echo "Plotting Categorized Time Table"
168# Plots the information from logcat
169gnuplot --persist -e \
170 'filename(n) = sprintf("'"$OUT_DIR"'/time_output_%d.dat", n);
171 catnames = '"$PLOT_CATS"';
172 set title "Dex File Offset vs. Time accessed since App Start";
173 set xlabel "Time (milliseconds)";
174 set ylabel "Dex File Offset (bytes)";
175 plot for [i=0:'"$NUM_CAT"'] filename(i) using 1:2 title word(catnames, i + 1);'
176
177if [ $USE_TEMP = true ]; then
178 echo "Removing temp directory and files"
179 rm -rf $OUT_DIR
180fi