1#!/bin/bash
2
3# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7# Wrapper to run the platform_BootPerfServer autotest, and store the
8# results for later analysis by the 'showbootdata' script.
9#
10# NOTE: This script must be run from inside the chromeos build
11# chroot environment.
12#
13
14# --- BEGIN COMMON.SH BOILERPLATE ---
15# Load common CrOS utilities.  Inside the chroot this file is installed in
16# /usr/lib/crosutils.  Outside the chroot we find it relative to the script's
17# location.
18find_common_sh() {
19  local common_paths=(/usr/lib/crosutils "$(dirname "$(readlink -f "$0")")/..")
20  local path
21
22  SCRIPT_ROOT=
23  for path in "${common_paths[@]}"; do
24    if [ -r "${path}/common.sh" ]; then
25      SCRIPT_ROOT=${path}
26      break
27    fi
28  done
29}
30
31find_common_sh
32. "${SCRIPT_ROOT}/common.sh" || (echo "Unable to load common.sh" && exit 1)
33# --- END COMMON.SH BOILERPLATE ---
34
35# TODO(jrbarnette) The log files produced in this script will be
36# stored inside the chroot.  So, from outside the chroot, this
37# script doesn't work.  I don't know if this is easy to fix, but
38# you're welcome to try.  Let me know how it goes.  :-)
39assert_inside_chroot
40
41DEFINE_string output_dir "" "output directory for results" o
42DEFINE_string board "" "name of board we are testing"
43DEFINE_boolean keep_logs "$FLAGS_FALSE" "keep autotest results" k
44
45RUN_TEST="test_that"
46TEST='platform_BootPerfServer.bootperf'
47TMP_RESULTS="$(mktemp -d /tmp/bootperf.XXXXXX)"
48RESULTS_ROOT="results-1-$TEST"
49RESULTS_DIR=platform_BootPerfServer/results
50RESULTS_KEYVAL=$RESULTS_DIR/keyval
51RESULTS_SUMMARY_FILES=(
52  $RESULTS_DIR
53  keyval
54  platform_BootPerfServer/keyval
55  platform_BootPerfServer/platform_BootPerf/keyval
56  platform_BootPerfServer/platform_BootPerf/status
57  platform_BootPerfServer/status
58  platform_BootPerfServer/status.log
59  platform_BootPerfServer/sysinfo/cmdline
60  platform_BootPerfServer/sysinfo/cpuinfo
61  platform_BootPerfServer/sysinfo/modules
62  platform_BootPerfServer/sysinfo/uname
63  platform_BootPerfServer/sysinfo/version
64  status.log
65)
66
67# Structure of a results directory:
68#   $RUNDIR.$ITER/          - directory
69#       $RUNDIR_LOG             - file
70#       $RUNDIR_SUMMARY/        - directory
71#       $RUNDIR_ALL_RESULTS/    - optional directory
72#   $KEYVAL_SUMMARY/        - file
73# If you add any other content under the results directory, you'll
74# probably need to change extra_files(), below.
75RUNDIR=run
76RUNDIR_LOG=log.txt
77RUNDIR_SUMMARY=summary
78RUNDIR_ALL_RESULTS=logs
79KEYVAL_SUMMARY=results_keyval
80
81
82# Usage/help function.  This function is known to the shflags library,
83# and mustn't be renamed.
84flags_help() {
85  cat <<END_USAGE >&2
86usage: $(basename $0) [ <options> ] <ip-address> [ <count> ]
87Options:
88  --output_dir <directory>
89  --o <directory>       Specify output directory for results
90
91  --board <BOARDNAME>   name of board we are testing (e.g. daisy)
92
93  --[no]keep_logs
94  -k                    Keep [don't keep] autotest log files
95Summary:
96  Run the platform_BootPerfServer autotest, and store results in the
97  given destination directory.  The test target is specified by
98  <ip-address>.
99
100  By default, the test is run once; if <count> is given, the test is
101  run that many times.  Note that the platform_BootPerfServer test
102  reboots the target 10 times, so the total number of reboots will
103  be 10*<count>.
104
105  If the destination directory doesn't exist, it is created.  If the
106  destination directory already holds test results, additional
107  results are added in without overwriting earlier results.
108
109  If no destination is specified, the current directory is used,
110  provided that the directory is empty, or has been previously used
111  as a destination directory for this command.
112
113  By default, only a summary subset of the log files created by
114  autotest is preserved; with --keep_logs the (potentially large)
115  autotest logs are preserved with the test results.
116END_USAGE
117  return $FLAGS_TRUE
118}
119
120usage() {
121  if [ $# -gt 0 ]; then
122    error "$(basename $0): $*"
123    echo >&2
124  fi
125  flags_help
126  exit 1
127}
128
129# List any files in the current directory not created as output
130# from running this script.
131extra_files() {
132  ls | grep -v "^$RUNDIR[.]...\$" |
133       grep -v $KEYVAL_SUMMARY
134}
135
136# Main function to run the boot performance test.  Run the boot
137# performance test for the given count, putting output into the
138# current directory.
139#
140# Arguments are <ip-address> and <count> arguments, as for the main
141# command.
142#
143# We terminate test runs if "test_that" ever fails to produce the
144# results keyval file; generally this is the result of a serious
145# error (e.g. disk full) that won't go away if we just plow on.
146run_boot_test() {
147  local remote="$1"
148  local count="${2:-1}"
149
150  local iter=$(expr "$(echo $RUNDIR.???)" : '.*\(...\)')
151  if [ "$iter" != "???" ]; then
152      iter=$(echo $iter | awk '{printf "%03d\n", $1 + 1}')
153  else
154      iter=000
155  fi
156
157  i=0
158  while [ $i -lt $count ]; do
159    local iter_rundir=$RUNDIR.$iter
160    local logfile=$(pwd)/$iter_rundir/$RUNDIR_LOG
161    local summary_dir=$iter_rundir/$RUNDIR_SUMMARY
162    local all_results_dir=$iter_rundir/$RUNDIR_ALL_RESULTS
163
164    mkdir $iter_rundir
165    echo "$(date '+%T') - $logfile"
166
167    $RUN_TEST --results_dir="$TMP_RESULTS" --args "10" $BOARD \
168              "$remote" $TEST >$logfile 2>&1
169    if [ ! -e "$TMP_RESULTS/$RESULTS_ROOT/$RESULTS_KEYVAL" ]; then
170      error "No results file; terminating test runs."
171      error "Check $logfile for output from the test run,"
172      error "and see $TMP_RESULTS for full test logs and output."
173      return
174    fi
175    mkdir $summary_dir
176    tar cf - -C $TMP_RESULTS/$RESULTS_ROOT "${RESULTS_SUMMARY_FILES[@]}" |
177      tar xf - -C $summary_dir
178    if [ $FLAGS_keep_logs -eq $FLAGS_TRUE ]; then
179      mv $TMP_RESULTS $all_results_dir
180      chmod 755 $all_results_dir
181    else
182      rm -rf $TMP_RESULTS
183    fi
184    i=$(expr $i + 1)
185    iter=$(echo $iter | awk '{printf "%03d\n", $1 + 1}')
186  done
187  date '+%T'
188  cat $RUNDIR.???/$RUNDIR_SUMMARY/$RESULTS_KEYVAL >$KEYVAL_SUMMARY
189}
190
191# Main routine - check validity of the (already parsed) command line
192# options.  'cd' to the results directory, if it was specified.  If
193# all the arguments checks pass, hand control to run_boot_test
194main() {
195  if [ $# -lt 1 ]; then
196      usage "Missing target host address"
197  elif [ $# -gt 2 ]; then
198      usage "Too many arguments"
199  fi
200
201  if [ -n "${FLAGS_board}" ]; then
202    BOARD="--board=${FLAGS_board}"
203  fi
204
205  if [ -n "${FLAGS_output_dir}" ]; then
206    if [ ! -d "${FLAGS_output_dir}" ]; then
207      if ! mkdir "${FLAGS_output_dir}"; then
208        usage "Unable to create ${FLAGS_output_dir}"
209      fi
210    fi
211    cd "${FLAGS_output_dir}" ||
212      usage "No permissions to chdir to ${FLAGS_output_dir}"
213  elif [ -n "$(extra_files)" ]; then
214    error "No results directory specified, and current directory"
215    error "contains contents other than run results."
216    error "You can override this error by using the --output_dir option"
217    usage
218  fi
219
220  # Check the count argument.
221  # N.B. the test [ "$2" -eq "$2" ] tests whether "$2" is valid as a
222  # number; when it fails it will also report a syntax error (which
223  # we suppress).
224  if [ -n "$2" ]; then
225    if ! [ "$2" -eq "$2" ] 2>/dev/null || [ "$2" -le 0 ]; then
226      usage "<count> argument must be a positive number"
227    fi
228  fi
229
230  run_boot_test "$@"
231}
232
233# shflags defines --help implicitly; if it's used on the command
234# line FLAGS will invoke flags_help, set FLAGS_help to TRUE, and
235# then return false.  To avoid printing help twice, we have to check
236# for that case here.
237if ! FLAGS "$@"; then
238  if [ ${FLAGS_help} -eq ${FLAGS_TRUE} ]; then
239    exit 0
240  else
241    usage
242  fi
243fi
244
245eval main "${FLAGS_ARGV}"
246