[5/7] perf test: test_intel_pt.sh: Add jitdump test

Message ID 20221014170905.64069-6-adrian.hunter@intel.com
State New
Headers
Series perf intel-pt: jitdump fix and test |

Commit Message

Adrian Hunter Oct. 14, 2022, 5:09 p.m. UTC
  Add a test for decoding self-modifying code using a jitdump file.

The test creates a workload that uses self-modifying code and generates its
own jitdump file.  The result is processed with perf inject --jit and
checked for decoding errors.

Note the test will fail without patch "perf inject: Fix GEN_ELF_TEXT_OFFSET
for jit" applied.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/tests/shell/test_intel_pt.sh | 162 ++++++++++++++++++++++++
 1 file changed, 162 insertions(+)
  

Comments

Arnaldo Carvalho de Melo Oct. 14, 2022, 5:28 p.m. UTC | #1
Em Fri, Oct 14, 2022 at 08:09:03PM +0300, Adrian Hunter escreveu:
> Add a test for decoding self-modifying code using a jitdump file.
> 
> The test creates a workload that uses self-modifying code and generates its
> own jitdump file.  The result is processed with perf inject --jit and
> checked for decoding errors.
> 
> Note the test will fail without patch "perf inject: Fix GEN_ELF_TEXT_OFFSET
> for jit" applied.
> 
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>  tools/perf/tests/shell/test_intel_pt.sh | 162 ++++++++++++++++++++++++
>  1 file changed, 162 insertions(+)
> 
> diff --git a/tools/perf/tests/shell/test_intel_pt.sh b/tools/perf/tests/shell/test_intel_pt.sh
> index 79dde57b561d..e0bf75981b9c 100755
> --- a/tools/perf/tests/shell/test_intel_pt.sh
> +++ b/tools/perf/tests/shell/test_intel_pt.sh
> @@ -22,6 +22,7 @@ outfile="${temp_dir}/test-out.txt"
>  errfile="${temp_dir}/test-err.txt"
>  workload="${temp_dir}/workload"
>  awkscript="${temp_dir}/awkscript"
> +jitdump_workload="${temp_dir}/jitdump_workload"
>  
>  cleanup()
>  {
> @@ -50,6 +51,13 @@ perf_record_no_decode()
>  	perf record -B -N --no-bpf-event "$@"
>  }
>  
> +# perf record for testing should not need BPF events
> +perf_record_no_bpf()
> +{
> +	# Options for no BPF events
> +	perf record --no-bpf-event "$@"
> +}
> +
>  have_workload=false
>  cat << _end_of_file_ | /usr/bin/cc -o "${workload}" -xc - -pthread && have_workload=true
>  #include <time.h>
> @@ -269,6 +277,159 @@ test_per_thread()
>  	return 0
>  }
>  
> +test_jitdump()
> +{
> +	echo "--- Test tracing self-modifying code that uses jitdump ---"
> +
> +	script_path=$(realpath "$0")
> +	script_dir=$(dirname "$script_path")
> +	jitdump_incl_dir="${script_dir}/../../util"
> +	jitdump_h="${jitdump_incl_dir}/jitdump.h"

So this requires one to test this being on the kernel (perf) sources
dir? I think we should add this header to some 'perf test' directory to
remove this requirement, ok?

But this can be done on top, right now we just don't test jitdump:

fd 20 : idx 11: mmapping fd 20
Checking 16 fds
OK
--- Test tracing self-modifying code that uses jitdump ---
SKIP: Include file jitdump.h not found
--- Cleaning up ---
--- Done ---
test child finished with 0
---- end ----
Miscellaneous Intel PT testing: Ok


> +	if [ ! -e "${jitdump_h}" ] ; then
> +		echo "SKIP: Include file jitdump.h not found"
> +		return 2
> +	fi
> +
> +	if [ -z "${have_jitdump_workload}" ] ; then
> +		have_jitdump_workload=false
> +		# Create a workload that uses self-modifying code and generates its own jitdump file
> +		cat <<- "_end_of_file_" | /usr/bin/cc -o "${jitdump_workload}" -I "${jitdump_incl_dir}" -xc - -pthread && have_jitdump_workload=true
> +		#define _GNU_SOURCE
> +		#include <sys/mman.h>
> +		#include <sys/types.h>
> +		#include <stddef.h>
> +		#include <stdio.h>
> +		#include <stdint.h>
> +		#include <unistd.h>
> +		#include <string.h>
> +
> +		#include "jitdump.h"
> +
> +		#define CHK_BYTE 0x5a
> +
> +		static inline uint64_t rdtsc(void)
> +		{
> +			unsigned int low, high;
> +
> +			asm volatile("rdtsc" : "=a" (low), "=d" (high));
> +
> +			return low | ((uint64_t)high) << 32;
> +		}
> +
> +		static FILE *open_jitdump(void)
> +		{
> +			struct jitheader header = {
> +				.magic      = JITHEADER_MAGIC,
> +				.version    = JITHEADER_VERSION,
> +				.total_size = sizeof(header),
> +				.pid        = getpid(),
> +				.timestamp  = rdtsc(),
> +				.flags      = JITDUMP_FLAGS_ARCH_TIMESTAMP,
> +			};
> +			char filename[256];
> +			FILE *f;
> +			void *m;
> +
> +			snprintf(filename, sizeof(filename), "jit-%d.dump", getpid());
> +			f = fopen(filename, "w+");
> +			if (!f)
> +				goto err;
> +			/* Create an MMAP event for the jitdump file. That is how perf tool finds it. */
> +			m = mmap(0, 4096, PROT_READ | PROT_EXEC, MAP_PRIVATE, fileno(f), 0);
> +			if (m == MAP_FAILED)
> +				goto err_close;
> +			munmap(m, 4096);
> +			if (fwrite(&header,sizeof(header),1,f) != 1)
> +				goto err_close;
> +			return f;
> +
> +		err_close:
> +			fclose(f);
> +		err:
> +			return NULL;
> +		}
> +
> +		static int write_jitdump(FILE *f, void *addr, const uint8_t *dat, size_t sz, uint64_t *idx)
> +		{
> +			struct jr_code_load rec = {
> +				.p.id          = JIT_CODE_LOAD,
> +				.p.total_size  = sizeof(rec) + sz,
> +				.p.timestamp   = rdtsc(),
> +				.pid	       = getpid(),
> +				.tid	       = gettid(),
> +				.vma           = (unsigned long)addr,
> +				.code_addr     = (unsigned long)addr,
> +				.code_size     = sz,
> +				.code_index    = ++*idx,
> +			};
> +
> +			if (fwrite(&rec,sizeof(rec),1,f) != 1 ||
> +			fwrite(dat, sz, 1, f) != 1)
> +				return -1;
> +			return 0;
> +		}
> +
> +		static void close_jitdump(FILE *f)
> +		{
> +			fclose(f);
> +		}
> +
> +		int main()
> +		{
> +			/* Get a memory page to store executable code */
> +			void *addr = mmap(0, 4096, PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +			/* Code to execute: mov CHK_BYTE, %eax ; ret */
> +			uint8_t dat[] = {0xb8, CHK_BYTE, 0x00, 0x00, 0x00, 0xc3};
> +			FILE *f = open_jitdump();
> +			uint64_t idx = 0;
> +			int ret = 1;
> +
> +			if (!f)
> +				return 1;
> +			/* Copy executable code to executable memory page */
> +			memcpy(addr, dat, sizeof(dat));
> +			/* Record it in the jitdump file */
> +			if (write_jitdump(f, addr, dat, sizeof(dat), &idx))
> +				goto out_close;
> +			/* Call it */
> +			ret = ((int (*)(void))addr)() - CHK_BYTE;
> +		out_close:
> +			close_jitdump(f);
> +			return ret;
> +		}
> +		_end_of_file_
> +	fi
> +
> +	if ! $have_jitdump_workload ; then
> +		echo "SKIP: No jitdump workload"
> +		return 2
> +	fi
> +
> +	# Change to temp_dir so jitdump collateral files go there
> +	cd "${temp_dir}"
> +	perf_record_no_bpf -o "${tmpfile}" -e intel_pt//u "${jitdump_workload}"
> +	perf inject -i "${tmpfile}" -o "${perfdatafile}" --jit
> +	decode_br_cnt=$(perf script -i "${perfdatafile}" --itrace=b | wc -l)
> +	# Note that overflow and lost errors are suppressed for the error count
> +	decode_err_cnt=$(perf script -i "${perfdatafile}" --itrace=e-o-l | grep -ci error)
> +	cd -
> +	# Should be thousands of branches
> +	if [ "${decode_br_cnt}" -lt 1000 ] ; then
> +		echo "Decode failed, only ${decode_br_cnt} branches"
> +		return 1
> +	fi
> +	# Should be no errors
> +	if [ "${decode_err_cnt}" -ne 0 ] ; then
> +		echo "Decode failed, ${decode_err_cnt} errors"
> +		perf script -i "${perfdatafile}" --itrace=e-o-l
> +		return 1
> +	fi
> +
> +	echo OK
> +	return 0
> +}
> +
>  count_result()
>  {
>  	if [ "$1" -eq 2 ] ; then
> @@ -286,6 +447,7 @@ ret=0
>  test_system_wide_side_band		|| ret=$? ; count_result $ret ; ret=0
>  test_per_thread "" ""			|| ret=$? ; count_result $ret ; ret=0
>  test_per_thread "k" "(incl. kernel) "	|| ret=$? ; count_result $ret ; ret=0
> +test_jitdump				|| ret=$? ; count_result $ret ; ret=0
>  
>  cleanup
>  
> -- 
> 2.25.1
  
Arnaldo Carvalho de Melo Oct. 14, 2022, 5:32 p.m. UTC | #2
Em Fri, Oct 14, 2022 at 02:28:58PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Fri, Oct 14, 2022 at 08:09:03PM +0300, Adrian Hunter escreveu:
> > Add a test for decoding self-modifying code using a jitdump file.
> > 
> > The test creates a workload that uses self-modifying code and generates its
> > own jitdump file.  The result is processed with perf inject --jit and
> > checked for decoding errors.
> > 
> > Note the test will fail without patch "perf inject: Fix GEN_ELF_TEXT_OFFSET
> > for jit" applied.
> > 
> > Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> > ---
> >  tools/perf/tests/shell/test_intel_pt.sh | 162 ++++++++++++++++++++++++
> >  1 file changed, 162 insertions(+)
> > 
> > diff --git a/tools/perf/tests/shell/test_intel_pt.sh b/tools/perf/tests/shell/test_intel_pt.sh
> > index 79dde57b561d..e0bf75981b9c 100755
> > --- a/tools/perf/tests/shell/test_intel_pt.sh
> > +++ b/tools/perf/tests/shell/test_intel_pt.sh
> > @@ -22,6 +22,7 @@ outfile="${temp_dir}/test-out.txt"
> >  errfile="${temp_dir}/test-err.txt"
> >  workload="${temp_dir}/workload"
> >  awkscript="${temp_dir}/awkscript"
> > +jitdump_workload="${temp_dir}/jitdump_workload"
> >  
> >  cleanup()
> >  {
> > @@ -50,6 +51,13 @@ perf_record_no_decode()
> >  	perf record -B -N --no-bpf-event "$@"
> >  }
> >  
> > +# perf record for testing should not need BPF events
> > +perf_record_no_bpf()
> > +{
> > +	# Options for no BPF events
> > +	perf record --no-bpf-event "$@"
> > +}
> > +
> >  have_workload=false
> >  cat << _end_of_file_ | /usr/bin/cc -o "${workload}" -xc - -pthread && have_workload=true
> >  #include <time.h>
> > @@ -269,6 +277,159 @@ test_per_thread()
> >  	return 0
> >  }
> >  
> > +test_jitdump()
> > +{
> > +	echo "--- Test tracing self-modifying code that uses jitdump ---"
> > +
> > +	script_path=$(realpath "$0")
> > +	script_dir=$(dirname "$script_path")
> > +	jitdump_incl_dir="${script_dir}/../../util"
> > +	jitdump_h="${jitdump_incl_dir}/jitdump.h"
> 
> So this requires one to test this being on the kernel (perf) sources
> dir? I think we should add this header to some 'perf test' directory to
> remove this requirement, ok?
> 
> But this can be done on top, right now we just don't test jitdump:
> 
> fd 20 : idx 11: mmapping fd 20
> Checking 16 fds
> OK
> --- Test tracing self-modifying code that uses jitdump ---
> SKIP: Include file jitdump.h not found
> --- Cleaning up ---
> --- Done ---
> test child finished with 0
> ---- end ----
> Miscellaneous Intel PT testing: Ok

Actually:

--- Test tracing self-modifying code that uses jitdump ---
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.018 MB /tmp/perf-test-intel-pt-sh.GJoKOxGVFY/tmp-perf.data ]

Warning:
1 instruction trace errors
/home/acme/git/perf
Decode failed, 1 errors
Warning:
1 instruction trace errors
 instruction trace error type 1 time 494778.777081924 cpu 3 pid 309650 tid 309650 ip 0x7f0972f22009 code 5: Failed to get instruction
--- Cleaning up ---
--- Done ---
test child finished with -1
---- end ----
Miscellaneous Intel PT testing: FAILED!
[root@quaco perf]#
[root@quaco perf]# pwd
/home/acme/git/perf

Multiple runs end up failing, processor info:

[root@quaco perf]# grep -m1 -A26 vendor_id /proc/cpuinfo
vendor_id	: GenuineIntel
cpu family	: 6
model		: 142
model name	: Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz
stepping	: 10
microcode	: 0xf0
cpu MHz		: 2100.000
cache size	: 8192 KB
physical id	: 0
siblings	: 8
core id		: 0
cpu cores	: 4
apicid		: 0
initial apicid	: 0
fpu		: yes
fpu_exception	: yes
cpuid level	: 22
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d arch_capabilities
vmx flags	: vnmi preemption_timer invvpid ept_x_only ept_ad ept_1gb flexpriority tsc_offset vtpr mtf vapic ept vpid unrestricted_guest ple shadow_vmcs pml ept_mode_based_exec
bugs		: cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs taa itlb_multihit srbds mmio_stale_data retbleed
bogomips	: 4199.88
clflush size	: 64
cache_alignment	: 64
address sizes	: 39 bits physical, 48 bits virtual
power management:

[root@quaco perf]#
  
Arnaldo Carvalho de Melo Oct. 14, 2022, 5:33 p.m. UTC | #3
Em Fri, Oct 14, 2022 at 02:32:19PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Fri, Oct 14, 2022 at 02:28:58PM -0300, Arnaldo Carvalho de Melo escreveu:
> > Miscellaneous Intel PT testing: Ok
 
> Actually:
 
> --- Test tracing self-modifying code that uses jitdump ---
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 0.018 MB /tmp/perf-test-intel-pt-sh.GJoKOxGVFY/tmp-perf.data ]
> 
> Warning:
> 1 instruction trace errors
> /home/acme/git/perf
> Decode failed, 1 errors
> Warning:
> 1 instruction trace errors
>  instruction trace error type 1 time 494778.777081924 cpu 3 pid 309650 tid 309650 ip 0x7f0972f22009 code 5: Failed to get instruction
> --- Cleaning up ---
> --- Done ---
> test child finished with -1
> ---- end ----
> Miscellaneous Intel PT testing: FAILED!
> [root@quaco perf]#
> [root@quaco perf]# pwd
> /home/acme/git/perf

I see... nevermind, this is what is expected, failing now, then the fix,
then stops failing, nothing to see here, move along 8-)

- Arnaldo
  
Arnaldo Carvalho de Melo Oct. 14, 2022, 5:35 p.m. UTC | #4
Em Fri, Oct 14, 2022 at 02:33:39PM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Fri, Oct 14, 2022 at 02:32:19PM -0300, Arnaldo Carvalho de Melo escreveu:
> > Em Fri, Oct 14, 2022 at 02:28:58PM -0300, Arnaldo Carvalho de Melo escreveu:
> > > Miscellaneous Intel PT testing: Ok
>  
> > Actually:
>  
> > --- Test tracing self-modifying code that uses jitdump ---
> > [ perf record: Woken up 1 times to write data ]
> > [ perf record: Captured and wrote 0.018 MB /tmp/perf-test-intel-pt-sh.GJoKOxGVFY/tmp-perf.data ]
> > 
> > Warning:
> > 1 instruction trace errors
> > /home/acme/git/perf
> > Decode failed, 1 errors
> > Warning:
> > 1 instruction trace errors
> >  instruction trace error type 1 time 494778.777081924 cpu 3 pid 309650 tid 309650 ip 0x7f0972f22009 code 5: Failed to get instruction
> > --- Cleaning up ---
> > --- Done ---
> > test child finished with -1
> > ---- end ----
> > Miscellaneous Intel PT testing: FAILED!
> > [root@quaco perf]#
> > [root@quaco perf]# pwd
> > /home/acme/git/perf
> 
> I see... nevermind, this is what is expected, failing now, then the fix,
> then stops failing, nothing to see here, move along 8-)

Just for completeness sake, after the genelf.h fix:

[root@quaco perf]# perf test "Miscellaneous Intel PT testing"
110: Miscellaneous Intel PT testing                                  : Ok
[root@quaco perf]# perf test -v "Miscellaneous Intel PT testing"
110: Miscellaneous Intel PT testing                                  :
--- start ---
test child forked, pid 314597
--- Test system-wide sideband ---
Checking for CPU-wide recording on CPU 0
OK
Checking for CPU-wide recording on CPU 1
OK
Linux
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.189 MB /tmp/perf-test-intel-pt-sh.TRr45lCVrl/test-perf.data ]
OK
--- Test per-thread recording ---
Workload PIDs are 314619 and 314620
perf PID is 314631
Waiting for "perf record has started" message
OK
pid 314619 cpu -1 fd 5 : sys_perf_event_open: pid 314619  cpu -1  group_fd -1  flags 0x8 = 5
pid 314623 cpu -1 fd 6 : sys_perf_event_open: pid 314623  cpu -1  group_fd -1  flags 0x8 = 6
pid 314620 cpu -1 fd 7 : sys_perf_event_open: pid 314620  cpu -1  group_fd -1  flags 0x8 = 7
pid 314622 cpu -1 fd 8 : sys_perf_event_open: pid 314622  cpu -1  group_fd -1  flags 0x8 = 8
pid 314619 cpu -1 fd 9 : sys_perf_event_open: pid 314619  cpu -1  group_fd -1  flags 0x8 = 9
pid 314623 cpu -1 fd 10 : sys_perf_event_open: pid 314623  cpu -1  group_fd -1  flags 0x8 = 10
pid 314620 cpu -1 fd 11 : sys_perf_event_open: pid 314620  cpu -1  group_fd -1  flags 0x8 = 11
pid 314622 cpu -1 fd 12 : sys_perf_event_open: pid 314622  cpu -1  group_fd -1  flags 0x8 = 12
fd 5 : idx 0: mmapping fd 5
fd 9 fd_to 5 : idx 0: set output fd 9 -> 5
fd 6 : idx 1: mmapping fd 6
fd 10 fd_to 6 : idx 1: set output fd 10 -> 6
fd 7 : idx 2: mmapping fd 7
fd 11 fd_to 7 : idx 2: set output fd 11 -> 7
fd 8 : idx 3: mmapping fd 8
fd 12 fd_to 8 : idx 3: set output fd 12 -> 8
Checking 8 fds
OK
--- Test per-thread (incl. kernel) recording ---
Workload PIDs are 315355 and 315356
perf PID is 315367
Waiting for "perf record has started" message
OK
pid 315355 cpu -1 fd 5 : sys_perf_event_open: pid 315355  cpu -1  group_fd -1  flags 0x8 = 5
pid 315358 cpu -1 fd 6 : sys_perf_event_open: pid 315358  cpu -1  group_fd -1  flags 0x8 = 6
pid 315356 cpu -1 fd 7 : sys_perf_event_open: pid 315356  cpu -1  group_fd -1  flags 0x8 = 7
pid 315359 cpu -1 fd 8 : sys_perf_event_open: pid 315359  cpu -1  group_fd -1  flags 0x8 = 8
pid 315355 cpu -1 fd 9 : sys_perf_event_open: pid 315355  cpu -1  group_fd -1  flags 0x8 = 9
pid 315358 cpu -1 fd 10 : sys_perf_event_open: pid 315358  cpu -1  group_fd -1  flags 0x8 = 10
pid 315356 cpu -1 fd 11 : sys_perf_event_open: pid 315356  cpu -1  group_fd -1  flags 0x8 = 11
pid 315359 cpu -1 fd 12 : sys_perf_event_open: pid 315359  cpu -1  group_fd -1  flags 0x8 = 12
pid -1 cpu 0 fd 13 : sys_perf_event_open: pid -1  cpu 0  group_fd -1  flags 0x8 = 13
pid -1 cpu 1 fd 14 : sys_perf_event_open: pid -1  cpu 1  group_fd -1  flags 0x8 = 14
pid -1 cpu 2 fd 15 : sys_perf_event_open: pid -1  cpu 2  group_fd -1  flags 0x8 = 15
pid -1 cpu 3 fd 16 : sys_perf_event_open: pid -1  cpu 3  group_fd -1  flags 0x8 = 16
pid -1 cpu 4 fd 17 : sys_perf_event_open: pid -1  cpu 4  group_fd -1  flags 0x8 = 17
pid -1 cpu 5 fd 18 : sys_perf_event_open: pid -1  cpu 5  group_fd -1  flags 0x8 = 18
pid -1 cpu 6 fd 19 : sys_perf_event_open: pid -1  cpu 6  group_fd -1  flags 0x8 = 19
pid -1 cpu 7 fd 20 : sys_perf_event_open: pid -1  cpu 7  group_fd -1  flags 0x8 = 20
fd 5 : idx 0: mmapping fd 5
fd 9 fd_to 5 : idx 0: set output fd 9 -> 5
fd 6 : idx 1: mmapping fd 6
fd 10 fd_to 6 : idx 1: set output fd 10 -> 6
fd 7 : idx 2: mmapping fd 7
fd 11 fd_to 7 : idx 2: set output fd 11 -> 7
fd 8 : idx 3: mmapping fd 8
fd 12 fd_to 8 : idx 3: set output fd 12 -> 8
fd 13 : idx 4: mmapping fd 13
fd 14 : idx 5: mmapping fd 14
fd 15 : idx 6: mmapping fd 15
fd 16 : idx 7: mmapping fd 16
fd 17 : idx 8: mmapping fd 17
fd 18 : idx 9: mmapping fd 18
fd 19 : idx 10: mmapping fd 19
fd 20 : idx 11: mmapping fd 20
Checking 16 fds
OK
--- Test tracing self-modifying code that uses jitdump ---
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.021 MB /tmp/perf-test-intel-pt-sh.TRr45lCVrl/tmp-perf.data ]
/home/acme/git/perf
OK
--- Cleaning up ---
--- Done ---
test child finished with 0
---- end ----
Miscellaneous Intel PT testing: Ok
[root@quaco perf]#
  
Adrian Hunter Oct. 17, 2022, 9:35 a.m. UTC | #5
On 17/10/22 16:44, Arnaldo Carvalho de Melo wrote:
> Em Mon, Oct 17, 2022 at 03:57:03PM +0300, Adrian Hunter escreveu:
>> On 14/10/22 20:28, Arnaldo Carvalho de Melo wrote:
>>> Em Fri, Oct 14, 2022 at 08:09:03PM +0300, Adrian Hunter escreveu:
>>>> Add a test for decoding self-modifying code using a jitdump file.
>>>>
>>>> The test creates a workload that uses self-modifying code and generates its
>>>> own jitdump file.  The result is processed with perf inject --jit and
>>>> checked for decoding errors.
>>>>
>>>> Note the test will fail without patch "perf inject: Fix GEN_ELF_TEXT_OFFSET
>>>> for jit" applied.
>>>>
>>>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>>>> ---
>>>>  tools/perf/tests/shell/test_intel_pt.sh | 162 ++++++++++++++++++++++++
>>>>  1 file changed, 162 insertions(+)
>>>>
>>>> diff --git a/tools/perf/tests/shell/test_intel_pt.sh b/tools/perf/tests/shell/test_intel_pt.sh
>>>> index 79dde57b561d..e0bf75981b9c 100755
>>>> --- a/tools/perf/tests/shell/test_intel_pt.sh
>>>> +++ b/tools/perf/tests/shell/test_intel_pt.sh
>>>> @@ -22,6 +22,7 @@ outfile="${temp_dir}/test-out.txt"
>>>>  errfile="${temp_dir}/test-err.txt"
>>>>  workload="${temp_dir}/workload"
>>>>  awkscript="${temp_dir}/awkscript"
>>>> +jitdump_workload="${temp_dir}/jitdump_workload"
>>>>  
>>>>  cleanup()
>>>>  {
>>>> @@ -50,6 +51,13 @@ perf_record_no_decode()
>>>>  	perf record -B -N --no-bpf-event "$@"
>>>>  }
>>>>  
>>>> +# perf record for testing should not need BPF events
>>>> +perf_record_no_bpf()
>>>> +{
>>>> +	# Options for no BPF events
>>>> +	perf record --no-bpf-event "$@"
>>>> +}
>>>> +
>>>>  have_workload=false
>>>>  cat << _end_of_file_ | /usr/bin/cc -o "${workload}" -xc - -pthread && have_workload=true
>>>>  #include <time.h>
>>>> @@ -269,6 +277,159 @@ test_per_thread()
>>>>  	return 0
>>>>  }
>>>>  
>>>> +test_jitdump()
>>>> +{
>>>> +	echo "--- Test tracing self-modifying code that uses jitdump ---"
>>>> +
>>>> +	script_path=$(realpath "$0")
>>>> +	script_dir=$(dirname "$script_path")
>>>> +	jitdump_incl_dir="${script_dir}/../../util"
>>>> +	jitdump_h="${jitdump_incl_dir}/jitdump.h"
>>>
>>> So this requires one to test this being on the kernel (perf) sources
>>> dir? I think we should add this header to some 'perf test' directory to
>>> remove this requirement, ok?
>>>
>>
>> How about this:
> 
> Better, but see below
>  
>> From: Adrian Hunter <adrian.hunter@intel.com>
>> Date: Mon, 17 Oct 2022 15:14:25 +0300
>> Subject: [PATCH] perf test: test_intel_pt.sh: Install jitdump.h for use by
>>  tests
>>
>> test_intel_pt.sh builds a workload for testing jitdump and the workload
>> includes file jitdump.h.
>>
>> Currently, test_intel_pt.sh finds jitdump.h assuming the test is run in
>> the kernel source directory, and skips that test if it is not found.
>>
>> To improve that situation, amend the build to install the jitdump.h file
>> in the test shell directory, and look there first, falling back to the
>> original way if that is not found.
>>
>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>> ---
>>  tools/perf/Makefile.perf                |  1 +
>>  tools/perf/tests/shell/test_intel_pt.sh | 12 +++++++++---
>>  2 files changed, 10 insertions(+), 3 deletions(-)
>>
>> diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
>> index a432e59afc42..c4ec66194465 100644
>> --- a/tools/perf/Makefile.perf
>> +++ b/tools/perf/Makefile.perf
>> @@ -1013,6 +1013,7 @@ install-tests: all install-gtk
>>  		$(INSTALL) tests/attr/* -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
>>  		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell'; \
>>  		$(INSTALL) tests/shell/*.sh '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell'; \
>> +		$(INSTALL) util/jitdump.h -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell'; \
>>  		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \
>>  		$(INSTALL) tests/shell/lib/*.sh -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \
>>  		$(INSTALL) tests/shell/lib/*.py -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \
>> diff --git a/tools/perf/tests/shell/test_intel_pt.sh b/tools/perf/tests/shell/test_intel_pt.sh
>> index 4c0aabbe33bd..3abf803f96b9 100755
>> --- a/tools/perf/tests/shell/test_intel_pt.sh
>> +++ b/tools/perf/tests/shell/test_intel_pt.sh
>> @@ -284,14 +284,20 @@ test_jitdump()
>>  
>>  	script_path=$(realpath "$0")
>>  	script_dir=$(dirname "$script_path")
>> -	jitdump_incl_dir="${script_dir}/../../util"
>> +	jitdump_incl_dir="${script_dir}"
>>  	jitdump_h="${jitdump_incl_dir}/jitdump.h"
>>  
>>  	if [ ! -e "${jitdump_h}" ] ; then
>> -		echo "SKIP: Include file jitdump.h not found"
>> -		return 2
>> +		jitdump_incl_dir="${script_dir}/../../util"
>> +		jitdump_h="${jitdump_incl_dir}/jitdump.h"
>> +		if [ ! -e "${jitdump_h}" ] ; then
>> +			echo "SKIP: Include file jitdump.h not found"
>> +			return 2
>> +		fi
>>  	fi
>>  
>> +	echo "Using include file: ${jitdump_h}"
> 
> Shouldn't this appear only with -v?

Yes, but shell scripts do not process -v.  Instead all output is
suppressed by perf test unless -v is used.  So it should be OK?

> 
> - Arnaldo
> 
>> +
>>  	if [ -z "${have_jitdump_workload}" ] ; then
>>  		have_jitdump_workload=false
>>  		# Create a workload that uses self-modifying code and generates its own jitdump file
  
Adrian Hunter Oct. 17, 2022, 12:57 p.m. UTC | #6
On 14/10/22 20:28, Arnaldo Carvalho de Melo wrote:
> Em Fri, Oct 14, 2022 at 08:09:03PM +0300, Adrian Hunter escreveu:
>> Add a test for decoding self-modifying code using a jitdump file.
>>
>> The test creates a workload that uses self-modifying code and generates its
>> own jitdump file.  The result is processed with perf inject --jit and
>> checked for decoding errors.
>>
>> Note the test will fail without patch "perf inject: Fix GEN_ELF_TEXT_OFFSET
>> for jit" applied.
>>
>> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
>> ---
>>  tools/perf/tests/shell/test_intel_pt.sh | 162 ++++++++++++++++++++++++
>>  1 file changed, 162 insertions(+)
>>
>> diff --git a/tools/perf/tests/shell/test_intel_pt.sh b/tools/perf/tests/shell/test_intel_pt.sh
>> index 79dde57b561d..e0bf75981b9c 100755
>> --- a/tools/perf/tests/shell/test_intel_pt.sh
>> +++ b/tools/perf/tests/shell/test_intel_pt.sh
>> @@ -22,6 +22,7 @@ outfile="${temp_dir}/test-out.txt"
>>  errfile="${temp_dir}/test-err.txt"
>>  workload="${temp_dir}/workload"
>>  awkscript="${temp_dir}/awkscript"
>> +jitdump_workload="${temp_dir}/jitdump_workload"
>>  
>>  cleanup()
>>  {
>> @@ -50,6 +51,13 @@ perf_record_no_decode()
>>  	perf record -B -N --no-bpf-event "$@"
>>  }
>>  
>> +# perf record for testing should not need BPF events
>> +perf_record_no_bpf()
>> +{
>> +	# Options for no BPF events
>> +	perf record --no-bpf-event "$@"
>> +}
>> +
>>  have_workload=false
>>  cat << _end_of_file_ | /usr/bin/cc -o "${workload}" -xc - -pthread && have_workload=true
>>  #include <time.h>
>> @@ -269,6 +277,159 @@ test_per_thread()
>>  	return 0
>>  }
>>  
>> +test_jitdump()
>> +{
>> +	echo "--- Test tracing self-modifying code that uses jitdump ---"
>> +
>> +	script_path=$(realpath "$0")
>> +	script_dir=$(dirname "$script_path")
>> +	jitdump_incl_dir="${script_dir}/../../util"
>> +	jitdump_h="${jitdump_incl_dir}/jitdump.h"
> 
> So this requires one to test this being on the kernel (perf) sources
> dir? I think we should add this header to some 'perf test' directory to
> remove this requirement, ok?
> 

How about this:

From: Adrian Hunter <adrian.hunter@intel.com>
Date: Mon, 17 Oct 2022 15:14:25 +0300
Subject: [PATCH] perf test: test_intel_pt.sh: Install jitdump.h for use by
 tests

test_intel_pt.sh builds a workload for testing jitdump and the workload
includes file jitdump.h.

Currently, test_intel_pt.sh finds jitdump.h assuming the test is run in
the kernel source directory, and skips that test if it is not found.

To improve that situation, amend the build to install the jitdump.h file
in the test shell directory, and look there first, falling back to the
original way if that is not found.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/Makefile.perf                |  1 +
 tools/perf/tests/shell/test_intel_pt.sh | 12 +++++++++---
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index a432e59afc42..c4ec66194465 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -1013,6 +1013,7 @@ install-tests: all install-gtk
 		$(INSTALL) tests/attr/* -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell'; \
 		$(INSTALL) tests/shell/*.sh '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell'; \
+		$(INSTALL) util/jitdump.h -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell'; \
 		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \
 		$(INSTALL) tests/shell/lib/*.sh -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \
 		$(INSTALL) tests/shell/lib/*.py -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \
diff --git a/tools/perf/tests/shell/test_intel_pt.sh b/tools/perf/tests/shell/test_intel_pt.sh
index 4c0aabbe33bd..3abf803f96b9 100755
--- a/tools/perf/tests/shell/test_intel_pt.sh
+++ b/tools/perf/tests/shell/test_intel_pt.sh
@@ -284,14 +284,20 @@ test_jitdump()
 
 	script_path=$(realpath "$0")
 	script_dir=$(dirname "$script_path")
-	jitdump_incl_dir="${script_dir}/../../util"
+	jitdump_incl_dir="${script_dir}"
 	jitdump_h="${jitdump_incl_dir}/jitdump.h"
 
 	if [ ! -e "${jitdump_h}" ] ; then
-		echo "SKIP: Include file jitdump.h not found"
-		return 2
+		jitdump_incl_dir="${script_dir}/../../util"
+		jitdump_h="${jitdump_incl_dir}/jitdump.h"
+		if [ ! -e "${jitdump_h}" ] ; then
+			echo "SKIP: Include file jitdump.h not found"
+			return 2
+		fi
 	fi
 
+	echo "Using include file: ${jitdump_h}"
+
 	if [ -z "${have_jitdump_workload}" ] ; then
 		have_jitdump_workload=false
 		# Create a workload that uses self-modifying code and generates its own jitdump file
  
Arnaldo Carvalho de Melo Oct. 17, 2022, 1:44 p.m. UTC | #7
Em Mon, Oct 17, 2022 at 03:57:03PM +0300, Adrian Hunter escreveu:
> On 14/10/22 20:28, Arnaldo Carvalho de Melo wrote:
> > Em Fri, Oct 14, 2022 at 08:09:03PM +0300, Adrian Hunter escreveu:
> >> Add a test for decoding self-modifying code using a jitdump file.
> >>
> >> The test creates a workload that uses self-modifying code and generates its
> >> own jitdump file.  The result is processed with perf inject --jit and
> >> checked for decoding errors.
> >>
> >> Note the test will fail without patch "perf inject: Fix GEN_ELF_TEXT_OFFSET
> >> for jit" applied.
> >>
> >> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> >> ---
> >>  tools/perf/tests/shell/test_intel_pt.sh | 162 ++++++++++++++++++++++++
> >>  1 file changed, 162 insertions(+)
> >>
> >> diff --git a/tools/perf/tests/shell/test_intel_pt.sh b/tools/perf/tests/shell/test_intel_pt.sh
> >> index 79dde57b561d..e0bf75981b9c 100755
> >> --- a/tools/perf/tests/shell/test_intel_pt.sh
> >> +++ b/tools/perf/tests/shell/test_intel_pt.sh
> >> @@ -22,6 +22,7 @@ outfile="${temp_dir}/test-out.txt"
> >>  errfile="${temp_dir}/test-err.txt"
> >>  workload="${temp_dir}/workload"
> >>  awkscript="${temp_dir}/awkscript"
> >> +jitdump_workload="${temp_dir}/jitdump_workload"
> >>  
> >>  cleanup()
> >>  {
> >> @@ -50,6 +51,13 @@ perf_record_no_decode()
> >>  	perf record -B -N --no-bpf-event "$@"
> >>  }
> >>  
> >> +# perf record for testing should not need BPF events
> >> +perf_record_no_bpf()
> >> +{
> >> +	# Options for no BPF events
> >> +	perf record --no-bpf-event "$@"
> >> +}
> >> +
> >>  have_workload=false
> >>  cat << _end_of_file_ | /usr/bin/cc -o "${workload}" -xc - -pthread && have_workload=true
> >>  #include <time.h>
> >> @@ -269,6 +277,159 @@ test_per_thread()
> >>  	return 0
> >>  }
> >>  
> >> +test_jitdump()
> >> +{
> >> +	echo "--- Test tracing self-modifying code that uses jitdump ---"
> >> +
> >> +	script_path=$(realpath "$0")
> >> +	script_dir=$(dirname "$script_path")
> >> +	jitdump_incl_dir="${script_dir}/../../util"
> >> +	jitdump_h="${jitdump_incl_dir}/jitdump.h"
> > 
> > So this requires one to test this being on the kernel (perf) sources
> > dir? I think we should add this header to some 'perf test' directory to
> > remove this requirement, ok?
> > 
> 
> How about this:

Better, but see below
 
> From: Adrian Hunter <adrian.hunter@intel.com>
> Date: Mon, 17 Oct 2022 15:14:25 +0300
> Subject: [PATCH] perf test: test_intel_pt.sh: Install jitdump.h for use by
>  tests
> 
> test_intel_pt.sh builds a workload for testing jitdump and the workload
> includes file jitdump.h.
> 
> Currently, test_intel_pt.sh finds jitdump.h assuming the test is run in
> the kernel source directory, and skips that test if it is not found.
> 
> To improve that situation, amend the build to install the jitdump.h file
> in the test shell directory, and look there first, falling back to the
> original way if that is not found.
> 
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>  tools/perf/Makefile.perf                |  1 +
>  tools/perf/tests/shell/test_intel_pt.sh | 12 +++++++++---
>  2 files changed, 10 insertions(+), 3 deletions(-)
> 
> diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
> index a432e59afc42..c4ec66194465 100644
> --- a/tools/perf/Makefile.perf
> +++ b/tools/perf/Makefile.perf
> @@ -1013,6 +1013,7 @@ install-tests: all install-gtk
>  		$(INSTALL) tests/attr/* -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
>  		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell'; \
>  		$(INSTALL) tests/shell/*.sh '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell'; \
> +		$(INSTALL) util/jitdump.h -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell'; \
>  		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \
>  		$(INSTALL) tests/shell/lib/*.sh -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \
>  		$(INSTALL) tests/shell/lib/*.py -m 644 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/lib'; \
> diff --git a/tools/perf/tests/shell/test_intel_pt.sh b/tools/perf/tests/shell/test_intel_pt.sh
> index 4c0aabbe33bd..3abf803f96b9 100755
> --- a/tools/perf/tests/shell/test_intel_pt.sh
> +++ b/tools/perf/tests/shell/test_intel_pt.sh
> @@ -284,14 +284,20 @@ test_jitdump()
>  
>  	script_path=$(realpath "$0")
>  	script_dir=$(dirname "$script_path")
> -	jitdump_incl_dir="${script_dir}/../../util"
> +	jitdump_incl_dir="${script_dir}"
>  	jitdump_h="${jitdump_incl_dir}/jitdump.h"
>  
>  	if [ ! -e "${jitdump_h}" ] ; then
> -		echo "SKIP: Include file jitdump.h not found"
> -		return 2
> +		jitdump_incl_dir="${script_dir}/../../util"
> +		jitdump_h="${jitdump_incl_dir}/jitdump.h"
> +		if [ ! -e "${jitdump_h}" ] ; then
> +			echo "SKIP: Include file jitdump.h not found"
> +			return 2
> +		fi
>  	fi
>  
> +	echo "Using include file: ${jitdump_h}"

Shouldn't this appear only with -v?

- Arnaldo

> +
>  	if [ -z "${have_jitdump_workload}" ] ; then
>  		have_jitdump_workload=false
>  		# Create a workload that uses self-modifying code and generates its own jitdump file
  

Patch

diff --git a/tools/perf/tests/shell/test_intel_pt.sh b/tools/perf/tests/shell/test_intel_pt.sh
index 79dde57b561d..e0bf75981b9c 100755
--- a/tools/perf/tests/shell/test_intel_pt.sh
+++ b/tools/perf/tests/shell/test_intel_pt.sh
@@ -22,6 +22,7 @@  outfile="${temp_dir}/test-out.txt"
 errfile="${temp_dir}/test-err.txt"
 workload="${temp_dir}/workload"
 awkscript="${temp_dir}/awkscript"
+jitdump_workload="${temp_dir}/jitdump_workload"
 
 cleanup()
 {
@@ -50,6 +51,13 @@  perf_record_no_decode()
 	perf record -B -N --no-bpf-event "$@"
 }
 
+# perf record for testing should not need BPF events
+perf_record_no_bpf()
+{
+	# Options for no BPF events
+	perf record --no-bpf-event "$@"
+}
+
 have_workload=false
 cat << _end_of_file_ | /usr/bin/cc -o "${workload}" -xc - -pthread && have_workload=true
 #include <time.h>
@@ -269,6 +277,159 @@  test_per_thread()
 	return 0
 }
 
+test_jitdump()
+{
+	echo "--- Test tracing self-modifying code that uses jitdump ---"
+
+	script_path=$(realpath "$0")
+	script_dir=$(dirname "$script_path")
+	jitdump_incl_dir="${script_dir}/../../util"
+	jitdump_h="${jitdump_incl_dir}/jitdump.h"
+
+	if [ ! -e "${jitdump_h}" ] ; then
+		echo "SKIP: Include file jitdump.h not found"
+		return 2
+	fi
+
+	if [ -z "${have_jitdump_workload}" ] ; then
+		have_jitdump_workload=false
+		# Create a workload that uses self-modifying code and generates its own jitdump file
+		cat <<- "_end_of_file_" | /usr/bin/cc -o "${jitdump_workload}" -I "${jitdump_incl_dir}" -xc - -pthread && have_jitdump_workload=true
+		#define _GNU_SOURCE
+		#include <sys/mman.h>
+		#include <sys/types.h>
+		#include <stddef.h>
+		#include <stdio.h>
+		#include <stdint.h>
+		#include <unistd.h>
+		#include <string.h>
+
+		#include "jitdump.h"
+
+		#define CHK_BYTE 0x5a
+
+		static inline uint64_t rdtsc(void)
+		{
+			unsigned int low, high;
+
+			asm volatile("rdtsc" : "=a" (low), "=d" (high));
+
+			return low | ((uint64_t)high) << 32;
+		}
+
+		static FILE *open_jitdump(void)
+		{
+			struct jitheader header = {
+				.magic      = JITHEADER_MAGIC,
+				.version    = JITHEADER_VERSION,
+				.total_size = sizeof(header),
+				.pid        = getpid(),
+				.timestamp  = rdtsc(),
+				.flags      = JITDUMP_FLAGS_ARCH_TIMESTAMP,
+			};
+			char filename[256];
+			FILE *f;
+			void *m;
+
+			snprintf(filename, sizeof(filename), "jit-%d.dump", getpid());
+			f = fopen(filename, "w+");
+			if (!f)
+				goto err;
+			/* Create an MMAP event for the jitdump file. That is how perf tool finds it. */
+			m = mmap(0, 4096, PROT_READ | PROT_EXEC, MAP_PRIVATE, fileno(f), 0);
+			if (m == MAP_FAILED)
+				goto err_close;
+			munmap(m, 4096);
+			if (fwrite(&header,sizeof(header),1,f) != 1)
+				goto err_close;
+			return f;
+
+		err_close:
+			fclose(f);
+		err:
+			return NULL;
+		}
+
+		static int write_jitdump(FILE *f, void *addr, const uint8_t *dat, size_t sz, uint64_t *idx)
+		{
+			struct jr_code_load rec = {
+				.p.id          = JIT_CODE_LOAD,
+				.p.total_size  = sizeof(rec) + sz,
+				.p.timestamp   = rdtsc(),
+				.pid	       = getpid(),
+				.tid	       = gettid(),
+				.vma           = (unsigned long)addr,
+				.code_addr     = (unsigned long)addr,
+				.code_size     = sz,
+				.code_index    = ++*idx,
+			};
+
+			if (fwrite(&rec,sizeof(rec),1,f) != 1 ||
+			fwrite(dat, sz, 1, f) != 1)
+				return -1;
+			return 0;
+		}
+
+		static void close_jitdump(FILE *f)
+		{
+			fclose(f);
+		}
+
+		int main()
+		{
+			/* Get a memory page to store executable code */
+			void *addr = mmap(0, 4096, PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+			/* Code to execute: mov CHK_BYTE, %eax ; ret */
+			uint8_t dat[] = {0xb8, CHK_BYTE, 0x00, 0x00, 0x00, 0xc3};
+			FILE *f = open_jitdump();
+			uint64_t idx = 0;
+			int ret = 1;
+
+			if (!f)
+				return 1;
+			/* Copy executable code to executable memory page */
+			memcpy(addr, dat, sizeof(dat));
+			/* Record it in the jitdump file */
+			if (write_jitdump(f, addr, dat, sizeof(dat), &idx))
+				goto out_close;
+			/* Call it */
+			ret = ((int (*)(void))addr)() - CHK_BYTE;
+		out_close:
+			close_jitdump(f);
+			return ret;
+		}
+		_end_of_file_
+	fi
+
+	if ! $have_jitdump_workload ; then
+		echo "SKIP: No jitdump workload"
+		return 2
+	fi
+
+	# Change to temp_dir so jitdump collateral files go there
+	cd "${temp_dir}"
+	perf_record_no_bpf -o "${tmpfile}" -e intel_pt//u "${jitdump_workload}"
+	perf inject -i "${tmpfile}" -o "${perfdatafile}" --jit
+	decode_br_cnt=$(perf script -i "${perfdatafile}" --itrace=b | wc -l)
+	# Note that overflow and lost errors are suppressed for the error count
+	decode_err_cnt=$(perf script -i "${perfdatafile}" --itrace=e-o-l | grep -ci error)
+	cd -
+	# Should be thousands of branches
+	if [ "${decode_br_cnt}" -lt 1000 ] ; then
+		echo "Decode failed, only ${decode_br_cnt} branches"
+		return 1
+	fi
+	# Should be no errors
+	if [ "${decode_err_cnt}" -ne 0 ] ; then
+		echo "Decode failed, ${decode_err_cnt} errors"
+		perf script -i "${perfdatafile}" --itrace=e-o-l
+		return 1
+	fi
+
+	echo OK
+	return 0
+}
+
 count_result()
 {
 	if [ "$1" -eq 2 ] ; then
@@ -286,6 +447,7 @@  ret=0
 test_system_wide_side_band		|| ret=$? ; count_result $ret ; ret=0
 test_per_thread "" ""			|| ret=$? ; count_result $ret ; ret=0
 test_per_thread "k" "(incl. kernel) "	|| ret=$? ; count_result $ret ; ret=0
+test_jitdump				|| ret=$? ; count_result $ret ; ret=0
 
 cleanup