• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/bin/bash
2#
3# Runs a CUJ multiple times and generates KPIs.
4
5set -E
6function trap_error() {
7    local return_value=$?
8    local line_no=$1
9    echo "Error at line ${line_no}: \"${BASH_COMMAND}\"" | tee -a ${OUTPUT_DIR}/fatal_log.txt
10    echo "Desc output ${desc}" | tee -a ${OUTPUT_DIR}/fatal_log.txt
11    pkill -P $$
12}
13trap 'trap_error $LINENO' ERR
14
15function clean_exit() {
16  adb wait-for-device
17  adb logcat -G 64K
18  adb shell setprop persist.logd.logpersistd \\\"\\\"
19  adb shell setprop persist.logd.logpersistd.enable false
20}
21trap 'clean_exit' EXIT
22
23readonly PSI_MONITOR_REPO_DIR="packages/services/Car/tools/psi_monitor"
24readonly ADB_WAIT_FOR_DEVICE_SCRIPT="adb_wait_for_device.sh"
25readonly RUN_CUJ_SCRIPT="run_cuj.sh"
26readonly GENERATE_KPI_STATS_SCRIPT="generate_kpi_stats.py"
27function setup_local_dir() {
28  if [[ -z ${ANDROID_BUILD_TOP} ]]; then
29    readonly LOCAL_SCRIPT_DIR=$(dirname ${0})
30  else
31    readonly LOCAL_SCRIPT_DIR=${ANDROID_BUILD_TOP}/${PSI_MONITOR_REPO_DIR}
32  fi
33  if [[ ! -f ${LOCAL_SCRIPT_DIR}/${ADB_WAIT_FOR_DEVICE_SCRIPT} ]]; then
34    ehco -e "${ADB_WAIT_FOR_DEVICE_SCRIPT} script not found in ${LOCAL_SCRIPT_DIR}" >&2
35    exit 1
36  fi
37  if [[ ! -f ${LOCAL_SCRIPT_DIR}/${RUN_CUJ_SCRIPT} ]]; then
38    echo -e "PSI monitor script ${RUN_CUJ_SCRIPT} not found in ${LOCAL_SCRIPT_DIR}" >&2
39    exit 1
40  fi
41  if [[ ! -f ${LOCAL_SCRIPT_DIR}/${GENERATE_KPI_STATS_SCRIPT} ]]; then
42    echo -e "KPI stats script ${GENERATE_KPI_STATS_SCRIPT} not found in ${LOCAL_SCRIPT_DIR}" >&2
43    exit 1
44  fi
45}
46
47setup_local_dir
48source ${LOCAL_SCRIPT_DIR}/adb_wait_for_device.sh
49
50OUTPUT_DIR=${PWD}/out
51CUJ_RUNS_OUTPUT_DIR_PREFIX=""
52RUN_PREFIX=run
53RUN_CUJ_ARGS=""
54ITERATIONS=0
55TOTAL_FAILURE_RETRIES=0
56KPI_CSV_FILE_LOCATION="processed/kpis.csv"
57
58function print_log() {
59  echo -e "[$(date +'%Y-%m-%d %H:%M:%S%z')] $@" | tee -a ${OUTPUT_DIR}/log.txt
60}
61
62function err() {
63  echo -e "[$(date +'%Y-%m-%d %H:%M:%S%z')] $@" >&2 | tee -a ${OUTPUT_DIR}/err.txt
64}
65
66function usage() {
67  echo "Runs a CUJ multiple times and generates KPIs."
68  echo "Usage: multi_run_cuj.sh [-o|--out_dir=<output_dir>]"\
69       "--run_cuj_args <run_cuj.sh args> [-i|--iterations] <Number of iterations>"\
70       "[--retry_any_failure] <Number of times to retry failures>"
71
72  echo "-o|--out_dir: Location to output the psi dump, CSV files, and KPIs"
73  echo "--run_cuj_args: Args to pass down to the run_cuj.sh script except output dir argument"
74  echo "-i|--iterations: Number of iterations to run the CUJ with run_cuj.sh script"
75  echo "--retry_any_failure: Number of times to retry any failure"
76  echo -e "\nExample commands:"
77  echo -e "\t1. ./multi_run_cuj.sh -o boot_with_threshold_met_app_launch --run_cuj_args \"-d 90 "\
78          "-g 20 -t 20 --bootup_with_app_launch threshold_met\" -i 20 --retry_any_failure 5"
79  echo -e "\t1. ./multi_run_cuj.sh -o app_launch --run_cuj_args \"-d 90 "\
80          "-g 20 -t 5 -a com.android.contacts --app_startup_times 10\" -i 20"
81}
82
83function usage_err() {
84  err "$@\n"
85  usage
86}
87
88function parse_arguments() {
89  while [[ $# > 0 ]]; do
90    key="$1"
91    case $key in
92    -h|--help)
93        usage
94        exit 1;;
95    -o|--out_dir)
96      OUTPUT_DIR=${2}
97      shift;;
98    --run_cuj_args)
99      RUN_CUJ_ARGS=${2}
100      shift;;
101    -i|--iterations)
102      ITERATIONS=${2}
103      shift;;
104    --retry_any_failure)
105      TOTAL_FAILURE_RETRIES=${2}
106      shift;;
107    *)
108      echo "${0}: Invalid option ${1}"
109      usage
110      exit 1;;
111    esac
112    shift # past argument or value
113  done
114}
115
116function check_arguments() {
117  readonly OUTPUT_DIR
118  mkdir -p ${OUTPUT_DIR}
119  if [[ ! -d ${OUTPUT_DIR} ]]; then
120    err "Out dir ${OUTPUT_DIR} does not exist"
121    exit 1
122  fi
123
124  readonly RUN_CUJ_ARGS
125  if [[ -z ${RUN_CUJ_ARGS} ]]; then
126    echo "Must provide run_cuj.sh arguments with the --run_cuj_args option"
127    exit 1
128  fi
129
130  readonly ITERATIONS
131  if [[ ${ITERATIONS} != +([[:digit:]]) || ${ITERATIONS} -le 0 || ${ITERATIONS} -gt 100 ]]; then
132    echo "Iterations ${ITERATIONS} is not a valid number. The values should be between 0 and 100"
133  fi
134
135  readonly TOTAL_FAILURE_RETRIES
136  if [[ ${TOTAL_FAILURE_RETRIES} != +([[:digit:]]) ]]; then
137    echo "Total failure retries ${TOTAL_FAILURE_RETRIES} is not a valid number"
138  fi
139}
140
141function setup() {
142  readonly CUJ_RUNS_OUTPUT_DIR_PREFIX=${OUTPUT_DIR}/"cuj_out/run_"
143  adb shell setprop persist.logd.logpersistd logcatd
144  adb shell setprop persist.logd.logpersistd.enable true
145  # Capture a bugreport for tracking the build details.
146  # adb bugreport ${OUTPUT_DIR}
147  adb_wait_with_recovery
148  fetch_device_info
149}
150
151function run_cuj_iterations() {
152  total_failure_count=0
153  for i in $(seq 1 ${ITERATIONS}); do
154    adb_wait_with_recovery
155    out_dir=${CUJ_RUNS_OUTPUT_DIR_PREFIX}${i}
156    print_log "\n\nRunning iteration ${i}. Output dir ${out_dir}"
157    while : ; do
158      mkdir -p ${out_dir}
159      (./run_cuj.sh ${RUN_CUJ_ARGS} -o ${out_dir} --no_show_plots)
160      if [ $? -eq 0 ]; then
161        break;
162      else
163        # Capture a bugreport for investigation purposes.
164        adb bugreport ${out_dir}
165        mv ${out_dir} ${out_dir}_failure_${total_failure_count}
166        pkill -P $$
167        if [[ ${total_failure_count} -ge ${TOTAL_FAILURE_RETRIES} ]]; then
168          print_log "CUJ run ${i} failed... Total remaining retries is"\
169          "((${TOTAL_FAILURE_RETRIES}-${total_failure_count})). Exiting";
170          return;
171        else
172          print_log "CUJ run ${i} failed... Total remaining retries is"\
173               "((${TOTAL_FAILURE_RETRIES}-${total_failure_count})). Retrying current failure"
174          total_failure_count=$((${total_failure_count}+1))
175        fi
176      fi
177    done
178  done
179}
180
181function generate_kpi_stats() {
182  kpi_csv_files=""
183  for i in $(seq 1 ${ITERATIONS}); do
184    kpi_csv_file=${CUJ_RUNS_OUTPUT_DIR_PREFIX}${i}/${KPI_CSV_FILE_LOCATION}
185    if [[ ! -f ${kpi_csv_file} ]]; then
186      err "Expected '${out_dir}' file doesn't exist. Skipping run iteration ${i}"
187      continue
188    fi
189    if [ -z ${kpi_csv_files} ]; then
190      kpi_csv_files=${kpi_csv_file}
191    else
192      kpi_csv_files+=",${kpi_csv_file}"
193    fi
194  done
195
196  echo -e "#!/bin/bash\n\n${LOCAL_SCRIPT_DIR}/${GENERATE_KPI_STATS_SCRIPT}"\
197       "--kpi_csv_files ${kpi_csv_files} --run_id_re \".*\/run_(\d+)\/processed\/kpis.csv\""\
198       "--out_file ${OUTPUT_DIR}/kpi_stats.csv" > ${OUTPUT_DIR}/generate_kpi_stats_cmd.sh
199  chmod +x ${OUTPUT_DIR}/generate_kpi_stats_cmd.sh
200
201  ${LOCAL_SCRIPT_DIR}/${GENERATE_KPI_STATS_SCRIPT} --kpi_csv_files "${kpi_csv_files}"\
202  --run_id_re ".*\/run_(\d+)\/processed\/kpis.csv" --out_file "${OUTPUT_DIR}/kpi_stats.csv"
203
204# Sample command for manual run:
205# (export IN_DIR=~/post_boot/cuj_out; export KPIS_CSV=processed/kpis.csv; \
206#  ~/android/main/packages/services/Car/tools/psi_monitor/generate_kpi_stats.py --kpi_csv_files \
207#  ${IN_DIR}/run_1/${KPIS_CSV},${IN_DIR}/run_2/${KPIS_CSV},${IN_DIR}/run_3/${KPIS_CSV},\
208#  ${IN_DIR}/run_4/${KPIS_CSV},${IN_DIR}/run_5/${KPIS_CSV},${IN_DIR}/run_6/${KPIS_CSV},\
209#  ${IN_DIR}/run_7/${KPIS_CSV},${IN_DIR}/run_8/${KPIS_CSV},${IN_DIR}/run_9/${KPIS_CSV},\
210#  ${IN_DIR}/run_10/${KPIS_CSV},${IN_DIR}/run_11/${KPIS_CSV},${IN_DIR}/run_12/${KPIS_CSV},\
211#  ${IN_DIR}/run_13/${KPIS_CSV},${IN_DIR}/run_14/${KPIS_CSV},${IN_DIR}/run_15/${KPIS_CSV},\
212#  ${IN_DIR}/run_16/${KPIS_CSV},${IN_DIR}/run_17/${KPIS_CSV},${IN_DIR}/run_18/${KPIS_CSV},\
213#  ${IN_DIR}/run_19/${KPIS_CSV} --run_id_re ".*\/run_(\d+)\/processed\/kpis.csv" \
214#  --out_file ${IN_DIR}/kpi_stats.csv)
215}
216
217function main() {
218  set -e
219  parse_arguments "$@"
220  check_arguments
221
222  setup
223
224  desc=$(${LOCAL_SCRIPT_DIR}/${RUN_CUJ_SCRIPT} ${RUN_CUJ_ARGS} --print_cuj_desc 2>&1)
225  print_log "Running CUJ '${desc}' for ${ITERATIONS} times"
226
227  set +e
228  run_cuj_iterations
229  set -e
230
231  generate_kpi_stats
232
233  adb shell setprop persist.logd.logpersistd ""
234  adb shell setprop persist.logd.logpersistd.enable false
235}
236
237main "$@"
238