mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

There are 43 instances of posix shell tests and 35 instances of bash. To give us a single consistent language for testing in, replace all #!/bin/sh to #!/bin/bash. Common sources that are included in both different shells will now work as expected. And we no longer have to fix up bashisms that appear to work when someone's system has sh symlinked to bash, but don't work on other systems that have both shells installed. Although we could have chosen sh, it's not backwards compatible so it wouldn't be possible to bulk convert without re-writing the existing bash tests. Choosing bash also gives us some nicer features including 'local' variable definitions and regexes in if statements that are already widely used in the tests. It's not expected that there are any users with only sh available due to the large number of bash tests that exist. Discussed in relation to running shellcheck here: https://lore.kernel.org/linux-perf-users/e3751a74be34bbf3781c4644f518702a7270220b.1749785642.git.collin.funk1@gmail.com/ Signed-off-by: James Clark <james.clark@linaro.org> Reviewed-by: Collin Funk <collin.funk1@gmail.com> Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com> Link: https://lore.kernel.org/r/20250623-james-perf-bash-tests-v1-1-f572f54d4559@linaro.org Signed-off-by: Namhyung Kim <namhyung@kernel.org>
721 lines
17 KiB
Bash
Executable file
721 lines
17 KiB
Bash
Executable file
#!/bin/bash
|
|
# Miscellaneous Intel PT testing (exclusive)
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
|
|
set -e
|
|
|
|
# Skip if no Intel PT
|
|
perf list pmu | grep -q 'intel_pt//' || exit 2
|
|
|
|
shelldir=$(dirname "$0")
|
|
# shellcheck source=lib/waiting.sh
|
|
. "${shelldir}"/lib/waiting.sh
|
|
|
|
skip_cnt=0
|
|
ok_cnt=0
|
|
err_cnt=0
|
|
|
|
temp_dir=$(mktemp -d /tmp/perf-test-intel-pt-sh.XXXXXXXXXX)
|
|
|
|
tmpfile="${temp_dir}/tmp-perf.data"
|
|
perfdatafile="${temp_dir}/test-perf.data"
|
|
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"
|
|
maxbrstack="${temp_dir}/maxbrstack.py"
|
|
|
|
cleanup()
|
|
{
|
|
trap - EXIT TERM INT
|
|
sane=$(echo "${temp_dir}" | cut -b 1-26)
|
|
if [ "${sane}" = "/tmp/perf-test-intel-pt-sh" ] ; then
|
|
echo "--- Cleaning up ---"
|
|
rm -f "${temp_dir}/"*
|
|
rmdir "${temp_dir}"
|
|
fi
|
|
}
|
|
|
|
trap_cleanup()
|
|
{
|
|
cleanup
|
|
exit 1
|
|
}
|
|
|
|
trap trap_cleanup EXIT TERM INT
|
|
|
|
# perf record for testing without decoding
|
|
perf_record_no_decode()
|
|
{
|
|
# Options to speed up recording: no post-processing, no build-id cache update,
|
|
# and no BPF events.
|
|
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>
|
|
#include <pthread.h>
|
|
|
|
void work(void) {
|
|
struct timespec tm = {
|
|
.tv_nsec = 1000000,
|
|
};
|
|
int i;
|
|
|
|
/* Run for about 30 seconds */
|
|
for (i = 0; i < 30000; i++)
|
|
nanosleep(&tm, NULL);
|
|
}
|
|
|
|
void *threadfunc(void *arg) {
|
|
work();
|
|
return NULL;
|
|
}
|
|
|
|
int main(void) {
|
|
pthread_t th;
|
|
|
|
pthread_create(&th, NULL, threadfunc, NULL);
|
|
work();
|
|
pthread_join(th, NULL);
|
|
return 0;
|
|
}
|
|
_end_of_file_
|
|
|
|
can_cpu_wide()
|
|
{
|
|
echo "Checking for CPU-wide recording on CPU $1"
|
|
if ! perf_record_no_decode -o "${tmpfile}" -e dummy:u -C "$1" true >/dev/null 2>&1 ; then
|
|
echo "No so skipping"
|
|
return 2
|
|
fi
|
|
echo OK
|
|
return 0
|
|
}
|
|
|
|
test_system_wide_side_band()
|
|
{
|
|
echo "--- Test system-wide sideband ---"
|
|
|
|
# Need CPU 0 and CPU 1
|
|
can_cpu_wide 0 || return $?
|
|
can_cpu_wide 1 || return $?
|
|
|
|
# Record on CPU 0 a task running on CPU 1
|
|
perf_record_no_decode -o "${perfdatafile}" -e intel_pt//u -C 0 -- taskset --cpu-list 1 uname
|
|
|
|
# Should get MMAP events from CPU 1 because they can be needed to decode
|
|
mmap_cnt=$(perf script -i "${perfdatafile}" --no-itrace --show-mmap-events -C 1 2>/dev/null | grep -c MMAP)
|
|
|
|
if [ "${mmap_cnt}" -gt 0 ] ; then
|
|
echo OK
|
|
return 0
|
|
fi
|
|
|
|
echo "Failed to record MMAP events on CPU 1 when tracing CPU 0"
|
|
return 1
|
|
}
|
|
|
|
can_kernel()
|
|
{
|
|
if [ -z "${can_kernel_trace}" ] ; then
|
|
can_kernel_trace=0
|
|
perf_record_no_decode -o "${tmpfile}" -e dummy:k true >/dev/null 2>&1 && can_kernel_trace=1
|
|
fi
|
|
if [ ${can_kernel_trace} -eq 0 ] ; then
|
|
echo "SKIP: no kernel tracing"
|
|
return 2
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
test_per_thread()
|
|
{
|
|
k="$1"
|
|
desc="$2"
|
|
|
|
echo "--- Test per-thread ${desc}recording ---"
|
|
|
|
if ! $have_workload ; then
|
|
echo "No workload, so skipping"
|
|
return 2
|
|
fi
|
|
|
|
if [ "${k}" = "k" ] ; then
|
|
can_kernel || return 2
|
|
fi
|
|
|
|
cat <<- "_end_of_file_" > "${awkscript}"
|
|
BEGIN {
|
|
s = "[ ]*"
|
|
u = s"[0-9]+"s
|
|
d = s"[0-9-]+"s
|
|
x = s"[0-9a-fA-FxX]+"s
|
|
mmapping = "idx"u": mmapping fd"u
|
|
set_output = "idx"u": set output fd"u"->"u
|
|
perf_event_open = "sys_perf_event_open: pid"d"cpu"d"group_fd"d"flags"x"="u
|
|
}
|
|
|
|
/perf record opening and mmapping events/ {
|
|
if (!done)
|
|
active = 1
|
|
}
|
|
|
|
/perf record done opening and mmapping events/ {
|
|
active = 0
|
|
done = 1
|
|
}
|
|
|
|
$0 ~ perf_event_open && active {
|
|
match($0, perf_event_open)
|
|
$0 = substr($0, RSTART, RLENGTH)
|
|
pid = $3
|
|
cpu = $5
|
|
fd = $11
|
|
print "pid " pid " cpu " cpu " fd " fd " : " $0
|
|
fd_array[fd] = fd
|
|
pid_array[fd] = pid
|
|
cpu_array[fd] = cpu
|
|
}
|
|
|
|
$0 ~ mmapping && active {
|
|
match($0, mmapping)
|
|
$0 = substr($0, RSTART, RLENGTH)
|
|
fd = $5
|
|
print "fd " fd " : " $0
|
|
if (fd in fd_array) {
|
|
mmap_array[fd] = 1
|
|
} else {
|
|
print "Unknown fd " fd
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
$0 ~ set_output && active {
|
|
match($0, set_output)
|
|
$0 = substr($0, RSTART, RLENGTH)
|
|
fd = $6
|
|
fd_to = $8
|
|
print "fd " fd " fd_to " fd_to " : " $0
|
|
if (fd in fd_array) {
|
|
if (fd_to in fd_array) {
|
|
set_output_array[fd] = fd_to
|
|
} else {
|
|
print "Unknown fd " fd_to
|
|
exit 1
|
|
}
|
|
} else {
|
|
print "Unknown fd " fd
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
END {
|
|
print "Checking " length(fd_array) " fds"
|
|
for (fd in fd_array) {
|
|
if (fd in mmap_array) {
|
|
pid = pid_array[fd]
|
|
if (pid != -1) {
|
|
if (pid in pids) {
|
|
print "More than 1 mmap for PID " pid
|
|
exit 1
|
|
}
|
|
pids[pid] = 1
|
|
}
|
|
cpu = cpu_array[fd]
|
|
if (cpu != -1) {
|
|
if (cpu in cpus) {
|
|
print "More than 1 mmap for CPU " cpu
|
|
exit 1
|
|
}
|
|
cpus[cpu] = 1
|
|
}
|
|
} else if (!(fd in set_output_array)) {
|
|
print "No mmap for fd " fd
|
|
exit 1
|
|
}
|
|
}
|
|
n = length(pids)
|
|
if (n != thread_cnt) {
|
|
print "Expected " thread_cnt " per-thread mmaps - found " n
|
|
exit 1
|
|
}
|
|
}
|
|
_end_of_file_
|
|
|
|
$workload &
|
|
w1=$!
|
|
$workload &
|
|
w2=$!
|
|
echo "Workload PIDs are $w1 and $w2"
|
|
wait_for_threads ${w1} 2
|
|
wait_for_threads ${w2} 2
|
|
|
|
perf_record_no_decode -o "${perfdatafile}" -e intel_pt//u"${k}" -vvv --per-thread -p "${w1},${w2}" 2>"${errfile}" >"${outfile}" &
|
|
ppid=$!
|
|
echo "perf PID is $ppid"
|
|
wait_for_perf_to_start ${ppid} "${errfile}" || return 1
|
|
|
|
kill ${w1}
|
|
wait_for_process_to_exit ${w1} || return 1
|
|
is_running ${ppid} || return 1
|
|
|
|
kill ${w2}
|
|
wait_for_process_to_exit ${w2} || return 1
|
|
wait_for_process_to_exit ${ppid} || return 1
|
|
|
|
awk -v thread_cnt=4 -f "${awkscript}" "${errfile}" || return 1
|
|
|
|
echo OK
|
|
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 ! perf check feature -q libelf ; then
|
|
echo "SKIP: libelf is needed for jitdump"
|
|
return 2
|
|
fi
|
|
|
|
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 --show-mmap-events | cat
|
|
return 1
|
|
fi
|
|
|
|
echo OK
|
|
return 0
|
|
}
|
|
|
|
test_packet_filter()
|
|
{
|
|
echo "--- Test with MTC and TSC disabled ---"
|
|
# Disable MTC and TSC
|
|
perf_record_no_decode -o "${perfdatafile}" -e intel_pt/mtc=0,tsc=0/u uname
|
|
# Should not get MTC packet
|
|
mtc_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "MTC 0x")
|
|
if [ "${mtc_cnt}" -ne 0 ] ; then
|
|
echo "Failed to filter with mtc=0"
|
|
return 1
|
|
fi
|
|
# Should not get TSC package
|
|
tsc_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "TSC 0x")
|
|
if [ "${tsc_cnt}" -ne 0 ] ; then
|
|
echo "Failed to filter with tsc=0"
|
|
return 1
|
|
fi
|
|
echo OK
|
|
return 0
|
|
}
|
|
|
|
test_disable_branch()
|
|
{
|
|
echo "--- Test with branches disabled ---"
|
|
# Disable branch
|
|
perf_record_no_decode -o "${perfdatafile}" -e intel_pt/branch=0/u uname
|
|
# Should not get branch related packets
|
|
tnt_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "TNT 0x")
|
|
tip_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "TIP 0x")
|
|
fup_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "FUP 0x")
|
|
if [ "${tnt_cnt}" -ne 0 ] || [ "${tip_cnt}" -ne 0 ] || [ "${fup_cnt}" -ne 0 ] ; then
|
|
echo "Failed to disable branches"
|
|
return 1
|
|
fi
|
|
echo OK
|
|
return 0
|
|
}
|
|
|
|
test_time_cyc()
|
|
{
|
|
echo "--- Test with/without CYC ---"
|
|
# Check if CYC is supported
|
|
cyc=$(cat /sys/bus/event_source/devices/intel_pt/caps/psb_cyc)
|
|
if [ "${cyc}" != "1" ] ; then
|
|
echo "SKIP: CYC is not supported"
|
|
return 2
|
|
fi
|
|
# Enable CYC
|
|
perf_record_no_decode -o "${perfdatafile}" -e intel_pt/cyc/u uname
|
|
# should get CYC packets
|
|
cyc_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "CYC 0x")
|
|
if [ "${cyc_cnt}" = "0" ] ; then
|
|
echo "Failed to get CYC packet"
|
|
return 1
|
|
fi
|
|
# Without CYC
|
|
perf_record_no_decode -o "${perfdatafile}" -e intel_pt//u uname
|
|
# Should not get CYC packets
|
|
cyc_cnt=$(perf script -i "${perfdatafile}" -D 2>/dev/null | grep -c "CYC 0x")
|
|
if [ "${cyc_cnt}" -gt 0 ] ; then
|
|
echo "Still get CYC packet without cyc"
|
|
return 1
|
|
fi
|
|
echo OK
|
|
return 0
|
|
}
|
|
|
|
test_sample()
|
|
{
|
|
echo "--- Test recording with sample mode ---"
|
|
# Check if recording with sample mode is working
|
|
if ! perf_record_no_decode -o "${perfdatafile}" --aux-sample=8192 -e '{intel_pt//u,branch-misses:u}' uname ; then
|
|
echo "perf record failed with --aux-sample"
|
|
return 1
|
|
fi
|
|
# Check with event with PMU name
|
|
if perf_record_no_decode -o "${perfdatafile}" -e br_misp_retired.all_branches:u uname ; then
|
|
if ! perf_record_no_decode -o "${perfdatafile}" -e '{intel_pt//,br_misp_retired.all_branches/aux-sample-size=8192/}:u' uname ; then
|
|
echo "perf record failed with --aux-sample-size"
|
|
return 1
|
|
fi
|
|
fi
|
|
echo OK
|
|
return 0
|
|
}
|
|
|
|
test_kernel_trace()
|
|
{
|
|
echo "--- Test with kernel trace ---"
|
|
# Check if recording with kernel trace is working
|
|
can_kernel || return 2
|
|
if ! perf_record_no_decode -o "${perfdatafile}" -e intel_pt//k -m1,128 uname ; then
|
|
echo "perf record failed with intel_pt//k"
|
|
return 1
|
|
fi
|
|
echo OK
|
|
return 0
|
|
}
|
|
|
|
test_virtual_lbr()
|
|
{
|
|
echo "--- Test virtual LBR ---"
|
|
# Check if python script is supported
|
|
libpython=$(perf version --build-options | grep python | grep -cv OFF)
|
|
if [ "${libpython}" != "1" ] ; then
|
|
echo "SKIP: python scripting is not supported"
|
|
return 2
|
|
fi
|
|
|
|
# Python script to determine the maximum size of branch stacks
|
|
cat << "_end_of_file_" > "${maxbrstack}"
|
|
from __future__ import print_function
|
|
|
|
bmax = 0
|
|
|
|
def process_event(param_dict):
|
|
if "brstack" in param_dict:
|
|
brstack = param_dict["brstack"]
|
|
n = len(brstack)
|
|
global bmax
|
|
if n > bmax:
|
|
bmax = n
|
|
|
|
def trace_end():
|
|
print("max brstack", bmax)
|
|
_end_of_file_
|
|
|
|
# Check if virtual lbr is working
|
|
perf_record_no_bpf -o "${perfdatafile}" --aux-sample -e '{intel_pt//,cycles}:u' uname
|
|
times_val=$(perf script -i "${perfdatafile}" --itrace=L -s "${maxbrstack}" 2>/dev/null | grep "max brstack " | cut -d " " -f 3)
|
|
case "${times_val}" in
|
|
[0-9]*) ;;
|
|
*) times_val=0;;
|
|
esac
|
|
if [ "${times_val}" -lt 2 ] ; then
|
|
echo "Failed with virtual lbr"
|
|
return 1
|
|
fi
|
|
echo OK
|
|
return 0
|
|
}
|
|
|
|
test_power_event()
|
|
{
|
|
echo "--- Test power events ---"
|
|
# Check if power events are supported
|
|
power_event=$(cat /sys/bus/event_source/devices/intel_pt/caps/power_event_trace)
|
|
if [ "${power_event}" != "1" ] ; then
|
|
echo "SKIP: power_event_trace is not supported"
|
|
return 2
|
|
fi
|
|
if ! perf_record_no_decode -o "${perfdatafile}" -a -e intel_pt/pwr_evt/u uname ; then
|
|
echo "perf record failed with pwr_evt"
|
|
return 1
|
|
fi
|
|
echo OK
|
|
return 0
|
|
}
|
|
|
|
test_no_tnt()
|
|
{
|
|
echo "--- Test with TNT packets disabled ---"
|
|
# Check if TNT disable is supported
|
|
notnt=$(cat /sys/bus/event_source/devices/intel_pt/caps/tnt_disable)
|
|
if [ "${notnt}" != "1" ] ; then
|
|
echo "SKIP: tnt_disable is not supported"
|
|
return 2
|
|
fi
|
|
perf_record_no_decode -o "${perfdatafile}" -e intel_pt/notnt/u uname
|
|
# Should be no TNT packets
|
|
tnt_cnt=$(perf script -i "${perfdatafile}" -D | grep -c TNT)
|
|
if [ "${tnt_cnt}" -ne 0 ] ; then
|
|
echo "TNT packets still there after notnt"
|
|
return 1
|
|
fi
|
|
echo OK
|
|
return 0
|
|
}
|
|
|
|
test_event_trace()
|
|
{
|
|
echo "--- Test with event_trace ---"
|
|
# Check if event_trace is supported
|
|
event_trace=$(cat /sys/bus/event_source/devices/intel_pt/caps/event_trace)
|
|
if [ "${event_trace}" != 1 ] ; then
|
|
echo "SKIP: event_trace is not supported"
|
|
return 2
|
|
fi
|
|
if ! perf_record_no_decode -o "${perfdatafile}" -e intel_pt/event/u uname ; then
|
|
echo "perf record failed with event trace"
|
|
return 1
|
|
fi
|
|
echo OK
|
|
return 0
|
|
}
|
|
|
|
test_pipe()
|
|
{
|
|
echo "--- Test with pipe mode ---"
|
|
# Check if it works with pipe
|
|
if ! perf_record_no_bpf -o- -e intel_pt//u uname | perf report -q -i- --itrace=i10000 ; then
|
|
echo "perf record + report failed with pipe mode"
|
|
return 1
|
|
fi
|
|
if ! perf_record_no_bpf -o- -e intel_pt//u uname | perf inject -b > /dev/null ; then
|
|
echo "perf record + inject failed with pipe mode"
|
|
return 1
|
|
fi
|
|
echo OK
|
|
return 0
|
|
}
|
|
|
|
test_pause_resume()
|
|
{
|
|
echo "--- Test with pause / resume ---"
|
|
if ! perf_record_no_decode -o "${perfdatafile}" -e intel_pt/aux-action=start-paused/u uname ; then
|
|
echo "SKIP: pause / resume is not supported"
|
|
return 2
|
|
fi
|
|
if ! perf_record_no_bpf -o "${perfdatafile}" \
|
|
-e intel_pt/aux-action=start-paused/u \
|
|
-e instructions/period=50000,aux-action=resume,name=Resume/u \
|
|
-e instructions/period=100000,aux-action=pause,name=Pause/u uname ; then
|
|
echo "perf record with pause / resume failed"
|
|
return 1
|
|
fi
|
|
if ! perf script -i "${perfdatafile}" --itrace=b -Fperiod,event | \
|
|
awk 'BEGIN {paused=1;branches=0}
|
|
/Resume/ {paused=0}
|
|
/branches/ {if (paused) exit 1;branches=1}
|
|
/Pause/ {paused=1}
|
|
END {if (!branches) exit 1}' ; then
|
|
echo "perf record with pause / resume failed"
|
|
return 1
|
|
fi
|
|
echo OK
|
|
return 0
|
|
}
|
|
|
|
count_result()
|
|
{
|
|
if [ "$1" -eq 2 ] ; then
|
|
skip_cnt=$((skip_cnt + 1))
|
|
return
|
|
fi
|
|
if [ "$1" -eq 0 ] ; then
|
|
ok_cnt=$((ok_cnt + 1))
|
|
return
|
|
fi
|
|
err_cnt=$((err_cnt + 1))
|
|
}
|
|
|
|
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
|
|
test_packet_filter || ret=$? ; count_result $ret ; ret=0
|
|
test_disable_branch || ret=$? ; count_result $ret ; ret=0
|
|
test_time_cyc || ret=$? ; count_result $ret ; ret=0
|
|
test_sample || ret=$? ; count_result $ret ; ret=0
|
|
test_kernel_trace || ret=$? ; count_result $ret ; ret=0
|
|
test_virtual_lbr || ret=$? ; count_result $ret ; ret=0
|
|
test_power_event || ret=$? ; count_result $ret ; ret=0
|
|
test_no_tnt || ret=$? ; count_result $ret ; ret=0
|
|
test_event_trace || ret=$? ; count_result $ret ; ret=0
|
|
test_pipe || ret=$? ; count_result $ret ; ret=0
|
|
test_pause_resume || ret=$? ; count_result $ret ; ret=0
|
|
|
|
cleanup
|
|
|
|
echo "--- Done ---"
|
|
|
|
if [ ${err_cnt} -gt 0 ] ; then
|
|
exit 1
|
|
fi
|
|
|
|
if [ ${ok_cnt} -gt 0 ] ; then
|
|
exit 0
|
|
fi
|
|
|
|
exit 2
|