1#!/bin/sh 2# Miscellaneous Intel PT testing 3# SPDX-License-Identifier: GPL-2.0 4 5set -e 6 7# Skip if no Intel PT 8perf list | grep -q 'intel_pt//' || exit 2 9 10shelldir=$(dirname "$0") 11. "${shelldir}"/lib/waiting.sh 12 13skip_cnt=0 14ok_cnt=0 15err_cnt=0 16 17temp_dir=$(mktemp -d /tmp/perf-test-intel-pt-sh.XXXXXXXXXX) 18 19tmpfile="${temp_dir}/tmp-perf.data" 20perfdatafile="${temp_dir}/test-perf.data" 21outfile="${temp_dir}/test-out.txt" 22errfile="${temp_dir}/test-err.txt" 23workload="${temp_dir}/workload" 24awkscript="${temp_dir}/awkscript" 25 26cleanup() 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 37trap_cleanup() 38{ 39 cleanup 40 exit 1 41} 42 43trap trap_cleanup EXIT TERM INT 44 45have_workload=false 46cat << _end_of_file_ | /usr/bin/cc -o "${workload}" -xc - -pthread && have_workload=true 47#include <time.h> 48#include <pthread.h> 49 50void 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 61void *threadfunc(void *arg) { 62 work(); 63 return NULL; 64} 65 66int 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 76can_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 87test_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 110can_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 116test_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 257count_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 ret=0 269} 270 271ret=0 272test_system_wide_side_band || ret=$? ; count_result $ret 273test_per_thread "" "" || ret=$? ; count_result $ret 274test_per_thread "k" "(incl. kernel) " || ret=$? ; count_result $ret 275 276cleanup 277 278echo "--- Done ---" 279 280if [ ${err_cnt} -gt 0 ] ; then 281 exit 1 282fi 283 284if [ ${ok_cnt} -gt 0 ] ; then 285 exit 0 286fi 287 288exit 2 289