kvm-series.sh 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. #!/bin/bash
  2. # SPDX-License-Identifier: GPL-2.0+
  3. #
  4. # Usage: kvm-series.sh config-list commit-id-list [ kvm.sh parameters ]
  5. #
  6. # Tests the specified list of unadorned configs ("TREE01 SRCU-P" but not
  7. # "CFLIST" or "3*TRACE01") and an indication of a set of commits to test,
  8. # then runs each commit through the specified list of commits using kvm.sh.
  9. # The runs are grouped into a -series/config/commit directory tree.
  10. # Each run defaults to a duration of one minute.
  11. #
  12. # Run in top-level Linux source directory. Please note that this is in
  13. # no way a replacement for "git bisect"!!!
  14. #
  15. # This script is intended to replace kvm-check-branches.sh by providing
  16. # ease of use and faster execution.
  17. T="`mktemp -d ${TMPDIR-/tmp}/kvm-series.sh.XXXXXX`"; export T
  18. trap 'rm -rf $T' 0
  19. scriptname=$0
  20. args="$*"
  21. config_list="${1}"
  22. if test -z "${config_list}"
  23. then
  24. echo "$0: Need a quoted list of --config arguments for first argument."
  25. exit 1
  26. fi
  27. if test -z "${config_list}" || echo "${config_list}" | grep -q '\*'
  28. then
  29. echo "$0: Repetition ('*') not allowed in config list."
  30. exit 1
  31. fi
  32. config_list_len="`echo ${config_list} | wc -w | awk '{ print $1; }'`"
  33. commit_list="${2}"
  34. if test -z "${commit_list}"
  35. then
  36. echo "$0: Need a list of commits (e.g., HEAD^^^..) for second argument."
  37. exit 2
  38. fi
  39. git log --pretty=format:"%h" "${commit_list}" > $T/commits
  40. ret=$?
  41. if test "${ret}" -ne 0
  42. then
  43. echo "$0: Invalid commit list ('${commit_list}')."
  44. exit 2
  45. fi
  46. sha1_list=`cat $T/commits`
  47. sha1_list_len="`echo ${sha1_list} | wc -w | awk '{ print $1; }'`"
  48. shift
  49. shift
  50. RCUTORTURE="`pwd`/tools/testing/selftests/rcutorture"; export RCUTORTURE
  51. PATH=${RCUTORTURE}/bin:$PATH; export PATH
  52. RES="${RCUTORTURE}/res"; export RES
  53. . functions.sh
  54. ret=0
  55. nbuildfail=0
  56. nrunfail=0
  57. nsuccess=0
  58. ncpus=0
  59. buildfaillist=
  60. runfaillist=
  61. successlist=
  62. cursha1="`git rev-parse --abbrev-ref HEAD`"
  63. ds="`date +%Y.%m.%d-%H.%M.%S`-series"
  64. DS="${RES}/${ds}"; export DS
  65. startdate="`date`"
  66. starttime="`get_starttime`"
  67. echo " --- " $scriptname $args | tee -a $T/log
  68. echo " --- Results directory: " $ds | tee -a $T/log
  69. # Do all builds. Iterate through commits within a given scenario
  70. # because builds normally go faster from one commit to the next within a
  71. # given scenario. In contrast, switching scenarios on each rebuild will
  72. # often force a full rebuild due to Kconfig differences, for example,
  73. # turning preemption on and off. Defer actual runs in order to run
  74. # lots of them concurrently on large systems.
  75. touch $T/torunlist
  76. n2build="$((config_list_len*sha1_list_len))"
  77. nbuilt=0
  78. for config in ${config_list}
  79. do
  80. sha_n=0
  81. for sha in ${sha1_list}
  82. do
  83. sha1=${sha_n}.${sha} # Enable "sort -k1nr" to list commits in order.
  84. echo
  85. echo Starting ${config}/${sha1} "($((nbuilt+1)) of ${n2build})" at `date` | tee -a $T/log
  86. git checkout --detach "${sha}"
  87. tools/testing/selftests/rcutorture/bin/kvm.sh --configs "$config" --datestamp "$ds/${config}/${sha1}" --duration 1 --build-only --trust-make "$@"
  88. curret=$?
  89. if test "${curret}" -ne 0
  90. then
  91. nbuildfail=$((nbuildfail+1))
  92. buildfaillist="$buildfaillist ${config}/${sha1}(${curret})"
  93. else
  94. batchncpus="`grep -v "^# cpus=" "${DS}/${config}/${sha1}/batches" | awk '{ sum += $3 } END { print sum }'`"
  95. echo run_one_qemu ${sha_n} ${config}/${sha1} ${batchncpus} >> $T/torunlist
  96. if test "${ncpus}" -eq 0
  97. then
  98. ncpus="`grep "^# cpus=" "${DS}/${config}/${sha1}/batches" | sed -e 's/^# cpus=//'`"
  99. case "${ncpus}" in
  100. ^[0-9]*$)
  101. ;;
  102. *)
  103. ncpus=0
  104. ;;
  105. esac
  106. fi
  107. fi
  108. if test "${ret}" -eq 0
  109. then
  110. ret=${curret}
  111. fi
  112. sha_n=$((sha_n+1))
  113. nbuilt=$((nbuilt+1))
  114. done
  115. done
  116. # If the user did not specify the number of CPUs, use them all.
  117. if test "${ncpus}" -eq 0
  118. then
  119. ncpus="`identify_qemu_vcpus`"
  120. fi
  121. cpusused=0
  122. touch $T/successlistfile
  123. touch $T/faillistfile
  124. n2run="`wc -l $T/torunlist | awk '{ print $1; }'`"
  125. nrun=0
  126. # do_run_one_qemu ds resultsdir qemu_curout
  127. #
  128. # Start the specified qemu run and record its success or failure.
  129. do_run_one_qemu () {
  130. local ret
  131. local ds="$1"
  132. local resultsdir="$2"
  133. local qemu_curout="$3"
  134. tools/testing/selftests/rcutorture/bin/kvm-again.sh "${DS}/${resultsdir}" --link inplace-force > ${qemu_curout} 2>&1
  135. ret=$?
  136. if test "${ret}" -eq 0
  137. then
  138. echo ${resultsdir} >> $T/successlistfile
  139. # Successful run, so remove large files.
  140. rm -f ${DS}/${resultsdir}/{vmlinux,bzImage,System.map,Module.symvers}
  141. else
  142. echo "${resultsdir}(${ret})" >> $T/faillistfile
  143. fi
  144. }
  145. # cleanup_qemu_batch batchncpus
  146. #
  147. # Update success and failure lists, files, and counts at the end of
  148. # a batch.
  149. cleanup_qemu_batch () {
  150. local batchncpus="$1"
  151. echo Waiting, cpusused=${cpusused}, ncpus=${ncpus} `date` | tee -a $T/log
  152. wait
  153. cpusused="${batchncpus}"
  154. nsuccessbatch="`wc -l $T/successlistfile | awk '{ print $1 }'`"
  155. nsuccess=$((nsuccess+nsuccessbatch))
  156. successlist="$successlist `cat $T/successlistfile`"
  157. rm $T/successlistfile
  158. touch $T/successlistfile
  159. nfailbatch="`wc -l $T/faillistfile | awk '{ print $1 }'`"
  160. nrunfail=$((nrunfail+nfailbatch))
  161. runfaillist="$runfaillist `cat $T/faillistfile`"
  162. rm $T/faillistfile
  163. touch $T/faillistfile
  164. }
  165. # run_one_qemu sha_n config/sha1 batchncpus
  166. #
  167. # Launch into the background the sha_n-th qemu job whose results directory
  168. # is config/sha1 and which uses batchncpus CPUs. Once we reach a job that
  169. # would overflow the number of available CPUs, wait for the previous jobs
  170. # to complete and record their results.
  171. run_one_qemu () {
  172. local sha_n="$1"
  173. local config_sha1="$2"
  174. local batchncpus="$3"
  175. local qemu_curout
  176. cpusused=$((cpusused+batchncpus))
  177. if test "${cpusused}" -gt $ncpus
  178. then
  179. cleanup_qemu_batch "${batchncpus}"
  180. fi
  181. echo Starting ${config_sha1} using ${batchncpus} CPUs "($((nrun+1)) of ${n2run})" `date`
  182. qemu_curout="${DS}/${config_sha1}/qemu-series"
  183. do_run_one_qemu "$ds" "${config_sha1}" ${qemu_curout} &
  184. nrun="$((nrun+1))"
  185. }
  186. # Re-ordering the runs will mess up the affinity chosen at build time
  187. # (among other things, over-using CPU 0), so suppress it.
  188. TORTURE_NO_AFFINITY="no-affinity"; export TORTURE_NO_AFFINITY
  189. # Run the kernels (if any) that built correctly.
  190. echo | tee -a $T/log # Put a blank line between build and run messages.
  191. . $T/torunlist
  192. cleanup_qemu_batch "${batchncpus}"
  193. # Get back to initial checkout/SHA-1.
  194. git checkout "${cursha1}"
  195. # Throw away leading and trailing space characters for fmt.
  196. successlist="`echo ${successlist} | sed -e 's/^ *//' -e 's/ *$//'`"
  197. buildfaillist="`echo ${buildfaillist} | sed -e 's/^ *//' -e 's/ *$//'`"
  198. runfaillist="`echo ${runfaillist} | sed -e 's/^ *//' -e 's/ *$//'`"
  199. # Print lists of successes, build failures, and run failures, if any.
  200. if test "${nsuccess}" -gt 0
  201. then
  202. echo | tee -a $T/log
  203. echo ${nsuccess} SUCCESSES: | tee -a $T/log
  204. echo ${successlist} | fmt | tee -a $T/log
  205. fi
  206. if test "${nbuildfail}" -gt 0
  207. then
  208. echo | tee -a $T/log
  209. echo ${nbuildfail} BUILD FAILURES: | tee -a $T/log
  210. echo ${buildfaillist} | fmt | tee -a $T/log
  211. fi
  212. if test "${nrunfail}" -gt 0
  213. then
  214. echo | tee -a $T/log
  215. echo ${nrunfail} RUN FAILURES: | tee -a $T/log
  216. echo ${runfaillist} | fmt | tee -a $T/log
  217. fi
  218. # If there were build or runtime failures, map them to commits.
  219. if test "${nbuildfail}" -gt 0 || test "${nrunfail}" -gt 0
  220. then
  221. echo | tee -a $T/log
  222. echo Build failures across commits: | tee -a $T/log
  223. echo ${buildfaillist} | tr ' ' '\012' | sed -e 's,^[^/]*/,,' -e 's/([0-9]*)//' |
  224. sort | uniq -c | sort -k2n | tee -a $T/log
  225. fi
  226. # Print run summary.
  227. echo | tee -a $T/log
  228. echo Started at $startdate, ended at `date`, duration `get_starttime_duration $starttime`. | tee -a $T/log
  229. echo Summary: Successes: ${nsuccess} " "Build Failures: ${nbuildfail} " "Runtime Failures: ${nrunfail}| tee -a $T/log
  230. cp $T/log ${DS}
  231. exit "${ret}"