162306a36Sopenharmony_ci#!/bin/sh
262306a36Sopenharmony_ci# Miscellaneous Intel PT testing
362306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
462306a36Sopenharmony_ci
562306a36Sopenharmony_ciset -e
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci# Skip if no Intel PT
862306a36Sopenharmony_ciperf list | grep -q 'intel_pt//' || exit 2
962306a36Sopenharmony_ci
1062306a36Sopenharmony_cishelldir=$(dirname "$0")
1162306a36Sopenharmony_ci. "${shelldir}"/lib/waiting.sh
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ciskip_cnt=0
1462306a36Sopenharmony_ciok_cnt=0
1562306a36Sopenharmony_cierr_cnt=0
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_citemp_dir=$(mktemp -d /tmp/perf-test-intel-pt-sh.XXXXXXXXXX)
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_citmpfile="${temp_dir}/tmp-perf.data"
2062306a36Sopenharmony_ciperfdatafile="${temp_dir}/test-perf.data"
2162306a36Sopenharmony_cioutfile="${temp_dir}/test-out.txt"
2262306a36Sopenharmony_cierrfile="${temp_dir}/test-err.txt"
2362306a36Sopenharmony_ciworkload="${temp_dir}/workload"
2462306a36Sopenharmony_ciawkscript="${temp_dir}/awkscript"
2562306a36Sopenharmony_cijitdump_workload="${temp_dir}/jitdump_workload"
2662306a36Sopenharmony_cimaxbrstack="${temp_dir}/maxbrstack.py"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cicleanup()
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	trap - EXIT TERM INT
3162306a36Sopenharmony_ci	sane=$(echo "${temp_dir}" | cut -b 1-26)
3262306a36Sopenharmony_ci	if [ "${sane}" = "/tmp/perf-test-intel-pt-sh" ] ; then
3362306a36Sopenharmony_ci		echo "--- Cleaning up ---"
3462306a36Sopenharmony_ci		rm -f "${temp_dir}/"*
3562306a36Sopenharmony_ci		rmdir "${temp_dir}"
3662306a36Sopenharmony_ci	fi
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_citrap_cleanup()
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	cleanup
4262306a36Sopenharmony_ci	exit 1
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_citrap trap_cleanup EXIT TERM INT
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci# perf record for testing without decoding
4862306a36Sopenharmony_ciperf_record_no_decode()
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	# Options to speed up recording: no post-processing, no build-id cache update,
5162306a36Sopenharmony_ci	# and no BPF events.
5262306a36Sopenharmony_ci	perf record -B -N --no-bpf-event "$@"
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci# perf record for testing should not need BPF events
5662306a36Sopenharmony_ciperf_record_no_bpf()
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	# Options for no BPF events
5962306a36Sopenharmony_ci	perf record --no-bpf-event "$@"
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cihave_workload=false
6362306a36Sopenharmony_cicat << _end_of_file_ | /usr/bin/cc -o "${workload}" -xc - -pthread && have_workload=true
6462306a36Sopenharmony_ci#include <time.h>
6562306a36Sopenharmony_ci#include <pthread.h>
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_civoid work(void) {
6862306a36Sopenharmony_ci	struct timespec tm = {
6962306a36Sopenharmony_ci		.tv_nsec = 1000000,
7062306a36Sopenharmony_ci	};
7162306a36Sopenharmony_ci	int i;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	/* Run for about 30 seconds */
7462306a36Sopenharmony_ci	for (i = 0; i < 30000; i++)
7562306a36Sopenharmony_ci		nanosleep(&tm, NULL);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_civoid *threadfunc(void *arg) {
7962306a36Sopenharmony_ci	work();
8062306a36Sopenharmony_ci	return NULL;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ciint main(void) {
8462306a36Sopenharmony_ci	pthread_t th;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	pthread_create(&th, NULL, threadfunc, NULL);
8762306a36Sopenharmony_ci	work();
8862306a36Sopenharmony_ci	pthread_join(th, NULL);
8962306a36Sopenharmony_ci	return 0;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci_end_of_file_
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cican_cpu_wide()
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	echo "Checking for CPU-wide recording on CPU $1"
9662306a36Sopenharmony_ci	if ! perf_record_no_decode -o "${tmpfile}" -e dummy:u -C "$1" true >/dev/null 2>&1 ; then
9762306a36Sopenharmony_ci		echo "No so skipping"
9862306a36Sopenharmony_ci		return 2
9962306a36Sopenharmony_ci	fi
10062306a36Sopenharmony_ci	echo OK
10162306a36Sopenharmony_ci	return 0
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_citest_system_wide_side_band()
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	echo "--- Test system-wide sideband ---"
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	# Need CPU 0 and CPU 1
10962306a36Sopenharmony_ci	can_cpu_wide 0 || return $?
11062306a36Sopenharmony_ci	can_cpu_wide 1 || return $?
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	# Record on CPU 0 a task running on CPU 1
11362306a36Sopenharmony_ci	perf_record_no_decode -o "${perfdatafile}" -e intel_pt//u -C 0 -- taskset --cpu-list 1 uname
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	# Should get MMAP events from CPU 1 because they can be needed to decode
11662306a36Sopenharmony_ci	mmap_cnt=$(perf script -i "${perfdatafile}" --no-itrace --show-mmap-events -C 1 2>/dev/null | grep -c MMAP)
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	if [ "${mmap_cnt}" -gt 0 ] ; then
11962306a36Sopenharmony_ci		echo OK
12062306a36Sopenharmony_ci		return 0
12162306a36Sopenharmony_ci	fi
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	echo "Failed to record MMAP events on CPU 1 when tracing CPU 0"
12462306a36Sopenharmony_ci	return 1
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cican_kernel()
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	if [ -z "${can_kernel_trace}" ] ; then
13062306a36Sopenharmony_ci		can_kernel_trace=0
13162306a36Sopenharmony_ci		perf_record_no_decode -o "${tmpfile}" -e dummy:k true >/dev/null 2>&1 && can_kernel_trace=1
13262306a36Sopenharmony_ci	fi
13362306a36Sopenharmony_ci	if [ ${can_kernel_trace} -eq 0 ] ; then
13462306a36Sopenharmony_ci		echo "SKIP: no kernel tracing"
13562306a36Sopenharmony_ci		return 2
13662306a36Sopenharmony_ci	fi
13762306a36Sopenharmony_ci	return 0
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_citest_per_thread()
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	k="$1"
14362306a36Sopenharmony_ci	desc="$2"
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	echo "--- Test per-thread ${desc}recording ---"
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if ! $have_workload ; then
14862306a36Sopenharmony_ci		echo "No workload, so skipping"
14962306a36Sopenharmony_ci		return 2
15062306a36Sopenharmony_ci	fi
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	if [ "${k}" = "k" ] ; then
15362306a36Sopenharmony_ci		can_kernel || return 2
15462306a36Sopenharmony_ci	fi
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	cat <<- "_end_of_file_" > "${awkscript}"
15762306a36Sopenharmony_ci	BEGIN {
15862306a36Sopenharmony_ci		s = "[ ]*"
15962306a36Sopenharmony_ci		u = s"[0-9]+"s
16062306a36Sopenharmony_ci		d = s"[0-9-]+"s
16162306a36Sopenharmony_ci		x = s"[0-9a-fA-FxX]+"s
16262306a36Sopenharmony_ci		mmapping = "idx"u": mmapping fd"u
16362306a36Sopenharmony_ci		set_output = "idx"u": set output fd"u"->"u
16462306a36Sopenharmony_ci		perf_event_open = "sys_perf_event_open: pid"d"cpu"d"group_fd"d"flags"x"="u
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/perf record opening and mmapping events/ {
16862306a36Sopenharmony_ci		if (!done)
16962306a36Sopenharmony_ci			active = 1
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/perf record done opening and mmapping events/ {
17362306a36Sopenharmony_ci		active = 0
17462306a36Sopenharmony_ci		done = 1
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	$0 ~ perf_event_open && active {
17862306a36Sopenharmony_ci		match($0, perf_event_open)
17962306a36Sopenharmony_ci		$0 = substr($0, RSTART, RLENGTH)
18062306a36Sopenharmony_ci		pid = $3
18162306a36Sopenharmony_ci		cpu = $5
18262306a36Sopenharmony_ci		fd = $11
18362306a36Sopenharmony_ci		print "pid " pid " cpu " cpu " fd " fd " : " $0
18462306a36Sopenharmony_ci		fd_array[fd] = fd
18562306a36Sopenharmony_ci		pid_array[fd] = pid
18662306a36Sopenharmony_ci		cpu_array[fd] = cpu
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	$0 ~ mmapping && active  {
19062306a36Sopenharmony_ci		match($0, mmapping)
19162306a36Sopenharmony_ci		$0 = substr($0, RSTART, RLENGTH)
19262306a36Sopenharmony_ci		fd = $5
19362306a36Sopenharmony_ci		print "fd " fd " : " $0
19462306a36Sopenharmony_ci		if (fd in fd_array) {
19562306a36Sopenharmony_ci			mmap_array[fd] = 1
19662306a36Sopenharmony_ci		} else {
19762306a36Sopenharmony_ci			print "Unknown fd " fd
19862306a36Sopenharmony_ci			exit 1
19962306a36Sopenharmony_ci		}
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	$0 ~ set_output && active {
20362306a36Sopenharmony_ci		match($0, set_output)
20462306a36Sopenharmony_ci		$0 = substr($0, RSTART, RLENGTH)
20562306a36Sopenharmony_ci		fd = $6
20662306a36Sopenharmony_ci		fd_to = $8
20762306a36Sopenharmony_ci		print "fd " fd " fd_to " fd_to " : " $0
20862306a36Sopenharmony_ci		if (fd in fd_array) {
20962306a36Sopenharmony_ci			if (fd_to in fd_array) {
21062306a36Sopenharmony_ci				set_output_array[fd] = fd_to
21162306a36Sopenharmony_ci			} else {
21262306a36Sopenharmony_ci				print "Unknown fd " fd_to
21362306a36Sopenharmony_ci				exit 1
21462306a36Sopenharmony_ci			}
21562306a36Sopenharmony_ci		} else {
21662306a36Sopenharmony_ci			print "Unknown fd " fd
21762306a36Sopenharmony_ci			exit 1
21862306a36Sopenharmony_ci		}
21962306a36Sopenharmony_ci	}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	END {
22262306a36Sopenharmony_ci		print "Checking " length(fd_array) " fds"
22362306a36Sopenharmony_ci		for (fd in fd_array) {
22462306a36Sopenharmony_ci			if (fd in mmap_array) {
22562306a36Sopenharmony_ci				pid = pid_array[fd]
22662306a36Sopenharmony_ci				if (pid != -1) {
22762306a36Sopenharmony_ci					if (pid in pids) {
22862306a36Sopenharmony_ci						print "More than 1 mmap for PID " pid
22962306a36Sopenharmony_ci						exit 1
23062306a36Sopenharmony_ci					}
23162306a36Sopenharmony_ci					pids[pid] = 1
23262306a36Sopenharmony_ci				}
23362306a36Sopenharmony_ci				cpu = cpu_array[fd]
23462306a36Sopenharmony_ci				if (cpu != -1) {
23562306a36Sopenharmony_ci					if (cpu in cpus) {
23662306a36Sopenharmony_ci						print "More than 1 mmap for CPU " cpu
23762306a36Sopenharmony_ci						exit 1
23862306a36Sopenharmony_ci					}
23962306a36Sopenharmony_ci					cpus[cpu] = 1
24062306a36Sopenharmony_ci				}
24162306a36Sopenharmony_ci			} else if (!(fd in set_output_array)) {
24262306a36Sopenharmony_ci				print "No mmap for fd " fd
24362306a36Sopenharmony_ci				exit 1
24462306a36Sopenharmony_ci			}
24562306a36Sopenharmony_ci		}
24662306a36Sopenharmony_ci		n = length(pids)
24762306a36Sopenharmony_ci		if (n != thread_cnt) {
24862306a36Sopenharmony_ci			print "Expected " thread_cnt " per-thread mmaps - found " n
24962306a36Sopenharmony_ci			exit 1
25062306a36Sopenharmony_ci		}
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci	_end_of_file_
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	$workload &
25562306a36Sopenharmony_ci	w1=$!
25662306a36Sopenharmony_ci	$workload &
25762306a36Sopenharmony_ci	w2=$!
25862306a36Sopenharmony_ci	echo "Workload PIDs are $w1 and $w2"
25962306a36Sopenharmony_ci	wait_for_threads ${w1} 2
26062306a36Sopenharmony_ci	wait_for_threads ${w2} 2
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	perf_record_no_decode -o "${perfdatafile}" -e intel_pt//u"${k}" -vvv --per-thread -p "${w1},${w2}" 2>"${errfile}" >"${outfile}" &
26362306a36Sopenharmony_ci	ppid=$!
26462306a36Sopenharmony_ci	echo "perf PID is $ppid"
26562306a36Sopenharmony_ci	wait_for_perf_to_start ${ppid} "${errfile}" || return 1
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	kill ${w1}
26862306a36Sopenharmony_ci	wait_for_process_to_exit ${w1} || return 1
26962306a36Sopenharmony_ci	is_running ${ppid} || return 1
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	kill ${w2}
27262306a36Sopenharmony_ci	wait_for_process_to_exit ${w2} || return 1
27362306a36Sopenharmony_ci	wait_for_process_to_exit ${ppid} || return 1
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	awk -v thread_cnt=4 -f "${awkscript}" "${errfile}" || return 1
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	echo OK
27862306a36Sopenharmony_ci	return 0
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_citest_jitdump()
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	echo "--- Test tracing self-modifying code that uses jitdump ---"
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	script_path=$(realpath "$0")
28662306a36Sopenharmony_ci	script_dir=$(dirname "$script_path")
28762306a36Sopenharmony_ci	jitdump_incl_dir="${script_dir}/../../util"
28862306a36Sopenharmony_ci	jitdump_h="${jitdump_incl_dir}/jitdump.h"
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if [ ! -e "${jitdump_h}" ] ; then
29162306a36Sopenharmony_ci		echo "SKIP: Include file jitdump.h not found"
29262306a36Sopenharmony_ci		return 2
29362306a36Sopenharmony_ci	fi
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if [ -z "${have_jitdump_workload}" ] ; then
29662306a36Sopenharmony_ci		have_jitdump_workload=false
29762306a36Sopenharmony_ci		# Create a workload that uses self-modifying code and generates its own jitdump file
29862306a36Sopenharmony_ci		cat <<- "_end_of_file_" | /usr/bin/cc -o "${jitdump_workload}" -I "${jitdump_incl_dir}" -xc - -pthread && have_jitdump_workload=true
29962306a36Sopenharmony_ci		#define _GNU_SOURCE
30062306a36Sopenharmony_ci		#include <sys/mman.h>
30162306a36Sopenharmony_ci		#include <sys/types.h>
30262306a36Sopenharmony_ci		#include <stddef.h>
30362306a36Sopenharmony_ci		#include <stdio.h>
30462306a36Sopenharmony_ci		#include <stdint.h>
30562306a36Sopenharmony_ci		#include <unistd.h>
30662306a36Sopenharmony_ci		#include <string.h>
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci		#include "jitdump.h"
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci		#define CHK_BYTE 0x5a
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci		static inline uint64_t rdtsc(void)
31362306a36Sopenharmony_ci		{
31462306a36Sopenharmony_ci			unsigned int low, high;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci			asm volatile("rdtsc" : "=a" (low), "=d" (high));
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci			return low | ((uint64_t)high) << 32;
31962306a36Sopenharmony_ci		}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci		static FILE *open_jitdump(void)
32262306a36Sopenharmony_ci		{
32362306a36Sopenharmony_ci			struct jitheader header = {
32462306a36Sopenharmony_ci				.magic      = JITHEADER_MAGIC,
32562306a36Sopenharmony_ci				.version    = JITHEADER_VERSION,
32662306a36Sopenharmony_ci				.total_size = sizeof(header),
32762306a36Sopenharmony_ci				.pid        = getpid(),
32862306a36Sopenharmony_ci				.timestamp  = rdtsc(),
32962306a36Sopenharmony_ci				.flags      = JITDUMP_FLAGS_ARCH_TIMESTAMP,
33062306a36Sopenharmony_ci			};
33162306a36Sopenharmony_ci			char filename[256];
33262306a36Sopenharmony_ci			FILE *f;
33362306a36Sopenharmony_ci			void *m;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci			snprintf(filename, sizeof(filename), "jit-%d.dump", getpid());
33662306a36Sopenharmony_ci			f = fopen(filename, "w+");
33762306a36Sopenharmony_ci			if (!f)
33862306a36Sopenharmony_ci				goto err;
33962306a36Sopenharmony_ci			/* Create an MMAP event for the jitdump file. That is how perf tool finds it. */
34062306a36Sopenharmony_ci			m = mmap(0, 4096, PROT_READ | PROT_EXEC, MAP_PRIVATE, fileno(f), 0);
34162306a36Sopenharmony_ci			if (m == MAP_FAILED)
34262306a36Sopenharmony_ci				goto err_close;
34362306a36Sopenharmony_ci			munmap(m, 4096);
34462306a36Sopenharmony_ci			if (fwrite(&header,sizeof(header),1,f) != 1)
34562306a36Sopenharmony_ci				goto err_close;
34662306a36Sopenharmony_ci			return f;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		err_close:
34962306a36Sopenharmony_ci			fclose(f);
35062306a36Sopenharmony_ci		err:
35162306a36Sopenharmony_ci			return NULL;
35262306a36Sopenharmony_ci		}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci		static int write_jitdump(FILE *f, void *addr, const uint8_t *dat, size_t sz, uint64_t *idx)
35562306a36Sopenharmony_ci		{
35662306a36Sopenharmony_ci			struct jr_code_load rec = {
35762306a36Sopenharmony_ci				.p.id          = JIT_CODE_LOAD,
35862306a36Sopenharmony_ci				.p.total_size  = sizeof(rec) + sz,
35962306a36Sopenharmony_ci				.p.timestamp   = rdtsc(),
36062306a36Sopenharmony_ci				.pid	       = getpid(),
36162306a36Sopenharmony_ci				.tid	       = gettid(),
36262306a36Sopenharmony_ci				.vma           = (unsigned long)addr,
36362306a36Sopenharmony_ci				.code_addr     = (unsigned long)addr,
36462306a36Sopenharmony_ci				.code_size     = sz,
36562306a36Sopenharmony_ci				.code_index    = ++*idx,
36662306a36Sopenharmony_ci			};
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci			if (fwrite(&rec,sizeof(rec),1,f) != 1 ||
36962306a36Sopenharmony_ci			fwrite(dat, sz, 1, f) != 1)
37062306a36Sopenharmony_ci				return -1;
37162306a36Sopenharmony_ci			return 0;
37262306a36Sopenharmony_ci		}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci		static void close_jitdump(FILE *f)
37562306a36Sopenharmony_ci		{
37662306a36Sopenharmony_ci			fclose(f);
37762306a36Sopenharmony_ci		}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		int main()
38062306a36Sopenharmony_ci		{
38162306a36Sopenharmony_ci			/* Get a memory page to store executable code */
38262306a36Sopenharmony_ci			void *addr = mmap(0, 4096, PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
38362306a36Sopenharmony_ci			/* Code to execute: mov CHK_BYTE, %eax ; ret */
38462306a36Sopenharmony_ci			uint8_t dat[] = {0xb8, CHK_BYTE, 0x00, 0x00, 0x00, 0xc3};
38562306a36Sopenharmony_ci			FILE *f = open_jitdump();
38662306a36Sopenharmony_ci			uint64_t idx = 0;
38762306a36Sopenharmony_ci			int ret = 1;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci			if (!f)
39062306a36Sopenharmony_ci				return 1;
39162306a36Sopenharmony_ci			/* Copy executable code to executable memory page */
39262306a36Sopenharmony_ci			memcpy(addr, dat, sizeof(dat));
39362306a36Sopenharmony_ci			/* Record it in the jitdump file */
39462306a36Sopenharmony_ci			if (write_jitdump(f, addr, dat, sizeof(dat), &idx))
39562306a36Sopenharmony_ci				goto out_close;
39662306a36Sopenharmony_ci			/* Call it */
39762306a36Sopenharmony_ci			ret = ((int (*)(void))addr)() - CHK_BYTE;
39862306a36Sopenharmony_ci		out_close:
39962306a36Sopenharmony_ci			close_jitdump(f);
40062306a36Sopenharmony_ci			return ret;
40162306a36Sopenharmony_ci		}
40262306a36Sopenharmony_ci		_end_of_file_
40362306a36Sopenharmony_ci	fi
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if ! $have_jitdump_workload ; then
40662306a36Sopenharmony_ci		echo "SKIP: No jitdump workload"
40762306a36Sopenharmony_ci		return 2
40862306a36Sopenharmony_ci	fi
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	# Change to temp_dir so jitdump collateral files go there
41162306a36Sopenharmony_ci	cd "${temp_dir}"
41262306a36Sopenharmony_ci	perf_record_no_bpf -o "${tmpfile}" -e intel_pt//u "${jitdump_workload}"
41362306a36Sopenharmony_ci	perf inject -i "${tmpfile}" -o "${perfdatafile}" --jit
41462306a36Sopenharmony_ci	decode_br_cnt=$(perf script -i "${perfdatafile}" --itrace=b | wc -l)
41562306a36Sopenharmony_ci	# Note that overflow and lost errors are suppressed for the error count
41662306a36Sopenharmony_ci	decode_err_cnt=$(perf script -i "${perfdatafile}" --itrace=e-o-l | grep -ci error)
41762306a36Sopenharmony_ci	cd -
41862306a36Sopenharmony_ci	# Should be thousands of branches
41962306a36Sopenharmony_ci	if [ "${decode_br_cnt}" -lt 1000 ] ; then
42062306a36Sopenharmony_ci		echo "Decode failed, only ${decode_br_cnt} branches"
42162306a36Sopenharmony_ci		return 1
42262306a36Sopenharmony_ci	fi
42362306a36Sopenharmony_ci	# Should be no errors
42462306a36Sopenharmony_ci	if [ "${decode_err_cnt}" -ne 0 ] ; then
42562306a36Sopenharmony_ci		echo "Decode failed, ${decode_err_cnt} errors"
42662306a36Sopenharmony_ci		perf script -i "${perfdatafile}" --itrace=e-o-l --show-mmap-events | cat
42762306a36Sopenharmony_ci		return 1
42862306a36Sopenharmony_ci	fi
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	echo OK
43162306a36Sopenharmony_ci	return 0
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_citest_packet_filter()
43562306a36Sopenharmony_ci{
43662306a36Sopenharmony_ci	echo "--- Test with MTC and TSC disabled ---"
43762306a36Sopenharmony_ci	# Disable MTC and TSC
43862306a36Sopenharmony_ci	perf_record_no_decode -o "${perfdatafile}" -e intel_pt/mtc=0,tsc=0/u uname
43962306a36Sopenharmony_ci	# Should not get MTC packet
44062306a36Sopenharmony_ci	mtc_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "MTC 0x")
44162306a36Sopenharmony_ci	if [ "${mtc_cnt}" -ne 0 ] ; then
44262306a36Sopenharmony_ci		echo "Failed to filter with mtc=0"
44362306a36Sopenharmony_ci		return 1
44462306a36Sopenharmony_ci	fi
44562306a36Sopenharmony_ci	# Should not get TSC package
44662306a36Sopenharmony_ci	tsc_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "TSC 0x")
44762306a36Sopenharmony_ci	if [ "${tsc_cnt}" -ne 0 ] ; then
44862306a36Sopenharmony_ci		echo "Failed to filter with tsc=0"
44962306a36Sopenharmony_ci		return 1
45062306a36Sopenharmony_ci	fi
45162306a36Sopenharmony_ci	echo OK
45262306a36Sopenharmony_ci	return 0
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_citest_disable_branch()
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	echo "--- Test with branches disabled ---"
45862306a36Sopenharmony_ci	# Disable branch
45962306a36Sopenharmony_ci	perf_record_no_decode -o "${perfdatafile}" -e intel_pt/branch=0/u uname
46062306a36Sopenharmony_ci	# Should not get branch related packets
46162306a36Sopenharmony_ci	tnt_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "TNT 0x")
46262306a36Sopenharmony_ci	tip_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "TIP 0x")
46362306a36Sopenharmony_ci	fup_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "FUP 0x")
46462306a36Sopenharmony_ci	if [ "${tnt_cnt}" -ne 0 ] || [ "${tip_cnt}" -ne 0 ] || [ "${fup_cnt}" -ne 0 ] ; then
46562306a36Sopenharmony_ci		echo "Failed to disable branches"
46662306a36Sopenharmony_ci		return 1
46762306a36Sopenharmony_ci	fi
46862306a36Sopenharmony_ci	echo OK
46962306a36Sopenharmony_ci	return 0
47062306a36Sopenharmony_ci}
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_citest_time_cyc()
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	echo "--- Test with/without CYC ---"
47562306a36Sopenharmony_ci	# Check if CYC is supported
47662306a36Sopenharmony_ci	cyc=$(cat /sys/bus/event_source/devices/intel_pt/caps/psb_cyc)
47762306a36Sopenharmony_ci	if [ "${cyc}" != "1" ] ; then
47862306a36Sopenharmony_ci		echo "SKIP: CYC is not supported"
47962306a36Sopenharmony_ci		return 2
48062306a36Sopenharmony_ci	fi
48162306a36Sopenharmony_ci	# Enable CYC
48262306a36Sopenharmony_ci	perf_record_no_decode -o "${perfdatafile}" -e intel_pt/cyc/u uname
48362306a36Sopenharmony_ci	# should get CYC packets
48462306a36Sopenharmony_ci	cyc_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "CYC 0x")
48562306a36Sopenharmony_ci	if [ "${cyc_cnt}" = "0" ] ; then
48662306a36Sopenharmony_ci		echo "Failed to get CYC packet"
48762306a36Sopenharmony_ci		return 1
48862306a36Sopenharmony_ci	fi
48962306a36Sopenharmony_ci	# Without CYC
49062306a36Sopenharmony_ci	perf_record_no_decode -o "${perfdatafile}" -e intel_pt//u uname
49162306a36Sopenharmony_ci	# Should not get CYC packets
49262306a36Sopenharmony_ci	cyc_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "CYC 0x")
49362306a36Sopenharmony_ci	if [ "${cyc_cnt}" -gt 0 ] ; then
49462306a36Sopenharmony_ci		echo "Still get CYC packet without cyc"
49562306a36Sopenharmony_ci		return 1
49662306a36Sopenharmony_ci	fi
49762306a36Sopenharmony_ci	echo OK
49862306a36Sopenharmony_ci	return 0
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_citest_sample()
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	echo "--- Test recording with sample mode ---"
50462306a36Sopenharmony_ci	# Check if recording with sample mode is working
50562306a36Sopenharmony_ci	if ! perf_record_no_decode -o "${perfdatafile}" --aux-sample=8192 -e '{intel_pt//u,branch-misses:u}' uname ; then
50662306a36Sopenharmony_ci		echo "perf record failed with --aux-sample"
50762306a36Sopenharmony_ci		return 1
50862306a36Sopenharmony_ci	fi
50962306a36Sopenharmony_ci	# Check with event with PMU name
51062306a36Sopenharmony_ci	if perf_record_no_decode -o "${perfdatafile}" -e br_misp_retired.all_branches:u uname ; then
51162306a36Sopenharmony_ci		if ! perf_record_no_decode -o "${perfdatafile}" -e '{intel_pt//,br_misp_retired.all_branches/aux-sample-size=8192/}:u' uname ; then
51262306a36Sopenharmony_ci			echo "perf record failed with --aux-sample-size"
51362306a36Sopenharmony_ci			return 1
51462306a36Sopenharmony_ci		fi
51562306a36Sopenharmony_ci	fi
51662306a36Sopenharmony_ci	echo OK
51762306a36Sopenharmony_ci	return 0
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_citest_kernel_trace()
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	echo "--- Test with kernel trace ---"
52362306a36Sopenharmony_ci	# Check if recording with kernel trace is working
52462306a36Sopenharmony_ci	can_kernel || return 2
52562306a36Sopenharmony_ci	if ! perf_record_no_decode -o "${perfdatafile}" -e intel_pt//k -m1,128 uname ; then
52662306a36Sopenharmony_ci		echo "perf record failed with intel_pt//k"
52762306a36Sopenharmony_ci		return 1
52862306a36Sopenharmony_ci	fi
52962306a36Sopenharmony_ci	echo OK
53062306a36Sopenharmony_ci	return 0
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_citest_virtual_lbr()
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	echo "--- Test virtual LBR ---"
53662306a36Sopenharmony_ci	# Check if python script is supported
53762306a36Sopenharmony_ci	libpython=$(perf version --build-options | grep python | grep -cv OFF)
53862306a36Sopenharmony_ci	if [ "${libpython}" != "1" ] ; then
53962306a36Sopenharmony_ci		echo "SKIP: python scripting is not supported"
54062306a36Sopenharmony_ci		return 2
54162306a36Sopenharmony_ci	fi
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	# Python script to determine the maximum size of branch stacks
54462306a36Sopenharmony_ci	cat << "_end_of_file_" > "${maxbrstack}"
54562306a36Sopenharmony_cifrom __future__ import print_function
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_cibmax = 0
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_cidef process_event(param_dict):
55062306a36Sopenharmony_ci	if "brstack" in param_dict:
55162306a36Sopenharmony_ci		brstack = param_dict["brstack"]
55262306a36Sopenharmony_ci		n = len(brstack)
55362306a36Sopenharmony_ci		global bmax
55462306a36Sopenharmony_ci		if n > bmax:
55562306a36Sopenharmony_ci			bmax = n
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_cidef trace_end():
55862306a36Sopenharmony_ci	print("max brstack", bmax)
55962306a36Sopenharmony_ci_end_of_file_
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	# Check if virtual lbr is working
56262306a36Sopenharmony_ci	perf_record_no_bpf -o "${perfdatafile}" --aux-sample -e '{intel_pt//,cycles}:u' uname
56362306a36Sopenharmony_ci	times_val=$(perf script -i "${perfdatafile}" --itrace=L -s "${maxbrstack}" 2>/dev/null | grep "max brstack " | cut -d " " -f 3)
56462306a36Sopenharmony_ci	case "${times_val}" in
56562306a36Sopenharmony_ci		[0-9]*)	;;
56662306a36Sopenharmony_ci		*)	times_val=0;;
56762306a36Sopenharmony_ci	esac
56862306a36Sopenharmony_ci	if [ "${times_val}" -lt 2 ] ; then
56962306a36Sopenharmony_ci		echo "Failed with virtual lbr"
57062306a36Sopenharmony_ci		return 1
57162306a36Sopenharmony_ci	fi
57262306a36Sopenharmony_ci	echo OK
57362306a36Sopenharmony_ci	return 0
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_citest_power_event()
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	echo "--- Test power events ---"
57962306a36Sopenharmony_ci	# Check if power events are supported
58062306a36Sopenharmony_ci	power_event=$(cat /sys/bus/event_source/devices/intel_pt/caps/power_event_trace)
58162306a36Sopenharmony_ci	if [ "${power_event}" != "1" ] ; then
58262306a36Sopenharmony_ci		echo "SKIP: power_event_trace is not supported"
58362306a36Sopenharmony_ci		return 2
58462306a36Sopenharmony_ci	fi
58562306a36Sopenharmony_ci	if ! perf_record_no_decode -o "${perfdatafile}" -a -e intel_pt/pwr_evt/u uname ; then
58662306a36Sopenharmony_ci		echo "perf record failed with pwr_evt"
58762306a36Sopenharmony_ci		return 1
58862306a36Sopenharmony_ci	fi
58962306a36Sopenharmony_ci	echo OK
59062306a36Sopenharmony_ci	return 0
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_citest_no_tnt()
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	echo "--- Test with TNT packets disabled  ---"
59662306a36Sopenharmony_ci	# Check if TNT disable is supported
59762306a36Sopenharmony_ci	notnt=$(cat /sys/bus/event_source/devices/intel_pt/caps/tnt_disable)
59862306a36Sopenharmony_ci	if [ "${notnt}" != "1" ] ; then
59962306a36Sopenharmony_ci		echo "SKIP: tnt_disable is not supported"
60062306a36Sopenharmony_ci		return 2
60162306a36Sopenharmony_ci	fi
60262306a36Sopenharmony_ci	perf_record_no_decode -o "${perfdatafile}" -e intel_pt/notnt/u uname
60362306a36Sopenharmony_ci	# Should be no TNT packets
60462306a36Sopenharmony_ci	tnt_cnt=$(perf script -i "${perfdatafile}" -D | grep -c TNT)
60562306a36Sopenharmony_ci	if [ "${tnt_cnt}" -ne 0 ] ; then
60662306a36Sopenharmony_ci		echo "TNT packets still there after notnt"
60762306a36Sopenharmony_ci		return 1
60862306a36Sopenharmony_ci	fi
60962306a36Sopenharmony_ci	echo OK
61062306a36Sopenharmony_ci	return 0
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_citest_event_trace()
61462306a36Sopenharmony_ci{
61562306a36Sopenharmony_ci	echo "--- Test with event_trace ---"
61662306a36Sopenharmony_ci	# Check if event_trace is supported
61762306a36Sopenharmony_ci	event_trace=$(cat /sys/bus/event_source/devices/intel_pt/caps/event_trace)
61862306a36Sopenharmony_ci	if [ "${event_trace}" != 1 ] ; then
61962306a36Sopenharmony_ci		echo "SKIP: event_trace is not supported"
62062306a36Sopenharmony_ci		return 2
62162306a36Sopenharmony_ci	fi
62262306a36Sopenharmony_ci	if ! perf_record_no_decode -o "${perfdatafile}" -e intel_pt/event/u uname ; then
62362306a36Sopenharmony_ci		echo "perf record failed with event trace"
62462306a36Sopenharmony_ci		return 1
62562306a36Sopenharmony_ci	fi
62662306a36Sopenharmony_ci	echo OK
62762306a36Sopenharmony_ci	return 0
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_citest_pipe()
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	echo "--- Test with pipe mode ---"
63362306a36Sopenharmony_ci	# Check if it works with pipe
63462306a36Sopenharmony_ci	if ! perf_record_no_bpf -o- -e intel_pt//u uname | perf report -q -i- --itrace=i10000 ; then
63562306a36Sopenharmony_ci		echo "perf record + report failed with pipe mode"
63662306a36Sopenharmony_ci		return 1
63762306a36Sopenharmony_ci	fi
63862306a36Sopenharmony_ci	if ! perf_record_no_bpf -o- -e intel_pt//u uname | perf inject -b > /dev/null ; then
63962306a36Sopenharmony_ci		echo "perf record + inject failed with pipe mode"
64062306a36Sopenharmony_ci		return 1
64162306a36Sopenharmony_ci	fi
64262306a36Sopenharmony_ci	echo OK
64362306a36Sopenharmony_ci	return 0
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cicount_result()
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	if [ "$1" -eq 2 ] ; then
64962306a36Sopenharmony_ci		skip_cnt=$((skip_cnt + 1))
65062306a36Sopenharmony_ci		return
65162306a36Sopenharmony_ci	fi
65262306a36Sopenharmony_ci	if [ "$1" -eq 0 ] ; then
65362306a36Sopenharmony_ci		ok_cnt=$((ok_cnt + 1))
65462306a36Sopenharmony_ci		return
65562306a36Sopenharmony_ci	fi
65662306a36Sopenharmony_ci	err_cnt=$((err_cnt + 1))
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ciret=0
66062306a36Sopenharmony_citest_system_wide_side_band		|| ret=$? ; count_result $ret ; ret=0
66162306a36Sopenharmony_citest_per_thread "" ""			|| ret=$? ; count_result $ret ; ret=0
66262306a36Sopenharmony_citest_per_thread "k" "(incl. kernel) "	|| ret=$? ; count_result $ret ; ret=0
66362306a36Sopenharmony_citest_jitdump				|| ret=$? ; count_result $ret ; ret=0
66462306a36Sopenharmony_citest_packet_filter			|| ret=$? ; count_result $ret ; ret=0
66562306a36Sopenharmony_citest_disable_branch			|| ret=$? ; count_result $ret ; ret=0
66662306a36Sopenharmony_citest_time_cyc				|| ret=$? ; count_result $ret ; ret=0
66762306a36Sopenharmony_citest_sample				|| ret=$? ; count_result $ret ; ret=0
66862306a36Sopenharmony_citest_kernel_trace			|| ret=$? ; count_result $ret ; ret=0
66962306a36Sopenharmony_citest_virtual_lbr			|| ret=$? ; count_result $ret ; ret=0
67062306a36Sopenharmony_citest_power_event			|| ret=$? ; count_result $ret ; ret=0
67162306a36Sopenharmony_citest_no_tnt				|| ret=$? ; count_result $ret ; ret=0
67262306a36Sopenharmony_citest_event_trace			|| ret=$? ; count_result $ret ; ret=0
67362306a36Sopenharmony_citest_pipe				|| ret=$? ; count_result $ret ; ret=0
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_cicleanup
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ciecho "--- Done ---"
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ciif [ ${err_cnt} -gt 0 ] ; then
68062306a36Sopenharmony_ci	exit 1
68162306a36Sopenharmony_cifi
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ciif [ ${ok_cnt} -gt 0 ] ; then
68462306a36Sopenharmony_ci	exit 0
68562306a36Sopenharmony_cifi
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ciexit 2
688