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 RCUTORTURE="`pwd`/tools/testing/selftests/rcutorture"; export RCUTORTURE
17 PATH=${RCUTORTURE}/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_concurrency="`identify_qemu_vcpus`"
42 duration_rcutorture_frac=7
43 duration_locktorture_frac=1
44 duration_scftorture_frac=2
46 # "yes" or "no" parameters
58 # doyesno - Helper function for yes/no arguments
69 echo "Usage: $scriptname optional arguments:"
70 echo " --compress-concurrency concurrency"
71 echo " --configs-rcutorture \"config-file list w/ repeat factor (3*TINY01)\""
72 echo " --configs-locktorture \"config-file list w/ repeat factor (10*LOCK01)\""
73 echo " --configs-scftorture \"config-file list w/ repeat factor (2*CFLIST)\""
75 echo " --do-allmodconfig / --do-no-allmodconfig"
76 echo " --do-clocksourcewd / --do-no-clocksourcewd"
77 echo " --do-kasan / --do-no-kasan"
78 echo " --do-kcsan / --do-no-kcsan"
79 echo " --do-kvfree / --do-no-kvfree"
80 echo " --do-locktorture / --do-no-locktorture"
82 echo " --do-rcuscale / --do-no-rcuscale"
83 echo " --do-rcutorture / --do-no-rcutorture"
84 echo " --do-refscale / --do-no-refscale"
85 echo " --do-scftorture / --do-no-scftorture"
86 echo " --duration [ <minutes> | <hours>h | <days>d ]"
87 echo " --kcsan-kmake-arg kernel-make-arguments"
94 --compress-concurrency)
95 checkarg --compress-concurrency "(concurrency level)" $# "$2" '^[0-9][0-9]*$' '^error'
96 compress_concurrency=$2
99 --config-rcutorture|--configs-rcutorture)
100 checkarg --configs-rcutorture "(list of config files)" "$#" "$2" '^[^/]\+$' '^--'
101 configs_rcutorture="$configs_rcutorture $2"
104 --config-locktorture|--configs-locktorture)
105 checkarg --configs-locktorture "(list of config files)" "$#" "$2" '^[^/]\+$' '^--'
106 configs_locktorture="$configs_locktorture $2"
109 --config-scftorture|--configs-scftorture)
110 checkarg --configs-scftorture "(list of config files)" "$#" "$2" '^[^/]\+$' '^--'
111 configs_scftorture="$configs_scftorture $2"
126 --do-allmodconfig|--do-no-allmodconfig)
127 do_allmodconfig=`doyesno "$1" --do-allmodconfig`
129 --do-clocksourcewd|--do-no-clocksourcewd)
130 do_clocksourcewd=`doyesno "$1" --do-clocksourcewd`
132 --do-kasan|--do-no-kasan)
133 do_kasan=`doyesno "$1" --do-kasan`
135 --do-kcsan|--do-no-kcsan)
136 do_kcsan=`doyesno "$1" --do-kcsan`
138 --do-kvfree|--do-no-kvfree)
139 do_kvfree=`doyesno "$1" --do-kvfree`
141 --do-locktorture|--do-no-locktorture)
142 do_locktorture=`doyesno "$1" --do-locktorture`
156 --do-rcuscale|--do-no-rcuscale)
157 do_rcuscale=`doyesno "$1" --do-rcuscale`
159 --do-rcutorture|--do-no-rcutorture)
160 do_rcutorture=`doyesno "$1" --do-rcutorture`
162 --do-refscale|--do-no-refscale)
163 do_refscale=`doyesno "$1" --do-refscale`
165 --do-scftorture|--do-no-scftorture)
166 do_scftorture=`doyesno "$1" --do-scftorture`
169 checkarg --duration "(minutes)" $# "$2" '^[0-9][0-9]*\(m\|h\|d\|\)$' '^error'
171 if echo "$2" | grep -q 'm$'
174 elif echo "$2" | grep -q 'h$'
177 elif echo "$2" | grep -q 'd$'
181 ts=`echo $2 | sed -e 's/[smhd]$//'`
182 duration_base=$(($ts*mult))
185 --kcsan-kmake-arg|--kcsan-kmake-args)
186 checkarg --kcsan-kmake-arg "(kernel make arguments)" $# "$2" '.*' '^error$'
187 kcsan_kmake_args="`echo "$kcsan_kmake_args $2" | sed -e 's/^ *//' -e 's/ *$//'`"
191 echo Unknown argument $1
198 ds="`date +%Y.%m.%d-%H.%M.%S`-torture"
200 starttime="`get_starttime`"
206 echo " --- " $scriptname $args | tee -a $T/log
207 echo " --- Results directory: " $ds | tee -a $T/log
209 # Calculate rcutorture defaults and apportion time
210 if test -z "$configs_rcutorture"
212 configs_rcutorture=CFLIST
214 duration_rcutorture=$((duration_base*duration_rcutorture_frac/10))
215 if test "$duration_rcutorture" -eq 0
217 echo " --- Zero time for rcutorture, disabling" | tee -a $T/log
221 # Calculate locktorture defaults and apportion time
222 if test -z "$configs_locktorture"
224 configs_locktorture=CFLIST
226 duration_locktorture=$((duration_base*duration_locktorture_frac/10))
227 if test "$duration_locktorture" -eq 0
229 echo " --- Zero time for locktorture, disabling" | tee -a $T/log
233 # Calculate scftorture defaults and apportion time
234 if test -z "$configs_scftorture"
236 configs_scftorture=CFLIST
238 duration_scftorture=$((duration_base*duration_scftorture_frac/10))
239 if test "$duration_scftorture" -eq 0
241 echo " --- Zero time for scftorture, disabling" | tee -a $T/log
248 # torture_one - Does a single kvm.sh run.
251 # torture_bootargs="[ kernel boot arguments ]"
252 # torture_one flavor [ kvm.sh arguments ]
254 # Note that "flavor" is an arbitrary string. Supply --torture if needed.
255 # Note that quoting is problematic. So on the command line, pass multiple
256 # values with multiple kvm.sh argument instances.
257 function torture_one {
261 echo " --- $curflavor:" Start `date` | tee -a $T/log
262 if test -n "$torture_bootargs"
265 cur_bootargs="$torture_bootargs"
267 "$@" $boottag "$cur_bootargs" --datestamp "$ds/results-$curflavor" > $T/$curflavor.out 2>&1
269 resdir="`grep '^Results directory: ' $T/$curflavor.out | tail -1 | sed -e 's/^Results directory: //'`"
272 cat $T/$curflavor.out | tee -a $T/log
273 echo retcode=$retcode | tee -a $T/log
275 if test "$retcode" == 0
277 echo "$curflavor($retcode)" $resdir >> $T/successes
279 echo "$curflavor($retcode)" $resdir >> $T/failures
283 # torture_set - Does a set of tortures with and without KASAN and KCSAN.
286 # torture_bootargs="[ kernel boot arguments ]"
287 # torture_set flavor [ kvm.sh arguments ]
289 # Note that "flavor" is an arbitrary string that does not affect kvm.sh
290 # in any way. So also supply --torture if you need something other than
292 function torture_set {
293 local cur_kcsan_kmake_args=
294 local kcsan_kmake_tag=
299 if test "$do_kasan" = "yes"
301 curflavor=${flavor}-kasan
302 torture_one "$@" --kasan
304 if test "$do_kcsan" = "yes"
306 curflavor=${flavor}-kcsan
307 if test -n "$kcsan_kmake_args"
309 kcsan_kmake_tag="--kmake-args"
310 cur_kcsan_kmake_args="$kcsan_kmake_args"
312 torture_one "$@" --kconfig "CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y" $kcsan_kmake_tag $cur_kcsan_kmake_args --kcsan
317 if test "$do_allmodconfig" = "yes"
319 echo " --- allmodconfig:" Start `date` | tee -a $T/log
320 amcdir="tools/testing/selftests/rcutorture/res/$ds/allmodconfig"
322 echo " --- make clean" > "$amcdir/Make.out" 2>&1
323 make -j$MAKE_ALLOTED_CPUS clean >> "$amcdir/Make.out" 2>&1
324 echo " --- make allmodconfig" >> "$amcdir/Make.out" 2>&1
325 make -j$MAKE_ALLOTED_CPUS allmodconfig >> "$amcdir/Make.out" 2>&1
326 echo " --- make " >> "$amcdir/Make.out" 2>&1
327 make -j$MAKE_ALLOTED_CPUS >> "$amcdir/Make.out" 2>&1
329 echo $retcode > "$amcdir/Make.exitcode"
330 if test "$retcode" == 0
332 echo "allmodconfig($retcode)" $amcdir >> $T/successes
334 echo "allmodconfig($retcode)" $amcdir >> $T/failures
339 if test "$do_rcutorture" = "yes"
341 torture_bootargs="rcupdate.rcu_cpu_stall_suppress_at_boot=1 torture.disable_onoff_at_boot rcupdate.rcu_task_stall_timeout=30000"
342 torture_set "rcutorture" tools/testing/selftests/rcutorture/bin/kvm.sh --allcpus --duration "$duration_rcutorture" --configs "$configs_rcutorture" --trust-make
345 if test "$do_locktorture" = "yes"
347 torture_bootargs="torture.disable_onoff_at_boot"
348 torture_set "locktorture" tools/testing/selftests/rcutorture/bin/kvm.sh --torture lock --allcpus --duration "$duration_locktorture" --configs "$configs_locktorture" --trust-make
351 if test "$do_scftorture" = "yes"
353 torture_bootargs="scftorture.nthreads=$HALF_ALLOTED_CPUS torture.disable_onoff_at_boot"
354 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" --memory 1G --trust-make
357 if test "$do_refscale" = yes
359 primlist="`grep '\.name[ ]*=' kernel/rcu/refscale.c | sed -e 's/^[^"]*"//' -e 's/".*$//'`"
363 for prim in $primlist
365 torture_bootargs="refscale.scale_type="$prim" refscale.nreaders=$HALF_ALLOTED_CPUS refscale.loops=10000 refscale.holdoff=20 torture.disable_onoff_at_boot"
366 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
369 if test "$do_rcuscale" = yes
371 primlist="`grep '\.name[ ]*=' kernel/rcu/rcuscale.c | sed -e 's/^[^"]*"//' -e 's/".*$//'`"
375 for prim in $primlist
377 torture_bootargs="rcuscale.scale_type="$prim" rcuscale.nwriters=$HALF_ALLOTED_CPUS rcuscale.holdoff=20 torture.disable_onoff_at_boot"
378 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
381 if test "$do_kvfree" = "yes"
383 torture_bootargs="rcuscale.kfree_rcu_test=1 rcuscale.kfree_nthreads=16 rcuscale.holdoff=20 rcuscale.kfree_loops=10000 torture.disable_onoff_at_boot"
384 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
387 if test "$do_clocksourcewd" = "yes"
389 torture_bootargs="rcupdate.rcu_cpu_stall_suppress_at_boot=1 torture.disable_onoff_at_boot rcupdate.rcu_task_stall_timeout=30000"
390 torture_set "clocksourcewd-1" tools/testing/selftests/rcutorture/bin/kvm.sh --allcpus --duration 45s --configs TREE03 --kconfig "CONFIG_TEST_CLOCKSOURCE_WATCHDOG=y" --trust-make
392 torture_bootargs="rcupdate.rcu_cpu_stall_suppress_at_boot=1 torture.disable_onoff_at_boot rcupdate.rcu_task_stall_timeout=30000 clocksource.max_cswd_read_retries=1"
393 torture_set "clocksourcewd-2" tools/testing/selftests/rcutorture/bin/kvm.sh --allcpus --duration 45s --configs TREE03 --kconfig "CONFIG_TEST_CLOCKSOURCE_WATCHDOG=y" --trust-make
395 # In case our work is already done...
396 if test "$do_rcutorture" != "yes"
398 torture_bootargs="rcupdate.rcu_cpu_stall_suppress_at_boot=1 torture.disable_onoff_at_boot rcupdate.rcu_task_stall_timeout=30000"
399 torture_set "clocksourcewd-3" tools/testing/selftests/rcutorture/bin/kvm.sh --allcpus --duration 45s --configs TREE03 --trust-make
403 echo " --- " $scriptname $args
404 echo " --- " Done `date` | tee -a $T/log
407 echo SUCCESSES: | tee -a $T/log
408 if test -s "$T/successes"
410 cat "$T/successes" | tee -a $T/log
411 nsuccesses="`wc -l "$T/successes" | awk '{ print $1 }'`"
414 echo FAILURES: | tee -a $T/log
415 if test -s "$T/failures"
417 awk < "$T/failures" -v sq="'" '{ print "echo " sq $0 sq; print "sed -e " sq "1,/^ --- .* Test summary:$/d" sq " " $2 "/log | grep Summary: | sed -e " sq "s/^[^S]*/ /" sq; }' | sh | tee -a $T/log | tee "$T/failuresum"
418 nfailures="`wc -l "$T/failures" | awk '{ print $1 }'`"
419 grep "^ Summary: " "$T/failuresum" |
420 grep -v '^ Summary: Bugs: [0-9]* (all bugs kcsan)$' > "$T/nonkcsan"
421 if test -s "$T/nonkcsan"
427 if test "$do_kcsan" = "yes"
429 TORTURE_KCONFIG_KCSAN_ARG=1 tools/testing/selftests/rcutorture/bin/kcsan-collapse.sh tools/testing/selftests/rcutorture/res/$ds > tools/testing/selftests/rcutorture/res/$ds/kcsan.sum
431 echo Started at $startdate, ended at `date`, duration `get_starttime_duration $starttime`. | tee -a $T/log
432 echo Summary: Successes: $nsuccesses Failures: $nfailures. | tee -a $T/log
433 if test -z "$nonkcsanbug" && test -s "$T/failuresum"
435 echo " All bugs were KCSAN failures."
437 tdir="`cat $T/successes $T/failures | head -1 | awk '{ print $NF }' | sed -e 's,/[^/]\+/*$,,'`"
438 if test -n "$tdir" && test $compress_concurrency -gt 0
440 # KASAN vmlinux files can approach 1GB in size, so compress them.
441 echo Looking for K[AC]SAN files to compress: `date` > "$tdir/log-xz" 2>&1
442 find "$tdir" -type d -name '*-k[ac]san' -print > $T/xz-todo
445 if test -s $T/xz-todo
447 for i in `cat $T/xz-todo`
449 find $i -name 'vmlinux*' -print
450 done | wc -l | awk '{ print $1 }' > $T/xz-todo-count
451 n2compress="`cat $T/xz-todo-count`"
452 echo Size before compressing $n2compress files: `du -sh $tdir | awk '{ print $1 }'` `date` 2>&1 | tee -a "$tdir/log-xz" | tee -a $T/log
453 for i in `cat $T/xz-todo`
455 echo Compressing vmlinux files in ${i}: `date` >> "$tdir/log-xz" 2>&1
456 for j in $i/*/vmlinux
458 xz "$j" >> "$tdir/log-xz" 2>&1 &
459 ncompresses=$((ncompresses+1))
460 if test $ncompresses -ge $compress_concurrency
462 echo Waiting for batch $batchno of $ncompresses compressions `date` | tee -a "$tdir/log-xz" | tee -a $T/log
465 batchno=$((batchno+1))
469 if test $ncompresses -gt 0
471 echo Waiting for final batch $batchno of $ncompresses compressions `date` | tee -a "$tdir/log-xz" | tee -a $T/log
474 echo Size after compressing $n2compress files: `du -sh $tdir | awk '{ print $1 }'` `date` 2>&1 | tee -a "$tdir/log-xz" | tee -a $T/log
475 echo Total duration `get_starttime_duration $starttime`. | tee -a $T/log
477 echo No compression needed: `date` >> "$tdir/log-xz" 2>&1