xref: /libCEED/benchmarks/benchmark.sh (revision 2f4d9adb86426a8397f9d81f8b0a0e6244dbfdbd)
1*2f4d9adbSJeremy L Thompson#!/bin/bash
2*2f4d9adbSJeremy L Thompson
3*2f4d9adbSJeremy L Thompson# Copyright (c) 2017-2018, Lawrence Livermore National Security, LLC.
4*2f4d9adbSJeremy L Thompson# Produced at the Lawrence Livermore National Laboratory. LLNL-CODE-734707.
5*2f4d9adbSJeremy L Thompson# All Rights reserved. See files LICENSE and NOTICE for details.
6*2f4d9adbSJeremy L Thompson#
7*2f4d9adbSJeremy L Thompson# This file is part of CEED, a collection of benchmarks, miniapps, software
8*2f4d9adbSJeremy L Thompson# libraries and APIs for efficient high-order finite element and spectral
9*2f4d9adbSJeremy L Thompson# element discretizations for exascale applications. For more information and
10*2f4d9adbSJeremy L Thompson# source code availability see http://github.com/ceed.
11*2f4d9adbSJeremy L Thompson#
12*2f4d9adbSJeremy L Thompson# The CEED research is supported by the Exascale Computing Project 17-SC-20-SC,
13*2f4d9adbSJeremy L Thompson# a collaborative effort of two U.S. Department of Energy organizations (Office
14*2f4d9adbSJeremy L Thompson# of Science and the National Nuclear Security Administration) responsible for
15*2f4d9adbSJeremy L Thompson# the planning and preparation of a capable exascale ecosystem, including
16*2f4d9adbSJeremy L Thompson# software, applications, hardware, advanced system engineering and early
17*2f4d9adbSJeremy L Thompson# testbed platforms, in support of the nation's exascale computing imperative.
18*2f4d9adbSJeremy L Thompson
19*2f4d9adbSJeremy L Thompsonthis_file="${BASH_SOURCE[0]}"
20*2f4d9adbSJeremy L Thompsonif [[ "${#BASH_ARGV[@]}" -ne "$#" ]]; then
21*2f4d9adbSJeremy L Thompson   script_is_sourced="yes"
22*2f4d9adbSJeremy L Thompson   exit_cmd=return
23*2f4d9adbSJeremy L Thompsonelse
24*2f4d9adbSJeremy L Thompson   script_is_sourced=""
25*2f4d9adbSJeremy L Thompson   exit_cmd=exit
26*2f4d9adbSJeremy L Thompsonfi
27*2f4d9adbSJeremy L Thompsontest_file=""
28*2f4d9adbSJeremy L Thompsonbackend_list="/cpu/self"
29*2f4d9adbSJeremy L Thompsonrun=""
30*2f4d9adbSJeremy L Thompsonnum_proc_run=${num_proc_run:-""}
31*2f4d9adbSJeremy L Thompsonnum_proc_node=${num_proc_node:-""}
32*2f4d9adbSJeremy L Thompsondry_run="" # empty string = NO
33*2f4d9adbSJeremy L Thompsonstart_shell=""
34*2f4d9adbSJeremy L Thompsonverbose=""
35*2f4d9adbSJeremy L Thompsoncur_dir="$PWD"
36*2f4d9adbSJeremy L Thompson
37*2f4d9adbSJeremy L Thompsonmpiexec="mpirun"
38*2f4d9adbSJeremy L Thompsonmpiexec_np="-np"
39*2f4d9adbSJeremy L Thompsonmpiexec_opts=""
40*2f4d9adbSJeremy L Thompsonmpiexec_post_opts=""
41*2f4d9adbSJeremy L Thompsonprofiler=""
42*2f4d9adbSJeremy L Thompson
43*2f4d9adbSJeremy L Thompsonfunction abspath()
44*2f4d9adbSJeremy L Thompson{
45*2f4d9adbSJeremy L Thompson   local outvar="$1" path="$2" cur_dir="$PWD"
46*2f4d9adbSJeremy L Thompson   cd "$path" && path="$PWD" && cd "$cur_dir" && eval "$outvar=\"$path\""
47*2f4d9adbSJeremy L Thompson}
48*2f4d9adbSJeremy L Thompson
49*2f4d9adbSJeremy L Thompsonabspath root_dir ".." || $exit_cmd 1
50*2f4d9adbSJeremy L Thompsonbuild_root="$root_dir/build"
51*2f4d9adbSJeremy L Thompson
52*2f4d9adbSJeremy L Thompsonif [[ -t 1 ]]; then
53*2f4d9adbSJeremy L Thompson   # ANSI color codes
54*2f4d9adbSJeremy L Thompson   none=$'\E[0m'
55*2f4d9adbSJeremy L Thompson   red=$'\E[0;31m'
56*2f4d9adbSJeremy L Thompson   green=$'\E[0;32m'
57*2f4d9adbSJeremy L Thompson   yellow=$'\E[0;33m'
58*2f4d9adbSJeremy L Thompson   blue=$'\E[0;34m'
59*2f4d9adbSJeremy L Thompson   bblue=$'\E[1;34m'
60*2f4d9adbSJeremy L Thompson   magenta=$'\E[0;35m'
61*2f4d9adbSJeremy L Thompson   cyan=$'\E[0;36m'
62*2f4d9adbSJeremy L Thompson   clear="$(tput sgr0)"
63*2f4d9adbSJeremy L Thompsonfi
64*2f4d9adbSJeremy L Thompson
65*2f4d9adbSJeremy L Thompsonhelp_msg="
66*2f4d9adbSJeremy L Thompson$this_file [options]
67*2f4d9adbSJeremy L Thompson
68*2f4d9adbSJeremy L ThompsonOptions:
69*2f4d9adbSJeremy L Thompson   -h|--help                print this usage information and exit
70*2f4d9adbSJeremy L Thompson   -c|--ceed \"list\"         choose the libCEED backends to benchmark
71*2f4d9adbSJeremy L Thompson   -r|--run <name>          run the tests in the script <name>
72*2f4d9adbSJeremy L Thompson   -n|--num-proc \"list\"     total number of MPI tasks to use in the tests
73*2f4d9adbSJeremy L Thompson   -p|--proc-node \"list\"    number of MPI tasks per node to use in the tests
74*2f4d9adbSJeremy L Thompson   -d|--dry-run             show (but do not run) the commands for the tests
75*2f4d9adbSJeremy L Thompson   -s|--shell               execute bash shell commands before running the test
76*2f4d9adbSJeremy L Thompson   -v|--verbose             print additional messages
77*2f4d9adbSJeremy L Thompson   -x                       enable script tracing with 'set -x'
78*2f4d9adbSJeremy L Thompson   var=value                define shell variables; evaluated with 'eval'
79*2f4d9adbSJeremy L Thompson
80*2f4d9adbSJeremy L ThompsonThis script builds and runs a set of benchmarks for a list of specified
81*2f4d9adbSJeremy L Thompsonbackends.
82*2f4d9adbSJeremy L Thompson
83*2f4d9adbSJeremy L ThompsonExample usage:
84*2f4d9adbSJeremy L Thompson  $this_file  --run petsc-bp1.sh
85*2f4d9adbSJeremy L Thompson"
86*2f4d9adbSJeremy L Thompson
87*2f4d9adbSJeremy L Thompson
88*2f4d9adbSJeremy L Thompsonfunction build_examples()
89*2f4d9adbSJeremy L Thompson{
90*2f4d9adbSJeremy L Thompson   for example; do
91*2f4d9adbSJeremy L Thompson      # We require the examples to be already built because we do not know what
92*2f4d9adbSJeremy L Thompson      # options to use when building the library + examples.
93*2f4d9adbSJeremy L Thompson      if [ ! -e $build_root/$example ]; then
94*2f4d9adbSJeremy L Thompson         echo "Error: example is not built: $example"
95*2f4d9adbSJeremy L Thompson         return 1
96*2f4d9adbSJeremy L Thompson      fi
97*2f4d9adbSJeremy L Thompson   done
98*2f4d9adbSJeremy L Thompson}
99*2f4d9adbSJeremy L Thompson
100*2f4d9adbSJeremy L Thompson
101*2f4d9adbSJeremy L Thompsonfunction compose_mpi_run_command()
102*2f4d9adbSJeremy L Thompson{
103*2f4d9adbSJeremy L Thompson   mpi_run="${mpiexec:-mpirun} ${mpiexec_opts}"
104*2f4d9adbSJeremy L Thompson   mpi_run+=" ${mpiexec_np:--np} ${num_proc_run} ${mpiexec_post_opts}"
105*2f4d9adbSJeremy L Thompson   if [[ -n "$profiler" ]]; then
106*2f4d9adbSJeremy L Thompson      mpi_run+=" $profiler"
107*2f4d9adbSJeremy L Thompson   fi
108*2f4d9adbSJeremy L Thompson}
109*2f4d9adbSJeremy L Thompson
110*2f4d9adbSJeremy L Thompson
111*2f4d9adbSJeremy L Thompsonfunction quoted_echo()
112*2f4d9adbSJeremy L Thompson{
113*2f4d9adbSJeremy L Thompson   local arg= string=
114*2f4d9adbSJeremy L Thompson   for arg; do
115*2f4d9adbSJeremy L Thompson      if [[ -z "${arg##* *}" ]]; then
116*2f4d9adbSJeremy L Thompson         string+=" \"${arg//\"/\\\"}\""
117*2f4d9adbSJeremy L Thompson      else
118*2f4d9adbSJeremy L Thompson         string+=" $arg"
119*2f4d9adbSJeremy L Thompson      fi
120*2f4d9adbSJeremy L Thompson   done
121*2f4d9adbSJeremy L Thompson   printf "%s\n" "${string# }"
122*2f4d9adbSJeremy L Thompson}
123*2f4d9adbSJeremy L Thompson
124*2f4d9adbSJeremy L Thompson
125*2f4d9adbSJeremy L Thompsonfunction set_num_nodes()
126*2f4d9adbSJeremy L Thompson{
127*2f4d9adbSJeremy L Thompson   if [[ -n "$num_proc_node" ]]; then
128*2f4d9adbSJeremy L Thompson      ((num_proc_run % num_proc_node != 0)) && {
129*2f4d9adbSJeremy L Thompson         echo "The total number of tasks ($num_proc_run) must be a multiple of"
130*2f4d9adbSJeremy L Thompson         echo "the number of tasks per node ($num_proc_node). Stop."
131*2f4d9adbSJeremy L Thompson         return 1
132*2f4d9adbSJeremy L Thompson      }
133*2f4d9adbSJeremy L Thompson      ((num_nodes = num_proc_run / num_proc_node))
134*2f4d9adbSJeremy L Thompson   else
135*2f4d9adbSJeremy L Thompson      num_proc_node="unknown number of"
136*2f4d9adbSJeremy L Thompson      num_nodes=""
137*2f4d9adbSJeremy L Thompson   fi
138*2f4d9adbSJeremy L Thompson   echo "Running the tests using a total of $num_proc_run MPI tasks ..." | tee -a $output_file
139*2f4d9adbSJeremy L Thompson   echo "... with $num_proc_node tasks per node ..." | tee -a $output_file
140*2f4d9adbSJeremy L Thompson   echo | tee -a $output_file
141*2f4d9adbSJeremy L Thompson}
142*2f4d9adbSJeremy L Thompson
143*2f4d9adbSJeremy L Thompson
144*2f4d9adbSJeremy L Thompson### Process command line parameters
145*2f4d9adbSJeremy L Thompson
146*2f4d9adbSJeremy L Thompsonwhile [ $# -gt 0 ]; do
147*2f4d9adbSJeremy L Thompson
148*2f4d9adbSJeremy L Thompsoncase "$1" in
149*2f4d9adbSJeremy L Thompson   -h|--help)
150*2f4d9adbSJeremy L Thompson      # Echo usage information
151*2f4d9adbSJeremy L Thompson      echo "$help_msg"
152*2f4d9adbSJeremy L Thompson      $exit_cmd
153*2f4d9adbSJeremy L Thompson      ;;
154*2f4d9adbSJeremy L Thompson   -c|--ceed)
155*2f4d9adbSJeremy L Thompson      shift
156*2f4d9adbSJeremy L Thompson      [ $# -gt 0 ] || {
157*2f4d9adbSJeremy L Thompson      echo "Missing \"list\" in --ceed \"list\""; $exit_cmd 1; }
158*2f4d9adbSJeremy L Thompson      backend_list="$1"
159*2f4d9adbSJeremy L Thompson      ;;
160*2f4d9adbSJeremy L Thompson   -r|--run)
161*2f4d9adbSJeremy L Thompson      run=on
162*2f4d9adbSJeremy L Thompson      shift
163*2f4d9adbSJeremy L Thompson      [ $# -gt 0 ] || { echo "Missing <name> in --run <name>"; $exit_cmd 1; }
164*2f4d9adbSJeremy L Thompson      test_file="$1"
165*2f4d9adbSJeremy L Thompson      [[ -r "$test_file" ]] || {
166*2f4d9adbSJeremy L Thompson         echo "Test script not found: '$1'"; $exit_cmd 1
167*2f4d9adbSJeremy L Thompson      }
168*2f4d9adbSJeremy L Thompson      ;;
169*2f4d9adbSJeremy L Thompson   -n|--num-proc)
170*2f4d9adbSJeremy L Thompson      shift
171*2f4d9adbSJeremy L Thompson      [ $# -gt 0 ] || {
172*2f4d9adbSJeremy L Thompson      echo "Missing \"list\" in --num-proc \"list\""; $exit_cmd 1; }
173*2f4d9adbSJeremy L Thompson      num_proc_run="$1"
174*2f4d9adbSJeremy L Thompson      ;;
175*2f4d9adbSJeremy L Thompson   -p|--proc-node)
176*2f4d9adbSJeremy L Thompson      shift
177*2f4d9adbSJeremy L Thompson      [ $# -gt 0 ] || {
178*2f4d9adbSJeremy L Thompson      echo "Missing \"list\" in --proc-node \"list\""; $exit_cmd 1; }
179*2f4d9adbSJeremy L Thompson      num_proc_node="$1"
180*2f4d9adbSJeremy L Thompson      ;;
181*2f4d9adbSJeremy L Thompson   -d|--dry-run)
182*2f4d9adbSJeremy L Thompson      dry_run="quoted_echo"
183*2f4d9adbSJeremy L Thompson      ;;
184*2f4d9adbSJeremy L Thompson   -s|--shell)
185*2f4d9adbSJeremy L Thompson      start_shell="yes"
186*2f4d9adbSJeremy L Thompson      ;;
187*2f4d9adbSJeremy L Thompson   -v|--verbose)
188*2f4d9adbSJeremy L Thompson      verbose="yes"
189*2f4d9adbSJeremy L Thompson      ;;
190*2f4d9adbSJeremy L Thompson   -x)
191*2f4d9adbSJeremy L Thompson      set -x
192*2f4d9adbSJeremy L Thompson      ;;
193*2f4d9adbSJeremy L Thompson   *=*)
194*2f4d9adbSJeremy L Thompson      eval "$1" || { echo "Error evaluating argument: $1"; $exit_cmd 1; }
195*2f4d9adbSJeremy L Thompson      ;;
196*2f4d9adbSJeremy L Thompson   *)
197*2f4d9adbSJeremy L Thompson      echo "Unknown option: '$1'"
198*2f4d9adbSJeremy L Thompson      $exit_cmd 1
199*2f4d9adbSJeremy L Thompson      ;;
200*2f4d9adbSJeremy L Thompsonesac
201*2f4d9adbSJeremy L Thompson
202*2f4d9adbSJeremy L Thompsonshift
203*2f4d9adbSJeremy L Thompsondone # while ...
204*2f4d9adbSJeremy L Thompson# Done processing command line parameters
205*2f4d9adbSJeremy L Thompson
206*2f4d9adbSJeremy L Thompson
207*2f4d9adbSJeremy L Thompsonnum_proc_list=(${num_proc_run:-4})
208*2f4d9adbSJeremy L Thompsonnum_proc_list_size=${#num_proc_list[@]}
209*2f4d9adbSJeremy L Thompsonnum_proc_node_list=(${num_proc_node:-4})
210*2f4d9adbSJeremy L Thompsonnum_proc_node_list_size=${#num_proc_node_list[@]}
211*2f4d9adbSJeremy L Thompson(( num_proc_list_size != num_proc_node_list_size )) && {
212*2f4d9adbSJeremy L Thompson   echo "
213*2f4d9adbSJeremy L ThompsonThe size of the number-of-processors list (option --num-proc) must be the same
214*2f4d9adbSJeremy L Thompsonas the size of the number-of-processors-per-node list (option --proc-node)."
215*2f4d9adbSJeremy L Thompson   echo
216*2f4d9adbSJeremy L Thompson   $exit_cmd 1
217*2f4d9adbSJeremy L Thompson}
218*2f4d9adbSJeremy L Thompson
219*2f4d9adbSJeremy L Thompson
220*2f4d9adbSJeremy L Thompson### Loop over backends
221*2f4d9adbSJeremy L Thompson
222*2f4d9adbSJeremy L Thompsonfor backend in $backend_list; do
223*2f4d9adbSJeremy L Thompson(  ## Run each backend in its own environment
224*2f4d9adbSJeremy L Thompson
225*2f4d9adbSJeremy L Thompson### Setup output
226*2f4d9adbSJeremy L Thompson### Test name
227*2f4d9adbSJeremy L Thompsoncd "$cur_dir"
228*2f4d9adbSJeremy L Thompsonabspath test_dir "$(dirname "$test_file")" || $exit_cmd 1
229*2f4d9adbSJeremy L Thompsontest_basename="$(basename "$test_file")"
230*2f4d9adbSJeremy L Thompsontest_file="${test_dir}/${test_basename}"
231*2f4d9adbSJeremy L Thompson### Backend name
232*2f4d9adbSJeremy L Thompsonshort_backend=${backend//[\/]}
233*2f4d9adbSJeremy L Thompson### Output file
234*2f4d9adbSJeremy L Thompsonoutput_file="${test_file%%.*}-$short_backend-output.txt"
235*2f4d9adbSJeremy L Thompsonrm -rf output_file
236*2f4d9adbSJeremy L Thompson
237*2f4d9adbSJeremy L Thompson### Setup the environment based on $backend
238*2f4d9adbSJeremy L Thompson
239*2f4d9adbSJeremy L Thompsonecho
240*2f4d9adbSJeremy L Thompsonecho "Using backend $backend ..." | tee $output_file
241*2f4d9adbSJeremy L Thompson
242*2f4d9adbSJeremy L Thompson### Run the tests (building and running $test_file)
243*2f4d9adbSJeremy L Thompson
244*2f4d9adbSJeremy L Thompson[ -n "$run" ] && {
245*2f4d9adbSJeremy L Thompson
246*2f4d9adbSJeremy L Thompson[[ "$verbose" = "yes" ]] && {
247*2f4d9adbSJeremy L Thompson   echo "Test problem file, $test_basename:" | tee -a $output_file
248*2f4d9adbSJeremy L Thompson   echo "------------------------------------------------" | tee -a $output_file
249*2f4d9adbSJeremy L Thompson   cat $test_file | tee -a $output_file
250*2f4d9adbSJeremy L Thompson   echo "------------------------------------------------" | tee -a $output_file
251*2f4d9adbSJeremy L Thompson   echo | tee -a $output_file
252*2f4d9adbSJeremy L Thompson}
253*2f4d9adbSJeremy L Thompson
254*2f4d9adbSJeremy L Thompsontest_exe_dir="$build_root"
255*2f4d9adbSJeremy L Thompson
256*2f4d9adbSJeremy L Thompsontrap 'printf "\nScript interrupted.\n"; '$exit_cmd' 33' INT
257*2f4d9adbSJeremy L Thompson
258*2f4d9adbSJeremy L Thompson## Source the test script file.
259*2f4d9adbSJeremy L Thompsonecho "Reading test file: $test_file" | tee -a $output_file
260*2f4d9adbSJeremy L Thompsonecho | tee -a $output_file
261*2f4d9adbSJeremy L Thompsontest_required_examples=""
262*2f4d9adbSJeremy L Thompson. "$test_file" || $exit_cmd 1
263*2f4d9adbSJeremy L Thompson
264*2f4d9adbSJeremy L Thompson## Build files required by the test
265*2f4d9adbSJeremy L Thompsonecho "Example(s) required by the test: $test_required_examples" | tee -a $output_file
266*2f4d9adbSJeremy L Thompsonbuild_examples $test_required_examples || $exit_cmd 1
267*2f4d9adbSJeremy L Thompsonecho | tee -a $output_file
268*2f4d9adbSJeremy L Thompson
269*2f4d9adbSJeremy L Thompson## Loop over the number-of-processors list.
270*2f4d9adbSJeremy L Thompsonfor (( num_proc_idx = 0; num_proc_idx < num_proc_list_size; num_proc_idx++ ))
271*2f4d9adbSJeremy L Thompsondo
272*2f4d9adbSJeremy L Thompson
273*2f4d9adbSJeremy L Thompsonnum_proc_run="${num_proc_list[$num_proc_idx]}"
274*2f4d9adbSJeremy L Thompsonnum_proc_node="${num_proc_node_list[$num_proc_idx]}"
275*2f4d9adbSJeremy L Thompson
276*2f4d9adbSJeremy L Thompsonset_num_nodes || $exit_cmd 1
277*2f4d9adbSJeremy L Thompsoncompose_mpi_run_command
278*2f4d9adbSJeremy L Thompson
279*2f4d9adbSJeremy L Thompsonif [[ "$start_shell" = "yes" ]]; then
280*2f4d9adbSJeremy L Thompson   if [[ ! -t 1 ]]; then
281*2f4d9adbSJeremy L Thompson      echo "Standard output is not a terminal. Stop." | tee -a $output_file
282*2f4d9adbSJeremy L Thompson      $exit_cmd 1
283*2f4d9adbSJeremy L Thompson   fi
284*2f4d9adbSJeremy L Thompson   echo "Reading shell commands, type 'c' to continue, 'exit' to stop ..." | tee -a $output_file
285*2f4d9adbSJeremy L Thompson   echo | tee -a $output_file
286*2f4d9adbSJeremy L Thompson   cd "$cur_dir"
287*2f4d9adbSJeremy L Thompson   set -o emacs
288*2f4d9adbSJeremy L Thompson   PS1='$ '
289*2f4d9adbSJeremy L Thompson   [[ -r $HOME/.bashrc ]] && source $HOME/.bashrc
290*2f4d9adbSJeremy L Thompson   HISTFILE="$root_dir/.bash_history"
291*2f4d9adbSJeremy L Thompson   history -c
292*2f4d9adbSJeremy L Thompson   history -r
293*2f4d9adbSJeremy L Thompson   # bind '"\\C-i": menu-complete'
294*2f4d9adbSJeremy L Thompson   alias c='break'
295*2f4d9adbSJeremy L Thompson   while cwd="$PWD/" cwd="${cwd#${root_dir}/}" cwd="${cwd%/}" \
296*2f4d9adbSJeremy L Thompson         prompt="[${cyan}benchmarks$none:$blue$cwd$clear]\$ " && \
297*2f4d9adbSJeremy L Thompson         read -p "$prompt" -e line; do
298*2f4d9adbSJeremy L Thompson      history -s "$line"
299*2f4d9adbSJeremy L Thompson      history -w
300*2f4d9adbSJeremy L Thompson      shopt -q -s expand_aliases
301*2f4d9adbSJeremy L Thompson      eval "$line"
302*2f4d9adbSJeremy L Thompson      shopt -q -u expand_aliases
303*2f4d9adbSJeremy L Thompson   done
304*2f4d9adbSJeremy L Thompson   [[ "${#line}" -eq 0 ]] && { echo; $exit_cmd 0; }
305*2f4d9adbSJeremy L Thompson   shopt -q -u expand_aliases
306*2f4d9adbSJeremy L Thompson   echo "Continuing ..." | tee -a $output_file
307*2f4d9adbSJeremy L Thompsonfi
308*2f4d9adbSJeremy L Thompson
309*2f4d9adbSJeremy L Thompson# Call the function run_tests defined inside the $test_file
310*2f4d9adbSJeremy L Thompsonceed=$backend
311*2f4d9adbSJeremy L Thompsonif [ -z "$dry_run" ]; then
312*2f4d9adbSJeremy L Thompson   run_tests >> $output_file
313*2f4d9adbSJeremy L Thompsonelse
314*2f4d9adbSJeremy L Thompson   run_tests
315*2f4d9adbSJeremy L Thompsonfi
316*2f4d9adbSJeremy L Thompsonecho
317*2f4d9adbSJeremy L Thompson
318*2f4d9adbSJeremy L Thompsondone ## End of loop over processor numbers
319*2f4d9adbSJeremy L Thompson
320*2f4d9adbSJeremy L Thompsontrap - INT
321*2f4d9adbSJeremy L Thompson
322*2f4d9adbSJeremy L Thompson} ## run is on
323*2f4d9adbSJeremy L Thompson
324*2f4d9adbSJeremy L Thompson$exit_cmd 0
325*2f4d9adbSJeremy L Thompson
326*2f4d9adbSJeremy L Thompson) || {
327*2f4d9adbSJeremy L Thompson   echo "Sub-shell for backend '$backend' returned error code $?. Stop."
328*2f4d9adbSJeremy L Thompson   $exit_cmd 1
329*2f4d9adbSJeremy L Thompson}
330*2f4d9adbSJeremy L Thompsondone ## Loop over $backend_list
331*2f4d9adbSJeremy L Thompson
332*2f4d9adbSJeremy L Thompson
333*2f4d9adbSJeremy L Thompson$exit_cmd 0
334*2f4d9adbSJeremy L Thompson
335