| #!/bin/bash |
| # SPDX-License-Identifier: GPL-2.0+ |
| # |
| # Usage: kvm-series.sh config-list commit-id-range [ kvm.sh parameters ] |
| # |
| # Tests the specified list of unadorned configs ("TREE01 SRCU-P" but |
| # not "CFLIST" or "3*TRACE01") and an indication of a range of commits |
| # ("v7.0-rc1..rcu/dev", but not "cd0ce7bab0408 ff74db28df623 17c52d7b31a1f") |
| # to test, then runs each commit through the specified list of commits using |
| # kvm.sh. The runs are grouped into a -series/config/commit directory tree. |
| # Each run defaults to a duration of one minute. |
| # |
| # Run in top-level Linux source directory. Please note that this is in |
| # no way a replacement for "git bisect"!!! |
| # |
| # This script is intended to replace kvm-check-branches.sh by providing |
| # ease of use and faster execution. |
| |
| T="`mktemp -d ${TMPDIR-/tmp}/kvm-series.sh.XXXXXX`"; export T |
| trap 'rm -rf $T' 0 |
| |
| scriptname=$0 |
| args="$*" |
| |
| config_list="${1}" |
| if test -z "${config_list}" |
| then |
| echo "$0: Need a quoted list of --config arguments for first argument." |
| exit 1 |
| fi |
| if test -z "${config_list}" || echo "${config_list}" | grep -q '\*' |
| then |
| echo "$0: Repetition ('*') not allowed in config list." |
| exit 1 |
| fi |
| config_list_len="`echo ${config_list} | wc -w | awk '{ print $1; }'`" |
| |
| commit_list="${2}" |
| if test -z "${commit_list}" |
| then |
| echo "$0: Need a list of commits (e.g., HEAD^^^..) for second argument." |
| exit 2 |
| fi |
| git log --pretty=format:"%h" "${commit_list}" > $T/commits |
| ret=$? |
| if test "${ret}" -ne 0 |
| then |
| echo "$0: Invalid commit list ('${commit_list}')." |
| exit 2 |
| fi |
| sha1_list=`cat $T/commits` |
| sha1_list_len="`echo ${sha1_list} | wc -w | awk '{ print $1; }'`" |
| |
| shift |
| shift |
| |
| RCUTORTURE="`pwd`/tools/testing/selftests/rcutorture"; export RCUTORTURE |
| PATH=${RCUTORTURE}/bin:$PATH; export PATH |
| RES="${RCUTORTURE}/res"; export RES |
| . functions.sh |
| |
| ret=0 |
| nbuildfail=0 |
| nrunfail=0 |
| nsuccess=0 |
| ncpus=0 |
| buildfaillist= |
| runfaillist= |
| successlist= |
| cursha1="`git rev-parse --abbrev-ref HEAD`" |
| ds="`date +%Y.%m.%d-%H.%M.%S`-series" |
| DS="${RES}/${ds}"; export DS |
| startdate="`date`" |
| starttime="`get_starttime`" |
| |
| echo " --- " $scriptname $args | tee -a $T/log |
| echo " --- Results directory: " $ds | tee -a $T/log |
| |
| # Do all builds. Iterate through commits within a given scenario |
| # because builds normally go faster from one commit to the next within a |
| # given scenario. In contrast, switching scenarios on each rebuild will |
| # often force a full rebuild due to Kconfig differences, for example, |
| # turning preemption on and off. Defer actual runs in order to run |
| # lots of them concurrently on large systems. |
| touch $T/torunlist |
| n2build="$((config_list_len*sha1_list_len))" |
| nbuilt=0 |
| for config in ${config_list} |
| do |
| sha_n=0 |
| for sha in ${sha1_list} |
| do |
| sha1=${sha_n}.${sha} # Enable "sort -k1nr" to list commits in order. |
| echo |
| echo Starting ${config}/${sha1} "($((nbuilt+1)) of ${n2build})" at `date` | tee -a $T/log |
| git checkout --detach "${sha}" |
| tools/testing/selftests/rcutorture/bin/kvm.sh --configs "$config" --datestamp "$ds/${config}/${sha1}" --duration 1 --build-only --trust-make "$@" |
| curret=$? |
| if test "${curret}" -ne 0 |
| then |
| nbuildfail=$((nbuildfail+1)) |
| buildfaillist="$buildfaillist ${config}/${sha1}(${curret})" |
| else |
| batchncpus="`grep -v "^# cpus=" "${DS}/${config}/${sha1}/batches" | awk '{ sum += $3 } END { print sum }'`" |
| echo run_one_qemu ${sha_n} ${config}/${sha1} ${batchncpus} >> $T/torunlist |
| if test "${ncpus}" -eq 0 |
| then |
| ncpus="`grep "^# cpus=" "${DS}/${config}/${sha1}/batches" | sed -e 's/^# cpus=//'`" |
| case "${ncpus}" in |
| ^[0-9]*$) |
| ;; |
| *) |
| ncpus=0 |
| ;; |
| esac |
| fi |
| fi |
| if test "${ret}" -eq 0 |
| then |
| ret=${curret} |
| fi |
| sha_n=$((sha_n+1)) |
| nbuilt=$((nbuilt+1)) |
| done |
| done |
| |
| # If the user did not specify the number of CPUs, use them all. |
| if test "${ncpus}" -eq 0 |
| then |
| ncpus="`identify_qemu_vcpus`" |
| fi |
| |
| cpusused=0 |
| touch $T/successlistfile |
| touch $T/faillistfile |
| n2run="`wc -l $T/torunlist | awk '{ print $1; }'`" |
| nrun=0 |
| |
| # do_run_one_qemu ds resultsdir qemu_curout |
| # |
| # Start the specified qemu run and record its success or failure. |
| do_run_one_qemu () { |
| local ret |
| local ds="$1" |
| local resultsdir="$2" |
| local qemu_curout="$3" |
| |
| tools/testing/selftests/rcutorture/bin/kvm-again.sh "${DS}/${resultsdir}" --link inplace-force > ${qemu_curout} 2>&1 |
| ret=$? |
| if test "${ret}" -eq 0 |
| then |
| echo ${resultsdir} >> $T/successlistfile |
| # Successful run, so remove large files. |
| rm -f ${DS}/${resultsdir}/{vmlinux,bzImage,System.map,Module.symvers} |
| else |
| echo "${resultsdir}(${ret})" >> $T/faillistfile |
| fi |
| } |
| |
| # cleanup_qemu_batch batchncpus |
| # |
| # Update success and failure lists, files, and counts at the end of |
| # a batch. |
| cleanup_qemu_batch () { |
| local batchncpus="$1" |
| |
| echo Waiting, cpusused=${cpusused}, ncpus=${ncpus} `date` | tee -a $T/log |
| wait |
| cpusused="${batchncpus}" |
| nsuccessbatch="`wc -l $T/successlistfile | awk '{ print $1 }'`" |
| nsuccess=$((nsuccess+nsuccessbatch)) |
| successlist="$successlist `cat $T/successlistfile`" |
| rm $T/successlistfile |
| touch $T/successlistfile |
| nfailbatch="`wc -l $T/faillistfile | awk '{ print $1 }'`" |
| nrunfail=$((nrunfail+nfailbatch)) |
| runfaillist="$runfaillist `cat $T/faillistfile`" |
| rm $T/faillistfile |
| touch $T/faillistfile |
| } |
| |
| # run_one_qemu sha_n config/sha1 batchncpus |
| # |
| # Launch into the background the sha_n-th qemu job whose results directory |
| # is config/sha1 and which uses batchncpus CPUs. Once we reach a job that |
| # would overflow the number of available CPUs, wait for the previous jobs |
| # to complete and record their results. |
| run_one_qemu () { |
| local sha_n="$1" |
| local config_sha1="$2" |
| local batchncpus="$3" |
| local qemu_curout |
| |
| cpusused=$((cpusused+batchncpus)) |
| if test "${cpusused}" -gt $ncpus |
| then |
| cleanup_qemu_batch "${batchncpus}" |
| fi |
| echo Starting ${config_sha1} using ${batchncpus} CPUs "($((nrun+1)) of ${n2run})" `date` |
| qemu_curout="${DS}/${config_sha1}/qemu-series" |
| do_run_one_qemu "$ds" "${config_sha1}" ${qemu_curout} & |
| nrun="$((nrun+1))" |
| } |
| |
| # Re-ordering the runs will mess up the affinity chosen at build time |
| # (among other things, over-using CPU 0), so suppress it. |
| TORTURE_NO_AFFINITY="no-affinity"; export TORTURE_NO_AFFINITY |
| |
| # Run the kernels (if any) that built correctly. |
| echo | tee -a $T/log # Put a blank line between build and run messages. |
| . $T/torunlist |
| cleanup_qemu_batch "${batchncpus}" |
| |
| # Get back to initial checkout/SHA-1. |
| git checkout "${cursha1}" |
| |
| # Throw away leading and trailing space characters for fmt. |
| successlist="`echo ${successlist} | sed -e 's/^ *//' -e 's/ *$//'`" |
| buildfaillist="`echo ${buildfaillist} | sed -e 's/^ *//' -e 's/ *$//'`" |
| runfaillist="`echo ${runfaillist} | sed -e 's/^ *//' -e 's/ *$//'`" |
| |
| # Print lists of successes, build failures, and run failures, if any. |
| if test "${nsuccess}" -gt 0 |
| then |
| echo | tee -a $T/log |
| echo ${nsuccess} SUCCESSES: | tee -a $T/log |
| echo ${successlist} | fmt | tee -a $T/log |
| fi |
| if test "${nbuildfail}" -gt 0 |
| then |
| echo | tee -a $T/log |
| echo ${nbuildfail} BUILD FAILURES: | tee -a $T/log |
| echo ${buildfaillist} | fmt | tee -a $T/log |
| fi |
| if test "${nrunfail}" -gt 0 |
| then |
| echo | tee -a $T/log |
| echo ${nrunfail} RUN FAILURES: | tee -a $T/log |
| echo ${runfaillist} | fmt | tee -a $T/log |
| fi |
| |
| # If there were build or runtime failures, map them to commits. |
| if test "${nbuildfail}" -gt 0 || test "${nrunfail}" -gt 0 |
| then |
| echo | tee -a $T/log |
| echo Build failures across commits: | tee -a $T/log |
| echo ${buildfaillist} | tr ' ' '\012' | sed -e 's,^[^/]*/,,' -e 's/([0-9]*)//' | |
| sort | uniq -c | sort -k2n | tee -a $T/log |
| fi |
| |
| # Print run summary. |
| echo | tee -a $T/log |
| echo Started at $startdate, ended at `date`, duration `get_starttime_duration $starttime`. | tee -a $T/log |
| echo Summary: Successes: ${nsuccess} " "Build Failures: ${nbuildfail} " "Runtime Failures: ${nrunfail}| tee -a $T/log |
| cp $T/log ${DS} |
| |
| exit "${ret}" |