#!/bin/bash # Clean: shellcheck -e 2001 ./tcwg-benchmark.sh set -eux scripts=$(dirname "$0") # shellcheck source=jenkins-helpers.sh . $scripts/jenkins-helpers.sh convert_args_to_variables "$@" obligatory_variables \ boardname \ image_arch \ toolchain_url \ bench_list \ cflags \ ldflags \ extension \ testmode \ iterations \ run_profile \ sysroot \ forceinstall \ builder \ results_id \ BUILD_NUMBER \ WORKSPACE \ reboot \ ignore_errors \ clean_older_than declare -g \ boardname \ image_arch \ toolchain_url \ bench_list \ cflags \ ldflags \ extension \ testmode \ iterations \ run_profile \ sysroot \ forceinstall \ builder \ results_id \ BUILD_NUMBER \ WORKSPACE \ reboot \ ignore_errors \ clean_older_than # Make shellcheck happy and workaround Jenkins not defining variables # for empty arguments. bench_container_tag="${bench_container_tag-bionic}" build_container_tag="${build_container_tag-bionic}" toolchain_type="${toolchain_type-auto}" prepare_board="${prepare_board-true}" if echo "$builder" | grep -q ".*-[0-9]\+"; then docker_host_opt="--arch amd64 --node $builder" else docker_host_opt="--label $builder" fi # shellcheck source=jenkins-helpers.sh . $scripts/jenkins-helpers.sh # If $toolchain_url is of ssh:// type, don't create a remote build # container, just use the ssh command as provided. build_container_host= build_container_port= case "$toolchain_url" in "ssh://"*) ccprefix="${toolchain_url##ssh://}" # Extract host:port: specification from ccprefix, we don't # need to care about :parallelize here, just pass it to run.sh # if present. build=${ccprefix%:*} build_container_host="$(echo $build | cut -d: -f 1)" case ${ccprefix} in *:*:*) build_container_port="$(echo $build | cut -s -d: -f 2)" ;; *:*) # If no port is specified, use 22 (ssh default port) build_container_port=22 ;; esac if [ "x$build_container_host" = "x" ]; then echo "ERROR: ssh:// toolchain_url lacks a host: $toolchain_url." exit 1 fi if [ "x$build_container_port" = "x" ]; then echo "ERROR: ssh:// toolchain_url lacks a port: $toolchain_url." exit 1 fi ;; *) # Make sure to cleanup build container if something goes # wrong when preparing the test environment trap "cleanup_all_containers" EXIT $scripts/start-container-docker.sh $docker_host_opt --distro "$build_container_tag" --task build --prefix build_ > build-container.sh . ./build-container.sh ;; esac case "$toolchain_url" in "ssh://"*) if [ x"$sysroot" = x"tarball" ]; then echo "ERROR: Unsupported sysroot $sysroot for toolchain_url $toolchain_url" exit 1 fi # Last component of ccprefix is the path, keep it toolchaindir="$(dirname ${ccprefix##*:})" ;; "http://"*".tar.xz"|"https://"*".tar.xz") toolchaindir=$(untar_url "$toolchain_url" "$WORKSPACE" "--strip-components 1") ;; "rsync://"*) ccprefix="${toolchain_url##rsync://}" # We want to access the remote toolchain via a container, to # avoid problems with the hosts's ssh server restrictions on the # number of simulaneous connexions. # We copy it to the build container (assuming it uses the same # architecture as the machine pointed to by $toolchain_url). # Assume ccprefix looks like /path/bin/target-triplet-, and # compute 'path'. src_toolchaindir=$(dirname "$(dirname ${ccprefix})") toolchaindir="${WORKSPACE}/toolchain-${BUILD_NUMBER}" rsync -az --delete "$src_toolchaindir/" "$toolchaindir/" ;; *) echo "ERROR: Cannot handle toolchain_url: $toolchain_url" exit 1 ;; esac # Sanity check that toolchain_type is supported case "$toolchain_type" in gnu|llvm) ;; *) echo "ERROR: Unsupported toolchain type: $toolchain_type" exit 1 ;; esac case "$toolchain_url" in "http://"*|"https://"*|"rsync://"*|"ssh://"*) # In the ssh:// case, we have to perform the 'find' operations # remotely. case "$toolchain_url" in "ssh://"*) maybe_remote="ssh -p $build_container_port $build_container_host" ;; *) maybe_remote="" ;; esac case "$toolchain_type" in "gnu"|"llvm") ;; "auto") if [ x"$($maybe_remote find "$toolchaindir" -path "*bin/*gcc" | wc -l)" != x"0" ]; then toolchain_type="gnu" elif [ x"$($maybe_remote find "$toolchaindir" -path "*bin/*clang" | wc -l)" != x"0" ]; then toolchain_type="llvm" else echo "ERROR: Cannot autodetect toolchain type" exit 1 fi ;; esac case "$toolchain_type" in "gnu") ccname="gcc" ;; "llvm") ccname="clang" ;; esac ccpath=$($maybe_remote find "$toolchaindir" -path "*bin/*$ccname") if [ "$(echo "$ccpath" | wc -w)" -ne 1 ]; then echo "ERROR: found more than one compiler: $ccpath" exit 1 fi # Non-ssh:// cases have to copy the just-copied toolchain to # the remote build container. For ssh://, we'll access the # toolchain remotely. case "$toolchain_url" in "ssh://"*) ;; *) ccprefix=$(echo "$ccpath" | sed -e "s/$ccname\$//") # Copy toolchain to the build container. rsync -a --delete -e "ssh -p$build_container_port" "$toolchaindir/" "$build_container_host:$toolchaindir/" ccprefix="$build_container_host:$build_container_port:$ccprefix" ;; esac ;; esac case "$sysroot" in "tarball") sysroot="$build_container_host:$build_container_port:$(find "$toolchaindir" -name "libc")" ;; "http://"*|"https://"*) sysrootdir=$(untar_url "$sysroot" "$WORKSPACE" "--strip-components 1") # Copy toolchain to the build container. rsync -a --delete -e "ssh -p$build_container_port" "$sysrootdir/" "$build_container_host:$sysrootdir/" sysroot="$build_container_host:$build_container_port:$sysrootdir" ;; "ssh://"*) sysroot="${sysroot##ssh://}" # Check host:port specification from sysroot. case ${sysroot} in *:*) ;; *) echo "ERROR: ssh:// sysroot lacks a host: $sysroot" exit 1 ;; esac ;; "") # Use system sysroot. ;; *) echo "ERROR: Cannot handle sysroot: $sysroot" exit 1 ;; esac if echo "$results_id" | grep -q "\.\."; then echo "ERROR: results_id should not escape /home/tcwg-benchmark/results* hierarchy; do not use \"..\"" exit 1 fi hw_tag="${results_id%%/*}" case "$hw_tag:$boardname:$image_arch" in sq_32:*-sq-*:armhf) ;; sq_64:*-sq-*:arm64) ;; tk1_32:*-tk1-*:armhf) ;; tx1_64:*-tx1-*:arm64) ;; tx1_32:*-tx1-*:armhf) ;; *) echo "ERROR: results_id does not start with a valid hw_tag: $hw_tag" exit 1 ;; esac # Check that we can ssh to the board and rsync scripts. This ensures that # the board is online and filesystem is good condition. Try to reboot and/or # power-cycle the board as needed. if $reboot; then # 1. Try access after soft reboot # 2. Try access after power-cycle tries_left=2 else # 1. Try access without rebooting # 2. Try access after soft reboot # 3. Try access after power-cycle tries_left=3 fi force_power_cycle=false while [ $tries_left != 0 ]; do tries_left=$(($tries_left-1)) if $reboot; then if ! ssh "$boardname" true || $force_power_cycle; then echo "Trying to power-cycle $boardname" ( pdu_name=$(echo "${boardname%.tcwglab}" \ | sed -e 's/^tcwg-bmk-/tcwg-/') nvidia-power-cycle.sh "$pdu_name" wait_for_ssh_server "$boardname" 22 100 ) & wait $! || exit $EXTERNAL_FAIL echo "Successfully powered-cycled $boardname" else # Reboot the board. # Ping board every second (ServerAliveInterval=1) to avoid # waiting [default] 5min for ssh to break connection. ssh -Snone -oServerAliveInterval=1 $boardname sudo /sbin/reboot \ || true # Wait until the ssh server is ready sleep 30 # Give time to the board to shutdown ret=0 wait_for_ssh_server $boardname 22 100 || ret=$? if [ $ret != 0 ]; then echo "SSH server did not respond after reboot, exiting." exit $EXTERNAL_FAIL fi fi fi rsync -az --delete bmk-scripts/ "$boardname:bmk-scripts/" & res=0 && wait $! || res=$? if [ $res = 0 ]; then break else reboot=true if [ x"$tries_left" = x"1" ]; then force_power_cycle=true fi fi done if [ $res != 0 ]; then echo "ERROR: Could not get board online" exit $EXTERNAL_FAIL fi case "$testmode" in build|verify) input_size="test" ;; benchmark) input_size="ref" ;; esac if $prepare_board; then # FIXME: Implement more configurations and checks: # disable swap # set interrupt affinity # check that there are no stray processes # test that taskset works remote_exec "$boardname:::-t -Snone" \ sudo /usr/local/bin/benchmark.sh --hw_tag "$hw_tag" \ --action start_board --verbose \ --image "linaro/ci-$image_arch-tcwg-build-ubuntu:$bench_container_tag" & res=0 && wait $! || res=$? if [ $res != 0 ]; then echo "ERROR: Could not prepare board for benchmarking" exit $EXTERNAL_FAIL fi fi # Start a container to run the benchmarks in. # We install SPEC in /home/tcwg-benchmark, so bind-mount it as $WORKSPACE. WORKSPACE=$HOME $scripts/start-container-docker.sh --session-host "$boardname" --arch "$image_arch" --distro "$bench_container_tag" --task bench --docker_opts "--privileged" --prefix run_ > run-container.sh & res=0 && wait $! || res=$? if [ $res != 0 ]; then echo "ERROR: Could not start benchmarking container" exit $EXTERNAL_FAIL fi trap "cleanup_all_containers" EXIT . ./run-container.sh # vars are from run-container.sh sourced above # shellcheck disable=SC2154 remote_exec "$run_container_host:$run_container_port::-t -Snone" \ bmk-scripts/run.sh \ --bench "$bench_list" \ --config "${BUILD_NUMBER}-$run_profile" \ --cflags "$cflags" \ --ldflags "$ldflags" \ --ccprefix "$ccprefix" \ --extension "$extension" \ --hw_tag "$hw_tag" \ --ignore_errors "$ignore_errors" \ --input_size "$input_size" \ --iterations "$iterations" \ --run_profile "$run_profile" \ ${sysroot:+--sysroot "$sysroot"} \ --toolchain "$toolchain_type" \ --resultsdest "bkp-01.tcwglab:/home/tcwg-benchmark/results-${results_id}/$boardname" \ --nodename "$boardname" \ --forceinstall "${forceinstall}" \ ${clean_older_than:+--clean_older_than "$clean_older_than"} \ --verbose true if $prepare_board; then remote_exec "$boardname:::-t -Snone" \ sudo /usr/local/bin/benchmark.sh --action stop_board --verbose & res=0 && wait $! || res=$? if [ $res != 0 ]; then echo "Warning: prepare-board.sh did not finish cleanly" fi fi