stat.sh 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. #!/bin/bash
  2. # perf stat tests
  3. # SPDX-License-Identifier: GPL-2.0
  4. set -e
  5. err=0
  6. stat_output=$(mktemp /tmp/perf-stat-test-output.XXXXX)
  7. cleanup() {
  8. rm -f "${stat_output}"
  9. trap - EXIT TERM INT
  10. }
  11. trap_cleanup() {
  12. echo "Unexpected signal in ${FUNCNAME[1]}"
  13. cleanup
  14. exit 1
  15. }
  16. trap trap_cleanup EXIT TERM INT
  17. test_default_stat() {
  18. echo "Basic stat command test"
  19. if ! perf stat true 2>&1 | grep -E -q "Performance counter stats for 'true':"
  20. then
  21. echo "Basic stat command test [Failed]"
  22. err=1
  23. return
  24. fi
  25. echo "Basic stat command test [Success]"
  26. }
  27. test_null_stat() {
  28. echo "Null stat command test"
  29. if ! perf stat --null true 2>&1 | grep -E -q "Performance counter stats for 'true':"
  30. then
  31. echo "Null stat command test [Failed]"
  32. err=1
  33. return
  34. fi
  35. echo "Null stat command test [Success]"
  36. }
  37. find_offline_cpu() {
  38. for i in $(seq 1 4096)
  39. do
  40. if [[ ! -f /sys/devices/system/cpu/cpu$i/online || \
  41. $(cat /sys/devices/system/cpu/cpu$i/online) == "0" ]]
  42. then
  43. echo $i
  44. return
  45. fi
  46. done
  47. echo "Failed to find offline CPU"
  48. exit 1
  49. }
  50. test_offline_cpu_stat() {
  51. cpu=$(find_offline_cpu)
  52. echo "Offline CPU stat command test (cpu $cpu)"
  53. if ! perf stat "-C$cpu" -e cycles true 2>&1 | grep -E -q "No supported events found."
  54. then
  55. echo "Offline CPU stat command test [Failed]"
  56. err=1
  57. return
  58. fi
  59. echo "Offline CPU stat command test [Success]"
  60. }
  61. test_stat_record_report() {
  62. echo "stat record and report test"
  63. if ! perf stat record -e task-clock -o - true | perf stat report -i - 2>&1 | \
  64. grep -E -q "Performance counter stats for 'pipe':"
  65. then
  66. echo "stat record and report test [Failed]"
  67. err=1
  68. return
  69. fi
  70. echo "stat record and report test [Success]"
  71. }
  72. test_stat_record_script() {
  73. echo "stat record and script test"
  74. if ! perf stat record -e task-clock -o - true | perf script -i - 2>&1 | \
  75. grep -E -q "CPU[[:space:]]+THREAD[[:space:]]+VAL[[:space:]]+ENA[[:space:]]+RUN[[:space:]]+TIME[[:space:]]+EVENT"
  76. then
  77. echo "stat record and script test [Failed]"
  78. err=1
  79. return
  80. fi
  81. echo "stat record and script test [Success]"
  82. }
  83. test_stat_repeat_weak_groups() {
  84. echo "stat repeat weak groups test"
  85. if ! perf stat -e '{cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles}' \
  86. true 2>&1 | grep -q 'seconds time elapsed'
  87. then
  88. echo "stat repeat weak groups test [Skipped event parsing failed]"
  89. return
  90. fi
  91. if ! perf stat -r2 -e '{cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles}:W' \
  92. true > /dev/null 2>&1
  93. then
  94. echo "stat repeat weak groups test [Failed]"
  95. err=1
  96. return
  97. fi
  98. echo "stat repeat weak groups test [Success]"
  99. }
  100. test_topdown_groups() {
  101. # Topdown events must be grouped with the slots event first. Test that
  102. # parse-events reorders this.
  103. echo "Topdown event group test"
  104. if ! perf stat -e '{slots,topdown-retiring}' true > /dev/null 2>&1
  105. then
  106. echo "Topdown event group test [Skipped event parsing failed]"
  107. return
  108. fi
  109. td_err=0
  110. do_topdown_group_test() {
  111. events=$1
  112. failure=$2
  113. if perf stat -e "$events" true 2>&1 | grep -E -q "<not supported>"
  114. then
  115. echo "Topdown event group test [Failed $failure for '$events']"
  116. td_err=1
  117. return
  118. fi
  119. }
  120. do_topdown_group_test "{slots,topdown-retiring}" "events not supported"
  121. do_topdown_group_test "{instructions,r400,r8000}" "raw format slots not reordered first"
  122. filler_events=("instructions" "cycles"
  123. "context-switches" "faults")
  124. for ((i = 0; i < ${#filler_events[@]}; i+=2))
  125. do
  126. filler1=${filler_events[i]}
  127. filler2=${filler_events[i+1]}
  128. do_topdown_group_test "$filler1,topdown-retiring,slots" \
  129. "slots not reordered first in no-group case"
  130. do_topdown_group_test "slots,$filler1,topdown-retiring" \
  131. "topdown metrics event not reordered in no-group case"
  132. do_topdown_group_test "{$filler1,topdown-retiring,slots}" \
  133. "slots not reordered first in single group case"
  134. do_topdown_group_test "{$filler1,slots},topdown-retiring" \
  135. "topdown metrics event not move into slots group"
  136. do_topdown_group_test "topdown-retiring,{$filler1,slots}" \
  137. "topdown metrics event not move into slots group last"
  138. do_topdown_group_test "{$filler1,slots},{topdown-retiring}" \
  139. "topdown metrics group not merge into slots group"
  140. do_topdown_group_test "{topdown-retiring},{$filler1,slots}" \
  141. "topdown metrics group not merge into slots group last"
  142. do_topdown_group_test "{$filler1,slots},$filler2,topdown-retiring" \
  143. "non-adjacent topdown metrics group not move into slots group"
  144. do_topdown_group_test "$filler2,topdown-retiring,{$filler1,slots}" \
  145. "non-adjacent topdown metrics group not move into slots group last"
  146. do_topdown_group_test "{$filler1,slots},{$filler2,topdown-retiring}" \
  147. "metrics group not merge into slots group"
  148. do_topdown_group_test "{$filler1,topdown-retiring},{$filler2,slots}" \
  149. "metrics group not merge into slots group last"
  150. done
  151. if test "$td_err" -eq 0
  152. then
  153. echo "Topdown event group test [Success]"
  154. else
  155. err="$td_err"
  156. fi
  157. }
  158. test_topdown_weak_groups() {
  159. # Weak groups break if the perf_event_open of multiple grouped events
  160. # fails. Breaking a topdown group causes the events to fail. Test a very large
  161. # grouping to see that the topdown events aren't broken out.
  162. echo "Topdown weak groups test"
  163. ok_grouping="{slots,topdown-bad-spec,topdown-be-bound,topdown-fe-bound,topdown-retiring},branch-instructions,branch-misses,bus-cycles,cache-misses,cache-references,cpu-cycles,instructions,mem-loads,mem-stores,ref-cycles,cache-misses,cache-references"
  164. if ! perf stat --no-merge -e "$ok_grouping" true > /dev/null 2>&1
  165. then
  166. echo "Topdown weak groups test [Skipped event parsing failed]"
  167. return
  168. fi
  169. group_needs_break="{slots,topdown-bad-spec,topdown-be-bound,topdown-fe-bound,topdown-retiring,branch-instructions,branch-misses,bus-cycles,cache-misses,cache-references,cpu-cycles,instructions,mem-loads,mem-stores,ref-cycles,cache-misses,cache-references}:W"
  170. if perf stat --no-merge -e "$group_needs_break" true 2>&1 | grep -E -q "<not supported>"
  171. then
  172. echo "Topdown weak groups test [Failed events not supported]"
  173. err=1
  174. return
  175. fi
  176. echo "Topdown weak groups test [Success]"
  177. }
  178. test_cputype() {
  179. # Test --cputype argument.
  180. echo "cputype test"
  181. # Bogus PMU should fail.
  182. if perf stat --cputype="123" -e instructions true > /dev/null 2>&1
  183. then
  184. echo "cputype test [Bogus PMU didn't fail]"
  185. err=1
  186. return
  187. fi
  188. # Find a known PMU for cputype.
  189. pmu=""
  190. devs="/sys/bus/event_source/devices"
  191. for i in $devs/cpu $devs/cpu_atom $devs/armv8_pmuv3_0 $devs/armv8_cortex_*
  192. do
  193. i_base=$(basename "$i")
  194. if test -d "$i"
  195. then
  196. pmu="$i_base"
  197. break
  198. fi
  199. if perf stat -e "$i_base/instructions/" true > /dev/null 2>&1
  200. then
  201. pmu="$i_base"
  202. break
  203. fi
  204. done
  205. if test "x$pmu" = "x"
  206. then
  207. echo "cputype test [Skipped known PMU not found]"
  208. return
  209. fi
  210. # Test running with cputype produces output.
  211. if ! perf stat --cputype="$pmu" -e instructions true 2>&1 | grep -E -q "instructions"
  212. then
  213. echo "cputype test [Failed count missed with given filter]"
  214. err=1
  215. return
  216. fi
  217. echo "cputype test [Success]"
  218. }
  219. test_hybrid() {
  220. # Test the default stat command on hybrid devices opens one cycles event for
  221. # each CPU type.
  222. echo "hybrid test"
  223. # Count the number of core PMUs, assume minimum of 1
  224. pmus=$(ls /sys/bus/event_source/devices/*/cpus 2>/dev/null | wc -l)
  225. if [ "$pmus" -lt 1 ]
  226. then
  227. pmus=1
  228. fi
  229. # Run default Perf stat
  230. cycles_events=$(perf stat -a -- sleep 0.1 2>&1 | grep -E "/cpu-cycles/[uH]*| cpu-cycles[:uH]* " | wc -l)
  231. # The expectation is that default output will have a cycles events on each
  232. # hybrid PMU. In situations with no cycles PMU events, like virtualized, this
  233. # can fall back to task-clock and so the end count may be 0. Fail if neither
  234. # condition holds.
  235. if [ "$pmus" -ne "$cycles_events" ] && [ "0" -ne "$cycles_events" ]
  236. then
  237. echo "hybrid test [Found $pmus PMUs but $cycles_events cycles events. Failed]"
  238. err=1
  239. return
  240. fi
  241. echo "hybrid test [Success]"
  242. }
  243. test_stat_cpu() {
  244. echo "stat -C <cpu> test"
  245. # Test the full online CPU list (ranges and lists)
  246. online_cpus=$(cat /sys/devices/system/cpu/online)
  247. if ! perf stat -C "$online_cpus" -a true > "${stat_output}" 2>&1
  248. then
  249. echo "stat -C <cpu> test [Failed - command failed for cpus $online_cpus]"
  250. cat "${stat_output}"
  251. err=1
  252. return
  253. fi
  254. if ! grep -E -q "Performance counter stats for" "${stat_output}"
  255. then
  256. echo "stat -C <cpu> test [Failed - missing output for cpus $online_cpus]"
  257. cat "${stat_output}"
  258. err=1
  259. return
  260. fi
  261. # Test each individual online CPU
  262. for cpu_dir in /sys/devices/system/cpu/cpu[0-9]*; do
  263. cpu=${cpu_dir##*/cpu}
  264. # Check if online
  265. if [ -f "$cpu_dir/online" ] && [ "$(cat "$cpu_dir/online")" -eq 0 ]
  266. then
  267. continue
  268. fi
  269. if ! perf stat -C "$cpu" -a true > "${stat_output}" 2>&1
  270. then
  271. echo "stat -C <cpu> test [Failed - command failed for cpu $cpu]"
  272. cat "${stat_output}"
  273. err=1
  274. return
  275. fi
  276. if ! grep -E -q "Performance counter stats for" "${stat_output}"
  277. then
  278. echo "stat -C <cpu> test [Failed - missing output for cpu $cpu]"
  279. cat "${stat_output}"
  280. err=1
  281. return
  282. fi
  283. done
  284. # Test synthetic list and range if cpu0 and cpu1 are online
  285. c0_online=0
  286. c1_online=0
  287. if [ -d "/sys/devices/system/cpu/cpu0" ]
  288. then
  289. if [ ! -f "/sys/devices/system/cpu/cpu0/online" ] || [ "$(cat /sys/devices/system/cpu/cpu0/online)" -eq 1 ]
  290. then
  291. c0_online=1
  292. fi
  293. fi
  294. if [ -d "/sys/devices/system/cpu/cpu1" ]
  295. then
  296. if [ ! -f "/sys/devices/system/cpu/cpu1/online" ] || [ "$(cat /sys/devices/system/cpu/cpu1/online)" -eq 1 ]
  297. then
  298. c1_online=1
  299. fi
  300. fi
  301. if [ $c0_online -eq 1 ] && [ $c1_online -eq 1 ]
  302. then
  303. # Test list "0,1"
  304. if ! perf stat -C "0,1" -a true > "${stat_output}" 2>&1
  305. then
  306. echo "stat -C <cpu> test [Failed - command failed for cpus 0,1]"
  307. cat "${stat_output}"
  308. err=1
  309. return
  310. fi
  311. if ! grep -E -q "Performance counter stats for" "${stat_output}"
  312. then
  313. echo "stat -C <cpu> test [Failed - missing output for cpus 0,1]"
  314. cat "${stat_output}"
  315. err=1
  316. return
  317. fi
  318. # Test range "0-1"
  319. if ! perf stat -C "0-1" -a true > "${stat_output}" 2>&1
  320. then
  321. echo "stat -C <cpu> test [Failed - command failed for cpus 0-1]"
  322. cat "${stat_output}"
  323. err=1
  324. return
  325. fi
  326. if ! grep -E -q "Performance counter stats for" "${stat_output}"
  327. then
  328. echo "stat -C <cpu> test [Failed - missing output for cpus 0-1]"
  329. cat "${stat_output}"
  330. err=1
  331. return
  332. fi
  333. fi
  334. echo "stat -C <cpu> test [Success]"
  335. }
  336. test_stat_no_aggr() {
  337. echo "stat -A test"
  338. if ! perf stat -A -a true > "${stat_output}" 2>&1
  339. then
  340. echo "stat -A test [Failed - command failed]"
  341. cat "${stat_output}"
  342. err=1
  343. return
  344. fi
  345. if ! grep -E -q "CPU" "${stat_output}"
  346. then
  347. echo "stat -A test [Failed - missing CPU column]"
  348. cat "${stat_output}"
  349. err=1
  350. return
  351. fi
  352. echo "stat -A test [Success]"
  353. }
  354. test_stat_detailed() {
  355. echo "stat -d test"
  356. if ! perf stat -d true > "${stat_output}" 2>&1
  357. then
  358. echo "stat -d test [Failed - command failed]"
  359. cat "${stat_output}"
  360. err=1
  361. return
  362. fi
  363. if ! grep -E -q "Performance counter stats" "${stat_output}"
  364. then
  365. echo "stat -d test [Failed - missing output]"
  366. cat "${stat_output}"
  367. err=1
  368. return
  369. fi
  370. if ! perf stat -dd true > "${stat_output}" 2>&1
  371. then
  372. echo "stat -dd test [Failed - command failed]"
  373. cat "${stat_output}"
  374. err=1
  375. return
  376. fi
  377. if ! grep -E -q "Performance counter stats" "${stat_output}"
  378. then
  379. echo "stat -dd test [Failed - missing output]"
  380. cat "${stat_output}"
  381. err=1
  382. return
  383. fi
  384. if ! perf stat -ddd true > "${stat_output}" 2>&1
  385. then
  386. echo "stat -ddd test [Failed - command failed]"
  387. cat "${stat_output}"
  388. err=1
  389. return
  390. fi
  391. if ! grep -E -q "Performance counter stats" "${stat_output}"
  392. then
  393. echo "stat -ddd test [Failed - missing output]"
  394. cat "${stat_output}"
  395. err=1
  396. return
  397. fi
  398. echo "stat -d test [Success]"
  399. }
  400. test_stat_repeat() {
  401. echo "stat -r test"
  402. if ! perf stat -r 2 true > "${stat_output}" 2>&1
  403. then
  404. echo "stat -r test [Failed - command failed]"
  405. cat "${stat_output}"
  406. err=1
  407. return
  408. fi
  409. if ! grep -E -q "\([[:space:]]*\+-.*%[[:space:]]*\)" "${stat_output}"
  410. then
  411. echo "stat -r test [Failed - missing variance]"
  412. cat "${stat_output}"
  413. err=1
  414. return
  415. fi
  416. echo "stat -r test [Success]"
  417. }
  418. test_stat_pid() {
  419. echo "stat -p test"
  420. sleep 1 &
  421. pid=$!
  422. if ! perf stat -p $pid > "${stat_output}" 2>&1
  423. then
  424. echo "stat -p test [Failed - command failed]"
  425. cat "${stat_output}"
  426. err=1
  427. kill $pid 2>/dev/null || true
  428. wait $pid 2>/dev/null || true
  429. return
  430. fi
  431. if ! grep -E -q "Performance counter stats" "${stat_output}"
  432. then
  433. echo "stat -p test [Failed - missing output]"
  434. cat "${stat_output}"
  435. err=1
  436. else
  437. echo "stat -p test [Success]"
  438. fi
  439. kill $pid 2>/dev/null || true
  440. wait $pid 2>/dev/null || true
  441. }
  442. test_default_stat
  443. test_null_stat
  444. test_offline_cpu_stat
  445. test_stat_record_report
  446. test_stat_record_script
  447. test_stat_repeat_weak_groups
  448. test_topdown_groups
  449. test_topdown_weak_groups
  450. test_cputype
  451. test_hybrid
  452. test_stat_cpu
  453. test_stat_no_aggr
  454. test_stat_detailed
  455. test_stat_repeat
  456. test_stat_pid
  457. cleanup
  458. exit $err