xref: /linux/tools/testing/selftests/rcutorture/bin/kvm-series.sh (revision 6f7e6393d1ce636bb7ec77a7fe7b77458fddf701)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0+
3#
4# Usage: kvm-series.sh config-list commit-id-list [ kvm.sh parameters ]
5#
6# Tests the specified list of unadorned configs ("TREE01 SRCU-P" but not
7# "CFLIST" or "3*TRACE01") and an indication of a set of commits to test,
8# then runs each commit through the specified list of commits using kvm.sh.
9# The runs are grouped into a -series/config/commit directory tree.
10# Each run defaults to a duration of one minute.
11#
12# Run in top-level Linux source directory.  Please note that this is in
13# no way a replacement for "git bisect"!!!
14#
15# This script is intended to replace kvm-check-branches.sh by providing
16# ease of use and faster execution.
17
18T="`mktemp -d ${TMPDIR-/tmp}/kvm-series.sh.XXXXXX`"; export T
19trap 'rm -rf $T' 0
20
21scriptname=$0
22args="$*"
23
24config_list="${1}"
25if test -z "${config_list}"
26then
27	echo "$0: Need a quoted list of --config arguments for first argument."
28	exit 1
29fi
30if test -z "${config_list}" || echo "${config_list}" | grep -q '\*'
31then
32	echo "$0: Repetition ('*') not allowed in config list."
33	exit 1
34fi
35config_list_len="`echo ${config_list} | wc -w | awk '{ print $1; }'`"
36
37commit_list="${2}"
38if test -z "${commit_list}"
39then
40	echo "$0: Need a list of commits (e.g., HEAD^^^..) for second argument."
41	exit 2
42fi
43git log --pretty=format:"%h" "${commit_list}" > $T/commits
44ret=$?
45if test "${ret}" -ne 0
46then
47	echo "$0: Invalid commit list ('${commit_list}')."
48	exit 2
49fi
50sha1_list=`cat $T/commits`
51sha1_list_len="`echo ${sha1_list} | wc -w | awk '{ print $1; }'`"
52
53shift
54shift
55
56RCUTORTURE="`pwd`/tools/testing/selftests/rcutorture"; export RCUTORTURE
57PATH=${RCUTORTURE}/bin:$PATH; export PATH
58RES="${RCUTORTURE}/res"; export RES
59. functions.sh
60
61ret=0
62nbuildfail=0
63nrunfail=0
64nsuccess=0
65ncpus=0
66buildfaillist=
67runfaillist=
68successlist=
69cursha1="`git rev-parse --abbrev-ref HEAD`"
70ds="`date +%Y.%m.%d-%H.%M.%S`-series"
71DS="${RES}/${ds}"; export DS
72startdate="`date`"
73starttime="`get_starttime`"
74
75echo " --- " $scriptname $args | tee -a $T/log
76echo " --- Results directory: " $ds | tee -a $T/log
77
78# Do all builds.  Iterate through commits within a given scenario
79# because builds normally go faster from one commit to the next within a
80# given scenario.  In contrast, switching scenarios on each rebuild will
81# often force a full rebuild due to Kconfig differences, for example,
82# turning preemption on and off.  Defer actual runs in order to run
83# lots of them concurrently on large systems.
84touch $T/torunlist
85n2build="$((config_list_len*sha1_list_len))"
86nbuilt=0
87for config in ${config_list}
88do
89	sha_n=0
90	for sha in ${sha1_list}
91	do
92		sha1=${sha_n}.${sha} # Enable "sort -k1nr" to list commits in order.
93		echo
94		echo Starting ${config}/${sha1} "($((nbuilt+1)) of ${n2build})" at `date` | tee -a $T/log
95		git checkout --detach "${sha}"
96		tools/testing/selftests/rcutorture/bin/kvm.sh --configs "$config" --datestamp "$ds/${config}/${sha1}" --duration 1 --build-only --trust-make "$@"
97		curret=$?
98		if test "${curret}" -ne 0
99		then
100			nbuildfail=$((nbuildfail+1))
101			buildfaillist="$buildfaillist ${config}/${sha1}(${curret})"
102		else
103			batchncpus="`grep -v "^# cpus=" "${DS}/${config}/${sha1}/batches" | awk '{ sum += $3 } END { print sum }'`"
104			echo run_one_qemu ${sha_n} ${config}/${sha1} ${batchncpus} >> $T/torunlist
105			if test "${ncpus}" -eq 0
106			then
107				ncpus="`grep "^# cpus=" "${DS}/${config}/${sha1}/batches" | sed -e 's/^# cpus=//'`"
108				case "${ncpus}" in
109				^[0-9]*$)
110					;;
111				*)
112					ncpus=0
113					;;
114				esac
115			fi
116		fi
117		if test "${ret}" -eq 0
118		then
119			ret=${curret}
120		fi
121		sha_n=$((sha_n+1))
122		nbuilt=$((nbuilt+1))
123	done
124done
125
126# If the user did not specify the number of CPUs, use them all.
127if test "${ncpus}" -eq 0
128then
129	ncpus="`identify_qemu_vcpus`"
130fi
131
132cpusused=0
133touch $T/successlistfile
134touch $T/faillistfile
135n2run="`wc -l $T/torunlist | awk '{ print $1; }'`"
136nrun=0
137
138# do_run_one_qemu ds resultsdir qemu_curout
139#
140# Start the specified qemu run and record its success or failure.
141do_run_one_qemu () {
142	local ret
143	local ds="$1"
144	local resultsdir="$2"
145	local qemu_curout="$3"
146
147	tools/testing/selftests/rcutorture/bin/kvm-again.sh "${DS}/${resultsdir}" --link inplace-force > ${qemu_curout} 2>&1
148	ret=$?
149	if test "${ret}" -eq 0
150	then
151		echo ${resultsdir} >> $T/successlistfile
152		# Successful run, so remove large files.
153		rm -f ${DS}/${resultsdir}/{vmlinux,bzImage,System.map,Module.symvers}
154	else
155		echo "${resultsdir}(${ret})" >> $T/faillistfile
156	fi
157}
158
159# cleanup_qemu_batch batchncpus
160#
161# Update success and failure lists, files, and counts at the end of
162# a batch.
163cleanup_qemu_batch () {
164	local batchncpus="$1"
165
166	echo Waiting, cpusused=${cpusused}, ncpus=${ncpus} `date` | tee -a $T/log
167	wait
168	cpusused="${batchncpus}"
169	nsuccessbatch="`wc -l $T/successlistfile | awk '{ print $1 }'`"
170	nsuccess=$((nsuccess+nsuccessbatch))
171	successlist="$successlist `cat $T/successlistfile`"
172	rm $T/successlistfile
173	touch $T/successlistfile
174	nfailbatch="`wc -l $T/faillistfile | awk '{ print $1 }'`"
175	nrunfail=$((nrunfail+nfailbatch))
176	runfaillist="$runfaillist `cat $T/faillistfile`"
177	rm $T/faillistfile
178	touch $T/faillistfile
179}
180
181# run_one_qemu sha_n config/sha1 batchncpus
182#
183# Launch into the background the sha_n-th qemu job whose results directory
184# is config/sha1 and which uses batchncpus CPUs.  Once we reach a job that
185# would overflow the number of available CPUs, wait for the previous jobs
186# to complete and record their results.
187run_one_qemu () {
188	local sha_n="$1"
189	local config_sha1="$2"
190	local batchncpus="$3"
191	local qemu_curout
192
193	cpusused=$((cpusused+batchncpus))
194	if test "${cpusused}" -gt $ncpus
195	then
196		cleanup_qemu_batch "${batchncpus}"
197	fi
198	echo Starting ${config_sha1} using ${batchncpus} CPUs "($((nrun+1)) of ${n2run})" `date`
199	qemu_curout="${DS}/${config_sha1}/qemu-series"
200	do_run_one_qemu "$ds" "${config_sha1}" ${qemu_curout} &
201	nrun="$((nrun+1))"
202}
203
204# Re-ordering the runs will mess up the affinity chosen at build time
205# (among other things, over-using CPU 0), so suppress it.
206TORTURE_NO_AFFINITY="no-affinity"; export TORTURE_NO_AFFINITY
207
208# Run the kernels (if any) that built correctly.
209echo | tee -a $T/log # Put a blank line between build and run messages.
210. $T/torunlist
211cleanup_qemu_batch "${batchncpus}"
212
213# Get back to initial checkout/SHA-1.
214git checkout "${cursha1}"
215
216# Throw away leading and trailing space characters for fmt.
217successlist="`echo ${successlist} | sed -e 's/^ *//' -e 's/ *$//'`"
218buildfaillist="`echo ${buildfaillist} | sed -e 's/^ *//' -e 's/ *$//'`"
219runfaillist="`echo ${runfaillist} | sed -e 's/^ *//' -e 's/ *$//'`"
220
221# Print lists of successes, build failures, and run failures, if any.
222if test "${nsuccess}" -gt 0
223then
224	echo | tee -a $T/log
225	echo ${nsuccess} SUCCESSES: | tee -a $T/log
226	echo ${successlist} | fmt | tee -a $T/log
227fi
228if test "${nbuildfail}" -gt 0
229then
230	echo | tee -a $T/log
231	echo ${nbuildfail} BUILD FAILURES: | tee -a $T/log
232	echo ${buildfaillist} | fmt | tee -a $T/log
233fi
234if test "${nrunfail}" -gt 0
235then
236	echo | tee -a $T/log
237	echo ${nrunfail} RUN FAILURES: | tee -a $T/log
238	echo ${runfaillist} | fmt | tee -a $T/log
239fi
240
241# If there were build or runtime failures, map them to commits.
242if test "${nbuildfail}" -gt 0 || test "${nrunfail}" -gt 0
243then
244	echo | tee -a $T/log
245	echo Build failures across commits: | tee -a $T/log
246	echo ${buildfaillist} | tr ' ' '\012' | sed -e 's,^[^/]*/,,' -e 's/([0-9]*)//' |
247		sort | uniq -c | sort -k2n | tee -a $T/log
248fi
249
250# Print run summary.
251echo | tee -a $T/log
252echo Started at $startdate, ended at `date`, duration `get_starttime_duration $starttime`. | tee -a $T/log
253echo Summary: Successes: ${nsuccess} " "Build Failures: ${nbuildfail} " "Runtime Failures: ${nrunfail}| tee -a $T/log
254cp $T/log ${DS}
255
256exit "${ret}"
257