11097b38fSAdrian Hunter#!/bin/sh
21097b38fSAdrian Hunter# Miscellaneous Intel PT testing
31097b38fSAdrian Hunter# SPDX-License-Identifier: GPL-2.0
41097b38fSAdrian Hunter
51097b38fSAdrian Hunterset -e
61097b38fSAdrian Hunter
71097b38fSAdrian Hunter# Skip if no Intel PT
81097b38fSAdrian Hunterperf list | grep -q 'intel_pt//' || exit 2
91097b38fSAdrian Hunter
105ebcdf07SAdrian Huntershelldir=$(dirname "$0")
115ebcdf07SAdrian Hunter. "${shelldir}"/lib/waiting.sh
125ebcdf07SAdrian Hunter
131097b38fSAdrian Hunterskip_cnt=0
141097b38fSAdrian Hunterok_cnt=0
151097b38fSAdrian Huntererr_cnt=0
161097b38fSAdrian Hunter
17170ac70fSAdrian Huntertemp_dir=$(mktemp -d /tmp/perf-test-intel-pt-sh.XXXXXXXXXX)
18170ac70fSAdrian Hunter
19170ac70fSAdrian Huntertmpfile="${temp_dir}/tmp-perf.data"
20170ac70fSAdrian Hunterperfdatafile="${temp_dir}/test-perf.data"
21fea753f8SAdrian Hunteroutfile="${temp_dir}/test-out.txt"
22fea753f8SAdrian Huntererrfile="${temp_dir}/test-err.txt"
23fea753f8SAdrian Hunterworkload="${temp_dir}/workload"
24fea753f8SAdrian Hunterawkscript="${temp_dir}/awkscript"
251097b38fSAdrian Hunter
2619af23dfSAdrian Huntercleanup()
2719af23dfSAdrian Hunter{
2819af23dfSAdrian Hunter	trap - EXIT TERM INT
29170ac70fSAdrian Hunter	sane=$(echo "${temp_dir}" | cut -b 1-26)
30170ac70fSAdrian Hunter	if [ "${sane}" = "/tmp/perf-test-intel-pt-sh" ] ; then
31170ac70fSAdrian Hunter		echo "--- Cleaning up ---"
32170ac70fSAdrian Hunter		rm -f "${temp_dir}/"*
33170ac70fSAdrian Hunter		rmdir "${temp_dir}"
34170ac70fSAdrian Hunter	fi
3519af23dfSAdrian Hunter}
3619af23dfSAdrian Hunter
3719af23dfSAdrian Huntertrap_cleanup()
3819af23dfSAdrian Hunter{
3919af23dfSAdrian Hunter	cleanup
4019af23dfSAdrian Hunter	exit 1
4119af23dfSAdrian Hunter}
4219af23dfSAdrian Hunter
4319af23dfSAdrian Huntertrap trap_cleanup EXIT TERM INT
4419af23dfSAdrian Hunter
455021d82bSAdrian Hunter# perf record for testing without decoding
465021d82bSAdrian Hunterperf_record_no_decode()
475021d82bSAdrian Hunter{
485021d82bSAdrian Hunter	# Options to speed up recording: no post-processing, no build-id cache update,
495021d82bSAdrian Hunter	# and no BPF events.
505021d82bSAdrian Hunter	perf record -B -N --no-bpf-event "$@"
515021d82bSAdrian Hunter}
525021d82bSAdrian Hunter
53fea753f8SAdrian Hunterhave_workload=false
54fea753f8SAdrian Huntercat << _end_of_file_ | /usr/bin/cc -o "${workload}" -xc - -pthread && have_workload=true
55fea753f8SAdrian Hunter#include <time.h>
56fea753f8SAdrian Hunter#include <pthread.h>
57fea753f8SAdrian Hunter
58fea753f8SAdrian Huntervoid work(void) {
59fea753f8SAdrian Hunter	struct timespec tm = {
60fea753f8SAdrian Hunter		.tv_nsec = 1000000,
61fea753f8SAdrian Hunter	};
62fea753f8SAdrian Hunter	int i;
63fea753f8SAdrian Hunter
64fea753f8SAdrian Hunter	/* Run for about 30 seconds */
65fea753f8SAdrian Hunter	for (i = 0; i < 30000; i++)
66fea753f8SAdrian Hunter		nanosleep(&tm, NULL);
67fea753f8SAdrian Hunter}
68fea753f8SAdrian Hunter
69fea753f8SAdrian Huntervoid *threadfunc(void *arg) {
70fea753f8SAdrian Hunter	work();
71fea753f8SAdrian Hunter	return NULL;
72fea753f8SAdrian Hunter}
73fea753f8SAdrian Hunter
74fea753f8SAdrian Hunterint main(void) {
75fea753f8SAdrian Hunter	pthread_t th;
76fea753f8SAdrian Hunter
77fea753f8SAdrian Hunter	pthread_create(&th, NULL, threadfunc, NULL);
78fea753f8SAdrian Hunter	work();
79fea753f8SAdrian Hunter	pthread_join(th, NULL);
80fea753f8SAdrian Hunter	return 0;
81fea753f8SAdrian Hunter}
82fea753f8SAdrian Hunter_end_of_file_
83fea753f8SAdrian Hunter
841097b38fSAdrian Huntercan_cpu_wide()
851097b38fSAdrian Hunter{
862c1c9e35SAdrian Hunter	echo "Checking for CPU-wide recording on CPU $1"
875021d82bSAdrian Hunter	if ! perf_record_no_decode -o "${tmpfile}" -e dummy:u -C "$1" true >/dev/null 2>&1 ; then
882c1c9e35SAdrian Hunter		echo "No so skipping"
892c1c9e35SAdrian Hunter		return 2
902c1c9e35SAdrian Hunter	fi
912c1c9e35SAdrian Hunter	echo OK
921097b38fSAdrian Hunter	return 0
931097b38fSAdrian Hunter}
941097b38fSAdrian Hunter
951097b38fSAdrian Huntertest_system_wide_side_band()
961097b38fSAdrian Hunter{
972c1c9e35SAdrian Hunter	echo "--- Test system-wide sideband ---"
982c1c9e35SAdrian Hunter
991097b38fSAdrian Hunter	# Need CPU 0 and CPU 1
1001097b38fSAdrian Hunter	can_cpu_wide 0 || return $?
1011097b38fSAdrian Hunter	can_cpu_wide 1 || return $?
1021097b38fSAdrian Hunter
1031097b38fSAdrian Hunter	# Record on CPU 0 a task running on CPU 1
1045021d82bSAdrian Hunter	perf_record_no_decode -o "${perfdatafile}" -e intel_pt//u -C 0 -- taskset --cpu-list 1 uname
1051097b38fSAdrian Hunter
1061097b38fSAdrian Hunter	# Should get MMAP events from CPU 1 because they can be needed to decode
1075d7aac2bSAdrian Hunter	mmap_cnt=$(perf script -i "${perfdatafile}" --no-itrace --show-mmap-events -C 1 2>/dev/null | grep -c MMAP)
1081097b38fSAdrian Hunter
1095d7aac2bSAdrian Hunter	if [ "${mmap_cnt}" -gt 0 ] ; then
1102c1c9e35SAdrian Hunter		echo OK
1111097b38fSAdrian Hunter		return 0
1121097b38fSAdrian Hunter	fi
1131097b38fSAdrian Hunter
1141097b38fSAdrian Hunter	echo "Failed to record MMAP events on CPU 1 when tracing CPU 0"
1151097b38fSAdrian Hunter	return 1
1161097b38fSAdrian Hunter}
1171097b38fSAdrian Hunter
118fea753f8SAdrian Huntercan_kernel()
119fea753f8SAdrian Hunter{
120*9637bf8fSAdrian Hunter	if [ -z "${can_kernel_trace}" ] ; then
121*9637bf8fSAdrian Hunter		can_kernel_trace=0
122*9637bf8fSAdrian Hunter		perf_record_no_decode -o "${tmpfile}" -e dummy:k true >/dev/null 2>&1 && can_kernel_trace=1
123*9637bf8fSAdrian Hunter	fi
124*9637bf8fSAdrian Hunter	if [ ${can_kernel_trace} -eq 0 ] ; then
125*9637bf8fSAdrian Hunter		echo "SKIP: no kernel tracing"
126*9637bf8fSAdrian Hunter		return 2
127*9637bf8fSAdrian Hunter	fi
128fea753f8SAdrian Hunter	return 0
129fea753f8SAdrian Hunter}
130fea753f8SAdrian Hunter
131fea753f8SAdrian Huntertest_per_thread()
132fea753f8SAdrian Hunter{
133fea753f8SAdrian Hunter	k="$1"
134fea753f8SAdrian Hunter	desc="$2"
135fea753f8SAdrian Hunter
136fea753f8SAdrian Hunter	echo "--- Test per-thread ${desc}recording ---"
137fea753f8SAdrian Hunter
138fea753f8SAdrian Hunter	if ! $have_workload ; then
139fea753f8SAdrian Hunter		echo "No workload, so skipping"
140fea753f8SAdrian Hunter		return 2
141fea753f8SAdrian Hunter	fi
142fea753f8SAdrian Hunter
143fea753f8SAdrian Hunter	if [ "${k}" = "k" ] ; then
144fea753f8SAdrian Hunter		can_kernel || return 2
145fea753f8SAdrian Hunter	fi
146fea753f8SAdrian Hunter
147fea753f8SAdrian Hunter	cat <<- "_end_of_file_" > "${awkscript}"
148fea753f8SAdrian Hunter	BEGIN {
149fea753f8SAdrian Hunter		s = "[ ]*"
150fea753f8SAdrian Hunter		u = s"[0-9]+"s
151fea753f8SAdrian Hunter		d = s"[0-9-]+"s
152fea753f8SAdrian Hunter		x = s"[0-9a-fA-FxX]+"s
153fea753f8SAdrian Hunter		mmapping = "idx"u": mmapping fd"u
154fea753f8SAdrian Hunter		set_output = "idx"u": set output fd"u"->"u
155fea753f8SAdrian Hunter		perf_event_open = "sys_perf_event_open: pid"d"cpu"d"group_fd"d"flags"x"="u
156fea753f8SAdrian Hunter	}
157fea753f8SAdrian Hunter
158fea753f8SAdrian Hunter	/perf record opening and mmapping events/ {
159fea753f8SAdrian Hunter		if (!done)
160fea753f8SAdrian Hunter			active = 1
161fea753f8SAdrian Hunter	}
162fea753f8SAdrian Hunter
163fea753f8SAdrian Hunter	/perf record done opening and mmapping events/ {
164fea753f8SAdrian Hunter		active = 0
165fea753f8SAdrian Hunter		done = 1
166fea753f8SAdrian Hunter	}
167fea753f8SAdrian Hunter
168fea753f8SAdrian Hunter	$0 ~ perf_event_open && active {
169fea753f8SAdrian Hunter		match($0, perf_event_open)
170fea753f8SAdrian Hunter		$0 = substr($0, RSTART, RLENGTH)
171fea753f8SAdrian Hunter		pid = $3
172fea753f8SAdrian Hunter		cpu = $5
173fea753f8SAdrian Hunter		fd = $11
174fea753f8SAdrian Hunter		print "pid " pid " cpu " cpu " fd " fd " : " $0
175fea753f8SAdrian Hunter		fd_array[fd] = fd
176fea753f8SAdrian Hunter		pid_array[fd] = pid
177fea753f8SAdrian Hunter		cpu_array[fd] = cpu
178fea753f8SAdrian Hunter	}
179fea753f8SAdrian Hunter
180fea753f8SAdrian Hunter	$0 ~ mmapping && active  {
181fea753f8SAdrian Hunter		match($0, mmapping)
182fea753f8SAdrian Hunter		$0 = substr($0, RSTART, RLENGTH)
183fea753f8SAdrian Hunter		fd = $5
184fea753f8SAdrian Hunter		print "fd " fd " : " $0
185fea753f8SAdrian Hunter		if (fd in fd_array) {
186fea753f8SAdrian Hunter			mmap_array[fd] = 1
187fea753f8SAdrian Hunter		} else {
188fea753f8SAdrian Hunter			print "Unknown fd " fd
189fea753f8SAdrian Hunter			exit 1
190fea753f8SAdrian Hunter		}
191fea753f8SAdrian Hunter	}
192fea753f8SAdrian Hunter
193fea753f8SAdrian Hunter	$0 ~ set_output && active {
194fea753f8SAdrian Hunter		match($0, set_output)
195fea753f8SAdrian Hunter		$0 = substr($0, RSTART, RLENGTH)
196fea753f8SAdrian Hunter		fd = $6
197fea753f8SAdrian Hunter		fd_to = $8
198fea753f8SAdrian Hunter		print "fd " fd " fd_to " fd_to " : " $0
199fea753f8SAdrian Hunter		if (fd in fd_array) {
200fea753f8SAdrian Hunter			if (fd_to in fd_array) {
201fea753f8SAdrian Hunter				set_output_array[fd] = fd_to
202fea753f8SAdrian Hunter			} else {
203fea753f8SAdrian Hunter				print "Unknown fd " fd_to
204fea753f8SAdrian Hunter				exit 1
205fea753f8SAdrian Hunter			}
206fea753f8SAdrian Hunter		} else {
207fea753f8SAdrian Hunter			print "Unknown fd " fd
208fea753f8SAdrian Hunter			exit 1
209fea753f8SAdrian Hunter		}
210fea753f8SAdrian Hunter	}
211fea753f8SAdrian Hunter
212fea753f8SAdrian Hunter	END {
213fea753f8SAdrian Hunter		print "Checking " length(fd_array) " fds"
214fea753f8SAdrian Hunter		for (fd in fd_array) {
215fea753f8SAdrian Hunter			if (fd in mmap_array) {
216fea753f8SAdrian Hunter				pid = pid_array[fd]
217fea753f8SAdrian Hunter				if (pid != -1) {
218fea753f8SAdrian Hunter					if (pid in pids) {
219fea753f8SAdrian Hunter						print "More than 1 mmap for PID " pid
220fea753f8SAdrian Hunter						exit 1
221fea753f8SAdrian Hunter					}
222fea753f8SAdrian Hunter					pids[pid] = 1
223fea753f8SAdrian Hunter				}
224fea753f8SAdrian Hunter				cpu = cpu_array[fd]
225fea753f8SAdrian Hunter				if (cpu != -1) {
226fea753f8SAdrian Hunter					if (cpu in cpus) {
227fea753f8SAdrian Hunter						print "More than 1 mmap for CPU " cpu
228fea753f8SAdrian Hunter						exit 1
229fea753f8SAdrian Hunter					}
230fea753f8SAdrian Hunter					cpus[cpu] = 1
231fea753f8SAdrian Hunter				}
232fea753f8SAdrian Hunter			} else if (!(fd in set_output_array)) {
233fea753f8SAdrian Hunter				print "No mmap for fd " fd
234fea753f8SAdrian Hunter				exit 1
235fea753f8SAdrian Hunter			}
236fea753f8SAdrian Hunter		}
237fea753f8SAdrian Hunter		n = length(pids)
238fea753f8SAdrian Hunter		if (n != thread_cnt) {
239fea753f8SAdrian Hunter			print "Expected " thread_cnt " per-thread mmaps - found " n
240fea753f8SAdrian Hunter			exit 1
241fea753f8SAdrian Hunter		}
242fea753f8SAdrian Hunter	}
243fea753f8SAdrian Hunter	_end_of_file_
244fea753f8SAdrian Hunter
245fea753f8SAdrian Hunter	$workload &
246fea753f8SAdrian Hunter	w1=$!
247fea753f8SAdrian Hunter	$workload &
248fea753f8SAdrian Hunter	w2=$!
249fea753f8SAdrian Hunter	echo "Workload PIDs are $w1 and $w2"
250fea753f8SAdrian Hunter	wait_for_threads ${w1} 2
251fea753f8SAdrian Hunter	wait_for_threads ${w2} 2
252fea753f8SAdrian Hunter
2535021d82bSAdrian Hunter	perf_record_no_decode -o "${perfdatafile}" -e intel_pt//u"${k}" -vvv --per-thread -p "${w1},${w2}" 2>"${errfile}" >"${outfile}" &
254fea753f8SAdrian Hunter	ppid=$!
255fea753f8SAdrian Hunter	echo "perf PID is $ppid"
2565ebcdf07SAdrian Hunter	wait_for_perf_to_start ${ppid} "${errfile}" || return 1
257fea753f8SAdrian Hunter
258fea753f8SAdrian Hunter	kill ${w1}
259fea753f8SAdrian Hunter	wait_for_process_to_exit ${w1} || return 1
260fea753f8SAdrian Hunter	is_running ${ppid} || return 1
261fea753f8SAdrian Hunter
262fea753f8SAdrian Hunter	kill ${w2}
263fea753f8SAdrian Hunter	wait_for_process_to_exit ${w2} || return 1
264fea753f8SAdrian Hunter	wait_for_process_to_exit ${ppid} || return 1
265fea753f8SAdrian Hunter
266fea753f8SAdrian Hunter	awk -v thread_cnt=4 -f "${awkscript}" "${errfile}" || return 1
267fea753f8SAdrian Hunter
268fea753f8SAdrian Hunter	echo OK
269fea753f8SAdrian Hunter	return 0
270fea753f8SAdrian Hunter}
271fea753f8SAdrian Hunter
2721097b38fSAdrian Huntercount_result()
2731097b38fSAdrian Hunter{
2745d7aac2bSAdrian Hunter	if [ "$1" -eq 2 ] ; then
275202d0394SAdrian Hunter		skip_cnt=$((skip_cnt + 1))
2761097b38fSAdrian Hunter		return
2771097b38fSAdrian Hunter	fi
2785d7aac2bSAdrian Hunter	if [ "$1" -eq 0 ] ; then
279202d0394SAdrian Hunter		ok_cnt=$((ok_cnt + 1))
2801097b38fSAdrian Hunter		return
2811097b38fSAdrian Hunter	fi
282202d0394SAdrian Hunter	err_cnt=$((err_cnt + 1))
2831097b38fSAdrian Hunter}
2841097b38fSAdrian Hunter
285fd9b45e3SAdrian Hunterret=0
286e4080492SAdrian Huntertest_system_wide_side_band || ret=$? ; count_result $ret ; ret=0
287e4080492SAdrian Huntertest_per_thread "" "" || ret=$? ; count_result $ret ; ret=0
288e4080492SAdrian Huntertest_per_thread "k" "(incl. kernel) " || ret=$? ; count_result $ret ; ret=0
2891097b38fSAdrian Hunter
29019af23dfSAdrian Huntercleanup
2911097b38fSAdrian Hunter
2922c1c9e35SAdrian Hunterecho "--- Done ---"
2932c1c9e35SAdrian Hunter
2941097b38fSAdrian Hunterif [ ${err_cnt} -gt 0 ] ; then
2951097b38fSAdrian Hunter	exit 1
2961097b38fSAdrian Hunterfi
2971097b38fSAdrian Hunter
2981097b38fSAdrian Hunterif [ ${ok_cnt} -gt 0 ] ; then
2991097b38fSAdrian Hunter	exit 0
3001097b38fSAdrian Hunterfi
3011097b38fSAdrian Hunter
3021097b38fSAdrian Hunterexit 2
303