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 27TORTURE_ALLOTED_CPUS="" 28TORTURE_DEFCONFIG=defconfig 29TORTURE_BOOT_IMAGE="" 30TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD 31TORTURE_KCONFIG_ARG="" 32TORTURE_KMAKE_ARG="" 33TORTURE_QEMU_MEM=512 34TORTURE_SHUTDOWN_GRACE=180 35TORTURE_SUITE=rcu 36TORTURE_TRUST_MAKE="" 37resdir="" 38configs="" 39cpus=0 40ds=`date +%Y.%m.%d-%H:%M:%S` 41jitter="-1" 42 43. functions.sh 44 45usage () { 46 echo "Usage: $scriptname optional arguments:" 47 echo " --bootargs kernel-boot-arguments" 48 echo " --bootimage relative-path-to-kernel-boot-image" 49 echo " --buildonly" 50 echo " --configs \"config-file list w/ repeat factor (3*TINY01)\"" 51 echo " --cpus N" 52 echo " --datestamp string" 53 echo " --defconfig string" 54 echo " --dryrun sched|script" 55 echo " --duration minutes" 56 echo " --interactive" 57 echo " --jitter N [ maxsleep (us) [ maxspin (us) ] ]" 58 echo " --kconfig Kconfig-options" 59 echo " --kmake-arg kernel-make-arguments" 60 echo " --mac nn:nn:nn:nn:nn:nn" 61 echo " --memory megabytes | nnnG" 62 echo " --no-initrd" 63 echo " --qemu-args qemu-arguments" 64 echo " --qemu-cmd qemu-system-..." 65 echo " --results absolute-pathname" 66 echo " --torture rcu" 67 echo " --trust-make" 68 exit 1 69} 70 71while test $# -gt 0 72do 73 case "$1" in 74 --bootargs|--bootarg) 75 checkarg --bootargs "(list of kernel boot arguments)" "$#" "$2" '.*' '^--' 76 TORTURE_BOOTARGS="$2" 77 shift 78 ;; 79 --bootimage) 80 checkarg --bootimage "(relative path to kernel boot image)" "$#" "$2" '[a-zA-Z0-9][a-zA-Z0-9_]*' '^--' 81 TORTURE_BOOT_IMAGE="$2" 82 shift 83 ;; 84 --buildonly) 85 TORTURE_BUILDONLY=1 86 ;; 87 --configs|--config) 88 checkarg --configs "(list of config files)" "$#" "$2" '^[^/]*$' '^--' 89 configs="$2" 90 shift 91 ;; 92 --cpus) 93 checkarg --cpus "(number)" "$#" "$2" '^[0-9]*$' '^--' 94 cpus=$2 95 TORTURE_ALLOTED_CPUS="$2" 96 shift 97 ;; 98 --datestamp) 99 checkarg --datestamp "(relative pathname)" "$#" "$2" '^[^/]*$' '^--' 100 ds=$2 101 shift 102 ;; 103 --defconfig) 104 checkarg --defconfig "defconfigtype" "$#" "$2" '^[^/][^/]*$' '^--' 105 TORTURE_DEFCONFIG=$2 106 shift 107 ;; 108 --dryrun) 109 checkarg --dryrun "sched|script" $# "$2" 'sched\|script' '^--' 110 dryrun=$2 111 shift 112 ;; 113 --duration) 114 checkarg --duration "(minutes)" $# "$2" '^[0-9]*$' '^error' 115 dur=$(($2*60)) 116 shift 117 ;; 118 --interactive) 119 TORTURE_QEMU_INTERACTIVE=1; export TORTURE_QEMU_INTERACTIVE 120 ;; 121 --jitter) 122 checkarg --jitter "(# threads [ sleep [ spin ] ])" $# "$2" '^-\{,1\}[0-9]\+\( \+[0-9]\+\)\{,2\} *$' '^error$' 123 jitter="$2" 124 shift 125 ;; 126 --kconfig) 127 checkarg --kconfig "(Kconfig options)" $# "$2" '^CONFIG_[A-Z0-9_]\+=\([ynm]\|[0-9]\+\)\( CONFIG_[A-Z0-9_]\+=\([ynm]\|[0-9]\+\)\)*$' '^error$' 128 TORTURE_KCONFIG_ARG="$2" 129 shift 130 ;; 131 --kmake-arg) 132 checkarg --kmake-arg "(kernel make arguments)" $# "$2" '.*' '^error$' 133 TORTURE_KMAKE_ARG="$2" 134 shift 135 ;; 136 --mac) 137 checkarg --mac "(MAC address)" $# "$2" '^\([0-9a-fA-F]\{2\}:\)\{5\}[0-9a-fA-F]\{2\}$' error 138 TORTURE_QEMU_MAC=$2 139 shift 140 ;; 141 --memory) 142 checkarg --memory "(memory size)" $# "$2" '^[0-9]\+[MG]\?$' error 143 TORTURE_QEMU_MEM=$2 144 shift 145 ;; 146 --no-initrd) 147 TORTURE_INITRD=""; export TORTURE_INITRD 148 ;; 149 --qemu-args|--qemu-arg) 150 checkarg --qemu-args "(qemu arguments)" $# "$2" '^-' '^error' 151 TORTURE_QEMU_ARG="$2" 152 shift 153 ;; 154 --qemu-cmd) 155 checkarg --qemu-cmd "(qemu-system-...)" $# "$2" 'qemu-system-' '^--' 156 TORTURE_QEMU_CMD="$2" 157 shift 158 ;; 159 --results) 160 checkarg --results "(absolute pathname)" "$#" "$2" '^/' '^error' 161 resdir=$2 162 shift 163 ;; 164 --shutdown-grace) 165 checkarg --shutdown-grace "(seconds)" "$#" "$2" '^[0-9]*$' '^error' 166 TORTURE_SHUTDOWN_GRACE=$2 167 shift 168 ;; 169 --torture) 170 checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\|rcuperf\)$' '^--' 171 TORTURE_SUITE=$2 172 shift 173 if test "$TORTURE_SUITE" = rcuperf 174 then 175 # If you really want jitter for rcuperf, specify 176 # it after specifying rcuperf. (But why?) 177 jitter=0 178 fi 179 ;; 180 --trust-make) 181 TORTURE_TRUST_MAKE="y" 182 ;; 183 *) 184 echo Unknown argument $1 185 usage 186 ;; 187 esac 188 shift 189done 190 191if test -z "$TORTURE_INITRD" || tools/testing/selftests/rcutorture/bin/mkinitrd.sh 192then 193 : 194else 195 echo No initrd and unable to create one, aborting test >&2 196 exit 1 197fi 198 199CONFIGFRAG=${KVM}/configs/${TORTURE_SUITE}; export CONFIGFRAG 200 201if test -z "$configs" 202then 203 configs="`cat $CONFIGFRAG/CFLIST`" 204fi 205 206if test -z "$resdir" 207then 208 resdir=$KVM/res 209fi 210 211# Create a file of test-name/#cpus pairs, sorted by decreasing #cpus. 212touch $T/cfgcpu 213for CF in $configs 214do 215 case $CF in 216 [0-9]\**|[0-9][0-9]\**|[0-9][0-9][0-9]\**) 217 config_reps=`echo $CF | sed -e 's/\*.*$//'` 218 CF1=`echo $CF | sed -e 's/^[^*]*\*//'` 219 ;; 220 *) 221 config_reps=1 222 CF1=$CF 223 ;; 224 esac 225 if test -f "$CONFIGFRAG/$CF1" 226 then 227 cpu_count=`configNR_CPUS.sh $CONFIGFRAG/$CF1` 228 cpu_count=`configfrag_boot_cpus "$TORTURE_BOOTARGS" "$CONFIGFRAG/$CF1" "$cpu_count"` 229 cpu_count=`configfrag_boot_maxcpus "$TORTURE_BOOTARGS" "$CONFIGFRAG/$CF1" "$cpu_count"` 230 for ((cur_rep=0;cur_rep<$config_reps;cur_rep++)) 231 do 232 echo $CF1 $cpu_count >> $T/cfgcpu 233 done 234 else 235 echo "The --configs file $CF1 does not exist, terminating." 236 exit 1 237 fi 238done 239sort -k2nr $T/cfgcpu -T="$T" > $T/cfgcpu.sort 240 241# Use a greedy bin-packing algorithm, sorting the list accordingly. 242awk < $T/cfgcpu.sort > $T/cfgcpu.pack -v ncpus=$cpus ' 243BEGIN { 244 njobs = 0; 245} 246 247{ 248 # Read file of tests and corresponding required numbers of CPUs. 249 cf[njobs] = $1; 250 cpus[njobs] = $2; 251 njobs++; 252} 253 254END { 255 batch = 0; 256 nc = -1; 257 258 # Each pass through the following loop creates on test batch 259 # that can be executed concurrently given ncpus. Note that a 260 # given test that requires more than the available CPUs will run in 261 # their own batch. Such tests just have to make do with what 262 # is available. 263 while (nc != ncpus) { 264 batch++; 265 nc = ncpus; 266 267 # Each pass through the following loop considers one 268 # test for inclusion in the current batch. 269 for (i = 0; i < njobs; i++) { 270 if (done[i]) 271 continue; # Already part of a batch. 272 if (nc >= cpus[i] || nc == ncpus) { 273 274 # This test fits into the current batch. 275 done[i] = batch; 276 nc -= cpus[i]; 277 if (nc <= 0) 278 break; # Too-big test in its own batch. 279 } 280 } 281 } 282 283 # Dump out the tests in batch order. 284 for (b = 1; b <= batch; b++) 285 for (i = 0; i < njobs; i++) 286 if (done[i] == b) 287 print cf[i], cpus[i]; 288}' 289 290# Generate a script to execute the tests in appropriate batches. 291cat << ___EOF___ > $T/script 292CONFIGFRAG="$CONFIGFRAG"; export CONFIGFRAG 293KVM="$KVM"; export KVM 294PATH="$PATH"; export PATH 295TORTURE_ALLOTED_CPUS="$TORTURE_ALLOTED_CPUS"; export TORTURE_ALLOTED_CPUS 296TORTURE_BOOT_IMAGE="$TORTURE_BOOT_IMAGE"; export TORTURE_BOOT_IMAGE 297TORTURE_BUILDONLY="$TORTURE_BUILDONLY"; export TORTURE_BUILDONLY 298TORTURE_DEFCONFIG="$TORTURE_DEFCONFIG"; export TORTURE_DEFCONFIG 299TORTURE_INITRD="$TORTURE_INITRD"; export TORTURE_INITRD 300TORTURE_KCONFIG_ARG="$TORTURE_KCONFIG_ARG"; export TORTURE_KCONFIG_ARG 301TORTURE_KMAKE_ARG="$TORTURE_KMAKE_ARG"; export TORTURE_KMAKE_ARG 302TORTURE_QEMU_CMD="$TORTURE_QEMU_CMD"; export TORTURE_QEMU_CMD 303TORTURE_QEMU_INTERACTIVE="$TORTURE_QEMU_INTERACTIVE"; export TORTURE_QEMU_INTERACTIVE 304TORTURE_QEMU_MAC="$TORTURE_QEMU_MAC"; export TORTURE_QEMU_MAC 305TORTURE_QEMU_MEM="$TORTURE_QEMU_MEM"; export TORTURE_QEMU_MEM 306TORTURE_SHUTDOWN_GRACE="$TORTURE_SHUTDOWN_GRACE"; export TORTURE_SHUTDOWN_GRACE 307TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE 308TORTURE_TRUST_MAKE="$TORTURE_TRUST_MAKE"; export TORTURE_TRUST_MAKE 309if ! test -e $resdir 310then 311 mkdir -p "$resdir" || : 312fi 313mkdir $resdir/$ds 314echo Results directory: $resdir/$ds 315echo $scriptname $args 316touch $resdir/$ds/log 317echo $scriptname $args >> $resdir/$ds/log 318echo ${TORTURE_SUITE} > $resdir/$ds/TORTURE_SUITE 319pwd > $resdir/$ds/testid.txt 320if test -d .git 321then 322 git status >> $resdir/$ds/testid.txt 323 git rev-parse HEAD >> $resdir/$ds/testid.txt 324 git diff HEAD >> $resdir/$ds/testid.txt 325fi 326___EOF___ 327awk < $T/cfgcpu.pack \ 328 -v TORTURE_BUILDONLY="$TORTURE_BUILDONLY" \ 329 -v CONFIGDIR="$CONFIGFRAG/" \ 330 -v KVM="$KVM" \ 331 -v ncpus=$cpus \ 332 -v jitter="$jitter" \ 333 -v rd=$resdir/$ds/ \ 334 -v dur=$dur \ 335 -v TORTURE_QEMU_ARG="$TORTURE_QEMU_ARG" \ 336 -v TORTURE_BOOTARGS="$TORTURE_BOOTARGS" \ 337'BEGIN { 338 i = 0; 339} 340 341{ 342 cf[i] = $1; 343 cpus[i] = $2; 344 i++; 345} 346 347# Dump out the scripting required to run one test batch. 348function dump(first, pastlast, batchnum) 349{ 350 print "echo ----Start batch " batchnum ": `date` | tee -a " rd "log"; 351 print "needqemurun=" 352 jn=1 353 for (j = first; j < pastlast; j++) { 354 builddir=KVM "/b" j - first + 1 355 cpusr[jn] = cpus[j]; 356 if (cfrep[cf[j]] == "") { 357 cfr[jn] = cf[j]; 358 cfrep[cf[j]] = 1; 359 } else { 360 cfrep[cf[j]]++; 361 cfr[jn] = cf[j] "." cfrep[cf[j]]; 362 } 363 if (cpusr[jn] > ncpus && ncpus != 0) 364 ovf = "-ovf"; 365 else 366 ovf = ""; 367 print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build. `date` | tee -a " rd "log"; 368 print "rm -f " builddir ".*"; 369 print "touch " builddir ".wait"; 370 print "mkdir " rd cfr[jn] " || :"; 371 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 &" 372 print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date` | tee -a " rd "log"; 373 print "while test -f " builddir ".wait" 374 print "do" 375 print "\tsleep 1" 376 print "done" 377 print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete. `date` | tee -a " rd "log"; 378 jn++; 379 } 380 for (j = 1; j < jn; j++) { 381 builddir=KVM "/b" j 382 print "rm -f " builddir ".ready" 383 print "if test -f \"" rd cfr[j] "/builtkernel\"" 384 print "then" 385 print "\techo ----", cfr[j], cpusr[j] ovf ": Kernel present. `date` | tee -a " rd "log"; 386 print "\tneedqemurun=1" 387 print "fi" 388 } 389 njitter = 0; 390 split(jitter, ja); 391 if (ja[1] == -1 && ncpus == 0) 392 njitter = 1; 393 else if (ja[1] == -1) 394 njitter = ncpus; 395 else 396 njitter = ja[1]; 397 if (TORTURE_BUILDONLY && njitter != 0) { 398 njitter = 0; 399 print "echo Build-only run, so suppressing jitter | tee -a " rd "log" 400 } 401 if (TORTURE_BUILDONLY) { 402 print "needqemurun=" 403 } 404 print "if test -n \"$needqemurun\"" 405 print "then" 406 print "\techo ---- Starting kernels. `date` | tee -a " rd "log"; 407 for (j = 0; j < njitter; j++) 408 print "\tjitter.sh " j " " dur " " ja[2] " " ja[3] "&" 409 print "\twait" 410 print "\techo ---- All kernel runs complete. `date` | tee -a " rd "log"; 411 print "else" 412 print "\twait" 413 print "\techo ---- No kernel runs. `date` | tee -a " rd "log"; 414 print "fi" 415 for (j = 1; j < jn; j++) { 416 builddir=KVM "/b" j 417 print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results: | tee -a " rd "log"; 418 print "cat " rd cfr[j] "/kvm-test-1-run.sh.out | tee -a " rd "log"; 419 } 420} 421 422END { 423 njobs = i; 424 nc = ncpus; 425 first = 0; 426 batchnum = 1; 427 428 # Each pass through the following loop considers one test. 429 for (i = 0; i < njobs; i++) { 430 if (ncpus == 0) { 431 # Sequential test specified, each test its own batch. 432 dump(i, i + 1, batchnum); 433 first = i; 434 batchnum++; 435 } else if (nc < cpus[i] && i != 0) { 436 # Out of CPUs, dump out a batch. 437 dump(first, i, batchnum); 438 first = i; 439 nc = ncpus; 440 batchnum++; 441 } 442 # Account for the CPUs needed by the current test. 443 nc -= cpus[i]; 444 } 445 # Dump the last batch. 446 if (ncpus != 0) 447 dump(first, i, batchnum); 448}' >> $T/script 449 450cat << ___EOF___ >> $T/script 451echo 452echo 453echo " --- `date` Test summary:" 454echo Results directory: $resdir/$ds 455kvm-recheck.sh $resdir/$ds 456___EOF___ 457 458if test "$dryrun" = script 459then 460 cat $T/script 461 exit 0 462elif test "$dryrun" = sched 463then 464 # Extract the test run schedule from the script. 465 egrep 'Start batch|Starting build\.' $T/script | 466 grep -v ">>" | 467 sed -e 's/:.*$//' -e 's/^echo //' 468 exit 0 469else 470 # Not a dryrun, so run the script. 471 sh $T/script 472fi 473 474# 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 475# Function-graph tracing: ftrace=function_graph ftrace_graph_filter=sched_setaffinity,migration_cpu_stop 476# Also --kconfig "CONFIG_FUNCTION_TRACER=y CONFIG_FUNCTION_GRAPH_TRACER=y" 477