xref: /linux/tools/testing/selftests/rcutorture/bin/kvm.sh (revision 6f7e6393d1ce636bb7ec77a7fe7b77458fddf701)
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="`mktemp -d ${TMPDIR-/tmp}/kvm.sh.XXXXXX`"
18trap 'rm -rf $T' 0
19
20cd `dirname $scriptname`/../../../../../
21
22# This script knows only English.
23LANG=en_US.UTF-8; export LANG
24
25dur=$((30*60))
26dryrun=""
27RCUTORTURE="`pwd`/tools/testing/selftests/rcutorture"; export RCUTORTURE
28PATH=${RCUTORTURE}/bin:$PATH; export PATH
29. functions.sh
30
31TORTURE_ALLOTED_CPUS="`identify_qemu_vcpus`"
32TORTURE_DEFCONFIG=defconfig
33TORTURE_BOOT_IMAGE=""
34TORTURE_BUILDONLY=
35TORTURE_INITRD="$RCUTORTURE/initrd"; export TORTURE_INITRD
36TORTURE_KCONFIG_ARG=""
37TORTURE_KCONFIG_GDB_ARG=""
38TORTURE_BOOT_GDB_ARG=""
39TORTURE_QEMU_GDB_ARG=""
40TORTURE_JITTER_START=""
41TORTURE_JITTER_STOP=""
42TORTURE_KCONFIG_KASAN_ARG=""
43TORTURE_KCONFIG_KCSAN_ARG=""
44TORTURE_KMAKE_ARG=""
45TORTURE_NO_AFFINITY=""
46TORTURE_QEMU_MEM=512
47torture_qemu_mem_default=1
48TORTURE_REMOTE=
49TORTURE_SHUTDOWN_GRACE=180
50TORTURE_SUITE=rcu
51TORTURE_MOD=rcutorture
52TORTURE_TRUST_MAKE=""
53debuginfo="CONFIG_DEBUG_INFO_NONE=n CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y"
54resdir=""
55configs=""
56cpus=0
57ds=`date +%Y.%m.%d-%H.%M.%S`
58jitter="-1"
59
60startdate="`date`"
61starttime="`get_starttime`"
62
63usage () {
64	echo "Usage: $scriptname optional arguments:"
65	echo "       --allcpus"
66	echo "       --bootargs kernel-boot-arguments"
67	echo "       --bootimage relative-path-to-kernel-boot-image"
68	echo "       --buildonly"
69	echo "       --configs \"config-file list w/ repeat factor (3*TINY01)\""
70	echo "       --cpus N"
71	echo "       --datestamp string"
72	echo "       --defconfig string"
73	echo "       --debug-info"
74	echo "       --dryrun batches|scenarios|sched|script"
75	echo "       --duration minutes | <seconds>s | <hours>h | <days>d"
76	echo "       --gdb"
77	echo "       --help"
78	echo "       --interactive"
79	echo "       --jitter N [ maxsleep (us) [ maxspin (us) ] ]"
80	echo "       --kasan"
81	echo "       --kconfig Kconfig-options"
82	echo "       --kcsan"
83	echo "       --kill-previous"
84	echo "       --kmake-arg kernel-make-arguments"
85	echo "       --mac nn:nn:nn:nn:nn:nn"
86	echo "       --memory megabytes|nnnG"
87	echo "       --no-affinity"
88	echo "       --no-initrd"
89	echo "       --qemu-args qemu-arguments"
90	echo "       --qemu-cmd qemu-system-..."
91	echo "       --remote"
92	echo "       --results absolute-pathname"
93	echo "       --shutdown-grace seconds"
94	echo "       --torture lock|rcu|rcuscale|refscale|scf|X*"
95	echo "       --trust-make"
96	exit 1
97}
98
99while test $# -gt 0
100do
101	case "$1" in
102	--allcpus)
103		cpus=$TORTURE_ALLOTED_CPUS
104		max_cpus=$TORTURE_ALLOTED_CPUS
105		;;
106	--bootargs|--bootarg)
107		checkarg --bootargs "(list of kernel boot arguments)" "$#" "$2" '.*' '^--'
108		TORTURE_BOOTARGS="$TORTURE_BOOTARGS $2"
109		shift
110		;;
111	--bootimage)
112		checkarg --bootimage "(relative path to kernel boot image)" "$#" "$2" '[a-zA-Z0-9][a-zA-Z0-9_]*' '^--'
113		TORTURE_BOOT_IMAGE="$2"
114		shift
115		;;
116	--buildonly|--build-only)
117		TORTURE_BUILDONLY=1
118		;;
119	--configs|--config)
120		checkarg --configs "(list of config files)" "$#" "$2" '^[^/.a-z]\+$' '^--'
121		configs="$configs $2"
122		shift
123		;;
124	--cpus)
125		checkarg --cpus "(number)" "$#" "$2" '^[0-9]*$' '^--'
126		cpus=$2
127		TORTURE_ALLOTED_CPUS="$2"
128		if test -z "$TORTURE_REMOTE"
129		then
130			max_cpus="`identify_qemu_vcpus`"
131			if test "$TORTURE_ALLOTED_CPUS" -gt "$max_cpus"
132			then
133				TORTURE_ALLOTED_CPUS=$max_cpus
134			fi
135		fi
136		shift
137		;;
138	--datestamp)
139		checkarg --datestamp "(relative pathname)" "$#" "$2" '^[a-zA-Z0-9._/-]*$' '^--'
140		ds=$2
141		shift
142		;;
143	--debug-info|--debuginfo)
144		if test -z "$TORTURE_KCONFIG_KCSAN_ARG" && test -z "$TORTURE_BOOT_GDB_ARG"
145		then
146			TORTURE_KCONFIG_KCSAN_ARG="$debuginfo"; export TORTURE_KCONFIG_KCSAN_ARG
147			TORTURE_BOOT_GDB_ARG="nokaslr"; export TORTURE_BOOT_GDB_ARG
148		else
149			echo "Ignored redundant --debug-info (implied by --kcsan &c)"
150		fi
151		;;
152	--defconfig)
153		checkarg --defconfig "defconfigtype" "$#" "$2" '^[^/][^/]*$' '^--'
154		TORTURE_DEFCONFIG=$2
155		shift
156		;;
157	--dryrun)
158		checkarg --dryrun "batches|sched|script" $# "$2" 'batches\|scenarios\|sched\|script' '^--'
159		dryrun=$2
160		shift
161		;;
162	--duration)
163		checkarg --duration "(minutes)" $# "$2" '^[0-9][0-9]*\(s\|m\|h\|d\|\)$' '^error'
164		mult=60
165		if echo "$2" | grep -q 's$'
166		then
167			mult=1
168		elif echo "$2" | grep -q 'h$'
169		then
170			mult=3600
171		elif echo "$2" | grep -q 'd$'
172		then
173			mult=86400
174		fi
175		ts=`echo $2 | sed -e 's/[smhd]$//'`
176		dur=$(($ts*mult))
177		shift
178		;;
179	--gdb)
180		TORTURE_KCONFIG_GDB_ARG="$debuginfo"; export TORTURE_KCONFIG_GDB_ARG
181		TORTURE_BOOT_GDB_ARG="nokaslr"; export TORTURE_BOOT_GDB_ARG
182		TORTURE_QEMU_GDB_ARG="-s -S"; export TORTURE_QEMU_GDB_ARG
183		;;
184	--help|-h)
185		usage
186		;;
187	--interactive)
188		TORTURE_QEMU_INTERACTIVE=1; export TORTURE_QEMU_INTERACTIVE
189		;;
190	--jitter)
191		checkarg --jitter "(# threads [ sleep [ spin ] ])" $# "$2" '^-\{,1\}[0-9]\+\( \+[0-9]\+\)\{,2\} *$' '^error$'
192		jitter="$2"
193		shift
194		;;
195	--kasan)
196		TORTURE_KCONFIG_KASAN_ARG="$debuginfo CONFIG_KASAN=y"; export TORTURE_KCONFIG_KASAN_ARG
197		if test -n "$torture_qemu_mem_default"
198		then
199			TORTURE_QEMU_MEM=2G
200		fi
201		;;
202	--kconfig|--kconfigs)
203		checkarg --kconfig "(Kconfig options)" $# "$2" '^\(#CHECK#\)\?CONFIG_[A-Z0-9_]\+=\([ynm]\|-\?[0-9]\+\|"[^"]*"\)\( \+\(#CHECK#\)\?CONFIG_[A-Z0-9_]\+=\([ynm]\|-\?[0-9]\+\|"[^"]*"\)\)* *$' '^error$'
204		TORTURE_KCONFIG_ARG="`echo "$TORTURE_KCONFIG_ARG $2" | sed -e 's/^ *//' -e 's/ *$//'`"
205		shift
206		;;
207	--kcsan)
208		TORTURE_KCONFIG_KCSAN_ARG="$debuginfo CONFIG_KCSAN=y CONFIG_KCSAN_STRICT=y CONFIG_KCSAN_REPORT_ONCE_IN_MS=100000 CONFIG_KCSAN_VERBOSE=y CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y"; export TORTURE_KCONFIG_KCSAN_ARG
209		;;
210	--kill-previous)
211		TORTURE_KILL_PREVIOUS=1
212		;;
213	--kmake-arg|--kmake-args)
214		checkarg --kmake-arg "(kernel make arguments)" $# "$2" '.*' '^error$'
215		TORTURE_KMAKE_ARG="`echo "$TORTURE_KMAKE_ARG $2" | sed -e 's/^ *//' -e 's/ *$//'`"
216		shift
217		;;
218	--mac)
219		checkarg --mac "(MAC address)" $# "$2" '^\([0-9a-fA-F]\{2\}:\)\{5\}[0-9a-fA-F]\{2\}$' error
220		TORTURE_QEMU_MAC=$2
221		shift
222		;;
223	--memory)
224		checkarg --memory "(memory size)" $# "$2" '^[0-9]\+[MG]\?$' error
225		TORTURE_QEMU_MEM=$2
226		torture_qemu_mem_default=
227		shift
228		;;
229	--no-affinity)
230		TORTURE_NO_AFFINITY="no-affinity"
231		;;
232	--no-initrd)
233		TORTURE_INITRD=""; export TORTURE_INITRD
234		;;
235	--qemu-args|--qemu-arg)
236		checkarg --qemu-args "(qemu arguments)" $# "$2" '^-' '^error'
237		TORTURE_QEMU_ARG="`echo "$TORTURE_QEMU_ARG $2" | sed -e 's/^ *//' -e 's/ *$//'`"
238		shift
239		;;
240	--qemu-cmd)
241		checkarg --qemu-cmd "(qemu-system-...)" $# "$2" 'qemu-system-' '^--'
242		TORTURE_QEMU_CMD="$2"
243		shift
244		;;
245	--remote)
246		TORTURE_REMOTE=1
247		;;
248	--results)
249		checkarg --results "(absolute pathname)" "$#" "$2" '^/' '^error'
250		resdir=$2
251		shift
252		;;
253	--shutdown-grace)
254		checkarg --shutdown-grace "(seconds)" "$#" "$2" '^[0-9]*$' '^error'
255		TORTURE_SHUTDOWN_GRACE=$2
256		shift
257		;;
258	--torture)
259		checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\|rcuscale\|refscale\|scf\|X.*\)$' '^--'
260		TORTURE_SUITE=$2
261		TORTURE_MOD="`echo $TORTURE_SUITE | sed -e 's/^\(lock\|rcu\|scf\)$/\1torture/'`"
262		shift
263		if test "$TORTURE_SUITE" = rcuscale || test "$TORTURE_SUITE" = refscale
264		then
265			# If you really want jitter for refscale or
266			# rcuscale, specify it after specifying the rcuscale
267			# or the refscale.  (But why jitter in these cases?)
268			jitter=0
269		fi
270		;;
271	--trust-make)
272		TORTURE_TRUST_MAKE="y"
273		;;
274	*)
275		echo Unknown argument $1
276		usage
277		;;
278	esac
279	shift
280done
281
282# Prevent concurrent kvm.sh runs on the same source tree.  The flock
283# is automatically released when the script exits, even if killed.
284TORTURE_LOCK="$RCUTORTURE/.kvm.sh.lock"
285
286# Terminate any processes holding the lock file, if requested.
287if test -n "$TORTURE_KILL_PREVIOUS"
288then
289	if test -e "$TORTURE_LOCK"
290	then
291		echo "Killing processes holding $TORTURE_LOCK..."
292		if fuser -k "$TORTURE_LOCK" >/dev/null 2>&1
293		then
294			sleep 2
295			echo "Previous kvm.sh processes killed."
296		else
297			echo "No processes were holding the lock."
298		fi
299	else
300		echo "No lock file exists, nothing to kill."
301	fi
302fi
303
304if test -z "$dryrun"
305then
306	# Create a file descriptor and flock it, so that when kvm.sh (and its
307	# children) exit, the flock is released by the kernel automatically.
308	exec 9>"$TORTURE_LOCK"
309	if ! flock -n 9
310	then
311		echo "ERROR: Another kvm.sh instance is already running on this tree."
312		echo "       Lock file: $TORTURE_LOCK"
313		echo "       To run kvm.sh, kill all existing kvm.sh runs first (--kill-previous)."
314		exit 1
315	fi
316fi
317
318if test -n "$dryrun" || test -z "$TORTURE_INITRD" || tools/testing/selftests/rcutorture/bin/mkinitrd.sh
319then
320	:
321else
322	echo No initrd and unable to create one, aborting test >&2
323	exit 1
324fi
325
326CONFIGFRAG=${RCUTORTURE}/configs/${TORTURE_SUITE}; export CONFIGFRAG
327
328defaultconfigs="`tr '\012' ' ' < $CONFIGFRAG/CFLIST`"
329if test -z "$configs"
330then
331	configs=$defaultconfigs
332fi
333
334if test -z "$resdir"
335then
336	resdir=$RCUTORTURE/res
337fi
338
339# Create a file of test-name/#cpus pairs, sorted by decreasing #cpus.
340configs_derep=
341for CF in $configs
342do
343	case $CF in
344	[0-9]\**|[0-9][0-9]\**|[0-9][0-9][0-9]\**|[0-9][0-9][0-9][0-9]\**)
345		config_reps=`echo $CF | sed -e 's/\*.*$//'`
346		CF1=`echo $CF | sed -e 's/^[^*]*\*//'`
347		;;
348	*)
349		config_reps=1
350		CF1=$CF
351		;;
352	esac
353	for ((cur_rep=0;cur_rep<$config_reps;cur_rep++))
354	do
355		configs_derep="$configs_derep $CF1"
356	done
357done
358touch $T/cfgcpu
359configs_derep="`echo $configs_derep | sed -e "s/\<CFLIST\>/$defaultconfigs/g"`"
360if test -n "$TORTURE_KCONFIG_GDB_ARG"
361then
362	if test "`echo $configs_derep | wc -w`" -gt 1
363	then
364		echo "The --config list is: $configs_derep."
365		echo "Only one --config permitted with --gdb, terminating."
366		exit 1
367	fi
368fi
369echo 'BEGIN {' > $T/cfgcpu.awk
370for CF1 in `echo $configs_derep | tr -s ' ' '\012' | sort -u`
371do
372	if test -f "$CONFIGFRAG/$CF1"
373	then
374		if echo "$TORTURE_KCONFIG_ARG" | grep -q '\<CONFIG_NR_CPUS='
375		then
376			echo "$TORTURE_KCONFIG_ARG" | tr -s ' ' | tr ' ' '\012' > $T/KCONFIG_ARG
377			cpu_count=`configNR_CPUS.sh $T/KCONFIG_ARG`
378		else
379			cpu_count=`configNR_CPUS.sh $CONFIGFRAG/$CF1`
380		fi
381		cpu_count=`configfrag_boot_cpus "$TORTURE_BOOTARGS" "$CONFIGFRAG/$CF1" "$cpu_count"`
382		cpu_count=`configfrag_boot_maxcpus "$TORTURE_BOOTARGS" "$CONFIGFRAG/$CF1" "$cpu_count"`
383		echo 'scenariocpu["'"$CF1"'"] = '"$cpu_count"';' >> $T/cfgcpu.awk
384	else
385		echo "The --configs file $CF1 does not exist, terminating."
386		exit 1
387	fi
388done
389cat << '___EOF___' >> $T/cfgcpu.awk
390}
391{
392	for (i = 1; i <= NF; i++)
393		print $i, scenariocpu[$i];
394}
395___EOF___
396echo $configs_derep | awk -f $T/cfgcpu.awk > $T/cfgcpu
397sort -k2nr $T/cfgcpu -T="$T" > $T/cfgcpu.sort
398
399# Use a greedy bin-packing algorithm, sorting the list accordingly.
400awk < $T/cfgcpu.sort > $T/cfgcpu.pack -v ncpus=$cpus '
401BEGIN {
402	njobs = 0;
403}
404
405{
406	# Read file of tests and corresponding required numbers of CPUs.
407	cf[njobs] = $1;
408	cpus[njobs] = $2;
409	njobs++;
410}
411
412END {
413	batch = 0;
414	nc = -1;
415
416	# Each pass through the following loop creates on test batch that
417	# can be executed concurrently given ncpus.  Note that a given test
418	# that requires more than the available CPUs will run in its own
419	# batch.  Such tests just have to make do with what is available.
420	while (nc != ncpus) {
421		batch++;
422		nc = ncpus;
423
424		# Each pass through the following loop considers one
425		# test for inclusion in the current batch.
426		for (i = 0; i < njobs; i++) {
427			if (done[i])
428				continue; # Already part of a batch.
429			if (nc >= cpus[i] || nc == ncpus) {
430
431				# This test fits into the current batch.
432				done[i] = batch;
433				nc -= cpus[i];
434				if (nc <= 0)
435					break; # Too-big test in its own batch.
436			}
437		}
438	}
439
440	# Dump out the tests in batch order.
441	for (b = 1; b <= batch; b++)
442		for (i = 0; i < njobs; i++)
443			if (done[i] == b)
444				print cf[i], cpus[i];
445}'
446
447# Generate a script to execute the tests in appropriate batches.
448cat << ___EOF___ > $T/script
449CONFIGFRAG="$CONFIGFRAG"; export CONFIGFRAG
450RCUTORTURE="$RCUTORTURE"; export RCUTORTURE
451PATH="$PATH"; export PATH
452TORTURE_ALLOTED_CPUS="$TORTURE_ALLOTED_CPUS"; export TORTURE_ALLOTED_CPUS
453TORTURE_BOOT_IMAGE="$TORTURE_BOOT_IMAGE"; export TORTURE_BOOT_IMAGE
454TORTURE_BUILDONLY="$TORTURE_BUILDONLY"; export TORTURE_BUILDONLY
455TORTURE_DEFCONFIG="$TORTURE_DEFCONFIG"; export TORTURE_DEFCONFIG
456TORTURE_INITRD="$TORTURE_INITRD"; export TORTURE_INITRD
457TORTURE_KCONFIG_ARG="$TORTURE_KCONFIG_ARG"; export TORTURE_KCONFIG_ARG
458TORTURE_KCONFIG_GDB_ARG="$TORTURE_KCONFIG_GDB_ARG"; export TORTURE_KCONFIG_GDB_ARG
459TORTURE_BOOT_GDB_ARG="$TORTURE_BOOT_GDB_ARG"; export TORTURE_BOOT_GDB_ARG
460TORTURE_QEMU_GDB_ARG="$TORTURE_QEMU_GDB_ARG"; export TORTURE_QEMU_GDB_ARG
461TORTURE_KCONFIG_KASAN_ARG="$TORTURE_KCONFIG_KASAN_ARG"; export TORTURE_KCONFIG_KASAN_ARG
462TORTURE_KCONFIG_KCSAN_ARG="$TORTURE_KCONFIG_KCSAN_ARG"; export TORTURE_KCONFIG_KCSAN_ARG
463TORTURE_KMAKE_ARG="$TORTURE_KMAKE_ARG"; export TORTURE_KMAKE_ARG
464TORTURE_MOD="$TORTURE_MOD"; export TORTURE_MOD
465TORTURE_NO_AFFINITY="$TORTURE_NO_AFFINITY"; export TORTURE_NO_AFFINITY
466TORTURE_QEMU_CMD="$TORTURE_QEMU_CMD"; export TORTURE_QEMU_CMD
467TORTURE_QEMU_INTERACTIVE="$TORTURE_QEMU_INTERACTIVE"; export TORTURE_QEMU_INTERACTIVE
468TORTURE_QEMU_MAC="$TORTURE_QEMU_MAC"; export TORTURE_QEMU_MAC
469TORTURE_QEMU_MEM="$TORTURE_QEMU_MEM"; export TORTURE_QEMU_MEM
470TORTURE_SHUTDOWN_GRACE="$TORTURE_SHUTDOWN_GRACE"; export TORTURE_SHUTDOWN_GRACE
471TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE
472TORTURE_TRUST_MAKE="$TORTURE_TRUST_MAKE"; export TORTURE_TRUST_MAKE
473if ! test -e $resdir
474then
475	mkdir -p "$resdir" || :
476fi
477mkdir -p $resdir/$ds
478TORTURE_RESDIR="$resdir/$ds"; export TORTURE_RESDIR
479TORTURE_STOPFILE="$resdir/$ds/STOP.1"; export TORTURE_STOPFILE
480echo Results directory: $resdir/$ds
481echo $scriptname $args
482touch $resdir/$ds/log
483echo $scriptname $args >> $resdir/$ds/log
484echo ${TORTURE_SUITE} > $resdir/$ds/torture_suite
485mktestid.sh $resdir/$ds
486___EOF___
487kvm-assign-cpus.sh /sys/devices/system/node > $T/cpuarray.awk
488kvm-get-cpus-script.sh $T/cpuarray.awk $T/dumpbatches.awk
489cat << '___EOF___' >> $T/dumpbatches.awk
490BEGIN {
491	i = 0;
492}
493
494{
495	cf[i] = $1;
496	cpus[i] = $2;
497	i++;
498}
499
500# Dump out the scripting required to run one test batch.
501function dump(first, pastlast, batchnum,  affinitylist)
502{
503	print "echo ----Start batch " batchnum ": `date` | tee -a " rd "log";
504	print "needqemurun="
505	jn=1
506	njitter = 0;
507	split(jitter, ja);
508	if (ja[1] == -1 && ncpus == 0)
509		njitter = 1;
510	else if (ja[1] == -1)
511		njitter = ncpus;
512	else
513		njitter = ja[1];
514	print "TORTURE_JITTER_START=\". jitterstart.sh " njitter " " rd " " dur " " ja[2] " " ja[3] "\"; export TORTURE_JITTER_START";
515	print "TORTURE_JITTER_STOP=\". jitterstop.sh " rd " \"; export TORTURE_JITTER_STOP"
516	for (j = first; j < pastlast; j++) {
517		cpusr[jn] = cpus[j];
518		if (cfrep[cf[j]] == "") {
519			cfr[jn] = cf[j];
520			cfrep[cf[j]] = 1;
521		} else {
522			cfrep[cf[j]]++;
523			cfr[jn] = cf[j] "." cfrep[cf[j]];
524		}
525		builddir=rd cfr[jn] "/build";
526		if (cpusr[jn] > ncpus && ncpus != 0)
527			ovf = "-ovf";
528		else
529			ovf = "";
530		print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build. `date` | tee -a " rd "log";
531		print "mkdir " rd cfr[jn] " || :";
532		print "touch " builddir ".wait";
533		affinitylist = "";
534		if (gotcpus()) {
535			affinitylist = nextcpus(cpusr[jn]);
536		}
537		if (affinitylist ~ /^[0-9,-][0-9,-]*$/)
538			print "export TORTURE_AFFINITY=" affinitylist;
539		else
540			print "export TORTURE_AFFINITY=";
541		print "kvm-test-1-run.sh " CONFIGDIR cf[j], rd cfr[jn], dur " \"" TORTURE_QEMU_ARG "\" \"" TORTURE_BOOTARGS "\" > " rd cfr[jn]  "/kvm-test-1-run.sh.out 2>&1 &"
542		print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date` | tee -a " rd "log";
543		print "while test -f " builddir ".wait"
544		print "do"
545		print "\tsleep 1"
546		print "done"
547		print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete. `date` | tee -a " rd "log";
548		jn++;
549	}
550	print "runfiles="
551	for (j = 1; j < jn; j++) {
552		builddir=rd cfr[j] "/build";
553		if (TORTURE_BUILDONLY)
554			print "rm -f " builddir ".ready"
555		else
556			print "mv " builddir ".ready " builddir ".run"
557			print "runfiles=\"$runfiles " builddir ".run\""
558		fi
559		print "if test -f \"" rd cfr[j] "/builtkernel\""
560		print "then"
561		print "\techo ----", cfr[j], cpusr[j] ovf ": Kernel present. `date` | tee -a " rd "log";
562		print "\tneedqemurun=1"
563		print "fi"
564	}
565	if (TORTURE_BUILDONLY && njitter != 0) {
566		njitter = 0;
567		print "echo Build-only run, so suppressing jitter | tee -a " rd "log"
568	}
569	if (TORTURE_BUILDONLY) {
570		print "needqemurun="
571	}
572	print "if test -n \"$needqemurun\""
573	print "then"
574	print "\techo ---- Starting kernels. `date` | tee -a " rd "log";
575	print "\t$TORTURE_JITTER_START";
576	print "\twhile ls $runfiles > /dev/null 2>&1"
577	print "\tdo"
578	print "\t\t:"
579	print "\tdone"
580	print "\t$TORTURE_JITTER_STOP";
581	print "\techo ---- All kernel runs complete. `date` | tee -a " rd "log";
582	print "else"
583	print "\twait"
584	print "\techo ---- No kernel runs. `date` | tee -a " rd "log";
585	print "fi"
586	for (j = 1; j < jn; j++) {
587		print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results: | tee -a " rd "log";
588		print "cat " rd cfr[j]  "/kvm-test-1-run.sh.out | tee -a " rd "log";
589	}
590}
591
592END {
593	njobs = i;
594	nc = ncpus;
595	first = 0;
596	batchnum = 1;
597
598	# Each pass through the following loop considers one test.
599	for (i = 0; i < njobs; i++) {
600		if (ncpus == 0) {
601			# Sequential test specified, each test its own batch.
602			dump(i, i + 1, batchnum);
603			first = i;
604			batchnum++;
605		} else if (nc < cpus[i] && i != 0) {
606			# Out of CPUs, dump out a batch.
607			dump(first, i, batchnum);
608			first = i;
609			nc = ncpus;
610			batchnum++;
611		}
612		# Account for the CPUs needed by the current test.
613		nc -= cpus[i];
614	}
615	# Dump the last batch.
616	if (ncpus != 0)
617		dump(first, i, batchnum);
618}
619___EOF___
620awk < $T/cfgcpu.pack \
621	-v TORTURE_BUILDONLY="$TORTURE_BUILDONLY" \
622	-v CONFIGDIR="$CONFIGFRAG/" \
623	-v RCUTORTURE="$RCUTORTURE" \
624	-v ncpus=$cpus \
625	-v jitter="$jitter" \
626	-v rd=$resdir/$ds/ \
627	-v dur=$dur \
628	-v TORTURE_QEMU_ARG="$TORTURE_QEMU_ARG" \
629	-v TORTURE_BOOTARGS="$TORTURE_BOOTARGS" \
630	-f $T/dumpbatches.awk >> $T/script
631echo kvm-end-run-stats.sh "$resdir/$ds" "$starttime" >> $T/script
632
633# Extract the tests and their batches from the script.
634grep -E 'Start batch|Starting build\.' $T/script | grep -v ">>" |
635	sed -e 's/:.*$//' -e 's/^echo //' -e 's/-ovf//' |
636	awk '
637	/^----Start/ {
638		batchno = $3;
639		next;
640	}
641	{
642		print batchno, $1, $2
643	}' > $T/batches
644
645# As above, but one line per batch.
646grep -v '^#' $T/batches | awk '
647BEGIN {
648	oldbatch = 1;
649}
650
651{
652	if (oldbatch != $1) {
653		print ++n ". " curbatch;
654		curbatch = "";
655		oldbatch = $1;
656	}
657	curbatch = curbatch " " $2;
658}
659
660END {
661	print ++n ". " curbatch;
662}' > $T/scenarios
663
664if test "$dryrun" = script
665then
666	cat $T/script
667	exit 0
668elif test "$dryrun" = sched
669then
670	# Extract the test run schedule from the script.
671	grep -E 'Start batch|Starting build\.' $T/script | grep -v ">>" |
672		sed -e 's/:.*$//' -e 's/^echo //'
673	nbuilds="`grep 'Starting build\.' $T/script |
674		  grep -v ">>" | sed -e 's/:.*$//' -e 's/^echo //' |
675		  awk '{ print $1 }' | grep -v '\.' | wc -l`"
676	echo Total number of builds: $nbuilds
677	nbatches="`grep 'Start batch' $T/script | grep -v ">>" | wc -l`"
678	echo Total number of batches: $nbatches
679	exit 0
680elif test "$dryrun" = batches
681then
682	cat $T/batches
683	exit 0
684elif test "$dryrun" = scenarios
685then
686	cat $T/scenarios
687	exit 0
688else
689	# Not a dryrun.  Record the batches and the number of CPUs, then run the script.
690	bash $T/script
691	ret=$?
692	cp $T/batches $resdir/$ds/batches
693	cp $T/scenarios $resdir/$ds/scenarios
694	echo '#' cpus=$cpus >> $resdir/$ds/batches
695	exit $ret
696fi
697
698# 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
699# Function-graph tracing: ftrace=function_graph ftrace_graph_filter=sched_setaffinity,migration_cpu_stop
700# Also --kconfig "CONFIG_FUNCTION_TRACER=y CONFIG_FUNCTION_GRAPH_TRACER=y"
701# Control buffer size: --bootargs trace_buf_size=3k
702# Get trace-buffer dumps on all oopses: --bootargs ftrace_dump_on_oops
703# Ditto, but dump only the oopsing CPU: --bootargs ftrace_dump_on_oops=orig_cpu
704# Heavy-handed way to also dump on warnings: --bootargs panic_on_warn=1
705