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"
25973db240SAdrian Hunterjitdump_workload="${temp_dir}/jitdump_workload"
26f77811a0SAmmy Yimaxbrstack="${temp_dir}/maxbrstack.py"
271097b38fSAdrian Hunter
2819af23dfSAdrian Huntercleanup()
2919af23dfSAdrian Hunter{
3019af23dfSAdrian Hunter	trap - EXIT TERM INT
31170ac70fSAdrian Hunter	sane=$(echo "${temp_dir}" | cut -b 1-26)
32170ac70fSAdrian Hunter	if [ "${sane}" = "/tmp/perf-test-intel-pt-sh" ] ; then
33170ac70fSAdrian Hunter		echo "--- Cleaning up ---"
34170ac70fSAdrian Hunter		rm -f "${temp_dir}/"*
35170ac70fSAdrian Hunter		rmdir "${temp_dir}"
36170ac70fSAdrian Hunter	fi
3719af23dfSAdrian Hunter}
3819af23dfSAdrian Hunter
3919af23dfSAdrian Huntertrap_cleanup()
4019af23dfSAdrian Hunter{
4119af23dfSAdrian Hunter	cleanup
4219af23dfSAdrian Hunter	exit 1
4319af23dfSAdrian Hunter}
4419af23dfSAdrian Hunter
4519af23dfSAdrian Huntertrap trap_cleanup EXIT TERM INT
4619af23dfSAdrian Hunter
475021d82bSAdrian Hunter# perf record for testing without decoding
485021d82bSAdrian Hunterperf_record_no_decode()
495021d82bSAdrian Hunter{
505021d82bSAdrian Hunter	# Options to speed up recording: no post-processing, no build-id cache update,
515021d82bSAdrian Hunter	# and no BPF events.
525021d82bSAdrian Hunter	perf record -B -N --no-bpf-event "$@"
535021d82bSAdrian Hunter}
545021d82bSAdrian Hunter
55973db240SAdrian Hunter# perf record for testing should not need BPF events
56973db240SAdrian Hunterperf_record_no_bpf()
57973db240SAdrian Hunter{
58973db240SAdrian Hunter	# Options for no BPF events
59973db240SAdrian Hunter	perf record --no-bpf-event "$@"
60973db240SAdrian Hunter}
61973db240SAdrian Hunter
62fea753f8SAdrian Hunterhave_workload=false
63fea753f8SAdrian Huntercat << _end_of_file_ | /usr/bin/cc -o "${workload}" -xc - -pthread && have_workload=true
64fea753f8SAdrian Hunter#include <time.h>
65fea753f8SAdrian Hunter#include <pthread.h>
66fea753f8SAdrian Hunter
67fea753f8SAdrian Huntervoid work(void) {
68fea753f8SAdrian Hunter	struct timespec tm = {
69fea753f8SAdrian Hunter		.tv_nsec = 1000000,
70fea753f8SAdrian Hunter	};
71fea753f8SAdrian Hunter	int i;
72fea753f8SAdrian Hunter
73fea753f8SAdrian Hunter	/* Run for about 30 seconds */
74fea753f8SAdrian Hunter	for (i = 0; i < 30000; i++)
75fea753f8SAdrian Hunter		nanosleep(&tm, NULL);
76fea753f8SAdrian Hunter}
77fea753f8SAdrian Hunter
78fea753f8SAdrian Huntervoid *threadfunc(void *arg) {
79fea753f8SAdrian Hunter	work();
80fea753f8SAdrian Hunter	return NULL;
81fea753f8SAdrian Hunter}
82fea753f8SAdrian Hunter
83fea753f8SAdrian Hunterint main(void) {
84fea753f8SAdrian Hunter	pthread_t th;
85fea753f8SAdrian Hunter
86fea753f8SAdrian Hunter	pthread_create(&th, NULL, threadfunc, NULL);
87fea753f8SAdrian Hunter	work();
88fea753f8SAdrian Hunter	pthread_join(th, NULL);
89fea753f8SAdrian Hunter	return 0;
90fea753f8SAdrian Hunter}
91fea753f8SAdrian Hunter_end_of_file_
92fea753f8SAdrian Hunter
931097b38fSAdrian Huntercan_cpu_wide()
941097b38fSAdrian Hunter{
952c1c9e35SAdrian Hunter	echo "Checking for CPU-wide recording on CPU $1"
965021d82bSAdrian Hunter	if ! perf_record_no_decode -o "${tmpfile}" -e dummy:u -C "$1" true >/dev/null 2>&1 ; then
972c1c9e35SAdrian Hunter		echo "No so skipping"
982c1c9e35SAdrian Hunter		return 2
992c1c9e35SAdrian Hunter	fi
1002c1c9e35SAdrian Hunter	echo OK
1011097b38fSAdrian Hunter	return 0
1021097b38fSAdrian Hunter}
1031097b38fSAdrian Hunter
1041097b38fSAdrian Huntertest_system_wide_side_band()
1051097b38fSAdrian Hunter{
1062c1c9e35SAdrian Hunter	echo "--- Test system-wide sideband ---"
1072c1c9e35SAdrian Hunter
1081097b38fSAdrian Hunter	# Need CPU 0 and CPU 1
1091097b38fSAdrian Hunter	can_cpu_wide 0 || return $?
1101097b38fSAdrian Hunter	can_cpu_wide 1 || return $?
1111097b38fSAdrian Hunter
1121097b38fSAdrian Hunter	# Record on CPU 0 a task running on CPU 1
1135021d82bSAdrian Hunter	perf_record_no_decode -o "${perfdatafile}" -e intel_pt//u -C 0 -- taskset --cpu-list 1 uname
1141097b38fSAdrian Hunter
1151097b38fSAdrian Hunter	# Should get MMAP events from CPU 1 because they can be needed to decode
1165d7aac2bSAdrian Hunter	mmap_cnt=$(perf script -i "${perfdatafile}" --no-itrace --show-mmap-events -C 1 2>/dev/null | grep -c MMAP)
1171097b38fSAdrian Hunter
1185d7aac2bSAdrian Hunter	if [ "${mmap_cnt}" -gt 0 ] ; then
1192c1c9e35SAdrian Hunter		echo OK
1201097b38fSAdrian Hunter		return 0
1211097b38fSAdrian Hunter	fi
1221097b38fSAdrian Hunter
1231097b38fSAdrian Hunter	echo "Failed to record MMAP events on CPU 1 when tracing CPU 0"
1241097b38fSAdrian Hunter	return 1
1251097b38fSAdrian Hunter}
1261097b38fSAdrian Hunter
127fea753f8SAdrian Huntercan_kernel()
128fea753f8SAdrian Hunter{
1299637bf8fSAdrian Hunter	if [ -z "${can_kernel_trace}" ] ; then
1309637bf8fSAdrian Hunter		can_kernel_trace=0
1319637bf8fSAdrian Hunter		perf_record_no_decode -o "${tmpfile}" -e dummy:k true >/dev/null 2>&1 && can_kernel_trace=1
1329637bf8fSAdrian Hunter	fi
1339637bf8fSAdrian Hunter	if [ ${can_kernel_trace} -eq 0 ] ; then
1349637bf8fSAdrian Hunter		echo "SKIP: no kernel tracing"
1359637bf8fSAdrian Hunter		return 2
1369637bf8fSAdrian Hunter	fi
137fea753f8SAdrian Hunter	return 0
138fea753f8SAdrian Hunter}
139fea753f8SAdrian Hunter
140fea753f8SAdrian Huntertest_per_thread()
141fea753f8SAdrian Hunter{
142fea753f8SAdrian Hunter	k="$1"
143fea753f8SAdrian Hunter	desc="$2"
144fea753f8SAdrian Hunter
145fea753f8SAdrian Hunter	echo "--- Test per-thread ${desc}recording ---"
146fea753f8SAdrian Hunter
147fea753f8SAdrian Hunter	if ! $have_workload ; then
148fea753f8SAdrian Hunter		echo "No workload, so skipping"
149fea753f8SAdrian Hunter		return 2
150fea753f8SAdrian Hunter	fi
151fea753f8SAdrian Hunter
152fea753f8SAdrian Hunter	if [ "${k}" = "k" ] ; then
153fea753f8SAdrian Hunter		can_kernel || return 2
154fea753f8SAdrian Hunter	fi
155fea753f8SAdrian Hunter
156fea753f8SAdrian Hunter	cat <<- "_end_of_file_" > "${awkscript}"
157fea753f8SAdrian Hunter	BEGIN {
158fea753f8SAdrian Hunter		s = "[ ]*"
159fea753f8SAdrian Hunter		u = s"[0-9]+"s
160fea753f8SAdrian Hunter		d = s"[0-9-]+"s
161fea753f8SAdrian Hunter		x = s"[0-9a-fA-FxX]+"s
162fea753f8SAdrian Hunter		mmapping = "idx"u": mmapping fd"u
163fea753f8SAdrian Hunter		set_output = "idx"u": set output fd"u"->"u
164fea753f8SAdrian Hunter		perf_event_open = "sys_perf_event_open: pid"d"cpu"d"group_fd"d"flags"x"="u
165fea753f8SAdrian Hunter	}
166fea753f8SAdrian Hunter
167fea753f8SAdrian Hunter	/perf record opening and mmapping events/ {
168fea753f8SAdrian Hunter		if (!done)
169fea753f8SAdrian Hunter			active = 1
170fea753f8SAdrian Hunter	}
171fea753f8SAdrian Hunter
172fea753f8SAdrian Hunter	/perf record done opening and mmapping events/ {
173fea753f8SAdrian Hunter		active = 0
174fea753f8SAdrian Hunter		done = 1
175fea753f8SAdrian Hunter	}
176fea753f8SAdrian Hunter
177fea753f8SAdrian Hunter	$0 ~ perf_event_open && active {
178fea753f8SAdrian Hunter		match($0, perf_event_open)
179fea753f8SAdrian Hunter		$0 = substr($0, RSTART, RLENGTH)
180fea753f8SAdrian Hunter		pid = $3
181fea753f8SAdrian Hunter		cpu = $5
182fea753f8SAdrian Hunter		fd = $11
183fea753f8SAdrian Hunter		print "pid " pid " cpu " cpu " fd " fd " : " $0
184fea753f8SAdrian Hunter		fd_array[fd] = fd
185fea753f8SAdrian Hunter		pid_array[fd] = pid
186fea753f8SAdrian Hunter		cpu_array[fd] = cpu
187fea753f8SAdrian Hunter	}
188fea753f8SAdrian Hunter
189fea753f8SAdrian Hunter	$0 ~ mmapping && active  {
190fea753f8SAdrian Hunter		match($0, mmapping)
191fea753f8SAdrian Hunter		$0 = substr($0, RSTART, RLENGTH)
192fea753f8SAdrian Hunter		fd = $5
193fea753f8SAdrian Hunter		print "fd " fd " : " $0
194fea753f8SAdrian Hunter		if (fd in fd_array) {
195fea753f8SAdrian Hunter			mmap_array[fd] = 1
196fea753f8SAdrian Hunter		} else {
197fea753f8SAdrian Hunter			print "Unknown fd " fd
198fea753f8SAdrian Hunter			exit 1
199fea753f8SAdrian Hunter		}
200fea753f8SAdrian Hunter	}
201fea753f8SAdrian Hunter
202fea753f8SAdrian Hunter	$0 ~ set_output && active {
203fea753f8SAdrian Hunter		match($0, set_output)
204fea753f8SAdrian Hunter		$0 = substr($0, RSTART, RLENGTH)
205fea753f8SAdrian Hunter		fd = $6
206fea753f8SAdrian Hunter		fd_to = $8
207fea753f8SAdrian Hunter		print "fd " fd " fd_to " fd_to " : " $0
208fea753f8SAdrian Hunter		if (fd in fd_array) {
209fea753f8SAdrian Hunter			if (fd_to in fd_array) {
210fea753f8SAdrian Hunter				set_output_array[fd] = fd_to
211fea753f8SAdrian Hunter			} else {
212fea753f8SAdrian Hunter				print "Unknown fd " fd_to
213fea753f8SAdrian Hunter				exit 1
214fea753f8SAdrian Hunter			}
215fea753f8SAdrian Hunter		} else {
216fea753f8SAdrian Hunter			print "Unknown fd " fd
217fea753f8SAdrian Hunter			exit 1
218fea753f8SAdrian Hunter		}
219fea753f8SAdrian Hunter	}
220fea753f8SAdrian Hunter
221fea753f8SAdrian Hunter	END {
222fea753f8SAdrian Hunter		print "Checking " length(fd_array) " fds"
223fea753f8SAdrian Hunter		for (fd in fd_array) {
224fea753f8SAdrian Hunter			if (fd in mmap_array) {
225fea753f8SAdrian Hunter				pid = pid_array[fd]
226fea753f8SAdrian Hunter				if (pid != -1) {
227fea753f8SAdrian Hunter					if (pid in pids) {
228fea753f8SAdrian Hunter						print "More than 1 mmap for PID " pid
229fea753f8SAdrian Hunter						exit 1
230fea753f8SAdrian Hunter					}
231fea753f8SAdrian Hunter					pids[pid] = 1
232fea753f8SAdrian Hunter				}
233fea753f8SAdrian Hunter				cpu = cpu_array[fd]
234fea753f8SAdrian Hunter				if (cpu != -1) {
235fea753f8SAdrian Hunter					if (cpu in cpus) {
236fea753f8SAdrian Hunter						print "More than 1 mmap for CPU " cpu
237fea753f8SAdrian Hunter						exit 1
238fea753f8SAdrian Hunter					}
239fea753f8SAdrian Hunter					cpus[cpu] = 1
240fea753f8SAdrian Hunter				}
241fea753f8SAdrian Hunter			} else if (!(fd in set_output_array)) {
242fea753f8SAdrian Hunter				print "No mmap for fd " fd
243fea753f8SAdrian Hunter				exit 1
244fea753f8SAdrian Hunter			}
245fea753f8SAdrian Hunter		}
246fea753f8SAdrian Hunter		n = length(pids)
247fea753f8SAdrian Hunter		if (n != thread_cnt) {
248fea753f8SAdrian Hunter			print "Expected " thread_cnt " per-thread mmaps - found " n
249fea753f8SAdrian Hunter			exit 1
250fea753f8SAdrian Hunter		}
251fea753f8SAdrian Hunter	}
252fea753f8SAdrian Hunter	_end_of_file_
253fea753f8SAdrian Hunter
254fea753f8SAdrian Hunter	$workload &
255fea753f8SAdrian Hunter	w1=$!
256fea753f8SAdrian Hunter	$workload &
257fea753f8SAdrian Hunter	w2=$!
258fea753f8SAdrian Hunter	echo "Workload PIDs are $w1 and $w2"
259fea753f8SAdrian Hunter	wait_for_threads ${w1} 2
260fea753f8SAdrian Hunter	wait_for_threads ${w2} 2
261fea753f8SAdrian Hunter
2625021d82bSAdrian Hunter	perf_record_no_decode -o "${perfdatafile}" -e intel_pt//u"${k}" -vvv --per-thread -p "${w1},${w2}" 2>"${errfile}" >"${outfile}" &
263fea753f8SAdrian Hunter	ppid=$!
264fea753f8SAdrian Hunter	echo "perf PID is $ppid"
2655ebcdf07SAdrian Hunter	wait_for_perf_to_start ${ppid} "${errfile}" || return 1
266fea753f8SAdrian Hunter
267fea753f8SAdrian Hunter	kill ${w1}
268fea753f8SAdrian Hunter	wait_for_process_to_exit ${w1} || return 1
269fea753f8SAdrian Hunter	is_running ${ppid} || return 1
270fea753f8SAdrian Hunter
271fea753f8SAdrian Hunter	kill ${w2}
272fea753f8SAdrian Hunter	wait_for_process_to_exit ${w2} || return 1
273fea753f8SAdrian Hunter	wait_for_process_to_exit ${ppid} || return 1
274fea753f8SAdrian Hunter
275fea753f8SAdrian Hunter	awk -v thread_cnt=4 -f "${awkscript}" "${errfile}" || return 1
276fea753f8SAdrian Hunter
277fea753f8SAdrian Hunter	echo OK
278fea753f8SAdrian Hunter	return 0
279fea753f8SAdrian Hunter}
280fea753f8SAdrian Hunter
281973db240SAdrian Huntertest_jitdump()
282973db240SAdrian Hunter{
283973db240SAdrian Hunter	echo "--- Test tracing self-modifying code that uses jitdump ---"
284973db240SAdrian Hunter
285973db240SAdrian Hunter	script_path=$(realpath "$0")
286973db240SAdrian Hunter	script_dir=$(dirname "$script_path")
287973db240SAdrian Hunter	jitdump_incl_dir="${script_dir}/../../util"
288973db240SAdrian Hunter	jitdump_h="${jitdump_incl_dir}/jitdump.h"
289973db240SAdrian Hunter
290973db240SAdrian Hunter	if [ ! -e "${jitdump_h}" ] ; then
291973db240SAdrian Hunter		echo "SKIP: Include file jitdump.h not found"
292973db240SAdrian Hunter		return 2
293973db240SAdrian Hunter	fi
294973db240SAdrian Hunter
295973db240SAdrian Hunter	if [ -z "${have_jitdump_workload}" ] ; then
296973db240SAdrian Hunter		have_jitdump_workload=false
297973db240SAdrian Hunter		# Create a workload that uses self-modifying code and generates its own jitdump file
298973db240SAdrian Hunter		cat <<- "_end_of_file_" | /usr/bin/cc -o "${jitdump_workload}" -I "${jitdump_incl_dir}" -xc - -pthread && have_jitdump_workload=true
299973db240SAdrian Hunter		#define _GNU_SOURCE
300973db240SAdrian Hunter		#include <sys/mman.h>
301973db240SAdrian Hunter		#include <sys/types.h>
302973db240SAdrian Hunter		#include <stddef.h>
303973db240SAdrian Hunter		#include <stdio.h>
304973db240SAdrian Hunter		#include <stdint.h>
305973db240SAdrian Hunter		#include <unistd.h>
306973db240SAdrian Hunter		#include <string.h>
307973db240SAdrian Hunter
308973db240SAdrian Hunter		#include "jitdump.h"
309973db240SAdrian Hunter
310973db240SAdrian Hunter		#define CHK_BYTE 0x5a
311973db240SAdrian Hunter
312973db240SAdrian Hunter		static inline uint64_t rdtsc(void)
313973db240SAdrian Hunter		{
314973db240SAdrian Hunter			unsigned int low, high;
315973db240SAdrian Hunter
316973db240SAdrian Hunter			asm volatile("rdtsc" : "=a" (low), "=d" (high));
317973db240SAdrian Hunter
318973db240SAdrian Hunter			return low | ((uint64_t)high) << 32;
319973db240SAdrian Hunter		}
320973db240SAdrian Hunter
321973db240SAdrian Hunter		static FILE *open_jitdump(void)
322973db240SAdrian Hunter		{
323973db240SAdrian Hunter			struct jitheader header = {
324973db240SAdrian Hunter				.magic      = JITHEADER_MAGIC,
325973db240SAdrian Hunter				.version    = JITHEADER_VERSION,
326973db240SAdrian Hunter				.total_size = sizeof(header),
327973db240SAdrian Hunter				.pid        = getpid(),
328973db240SAdrian Hunter				.timestamp  = rdtsc(),
329973db240SAdrian Hunter				.flags      = JITDUMP_FLAGS_ARCH_TIMESTAMP,
330973db240SAdrian Hunter			};
331973db240SAdrian Hunter			char filename[256];
332973db240SAdrian Hunter			FILE *f;
333973db240SAdrian Hunter			void *m;
334973db240SAdrian Hunter
335973db240SAdrian Hunter			snprintf(filename, sizeof(filename), "jit-%d.dump", getpid());
336973db240SAdrian Hunter			f = fopen(filename, "w+");
337973db240SAdrian Hunter			if (!f)
338973db240SAdrian Hunter				goto err;
339973db240SAdrian Hunter			/* Create an MMAP event for the jitdump file. That is how perf tool finds it. */
340973db240SAdrian Hunter			m = mmap(0, 4096, PROT_READ | PROT_EXEC, MAP_PRIVATE, fileno(f), 0);
341973db240SAdrian Hunter			if (m == MAP_FAILED)
342973db240SAdrian Hunter				goto err_close;
343973db240SAdrian Hunter			munmap(m, 4096);
344973db240SAdrian Hunter			if (fwrite(&header,sizeof(header),1,f) != 1)
345973db240SAdrian Hunter				goto err_close;
346973db240SAdrian Hunter			return f;
347973db240SAdrian Hunter
348973db240SAdrian Hunter		err_close:
349973db240SAdrian Hunter			fclose(f);
350973db240SAdrian Hunter		err:
351973db240SAdrian Hunter			return NULL;
352973db240SAdrian Hunter		}
353973db240SAdrian Hunter
354973db240SAdrian Hunter		static int write_jitdump(FILE *f, void *addr, const uint8_t *dat, size_t sz, uint64_t *idx)
355973db240SAdrian Hunter		{
356973db240SAdrian Hunter			struct jr_code_load rec = {
357973db240SAdrian Hunter				.p.id          = JIT_CODE_LOAD,
358973db240SAdrian Hunter				.p.total_size  = sizeof(rec) + sz,
359973db240SAdrian Hunter				.p.timestamp   = rdtsc(),
360973db240SAdrian Hunter				.pid	       = getpid(),
361973db240SAdrian Hunter				.tid	       = gettid(),
362973db240SAdrian Hunter				.vma           = (unsigned long)addr,
363973db240SAdrian Hunter				.code_addr     = (unsigned long)addr,
364973db240SAdrian Hunter				.code_size     = sz,
365973db240SAdrian Hunter				.code_index    = ++*idx,
366973db240SAdrian Hunter			};
367973db240SAdrian Hunter
368973db240SAdrian Hunter			if (fwrite(&rec,sizeof(rec),1,f) != 1 ||
369973db240SAdrian Hunter			fwrite(dat, sz, 1, f) != 1)
370973db240SAdrian Hunter				return -1;
371973db240SAdrian Hunter			return 0;
372973db240SAdrian Hunter		}
373973db240SAdrian Hunter
374973db240SAdrian Hunter		static void close_jitdump(FILE *f)
375973db240SAdrian Hunter		{
376973db240SAdrian Hunter			fclose(f);
377973db240SAdrian Hunter		}
378973db240SAdrian Hunter
379973db240SAdrian Hunter		int main()
380973db240SAdrian Hunter		{
381973db240SAdrian Hunter			/* Get a memory page to store executable code */
382973db240SAdrian Hunter			void *addr = mmap(0, 4096, PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
383973db240SAdrian Hunter			/* Code to execute: mov CHK_BYTE, %eax ; ret */
384973db240SAdrian Hunter			uint8_t dat[] = {0xb8, CHK_BYTE, 0x00, 0x00, 0x00, 0xc3};
385973db240SAdrian Hunter			FILE *f = open_jitdump();
386973db240SAdrian Hunter			uint64_t idx = 0;
387973db240SAdrian Hunter			int ret = 1;
388973db240SAdrian Hunter
389973db240SAdrian Hunter			if (!f)
390973db240SAdrian Hunter				return 1;
391973db240SAdrian Hunter			/* Copy executable code to executable memory page */
392973db240SAdrian Hunter			memcpy(addr, dat, sizeof(dat));
393973db240SAdrian Hunter			/* Record it in the jitdump file */
394973db240SAdrian Hunter			if (write_jitdump(f, addr, dat, sizeof(dat), &idx))
395973db240SAdrian Hunter				goto out_close;
396973db240SAdrian Hunter			/* Call it */
397973db240SAdrian Hunter			ret = ((int (*)(void))addr)() - CHK_BYTE;
398973db240SAdrian Hunter		out_close:
399973db240SAdrian Hunter			close_jitdump(f);
400973db240SAdrian Hunter			return ret;
401973db240SAdrian Hunter		}
402973db240SAdrian Hunter		_end_of_file_
403973db240SAdrian Hunter	fi
404973db240SAdrian Hunter
405973db240SAdrian Hunter	if ! $have_jitdump_workload ; then
406973db240SAdrian Hunter		echo "SKIP: No jitdump workload"
407973db240SAdrian Hunter		return 2
408973db240SAdrian Hunter	fi
409973db240SAdrian Hunter
410973db240SAdrian Hunter	# Change to temp_dir so jitdump collateral files go there
411973db240SAdrian Hunter	cd "${temp_dir}"
412973db240SAdrian Hunter	perf_record_no_bpf -o "${tmpfile}" -e intel_pt//u "${jitdump_workload}"
413973db240SAdrian Hunter	perf inject -i "${tmpfile}" -o "${perfdatafile}" --jit
414973db240SAdrian Hunter	decode_br_cnt=$(perf script -i "${perfdatafile}" --itrace=b | wc -l)
415973db240SAdrian Hunter	# Note that overflow and lost errors are suppressed for the error count
416973db240SAdrian Hunter	decode_err_cnt=$(perf script -i "${perfdatafile}" --itrace=e-o-l | grep -ci error)
417973db240SAdrian Hunter	cd -
418973db240SAdrian Hunter	# Should be thousands of branches
419973db240SAdrian Hunter	if [ "${decode_br_cnt}" -lt 1000 ] ; then
420973db240SAdrian Hunter		echo "Decode failed, only ${decode_br_cnt} branches"
421973db240SAdrian Hunter		return 1
422973db240SAdrian Hunter	fi
423973db240SAdrian Hunter	# Should be no errors
424973db240SAdrian Hunter	if [ "${decode_err_cnt}" -ne 0 ] ; then
425973db240SAdrian Hunter		echo "Decode failed, ${decode_err_cnt} errors"
426f77811a0SAmmy Yi		perf script -i "${perfdatafile}" --itrace=e-o-l --show-mmap-events | cat
427973db240SAdrian Hunter		return 1
428973db240SAdrian Hunter	fi
429973db240SAdrian Hunter
430973db240SAdrian Hunter	echo OK
431973db240SAdrian Hunter	return 0
432973db240SAdrian Hunter}
433973db240SAdrian Hunter
434f77811a0SAmmy Yitest_packet_filter()
435f77811a0SAmmy Yi{
436f77811a0SAmmy Yi	echo "--- Test with MTC and TSC disabled ---"
437f77811a0SAmmy Yi	# Disable MTC and TSC
438f77811a0SAmmy Yi	perf_record_no_decode -o "${perfdatafile}" -e intel_pt/mtc=0,tsc=0/u uname
439f77811a0SAmmy Yi	# Should not get MTC packet
440f77811a0SAmmy Yi	mtc_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "MTC 0x")
441f77811a0SAmmy Yi	if [ "${mtc_cnt}" -ne 0 ] ; then
442f77811a0SAmmy Yi		echo "Failed to filter with mtc=0"
443f77811a0SAmmy Yi		return 1
444f77811a0SAmmy Yi	fi
445f77811a0SAmmy Yi	# Should not get TSC package
446f77811a0SAmmy Yi	tsc_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "TSC 0x")
447f77811a0SAmmy Yi	if [ "${tsc_cnt}" -ne 0 ] ; then
448f77811a0SAmmy Yi		echo "Failed to filter with tsc=0"
449f77811a0SAmmy Yi		return 1
450f77811a0SAmmy Yi	fi
451f77811a0SAmmy Yi	echo OK
452f77811a0SAmmy Yi	return 0
453f77811a0SAmmy Yi}
454f77811a0SAmmy Yi
455f77811a0SAmmy Yitest_disable_branch()
456f77811a0SAmmy Yi{
457f77811a0SAmmy Yi	echo "--- Test with branches disabled ---"
458f77811a0SAmmy Yi	# Disable branch
459f77811a0SAmmy Yi	perf_record_no_decode -o "${perfdatafile}" -e intel_pt/branch=0/u uname
460f77811a0SAmmy Yi	# Should not get branch related packets
461f77811a0SAmmy Yi	tnt_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "TNT 0x")
462f77811a0SAmmy Yi	tip_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "TIP 0x")
463f77811a0SAmmy Yi	fup_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "FUP 0x")
464f77811a0SAmmy Yi	if [ "${tnt_cnt}" -ne 0 ] || [ "${tip_cnt}" -ne 0 ] || [ "${fup_cnt}" -ne 0 ] ; then
465f77811a0SAmmy Yi		echo "Failed to disable branches"
466f77811a0SAmmy Yi		return 1
467f77811a0SAmmy Yi	fi
468f77811a0SAmmy Yi	echo OK
469f77811a0SAmmy Yi	return 0
470f77811a0SAmmy Yi}
471f77811a0SAmmy Yi
472f77811a0SAmmy Yitest_time_cyc()
473f77811a0SAmmy Yi{
474f77811a0SAmmy Yi	echo "--- Test with/without CYC ---"
475f77811a0SAmmy Yi	# Check if CYC is supported
476f77811a0SAmmy Yi	cyc=$(cat /sys/bus/event_source/devices/intel_pt/caps/psb_cyc)
477f77811a0SAmmy Yi	if [ "${cyc}" != "1" ] ; then
478f77811a0SAmmy Yi		echo "SKIP: CYC is not supported"
479f77811a0SAmmy Yi		return 2
480f77811a0SAmmy Yi	fi
481f77811a0SAmmy Yi	# Enable CYC
482f77811a0SAmmy Yi	perf_record_no_decode -o "${perfdatafile}" -e intel_pt/cyc/u uname
483f77811a0SAmmy Yi	# should get CYC packets
484f77811a0SAmmy Yi	cyc_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "CYC 0x")
485f77811a0SAmmy Yi	if [ "${cyc_cnt}" = "0" ] ; then
486f77811a0SAmmy Yi		echo "Failed to get CYC packet"
487f77811a0SAmmy Yi		return 1
488f77811a0SAmmy Yi	fi
489f77811a0SAmmy Yi	# Without CYC
490f77811a0SAmmy Yi	perf_record_no_decode -o "${perfdatafile}" -e intel_pt//u uname
491f77811a0SAmmy Yi	# Should not get CYC packets
492f77811a0SAmmy Yi	cyc_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "CYC 0x")
493f77811a0SAmmy Yi	if [ "${cyc_cnt}" -gt 0 ] ; then
494f77811a0SAmmy Yi		echo "Still get CYC packet without cyc"
495f77811a0SAmmy Yi		return 1
496f77811a0SAmmy Yi	fi
497f77811a0SAmmy Yi	echo OK
498f77811a0SAmmy Yi	return 0
499f77811a0SAmmy Yi}
500f77811a0SAmmy Yi
501f77811a0SAmmy Yitest_sample()
502f77811a0SAmmy Yi{
503f77811a0SAmmy Yi	echo "--- Test recording with sample mode ---"
504f77811a0SAmmy Yi	# Check if recording with sample mode is working
505f77811a0SAmmy Yi	if ! perf_record_no_decode -o "${perfdatafile}" --aux-sample=8192 -e '{intel_pt//u,branch-misses:u}' uname ; then
506f77811a0SAmmy Yi		echo "perf record failed with --aux-sample"
507f77811a0SAmmy Yi		return 1
508f77811a0SAmmy Yi	fi
509*a4680850SAdrian Hunter	# Check with event with PMU name
510*a4680850SAdrian Hunter	if perf_record_no_decode -o "${perfdatafile}" -e br_misp_retired.all_branches:u uname ; then
511*a4680850SAdrian Hunter		if ! perf_record_no_decode -o "${perfdatafile}" -e '{intel_pt//,br_misp_retired.all_branches/aux-sample-size=8192/}:u' uname ; then
512*a4680850SAdrian Hunter			echo "perf record failed with --aux-sample-size"
513*a4680850SAdrian Hunter			return 1
514*a4680850SAdrian Hunter		fi
515*a4680850SAdrian Hunter	fi
516f77811a0SAmmy Yi	echo OK
517f77811a0SAmmy Yi	return 0
518f77811a0SAmmy Yi}
519f77811a0SAmmy Yi
520f77811a0SAmmy Yitest_kernel_trace()
521f77811a0SAmmy Yi{
522f77811a0SAmmy Yi	echo "--- Test with kernel trace ---"
523f77811a0SAmmy Yi	# Check if recording with kernel trace is working
524f77811a0SAmmy Yi	can_kernel || return 2
525f77811a0SAmmy Yi	if ! perf_record_no_decode -o "${perfdatafile}" -e intel_pt//k -m1,128 uname ; then
526f77811a0SAmmy Yi		echo "perf record failed with intel_pt//k"
527f77811a0SAmmy Yi		return 1
528f77811a0SAmmy Yi	fi
529f77811a0SAmmy Yi	echo OK
530f77811a0SAmmy Yi	return 0
531f77811a0SAmmy Yi}
532f77811a0SAmmy Yi
533f77811a0SAmmy Yitest_virtual_lbr()
534f77811a0SAmmy Yi{
535f77811a0SAmmy Yi	echo "--- Test virtual LBR ---"
536246122a8SNamhyung Kim	# Check if python script is supported
537246122a8SNamhyung Kim	libpython=$(perf version --build-options | grep python | grep -cv OFF)
538246122a8SNamhyung Kim	if [ "${libpython}" != "1" ] ; then
539246122a8SNamhyung Kim		echo "SKIP: python scripting is not supported"
540246122a8SNamhyung Kim		return 2
541246122a8SNamhyung Kim	fi
542f77811a0SAmmy Yi
543f77811a0SAmmy Yi	# Python script to determine the maximum size of branch stacks
544f77811a0SAmmy Yi	cat << "_end_of_file_" > "${maxbrstack}"
545f77811a0SAmmy Yifrom __future__ import print_function
546f77811a0SAmmy Yi
547f77811a0SAmmy Yibmax = 0
548f77811a0SAmmy Yi
549f77811a0SAmmy Yidef process_event(param_dict):
550f77811a0SAmmy Yi	if "brstack" in param_dict:
551f77811a0SAmmy Yi		brstack = param_dict["brstack"]
552f77811a0SAmmy Yi		n = len(brstack)
553f77811a0SAmmy Yi		global bmax
554f77811a0SAmmy Yi		if n > bmax:
555f77811a0SAmmy Yi			bmax = n
556f77811a0SAmmy Yi
557f77811a0SAmmy Yidef trace_end():
558f77811a0SAmmy Yi	print("max brstack", bmax)
559f77811a0SAmmy Yi_end_of_file_
560f77811a0SAmmy Yi
561f77811a0SAmmy Yi	# Check if virtual lbr is working
562f77811a0SAmmy Yi	perf_record_no_bpf -o "${perfdatafile}" --aux-sample -e '{intel_pt//,cycles}:u' uname
563f77811a0SAmmy Yi	times_val=$(perf script -i "${perfdatafile}" --itrace=L -s "${maxbrstack}" 2>/dev/null | grep "max brstack " | cut -d " " -f 3)
564f77811a0SAmmy Yi	case "${times_val}" in
565f77811a0SAmmy Yi		[0-9]*)	;;
566f77811a0SAmmy Yi		*)	times_val=0;;
567f77811a0SAmmy Yi	esac
568f77811a0SAmmy Yi	if [ "${times_val}" -lt 2 ] ; then
569f77811a0SAmmy Yi		echo "Failed with virtual lbr"
570f77811a0SAmmy Yi		return 1
571f77811a0SAmmy Yi	fi
572f77811a0SAmmy Yi	echo OK
573f77811a0SAmmy Yi	return 0
574f77811a0SAmmy Yi}
575f77811a0SAmmy Yi
576f77811a0SAmmy Yitest_power_event()
577f77811a0SAmmy Yi{
578f77811a0SAmmy Yi	echo "--- Test power events ---"
579f77811a0SAmmy Yi	# Check if power events are supported
580f77811a0SAmmy Yi	power_event=$(cat /sys/bus/event_source/devices/intel_pt/caps/power_event_trace)
581f77811a0SAmmy Yi	if [ "${power_event}" != "1" ] ; then
582f77811a0SAmmy Yi		echo "SKIP: power_event_trace is not supported"
583f77811a0SAmmy Yi		return 2
584f77811a0SAmmy Yi	fi
585f77811a0SAmmy Yi	if ! perf_record_no_decode -o "${perfdatafile}" -a -e intel_pt/pwr_evt/u uname ; then
586f77811a0SAmmy Yi		echo "perf record failed with pwr_evt"
587f77811a0SAmmy Yi		return 1
588f77811a0SAmmy Yi	fi
589f77811a0SAmmy Yi	echo OK
590f77811a0SAmmy Yi	return 0
591f77811a0SAmmy Yi}
592f77811a0SAmmy Yi
593f77811a0SAmmy Yitest_no_tnt()
594f77811a0SAmmy Yi{
595f77811a0SAmmy Yi	echo "--- Test with TNT packets disabled  ---"
596f77811a0SAmmy Yi	# Check if TNT disable is supported
597f77811a0SAmmy Yi	notnt=$(cat /sys/bus/event_source/devices/intel_pt/caps/tnt_disable)
598f77811a0SAmmy Yi	if [ "${notnt}" != "1" ] ; then
599f77811a0SAmmy Yi		echo "SKIP: tnt_disable is not supported"
600f77811a0SAmmy Yi		return 2
601f77811a0SAmmy Yi	fi
602f77811a0SAmmy Yi	perf_record_no_decode -o "${perfdatafile}" -e intel_pt/notnt/u uname
603f77811a0SAmmy Yi	# Should be no TNT packets
604f77811a0SAmmy Yi	tnt_cnt=$(perf script -i "${perfdatafile}" -D | grep -c TNT)
605f77811a0SAmmy Yi	if [ "${tnt_cnt}" -ne 0 ] ; then
606f77811a0SAmmy Yi		echo "TNT packets still there after notnt"
607f77811a0SAmmy Yi		return 1
608f77811a0SAmmy Yi	fi
609f77811a0SAmmy Yi	echo OK
610f77811a0SAmmy Yi	return 0
611f77811a0SAmmy Yi}
612f77811a0SAmmy Yi
613f77811a0SAmmy Yitest_event_trace()
614f77811a0SAmmy Yi{
615f77811a0SAmmy Yi	echo "--- Test with event_trace ---"
616f77811a0SAmmy Yi	# Check if event_trace is supported
617f77811a0SAmmy Yi	event_trace=$(cat /sys/bus/event_source/devices/intel_pt/caps/event_trace)
618f77811a0SAmmy Yi	if [ "${event_trace}" != 1 ] ; then
619f77811a0SAmmy Yi		echo "SKIP: event_trace is not supported"
620f77811a0SAmmy Yi		return 2
621f77811a0SAmmy Yi	fi
622f77811a0SAmmy Yi	if ! perf_record_no_decode -o "${perfdatafile}" -e intel_pt/event/u uname ; then
623f77811a0SAmmy Yi		echo "perf record failed with event trace"
624f77811a0SAmmy Yi		return 1
625f77811a0SAmmy Yi	fi
626f77811a0SAmmy Yi	echo OK
627f77811a0SAmmy Yi	return 0
628f77811a0SAmmy Yi}
629f77811a0SAmmy Yi
630e072b097SNamhyung Kimtest_pipe()
631e072b097SNamhyung Kim{
632e072b097SNamhyung Kim	echo "--- Test with pipe mode ---"
633e072b097SNamhyung Kim	# Check if it works with pipe
634e072b097SNamhyung Kim	if ! perf_record_no_bpf -o- -e intel_pt//u uname | perf report -q -i- --itrace=i10000 ; then
635e072b097SNamhyung Kim		echo "perf record + report failed with pipe mode"
636e072b097SNamhyung Kim		return 1
637e072b097SNamhyung Kim	fi
638e072b097SNamhyung Kim	if ! perf_record_no_bpf -o- -e intel_pt//u uname | perf inject -b > /dev/null ; then
639e072b097SNamhyung Kim		echo "perf record + inject failed with pipe mode"
640e072b097SNamhyung Kim		return 1
641e072b097SNamhyung Kim	fi
642e072b097SNamhyung Kim	echo OK
643e072b097SNamhyung Kim	return 0
644e072b097SNamhyung Kim}
645e072b097SNamhyung Kim
6461097b38fSAdrian Huntercount_result()
6471097b38fSAdrian Hunter{
6485d7aac2bSAdrian Hunter	if [ "$1" -eq 2 ] ; then
649202d0394SAdrian Hunter		skip_cnt=$((skip_cnt + 1))
6501097b38fSAdrian Hunter		return
6511097b38fSAdrian Hunter	fi
6525d7aac2bSAdrian Hunter	if [ "$1" -eq 0 ] ; then
653202d0394SAdrian Hunter		ok_cnt=$((ok_cnt + 1))
6541097b38fSAdrian Hunter		return
6551097b38fSAdrian Hunter	fi
656202d0394SAdrian Hunter	err_cnt=$((err_cnt + 1))
6571097b38fSAdrian Hunter}
6581097b38fSAdrian Hunter
659fd9b45e3SAdrian Hunterret=0
660e4080492SAdrian Huntertest_system_wide_side_band		|| ret=$? ; count_result $ret ; ret=0
661e4080492SAdrian Huntertest_per_thread "" ""			|| ret=$? ; count_result $ret ; ret=0
662e4080492SAdrian Huntertest_per_thread "k" "(incl. kernel) "	|| ret=$? ; count_result $ret ; ret=0
663973db240SAdrian Huntertest_jitdump				|| ret=$? ; count_result $ret ; ret=0
664f77811a0SAmmy Yitest_packet_filter			|| ret=$? ; count_result $ret ; ret=0
665f77811a0SAmmy Yitest_disable_branch			|| ret=$? ; count_result $ret ; ret=0
666f77811a0SAmmy Yitest_time_cyc				|| ret=$? ; count_result $ret ; ret=0
667f77811a0SAmmy Yitest_sample				|| ret=$? ; count_result $ret ; ret=0
668f77811a0SAmmy Yitest_kernel_trace			|| ret=$? ; count_result $ret ; ret=0
669f77811a0SAmmy Yitest_virtual_lbr			|| ret=$? ; count_result $ret ; ret=0
670f77811a0SAmmy Yitest_power_event			|| ret=$? ; count_result $ret ; ret=0
671f77811a0SAmmy Yitest_no_tnt				|| ret=$? ; count_result $ret ; ret=0
672f77811a0SAmmy Yitest_event_trace			|| ret=$? ; count_result $ret ; ret=0
673e072b097SNamhyung Kimtest_pipe				|| ret=$? ; count_result $ret ; ret=0
6741097b38fSAdrian Hunter
67519af23dfSAdrian Huntercleanup
6761097b38fSAdrian Hunter
6772c1c9e35SAdrian Hunterecho "--- Done ---"
6782c1c9e35SAdrian Hunter
6791097b38fSAdrian Hunterif [ ${err_cnt} -gt 0 ] ; then
6801097b38fSAdrian Hunter	exit 1
6811097b38fSAdrian Hunterfi
6821097b38fSAdrian Hunter
6831097b38fSAdrian Hunterif [ ${ok_cnt} -gt 0 ] ; then
6841097b38fSAdrian Hunter	exit 0
6851097b38fSAdrian Hunterfi
6861097b38fSAdrian Hunter
6871097b38fSAdrian Hunterexit 2
688