1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0+
3#
4# Run a series of tests under KVM.  By default, this series is specified
5# by the relevant CFLIST file, but can be overridden by the --configs
6# command-line argument.
7#
8# Usage: kvm.sh [ options ]
9#
10# Copyright (C) IBM Corporation, 2011
11#
12# Authors: Paul E. McKenney <paulmck@linux.ibm.com>
13
14scriptname=$0
15args="$*"
16
17T=${TMPDIR-/tmp}/kvm.sh.$$
18trap 'rm -rf $T' 0
19mkdir $T
20
21cd `dirname $scriptname`/../../../../../
22
23dur=$((30*60))
24dryrun=""
25KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM
26PATH=${KVM}/bin:$PATH; export PATH
27. functions.sh
28
29TORTURE_ALLOTED_CPUS="`identify_qemu_vcpus`"
30TORTURE_DEFCONFIG=defconfig
31TORTURE_BOOT_IMAGE=""
32TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD
33TORTURE_KCONFIG_ARG=""
34TORTURE_KCONFIG_GDB_ARG=""
35TORTURE_BOOT_GDB_ARG=""
36TORTURE_QEMU_GDB_ARG=""
37TORTURE_KCONFIG_KASAN_ARG=""
38TORTURE_KCONFIG_KCSAN_ARG=""
39TORTURE_KMAKE_ARG=""
40TORTURE_QEMU_MEM=512
41TORTURE_SHUTDOWN_GRACE=180
42TORTURE_SUITE=rcu
43TORTURE_TRUST_MAKE=""
44resdir=""
45configs=""
46cpus=0
47ds=`date +%Y.%m.%d-%H.%M.%S`
48jitter="-1"
49
50startdate="`date`"
51starttime="`get_starttime`"
52
53usage () {
54	echo "Usage: $scriptname optional arguments:"
55	echo "       --allcpus"
56	echo "       --bootargs kernel-boot-arguments"
57	echo "       --bootimage relative-path-to-kernel-boot-image"
58	echo "       --buildonly"
59	echo "       --configs \"config-file list w/ repeat factor (3*TINY01)\""
60	echo "       --cpus N"
61	echo "       --datestamp string"
62	echo "       --defconfig string"
63	echo "       --dryrun batches|sched|script"
64	echo "       --duration minutes | <seconds>s | <hours>h | <days>d"
65	echo "       --gdb"
66	echo "       --help"
67	echo "       --interactive"
68	echo "       --jitter N [ maxsleep (us) [ maxspin (us) ] ]"
69	echo "       --kconfig Kconfig-options"
70	echo "       --kmake-arg kernel-make-arguments"
71	echo "       --mac nn:nn:nn:nn:nn:nn"
72	echo "       --memory megabytes|nnnG"
73	echo "       --no-initrd"
74	echo "       --qemu-args qemu-arguments"
75	echo "       --qemu-cmd qemu-system-..."
76	echo "       --results absolute-pathname"
77	echo "       --torture lock|rcu|rcuscale|refscale|scf"
78	echo "       --trust-make"
79	exit 1
80}
81
82while test $# -gt 0
83do
84	case "$1" in
85	--allcpus)
86		cpus=$TORTURE_ALLOTED_CPUS
87		max_cpus=$TORTURE_ALLOTED_CPUS
88		;;
89	--bootargs|--bootarg)
90		checkarg --bootargs "(list of kernel boot arguments)" "$#" "$2" '.*' '^--'
91		TORTURE_BOOTARGS="$TORTURE_BOOTARGS $2"
92		shift
93		;;
94	--bootimage)
95		checkarg --bootimage "(relative path to kernel boot image)" "$#" "$2" '[a-zA-Z0-9][a-zA-Z0-9_]*' '^--'
96		TORTURE_BOOT_IMAGE="$2"
97		shift
98		;;
99	--buildonly|--build-only)
100		TORTURE_BUILDONLY=1
101		;;
102	--configs|--config)
103		checkarg --configs "(list of config files)" "$#" "$2" '^[^/]\+$' '^--'
104		configs="$configs $2"
105		shift
106		;;
107	--cpus)
108		checkarg --cpus "(number)" "$#" "$2" '^[0-9]*$' '^--'
109		cpus=$2
110		TORTURE_ALLOTED_CPUS="$2"
111		max_cpus="`identify_qemu_vcpus`"
112		if test "$TORTURE_ALLOTED_CPUS" -gt "$max_cpus"
113		then
114			TORTURE_ALLOTED_CPUS=$max_cpus
115		fi
116		shift
117		;;
118	--datestamp)
119		checkarg --datestamp "(relative pathname)" "$#" "$2" '^[a-zA-Z0-9._-/]*$' '^--'
120		ds=$2
121		shift
122		;;
123	--defconfig)
124		checkarg --defconfig "defconfigtype" "$#" "$2" '^[^/][^/]*$' '^--'
125		TORTURE_DEFCONFIG=$2
126		shift
127		;;
128	--dryrun)
129		checkarg --dryrun "batches|sched|script" $# "$2" 'batches\|sched\|script' '^--'
130		dryrun=$2
131		shift
132		;;
133	--duration)
134		checkarg --duration "(minutes)" $# "$2" '^[0-9][0-9]*\(s\|m\|h\|d\|\)$' '^error'
135		mult=60
136		if echo "$2" | grep -q 's$'
137		then
138			mult=1
139		elif echo "$2" | grep -q 'h$'
140		then
141			mult=3600
142		elif echo "$2" | grep -q 'd$'
143		then
144			mult=86400
145		fi
146		ts=`echo $2 | sed -e 's/[smhd]$//'`
147		dur=$(($ts*mult))
148		shift
149		;;
150	--gdb)
151		TORTURE_KCONFIG_GDB_ARG="CONFIG_DEBUG_INFO=y"; export TORTURE_KCONFIG_GDB_ARG
152		TORTURE_BOOT_GDB_ARG="nokaslr"; export TORTURE_BOOT_GDB_ARG
153		TORTURE_QEMU_GDB_ARG="-s -S"; export TORTURE_QEMU_GDB_ARG
154		;;
155	--help|-h)
156		usage
157		;;
158	--interactive)
159		TORTURE_QEMU_INTERACTIVE=1; export TORTURE_QEMU_INTERACTIVE
160		;;
161	--jitter)
162		checkarg --jitter "(# threads [ sleep [ spin ] ])" $# "$2" '^-\{,1\}[0-9]\+\( \+[0-9]\+\)\{,2\} *$' '^error$'
163		jitter="$2"
164		shift
165		;;
166	--kconfig|--kconfigs)
167		checkarg --kconfig "(Kconfig options)" $# "$2" '^CONFIG_[A-Z0-9_]\+=\([ynm]\|[0-9]\+\)\( CONFIG_[A-Z0-9_]\+=\([ynm]\|[0-9]\+\)\)*$' '^error$'
168		TORTURE_KCONFIG_ARG="`echo "$TORTURE_KCONFIG_ARG $2" | sed -e 's/^ *//' -e 's/ *$//'`"
169		shift
170		;;
171	--kasan)
172		TORTURE_KCONFIG_KASAN_ARG="CONFIG_DEBUG_INFO=y CONFIG_KASAN=y"; export TORTURE_KCONFIG_KASAN_ARG
173		;;
174	--kcsan)
175		TORTURE_KCONFIG_KCSAN_ARG="CONFIG_DEBUG_INFO=y CONFIG_KCSAN=y CONFIG_KCSAN_ASSUME_PLAIN_WRITES_ATOMIC=n CONFIG_KCSAN_REPORT_VALUE_CHANGE_ONLY=n CONFIG_KCSAN_REPORT_ONCE_IN_MS=100000 CONFIG_KCSAN_INTERRUPT_WATCHER=y CONFIG_KCSAN_VERBOSE=y CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y"; export TORTURE_KCONFIG_KCSAN_ARG
176		;;
177	--kmake-arg|--kmake-args)
178		checkarg --kmake-arg "(kernel make arguments)" $# "$2" '.*' '^error$'
179		TORTURE_KMAKE_ARG="`echo "$TORTURE_KMAKE_ARG $2" | sed -e 's/^ *//' -e 's/ *$//'`"
180		shift
181		;;
182	--mac)
183		checkarg --mac "(MAC address)" $# "$2" '^\([0-9a-fA-F]\{2\}:\)\{5\}[0-9a-fA-F]\{2\}$' error
184		TORTURE_QEMU_MAC=$2
185		shift
186		;;
187	--memory)
188		checkarg --memory "(memory size)" $# "$2" '^[0-9]\+[MG]\?$' error
189		TORTURE_QEMU_MEM=$2
190		shift
191		;;
192	--no-initrd)
193		TORTURE_INITRD=""; export TORTURE_INITRD
194		;;
195	--qemu-args|--qemu-arg)
196		checkarg --qemu-args "(qemu arguments)" $# "$2" '^-' '^error'
197		TORTURE_QEMU_ARG="`echo "$TORTURE_QEMU_ARG $2" | sed -e 's/^ *//' -e 's/ *$//'`"
198		shift
199		;;
200	--qemu-cmd)
201		checkarg --qemu-cmd "(qemu-system-...)" $# "$2" 'qemu-system-' '^--'
202		TORTURE_QEMU_CMD="$2"
203		shift
204		;;
205	--results)
206		checkarg --results "(absolute pathname)" "$#" "$2" '^/' '^error'
207		resdir=$2
208		shift
209		;;
210	--shutdown-grace)
211		checkarg --shutdown-grace "(seconds)" "$#" "$2" '^[0-9]*$' '^error'
212		TORTURE_SHUTDOWN_GRACE=$2
213		shift
214		;;
215	--torture)
216		checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\|rcuscale\|refscale\|scf\)$' '^--'
217		TORTURE_SUITE=$2
218		shift
219		if test "$TORTURE_SUITE" = rcuscale || test "$TORTURE_SUITE" = refscale
220		then
221			# If you really want jitter for refscale or
222			# rcuscale, specify it after specifying the rcuscale
223			# or the refscale.  (But why jitter in these cases?)
224			jitter=0
225		fi
226		;;
227	--trust-make)
228		TORTURE_TRUST_MAKE="y"
229		;;
230	*)
231		echo Unknown argument $1
232		usage
233		;;
234	esac
235	shift
236done
237
238if test -n "$dryrun" || test -z "$TORTURE_INITRD" || tools/testing/selftests/rcutorture/bin/mkinitrd.sh
239then
240	:
241else
242	echo No initrd and unable to create one, aborting test >&2
243	exit 1
244fi
245
246CONFIGFRAG=${KVM}/configs/${TORTURE_SUITE}; export CONFIGFRAG
247
248defaultconfigs="`tr '\012' ' ' < $CONFIGFRAG/CFLIST`"
249if test -z "$configs"
250then
251	configs=$defaultconfigs
252fi
253
254if test -z "$resdir"
255then
256	resdir=$KVM/res
257fi
258
259# Create a file of test-name/#cpus pairs, sorted by decreasing #cpus.
260configs_derep=
261for CF in $configs
262do
263	case $CF in
264	[0-9]\**|[0-9][0-9]\**|[0-9][0-9][0-9]\**)
265		config_reps=`echo $CF | sed -e 's/\*.*$//'`
266		CF1=`echo $CF | sed -e 's/^[^*]*\*//'`
267		;;
268	*)
269		config_reps=1
270		CF1=$CF
271		;;
272	esac
273	for ((cur_rep=0;cur_rep<$config_reps;cur_rep++))
274	do
275		configs_derep="$configs_derep $CF1"
276	done
277done
278touch $T/cfgcpu
279configs_derep="`echo $configs_derep | sed -e "s/\<CFLIST\>/$defaultconfigs/g"`"
280if test -n "$TORTURE_KCONFIG_GDB_ARG"
281then
282	if test "`echo $configs_derep | wc -w`" -gt 1
283	then
284		echo "The --config list is: $configs_derep."
285		echo "Only one --config permitted with --gdb, terminating."
286		exit 1
287	fi
288fi
289echo 'BEGIN {' > $T/cfgcpu.awk
290for CF1 in `echo $configs_derep | tr -s ' ' '\012' | sort -u`
291do
292	if test -f "$CONFIGFRAG/$CF1"
293	then
294		if echo "$TORTURE_KCONFIG_ARG" | grep -q '\<CONFIG_NR_CPUS='
295		then
296			echo "$TORTURE_KCONFIG_ARG" | tr -s ' ' | tr ' ' '\012' > $T/KCONFIG_ARG
297			cpu_count=`configNR_CPUS.sh $T/KCONFIG_ARG`
298		else
299			cpu_count=`configNR_CPUS.sh $CONFIGFRAG/$CF1`
300		fi
301		cpu_count=`configfrag_boot_cpus "$TORTURE_BOOTARGS" "$CONFIGFRAG/$CF1" "$cpu_count"`
302		cpu_count=`configfrag_boot_maxcpus "$TORTURE_BOOTARGS" "$CONFIGFRAG/$CF1" "$cpu_count"`
303		echo 'scenariocpu["'"$CF1"'"] = '"$cpu_count"';' >> $T/cfgcpu.awk
304	else
305		echo "The --configs file $CF1 does not exist, terminating."
306		exit 1
307	fi
308done
309cat << '___EOF___' >> $T/cfgcpu.awk
310}
311{
312	for (i = 1; i <= NF; i++)
313		print $i, scenariocpu[$i];
314}
315___EOF___
316echo $configs_derep | awk -f $T/cfgcpu.awk > $T/cfgcpu
317sort -k2nr $T/cfgcpu -T="$T" > $T/cfgcpu.sort
318
319# Use a greedy bin-packing algorithm, sorting the list accordingly.
320awk < $T/cfgcpu.sort > $T/cfgcpu.pack -v ncpus=$cpus '
321BEGIN {
322	njobs = 0;
323}
324
325{
326	# Read file of tests and corresponding required numbers of CPUs.
327	cf[njobs] = $1;
328	cpus[njobs] = $2;
329	njobs++;
330}
331
332END {
333	batch = 0;
334	nc = -1;
335
336	# Each pass through the following loop creates on test batch that
337	# can be executed concurrently given ncpus.  Note that a given test
338	# that requires more than the available CPUs will run in its own
339	# batch.  Such tests just have to make do with what is available.
340	while (nc != ncpus) {
341		batch++;
342		nc = ncpus;
343
344		# Each pass through the following loop considers one
345		# test for inclusion in the current batch.
346		for (i = 0; i < njobs; i++) {
347			if (done[i])
348				continue; # Already part of a batch.
349			if (nc >= cpus[i] || nc == ncpus) {
350
351				# This test fits into the current batch.
352				done[i] = batch;
353				nc -= cpus[i];
354				if (nc <= 0)
355					break; # Too-big test in its own batch.
356			}
357		}
358	}
359
360	# Dump out the tests in batch order.
361	for (b = 1; b <= batch; b++)
362		for (i = 0; i < njobs; i++)
363			if (done[i] == b)
364				print cf[i], cpus[i];
365}'
366
367# Generate a script to execute the tests in appropriate batches.
368cat << ___EOF___ > $T/script
369CONFIGFRAG="$CONFIGFRAG"; export CONFIGFRAG
370KVM="$KVM"; export KVM
371PATH="$PATH"; export PATH
372TORTURE_ALLOTED_CPUS="$TORTURE_ALLOTED_CPUS"; export TORTURE_ALLOTED_CPUS
373TORTURE_BOOT_IMAGE="$TORTURE_BOOT_IMAGE"; export TORTURE_BOOT_IMAGE
374TORTURE_BUILDONLY="$TORTURE_BUILDONLY"; export TORTURE_BUILDONLY
375TORTURE_DEFCONFIG="$TORTURE_DEFCONFIG"; export TORTURE_DEFCONFIG
376TORTURE_INITRD="$TORTURE_INITRD"; export TORTURE_INITRD
377TORTURE_KCONFIG_ARG="$TORTURE_KCONFIG_ARG"; export TORTURE_KCONFIG_ARG
378TORTURE_KCONFIG_GDB_ARG="$TORTURE_KCONFIG_GDB_ARG"; export TORTURE_KCONFIG_GDB_ARG
379TORTURE_BOOT_GDB_ARG="$TORTURE_BOOT_GDB_ARG"; export TORTURE_BOOT_GDB_ARG
380TORTURE_QEMU_GDB_ARG="$TORTURE_QEMU_GDB_ARG"; export TORTURE_QEMU_GDB_ARG
381TORTURE_KCONFIG_KASAN_ARG="$TORTURE_KCONFIG_KASAN_ARG"; export TORTURE_KCONFIG_KASAN_ARG
382TORTURE_KCONFIG_KCSAN_ARG="$TORTURE_KCONFIG_KCSAN_ARG"; export TORTURE_KCONFIG_KCSAN_ARG
383TORTURE_KMAKE_ARG="$TORTURE_KMAKE_ARG"; export TORTURE_KMAKE_ARG
384TORTURE_QEMU_CMD="$TORTURE_QEMU_CMD"; export TORTURE_QEMU_CMD
385TORTURE_QEMU_INTERACTIVE="$TORTURE_QEMU_INTERACTIVE"; export TORTURE_QEMU_INTERACTIVE
386TORTURE_QEMU_MAC="$TORTURE_QEMU_MAC"; export TORTURE_QEMU_MAC
387TORTURE_QEMU_MEM="$TORTURE_QEMU_MEM"; export TORTURE_QEMU_MEM
388TORTURE_SHUTDOWN_GRACE="$TORTURE_SHUTDOWN_GRACE"; export TORTURE_SHUTDOWN_GRACE
389TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE
390TORTURE_TRUST_MAKE="$TORTURE_TRUST_MAKE"; export TORTURE_TRUST_MAKE
391if ! test -e $resdir
392then
393	mkdir -p "$resdir" || :
394fi
395mkdir -p $resdir/$ds
396TORTURE_RESDIR="$resdir/$ds"; export TORTURE_RESDIR
397TORTURE_STOPFILE="$resdir/$ds/STOP.1"; export TORTURE_STOPFILE
398echo Results directory: $resdir/$ds
399echo $scriptname $args
400touch $resdir/$ds/log
401echo $scriptname $args >> $resdir/$ds/log
402echo ${TORTURE_SUITE} > $resdir/$ds/TORTURE_SUITE
403pwd > $resdir/$ds/testid.txt
404if test -d .git
405then
406	git status >> $resdir/$ds/testid.txt
407	git rev-parse HEAD >> $resdir/$ds/testid.txt
408	git diff HEAD >> $resdir/$ds/testid.txt
409fi
410___EOF___
411awk < $T/cfgcpu.pack \
412	-v TORTURE_BUILDONLY="$TORTURE_BUILDONLY" \
413	-v CONFIGDIR="$CONFIGFRAG/" \
414	-v KVM="$KVM" \
415	-v ncpus=$cpus \
416	-v jitter="$jitter" \
417	-v rd=$resdir/$ds/ \
418	-v dur=$dur \
419	-v TORTURE_QEMU_ARG="$TORTURE_QEMU_ARG" \
420	-v TORTURE_BOOTARGS="$TORTURE_BOOTARGS" \
421'BEGIN {
422	i = 0;
423}
424
425{
426	cf[i] = $1;
427	cpus[i] = $2;
428	i++;
429}
430
431# Dump out the scripting required to run one test batch.
432function dump(first, pastlast, batchnum)
433{
434	print "echo ----Start batch " batchnum ": `date` | tee -a " rd "log";
435	print "needqemurun="
436	jn=1
437	for (j = first; j < pastlast; j++) {
438		builddir=KVM "/b" j - first + 1
439		cpusr[jn] = cpus[j];
440		if (cfrep[cf[j]] == "") {
441			cfr[jn] = cf[j];
442			cfrep[cf[j]] = 1;
443		} else {
444			cfrep[cf[j]]++;
445			cfr[jn] = cf[j] "." cfrep[cf[j]];
446		}
447		if (cpusr[jn] > ncpus && ncpus != 0)
448			ovf = "-ovf";
449		else
450			ovf = "";
451		print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build. `date` | tee -a " rd "log";
452		print "rm -f " builddir ".*";
453		print "touch " builddir ".wait";
454		print "mkdir " rd cfr[jn] " || :";
455		print "kvm-test-1-run.sh " CONFIGDIR cf[j], builddir, rd cfr[jn], dur " \"" TORTURE_QEMU_ARG "\" \"" TORTURE_BOOTARGS "\" > " rd cfr[jn]  "/kvm-test-1-run.sh.out 2>&1 &"
456		print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date` | tee -a " rd "log";
457		print "while test -f " builddir ".wait"
458		print "do"
459		print "\tsleep 1"
460		print "done"
461		print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete. `date` | tee -a " rd "log";
462		jn++;
463	}
464	for (j = 1; j < jn; j++) {
465		builddir=KVM "/b" j
466		print "rm -f " builddir ".ready"
467		print "if test -f \"" rd cfr[j] "/builtkernel\""
468		print "then"
469		print "\techo ----", cfr[j], cpusr[j] ovf ": Kernel present. `date` | tee -a " rd "log";
470		print "\tneedqemurun=1"
471		print "fi"
472	}
473	njitter = 0;
474	split(jitter, ja);
475	if (ja[1] == -1 && ncpus == 0)
476		njitter = 1;
477	else if (ja[1] == -1)
478		njitter = ncpus;
479	else
480		njitter = ja[1];
481	if (TORTURE_BUILDONLY && njitter != 0) {
482		njitter = 0;
483		print "echo Build-only run, so suppressing jitter | tee -a " rd "log"
484	}
485	if (TORTURE_BUILDONLY) {
486		print "needqemurun="
487	}
488	print "if test -n \"$needqemurun\""
489	print "then"
490	print "\techo ---- Starting kernels. `date` | tee -a " rd "log";
491	print "\techo > " rd "jitter_pids"
492	for (j = 0; j < njitter; j++) {
493		print "\tjitter.sh " j " " dur " " ja[2] " " ja[3] "&"
494		print "\techo $! >> " rd "jitter_pids"
495	}
496	print "\twait"
497	print "\techo ---- All kernel runs complete. `date` | tee -a " rd "log";
498	print "else"
499	print "\twait"
500	print "\techo ---- No kernel runs. `date` | tee -a " rd "log";
501	print "fi"
502	for (j = 1; j < jn; j++) {
503		builddir=KVM "/b" j
504		print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results: | tee -a " rd "log";
505		print "cat " rd cfr[j]  "/kvm-test-1-run.sh.out | tee -a " rd "log";
506	}
507}
508
509END {
510	njobs = i;
511	nc = ncpus;
512	first = 0;
513	batchnum = 1;
514
515	# Each pass through the following loop considers one test.
516	for (i = 0; i < njobs; i++) {
517		if (ncpus == 0) {
518			# Sequential test specified, each test its own batch.
519			dump(i, i + 1, batchnum);
520			first = i;
521			batchnum++;
522		} else if (nc < cpus[i] && i != 0) {
523			# Out of CPUs, dump out a batch.
524			dump(first, i, batchnum);
525			first = i;
526			nc = ncpus;
527			batchnum++;
528		}
529		# Account for the CPUs needed by the current test.
530		nc -= cpus[i];
531	}
532	# Dump the last batch.
533	if (ncpus != 0)
534		dump(first, i, batchnum);
535}' >> $T/script
536
537cat << '___EOF___' >> $T/script
538echo | tee -a $TORTURE_RESDIR/log
539echo | tee -a $TORTURE_RESDIR/log
540echo " --- `date` Test summary:" | tee -a $TORTURE_RESDIR/log
541___EOF___
542cat << ___EOF___ >> $T/script
543echo Results directory: $resdir/$ds | tee -a $resdir/$ds/log
544kcsan-collapse.sh $resdir/$ds | tee -a $resdir/$ds/log
545kvm-recheck.sh $resdir/$ds > $T/kvm-recheck.sh.out 2>&1
546___EOF___
547echo 'ret=$?' >> $T/script
548echo "cat $T/kvm-recheck.sh.out | tee -a $resdir/$ds/log" >> $T/script
549echo 'exit $ret' >> $T/script
550
551if test "$dryrun" = script
552then
553	cat $T/script
554	exit 0
555elif test "$dryrun" = sched
556then
557	# Extract the test run schedule from the script.
558	egrep 'Start batch|Starting build\.' $T/script | grep -v ">>" |
559		sed -e 's/:.*$//' -e 's/^echo //'
560	nbuilds="`grep 'Starting build\.' $T/script |
561		  grep -v ">>" | sed -e 's/:.*$//' -e 's/^echo //' |
562		  awk '{ print $1 }' | grep -v '\.' | wc -l`"
563	echo Total number of builds: $nbuilds
564	nbatches="`grep 'Start batch' $T/script | grep -v ">>" | wc -l`"
565	echo Total number of batches: $nbatches
566	exit 0
567elif test "$dryrun" = batches
568then
569	# Extract the tests and their batches from the script.
570	egrep 'Start batch|Starting build\.' $T/script | grep -v ">>" |
571		sed -e 's/:.*$//' -e 's/^echo //' -e 's/-ovf//' |
572		awk '
573		/^----Start/ {
574			batchno = $3;
575			next;
576		}
577		{
578			print batchno, $1, $2
579		}'
580else
581	# Not a dryrun, so run the script.
582	bash $T/script
583	ret=$?
584	echo " --- Done at `date` (`get_starttime_duration $starttime`) exitcode $ret" | tee -a $resdir/$ds/log
585	exit $ret
586fi
587
588# Tracing: trace_event=rcu:rcu_grace_period,rcu:rcu_future_grace_period,rcu:rcu_grace_period_init,rcu:rcu_nocb_wake,rcu:rcu_preempt_task,rcu:rcu_unlock_preempted_task,rcu:rcu_quiescent_state_report,rcu:rcu_fqs,rcu:rcu_callback,rcu:rcu_kfree_callback,rcu:rcu_batch_start,rcu:rcu_invoke_callback,rcu:rcu_invoke_kfree_callback,rcu:rcu_batch_end,rcu:rcu_torture_read,rcu:rcu_barrier
589# Function-graph tracing: ftrace=function_graph ftrace_graph_filter=sched_setaffinity,migration_cpu_stop
590# Also --kconfig "CONFIG_FUNCTION_TRACER=y CONFIG_FUNCTION_GRAPH_TRACER=y"
591# Control buffer size: --bootargs trace_buf_size=3k
592# Get trace-buffer dumps on all oopses: --bootargs ftrace_dump_on_oops
593# Ditto, but dump only the oopsing CPU: --bootargs ftrace_dump_on_oops=orig_cpu
594# Heavy-handed way to also dump on warnings: --bootargs panic_on_warn
595