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