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