2 # SPDX-License-Identifier: GPL-2.0+
4 # Run a series of torture tests, intended for overnight or
5 # longer timeframes, and also for large systems.
7 # Usage: torture.sh [ options ]
9 # Copyright (C) 2020 Facebook, Inc.
11 # Authors: Paul E. McKenney <paulmck@kernel.org>
16 KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM
17 PATH=${KVM}/bin:$PATH; export PATH
20 TORTURE_ALLOTED_CPUS="`identify_qemu_vcpus`"
21 MAKE_ALLOTED_CPUS=$((TORTURE_ALLOTED_CPUS*2))
22 HALF_ALLOTED_CPUS=$((TORTURE_ALLOTED_CPUS/2))
23 if test "$HALF_ALLOTED_CPUS" -lt 1
27 VERBOSE_BATCH_CPUS=$((TORTURE_ALLOTED_CPUS/16))
28 if test "$VERBOSE_BATCH_CPUS" -lt 2
33 # Configurations/scenarios.
39 # Default compression, duration, and apportionment.
40 compress_kasan_vmlinux="`identify_qemu_vcpus`"
42 duration_rcutorture_frac=7
43 duration_locktorture_frac=1
44 duration_scftorture_frac=2
46 # "yes" or "no" parameters
57 # doyesno - Helper function for yes/no arguments
68 echo "Usage: $scriptname optional arguments:"
69 echo " --compress-kasan-vmlinux concurrency"
70 echo " --configs-rcutorture \"config-file list w/ repeat factor (3*TINY01)\""
71 echo " --configs-locktorture \"config-file list w/ repeat factor (10*LOCK01)\""
72 echo " --configs-scftorture \"config-file list w/ repeat factor (2*CFLIST)\""
74 echo " --doallmodconfig / --do-no-allmodconfig"
75 echo " --do-kasan / --do-no-kasan"
76 echo " --do-kcsan / --do-no-kcsan"
77 echo " --do-kvfree / --do-no-kvfree"
78 echo " --do-locktorture / --do-no-locktorture"
80 echo " --do-rcuscale / --do-no-rcuscale"
81 echo " --do-rcutorture / --do-no-rcutorture"
82 echo " --do-refscale / --do-no-refscale"
83 echo " --do-scftorture / --do-no-scftorture"
84 echo " --duration [ <minutes> | <hours>h | <days>d ]"
85 echo " --kcsan-kmake-arg kernel-make-arguments"
92 --compress-kasan-vmlinux)
93 checkarg --compress-kasan-vmlinux "(concurrency level)" $# "$2" '^[0-9][0-9]*$' '^error'
94 compress_kasan_vmlinux=$2
97 --config-rcutorture|--configs-rcutorture)
98 checkarg --configs-rcutorture "(list of config files)" "$#" "$2" '^[^/]\+$' '^--'
99 configs_rcutorture="$configs_rcutorture $2"
102 --config-locktorture|--configs-locktorture)
103 checkarg --configs-locktorture "(list of config files)" "$#" "$2" '^[^/]\+$' '^--'
104 configs_locktorture="$configs_locktorture $2"
107 --config-scftorture|--configs-scftorture)
108 checkarg --configs-scftorture "(list of config files)" "$#" "$2" '^[^/]\+$' '^--'
109 configs_scftorture="$configs_scftorture $2"
123 --do-allmodconfig|--do-no-allmodconfig)
124 do_allmodconfig=`doyesno "$1" --do-allmodconfig`
126 --do-kasan|--do-no-kasan)
127 do_kasan=`doyesno "$1" --do-kasan`
129 --do-kcsan|--do-no-kcsan)
130 do_kcsan=`doyesno "$1" --do-kcsan`
132 --do-kvfree|--do-no-kvfree)
133 do_kvfree=`doyesno "$1" --do-kvfree`
135 --do-locktorture|--do-no-locktorture)
136 do_locktorture=`doyesno "$1" --do-locktorture`
149 --do-rcuscale|--do-no-rcuscale)
150 do_rcuscale=`doyesno "$1" --do-rcuscale`
152 --do-rcutorture|--do-no-rcutorture)
153 do_rcutorture=`doyesno "$1" --do-rcutorture`
155 --do-refscale|--do-no-refscale)
156 do_refscale=`doyesno "$1" --do-refscale`
158 --do-scftorture|--do-no-scftorture)
159 do_scftorture=`doyesno "$1" --do-scftorture`
162 checkarg --duration "(minutes)" $# "$2" '^[0-9][0-9]*\(m\|h\|d\|\)$' '^error'
164 if echo "$2" | grep -q 'm$'
167 elif echo "$2" | grep -q 'h$'
170 elif echo "$2" | grep -q 'd$'
174 ts=`echo $2 | sed -e 's/[smhd]$//'`
175 duration_base=$(($ts*mult))
178 --kcsan-kmake-arg|--kcsan-kmake-args)
179 checkarg --kcsan-kmake-arg "(kernel make arguments)" $# "$2" '.*' '^error$'
180 kcsan_kmake_args="`echo "$kcsan_kmake_args $2" | sed -e 's/^ *//' -e 's/ *$//'`"
184 echo Unknown argument $1
191 ds="`date +%Y.%m.%d-%H.%M.%S`-torture"
193 starttime="`get_starttime`"
199 echo " --- " $scriptname $args | tee -a $T/log
200 echo " --- Results directory: " $ds | tee -a $T/log
202 # Calculate rcutorture defaults and apportion time
203 if test -z "$configs_rcutorture"
205 configs_rcutorture=CFLIST
207 duration_rcutorture=$((duration_base*duration_rcutorture_frac/10))
208 if test "$duration_rcutorture" -eq 0
210 echo " --- Zero time for rcutorture, disabling" | tee -a $T/log
214 # Calculate locktorture defaults and apportion time
215 if test -z "$configs_locktorture"
217 configs_locktorture=CFLIST
219 duration_locktorture=$((duration_base*duration_locktorture_frac/10))
220 if test "$duration_locktorture" -eq 0
222 echo " --- Zero time for locktorture, disabling" | tee -a $T/log
226 # Calculate scftorture defaults and apportion time
227 if test -z "$configs_scftorture"
229 configs_scftorture=CFLIST
231 duration_scftorture=$((duration_base*duration_scftorture_frac/10))
232 if test "$duration_scftorture" -eq 0
234 echo " --- Zero time for scftorture, disabling" | tee -a $T/log
241 # torture_one - Does a single kvm.sh run.
244 # torture_bootargs="[ kernel boot arguments ]"
245 # torture_one flavor [ kvm.sh arguments ]
247 # Note that "flavor" is an arbitrary string. Supply --torture if needed.
248 # Note that quoting is problematic. So on the command line, pass multiple
249 # values with multiple kvm.sh argument instances.
250 function torture_one {
254 echo " --- $curflavor:" Start `date` | tee -a $T/log
255 if test -n "$torture_bootargs"
258 cur_bootargs="$torture_bootargs"
260 "$@" $boottag "$cur_bootargs" --datestamp "$ds/results-$curflavor" > $T/$curflavor.out 2>&1
262 resdir="`grep '^Results directory: ' $T/$curflavor.out | tail -1 | sed -e 's/^Results directory: //'`"
265 cat $T/$curflavor.out | tee -a $T/log
266 echo retcode=$retcode | tee -a $T/log
268 if test "$retcode" == 0
270 echo "$curflavor($retcode)" $resdir >> $T/successes
272 echo "$curflavor($retcode)" $resdir >> $T/failures
276 # torture_set - Does a set of tortures with and without KASAN and KCSAN.
279 # torture_bootargs="[ kernel boot arguments ]"
280 # torture_set flavor [ kvm.sh arguments ]
282 # Note that "flavor" is an arbitrary string. Supply --torture if needed.
283 # Note that quoting is problematic. So on the command line, pass multiple
284 # values with multiple kvm.sh argument instances.
285 function torture_set {
286 local cur_kcsan_kmake_args=
287 local kcsan_kmake_tag=
292 if test "$do_kasan" = "yes"
294 curflavor=${flavor}-kasan
295 torture_one "$@" --kasan
297 if test "$do_kcsan" = "yes"
299 curflavor=${flavor}-kcsan
300 if test -n "$kcsan_kmake_args"
302 kcsan_kmake_tag="--kmake-args"
303 cur_kcsan_kmake_args="$kcsan_kmake_args"
305 torture_one "$@" --kconfig "CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y" $kcsan_kmake_tag $cur_kcsan_kmake_args --kcsan
310 if test "$do_allmodconfig" = "yes"
312 echo " --- allmodconfig:" Start `date` | tee -a $T/log
313 amcdir="tools/testing/selftests/rcutorture/res/$ds/allmodconfig"
315 echo " --- make clean" > "$amcdir/Make.out" 2>&1
316 make -j$MAKE_ALLOTED_CPUS clean >> "$amcdir/Make.out" 2>&1
317 echo " --- make allmodconfig" >> "$amcdir/Make.out" 2>&1
318 make -j$MAKE_ALLOTED_CPUS allmodconfig >> "$amcdir/Make.out" 2>&1
319 echo " --- make " >> "$amcdir/Make.out" 2>&1
320 make -j$MAKE_ALLOTED_CPUS >> "$amcdir/Make.out" 2>&1
322 echo $retcode > "$amcdir/Make.exitcode"
323 if test "$retcode" == 0
325 echo "allmodconfig($retcode)" $amcdir >> $T/successes
327 echo "allmodconfig($retcode)" $amcdir >> $T/failures
332 if test "$do_rcutorture" = "yes"
334 torture_bootargs="rcupdate.rcu_cpu_stall_suppress_at_boot=1 torture.disable_onoff_at_boot rcupdate.rcu_task_stall_timeout=30000"
335 torture_set "rcutorture" tools/testing/selftests/rcutorture/bin/kvm.sh --allcpus --duration "$duration_rcutorture" --configs "$configs_rcutorture" --trust-make
338 if test "$do_locktorture" = "yes"
340 torture_bootargs="torture.disable_onoff_at_boot"
341 torture_set "locktorture" tools/testing/selftests/rcutorture/bin/kvm.sh --torture lock --allcpus --duration "$duration_locktorture" --configs "$configs_locktorture" --trust-make
344 if test "$do_scftorture" = "yes"
346 torture_bootargs="scftorture.nthreads=$HALF_ALLOTED_CPUS torture.disable_onoff_at_boot"
347 torture_set "scftorture" tools/testing/selftests/rcutorture/bin/kvm.sh --torture scf --allcpus --duration "$duration_scftorture" --configs "$configs_scftorture" --kconfig "CONFIG_NR_CPUS=$HALF_ALLOTED_CPUS" --trust-make
350 if test "$do_refscale" = yes
352 primlist="`grep '\.name[ ]*=' kernel/rcu/refscale.c | sed -e 's/^[^"]*"//' -e 's/".*$//'`"
356 for prim in $primlist
358 torture_bootargs="refscale.scale_type="$prim" refscale.nreaders=$HALF_ALLOTED_CPUS refscale.loops=10000 refscale.holdoff=20 torture.disable_onoff_at_boot"
359 torture_set "refscale-$prim" tools/testing/selftests/rcutorture/bin/kvm.sh --torture refscale --allcpus --duration 5 --kconfig "CONFIG_NR_CPUS=$HALF_ALLOTED_CPUS" --bootargs "verbose_batched=$VERBOSE_BATCH_CPUS torture.verbose_sleep_frequency=8 torture.verbose_sleep_duration=$VERBOSE_BATCH_CPUS" --trust-make
362 if test "$do_rcuscale" = yes
364 primlist="`grep '\.name[ ]*=' kernel/rcu/rcuscale.c | sed -e 's/^[^"]*"//' -e 's/".*$//'`"
368 for prim in $primlist
370 torture_bootargs="rcuscale.scale_type="$prim" rcuscale.nwriters=$HALF_ALLOTED_CPUS rcuscale.holdoff=20 torture.disable_onoff_at_boot"
371 torture_set "rcuscale-$prim" tools/testing/selftests/rcutorture/bin/kvm.sh --torture rcuscale --allcpus --duration 5 --kconfig "CONFIG_NR_CPUS=$HALF_ALLOTED_CPUS" --trust-make
374 if test "$do_kvfree" = "yes"
376 torture_bootargs="rcuscale.kfree_rcu_test=1 rcuscale.kfree_nthreads=16 rcuscale.holdoff=20 rcuscale.kfree_loops=10000 torture.disable_onoff_at_boot"
377 torture_set "rcuscale-kvfree" tools/testing/selftests/rcutorture/bin/kvm.sh --torture rcuscale --allcpus --duration 10 --kconfig "CONFIG_NR_CPUS=$HALF_ALLOTED_CPUS" --memory 1G --trust-make
380 echo " --- " $scriptname $args
381 echo " --- " Done `date` | tee -a $T/log
384 echo SUCCESSES: | tee -a $T/log
385 if test -s "$T/successes"
387 cat "$T/successes" | tee -a $T/log
388 nsuccesses="`wc -l "$T/successes" | awk '{ print $1 }'`"
391 echo FAILURES: | tee -a $T/log
392 if test -s "$T/failures"
394 cat "$T/failures" | tee -a $T/log
395 nfailures="`wc -l "$T/failures" | awk '{ print $1 }'`"
398 echo Started at $startdate, ended at `date`, duration `get_starttime_duration $starttime`. | tee -a $T/log
399 echo Summary: Successes: $nsuccesses Failures: $nfailures. | tee -a $T/log
400 tdir="`cat $T/successes $T/failures | head -1 | awk '{ print $NF }' | sed -e 's,/[^/]\+/*$,,'`"
401 if test -n "$tdir" && test $compress_kasan_vmlinux -gt 0
403 # KASAN vmlinux files can approach 1GB in size, so compress them.
404 echo Looking for KASAN files to compress: `date` > "$tdir/log-xz" 2>&1
405 find "$tdir" -type d -name '*-kasan' -print > $T/xz-todo
408 if test -s $T/xz-todo
410 echo Size before compressing: `du -sh $tdir | awk '{ print $1 }'` `date` 2>&1 | tee -a "$tdir/log-xz" | tee -a $T/log
411 for i in `cat $T/xz-todo`
413 echo Compressing vmlinux files in ${i}: `date` >> "$tdir/log-xz" 2>&1
414 for j in $i/*/vmlinux
416 xz "$j" >> "$tdir/log-xz" 2>&1 &
417 ncompresses=$((ncompresses+1))
418 if test $ncompresses -ge $compress_kasan_vmlinux
420 echo Waiting for batch $batchno of $ncompresses compressions `date` | tee -a "$tdir/log-xz" | tee -a $T/log
423 batchno=$((batchno+1))
427 if test $ncompresses -gt 0
429 echo Waiting for final batch $batchno of $ncompresses compressions `date` | tee -a "$tdir/log-xz" | tee -a $T/log
432 echo Size after compressing: `du -sh $tdir | awk '{ print $1 }'` `date` 2>&1 | tee -a "$tdir/log-xz" | tee -a $T/log
433 echo Total duration `get_starttime_duration $starttime`. | tee -a $T/log
435 echo No compression needed: `date` >> "$tdir/log-xz" 2>&1