xref: /linux/tools/perf/tests/shell/record.sh (revision 7f71507851fc7764b36a3221839607d3a45c2025)
1#!/bin/bash
2# perf record tests (exclusive)
3# SPDX-License-Identifier: GPL-2.0
4
5set -e
6
7shelldir=$(dirname "$0")
8# shellcheck source=lib/waiting.sh
9. "${shelldir}"/lib/waiting.sh
10
11# shellcheck source=lib/perf_has_symbol.sh
12. "${shelldir}"/lib/perf_has_symbol.sh
13
14testsym="test_loop"
15
16skip_test_missing_symbol ${testsym}
17
18err=0
19perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
20script_output=$(mktemp /tmp/__perf_test.perf.data.XXXXX.script)
21testprog="perf test -w thloop"
22cpu_pmu_dir="/sys/bus/event_source/devices/cpu*"
23br_cntr_file="/caps/branch_counter_nr"
24br_cntr_output="branch stack counters"
25br_cntr_script_output="br_cntr: A"
26
27default_fd_limit=$(ulimit -Sn)
28# With option --threads=cpu the number of open file descriptors should be
29# equal to sum of:    nmb_cpus * nmb_events (2+dummy),
30#                     nmb_threads for perf.data.n (equal to nmb_cpus) and
31#                     2*nmb_cpus of pipes = 4*nmb_cpus (each pipe has 2 ends)
32# All together it needs 8*nmb_cpus file descriptors plus some are also used
33# outside of testing, thus raising the limit to 16*nmb_cpus
34min_fd_limit=$(($(getconf _NPROCESSORS_ONLN) * 16))
35
36cleanup() {
37  rm -rf "${perfdata}"
38  rm -rf "${perfdata}".old
39
40  trap - EXIT TERM INT
41}
42
43trap_cleanup() {
44  cleanup
45  exit 1
46}
47trap trap_cleanup EXIT TERM INT
48
49test_per_thread() {
50  echo "Basic --per-thread mode test"
51  if ! perf record -o /dev/null --quiet ${testprog} 2> /dev/null
52  then
53    echo "Per-thread record [Skipped event not supported]"
54    return
55  fi
56  if ! perf record --per-thread -o "${perfdata}" ${testprog} 2> /dev/null
57  then
58    echo "Per-thread record [Failed record]"
59    err=1
60    return
61  fi
62  if ! perf report -i "${perfdata}" -q | grep -q "${testsym}"
63  then
64    echo "Per-thread record [Failed missing output]"
65    err=1
66    return
67  fi
68
69  # run the test program in background (for 30 seconds)
70  ${testprog} 30 &
71  TESTPID=$!
72
73  rm -f "${perfdata}"
74
75  wait_for_threads ${TESTPID} 2
76  perf record -p "${TESTPID}" --per-thread -o "${perfdata}" sleep 1 2> /dev/null
77  kill ${TESTPID}
78
79  if [ ! -e "${perfdata}" ]
80  then
81    echo "Per-thread record [Failed record -p]"
82    err=1
83    return
84  fi
85  if ! perf report -i "${perfdata}" -q | grep -q "${testsym}"
86  then
87    echo "Per-thread record [Failed -p missing output]"
88    err=1
89    return
90  fi
91
92  echo "Basic --per-thread mode test [Success]"
93}
94
95test_register_capture() {
96  echo "Register capture test"
97  if ! perf list pmu | grep -q 'br_inst_retired.near_call'
98  then
99    echo "Register capture test [Skipped missing event]"
100    return
101  fi
102  if ! perf record --intr-regs=\? 2>&1 | grep -q 'available registers: AX BX CX DX SI DI BP SP IP FLAGS CS SS R8 R9 R10 R11 R12 R13 R14 R15'
103  then
104    echo "Register capture test [Skipped missing registers]"
105    return
106  fi
107  if ! perf record -o - --intr-regs=di,r8,dx,cx -e br_inst_retired.near_call \
108    -c 1000 --per-thread ${testprog} 2> /dev/null \
109    | perf script -F ip,sym,iregs -i - 2> /dev/null \
110    | grep -q "DI:"
111  then
112    echo "Register capture test [Failed missing output]"
113    err=1
114    return
115  fi
116  echo "Register capture test [Success]"
117}
118
119test_system_wide() {
120  echo "Basic --system-wide mode test"
121  if ! perf record -aB --synth=no -o "${perfdata}" ${testprog} 2> /dev/null
122  then
123    echo "System-wide record [Skipped not supported]"
124    return
125  fi
126  if ! perf report -i "${perfdata}" -q | grep -q "${testsym}"
127  then
128    echo "System-wide record [Failed missing output]"
129    err=1
130    return
131  fi
132  if ! perf record -aB --synth=no -e cpu-clock,cs --threads=cpu \
133    -o "${perfdata}" ${testprog} 2> /dev/null
134  then
135    echo "System-wide record [Failed record --threads option]"
136    err=1
137    return
138  fi
139  if ! perf report -i "${perfdata}" -q | grep -q "${testsym}"
140  then
141    echo "System-wide record [Failed --threads missing output]"
142    err=1
143    return
144  fi
145  echo "Basic --system-wide mode test [Success]"
146}
147
148test_workload() {
149  echo "Basic target workload test"
150  if ! perf record -o "${perfdata}" ${testprog} 2> /dev/null
151  then
152    echo "Workload record [Failed record]"
153    err=1
154    return
155  fi
156  if ! perf report -i "${perfdata}" -q | grep -q "${testsym}"
157  then
158    echo "Workload record [Failed missing output]"
159    err=1
160    return
161  fi
162  if ! perf record -e cpu-clock,cs --threads=package \
163    -o "${perfdata}" ${testprog} 2> /dev/null
164  then
165    echo "Workload record [Failed record --threads option]"
166    err=1
167    return
168  fi
169  if ! perf report -i "${perfdata}" -q | grep -q "${testsym}"
170  then
171    echo "Workload record [Failed --threads missing output]"
172    err=1
173    return
174  fi
175  echo "Basic target workload test [Success]"
176}
177
178test_branch_counter() {
179  echo "Branch counter test"
180  # Check if the branch counter feature is supported
181  for dir in $cpu_pmu_dir
182  do
183    if [ ! -e "$dir$br_cntr_file" ]
184    then
185      echo "branch counter feature not supported on all core PMUs ($dir) [Skipped]"
186      return
187    fi
188  done
189  if ! perf record -o "${perfdata}" -e "{branches:p,instructions}" -j any,counter ${testprog} 2> /dev/null
190  then
191    echo "Branch counter record test [Failed record]"
192    err=1
193    return
194  fi
195  if ! perf report -i "${perfdata}" -D -q | grep -q "$br_cntr_output"
196  then
197    echo "Branch counter report test [Failed missing output]"
198    err=1
199    return
200  fi
201  if ! perf script -i "${perfdata}" -F +brstackinsn,+brcntr | grep -q "$br_cntr_script_output"
202  then
203    echo " Branch counter script test [Failed missing output]"
204    err=1
205    return
206  fi
207  echo "Branch counter test [Success]"
208}
209
210test_cgroup() {
211  echo "Cgroup sampling test"
212  if ! perf record -aB --synth=cgroup --all-cgroups -o "${perfdata}" ${testprog} 2> /dev/null
213  then
214    echo "Cgroup sampling [Skipped not supported]"
215    return
216  fi
217  if ! perf report -i "${perfdata}" -D | grep -q "CGROUP"
218  then
219    echo "Cgroup sampling [Failed missing output]"
220    err=1
221    return
222  fi
223  if ! perf script -i "${perfdata}" -F cgroup | grep -q -v "unknown"
224  then
225    echo "Cgroup sampling [Failed cannot resolve cgroup names]"
226    err=1
227    return
228  fi
229  echo "Cgroup sampling test [Success]"
230}
231
232test_leader_sampling() {
233  echo "Basic leader sampling test"
234  if ! perf record -o "${perfdata}" -e "{instructions,instructions}:Su" -- \
235    perf test -w brstack 2> /dev/null
236  then
237    echo "Leader sampling [Failed record]"
238    err=1
239    return
240  fi
241  index=0
242  perf script -i "${perfdata}" > $script_output
243  while IFS= read -r line
244  do
245    # Check if the two instruction counts are equal in each record
246    instructions=$(echo $line | awk '{for(i=1;i<=NF;i++) if($i=="instructions:") print $(i-1)}')
247    if [ $(($index%2)) -ne 0 ] && [ ${instructions}x != ${prev_instructions}x ]
248    then
249      echo "Leader sampling [Failed inconsistent instructions count]"
250      err=1
251      return
252    fi
253    index=$(($index+1))
254    prev_instructions=$instructions
255  done < $script_output
256  echo "Basic leader sampling test [Success]"
257}
258
259test_topdown_leader_sampling() {
260  echo "Topdown leader sampling test"
261  if ! perf stat -e "{slots,topdown-retiring}" true 2> /dev/null
262  then
263    echo "Topdown leader sampling [Skipped event parsing failed]"
264    return
265  fi
266  if ! perf record -o "${perfdata}" -e "{instructions,slots,topdown-retiring}:S" true 2> /dev/null
267  then
268    echo "Topdown leader sampling [Failed topdown events not reordered correctly]"
269    err=1
270    return
271  fi
272  echo "Topdown leader sampling test [Success]"
273}
274
275test_precise_max() {
276  echo "precise_max attribute test"
277  if ! perf stat -e "cycles,instructions" true 2> /dev/null
278  then
279    echo "precise_max attribute [Skipped no hardware events]"
280    return
281  fi
282  # Just to make sure it doesn't fail
283  if ! perf record -o "${perfdata}" -e "cycles:P" true 2> /dev/null
284  then
285    echo "precise_max attribute [Failed cycles:P event]"
286    err=1
287    return
288  fi
289  # On AMD, cycles and instructions events are treated differently
290  if ! perf record -o "${perfdata}" -e "instructions:P" true 2> /dev/null
291  then
292    echo "precise_max attribute [Failed instructions:P event]"
293    err=1
294    return
295  fi
296  echo "precise_max attribute test [Success]"
297}
298
299# raise the limit of file descriptors to minimum
300if [[ $default_fd_limit -lt $min_fd_limit ]]; then
301       ulimit -Sn $min_fd_limit
302fi
303
304test_per_thread
305test_register_capture
306test_system_wide
307test_workload
308test_branch_counter
309test_cgroup
310test_leader_sampling
311test_topdown_leader_sampling
312test_precise_max
313
314# restore the default value
315ulimit -Sn $default_fd_limit
316
317cleanup
318exit $err
319