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