xref: /linux/tools/perf/tests/shell/stat.sh (revision 7b8e9264f55a9c320f398e337d215e68cca50131)
1#!/bin/bash
2# perf stat tests
3# SPDX-License-Identifier: GPL-2.0
4
5set -e
6
7err=0
8test_default_stat() {
9  echo "Basic stat command test"
10  if ! perf stat true 2>&1 | grep -E -q "Performance counter stats for 'true':"
11  then
12    echo "Basic stat command test [Failed]"
13    err=1
14    return
15  fi
16  echo "Basic stat command test [Success]"
17}
18
19test_null_stat() {
20  echo "Null stat command test"
21  if ! perf stat --null true 2>&1 | grep -E -q "Performance counter stats for 'true':"
22  then
23    echo "Null stat command test [Failed]"
24    err=1
25    return
26  fi
27  echo "Null stat command test [Success]"
28}
29
30find_offline_cpu() {
31  for i in $(seq 1 4096)
32  do
33    if [[ ! -f /sys/devices/system/cpu/cpu$i/online || \
34          $(cat /sys/devices/system/cpu/cpu$i/online) == "0" ]]
35    then
36      echo $i
37      return
38    fi
39  done
40  echo "Failed to find offline CPU"
41  exit 1
42}
43
44test_offline_cpu_stat() {
45  cpu=$(find_offline_cpu)
46  echo "Offline CPU stat command test (cpu $cpu)"
47  if ! perf stat "-C$cpu" -e cycles true 2>&1 | grep -E -q "No supported events found."
48  then
49    echo "Offline CPU stat command test [Failed]"
50    err=1
51    return
52  fi
53  echo "Offline CPU stat command test [Success]"
54}
55
56test_stat_record_report() {
57  echo "stat record and report test"
58  if ! perf stat record -e task-clock -o - true | perf stat report -i - 2>&1 | \
59    grep -E -q "Performance counter stats for 'pipe':"
60  then
61    echo "stat record and report test [Failed]"
62    err=1
63    return
64  fi
65  echo "stat record and report test [Success]"
66}
67
68test_stat_record_script() {
69  echo "stat record and script test"
70  if ! perf stat record -e task-clock -o - true | perf script -i - 2>&1 | \
71    grep -E -q "CPU[[:space:]]+THREAD[[:space:]]+VAL[[:space:]]+ENA[[:space:]]+RUN[[:space:]]+TIME[[:space:]]+EVENT"
72  then
73    echo "stat record and script test [Failed]"
74    err=1
75    return
76  fi
77  echo "stat record and script test [Success]"
78}
79
80test_stat_repeat_weak_groups() {
81  echo "stat repeat weak groups test"
82  if ! perf stat -e '{cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles}' \
83     true 2>&1 | grep -q 'seconds time elapsed'
84  then
85    echo "stat repeat weak groups test [Skipped event parsing failed]"
86    return
87  fi
88  if ! perf stat -r2 -e '{cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles,cycles}:W' \
89    true > /dev/null 2>&1
90  then
91    echo "stat repeat weak groups test [Failed]"
92    err=1
93    return
94  fi
95  echo "stat repeat weak groups test [Success]"
96}
97
98test_topdown_groups() {
99  # Topdown events must be grouped with the slots event first. Test that
100  # parse-events reorders this.
101  echo "Topdown event group test"
102  if ! perf stat -e '{slots,topdown-retiring}' true > /dev/null 2>&1
103  then
104    echo "Topdown event group test [Skipped event parsing failed]"
105    return
106  fi
107  td_err=0
108  do_topdown_group_test() {
109    events=$1
110    failure=$2
111    if perf stat -e "$events" true 2>&1 | grep -E -q "<not supported>"
112    then
113      echo "Topdown event group test [Failed $failure for '$events']"
114      td_err=1
115      return
116    fi
117  }
118  do_topdown_group_test "{slots,topdown-retiring}" "events not supported"
119  do_topdown_group_test "{instructions,r400,r8000}" "raw format slots not reordered first"
120  filler_events=("instructions" "cycles"
121                 "context-switches" "faults")
122  for ((i = 0; i < ${#filler_events[@]}; i+=2))
123  do
124    filler1=${filler_events[i]}
125    filler2=${filler_events[i+1]}
126    do_topdown_group_test "$filler1,topdown-retiring,slots" \
127      "slots not reordered first in no-group case"
128    do_topdown_group_test "slots,$filler1,topdown-retiring" \
129      "topdown metrics event not reordered in no-group case"
130    do_topdown_group_test "{$filler1,topdown-retiring,slots}" \
131      "slots not reordered first in single group case"
132    do_topdown_group_test "{$filler1,slots},topdown-retiring" \
133      "topdown metrics event not move into slots group"
134    do_topdown_group_test "topdown-retiring,{$filler1,slots}" \
135      "topdown metrics event not move into slots group last"
136    do_topdown_group_test "{$filler1,slots},{topdown-retiring}" \
137      "topdown metrics group not merge into slots group"
138    do_topdown_group_test "{topdown-retiring},{$filler1,slots}" \
139      "topdown metrics group not merge into slots group last"
140    do_topdown_group_test "{$filler1,slots},$filler2,topdown-retiring" \
141      "non-adjacent topdown metrics group not move into slots group"
142    do_topdown_group_test "$filler2,topdown-retiring,{$filler1,slots}" \
143      "non-adjacent topdown metrics group not move into slots group last"
144    do_topdown_group_test "{$filler1,slots},{$filler2,topdown-retiring}" \
145      "metrics group not merge into slots group"
146    do_topdown_group_test "{$filler1,topdown-retiring},{$filler2,slots}" \
147      "metrics group not merge into slots group last"
148  done
149  if test "$td_err" -eq 0
150  then
151    echo "Topdown event group test [Success]"
152  else
153    err="$td_err"
154  fi
155}
156
157test_topdown_weak_groups() {
158  # Weak groups break if the perf_event_open of multiple grouped events
159  # fails. Breaking a topdown group causes the events to fail. Test a very large
160  # grouping to see that the topdown events aren't broken out.
161  echo "Topdown weak groups test"
162  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"
163  if ! perf stat --no-merge -e "$ok_grouping" true > /dev/null 2>&1
164  then
165    echo "Topdown weak groups test [Skipped event parsing failed]"
166    return
167  fi
168  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"
169  if perf stat --no-merge -e "$group_needs_break" true 2>&1 | grep -E -q "<not supported>"
170  then
171    echo "Topdown weak groups test [Failed events not supported]"
172    err=1
173    return
174  fi
175  echo "Topdown weak groups test [Success]"
176}
177
178test_cputype() {
179  # Test --cputype argument.
180  echo "cputype test"
181
182  # Bogus PMU should fail.
183  if perf stat --cputype="123" -e instructions true > /dev/null 2>&1
184  then
185    echo "cputype test [Bogus PMU didn't fail]"
186    err=1
187    return
188  fi
189
190  # Find a known PMU for cputype.
191  pmu=""
192  devs="/sys/bus/event_source/devices"
193  for i in $devs/cpu $devs/cpu_atom $devs/armv8_pmuv3_0 $devs/armv8_cortex_*
194  do
195    i_base=$(basename "$i")
196    if test -d "$i"
197    then
198      pmu="$i_base"
199      break
200    fi
201    if perf stat -e "$i_base/instructions/" true > /dev/null 2>&1
202    then
203      pmu="$i_base"
204      break
205    fi
206  done
207  if test "x$pmu" = "x"
208  then
209    echo "cputype test [Skipped known PMU not found]"
210    return
211  fi
212
213  # Test running with cputype produces output.
214  if ! perf stat --cputype="$pmu" -e instructions true 2>&1 | grep -E -q "instructions"
215  then
216    echo "cputype test [Failed count missed with given filter]"
217    err=1
218    return
219  fi
220  echo "cputype test [Success]"
221}
222
223test_hybrid() {
224  # Test the default stat command on hybrid devices opens one cycles event for
225  # each CPU type.
226  echo "hybrid test"
227
228  # Count the number of core PMUs, assume minimum of 1
229  pmus=$(ls /sys/bus/event_source/devices/*/cpus 2>/dev/null | wc -l)
230  if [ "$pmus" -lt 1 ]
231  then
232    pmus=1
233  fi
234
235  # Run default Perf stat
236  cycles_events=$(perf stat -a -- sleep 0.1 2>&1 | grep -E "/cpu-cycles/[uH]*|  cpu-cycles[:uH]*  " -c)
237
238  # The expectation is that default output will have a cycles events on each
239  # hybrid PMU. In situations with no cycles PMU events, like virtualized, this
240  # can fall back to task-clock and so the end count may be 0. Fail if neither
241  # condition holds.
242  if [ "$pmus" -ne "$cycles_events" ] && [ "0" -ne "$cycles_events" ]
243  then
244    echo "hybrid test [Found $pmus PMUs but $cycles_events cycles events. Failed]"
245    err=1
246    return
247  fi
248  echo "hybrid test [Success]"
249}
250
251test_default_stat
252test_null_stat
253test_offline_cpu_stat
254test_stat_record_report
255test_stat_record_script
256test_stat_repeat_weak_groups
257test_topdown_groups
258test_topdown_weak_groups
259test_cputype
260test_hybrid
261exit $err
262