4609a24c9340005247c969d3fcf27b8af2ddae51
[platform/kernel/linux-rpi.git] / tools / perf / tests / shell / test_intel_pt.sh
1 #!/bin/sh
2 # Miscellaneous Intel PT testing
3 # SPDX-License-Identifier: GPL-2.0
4
5 set -e
6
7 # Skip if no Intel PT
8 perf list | grep -q 'intel_pt//' || exit 2
9
10 shelldir=$(dirname "$0")
11 . "${shelldir}"/lib/waiting.sh
12
13 skip_cnt=0
14 ok_cnt=0
15 err_cnt=0
16
17 temp_dir=$(mktemp -d /tmp/perf-test-intel-pt-sh.XXXXXXXXXX)
18
19 tmpfile="${temp_dir}/tmp-perf.data"
20 perfdatafile="${temp_dir}/test-perf.data"
21 outfile="${temp_dir}/test-out.txt"
22 errfile="${temp_dir}/test-err.txt"
23 workload="${temp_dir}/workload"
24 awkscript="${temp_dir}/awkscript"
25
26 cleanup()
27 {
28         trap - EXIT TERM INT
29         sane=$(echo "${temp_dir}" | cut -b 1-26)
30         if [ "${sane}" = "/tmp/perf-test-intel-pt-sh" ] ; then
31                 echo "--- Cleaning up ---"
32                 rm -f "${temp_dir}/"*
33                 rmdir "${temp_dir}"
34         fi
35 }
36
37 trap_cleanup()
38 {
39         cleanup
40         exit 1
41 }
42
43 trap trap_cleanup EXIT TERM INT
44
45 have_workload=false
46 cat << _end_of_file_ | /usr/bin/cc -o "${workload}" -xc - -pthread && have_workload=true
47 #include <time.h>
48 #include <pthread.h>
49
50 void work(void) {
51         struct timespec tm = {
52                 .tv_nsec = 1000000,
53         };
54         int i;
55
56         /* Run for about 30 seconds */
57         for (i = 0; i < 30000; i++)
58                 nanosleep(&tm, NULL);
59 }
60
61 void *threadfunc(void *arg) {
62         work();
63         return NULL;
64 }
65
66 int main(void) {
67         pthread_t th;
68
69         pthread_create(&th, NULL, threadfunc, NULL);
70         work();
71         pthread_join(th, NULL);
72         return 0;
73 }
74 _end_of_file_
75
76 can_cpu_wide()
77 {
78         echo "Checking for CPU-wide recording on CPU $1"
79         if ! perf record -o "${tmpfile}" -B -N --no-bpf-event -e dummy:u -C "$1" true >/dev/null 2>&1 ; then
80                 echo "No so skipping"
81                 return 2
82         fi
83         echo OK
84         return 0
85 }
86
87 test_system_wide_side_band()
88 {
89         echo "--- Test system-wide sideband ---"
90
91         # Need CPU 0 and CPU 1
92         can_cpu_wide 0 || return $?
93         can_cpu_wide 1 || return $?
94
95         # Record on CPU 0 a task running on CPU 1
96         perf record -B -N --no-bpf-event -o "${perfdatafile}" -e intel_pt//u -C 0 -- taskset --cpu-list 1 uname
97
98         # Should get MMAP events from CPU 1 because they can be needed to decode
99         mmap_cnt=$(perf script -i "${perfdatafile}" --no-itrace --show-mmap-events -C 1 2>/dev/null | grep -c MMAP)
100
101         if [ "${mmap_cnt}" -gt 0 ] ; then
102                 echo OK
103                 return 0
104         fi
105
106         echo "Failed to record MMAP events on CPU 1 when tracing CPU 0"
107         return 1
108 }
109
110 can_kernel()
111 {
112         perf record -o "${tmpfile}" -B -N --no-bpf-event -e dummy:k true >/dev/null 2>&1 || return 2
113         return 0
114 }
115
116 test_per_thread()
117 {
118         k="$1"
119         desc="$2"
120
121         echo "--- Test per-thread ${desc}recording ---"
122
123         if ! $have_workload ; then
124                 echo "No workload, so skipping"
125                 return 2
126         fi
127
128         if [ "${k}" = "k" ] ; then
129                 can_kernel || return 2
130         fi
131
132         cat <<- "_end_of_file_" > "${awkscript}"
133         BEGIN {
134                 s = "[ ]*"
135                 u = s"[0-9]+"s
136                 d = s"[0-9-]+"s
137                 x = s"[0-9a-fA-FxX]+"s
138                 mmapping = "idx"u": mmapping fd"u
139                 set_output = "idx"u": set output fd"u"->"u
140                 perf_event_open = "sys_perf_event_open: pid"d"cpu"d"group_fd"d"flags"x"="u
141         }
142
143         /perf record opening and mmapping events/ {
144                 if (!done)
145                         active = 1
146         }
147
148         /perf record done opening and mmapping events/ {
149                 active = 0
150                 done = 1
151         }
152
153         $0 ~ perf_event_open && active {
154                 match($0, perf_event_open)
155                 $0 = substr($0, RSTART, RLENGTH)
156                 pid = $3
157                 cpu = $5
158                 fd = $11
159                 print "pid " pid " cpu " cpu " fd " fd " : " $0
160                 fd_array[fd] = fd
161                 pid_array[fd] = pid
162                 cpu_array[fd] = cpu
163         }
164
165         $0 ~ mmapping && active  {
166                 match($0, mmapping)
167                 $0 = substr($0, RSTART, RLENGTH)
168                 fd = $5
169                 print "fd " fd " : " $0
170                 if (fd in fd_array) {
171                         mmap_array[fd] = 1
172                 } else {
173                         print "Unknown fd " fd
174                         exit 1
175                 }
176         }
177
178         $0 ~ set_output && active {
179                 match($0, set_output)
180                 $0 = substr($0, RSTART, RLENGTH)
181                 fd = $6
182                 fd_to = $8
183                 print "fd " fd " fd_to " fd_to " : " $0
184                 if (fd in fd_array) {
185                         if (fd_to in fd_array) {
186                                 set_output_array[fd] = fd_to
187                         } else {
188                                 print "Unknown fd " fd_to
189                                 exit 1
190                         }
191                 } else {
192                         print "Unknown fd " fd
193                         exit 1
194                 }
195         }
196
197         END {
198                 print "Checking " length(fd_array) " fds"
199                 for (fd in fd_array) {
200                         if (fd in mmap_array) {
201                                 pid = pid_array[fd]
202                                 if (pid != -1) {
203                                         if (pid in pids) {
204                                                 print "More than 1 mmap for PID " pid
205                                                 exit 1
206                                         }
207                                         pids[pid] = 1
208                                 }
209                                 cpu = cpu_array[fd]
210                                 if (cpu != -1) {
211                                         if (cpu in cpus) {
212                                                 print "More than 1 mmap for CPU " cpu
213                                                 exit 1
214                                         }
215                                         cpus[cpu] = 1
216                                 }
217                         } else if (!(fd in set_output_array)) {
218                                 print "No mmap for fd " fd
219                                 exit 1
220                         }
221                 }
222                 n = length(pids)
223                 if (n != thread_cnt) {
224                         print "Expected " thread_cnt " per-thread mmaps - found " n
225                         exit 1
226                 }
227         }
228         _end_of_file_
229
230         $workload &
231         w1=$!
232         $workload &
233         w2=$!
234         echo "Workload PIDs are $w1 and $w2"
235         wait_for_threads ${w1} 2
236         wait_for_threads ${w2} 2
237
238         perf record -B -N --no-bpf-event -o "${perfdatafile}" -e intel_pt//u"${k}" -vvv --per-thread -p "${w1},${w2}" 2>"${errfile}" >"${outfile}" &
239         ppid=$!
240         echo "perf PID is $ppid"
241         wait_for_perf_to_start ${ppid} "${errfile}" || return 1
242
243         kill ${w1}
244         wait_for_process_to_exit ${w1} || return 1
245         is_running ${ppid} || return 1
246
247         kill ${w2}
248         wait_for_process_to_exit ${w2} || return 1
249         wait_for_process_to_exit ${ppid} || return 1
250
251         awk -v thread_cnt=4 -f "${awkscript}" "${errfile}" || return 1
252
253         echo OK
254         return 0
255 }
256
257 count_result()
258 {
259         if [ "$1" -eq 2 ] ; then
260                 skip_cnt=$((skip_cnt + 1))
261                 return
262         fi
263         if [ "$1" -eq 0 ] ; then
264                 ok_cnt=$((ok_cnt + 1))
265                 return
266         fi
267         err_cnt=$((err_cnt + 1))
268 }
269
270 ret=0
271 test_system_wide_side_band || ret=$? ; count_result $ret ; ret=0
272 test_per_thread "" "" || ret=$? ; count_result $ret ; ret=0
273 test_per_thread "k" "(incl. kernel) " || ret=$? ; count_result $ret ; ret=0
274
275 cleanup
276
277 echo "--- Done ---"
278
279 if [ ${err_cnt} -gt 0 ] ; then
280         exit 1
281 fi
282
283 if [ ${ok_cnt} -gt 0 ] ; then
284         exit 0
285 fi
286
287 exit 2