Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf test: test_intel_pt.sh: Add per-thread test

When tracing the kernel with Intel PT, text_poke events are recorded
per-cpu. In per-thread mode that results in a mixture of per-thread and
per-cpu events and mmaps. Check that happens correctly.

The debug output from perf record -vvv is recorded and then awk used to
process the debug messages that indicate what file descriptors were
opened and whether they were mmapped or set-output.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lore.kernel.org/lkml/20220912083412.7058-12-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Adrian Hunter and committed by
Arnaldo Carvalho de Melo
fea753f8 da406202

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