Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
#!/bin/bash
# test addr2line inline unwinding
# SPDX-License-Identifier: GPL-2.0
set -e
err=0
test_dir=$(mktemp -d /tmp/perf-test-inline-addr2line.XXXXXXXXXX)
perf_data="${test_dir}/perf.data"
perf_script_txt="${test_dir}/perf_script.txt"
cleanup() {
rm -rf "${test_dir}"
trap - EXIT TERM INT
}
trap_cleanup() {
echo "Unexpected signal in ${FUNCNAME[1]}"
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
test_fp() {
echo "Inline unwinding fp verification test"
# Record data. Currently only dwarf callchains support inlined functions.
perf record --call-graph fp -e task-clock:u -o "${perf_data}" -- perf test -w inlineloop 1
# Check output with inline (default) and srcline
perf script -i "${perf_data}" --fields +srcline > "${perf_script_txt}"
# Expect the leaf and middle functions to occur on lines in the 20s, with
# the non-inlined parent function on a line in the 30s.
if grep -q "inlineloop.c:2. (inlined)" "${perf_script_txt}" &&
grep -q "inlineloop.c:3.$" "${perf_script_txt}"
then
echo "Inline unwinding fp verification test [Success]"
else
echo "Inline unwinding fp verification test [Failed missing inlined functions]"
err=1
fi
}
test_dwarf() {
echo "Inline unwinding dwarf verification test"
# Record data. Currently only dwarf callchains support inlined functions.
perf record --call-graph dwarf -e task-clock:u -o "${perf_data}" -- perf test -w inlineloop 1
# Check output with inline (default) and srcline
perf script -i "${perf_data}" --fields +srcline > "${perf_script_txt}"
# Expect the leaf and middle functions to occur on lines in the 20s, with
# the non-inlined parent function on a line in the 30s.
if grep -q "inlineloop.c:2. (inlined)" "${perf_script_txt}" &&
grep -q "inlineloop.c:3.$" "${perf_script_txt}"
then
echo "Inline unwinding dwarf verification test [Success]"
else
echo "Inline unwinding dwarf verification test [Failed missing inlined functions]"
err=1
fi
}
test_lbr() {
echo "Inline unwinding LBR verification test"
if [ ! -f /sys/bus/event_source/devices/cpu/caps/branches ] &&
[ ! -f /sys/bus/event_source/devices/cpu_core/caps/branches ]
then
echo "Skip: only x86 CPUs support LBR"
return
fi
# Record data. Currently only dwarf callchains support inlined functions.
perf record --call-graph lbr -e cycles:u -o "${perf_data}" -- perf test -w inlineloop 1
# Check output with inline (default) and srcline
perf script -i "${perf_data}" --fields +srcline > "${perf_script_txt}"
# Expect the leaf and middle functions to occur on lines in the 20s, with
# the non-inlined parent function on a line in the 30s.
if grep -q "inlineloop.c:2. (inlined)" "${perf_script_txt}" &&
grep -q "inlineloop.c:3.$" "${perf_script_txt}"
then
echo "Inline unwinding lbr verification test [Success]"
else
echo "Inline unwinding lbr verification test [Failed missing inlined functions]"
err=1
fi
}
test_fp
test_dwarf
test_lbr
cleanup
exit $err
+121
View File
@@ -0,0 +1,121 @@
#!/bin/bash
# AMD IBS software filtering
cpu_family() {
grep -m1 '^cpu family[[:space:]]*:' /proc/cpuinfo \
| awk -F: '{gsub(/^[ \t]+/, "", $2); print $2}'
}
cpu_model() {
grep -m1 '^model[[:space:]]*:' /proc/cpuinfo \
| awk -F: '{gsub(/^[ \t]+/, "", $2); print $2}'
}
# IBS PMUs does not advertize privilege filtering capability. Rely
# on Family / Model check.
hw_priv_filter_supported() {
family=$(cpu_family)
model=$(cpu_model)
if (( family > 0x1a )) ||
{ (( family == 0x1a )) &&
{ { (( model >= 0x50 && model <= 0x5f )) ||
(( model >= 0x80 && model <= 0xaf )) ||
(( model >= 0xc0 && model <= 0xcf )); }; }; }; then
return 0 # True
else
return 1 # False
fi
}
ParanoidAndNotRoot() {
[ "$(id -u)" != 0 ] && [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt $1 ]
}
echo "check availability of IBS swfilt"
# check if IBS PMU is available
if [ ! -d /sys/bus/event_source/devices/ibs_op ]; then
echo "[SKIP] IBS PMU does not exist"
exit 2
fi
# check if IBS PMU has swfilt format
if [ ! -f /sys/bus/event_source/devices/ibs_op/format/swfilt ]; then
echo "[SKIP] IBS PMU does not have swfilt"
exit 2
fi
echo "run perf record with modifier and swfilt"
err=0
# setting any modifiers should fail
if ! hw_priv_filter_supported; then
perf record -B -e ibs_op//u -o /dev/null true 2> /dev/null
if [ $? -eq 0 ]; then
echo "[FAIL] IBS PMU should not accept exclude_kernel"
exit 1
fi
fi
# setting it with swfilt should be fine
perf record -B -e ibs_op/swfilt/u -o /dev/null true
if [ $? -ne 0 ]; then
echo "[FAIL] IBS op PMU cannot handle swfilt for exclude_kernel"
exit 1
fi
if ! ParanoidAndNotRoot 1
then
# setting it with swfilt=1 should be fine
perf record -B -e ibs_op/swfilt=1/k -o /dev/null true
if [ $? -ne 0 ]; then
echo "[FAIL] IBS op PMU cannot handle swfilt for exclude_user"
exit 1
fi
else
echo "[SKIP] not root and perf_event_paranoid too high for exclude_user"
err=2
fi
# check ibs_fetch PMU as well
perf record -B -e ibs_fetch/swfilt/u -o /dev/null true
if [ $? -ne 0 ]; then
echo "[FAIL] IBS fetch PMU cannot handle swfilt for exclude_kernel"
exit 1
fi
# check system wide recording
if ! ParanoidAndNotRoot 0
then
perf record -aB --synth=no -e ibs_op/swfilt/k -o /dev/null true
if [ $? -ne 0 ]; then
echo "[FAIL] IBS op PMU cannot handle swfilt in system-wide mode"
exit 1
fi
else
echo "[SKIP] not root and perf_event_paranoid too high for system-wide/exclude_user"
err=2
fi
echo "check number of samples with swfilt"
kernel_sample=$(perf record -e ibs_op/swfilt/u -o- true | perf script -i- -F misc | grep -c ^K)
if [ ${kernel_sample} -ne 0 ]; then
echo "[FAIL] unexpected kernel samples: " ${kernel_sample}
exit 1
fi
if ! ParanoidAndNotRoot 1
then
user_sample=$(perf record -e ibs_fetch/swfilt/k -o- true | perf script -i- -F misc | grep -c ^U)
if [ ${user_sample} -ne 0 ]; then
echo "[FAIL] unexpected user samples: " ${user_sample}
exit 1
fi
else
echo "[SKIP] not root and perf_event_paranoid too high for exclude_user"
err=2
fi
exit $err
+113
View File
@@ -0,0 +1,113 @@
#!/bin/bash
# perf annotate basic tests
# SPDX-License-Identifier: GPL-2.0
set -e
shelldir=$(dirname "$0")
# shellcheck source=lib/perf_has_symbol.sh
. "${shelldir}"/lib/perf_has_symbol.sh
testsym="noploop"
skip_test_missing_symbol ${testsym}
err=0
perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
perfout=$(mktemp /tmp/__perf_test.perf.out.XXXXX)
testprog="perf test -w noploop"
# disassembly format: "percent : offset: instruction (operands ...)"
disasm_regex="[0-9]*\.[0-9]* *: *\w*: *\w*"
cleanup() {
rm -rf "${perfdata}" "${perfout}"
rm -rf "${perfdata}".old
trap - EXIT TERM INT
}
trap_cleanup() {
echo "Unexpected signal in ${FUNCNAME[1]}"
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
test_basic() {
mode=$1
echo "${mode} perf annotate test"
if [ "x${mode}" == "xBasic" ]
then
perf record -o "${perfdata}" ${testprog} 2> /dev/null
else
perf record -o - ${testprog} 2> /dev/null > "${perfdata}"
fi
if [ "x$?" != "x0" ]
then
echo "${mode} annotate [Failed: perf record]"
err=1
return
fi
# Generate the annotated output file
if [ "x${mode}" == "xBasic" ]
then
perf annotate --no-demangle -i "${perfdata}" --stdio --percent-limit 10 2> /dev/null > "${perfout}"
else
perf annotate --no-demangle -i - --stdio 2> /dev/null --percent-limit 10 < "${perfdata}" > "${perfout}"
fi
# check if it has the target symbol
if ! grep -q "${testsym}" "${perfout}"
then
echo "${mode} annotate [Failed: missing target symbol]"
cat "${perfout}"
err=1
return
fi
# check if it has the disassembly lines
if ! grep -q "${disasm_regex}" "${perfout}"
then
echo "${mode} annotate [Failed: missing disasm output from default disassembler]"
err=1
return
fi
# check again with a target symbol name
if [ "x${mode}" == "xBasic" ]
then
perf annotate --no-demangle -i "${perfdata}" "${testsym}" 2> /dev/null > "${perfout}"
else
perf annotate --no-demangle -i - "${testsym}" 2> /dev/null < "${perfdata}" > "${perfout}"
fi
if ! head -250 "${perfout}"| grep -q -m 3 "${disasm_regex}"
then
echo "${mode} annotate [Failed: missing disasm output when specifying the target symbol]"
err=1
return
fi
# check one more with external objdump tool (forced by --objdump option)
if [ "x${mode}" == "xBasic" ]
then
perf annotate --no-demangle -i "${perfdata}" --percent-limit 10 --objdump=objdump 2> /dev/null > "${perfout}"
else
perf annotate --no-demangle -i - "${testsym}" --percent-limit 10 --objdump=objdump 2> /dev/null < "${perfdata}" > "${perfout}"
fi
if ! grep -q -m 3 "${disasm_regex}" "${perfout}"
then
echo "${mode} annotate [Failed: missing disasm output from non default disassembler (using --objdump)]"
err=1
return
fi
echo "${mode} annotate test [Success]"
}
test_basic Basic
test_basic Pipe
cleanup
exit $err
+22
View File
@@ -0,0 +1,22 @@
#!/bin/bash
# Perf attribute expectations test
# SPDX-License-Identifier: GPL-2.0
err=0
cleanup() {
trap - EXIT TERM INT
}
trap_cleanup() {
echo "Unexpected signal in ${FUNCNAME[1]}"
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
shelldir=$(dirname "$0")
perf_path=$(which perf)
python "${shelldir}"/lib/attr.py -d "${shelldir}"/attr -v -p "$perf_path"
cleanup
exit $err
@@ -0,0 +1,71 @@
The struct perf_event_attr test (attr tests) support
====================================================
This testing support is embedded into perf directly and is governed
by the PERF_TEST_ATTR environment variable and hook inside the
sys_perf_event_open function.
The general idea is to store 'struct perf_event_attr' details for
each event created within single perf command. Each event details
are stored into separate text file. Once perf command is finished
these files are checked for values we expect for command.
The attr tests consist of following parts:
tests/attr.c
------------
This is the sys_perf_event_open hook implementation. The hook
is triggered when the PERF_TEST_ATTR environment variable is
defined. It must contain name of existing directory with access
and write permissions.
For each sys_perf_event_open call event details are stored in
separate file. Besides 'struct perf_event_attr' values we also
store 'fd' and 'group_fd' values to allow checking for groups.
tests/attr.py
-------------
This is the python script that does all the hard work. It reads
the test definition, executes it and checks results.
tests/attr/
-----------
Directory containing all attr test definitions.
Following tests are defined (with perf commands):
perf record kill (test-record-basic)
perf record -b kill (test-record-branch-any)
perf record -j any kill (test-record-branch-filter-any)
perf record -j any_call kill (test-record-branch-filter-any_call)
perf record -j any_ret kill (test-record-branch-filter-any_ret)
perf record -j hv kill (test-record-branch-filter-hv)
perf record -j ind_call kill (test-record-branch-filter-ind_call)
perf record -j k kill (test-record-branch-filter-k)
perf record -j u kill (test-record-branch-filter-u)
perf record -c 123 kill (test-record-count)
perf record -d kill (test-record-data)
perf record -F 100 kill (test-record-freq)
perf record -g kill (test-record-graph-default)
perf record -g kill (test-record-graph-default-aarch64)
perf record --call-graph dwarf kill (test-record-graph-dwarf)
perf record --call-graph fp kill (test-record-graph-fp)
perf record --call-graph fp kill (test-record-graph-fp-aarch64)
perf record -e '{cycles,instructions}' kill (test-record-group1)
perf record -e '{cycles/period=1/,instructions/period=2/}:S' kill (test-record-group2)
perf record -e '{cycles,cache-misses}:S' kill (test-record-group-sampling1)
perf record -c 10000 -e '{cycles,cache-misses}:S' kill (test-record-group-sampling2)
perf record -D kill (test-record-no-delay)
perf record -i kill (test-record-no-inherit)
perf record -n kill (test-record-no-samples)
perf record -c 100 -P kill (test-record-period)
perf record -c 1 --pfm-events=cycles:period=2 (test-record-pfm-period)
perf record -R kill (test-record-raw)
perf record -c 2 -e arm_spe_0// -- kill (test-record-spe-period)
perf record -e arm_spe_0/period=3/ -- kill (test-record-spe-period-term)
perf record -e arm_spe_0/pa_enable=1/ -- kill (test-record-spe-physical-address)
perf stat -e cycles kill (test-stat-basic)
perf stat kill (test-stat-default)
perf stat -d kill (test-stat-detailed-1)
perf stat -dd kill (test-stat-detailed-2)
perf stat -ddd kill (test-stat-detailed-3)
perf stat -e '{cycles,instructions}' kill (test-stat-group1)
perf stat -i -e cycles kill (test-stat-no-inherit)
@@ -0,0 +1,41 @@
[event]
fd=1
group_fd=-1
# 0 or PERF_FLAG_FD_CLOEXEC flag
flags=0|8
cpu=*
type=0|1
size=136
config=0|1
sample_period=*
sample_type=263
read_format=0|4|20
disabled=1
inherit=1
pinned=0
exclusive=0
exclude_user=0
exclude_kernel=0|1
exclude_hv=0|1
exclude_idle=0
mmap=1
comm=1
freq=1
inherit_stat=0
enable_on_exec=1
task=1
watermark=0
precise_ip=0|1|2|3
mmap_data=0
sample_id_all=1
exclude_host=0|1
exclude_guest=0|1
exclude_callchain_kernel=0
exclude_callchain_user=0
wakeup_events=0
bp_type=0
config1=0
config2=0
branch_sample_type=0
sample_regs_user=0
sample_stack_user=0
@@ -0,0 +1,40 @@
[event]
fd=*
group_fd=-1
flags=*
cpu=*
type=*
size=*
config=*
sample_period=*
sample_type=*
read_format=*
disabled=*
inherit=*
pinned=*
exclusive=*
exclude_user=*
exclude_kernel=*
exclude_hv=*
exclude_idle=*
mmap=*
comm=*
freq=*
inherit_stat=*
enable_on_exec=*
task=*
watermark=*
precise_ip=*
mmap_data=*
sample_id_all=*
exclude_host=*
exclude_guest=*
exclude_callchain_kernel=*
exclude_callchain_user=*
wakeup_events=*
bp_type=*
config1=*
config2=*
branch_sample_type=*
sample_regs_user=*
sample_stack_user=*
@@ -0,0 +1,41 @@
[event]
fd=1
group_fd=-1
# 0 or PERF_FLAG_FD_CLOEXEC flag
flags=0|8
cpu=*
type=0
size=136
config=0
sample_period=0
sample_type=65536
read_format=3
disabled=1
inherit=1
pinned=0
exclusive=0
exclude_user=0
exclude_kernel=0|1
exclude_hv=0|1
exclude_idle=0
mmap=0
comm=0
freq=0
inherit_stat=0
enable_on_exec=1
task=0
watermark=0
precise_ip=0
mmap_data=0
sample_id_all=0
exclude_host=0|1
exclude_guest=0|1
exclude_callchain_kernel=0
exclude_callchain_user=0
wakeup_events=0
bp_type=0
config1=0
config2=0
branch_sample_type=0
sample_regs_user=0
sample_stack_user=0
@@ -0,0 +1,52 @@
# Event added by system-wide or CPU perf-record to handle the race of
# processes starting while /proc is processed.
[event]
fd=1
group_fd=-1
cpu=*
pid=-1
flags=8
type=1
size=136
config=9
sample_period=1
# PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME |
# PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER
sample_type=65671
read_format=4|20
# Event will be enabled right away.
disabled=0
inherit=1
pinned=0
exclusive=0
exclude_user=0
exclude_kernel=1
exclude_hv=1
exclude_idle=0
mmap=1
comm=1
freq=0
inherit_stat=0
enable_on_exec=0
task=1
watermark=0
precise_ip=0
mmap_data=0
sample_id_all=1
exclude_host=0
exclude_guest=1
exclude_callchain_kernel=0
exclude_callchain_user=0
mmap2=1
comm_exec=1
context_switch=0
write_backward=0
namespaces=0
use_clockid=0
wakeup_events=0
bp_type=0
config1=0
config2=0
branch_sample_type=0
sample_regs_user=0
sample_stack_user=0
@@ -0,0 +1,24 @@
[config]
command = record
args = --no-bpf-event -C 0 kill >/dev/null 2>&1
ret = 1
[event:base-record]
cpu=0
# no enable on exec for CPU attached
enable_on_exec=0
# PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME |
# PERF_SAMPLE_PERIOD | PERF_SAMPLE_IDENTIFIER
# + PERF_SAMPLE_CPU added by -C 0
sample_type=65927
# Dummy event handles mmaps, comm and task.
mmap=0
comm=0
task=0
inherit=0
[event:system-wide-dummy]
inherit=0
@@ -0,0 +1,6 @@
[config]
command = record
args = --no-bpf-event kill >/dev/null 2>&1
ret = 1
[event:base-record]
@@ -0,0 +1,8 @@
[config]
command = record
args = --no-bpf-event -b kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_type=2311
branch_sample_type=8
@@ -0,0 +1,8 @@
[config]
command = record
args = --no-bpf-event -j any kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_type=2311
branch_sample_type=8
@@ -0,0 +1,8 @@
[config]
command = record
args = --no-bpf-event -j any_call kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_type=2311
branch_sample_type=16
@@ -0,0 +1,8 @@
[config]
command = record
args = --no-bpf-event -j any_ret kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_type=2311
branch_sample_type=32
@@ -0,0 +1,8 @@
[config]
command = record
args = --no-bpf-event -j hv kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_type=2311
branch_sample_type=8
@@ -0,0 +1,8 @@
[config]
command = record
args = --no-bpf-event -j ind_call kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_type=2311
branch_sample_type=64
@@ -0,0 +1,8 @@
[config]
command = record
args = --no-bpf-event -j k kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_type=2311
branch_sample_type=8
@@ -0,0 +1,8 @@
[config]
command = record
args = --no-bpf-event -j u kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_type=2311
branch_sample_type=8
@@ -0,0 +1,9 @@
[config]
command = record
args = --no-bpf-event -c 123 kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_period=123
sample_type=7
freq=0
@@ -0,0 +1,10 @@
[config]
command = record
args = --no-bpf-event -d kill >/dev/null 2>&1
ret = 1
[event:base-record]
# sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME |
# PERF_SAMPLE_ADDR | PERF_SAMPLE_PERIOD | PERF_SAMPLE_DATA_SRC
sample_type=33039
mmap_data=1
@@ -0,0 +1,55 @@
[config]
command = record
args = --no-bpf-event -e dummy -C 0 kill >/dev/null 2>&1
ret = 1
[event]
fd=1
group_fd=-1
cpu=0
pid=-1
flags=8
type=1
size=136
config=9
sample_period=4000
# PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME |
# PERF_SAMPLE_PERIOD
# + PERF_SAMPLE_CPU added by -C 0
sample_type=391
read_format=4|20
disabled=0
inherit=0
pinned=0
exclusive=0
exclude_user=0
exclude_kernel=0
exclude_hv=0
exclude_idle=0
mmap=1
comm=1
freq=1
inherit_stat=0
enable_on_exec=0
task=1
watermark=0
precise_ip=0
mmap_data=0
sample_id_all=1
exclude_host=0
exclude_guest=0
exclude_callchain_kernel=0
exclude_callchain_user=0
mmap2=1
comm_exec=1
context_switch=0
write_backward=0
namespaces=0
use_clockid=0
wakeup_events=0
bp_type=0
config1=0
config2=0
branch_sample_type=0
sample_regs_user=0
sample_stack_user=0
@@ -0,0 +1,7 @@
[config]
command = record
args = --no-bpf-event -F 100 kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_period=100
@@ -0,0 +1,9 @@
[config]
command = record
args = --no-bpf-event -g kill >/dev/null 2>&1
ret = 1
# arm64 enables registers in the default mode (fp)
arch = !aarch64
[event:base-record]
sample_type=295
@@ -0,0 +1,9 @@
[config]
command = record
args = --no-bpf-event -g kill >/dev/null 2>&1
ret = 1
arch = aarch64
[event:base-record]
sample_type=4391
sample_regs_user=1073741824
@@ -0,0 +1,12 @@
[config]
command = record
args = --no-bpf-event --call-graph dwarf -- kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_type=45359
exclude_callchain_user=1
sample_stack_user=8192
# TODO different for each arch, no support for that now
sample_regs_user=*
mmap_data=1
@@ -0,0 +1,9 @@
[config]
command = record
args = --no-bpf-event --call-graph fp kill >/dev/null 2>&1
ret = 1
# arm64 enables registers in fp mode
arch = !aarch64
[event:base-record]
sample_type=295
@@ -0,0 +1,9 @@
[config]
command = record
args = --no-bpf-event --call-graph fp kill >/dev/null 2>&1
ret = 1
arch = aarch64
[event:base-record]
sample_type=4391
sample_regs_user=1073741824
@@ -0,0 +1,40 @@
[config]
command = record
args = --no-bpf-event -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1
ret = 1
kernel_until = 6.12
[event-1:base-record]
fd=1
group_fd=-1
sample_type=343
read_format=12|28
inherit=0
[event-2:base-record]
fd=2
group_fd=1
# cache-misses
type=0
config=3
# default | PERF_SAMPLE_READ | PERF_SAMPLE_PERIOD
sample_type=343
# PERF_FORMAT_ID | PERF_FORMAT_GROUP | PERF_FORMAT_LOST
read_format=12|28
task=0
mmap=0
comm=0
enable_on_exec=0
disabled=0
# inherit is disabled for group sampling
inherit=0
# sampling disabled
sample_freq=0
sample_period=0
freq=0
write_backward=0
@@ -0,0 +1,50 @@
[config]
command = record
args = --no-bpf-event -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1
ret = 1
kernel_since = 6.12
[event-1:base-record]
fd=1
group_fd=-1
# cycles
type=0
config=0
# default | PERF_SAMPLE_READ | PERF_SAMPLE_PERIOD
sample_type=343
# PERF_FORMAT_ID | PERF_FORMAT_GROUP | PERF_FORMAT_LOST | PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING
read_format=28|31
task=1
mmap=1
comm=1
enable_on_exec=1
disabled=1
# inherit is enabled for group sampling
inherit=1
[event-2:base-record]
fd=2
group_fd=1
# cache-misses
type=0
config=3
# default | PERF_SAMPLE_READ | PERF_SAMPLE_PERIOD
sample_type=343
# PERF_FORMAT_ID | PERF_FORMAT_GROUP | PERF_FORMAT_LOST | PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING
read_format=28|31
task=0
mmap=0
comm=0
enable_on_exec=0
disabled=0
freq=0
# inherit is enabled for group sampling
inherit=1
@@ -0,0 +1,61 @@
[config]
command = record
args = --no-bpf-event -c 10000 -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1
ret = 1
kernel_since = 6.12
[event-1:base-record]
fd=1
group_fd=-1
# cycles
type=0
config=0
# default | PERF_SAMPLE_READ
sample_type=87
# PERF_FORMAT_ID | PERF_FORMAT_GROUP | PERF_FORMAT_LOST | PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING
read_format=28|31
task=1
mmap=1
comm=1
enable_on_exec=1
disabled=1
# inherit is enabled for group sampling
inherit=1
# sampling disabled
sample_freq=0
sample_period=10000
freq=0
write_backward=0
[event-2:base-record]
fd=2
group_fd=1
# cache-misses
type=0
config=3
# default | PERF_SAMPLE_READ
sample_type=87
# PERF_FORMAT_ID | PERF_FORMAT_GROUP | PERF_FORMAT_LOST | PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING
read_format=28|31
task=0
mmap=0
comm=0
enable_on_exec=0
disabled=0
# inherit is enabled for group sampling
inherit=1
# sampling disabled
sample_freq=0
sample_period=0
freq=0
write_backward=0
@@ -0,0 +1,23 @@
[config]
command = record
args = --no-bpf-event -e '{cycles,instructions}' kill >/dev/null 2>&1
ret = 1
[event-1:base-record]
fd=1
group_fd=-1
sample_type=327
read_format=4|20
[event-2:base-record]
fd=2
group_fd=1
type=0
config=1
sample_type=327
read_format=4|20
mmap=0
comm=0
task=0
enable_on_exec=0
disabled=0
@@ -0,0 +1,30 @@
[config]
command = record
args = --no-bpf-event -e '{cycles/period=1234000/,instructions/period=6789000/}:S' kill >/dev/null 2>&1
ret = 1
kernel_until = 6.12
[event-1:base-record]
fd=1
group_fd=-1
config=0|1
sample_period=1234000
sample_type=87
read_format=12|28
inherit=0
freq=0
[event-2:base-record]
fd=2
group_fd=1
config=0|1
sample_period=6789000
sample_type=87
read_format=12|28
disabled=0
inherit=0
mmap=0
comm=0
freq=0
enable_on_exec=0
task=0
@@ -0,0 +1,31 @@
[config]
command = record
args = --no-bpf-event -e '{cycles/period=1234000/,instructions/period=6789000/}:S' kill >/dev/null 2>&1
ret = 1
kernel_since = 6.12
[event-1:base-record]
fd=1
group_fd=-1
config=0|1
sample_period=1234000
sample_type=87
read_format=28|31
disabled=1
inherit=1
freq=0
[event-2:base-record]
fd=2
group_fd=1
config=0|1
sample_period=6789000
sample_type=87
read_format=28|31
disabled=0
inherit=1
mmap=0
comm=0
freq=0
enable_on_exec=0
task=0
@@ -0,0 +1,9 @@
[config]
command = record
args = --no-bpf-event --no-buffering kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_type=263
watermark=0
wakeup_events=1
@@ -0,0 +1,8 @@
[config]
command = record
args = --no-bpf-event -i kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_type=263
inherit=0
@@ -0,0 +1,7 @@
[config]
command = record
args = --no-bpf-event -n kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_period=0
@@ -0,0 +1,8 @@
[config]
command = record
args = --no-bpf-event -c 100 -P kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_period=100
freq=0
@@ -0,0 +1,9 @@
[config]
command = record
args = --no-bpf-event -c 10000 --pfm-events=cycles:period=77777 kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_period=77777
sample_type=7
freq=0
@@ -0,0 +1,7 @@
[config]
command = record
args = --no-bpf-event -R kill >/dev/null 2>&1
ret = 1
[event:base-record]
sample_type=1415
@@ -0,0 +1,12 @@
[config]
command = record
args = --no-bpf-event -c 2 -e arm_spe_0// -- kill >/dev/null 2>&1
ret = 1
arch = aarch64
[event-10:base-record-spe]
sample_period=2
freq=0
# dummy event
[event-1:base-record-spe]
@@ -0,0 +1,12 @@
[config]
command = record
args = --no-bpf-event -e arm_spe_0/period=3/ -- kill >/dev/null 2>&1
ret = 1
arch = aarch64
[event-10:base-record-spe]
sample_period=3
freq=0
# dummy event
[event-1:base-record-spe]
@@ -0,0 +1,12 @@
[config]
command = record
args = --no-bpf-event -e arm_spe_0/pa_enable=1/ -- kill >/dev/null 2>&1
ret = 1
arch = aarch64
[event-10:base-record-spe]
# 622727 is the decimal of IP|TID|TIME|CPU|IDENTIFIER|DATA_SRC|PHYS_ADDR
sample_type=622727
# dummy event
[event-1:base-record-spe]
@@ -0,0 +1,9 @@
# Test that asking for VG fails if the system doesn't support SVE. This
# applies both before and after the feature was added in 6.1
[config]
command = record
args = --no-bpf-event --user-regs=vg kill >/dev/null 2>&1
ret = 129
test_ret = true
arch = aarch64
auxv = auxv["AT_HWCAP"] & 0x400000 == 0
@@ -0,0 +1,10 @@
# Test that asking for VG always fails on old kernels because it was
# added in 6.1. This applies to systems that either support or don't
# support SVE.
[config]
command = record
args = --no-bpf-event --user-regs=vg kill >/dev/null 2>&1
ret = 129
test_ret = true
arch = aarch64
kernel_until = 6.1
@@ -0,0 +1,14 @@
# Test that asking for VG works if the system has SVE and after the
# feature was added in 6.1
[config]
command = record
args = --no-bpf-event --user-regs=vg kill >/dev/null 2>&1
ret = 1
test_ret = true
arch = aarch64
auxv = auxv["AT_HWCAP"] & 0x400000 == 0x400000
kernel_since = 6.1
[event:base-record]
sample_type=4359
sample_regs_user=70368744177664
@@ -0,0 +1,10 @@
[config]
command = stat
args = -e cycles -C 0 kill >/dev/null 2>&1
ret = 1
[event:base-stat]
# events are disabled by default when attached to cpu
disabled=1
enable_on_exec=0
optional=1
@@ -0,0 +1,7 @@
[config]
command = stat
args = -e cycles kill >/dev/null 2>&1
ret = 1
[event:base-stat]
optional=1
@@ -0,0 +1,236 @@
[config]
command = stat
args = kill >/dev/null 2>&1
ret = 1
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
[event1:base-stat]
fd=1
type=1
config=1
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
[event2:base-stat]
fd=2
type=1
config=3
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
[event3:base-stat]
fd=3
type=1
config=4
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
[event4:base-stat]
fd=4
type=1
config=2
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
[event5:base-stat]
fd=5
type=0
config=0
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
[event6:base-stat]
fd=6
type=0
config=7
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
[event7:base-stat]
fd=7
type=0
config=8
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
[event8:base-stat]
fd=8
type=0
config=1
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
[event9:base-stat]
fd=9
type=0
config=4
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
[event10:base-stat]
fd=10
type=0
config=5
optional=1
# PERF_TYPE_RAW / slots (0x400)
[event11:base-stat]
fd=11
group_fd=-1
type=4
config=1024
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-retiring (0x8000)
[event12:base-stat]
fd=12
group_fd=11
type=4
config=32768
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-bad-spec (0x8100)
[event13:base-stat]
fd=13
group_fd=11
type=4
config=33024
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-fe-bound (0x8200)
[event14:base-stat]
fd=14
group_fd=11
type=4
config=33280
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-be-bound (0x8300)
[event15:base-stat]
fd=15
group_fd=11
type=4
config=33536
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-heavy-ops (0x8400)
[event16:base-stat]
fd=16
group_fd=11
type=4
config=33792
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-br-mispredict (0x8500)
[event17:base-stat]
fd=17
group_fd=11
type=4
config=34048
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-fetch-lat (0x8600)
[event18:base-stat]
fd=18
group_fd=11
type=4
config=34304
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-mem-bound (0x8700)
[event19:base-stat]
fd=19
group_fd=11
type=4
config=34560
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING
[event20:base-stat]
fd=20
type=4
config=4109
optional=1
# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/
[event21:base-stat]
fd=21
type=4
config=17039629
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD
[event22:base-stat]
fd=22
type=4
config=60
optional=1
# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY
[event23:base-stat]
fd=23
type=4
config=2097421
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK
[event24:base-stat]
fd=24
type=4
config=316
optional=1
# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE
[event25:base-stat]
fd=25
type=4
config=412
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE
[event26:base-stat]
fd=26
type=4
config=572
optional=1
# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS
[event27:base-stat]
fd=27
type=4
config=706
optional=1
# PERF_TYPE_RAW / UOPS_ISSUED.ANY
[event28:base-stat]
fd=28
type=4
config=270
optional=1
# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING
[event29:base-stat]
fd=29
type=4
config=4269
optional=1
@@ -0,0 +1,278 @@
[config]
command = stat
args = -d kill >/dev/null 2>&1
ret = 1
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
[event1:base-stat]
fd=1
type=1
config=1
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
[event2:base-stat]
fd=2
type=1
config=3
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
[event3:base-stat]
fd=3
type=1
config=4
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
[event4:base-stat]
fd=4
type=1
config=2
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
[event5:base-stat]
fd=5
type=0
config=0
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
[event6:base-stat]
fd=6
type=0
config=7
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
[event7:base-stat]
fd=7
type=0
config=8
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
[event8:base-stat]
fd=8
type=0
config=1
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
[event9:base-stat]
fd=9
type=0
config=4
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
[event10:base-stat]
fd=10
type=0
config=5
optional=1
# PERF_TYPE_RAW / slots (0x400)
[event11:base-stat]
fd=11
group_fd=-1
type=4
config=1024
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-retiring (0x8000)
[event12:base-stat]
fd=12
group_fd=11
type=4
config=32768
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-bad-spec (0x8100)
[event13:base-stat]
fd=13
group_fd=11
type=4
config=33024
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-fe-bound (0x8200)
[event14:base-stat]
fd=14
group_fd=11
type=4
config=33280
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-be-bound (0x8300)
[event15:base-stat]
fd=15
group_fd=11
type=4
config=33536
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-heavy-ops (0x8400)
[event16:base-stat]
fd=16
group_fd=11
type=4
config=33792
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-br-mispredict (0x8500)
[event17:base-stat]
fd=17
group_fd=11
type=4
config=34048
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-fetch-lat (0x8600)
[event18:base-stat]
fd=18
group_fd=11
type=4
config=34304
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-mem-bound (0x8700)
[event19:base-stat]
fd=19
group_fd=11
type=4
config=34560
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING
[event20:base-stat]
fd=20
type=4
config=4109
optional=1
# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/
[event21:base-stat]
fd=21
type=4
config=17039629
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD
[event22:base-stat]
fd=22
type=4
config=60
optional=1
# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY
[event23:base-stat]
fd=23
type=4
config=2097421
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK
[event24:base-stat]
fd=24
type=4
config=316
optional=1
# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE
[event25:base-stat]
fd=25
type=4
config=412
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE
[event26:base-stat]
fd=26
type=4
config=572
optional=1
# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS
[event27:base-stat]
fd=27
type=4
config=706
optional=1
# PERF_TYPE_RAW / UOPS_ISSUED.ANY
[event28:base-stat]
fd=28
type=4
config=270
optional=1
# PERF_TYPE_HW_CACHE /
# PERF_COUNT_HW_CACHE_L1D << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
[event29:base-stat]
fd=29
type=3
config=0
optional=1
# PERF_TYPE_HW_CACHE /
# PERF_COUNT_HW_CACHE_L1D << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
[event30:base-stat]
fd=30
type=3
config=65536
optional=1
# PERF_TYPE_HW_CACHE /
# PERF_COUNT_HW_CACHE_LL << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
[event31:base-stat]
fd=31
type=3
config=2
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_LL << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
[event32:base-stat]
fd=32
type=3
config=65538
optional=1
# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING
[event33:base-stat]
fd=33
type=4
config=4269
optional=1
@@ -0,0 +1,338 @@
[config]
command = stat
args = -dd kill >/dev/null 2>&1
ret = 1
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
[event1:base-stat]
fd=1
type=1
config=1
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
[event2:base-stat]
fd=2
type=1
config=3
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
[event3:base-stat]
fd=3
type=1
config=4
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
[event4:base-stat]
fd=4
type=1
config=2
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
[event5:base-stat]
fd=5
type=0
config=0
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
[event6:base-stat]
fd=6
type=0
config=7
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
[event7:base-stat]
fd=7
type=0
config=8
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
[event8:base-stat]
fd=8
type=0
config=1
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
[event9:base-stat]
fd=9
type=0
config=4
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
[event10:base-stat]
fd=10
type=0
config=5
optional=1
# PERF_TYPE_RAW / slots (0x400)
[event11:base-stat]
fd=11
group_fd=-1
type=4
config=1024
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-retiring (0x8000)
[event12:base-stat]
fd=12
group_fd=11
type=4
config=32768
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-bad-spec (0x8100)
[event13:base-stat]
fd=13
group_fd=11
type=4
config=33024
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-fe-bound (0x8200)
[event14:base-stat]
fd=14
group_fd=11
type=4
config=33280
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-be-bound (0x8300)
[event15:base-stat]
fd=15
group_fd=11
type=4
config=33536
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-heavy-ops (0x8400)
[event16:base-stat]
fd=16
group_fd=11
type=4
config=33792
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-br-mispredict (0x8500)
[event17:base-stat]
fd=17
group_fd=11
type=4
config=34048
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-fetch-lat (0x8600)
[event18:base-stat]
fd=18
group_fd=11
type=4
config=34304
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-mem-bound (0x8700)
[event19:base-stat]
fd=19
group_fd=11
type=4
config=34560
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING
[event20:base-stat]
fd=20
type=4
config=4109
optional=1
# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/
[event21:base-stat]
fd=21
type=4
config=17039629
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD
[event22:base-stat]
fd=22
type=4
config=60
optional=1
# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY
[event23:base-stat]
fd=23
type=4
config=2097421
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK
[event24:base-stat]
fd=24
type=4
config=316
optional=1
# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE
[event25:base-stat]
fd=25
type=4
config=412
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE
[event26:base-stat]
fd=26
type=4
config=572
optional=1
# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS
[event27:base-stat]
fd=27
type=4
config=706
optional=1
# PERF_TYPE_RAW / UOPS_ISSUED.ANY
[event28:base-stat]
fd=28
type=4
config=270
optional=1
# PERF_TYPE_HW_CACHE /
# PERF_COUNT_HW_CACHE_L1D << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
[event29:base-stat]
fd=29
type=3
config=0
optional=1
# PERF_TYPE_HW_CACHE /
# PERF_COUNT_HW_CACHE_L1D << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
[event30:base-stat]
fd=30
type=3
config=65536
optional=1
# PERF_TYPE_HW_CACHE /
# PERF_COUNT_HW_CACHE_LL << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
[event31:base-stat]
fd=31
type=3
config=2
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_LL << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
[event32:base-stat]
fd=32
type=3
config=65538
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_L1I << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
[event33:base-stat]
fd=33
type=3
config=1
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_L1I << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
[event34:base-stat]
fd=34
type=3
config=65537
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_DTLB << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
[event35:base-stat]
fd=35
type=3
config=3
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_DTLB << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
[event36:base-stat]
fd=36
type=3
config=65539
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_ITLB << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
[event37:base-stat]
fd=37
type=3
config=4
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_ITLB << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
[event38:base-stat]
fd=38
type=3
config=65540
optional=1
# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING
[event39:base-stat]
fd=39
type=4
config=4269
optional=1
@@ -0,0 +1,358 @@
[config]
command = stat
args = -ddd kill >/dev/null 2>&1
ret = 1
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_TASK_CLOCK
[event1:base-stat]
fd=1
type=1
config=1
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CONTEXT_SWITCHES
[event2:base-stat]
fd=2
type=1
config=3
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_MIGRATIONS
[event3:base-stat]
fd=3
type=1
config=4
# PERF_TYPE_SOFTWARE / PERF_COUNT_SW_PAGE_FAULTS
[event4:base-stat]
fd=4
type=1
config=2
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_CPU_CYCLES
[event5:base-stat]
fd=5
type=0
config=0
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_FRONTEND
[event6:base-stat]
fd=6
type=0
config=7
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND
[event7:base-stat]
fd=7
type=0
config=8
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS
[event8:base-stat]
fd=8
type=0
config=1
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_INSTRUCTIONS
[event9:base-stat]
fd=9
type=0
config=4
optional=1
# PERF_TYPE_HARDWARE / PERF_COUNT_HW_BRANCH_MISSES
[event10:base-stat]
fd=10
type=0
config=5
optional=1
# PERF_TYPE_RAW / slots (0x400)
[event11:base-stat]
fd=11
group_fd=-1
type=4
config=1024
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-retiring (0x8000)
[event12:base-stat]
fd=12
group_fd=11
type=4
config=32768
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-bad-spec (0x8100)
[event13:base-stat]
fd=13
group_fd=11
type=4
config=33024
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-fe-bound (0x8200)
[event14:base-stat]
fd=14
group_fd=11
type=4
config=33280
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-be-bound (0x8300)
[event15:base-stat]
fd=15
group_fd=11
type=4
config=33536
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-heavy-ops (0x8400)
[event16:base-stat]
fd=16
group_fd=11
type=4
config=33792
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-br-mispredict (0x8500)
[event17:base-stat]
fd=17
group_fd=11
type=4
config=34048
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-fetch-lat (0x8600)
[event18:base-stat]
fd=18
group_fd=11
type=4
config=34304
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / topdown-mem-bound (0x8700)
[event19:base-stat]
fd=19
group_fd=11
type=4
config=34560
disabled=0
enable_on_exec=0
read_format=15
optional=1
# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING
[event20:base-stat]
fd=20
type=4
config=4109
optional=1
# PERF_TYPE_RAW / cpu/INT_MISC.RECOVERY_CYCLES,cmask=1,edge/
[event21:base-stat]
fd=21
type=4
config=17039629
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.THREAD
[event22:base-stat]
fd=22
type=4
config=60
optional=1
# PERF_TYPE_RAW / INT_MISC.RECOVERY_CYCLES_ANY
[event23:base-stat]
fd=23
type=4
config=2097421
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.REF_XCLK
[event24:base-stat]
fd=24
type=4
config=316
optional=1
# PERF_TYPE_RAW / IDQ_UOPS_NOT_DELIVERED.CORE
[event25:base-stat]
fd=25
type=4
config=412
optional=1
# PERF_TYPE_RAW / CPU_CLK_UNHALTED.ONE_THREAD_ACTIVE
[event26:base-stat]
fd=26
type=4
config=572
optional=1
# PERF_TYPE_RAW / UOPS_RETIRED.RETIRE_SLOTS
[event27:base-stat]
fd=27
type=4
config=706
optional=1
# PERF_TYPE_RAW / UOPS_ISSUED.ANY
[event28:base-stat]
fd=28
type=4
config=270
optional=1
# PERF_TYPE_HW_CACHE /
# PERF_COUNT_HW_CACHE_L1D << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
[event29:base-stat]
fd=29
type=3
config=0
optional=1
# PERF_TYPE_HW_CACHE /
# PERF_COUNT_HW_CACHE_L1D << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
[event30:base-stat]
fd=30
type=3
config=65536
optional=1
# PERF_TYPE_HW_CACHE /
# PERF_COUNT_HW_CACHE_LL << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
[event31:base-stat]
fd=31
type=3
config=2
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_LL << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
[event32:base-stat]
fd=32
type=3
config=65538
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_L1I << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
[event33:base-stat]
fd=33
type=3
config=1
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_L1I << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
[event34:base-stat]
fd=34
type=3
config=65537
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_DTLB << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
[event35:base-stat]
fd=35
type=3
config=3
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_DTLB << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
[event36:base-stat]
fd=36
type=3
config=65539
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_ITLB << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
[event37:base-stat]
fd=37
type=3
config=4
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_ITLB << 0 |
# (PERF_COUNT_HW_CACHE_OP_READ << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
[event38:base-stat]
fd=38
type=3
config=65540
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_L1D << 0 |
# (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16)
[event39:base-stat]
fd=39
type=3
config=512
optional=1
# PERF_TYPE_HW_CACHE,
# PERF_COUNT_HW_CACHE_L1D << 0 |
# (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
# (PERF_COUNT_HW_CACHE_RESULT_MISS << 16)
[event40:base-stat]
fd=40
type=3
config=66048
optional=1
# PERF_TYPE_RAW / INT_MISC.UOP_DROPPING
[event41:base-stat]
fd=41
type=4
config=4269
optional=1
@@ -0,0 +1,17 @@
[config]
command = stat
args = -e '{cycles,instructions}' kill >/dev/null 2>&1
ret = 1
[event-1:base-stat]
fd=1
group_fd=-1
read_format=3|15
[event-2:base-stat]
fd=2
group_fd=1
config=1
disabled=0
enable_on_exec=0
read_format=3|15
@@ -0,0 +1,8 @@
[config]
command = stat
args = -i -e cycles kill >/dev/null 2>&1
ret = 1
[event:base-stat]
inherit=0
optional=1
@@ -0,0 +1,114 @@
#!/bin/bash
# perf_probe :: Reject blacklisted probes (exclusive)
# SPDX-License-Identifier: GPL-2.0
#
# test_adding_blacklisted of perf_probe test
# Author: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
# Author: Michael Petlan <mpetlan@redhat.com>
#
# Description:
#
# Blacklisted functions should not be added successfully as probes,
# they must be skipped.
#
DIR_PATH="$(dirname $0)"
TEST_RESULT=0
# include working environment
. "$DIR_PATH/../common/init.sh"
# skip if not supported
BLACKFUNC_LIST=`head -n 5 /sys/kernel/debug/kprobes/blacklist 2> /dev/null | cut -f2`
if [ -z "$BLACKFUNC_LIST" ]; then
print_overall_skipped
exit 2
fi
# try to find vmlinux with DWARF debug info
VMLINUX_FILE=$(perf probe -v random_probe |& grep "Using.*for symbols" | sed -r 's/^Using (.*) for symbols$/\1/')
# remove all previously added probes
clear_all_probes
### adding blacklisted function
REGEX_SCOPE_FAIL="Failed to find scope of probe point"
REGEX_SKIP_MESSAGE=" is blacklisted function, skip it\."
REGEX_NOT_FOUND_MESSAGE="Probe point \'$RE_EVENT\' not found."
REGEX_ERROR_MESSAGE="Error: Failed to add events."
REGEX_INVALID_ARGUMENT="Failed to write event: Invalid argument"
REGEX_SYMBOL_FAIL="Failed to find symbol at $RE_ADDRESS"
REGEX_OUT_SECTION="$RE_EVENT is out of \.\w+, skip it"
REGEX_MISSING_DECL_LINE="A function DIE doesn't have decl_line. Maybe broken DWARF?"
BLACKFUNC=""
SKIP_DWARF=0
for BLACKFUNC in $BLACKFUNC_LIST; do
echo "Probing $BLACKFUNC"
# functions from blacklist should be skipped by perf probe
! $CMD_PERF probe $BLACKFUNC > $LOGS_DIR/adding_blacklisted.log 2> $LOGS_DIR/adding_blacklisted.err
PERF_EXIT_CODE=$?
# check for bad DWARF polluting the result
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"$REGEX_MISSING_DECL_LINE" >/dev/null < $LOGS_DIR/adding_blacklisted.err
if [ $? -eq 0 ]; then
SKIP_DWARF=1
echo "Result polluted by broken DWARF, trying another probe"
# confirm that the broken DWARF comes from assembler
if [ -n "$VMLINUX_FILE" ]; then
readelf -wi "$VMLINUX_FILE" |
awk -v probe="$BLACKFUNC" '/DW_AT_language/ { comp_lang = $0 }
$0 ~ probe { if (comp_lang) { print comp_lang }; exit }' |
grep -q "MIPS assembler"
CHECK_EXIT_CODE=$?
if [ $CHECK_EXIT_CODE -ne 0 ]; then
SKIP_DWARF=0 # broken DWARF while available
break
fi
fi
else
"$DIR_PATH/../common/check_all_lines_matched.pl" \
"$REGEX_SKIP_MESSAGE" "$REGEX_NOT_FOUND_MESSAGE" \
"$REGEX_ERROR_MESSAGE" "$REGEX_SCOPE_FAIL" \
"$REGEX_INVALID_ARGUMENT" "$REGEX_SYMBOL_FAIL" \
"$REGEX_OUT_SECTION" < $LOGS_DIR/adding_blacklisted.err
CHECK_EXIT_CODE=$?
SKIP_DWARF=0
break
fi
done
if [ $SKIP_DWARF -eq 1 ]; then
print_testcase_skipped "adding blacklisted function $BLACKFUNC"
else
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "adding blacklisted function $BLACKFUNC"
(( TEST_RESULT += $? ))
fi
### listing not-added probe
# blacklisted probes should NOT appear in perf-list output
$CMD_PERF list probe:\* > $LOGS_DIR/adding_blacklisted_list.log
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_lines_matched.pl" \
"$RE_LINE_EMPTY" "List of pre-defined events" "Metric Groups:" \
< $LOGS_DIR/adding_blacklisted_list.log
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "listing blacklisted probe (should NOT be listed)"
(( TEST_RESULT += $? ))
# print overall results
print_overall_results "$TEST_RESULT"
exit $?
@@ -0,0 +1,346 @@
#!/bin/bash
# perf_probe :: Add probes, list and remove them (exclusive)
# SPDX-License-Identifier: GPL-2.0
#
# test_adding_kernel of perf_probe test
# Author: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
# Author: Michael Petlan <mpetlan@redhat.com>
#
# Description:
#
# This test tests adding of probes, their correct listing
# and removing.
#
DIR_PATH="$(dirname $0)"
TEST_RESULT=0
# include working environment
. "$DIR_PATH/../common/init.sh"
# shellcheck source=lib/probe_vfs_getname.sh
. "$DIR_PATH/../lib/probe_vfs_getname.sh"
TEST_PROBE=${TEST_PROBE:-"inode_permission"}
# set NO_DEBUGINFO to skip testcase if debuginfo is not present
# skip_if_no_debuginfo returns 2 if debuginfo is not present
skip_if_no_debuginfo
if [ $? -eq 2 ]; then
NO_DEBUGINFO=1
fi
check_kprobes_available
if [ $? -ne 0 ]; then
print_overall_skipped
exit 2
fi
### basic probe adding
for opt in "" "-a" "--add"; do
clear_all_probes
$CMD_PERF probe $opt $TEST_PROBE 2> $LOGS_DIR/adding_kernel_add$opt.err
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"Added new events?:" "probe:$TEST_PROBE" "on $TEST_PROBE" \
< $LOGS_DIR/adding_kernel_add$opt.err
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "adding probe $TEST_PROBE :: $opt"
(( TEST_RESULT += $? ))
done
### listing added probe :: perf list
# any added probes should appear in perf-list output
$CMD_PERF list probe:\* > $LOGS_DIR/adding_kernel_list.log
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_lines_matched.pl" \
"$RE_LINE_EMPTY" "List of pre-defined events" \
"probe:${TEST_PROBE}(?:_\d+)?\s+\[Tracepoint event\]" \
"Metric Groups:" < $LOGS_DIR/adding_kernel_list.log
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "listing added probe :: perf list"
(( TEST_RESULT += $? ))
### listing added probe :: perf probe -l
# '-l' should list all the added probes as well
$CMD_PERF probe -l > $LOGS_DIR/adding_kernel_list-l.log
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"\s*probe:${TEST_PROBE}(?:_\d+)?\s+\(on ${TEST_PROBE}(?:[:\+]$RE_NUMBER_HEX)?@.+\)" \
< $LOGS_DIR/adding_kernel_list-l.log
CHECK_EXIT_CODE=$?
if [ $NO_DEBUGINFO ] ; then
print_testcase_skipped $NO_DEBUGINFO $NO_DEBUGINFO "Skipped due to missing debuginfo"
else
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "listing added probe :: perf probe -l"
fi
(( TEST_RESULT += $? ))
### using added probe
$CMD_PERF stat -e probe:$TEST_PROBE\* -o $LOGS_DIR/adding_kernel_using_probe.log -- cat /proc/uptime > /dev/null
PERF_EXIT_CODE=$?
REGEX_STAT_HEADER="\s*Performance counter stats for \'cat /proc/uptime\':"
REGEX_STAT_VALUES="\s*\d+\s+probe:$TEST_PROBE"
# the value should be greater than 1
REGEX_STAT_VALUE_NONZERO="\s*[1-9][0-9]*\s+probe:$TEST_PROBE"
REGEX_STAT_TIME="\s*$RE_NUMBER\s+seconds (?:time elapsed|user|sys)"
"$DIR_PATH/../common/check_all_lines_matched.pl" \
"$REGEX_STAT_HEADER" "$REGEX_STAT_VALUES" "$REGEX_STAT_TIME" \
"$RE_LINE_COMMENT" "$RE_LINE_EMPTY" < $LOGS_DIR/adding_kernel_using_probe.log
CHECK_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"$REGEX_STAT_HEADER" "$REGEX_STAT_VALUE_NONZERO" "$REGEX_STAT_TIME" \
< $LOGS_DIR/adding_kernel_using_probe.log
(( CHECK_EXIT_CODE += $? ))
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "using added probe"
(( TEST_RESULT += $? ))
### removing added probe
# '-d' should remove the probe
$CMD_PERF probe -d $TEST_PROBE\* 2> $LOGS_DIR/adding_kernel_removing.err
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_lines_matched.pl" \
"Removed event: probe:$TEST_PROBE" < $LOGS_DIR/adding_kernel_removing.err
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "deleting added probe"
(( TEST_RESULT += $? ))
### listing removed probe
# removed probes should NOT appear in perf-list output
$CMD_PERF list probe:\* > $LOGS_DIR/adding_kernel_list_removed.log
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_lines_matched.pl" \
"$RE_LINE_EMPTY" "List of pre-defined events" "Metric Groups:" \
< $LOGS_DIR/adding_kernel_list_removed.log
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "listing removed probe (should NOT be listed)"
(( TEST_RESULT += $? ))
### dry run
# the '-n' switch should run it in dry mode
$CMD_PERF probe -n --add $TEST_PROBE 2> $LOGS_DIR/adding_kernel_dryrun.err
PERF_EXIT_CODE=$?
# check for the output (should be the same as usual)
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"Added new events?:" "probe:$TEST_PROBE" "on $TEST_PROBE" \
< $LOGS_DIR/adding_kernel_dryrun.err
CHECK_EXIT_CODE=$?
# check that no probe was added in real
! ( $CMD_PERF probe -l | grep "probe:$TEST_PROBE" )
(( CHECK_EXIT_CODE += $? ))
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "dry run :: adding probe"
(( TEST_RESULT += $? ))
### force-adding probes
# when using '--force' a probe should be added even if it is already there
$CMD_PERF probe --add $TEST_PROBE 2> $LOGS_DIR/adding_kernel_forceadd_01.err
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"Added new events?:" "probe:$TEST_PROBE" "on $TEST_PROBE" \
< $LOGS_DIR/adding_kernel_forceadd_01.err
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "force-adding probes :: first probe adding"
(( TEST_RESULT += $? ))
# adding existing probe without '--force' should fail
! $CMD_PERF probe --add $TEST_PROBE 2> $LOGS_DIR/adding_kernel_forceadd_02.err
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"Error: event \"$TEST_PROBE\" already exists." \
"Error: Failed to add events." < $LOGS_DIR/adding_kernel_forceadd_02.err
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "force-adding probes :: second probe adding (without force)"
(( TEST_RESULT += $? ))
# adding existing probe with '--force' should pass
NO_OF_PROBES=`$CMD_PERF probe -l $TEST_PROBE| wc -l`
$CMD_PERF probe --force --add $TEST_PROBE 2> $LOGS_DIR/adding_kernel_forceadd_03.err
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"Added new events?:" "probe:${TEST_PROBE}_${NO_OF_PROBES}" \
"on $TEST_PROBE" < $LOGS_DIR/adding_kernel_forceadd_03.err
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "force-adding probes :: second probe adding (with force)"
(( TEST_RESULT += $? ))
### using doubled probe
# since they are the same, they should produce the same results
$CMD_PERF stat -e probe:$TEST_PROBE -e probe:${TEST_PROBE}_${NO_OF_PROBES} -x';' -o $LOGS_DIR/adding_kernel_using_two.log -- bash -c 'cat /proc/cpuinfo > /dev/null'
PERF_EXIT_CODE=$?
REGEX_LINE="$RE_NUMBER;+probe:${TEST_PROBE}_?(?:$NO_OF_PROBES)?;$RE_NUMBER;$RE_NUMBER"
"$DIR_PATH/../common/check_all_lines_matched.pl" \
"$REGEX_LINE" "$RE_LINE_EMPTY" "$RE_LINE_COMMENT" \
< $LOGS_DIR/adding_kernel_using_two.log
CHECK_EXIT_CODE=$?
VALUE_1=`grep "$TEST_PROBE;" $LOGS_DIR/adding_kernel_using_two.log | awk -F';' '{print $1}'`
VALUE_2=`grep "${TEST_PROBE}_${NO_OF_PROBES};" $LOGS_DIR/adding_kernel_using_two.log | awk -F';' '{print $1}'`
test $VALUE_1 -eq $VALUE_2
(( CHECK_EXIT_CODE += $? ))
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "using doubled probe"
### removing multiple probes
# using wildcards should remove all matching probes
$CMD_PERF probe --del \* 2> $LOGS_DIR/adding_kernel_removing_wildcard.err
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_lines_matched.pl" \
"Removed event: probe:$TEST_PROBE" \
"Removed event: probe:${TEST_PROBE}_1" < $LOGS_DIR/adding_kernel_removing_wildcard.err
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "removing multiple probes"
(( TEST_RESULT += $? ))
### wildcard adding support
$CMD_PERF probe -nf --max-probes=512 -a 'vfs_* $params' 2> $LOGS_DIR/adding_kernel_adding_wildcard.err
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"probe:vfs_mknod" "probe:vfs_create" "probe:vfs_rmdir" \
"probe:vfs_link" "probe:vfs_write" < $LOGS_DIR/adding_kernel_adding_wildcard.err
CHECK_EXIT_CODE=$?
if [ $NO_DEBUGINFO ] ; then
print_testcase_skipped $NO_DEBUGINFO $NO_DEBUGINFO "Skipped due to missing debuginfo"
else
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "wildcard adding support"
fi
(( TEST_RESULT += $? ))
### non-existing variable
# perf probe should survive a non-existing variable probing attempt
{ $CMD_PERF probe 'vfs_read somenonexistingrandomstuffwhichisalsoprettylongorevenlongertoexceed64' ; } 2> $LOGS_DIR/adding_kernel_nonexisting.err
PERF_EXIT_CODE=$?
# the exitcode should not be 0 or segfault
test $PERF_EXIT_CODE -ne 139 -a $PERF_EXIT_CODE -ne 0
PERF_EXIT_CODE=$?
# check that the error message is reasonable
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"Failed to find" \
"somenonexistingrandomstuffwhichisalsoprettylongorevenlongertoexceed64" \
< $LOGS_DIR/adding_kernel_nonexisting.err
CHECK_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"in this function|at this address" "Error" "Failed to add events" \
< $LOGS_DIR/adding_kernel_nonexisting.err
(( CHECK_EXIT_CODE += $? ))
"$DIR_PATH/../common/check_all_lines_matched.pl" \
"Failed to find" "Error" "Probe point .+ not found" "optimized out" \
"Use.+\-\-range option to show.+location range" \
< $LOGS_DIR/adding_kernel_nonexisting.err
(( CHECK_EXIT_CODE += $? ))
"$DIR_PATH/../common/check_no_patterns_found.pl" \
"$RE_SEGFAULT" < $LOGS_DIR/adding_kernel_nonexisting.err
(( CHECK_EXIT_CODE += $? ))
if [ $NO_DEBUGINFO ]; then
print_testcase_skipped $NO_DEBUGINFO $NO_DEBUGINFO "Skipped due to missing debuginfo"
else
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "non-existing variable"
fi
(( TEST_RESULT += $? ))
### function with return value
# adding probe with return value
$CMD_PERF probe --add "$TEST_PROBE%return \$retval" 2> $LOGS_DIR/adding_kernel_func_retval_add.err
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"Added new events?:" "probe:$TEST_PROBE" \
"on $TEST_PROBE%return with \\\$retval" \
< $LOGS_DIR/adding_kernel_func_retval_add.err
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "function with retval :: add"
(( TEST_RESULT += $? ))
# recording some data
$CMD_PERF record -e probe:$TEST_PROBE\* -o $CURRENT_TEST_DIR/perf.data -- cat /proc/cpuinfo > /dev/null 2> $LOGS_DIR/adding_kernel_func_retval_record.err
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"$RE_LINE_RECORD1" "$RE_LINE_RECORD2" \
< $LOGS_DIR/adding_kernel_func_retval_record.err
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "function with retval :: record"
(( TEST_RESULT += $? ))
# perf script should report the function calls with the correct arg values
$CMD_PERF script -i $CURRENT_TEST_DIR/perf.data > $LOGS_DIR/adding_kernel_func_retval_script.log
PERF_EXIT_CODE=$?
REGEX_SCRIPT_LINE="\s*cat\s+$RE_NUMBER\s+\[$RE_NUMBER\]\s+$RE_NUMBER:\s+probe:$TEST_PROBE\w*:\s+\($RE_NUMBER_HEX\s+<\-\s+$RE_NUMBER_HEX\)\s+arg1=$RE_NUMBER_HEX"
"$DIR_PATH/../common/check_all_lines_matched.pl" \
"$REGEX_SCRIPT_LINE" < $LOGS_DIR/adding_kernel_func_retval_script.log
CHECK_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"$REGEX_SCRIPT_LINE" < $LOGS_DIR/adding_kernel_func_retval_script.log
(( CHECK_EXIT_CODE += $? ))
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "function argument probing :: script"
(( TEST_RESULT += $? ))
clear_all_probes
# print overall results
print_overall_results "$TEST_RESULT"
exit $?
@@ -0,0 +1,93 @@
#!/bin/bash
# perf_probe :: Basic perf probe functionality (exclusive)
# SPDX-License-Identifier: GPL-2.0
#
# test_basic of perf_probe test
# Author: Michael Petlan <mpetlan@redhat.com>
# Author: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
#
# Description:
#
# This test tests basic functionality of perf probe command.
#
DIR_PATH="$(dirname $0)"
TEST_RESULT=0
# include working environment
. "$DIR_PATH/../common/init.sh"
if ! check_kprobes_available; then
print_overall_skipped
exit 2
fi
### help message
if [ "$PARAM_GENERAL_HELP_TEXT_CHECK" = "y" ]; then
# test that a help message is shown and looks reasonable
$CMD_PERF probe --help > $LOGS_DIR/basic_helpmsg.log 2> $LOGS_DIR/basic_helpmsg.err
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"PERF-PROBE" "NAME" "SYNOPSIS" "DESCRIPTION" "OPTIONS" \
"PROBE\s+SYNTAX" "PROBE\s+ARGUMENT" "LINE\s+SYNTAX" \
< $LOGS_DIR/basic_helpmsg.log
CHECK_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"LAZY\s+MATCHING" "FILTER\s+PATTERN" "EXAMPLES" "SEE\s+ALSO" \
< $LOGS_DIR/basic_helpmsg.log
(( CHECK_EXIT_CODE += $? ))
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"vmlinux" "module=" "source=" "verbose" "quiet" "add=" "del=" \
"list.*EVENT" "line=" "vars=" "externs" < $LOGS_DIR/basic_helpmsg.log
(( CHECK_EXIT_CODE += $? ))
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"no-inlines" "funcs.*FILTER" "filter=FILTER" "force" "dry-run" \
"max-probes" "exec=" "demangle-kernel" < $LOGS_DIR/basic_helpmsg.log
(( CHECK_EXIT_CODE += $? ))
"$DIR_PATH/../common/check_no_patterns_found.pl" \
"No manual entry for" < $LOGS_DIR/basic_helpmsg.err
(( CHECK_EXIT_CODE += $? ))
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "help message"
(( TEST_RESULT += $? ))
else
print_testcase_skipped "help message"
fi
### usage message
# without any args perf-probe should print usage
$CMD_PERF probe 2> $LOGS_DIR/basic_usage.log > /dev/null
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"[Uu]sage" "perf probe" "verbose" "quiet" "add" "del" "force" \
"line" "vars" "externs" "range" < $LOGS_DIR/basic_usage.log
CHECK_EXIT_CODE=$?
print_results 0 $CHECK_EXIT_CODE "usage message"
(( TEST_RESULT += $? ))
### quiet switch
# '--quiet' should mute all output
$CMD_PERF probe --quiet --add vfs_read > $LOGS_DIR/basic_quiet01.log 2> $LOGS_DIR/basic_quiet01.err
PERF_EXIT_CODE=$?
$CMD_PERF probe --quiet --del vfs_read > $LOGS_DIR/basic_quiet03.log 2> $LOGS_DIR/basic_quiet02.err
(( PERF_EXIT_CODE += $? ))
test "`cat $LOGS_DIR/basic_quiet*log $LOGS_DIR/basic_quiet*err | wc -l`" -eq 0
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "quiet switch"
(( TEST_RESULT += $? ))
# print overall results
print_overall_results "$TEST_RESULT"
exit $?
@@ -0,0 +1,86 @@
#!/bin/bash
# perf_probe :: Reject invalid options (exclusive)
# SPDX-License-Identifier: GPL-2.0
#
# test_invalid_options of perf_probe test
# Author: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
# Author: Michael Petlan <mpetlan@redhat.com>
#
# Description:
#
# This test checks whether the invalid and incompatible options are reported
#
DIR_PATH="$(dirname $0)"
TEST_RESULT=0
# include working environment
. "$DIR_PATH/../common/init.sh"
if ! check_kprobes_available; then
print_overall_skipped
exit 2
fi
# Check for presence of DWARF
$CMD_PERF check feature -q dwarf
[ $? -ne 0 ] && HINT_FAIL="Some of the tests need DWARF to run"
### missing argument
# some options require an argument
for opt in '-a' '-d' '-L' '-V'; do
! $CMD_PERF probe $opt 2> $LOGS_DIR/invalid_options_missing_argument$opt.err
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"Error: switch .* requires a value" \
< $LOGS_DIR/invalid_options_missing_argument$opt.err
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "missing argument for $opt"
(( TEST_RESULT += $? ))
done
### unnecessary argument
# some options may omit the argument
for opt in '-F' '-l'; do
$CMD_PERF probe -F > /dev/null 2> $LOGS_DIR/invalid_options_unnecessary_argument$opt.err
PERF_EXIT_CODE=$?
test ! -s $LOGS_DIR/invalid_options_unnecessary_argument$opt.err
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "unnecessary argument for $opt"
(( TEST_RESULT += $? ))
done
### mutually exclusive options
# some options are mutually exclusive
test -e $LOGS_DIR/invalid_options_mutually_exclusive.log && rm -f $LOGS_DIR/invalid_options_mutually_exclusive.log
for opt in '-a xxx -d xxx' '-a xxx -L foo' '-a xxx -V foo' '-a xxx -l' '-a xxx -F' \
'-d xxx -L foo' '-d xxx -V foo' '-d xxx -l' '-d xxx -F' \
'-L foo -V bar' '-L foo -l' '-L foo -F' '-V foo -l' '-V foo -F' '-l -F'; do
! $CMD_PERF probe $opt > /dev/null 2> $LOGS_DIR/aux.log
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"Error: switch .+ cannot be used with switch .+" < $LOGS_DIR/aux.log
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "mutually exclusive options :: $opt"
(( TEST_RESULT += $? ))
# gather the logs
cat $LOGS_DIR/aux.log | grep "Error" >> $LOGS_DIR/invalid_options_mutually_exclusive.log
done
# print overall results
print_overall_results "$TEST_RESULT" $HINT_FAIL
exit $?
@@ -0,0 +1,59 @@
#!/bin/bash
# perf_probe :: Check patterns for line semantics (exclusive)
# SPDX-License-Identifier: GPL-2.0
#
# test_line_semantics of perf_probe test
# Author: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
# Author: Michael Petlan <mpetlan@redhat.com>
#
# Description:
#
# This test checks whether the semantic errors of line option's
# arguments are properly reported.
#
DIR_PATH="$(dirname $0)"
TEST_RESULT=0
# include working environment
. "$DIR_PATH/../common/init.sh"
if ! check_kprobes_available; then
print_overall_skipped
exit 2
fi
# Check for presence of DWARF
$CMD_PERF check feature -q dwarf
[ $? -ne 0 ] && HINT_FAIL="Some of the tests need DWARF to run"
### acceptable --line descriptions
# testing acceptance of valid patterns for the '--line' option
VALID_PATTERNS="func func:10 func:0-10 func:2+10 func@source.c func@source.c:1 source.c:1 source.c:1+1 source.c:1-10"
for desc in $VALID_PATTERNS; do
! ( $CMD_PERF probe --line $desc 2>&1 | grep -q "Semantic error" )
CHECK_EXIT_CODE=$?
print_results 0 $CHECK_EXIT_CODE "acceptable descriptions :: $desc"
(( TEST_RESULT += $? ))
done
### unacceptable --line descriptions
# testing handling of invalid patterns for the '--line' option
INVALID_PATTERNS="func:foo func:1-foo func:1+foo func;lazy\*pattern"
for desc in $INVALID_PATTERNS; do
$CMD_PERF probe --line $desc 2>&1 | grep -q "Semantic error"
CHECK_EXIT_CODE=$?
print_results 0 $CHECK_EXIT_CODE "unacceptable descriptions :: $desc"
(( TEST_RESULT += $? ))
done
# print overall results
print_overall_results "$TEST_RESULT" $HINT_FAIL
exit $?
+52
View File
@@ -0,0 +1,52 @@
#!/bin/bash
# perftool-testsuite :: perf_report
# SPDX-License-Identifier: GPL-2.0
#
# setup.sh of perf report test
# Author: Michael Petlan <mpetlan@redhat.com>
#
# Description:
#
# We need some sample data for perf-report testing
#
#
DIR_PATH="$(dirname $0)"
# include working environment
. "$DIR_PATH/../common/init.sh"
TEST_RESULT=0
test -d "$HEADER_TAR_DIR" || mkdir -p "$HEADER_TAR_DIR"
SW_EVENT="cpu-clock"
$CMD_PERF record -asdg -e $SW_EVENT -o $CURRENT_TEST_DIR/perf.data -- $CMD_LONGER_SLEEP 2> $LOGS_DIR/setup.log
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"$RE_LINE_RECORD1" "$RE_LINE_RECORD2" < $LOGS_DIR/setup.log
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "prepare the perf.data file"
(( TEST_RESULT += $? ))
# Some minimal parallel workload.
$CMD_PERF record --latency -o $CURRENT_TEST_DIR/perf.data.1 bash -c "for i in {1..100} ; do cat /proc/cpuinfo 1> /dev/null & done; sleep 1" 2> $LOGS_DIR/setup-latency.log
PERF_EXIT_CODE=$?
echo ==================
cat $LOGS_DIR/setup-latency.log
echo ==================
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"$RE_LINE_RECORD1" "$RE_LINE_RECORD2" < $LOGS_DIR/setup-latency.log
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "prepare the perf.data.1 file"
(( TEST_RESULT += $? ))
print_overall_results $TEST_RESULT
exit $?
@@ -0,0 +1,5 @@
no symbols found in .*, maybe install a debug package
was updated .*is prelink enabled.+ Restart the long running apps that use it
Warning:
\d+ out of order events recorded.
detected invalid bpf_prog_info
@@ -0,0 +1,285 @@
#!/bin/bash
# perf_report :: Basic perf report options (exclusive)
# SPDX-License-Identifier: GPL-2.0
#
# test_basic of perf_report test
# Author: Michael Petlan <mpetlan@redhat.com>
#
# Description:
#
# This test tests basic functionality of perf report command.
#
#
DIR_PATH="$(dirname $0)"
TEST_RESULT=0
# include working environment
. "$DIR_PATH/../common/init.sh"
### help message
if [ "$PARAM_GENERAL_HELP_TEXT_CHECK" = "y" ]; then
# test that a help message is shown and looks reasonable
$CMD_PERF report --help > $LOGS_DIR/basic_helpmsg.log 2> $LOGS_DIR/basic_helpmsg.err
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"PERF-REPORT" "NAME" "SYNOPSIS" "DESCRIPTION" "OPTIONS" \
"OVERHEAD\s+CALCULATION" "SEE ALSO" < $LOGS_DIR/basic_helpmsg.log
CHECK_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"input" "verbose" "show-nr-samples" "show-cpu-utilization" \
"threads" "comms" "pid" "tid" "dsos" "symbols" "symbol-filter" \
< $LOGS_DIR/basic_helpmsg.log
(( CHECK_EXIT_CODE += $? ))
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"hide-unresolved" "sort" "fields" "parent" "exclude-other" \
"column-widths" "field-separator" "dump-raw-trace" "children" \
< $LOGS_DIR/basic_helpmsg.log
(( CHECK_EXIT_CODE += $? ))
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"call-graph" "max-stack" "inverted" "ignore-callees" "pretty" \
"stdio" "tui" "gtk" "vmlinux" "kallsyms" "modules" \
< $LOGS_DIR/basic_helpmsg.log
(( CHECK_EXIT_CODE += $? ))
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"force" "symfs" "cpu" "disassembler-style" "source" "asm-raw" \
"show-total-period" "show-info" "branch-stack" "group" \
< $LOGS_DIR/basic_helpmsg.log
(( CHECK_EXIT_CODE += $? ))
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"branch-history" "objdump" "demangle" "percent-limit" "percentage" \
"header" "itrace" "full-source-path" "show-ref-call-graph" \
< $LOGS_DIR/basic_helpmsg.log
(( CHECK_EXIT_CODE += $? ))
"$DIR_PATH/../common/check_no_patterns_found.pl" \
"No manual entry for" < $LOGS_DIR/basic_helpmsg.err
(( CHECK_EXIT_CODE += $? ))
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "help message"
(( TEST_RESULT += $? ))
else
print_testcase_skipped "help message"
fi
### basic execution
# test that perf report is even working
$CMD_PERF report -i $CURRENT_TEST_DIR/perf.data --stdio > $LOGS_DIR/basic_basic.log 2> $LOGS_DIR/basic_basic.err
PERF_EXIT_CODE=$?
REGEX_LOST_SAMPLES_INFO="#\s*Total Lost Samples:\s+$RE_NUMBER"
REGEX_SAMPLES_INFO="#\s*Samples:\s+(?:$RE_NUMBER)\w?\s+of\s+event\s+'$RE_EVENT_ANY'"
REGEX_LINES_HEADER="#\s*Children\s+Self\s+Command\s+Shared Object\s+Symbol"
REGEX_LINES="\s*$RE_NUMBER%\s+$RE_NUMBER%\s+\S+\s+\[kernel\.(?:vmlinux)|(?:kallsyms)\]\s+\[[k\.]\]\s+\w+"
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"$REGEX_LOST_SAMPLES_INFO" "$REGEX_SAMPLES_INFO" \
"$REGEX_LINES_HEADER" "$REGEX_LINES" < $LOGS_DIR/basic_basic.log
CHECK_EXIT_CODE=$?
"$DIR_PATH/../common/check_errors_whitelisted.pl" \
"$DIR_PATH/stderr-whitelist.txt" < $LOGS_DIR/basic_basic.err
(( CHECK_EXIT_CODE += $? ))
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "basic execution"
(( TEST_RESULT += $? ))
### number of samples
# '--show-nr-samples' should show number of samples for each symbol
$CMD_PERF report --stdio -i $CURRENT_TEST_DIR/perf.data --show-nr-samples > $LOGS_DIR/basic_nrsamples.log 2> $LOGS_DIR/basic_nrsamples.err
PERF_EXIT_CODE=$?
REGEX_LINES_HEADER="#\s*Children\s+Self\s+Samples\s+Command\s+Shared Object\s+Symbol"
REGEX_LINES="\s*$RE_NUMBER%\s+$RE_NUMBER%\s+$RE_NUMBER\s+\S+\s+\[kernel\.(?:vmlinux)|(?:kallsyms)\]\s+\[[k\.]\]\s+\w+"
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"$REGEX_LINES_HEADER" "$REGEX_LINES" < $LOGS_DIR/basic_nrsamples.log
CHECK_EXIT_CODE=$?
"$DIR_PATH/../common/check_errors_whitelisted.pl" \
"$DIR_PATH/stderr-whitelist.txt" < $LOGS_DIR/basic_nrsamples.err
(( CHECK_EXIT_CODE += $? ))
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "number of samples"
(( TEST_RESULT += $? ))
### header
# '--header' and '--header-only' should show perf report header
$CMD_PERF report -i $CURRENT_TEST_DIR/perf.data --stdio --header-only > $LOGS_DIR/basic_header.log
PERF_EXIT_CODE=$?
REGEX_LINE_TIMESTAMP="#\s+captured on\s*:\s*$RE_DATE_TIME"
REGEX_LINE_HOSTNAME="#\s+hostname\s*:\s*$MY_HOSTNAME"
REGEX_LINE_KERNEL="#\s+os release\s*:\s*${MY_KERNEL_VERSION//+/\\+}"
REGEX_LINE_PERF="#\s+perf version\s*:\s*"
REGEX_LINE_ARCH="#\s+arch\s*:\s*$MY_ARCH"
REGEX_LINE_CPUS_ONLINE="#\s+nrcpus online\s*:\s*$MY_CPUS_ONLINE"
REGEX_LINE_CPUS_AVAIL="#\s+nrcpus avail\s*:\s*$MY_CPUS_AVAILABLE"
# disable precise check for "nrcpus avail" in BASIC runmode
test $PERFTOOL_TESTSUITE_RUNMODE -lt $RUNMODE_STANDARD && REGEX_LINE_CPUS_AVAIL="#\s+nrcpus avail\s*:\s*$RE_NUMBER"
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"$REGEX_LINE_TIMESTAMP" "$REGEX_LINE_HOSTNAME" "$REGEX_LINE_KERNEL" \
"$REGEX_LINE_PERF" "$REGEX_LINE_ARCH" "$REGEX_LINE_CPUS_ONLINE" \
"$REGEX_LINE_CPUS_AVAIL" < $LOGS_DIR/basic_header.log
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "header"
(( TEST_RESULT += $? ))
# '--header' and '--header-only' should use creation time
OLD_TIMESTAMP=`$CMD_PERF report --stdio --header-only -i $CURRENT_TEST_DIR/perf.data | grep "captured on"`
PERF_EXIT_CODE=$?
( tar -C $CURRENT_TEST_DIR -c perf.data | xz > $CURRENT_TEST_DIR/perf.data.tar.xz ; xzcat $CURRENT_TEST_DIR/perf.data.tar.xz | tar x -C $HEADER_TAR_DIR )
(( PERF_EXIT_CODE += $? ))
NEW_TIMESTAMP=`$CMD_PERF report --stdio --header-only -i $HEADER_TAR_DIR/perf.data | grep "captured on"`
(( PERF_EXIT_CODE += $? ))
test "$OLD_TIMESTAMP" = "$NEW_TIMESTAMP"
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "header timestamp"
(( TEST_RESULT += $? ))
### show CPU utilization
# '--showcpuutilization' should show percentage for both system and userspace mode
$CMD_PERF report -i $CURRENT_TEST_DIR/perf.data --stdio --showcpuutilization > $LOGS_DIR/basic_cpuut.log 2> $LOGS_DIR/basic_cpuut.err
PERF_EXIT_CODE=$?
REGEX_LINES_HEADER="#\s*Children\s+Self\s+sys\s+usr\s+Command\s+Shared Object\s+Symbol"
REGEX_LINES="\s*$RE_NUMBER%\s+$RE_NUMBER%\s+$RE_NUMBER%\s+$RE_NUMBER%\s+\S+\s+\[kernel\.(?:vmlinux)|(?:kallsyms)\]\s+\[[k\.]\]\s+\w+"
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"$REGEX_LINES_HEADER" "$REGEX_LINES" < $LOGS_DIR/basic_cpuut.log
CHECK_EXIT_CODE=$?
"$DIR_PATH/../common/check_errors_whitelisted.pl" \
"$DIR_PATH/stderr-whitelist.txt" < $LOGS_DIR/basic_cpuut.err
(( CHECK_EXIT_CODE += $? ))
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "show CPU utilization"
(( TEST_RESULT += $? ))
### pid
# '--pid=' should limit the output for a process with the given pid only
$CMD_PERF report --stdio -i $CURRENT_TEST_DIR/perf.data --pid=1 > $LOGS_DIR/basic_pid.log 2> $LOGS_DIR/basic_pid.err
PERF_EXIT_CODE=$?
grep -P -v '^#' $LOGS_DIR/basic_pid.log | grep -P '\s+[\d\.]+%' | \
"$DIR_PATH/../common/check_all_lines_matched.pl" "systemd|init"
CHECK_EXIT_CODE=$?
"$DIR_PATH/../common/check_errors_whitelisted.pl" \
"$DIR_PATH/stderr-whitelist.txt" < $LOGS_DIR/basic_pid.err
(( CHECK_EXIT_CODE += $? ))
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "pid"
(( TEST_RESULT += $? ))
### non-existing symbol
# '--symbols' should show only the given symbols
$CMD_PERF report --stdio -i $CURRENT_TEST_DIR/perf.data --symbols=dummynonexistingsymbol > $LOGS_DIR/basic_symbols.log 2> $LOGS_DIR/basic_symbols.err
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_lines_matched.pl" \
"$RE_LINE_EMPTY" "$RE_LINE_COMMENT" < $LOGS_DIR/basic_symbols.log
CHECK_EXIT_CODE=$?
"$DIR_PATH/../common/check_errors_whitelisted.pl" \
"$DIR_PATH/stderr-whitelist.txt" < $LOGS_DIR/basic_symbols.err
(( CHECK_EXIT_CODE += $? ))
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "non-existing symbol"
(( TEST_RESULT += $? ))
### symbol filter
# '--symbol-filter' should filter symbols based on substrings
$CMD_PERF report --stdio -i $CURRENT_TEST_DIR/perf.data --symbol-filter=map > $LOGS_DIR/basic_symbolfilter.log 2> $LOGS_DIR/basic_symbolfilter.err
PERF_EXIT_CODE=$?
grep -P -v '^#' $LOGS_DIR/basic_symbolfilter.log | grep -P '\s+[\d\.]+%' | \
"$DIR_PATH/../common/check_all_lines_matched.pl" "\[[k\.]\]\s+.*map"
CHECK_EXIT_CODE=$?
"$DIR_PATH/../common/check_errors_whitelisted.pl" \
"$DIR_PATH/stderr-whitelist.txt" < $LOGS_DIR/basic_symbolfilter.err
(( CHECK_EXIT_CODE += $? ))
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "symbol filter"
(( TEST_RESULT += $? ))
### latency and parallelism
# Record with --latency should record with context switches.
$CMD_PERF report -i $CURRENT_TEST_DIR/perf.data.1 --stdio --header-only > $LOGS_DIR/latency_header.log
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
", context_switch = 1, " < $LOGS_DIR/latency_header.log
CHECK_EXIT_CODE=$?
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "latency header"
(( TEST_RESULT += $? ))
# The default report for latency profile should show Overhead and Latency fields (in that order).
$CMD_PERF report --stdio -i $CURRENT_TEST_DIR/perf.data.1 > $LOGS_DIR/latency_default.log 2> $LOGS_DIR/latency_default.err
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"# Overhead Latency Command" < $LOGS_DIR/latency_default.log
CHECK_EXIT_CODE=$?
"$DIR_PATH/../common/check_errors_whitelisted.pl" \
"stderr-whitelist.txt" < $LOGS_DIR/latency_default.err
(( CHECK_EXIT_CODE += $? ))
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "default report for latency profile"
(( TEST_RESULT += $? ))
# The latency report for latency profile should show Latency and Overhead fields (in that order).
$CMD_PERF report --latency --stdio -i $CURRENT_TEST_DIR/perf.data.1 > $LOGS_DIR/latency_latency.log 2> $LOGS_DIR/latency_latency.err
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"# Latency Overhead Command" < $LOGS_DIR/latency_latency.log
CHECK_EXIT_CODE=$?
"$DIR_PATH/../common/check_errors_whitelisted.pl" \
"stderr-whitelist.txt" < $LOGS_DIR/latency_latency.err
(( CHECK_EXIT_CODE += $? ))
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "latency report for latency profile"
(( TEST_RESULT += $? ))
# Ensure parallelism histogram with parallelism filter does not fail/crash.
$CMD_PERF report --hierarchy --sort latency,parallelism,comm,symbol --parallelism=1,2 --stdio -i $CURRENT_TEST_DIR/perf.data.1 > $LOGS_DIR/parallelism_hierarchy.log 2> $LOGS_DIR/parallelism_hierarchy.err
PERF_EXIT_CODE=$?
"$DIR_PATH/../common/check_all_patterns_found.pl" \
"# Latency Parallelism / Command / Symbol" \
< $LOGS_DIR/parallelism_hierarchy.log
CHECK_EXIT_CODE=$?
"$DIR_PATH/../common/check_errors_whitelisted.pl" \
"stderr-whitelist.txt" < $LOGS_DIR/parallelism_hierarchy.err
(( CHECK_EXIT_CODE += $? ))
print_results $PERF_EXIT_CODE $CHECK_EXIT_CODE "parallelism histogram"
(( TEST_RESULT += $? ))
# TODO: $CMD_PERF report -n --showcpuutilization -TUxDg 2> 01.log
# print overall results
print_overall_results "$TEST_RESULT"
exit $?
+326
View File
@@ -0,0 +1,326 @@
#!/bin/bash
# build id cache operations
# SPDX-License-Identifier: GPL-2.0
# skip if there's no readelf
if ! [ -x "$(command -v readelf)" ]; then
echo "failed: no readelf, install binutils"
exit 2
fi
# skip if there's no compiler
if ! [ -x "$(command -v cc)" ]; then
echo "failed: no compiler, install gcc"
exit 2
fi
# check what we need to test windows binaries
add_pe=1
run_pe=1
if ! perf version --build-options | grep -q 'libbfd: .* on '; then
echo "WARNING: perf not built with libbfd. PE binaries will not be tested."
add_pe=0
run_pe=0
fi
if ! which wine > /dev/null; then
echo "WARNING: wine not found. PE binaries will not be run."
run_pe=0
fi
# set up wine
if [ ${run_pe} -eq 1 ]; then
wineprefix=$(mktemp -d /tmp/perf.wineprefix.XXX)
export WINEPREFIX=${wineprefix}
# clear display variables to prevent wine from popping up dialogs
unset DISPLAY
unset WAYLAND_DISPLAY
fi
build_id_dir=
ex_source=$(mktemp /tmp/perf_buildid_test.ex.XXX.c)
ex_md5=$(mktemp /tmp/perf_buildid_test.ex.MD5.XXX)
ex_sha1=$(mktemp /tmp/perf_buildid_test.ex.SHA1.XXX)
ex_pe=$(dirname $0)/../pe-file.exe
data=$(mktemp /tmp/perf_buildid_test.data.XXX)
log_out=$(mktemp /tmp/perf_buildid_test.log.out.XXX)
log_err=$(mktemp /tmp/perf_buildid_test.log.err.XXX)
cleanup() {
rm -f ${ex_source} ${ex_md5} ${ex_sha1} ${data} ${log_out} ${log_err}
if [ ${run_pe} -eq 1 ]; then
rm -r ${wineprefix}
fi
if [ -d ${build_id_dir} ]; then
rm -rf ${build_id_dir}
fi
trap - EXIT TERM INT
}
trap_cleanup() {
echo "Unexpected signal in ${FUNCNAME[1]}"
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
# Test program based on the noploop workload.
cat <<EOF > ${ex_source}
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
static volatile sig_atomic_t done;
static void sighandler(int sig)
{
(void)sig;
done = 1;
}
int main(int argc, const char **argv)
{
int sec = 1;
if (argc > 1)
sec = atoi(argv[1]);
signal(SIGINT, sighandler);
signal(SIGALRM, sighandler);
alarm(sec);
while (!done)
continue;
return 0;
}
EOF
cc -Wl,--build-id=sha1 ${ex_source} -o ${ex_sha1} -x c -
cc -Wl,--build-id=md5 ${ex_source} -o ${ex_md5} -x c -
echo "test binaries: ${ex_sha1} ${ex_md5} ${ex_pe}"
get_build_id()
{
case $1 in
*.exe)
# We don't have a tool that can pull a nicely formatted build-id out of
# a PE file, but we can extract the whole section with objcopy and
# format it ourselves. The .buildid section is a Debug Directory
# containing a CodeView entry:
# https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#debug-directory-image-only
# https://github.com/dotnet/runtime/blob/da94c022576a5c3bbc0e896f006565905eb137f9/docs/design/specs/PE-COFF.md
# The build-id starts at byte 33 and must be rearranged into a GUID.
id=`objcopy -O binary --only-section=.buildid $1 /dev/stdout | \
cut -c 33-48 | hexdump -ve '/1 "%02x"' | \
sed 's@^\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(.*\)0a$@\4\3\2\1\6\5\8\7\9@'`
;;
*)
id=`readelf -n ${1} 2>/dev/null | grep 'Build ID' | awk '{print $3}'`
;;
esac
echo ${id}
}
check()
{
file=$1
perf_data=$2
id=$(get_build_id $file)
echo "build id: ${id}"
id_file=${id#??}
id_dir=${id%$id_file}
link=$build_id_dir/.build-id/$id_dir/$id_file
echo "link: ${link}"
if [ ! -h $link ]; then
echo "failed: link ${link} does not exist"
exit 1
fi
cached_file=${build_id_dir}/.build-id/$id_dir/`readlink ${link}`/elf
echo "file: ${cached_file}"
# Check for file permission of original file
# in case of pe-file.exe file
echo $1 | grep ".exe"
if [ $? -eq 0 ]; then
if [ -x $1 ] && [ ! -x $cached_file ]; then
echo "failed: file ${cached_file} executable does not exist"
exit 1
fi
if [ ! -x $cached_file ] && [ ! -e $cached_file ]; then
echo "failed: file ${cached_file} does not exist"
exit 1
fi
elif [ ! -x $cached_file ]; then
echo "failed: file ${cached_file} does not exist"
exit 1
fi
diff ${cached_file} ${1}
if [ $? -ne 0 ]; then
echo "failed: ${cached_file} do not match"
exit 1
fi
${perf} buildid-cache -l | grep -q ${id}
if [ $? -ne 0 ]; then
echo "failed: ${id} is not reported by \"perf buildid-cache -l\""
exit 1
fi
if [ -n "${perf_data}" ]; then
${perf} buildid-list -i ${perf_data} | grep -q ${id}
if [ $? -ne 0 ]; then
echo "failed: ${id} is not reported by \"perf buildid-list -i ${perf_data}\""
exit 1
fi
fi
echo "OK for ${1}"
}
test_add()
{
build_id_dir=$(mktemp -d /tmp/perf_buildid_test.debug.XXX)
perf="perf --buildid-dir ${build_id_dir}"
${perf} buildid-cache -v -a ${1}
if [ $? -ne 0 ]; then
echo "failed: add ${1} to build id cache"
exit 1
fi
check ${1}
rm -rf ${build_id_dir}
}
test_remove()
{
build_id_dir=$(mktemp -d /tmp/perf_buildid_test.debug.XXX)
perf="perf --buildid-dir ${build_id_dir}"
${perf} buildid-cache -v -a ${1}
if [ $? -ne 0 ]; then
echo "failed: add ${1} to build id cache"
exit 1
fi
id=$(get_build_id ${1})
if ! ${perf} buildid-cache -l | grep -q ${id}; then
echo "failed: ${id} not in cache"
exit 1
fi
${perf} buildid-cache -v -r ${1}
if [ $? -ne 0 ]; then
echo "failed: remove ${id} from build id cache"
exit 1
fi
if ${perf} buildid-cache -l | grep -q ${id}; then
echo "failed: ${id} still in cache after remove"
exit 1
fi
echo "remove: OK"
rm -rf ${build_id_dir}
}
test_purge()
{
build_id_dir=$(mktemp -d /tmp/perf_buildid_test.debug.XXX)
perf="perf --buildid-dir ${build_id_dir}"
id1=$(get_build_id ${ex_sha1})
${perf} buildid-cache -v -a ${ex_sha1}
if ! ${perf} buildid-cache -l | grep -q ${id1}; then
echo "failed: ${id1} not in cache"
exit 1
fi
id2=$(get_build_id ${ex_md5})
${perf} buildid-cache -v -a ${ex_md5}
if ! ${perf} buildid-cache -l | grep -q ${id2}; then
echo "failed: ${id2} not in cache"
exit 1
fi
# Purge by path
${perf} buildid-cache -v -p ${ex_sha1}
if [ $? -ne 0 ]; then
echo "failed: purge build id cache of ${ex_sha1}"
exit 1
fi
${perf} buildid-cache -v -p ${ex_md5}
if [ $? -ne 0 ]; then
echo "failed: purge build id cache of ${ex_md5}"
exit 1
fi
# Verify both are gone
if ${perf} buildid-cache -l | grep -q ${id1}; then
echo "failed: ${id1} still in cache after purge"
exit 1
fi
if ${perf} buildid-cache -l | grep -q ${id2}; then
echo "failed: ${id2} still in cache after purge"
exit 1
fi
echo "purge: OK"
rm -rf ${build_id_dir}
}
test_record()
{
build_id_dir=$(mktemp -d /tmp/perf_buildid_test.debug.XXX)
perf="perf --buildid-dir ${build_id_dir}"
echo "running: perf record $*"
${perf} record --buildid-all -o ${data} "$@" 1>${log_out} 2>${log_err}
if [ $? -ne 0 ]; then
echo "failed: record $*"
echo "see log: ${log_err}"
exit 1
fi
args="$*"
check ${args##* } ${data}
rm -f ${log_out} ${log_err}
rm -rf ${build_id_dir}
rm -rf ${data}
}
# add binaries manual via perf buildid-cache -a
test_add ${ex_sha1}
test_add ${ex_md5}
if [ ${add_pe} -eq 1 ]; then
test_add ${ex_pe}
fi
# add binaries via perf record post processing
test_record ${ex_sha1}
test_record ${ex_md5}
if [ ${run_pe} -eq 1 ]; then
test_record wine ${ex_pe}
fi
# remove binaries manually via perf buildid-cache -r
test_remove ${ex_sha1}
test_remove ${ex_md5}
if [ ${add_pe} -eq 1 ]; then
test_remove ${ex_pe}
fi
# purge binaries manually via perf buildid-cache -p
test_purge
cleanup
exit 0
+62
View File
@@ -0,0 +1,62 @@
#!/bin/bash
# perf c2c tests
# SPDX-License-Identifier: GPL-2.0
set -e
err=0
perfdata=$(mktemp /tmp/__perf_c2c_test.perf.data.XXXXX)
cleanup() {
rm -f "${perfdata}"
rm -f "${perfdata}".old
trap - EXIT TERM INT
}
trap_cleanup() {
echo "Unexpected signal in ${FUNCNAME[1]}"
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
check_c2c_support() {
# Check if perf c2c record works.
if ! perf c2c record -o "${perfdata}" -- true > /dev/null 2>&1 ; then
return 1
fi
return 0
}
test_c2c_record_report() {
echo "c2c record and report test"
if ! check_c2c_support ; then
echo "c2c record and report test [Skipped: perf c2c record failed (possibly missing hardware support)]"
err=2
return
fi
# Run a workload that does some memory operations.
if ! perf c2c record -o "${perfdata}" -- perf test -w datasym 1 > /dev/null 2>&1 ; then
echo "c2c record and report test [Skipped: perf c2c record failed during workload]"
return
fi
if ! perf c2c report -i "${perfdata}" --stdio > /dev/null 2>&1 ; then
echo "c2c record and report test [Failed: report failed]"
err=1
return
fi
if ! perf c2c report -i "${perfdata}" -N > /dev/null 2>&1 ; then
echo "c2c record and report test [Failed: report -N failed]"
err=1
return
fi
echo "c2c record and report test [Success]"
}
test_c2c_record_report
cleanup
exit $err
@@ -0,0 +1,39 @@
#!/usr/bin/perl
# SPDX-License-Identifier: GPL-2.0
@regexps = @ARGV;
$max_printed_lines = 20;
$max_printed_lines = $ENV{TESTLOG_ERR_MSG_MAX_LINES} if (defined $ENV{TESTLOG_ERR_MSG_MAX_LINES});
$quiet = 1;
$quiet = 0 if (defined $ENV{TESTLOG_VERBOSITY} && $ENV{TESTLOG_VERBOSITY} ge 2);
$passed = 1;
$lines_printed = 0;
while (<STDIN>)
{
s/\n//;
$line_matched = 0;
for $r (@regexps)
{
if (/$r/)
{
$line_matched = 1;
last;
}
}
unless ($line_matched)
{
if ($lines_printed++ < $max_printed_lines)
{
print "Line did not match any pattern: \"$_\"\n" unless $quiet;
}
$passed = 0;
}
}
exit ($passed == 0);
@@ -0,0 +1,34 @@
#!/usr/bin/perl
# SPDX-License-Identifier: GPL-2.0
@regexps = @ARGV;
$quiet = 1;
$quiet = 0 if (defined $ENV{TESTLOG_VERBOSITY} && $ENV{TESTLOG_VERBOSITY} ge 2);
%found = ();
$passed = 1;
while (<STDIN>)
{
s/\n//;
for $r (@regexps)
{
if (/$r/)
{
$found{$r} = 1; # FIXME: maybe add counters -- how many times was the regexp matched
}
}
}
for $r (@regexps)
{
unless (exists $found{$r})
{
print "Regexp not found: \"$r\"\n" unless $quiet;
$passed = 0;
}
}
exit ($passed == 0);
@@ -0,0 +1,51 @@
#!/usr/bin/perl
# SPDX-License-Identifier: GPL-2.0
$whitelist_file = shift;
if (defined $whitelist_file)
{
open (INFILE, $whitelist_file) or die "Checker error: Unable to open the whitelist file: $whitelist_file\n";
@regexps = <INFILE>;
close INFILE or die "Checker error: Unable to close the whitelist file: $whitelist_file\n";
}
else
{
@regexps = ();
}
$max_printed_lines = 20;
$max_printed_lines = $ENV{TESTLOG_ERR_MSG_MAX_LINES} if (defined $ENV{TESTLOG_ERR_MSG_MAX_LINES});
$quiet = 1;
$quiet = 0 if (defined $ENV{TESTLOG_VERBOSITY} && $ENV{TESTLOG_VERBOSITY} ge 2);
$passed = 1;
$lines_printed = 0;
while (<STDIN>)
{
s/\n//;
$line_matched = 0;
for $r (@regexps)
{
chomp $r;
if (/$r/)
{
$line_matched = 1;
last;
}
}
unless ($line_matched)
{
if ($lines_printed++ < $max_printed_lines)
{
print "Line did not match any pattern: \"$_\"\n" unless $quiet;
}
$passed = 0;
}
}
exit ($passed == 0);
@@ -0,0 +1,34 @@
#!/usr/bin/perl
# SPDX-License-Identifier: GPL-2.0
@regexps = @ARGV;
$quiet = 1;
$quiet = 0 if (defined $ENV{TESTLOG_VERBOSITY} && $ENV{TESTLOG_VERBOSITY} ge 2);
%found = ();
$passed = 1;
while (<STDIN>)
{
s/\n//;
for $r (@regexps)
{
if (/$r/)
{
$found{$r} = 1;
}
}
}
for $r (@regexps)
{
if (exists $found{$r})
{
print "Regexp found: \"$r\"\n" unless $quiet;
$passed = 0;
}
}
exit ($passed == 0);
@@ -0,0 +1,143 @@
# SPDX-License-Identifier: GPL-2.0
#
# init.sh
# Author: Michael Petlan <mpetlan@redhat.com>
#
# Description:
#
# This file should be used for initialization of basic functions
# for checking, reporting results etc.
#
#
. "$(dirname $0)/../common/settings.sh"
. "$(dirname $0)/../common/patterns.sh"
THIS_TEST_NAME=`basename $0 .sh`
_echo()
{
test "$TESTLOG_VERBOSITY" -ne 0 && echo -e "$@"
}
print_results()
{
PERF_RETVAL="$1"; shift
CHECK_RETVAL="$1"; shift
FAILURE_REASON=""
TASK_COMMENT="$*"
if [ $PERF_RETVAL -eq 0 ] && [ $CHECK_RETVAL -eq 0 ]; then
_echo "$MPASS-- [ PASS ] --$MEND $TEST_NAME :: $THIS_TEST_NAME :: $TASK_COMMENT"
return 0
else
if [ $PERF_RETVAL -ne 0 ]; then
FAILURE_REASON="command exitcode"
fi
if [ $CHECK_RETVAL -ne 0 ]; then
test -n "$FAILURE_REASON" && FAILURE_REASON="$FAILURE_REASON + "
FAILURE_REASON="$FAILURE_REASON""output regexp parsing"
fi
_echo "$MFAIL-- [ FAIL ] --$MEND $TEST_NAME :: $THIS_TEST_NAME :: $TASK_COMMENT ($FAILURE_REASON)"
return 1
fi
}
print_overall_results()
{
RETVAL="$1"; shift
TASK_COMMENT="$*"
test -n "$TASK_COMMENT" && TASK_COMMENT=":: $TASK_COMMENT"
if [ $RETVAL -eq 0 ]; then
_echo "$MALLPASS## [ PASS ] ##$MEND $TEST_NAME :: $THIS_TEST_NAME SUMMARY"
else
_echo "$MALLFAIL## [ FAIL ] ##$MEND $TEST_NAME :: $THIS_TEST_NAME SUMMARY :: $RETVAL failures found $TASK_COMMENT"
fi
return $RETVAL
}
print_testcase_skipped()
{
TASK_COMMENT="$*"
_echo "$MSKIP-- [ SKIP ] --$MEND $TEST_NAME :: $THIS_TEST_NAME :: $TASK_COMMENT :: testcase skipped"
return 0
}
print_overall_skipped()
{
_echo "$MSKIP## [ SKIP ] ##$MEND $TEST_NAME :: $THIS_TEST_NAME :: testcase skipped"
return 0
}
print_warning()
{
WARN_COMMENT="$*"
_echo "$MWARN-- [ WARN ] --$MEND $TEST_NAME :: $THIS_TEST_NAME :: $WARN_COMMENT"
return 0
}
# this function should skip a testcase if the testsuite is not run in
# a runmode that fits the testcase --> if the suite runs in BASIC mode
# all STANDARD and EXPERIMENTAL testcases will be skipped; if the suite
# runs in STANDARD mode, all EXPERIMENTAL testcases will be skipped and
# if the suite runs in EXPERIMENTAL mode, nothing is skipped
consider_skipping()
{
TESTCASE_RUNMODE="$1"
# the runmode of a testcase needs to be at least the current suite's runmode
if [ $PERFTOOL_TESTSUITE_RUNMODE -lt $TESTCASE_RUNMODE ]; then
print_overall_skipped
exit 2
fi
}
detect_baremetal()
{
# return values:
# 0 = bare metal
# 1 = virtualization detected
# 2 = unknown state
VIRT=`systemd-detect-virt 2>/dev/null`
test $? -eq 127 && return 2
test "$VIRT" = "none"
}
detect_intel()
{
# return values:
# 0 = is Intel
# 1 = is not Intel or unknown
grep "vendor_id" < /proc/cpuinfo | grep -q "GenuineIntel"
}
detect_amd()
{
# return values:
# 0 = is AMD
# 1 = is not AMD or unknown
grep "vendor_id" < /proc/cpuinfo | grep -q "AMD"
}
# base probe utility
check_kprobes_available()
{
test -e /sys/kernel/debug/tracing/kprobe_events
}
check_uprobes_available()
{
test -e /sys/kernel/debug/tracing/uprobe_events
}
clear_all_probes()
{
echo 0 > /sys/kernel/debug/tracing/events/enable
check_kprobes_available && echo > /sys/kernel/debug/tracing/kprobe_events
check_uprobes_available && echo > /sys/kernel/debug/tracing/uprobe_events
}
check_sdt_support()
{
$CMD_PERF list sdt | grep sdt > /dev/null 2> /dev/null
}
@@ -0,0 +1,268 @@
# SPDX-License-Identifier: GPL-2.0
export RE_NUMBER="[0-9\.]+"
# Number
# Examples:
# 123.456
export RE_NUMBER_HEX="[0-9A-Fa-f]+"
# Hexadecimal number
# Examples:
# 1234
# a58d
# aBcD
# deadbeef
export RE_DATE_YYYYMMDD="[0-9]{4}-(?:(?:01|03|05|07|08|10|12)-(?:[0-2][0-9]|3[0-1])|02-[0-2][0-9]|(?:(?:04|06|09|11)-(?:[0-2][0-9]|30)))"
# Date in YYYY-MM-DD form
# Examples:
# 1990-02-29
# 0015-07-31
# 2456-12-31
#! 2012-13-01
#! 1963-09-31
export RE_TIME="(?:[0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]"
# Time
# Examples:
# 15:12:27
# 23:59:59
#! 24:00:00
#! 11:25:60
#! 17:60:15
export RE_DATE_TIME="\w+\s+\w+\s+$RE_NUMBER\s+$RE_TIME\s+$RE_NUMBER"
# Time and date
# Examples:
# Wed Feb 12 10:46:26 2020
# Mon Mar 2 13:27:06 2020
#! St úno 12 10:57:21 CET 2020
#! Po úno 14 15:17:32 2010
export RE_ADDRESS="0x$RE_NUMBER_HEX"
# Memory address
# Examples:
# 0x123abc
# 0xffffffff9abe8ae8
# 0x0
export RE_ADDRESS_NOT_NULL="0x[0-9A-Fa-f]*[1-9A-Fa-f]+[0-9A-Fa-f]*"
# Memory address (not NULL)
# Examples:
# 0xffffffff9abe8ae8
#! 0x0
#! 0x0000000000000000
export RE_PROCESS_PID="[^\/]+\/\d+"
# A process with PID
# Example:
# sleep/4102
# test_overhead./866185
# in:imjournal/1096
# random#$& test/866607
export RE_EVENT_ANY="[\w\-\:\/_=,]+"
# Name of any event (universal)
# Examples:
# cpu-cycles
# cpu/event=12,umask=34/
# r41e1
# nfs:nfs_getattr_enter
export RE_EVENT="[\w\-:_]+"
# Name of an usual event
# Examples:
# cpu-cycles
export RE_EVENT_RAW="r$RE_NUMBER_HEX"
# Specification of a raw event
# Examples:
# r41e1
# r1a
export RE_EVENT_CPU="cpu/(\w+=$RE_NUMBER_HEX,?)+/p*"
# Specification of a CPU event
# Examples:
# cpu/event=12,umask=34/pp
export RE_EVENT_UNCORE="uncore/[\w_]+/"
# Specification of an uncore event
# Examples:
# uncore/qhl_request_local_reads/
export RE_EVENT_SUBSYSTEM="[\w\-]+:[\w\-]+"
# Name of an event from subsystem
# Examples:
# ext4:ext4_ordered_write_end
# sched:sched_switch
export RE_FILE_NAME="[\w\+\.-]+"
# A filename
# Examples:
# libstdc++.so.6
#! some/path
export RE_PATH_ABSOLUTE="(?:\/$RE_FILE_NAME)+"
# A full filepath
# Examples:
# /usr/lib64/somelib.so.5.4.0
# /lib/modules/4.3.0-rc5/kernel/fs/xfs/xfs.ko
# /usr/bin/mv
#! some/relative/path
#! ./some/relative/path
export RE_PATH="(?:$RE_FILE_NAME)?$RE_PATH_ABSOLUTE"
# A filepath
# Examples:
# /usr/lib64/somelib.so.5.4.0
# /lib/modules/4.3.0-rc5/kernel/fs/xfs/xfs.ko
# ./.emacs
# src/fs/file.c
export RE_DSO="(?:$RE_PATH_ABSOLUTE(?: \(deleted\))?|\[kernel\.kallsyms\]|\[unknown\]|\[vdso\]|\[kernel\.vmlinux\][\.\w]*)"
# A DSO name in various result tables
# Examples:
# /usr/lib64/somelib.so.5.4.0
# /usr/bin/somebinart (deleted)
# /lib/modules/4.3.0-rc5/kernel/fs/xfs/xfs.ko
# [kernel.kallsyms]
# [kernel.vmlinux]
# [vdso]
# [unknown]
export RE_LINE_COMMENT="^#.*"
# A comment line
# Examples:
# # Started on Thu Sep 10 11:43:00 2015
export RE_LINE_EMPTY="^\s*$"
# An empty line with possible whitespaces
# Examples:
#
export RE_LINE_RECORD1="^\[\s+perf\s+record:\s+Woken up $RE_NUMBER times? to write data\s+\].*$"
# The first line of perf-record "OK" output
# Examples:
# [ perf record: Woken up 1 times to write data ]
export RE_LINE_RECORD2="^\[\s+perf\s+record:\s+Captured and wrote $RE_NUMBER\s*MB\s+(?:[\w\+\.-]*(?:$RE_PATH)?\/)?perf\.data(?:\.\d+)?\s*\(~?$RE_NUMBER samples\)\s+\].*$"
# The second line of perf-record "OK" output
# Examples:
# [ perf record: Captured and wrote 0.405 MB perf.data (109 samples) ]
# [ perf record: Captured and wrote 0.405 MB perf.data (~109 samples) ]
# [ perf record: Captured and wrote 0.405 MB /some/temp/dir/perf.data (109 samples) ]
# [ perf record: Captured and wrote 0.405 MB ./perf.data (109 samples) ]
# [ perf record: Captured and wrote 0.405 MB ./perf.data.3 (109 samples) ]
export RE_LINE_RECORD2_TOLERANT="^\[\s+perf\s+record:\s+Captured and wrote $RE_NUMBER\s*MB\s+(?:[\w\+\.-]*(?:$RE_PATH)?\/)?perf\.data(?:\.\d+)?\s*(?:\(~?$RE_NUMBER samples\))?\s+\].*$"
# The second line of perf-record "OK" output, even no samples is OK here
# Examples:
# [ perf record: Captured and wrote 0.405 MB perf.data (109 samples) ]
# [ perf record: Captured and wrote 0.405 MB perf.data (~109 samples) ]
# [ perf record: Captured and wrote 0.405 MB /some/temp/dir/perf.data (109 samples) ]
# [ perf record: Captured and wrote 0.405 MB ./perf.data (109 samples) ]
# [ perf record: Captured and wrote 0.405 MB ./perf.data.3 (109 samples) ]
# [ perf record: Captured and wrote 0.405 MB perf.data ]
export RE_LINE_RECORD2_TOLERANT_FILENAME="^\[\s+perf\s+record:\s+Captured and wrote $RE_NUMBER\s*MB\s+(?:[\w\+\.-]*(?:$RE_PATH)?\/)?perf\w*\.data(?:\.\d+)?\s*\(~?$RE_NUMBER samples\)\s+\].*$"
# The second line of perf-record "OK" output
# Examples:
# [ perf record: Captured and wrote 0.405 MB perf.data (109 samples) ]
# [ perf record: Captured and wrote 0.405 MB perf_ls.data (~109 samples) ]
# [ perf record: Captured and wrote 0.405 MB perf_aNyCaSe.data (109 samples) ]
# [ perf record: Captured and wrote 0.405 MB ./perfdata.data.3 (109 samples) ]
#! [ perf record: Captured and wrote 0.405 MB /some/temp/dir/my_own.data (109 samples) ]
#! [ perf record: Captured and wrote 0.405 MB ./UPPERCASE.data (109 samples) ]
#! [ perf record: Captured and wrote 0.405 MB ./aNyKiNDoF.data.3 (109 samples) ]
#! [ perf record: Captured and wrote 0.405 MB perf.data ]
export RE_LINE_TRACE_FULL="^\s*$RE_NUMBER\s*\(\s*$RE_NUMBER\s*ms\s*\):\s*$RE_PROCESS_PID\s+.*\)\s+=\s+(:?\-?$RE_NUMBER|0x$RE_NUMBER_HEX).*$"
# A line of perf-trace output
# Examples:
# 0.115 ( 0.005 ms): sleep/4102 open(filename: 0xd09e2ab2, flags: CLOEXEC ) = 3
# 0.157 ( 0.005 ms): sleep/4102 mmap(len: 3932736, prot: EXEC|READ, flags: PRIVATE|DENYWRITE, fd: 3 ) = 0x7f89d0605000
#! 0.115 ( 0.005 ms): sleep/4102 open(filename: 0xd09e2ab2, flags: CLOEXEC ) =
export RE_LINE_TRACE_ONE_PROC="^\s*$RE_NUMBER\s*\(\s*$RE_NUMBER\s*ms\s*\):\s*\w+\(.*\)\s+=\s+(?:\-?$RE_NUMBER|0x$RE_NUMBER_HEX).*$"
# A line of perf-trace output
# Examples:
# 0.115 ( 0.005 ms): open(filename: 0xd09e2ab2, flags: CLOEXEC ) = 3
# 0.157 ( 0.005 ms): mmap(len: 3932736, prot: EXEC|READ, flags: PRIVATE|DENYWRITE, fd: 3 ) = 0x7f89d0605000
#! 0.115 ( 0.005 ms): open(filename: 0xd09e2ab2, flags: CLOEXEC ) =
export RE_LINE_TRACE_CONTINUED="^\s*(:?$RE_NUMBER|\?)\s*\(\s*($RE_NUMBER\s*ms\s*)?\):\s*($RE_PROCESS_PID\s*)?\.\.\.\s*\[continued\]:\s+\w+\(\).*\s+=\s+(?:\-?$RE_NUMBER|0x$RE_NUMBER_HEX).*$"
# A line of perf-trace output
# Examples:
# 0.000 ( 0.000 ms): ... [continued]: nanosleep()) = 0
# 0.000 ( 0.000 ms): ... [continued]: nanosleep()) = 0x00000000
# ? ( ): packagekitd/94838 ... [continued]: poll()) = 0 (Timeout)
#! 0.000 ( 0.000 ms): ... [continued]: nanosleep()) =
export RE_LINE_TRACE_UNFINISHED="^\s*$RE_NUMBER\s*\(\s*\):\s*$RE_PROCESS_PID\s+.*\)\s+\.\.\.\s*$"
# A line of perf-trace output
# Examples:
# 901.040 ( ): in:imjournal/1096 ppoll(ufds: 0x7f701a5adb70, nfds: 1, tsp: 0x7f701a5adaf0, sigsetsize: 8) ...
# 613.727 ( ): gmain/1099 poll(ufds: 0x56248f6b64b0, nfds: 2, timeout_msecs: 3996) ...
export RE_LINE_TRACE_SUMMARY_HEADER="\s*syscall\s+calls\s+(?:errors\s+)?total\s+min\s+avg\s+max\s+stddev"
# A header of a perf-trace summary table
# Example:
# syscall calls total min avg max stddev
# syscall calls errors total min avg max stddev
export RE_LINE_TRACE_SUMMARY_CONTENT="^\s*\w+\s+(?:$RE_NUMBER\s+){5,6}$RE_NUMBER%"
# A line of a perf-trace summary table
# Example:
# open 3 0.017 0.005 0.006 0.007 10.90%
# openat 2 0 0.017 0.008 0.009 0.010 12.29%
export RE_LINE_REPORT_CONTENT="^\s+$RE_NUMBER%\s+\w+\s+\S+\s+\S+\s+\S+" # FIXME
# A line from typicap perf report --stdio output
# Example:
# 100.00% sleep [kernel.vmlinux] [k] syscall_return_slowpath
export RE_TASK="\s+[\w~\/ \.\+:#-]+(?:\[-1(?:\/\d+)?\]|\[\d+(?:\/\d+)?\])"
# A name of a task used for perf sched timehist -s
# Example:
# sleep[62755]
# runtest.sh[62762]
# gmain[705/682]
# xfsaild/dm-0[495]
# kworker/u8:1-ev[62714]
# :-1[-1/62756]
# :-1[-1]
# :-1[62756]
export RE_SEGFAULT=".*(?:Segmentation\sfault|SIGSEGV|\score\s|dumped|segfault).*"
# Possible variations of the segfault message
# Example:
# /bin/bash: line 1: 32 Segmentation fault timeout 15s
# Segmentation fault (core dumped)
# Program terminated with signal SIGSEGV
#! WARNING: 12323431 isn't a 'cpu_core', please use a CPU list in the 'cpu_core' range (0-15)
@@ -0,0 +1,105 @@
# SPDX-License-Identifier: GPL-2.0
#
# settings.sh
# Author: Michael Petlan <mpetlan@redhat.com>
#
# Description:
#
# This file contains global settings for the whole testsuite.
# Its purpose is to make it easier when it is necessary i.e. to
# change the usual sample command which is used in all of the tests
# in many files.
#
# This file is intended to be sourced in the tests.
#
#### which perf to use in the testing
export CMD_PERF=${CMD_PERF:-`which perf`}
#### basic programs examinated by perf
export CMD_BASIC_SLEEP="sleep 0.1"
export CMD_QUICK_SLEEP="sleep 0.01"
export CMD_LONGER_SLEEP="sleep 2"
export CMD_DOUBLE_LONGER_SLEEP="sleep 4"
export CMD_VERY_LONG_SLEEP="sleep 30"
export CMD_SIMPLE="true"
#### testsuite run mode
# define constants:
export RUNMODE_BASIC=0
export RUNMODE_STANDARD=1
export RUNMODE_EXPERIMENTAL=2
# default runmode is STANDARD
export PERFTOOL_TESTSUITE_RUNMODE=${PERFTOOL_TESTSUITE_RUNMODE:-$RUNMODE_STANDARD}
#### common settings
export TESTLOG_VERBOSITY=${TESTLOG_VERBOSITY:-2}
export TESTLOG_FORCE_COLOR=${TESTLOG_FORCE_COLOR:-n}
export TESTLOG_ERR_MSG_MAX_LINES=${TESTLOG_ERR_MSG_MAX_LINES:-20}
export TESTLOG_CLEAN=${TESTLOG_CLEAN:-y}
#### other environment-related settings
export TEST_IGNORE_MISSING_PMU=${TEST_IGNORE_MISSING_PMU:-n}
#### clear locale
export LC_ALL=C
#### colors
if [ -t 1 ] || [ "$TESTLOG_FORCE_COLOR" = "yes" ]; then
export MPASS="\e[32m"
export MALLPASS="\e[1;32m"
export MFAIL="\e[31m"
export MALLFAIL="\e[1;31m"
export MWARN="\e[1;35m"
export MSKIP="\e[33m"
export MHIGH="\e[1;33m"
export MEND="\e[m"
else
export MPASS=""
export MALLPASS=""
export MFAIL=""
export MALLFAIL=""
export MWARN=""
export MSKIP=""
export MHIGH=""
export MEND=""
fi
### general info
DIR_PATH=`dirname "$(readlink -e "$0")"`
TEST_NAME=`basename $DIR_PATH | sed 's/base/perf/'`; export TEST_NAME
MY_ARCH=`arch`; export MY_ARCH
# storing logs and temporary files variables
if [ -n "$PERFSUITE_RUN_DIR" ]; then
# when $PERFSUITE_RUN_DIR is set to something, all the logs and temp files will be placed there
# --> the $PERFSUITE_RUN_DIR/perf_something/examples and $PERFSUITE_RUN_DIR/perf_something/logs
# dirs will be used for that
PERFSUITE_RUN_DIR=`readlink -f $PERFSUITE_RUN_DIR`; export PERFSUITE_RUN_DIR
export CURRENT_TEST_DIR="$PERFSUITE_RUN_DIR/$TEST_NAME"
export MAKE_TARGET_DIR="$CURRENT_TEST_DIR/examples"
export LOGS_DIR="$CURRENT_TEST_DIR/logs"
export HEADER_TAR_DIR="$CURRENT_TEST_DIR/header_tar"
test -d "$CURRENT_TEST_DIR" || mkdir -p "$CURRENT_TEST_DIR"
test -d "$LOGS_DIR" || mkdir -p "$LOGS_DIR"
else
# when $PERFSUITE_RUN_DIR is not set, logs will be placed here
export CURRENT_TEST_DIR="."
export LOGS_DIR="."
export HEADER_TAR_DIR="./header_tar"
fi
#### test parametrization
if [ ! -d ./common ]; then
# set parameters based on runmode
if [ -f ../common/parametrization.$PERFTOOL_TESTSUITE_RUNMODE.sh ]; then
# shellcheck source=/dev/null
. ../common/parametrization.$PERFTOOL_TESTSUITE_RUNMODE.sh
fi
# if some parameters haven't been set until now, set them to default
if [ -f ../common/parametrization.sh ]; then
. ../common/parametrization.sh
fi
fi
@@ -0,0 +1,45 @@
#!/bin/bash -e
# CoreSight concurrent threads (exclusive)
# SPDX-License-Identifier: GPL-2.0
# If CoreSight is not available, skip the test
perf list pmu | grep -q cs_etm || exit 2
tmpdir=$(mktemp -d /tmp/__perf_test.coresight_concurrent_threads.XXXXX)
cleanup() {
rm -rf "${tmpdir}"
trap - EXIT TERM INT
}
trap_cleanup() {
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
cf="$tmpdir/ctl"
af="$tmpdir/ack"
mkfifo "$cf" "$af"
nthreads=10
# Timestamps off to reduce trace size, start disabled and use the control FIFO
# to only record the workload and not startup.
perf record -o "$tmpdir/data" -e cs_etm/timestamp=0/u -D -1 --control fifo:"$cf","$af" \
-- perf test --record-ctl fifo:"$cf","$af" -w named_threads $nthreads 1 > /dev/null 2>&1
perf script -i "$tmpdir/data" > "$tmpdir/script" 2>/dev/null
# Check all threads were traced and they have the correct thread name and symbol
for i in $(seq 1 $nthreads); do
if ! grep -q "thread${i} .* named_threads_thread${i}" "$tmpdir/script"; then
echo "Error: thread${i} missing" >&2
cleanup
exit 1
fi
done
cleanup
exit 0
@@ -0,0 +1,69 @@
#!/bin/bash -e
# CoreSight context switch thread attribution (exclusive)
# SPDX-License-Identifier: GPL-2.0
# If CoreSight is not available, skip the test
perf list pmu | grep -q cs_etm || exit 2
if [ "$(id -u)" != 0 ]; then
# Requires root for "-C 0" in record command
echo "[Skip] No root permission"
exit 2
fi
tmpdir=$(mktemp -d /tmp/__perf_test.coresight_context_switch.XXXXX)
cleanup() {
rm -rf "${tmpdir}"
trap - EXIT TERM INT
}
trap_cleanup() {
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
check_samples() {
owner_samples=$(grep -c "proc1.*context_switch_loop_proc1" "$tmpdir/script" || true)
next_samples=$(grep -c "proc2.*context_switch_loop_proc2" "$tmpdir/script" || true)
if [ "$owner_samples" -eq 0 ] || [ "$next_samples" -eq 0 ]; then
echo "No samples found"
cleanup
exit 1
fi
if grep "proc2.*context_switch_loop_proc1" "$tmpdir/script"; then
echo "Thread1 symbol was attributed to proc2"
cleanup
exit 1
fi
if grep "proc1.*context_switch_loop_proc2" "$tmpdir/script"; then
echo "Thread2 symbol was attributed to proc1"
cleanup
exit 1
fi
}
cf="$tmpdir/ctl"
af="$tmpdir/ack"
mkfifo "$cf" "$af"
# Pin to one CPU so the two threads alternate running but record into the same
# trace buffer. Start disabled and use the control FIFO to only record the
# workload and not startup.
perf record -o "$tmpdir/data" -e cs_etm/timestamp=0/u -C 0 -D -1 --control fifo:"$cf","$af" -- \
taskset --cpu-list 0 perf test --record-ctl fifo:"$cf","$af" \
-w context_switch_loop > /dev/null 2>&1
# Test both instruction and branch sample generation modes.
perf script -i "$tmpdir/data" --itrace=i4 -F comm,pid,tid,ip,sym > "$tmpdir/script" 2>/dev/null
check_samples
perf script -i "$tmpdir/data" --itrace=b -F comm,pid,tid,ip,sym > "$tmpdir/script" 2>/dev/null
check_samples
cleanup
exit 0
@@ -0,0 +1,72 @@
#!/bin/bash -e
# CoreSight deterministic workload decode (exclusive)
# SPDX-License-Identifier: GPL-2.0
# If CoreSight is not available, skip the test
perf list pmu | grep -q cs_etm || exit 2
tmpdir=$(mktemp -d /tmp/__perf_test.coresight_deterministic.XXXXX)
cleanup() {
rm -rf "${tmpdir}"
trap - EXIT TERM INT
}
trap_cleanup() {
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
cf="$tmpdir/ctl"
af="$tmpdir/ack"
mkfifo "$cf" "$af"
# Start disabled and use the control FIFO to only record the workload and not
# startup.
perf record -o "$tmpdir/data" -e cs_etm//u -D -1 --control fifo:"$cf","$af" -- \
perf test --record-ctl fifo:"$cf","$af" -w deterministic > /dev/null 2>&1
perf script -i "$tmpdir/data" --itrace=i1i -F ip,srcline | \
grep "deterministic.c" | uniq > "$tmpdir/script" 2>/dev/null
# Remove brace lines and call sites as they may not be hit or may have
# extra hits after returning, depending on the compiler.
sed -i \
-e '/deterministic.c:8$/d' \
-e '/deterministic.c:12$/d' \
-e '/deterministic.c:15$/d' \
-e '/deterministic.c:19$/d' \
-e '/deterministic.c:23$/d' \
-e '/deterministic.c:28$/d' \
-e '/deterministic.c:34$/d' \
-e '/deterministic.c:36$/d' \
-e '/deterministic.c:37$/d' \
"$tmpdir/script"
cat > "$tmpdir/expected" << EOF
deterministic.c:24
deterministic.c:25
deterministic.c:26
deterministic.c:9
deterministic.c:10
deterministic.c:11
deterministic.c:30
deterministic.c:31
deterministic.c:32
deterministic.c:16
deterministic.c:17
deterministic.c:18
EOF
if ! diff -q "$tmpdir/script" "$tmpdir/expected"; then
echo "FAIL: line numbers don't match expected: "
head -n 100 "$tmpdir/script"
cleanup
exit 1
fi
cleanup
exit 0
@@ -0,0 +1,65 @@
#!/bin/bash -e
# CoreSight raw dump stress (exclusive)
# SPDX-License-Identifier: GPL-2.0
if [ "$(id -u)" != 0 ]; then
# Requires root for larger buffer size
echo "[Skip] No root permission"
exit 2
fi
# If CoreSight is not available, skip the test
perf list pmu | grep -q cs_etm || exit 2
tmpdir=$(mktemp -d /tmp/__perf_test.coresight_raw_dump_stress.XXXXX)
cleanup() {
rm -r "${tmpdir}"
trap - EXIT TERM INT
}
trap_cleanup() {
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
# Use exit snapshot to record 2M of trace to make about 80MB of raw dump data.
echo "Recording..."
perf record -e cs_etm/timestamp=0/u -m,2M -Se -o "$tmpdir/data" -- \
perf test -w brstack 20000 > /dev/null 2>&1
# Test raw dump runs to completion but don't decode because that's too slow for
# a test
echo "Dumping raw trace..."
perf report --dump-raw-trace -i "$tmpdir/data" 2>/dev/null > "$tmpdir/rawdump"
# Get the size and offset of the first AUXTRACE buffer and the index of the last
# packet in the raw dump.
read -r size offset last_idx <<< "$(awk '
found && /PERF_RECORD_/ { exit }
/PERF_RECORD_AUXTRACE / { found = 1; size = $7; offset = $9; next }
found && /Idx:/ { last_idx = $1; gsub(/Idx:|;/, "", last_idx) }
END { if (last_idx) print size, offset, last_idx }
' "$tmpdir/rawdump")"
# The last Idx minus start offset should equal the size of the buffer if
# everything was dumped. Allow 48 bytes difference to cover 3 frames: current
# frame length, a partial frame and a final empty one, all of which aren't
# dumped.
#
# TODO: for a single snapshot, offset should always be zero. However, we
# currently output AUX records in snapshot mode when we shouldn't, which
# increments the offset. Allow for that until it's fixed so we can test raw
# dumping.
decode_size=$((1 + last_idx - offset))
if [ "$decode_size" -gt "$((size - 48))" ] && [ "$decode_size" -le "$((size))" ]; then
echo "PASS: AUXTRACE buffer length matches dumped packet index"
cleanup
exit 0
fi
echo "FAIL: AUXTRACE buffer length mismatch: size=$size offset=$offset last_idx=$last_idx decode_size=$decode_size"
cleanup
exit 1
@@ -0,0 +1,257 @@
#!/bin/bash
# Check Arm CoreSight trace data recording and synthesized samples (exclusive)
# Uses the 'perf record' to record trace data with Arm CoreSight sinks;
# then verify if there have any branch samples and instruction samples
# are generated by CoreSight with 'perf script' and 'perf report'
# commands.
# SPDX-License-Identifier: GPL-2.0
# Leo Yan <leo.yan@linaro.org>, 2020
glb_err=0
skip_if_no_cs_etm_event() {
perf list pmu | grep -q 'cs_etm//' && return 0
# cs_etm event doesn't exist
return 2
}
skip_if_no_cs_etm_event || exit 2
if [ "$(id -u)" != 0 ]; then
# Requires root for -C and system wide tests
echo "[Skip] No root permission"
exit 2
fi
perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
file=$(mktemp /tmp/temporary_file.XXXXX)
cleanup_files()
{
rm -f ${perfdata}
rm -f ${file}
rm -f "${perfdata}.old"
trap - EXIT TERM INT
exit $glb_err
}
trap cleanup_files EXIT TERM INT
record_touch_file() {
echo "Recording trace (only user mode) with path: CPU$2 => $1"
rm -f $file
perf record -o ${perfdata} -e cs_etm/@$1/u --per-thread \
-- taskset -c $2 touch $file > /dev/null 2>&1
}
perf_script_branch_samples() {
echo "Looking at perf.data file for dumping branch samples:"
# Below is an example of the branch samples dumping:
# touch 6512 1 branches:u: ffffb220824c strcmp+0xc (/lib/aarch64-linux-gnu/ld-2.27.so)
# touch 6512 1 branches:u: ffffb22082e0 strcmp+0xa0 (/lib/aarch64-linux-gnu/ld-2.27.so)
# touch 6512 1 branches:u: ffffb2208320 strcmp+0xe0 (/lib/aarch64-linux-gnu/ld-2.27.so)
perf script -F,-time -i ${perfdata} 2>&1 | \
grep -E " +$1 +[0-9]+ .* +branches:(.*:)? +" > /dev/null 2>&1
}
perf_report_instruction_samples() {
echo "Looking at perf.data file for instruction samples:"
# Below is an example of the instruction samples reporting:
# 68.12% touch libc-2.27.so [.] _dl_addr
# 5.80% touch libc-2.27.so [.] getenv
# 4.35% touch ld-2.27.so [.] _dl_fixup
perf report --itrace=i20i --stdio -i ${perfdata} 2>&1 | \
grep -E " +[0-9]+\.[0-9]+% +$1" > /dev/null 2>&1
}
arm_cs_report() {
if [ $2 != 0 ]; then
echo "$1: FAIL"
glb_err=$2
else
echo "$1: PASS"
fi
}
is_device_sink() {
# If the node of "enable_sink" is existed under the device path, this
# means the device is a sink device. Need to exclude 'tpiu' since it
# cannot support perf PMU.
echo "$1" | grep -E -q -v "tpiu"
if [ $? -eq 0 ] && [ -e "$1/enable_sink" ]; then
pmu_dev="/sys/bus/event_source/devices/cs_etm/sinks/$2"
# Warn if the device is not supported by PMU
if ! [ -f $pmu_dev ]; then
echo "PMU doesn't support $pmu_dev"
fi
return 0
fi
# Otherwise, it's not a sink device
return 1
}
arm_cs_iterate_devices() {
for dev in $1/connections/out\:*; do
# Skip testing if it's not a directory
! [ -d $dev ] && continue;
# Read out its symbol link file name
path=`readlink -f $dev`
# Extract device name from path, e.g.
# path = '/sys/devices/platform/20010000.etf/tmc_etf0'
# `> device_name = 'tmc_etf0'
device_name=$(basename $path)
if is_device_sink $path $device_name; then
record_touch_file $device_name $2 &&
perf_script_branch_samples touch &&
perf_report_instruction_samples touch
err=$?
arm_cs_report "CoreSight path testing (CPU$2 -> $device_name)" $err
fi
arm_cs_iterate_devices $dev $2
done
}
arm_cs_etm_traverse_path_test() {
# Iterate for every ETM device
for dev in /sys/bus/event_source/devices/cs_etm/cpu*; do
# Canonicalize the path
dev=`readlink -f $dev`
# Find the ETM device belonging to which CPU
cpu=`cat $dev/cpu`
# Use depth-first search (DFS) to iterate outputs
arm_cs_iterate_devices $dev $cpu
done
}
arm_cs_etm_system_wide_test() {
echo "Recording trace with system wide mode"
perf record -o ${perfdata} -e cs_etm// -a -- ls > /dev/null 2>&1
# System-wide mode should include perf samples so test for that
# instead of ls
perf_script_branch_samples perf
err=$?
arm_cs_report "CoreSight system wide testing" $err
}
arm_cs_etm_snapshot_test() {
echo "Recording trace with snapshot mode"
perf record -o ${perfdata} -e cs_etm// -S -m,128K \
-- dd if=/dev/zero of=/dev/null > /dev/null 2>&1 &
PERFPID=$!
# Wait for perf program
sleep 1
# Send signal to snapshot trace data
kill -USR2 $PERFPID
# Stop perf program
kill $PERFPID
wait $PERFPID
perf_script_branch_samples dd &&
perf_report_instruction_samples dd
err=$?
arm_cs_report "CoreSight snapshot testing" $err
}
arm_cs_etm_basic_test() {
echo "Recording trace with '$*'"
perf record -o ${perfdata} "$@" -- true > /dev/null 2>&1
perf_script_branch_samples true
err=$?
arm_cs_report "CoreSight basic testing with '$*'" $err
}
arm_cs_etm_test_cpu_list() {
echo "Testing sparse CPU list: $1"
perf record -o ${perfdata} -e cs_etm//u -C $1 \
-- taskset --cpu-list $1 true > /dev/null 2>&1
perf_script_branch_samples true
err=$?
arm_cs_report "CoreSight sparse CPUs with '$*'" $err
}
arm_cs_etm_sparse_cpus_test() {
# Iterate for every ETM device
cpus=()
for dev in /sys/bus/event_source/devices/cs_etm/cpu*; do
# Canonicalize the path
dev=`readlink -f $dev`
# Find the ETM device belonging to which CPU
cpus+=("$(cat $dev/cpu)")
done
mapfile -t cpus < <(printf '%s\n' "${cpus[@]}" | sort -n)
total=${#cpus[@]}
# Need more than 1 to test
if [ $total -le 1 ]; then
return 0
fi
half=$((total / 2))
# First half
first_half=$(IFS=,; echo "${cpus[*]:0:$half}")
arm_cs_etm_test_cpu_list $first_half
# Second half
second_half=$(IFS=,; echo "${cpus[*]:$half}")
arm_cs_etm_test_cpu_list $second_half
# Odd list is the same as halves unless >= 4 CPUs
if [ $total -lt 4 ]; then
return 0
fi
# Odd indices
odd_cpus=()
for ((i=1; i<total; i+=2)); do
odd_cpus+=("${cpus[$i]}")
done
odd_list=$(IFS=,; echo "${odd_cpus[*]}")
arm_cs_etm_test_cpu_list $odd_list
}
arm_cs_etm_traverse_path_test
arm_cs_etm_system_wide_test
arm_cs_etm_snapshot_test
# Test all combinations of per-thread, system-wide and normal mode with
# and without timestamps
arm_cs_etm_basic_test -e cs_etm/timestamp=0/u --per-thread
arm_cs_etm_basic_test -e cs_etm/timestamp=1/u --per-thread
arm_cs_etm_basic_test -e cs_etm/timestamp=0/u -a
arm_cs_etm_basic_test -e cs_etm/timestamp=1/u -a
arm_cs_etm_basic_test -e cs_etm/timestamp=0/u
arm_cs_etm_basic_test -e cs_etm/timestamp=1/u
arm_cs_etm_sparse_cpus_test
exit $glb_err
@@ -0,0 +1,64 @@
#!/bin/bash
# Check Arm CoreSight disassembly script completes without errors (exclusive)
# SPDX-License-Identifier: GPL-2.0
# The disassembly script reconstructs ranges of instructions and gives these to objdump to
# decode. objdump doesn't like ranges that go backwards, but these are a good indication
# that decoding has gone wrong either in OpenCSD, Perf or in the range reconstruction in
# the script. Test all 3 parts are working correctly by running the script.
skip_if_no_cs_etm_event() {
perf list pmu | grep -q 'cs_etm//' && return 0
# cs_etm event doesn't exist
return 2
}
skip_if_no_cs_etm_event || exit 2
# Assume an error unless we reach the very end
set -e
glb_err=1
perfdata_dir=$(mktemp -d /tmp/__perf_test.perf.data.XXXXX)
perfdata=${perfdata_dir}/perf.data
file=$(mktemp /tmp/temporary_file.XXXXX)
# Relative path works whether it's installed or running from repo
script_path=$(dirname "$0")/../../../scripts/python/arm-cs-trace-disasm.py
cleanup_files()
{
set +e
rm -rf ${perfdata_dir}
rm -f ${file}
trap - EXIT TERM INT
exit $glb_err
}
trap cleanup_files EXIT TERM INT
# Ranges start and end on branches, so check for some likely branch instructions
branch_search='[[:space:]](bl|b(\.(eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al))?|br|blr|ret|cbz|cbnz|tbz|tbnz|svc|eret)([[:space:]]|$)'
## Test kernel ##
if [ "$(id -u)" == 0 ] && [ -e /proc/kcore ]; then
echo "Testing kernel disassembly"
perf record -o ${perfdata} -e cs_etm//k --kcore -Se -m,64K -- touch $file > /dev/null 2>&1
perf script -i ${perfdata} -s python:${script_path} -- \
-d --stop-sample=2 -k ${perfdata}/kcore_dir/kcore 2> /dev/null > ${file}
grep -q -E ${branch_search} ${file}
echo "Found kernel branches"
else
# Root and kcore are required for correct kernel decode due to runtime code patching
echo "No root or kcore, skipping kernel test"
fi
## Test user ##
echo "Testing userspace disassembly"
perf record -o ${perfdata} -e cs_etm//u -Se -m,64K -- touch $file > /dev/null 2>&1
perf script -i ${perfdata} -s python:${script_path} -- \
-d --stop-sample=2 2> /dev/null > ${file}
grep -q -E ${branch_search} ${file}
echo "Found userspace branches"
glb_err=0
+538
View File
@@ -0,0 +1,538 @@
#!/bin/bash
# daemon operations
# SPDX-License-Identifier: GPL-2.0
check_line_first()
{
local line=$1
local name=$2
local base=$3
local output=$4
local lock=$5
local up=$6
local line_name
line_name=`echo "${line}" | awk 'BEGIN { FS = ":" } ; { print $2 }'`
local line_base
line_base=`echo "${line}" | awk 'BEGIN { FS = ":" } ; { print $3 }'`
local line_output
line_output=`echo "${line}" | awk 'BEGIN { FS = ":" } ; { print $4 }'`
local line_lock
line_lock=`echo "${line}" | awk 'BEGIN { FS = ":" } ; { print $5 }'`
local line_up
line_up=`echo "${line}" | awk 'BEGIN { FS = ":" } ; { print $6 }'`
if [ "${name}" != "${line_name}" ]; then
echo "FAILED: wrong name"
error=1
fi
if [ "${base}" != "${line_base}" ]; then
echo "FAILED: wrong base"
error=1
fi
if [ "${output}" != "${line_output}" ]; then
echo "FAILED: wrong output"
error=1
fi
if [ "${lock}" != "${line_lock}" ]; then
echo "FAILED: wrong lock"
error=1
fi
if [ "${up}" != "${line_up}" ]; then
echo "FAILED: wrong up"
error=1
fi
}
check_line_other()
{
local line=$1
local name=$2
local run=$3
local base=$4
local output=$5
local control=$6
local ack=$7
local up=$8
local line_name
line_name=`echo "${line}" | awk 'BEGIN { FS = ":" } ; { print $2 }'`
local line_run
line_run=`echo "${line}" | awk 'BEGIN { FS = ":" } ; { print $3 }'`
local line_base
line_base=`echo "${line}" | awk 'BEGIN { FS = ":" } ; { print $4 }'`
local line_output
line_output=`echo "${line}" | awk 'BEGIN { FS = ":" } ; { print $5 }'`
local line_control
line_control=`echo "${line}" | awk 'BEGIN { FS = ":" } ; { print $6 }'`
local line_ack
line_ack=`echo "${line}" | awk 'BEGIN { FS = ":" } ; { print $7 }'`
local line_up
line_up=`echo "${line}" | awk 'BEGIN { FS = ":" } ; { print $8 }'`
if [ "${name}" != "${line_name}" ]; then
echo "FAILED: wrong name"
error=1
fi
if [ "${run}" != "${line_run}" ]; then
echo "FAILED: wrong run"
error=1
fi
if [ "${base}" != "${line_base}" ]; then
echo "FAILED: wrong base"
error=1
fi
if [ "${output}" != "${line_output}" ]; then
echo "FAILED: wrong output"
error=1
fi
if [ "${control}" != "${line_control}" ]; then
echo "FAILED: wrong control"
error=1
fi
if [ "${ack}" != "${line_ack}" ]; then
echo "FAILED: wrong ack"
error=1
fi
if [ "${up}" != "${line_up}" ]; then
echo "FAILED: wrong up"
error=1
fi
}
daemon_exit()
{
local config=$1
local line
line=`perf daemon --config ${config} -x: | head -1`
local pid
pid=`echo "${line}" | awk 'BEGIN { FS = ":" } ; { print $1 }'`
# Reset trap handler.
trap - SIGINT SIGTERM
# stop daemon
perf daemon stop --config ${config}
# ... and wait for the pid to go away
tail --pid=${pid} -f /dev/null
}
daemon_start()
{
local config=$1
local session=$2
perf daemon start --config ${config}
# Clean up daemon if interrupted.
trap 'echo "FAILED: Signal caught"; daemon_exit "${config}"; exit 1' SIGINT SIGTERM
# wait for the session to ping
local state="FAIL"
local retries=0
while [ "${state}" != "OK" ]; do
state=`perf daemon ping --config ${config} --session ${session} | awk '{ print $1 }'`
sleep 0.05
retries=$((${retries} +1))
if [ ${retries} -ge 600 ]; then
echo "FAILED: Timeout waiting for daemon to ping"
daemon_exit ${config}
exit 1
fi
done
}
test_list()
{
echo "test daemon list"
local config
config=$(mktemp /tmp/perf.daemon.config.XXX)
local base
base=$(mktemp -d /tmp/perf.daemon.base.XXX)
cat <<EOF > ${config}
[daemon]
base=BASE
[session-size]
run = -e cpu-clock -m 1 sleep 10
[session-time]
run = -e task-clock -m 1 sleep 10
EOF
sed -i -e "s|BASE|${base}|" ${config}
# start daemon
daemon_start ${config} size
# check first line
# pid:daemon:base:base/output:base/lock
local line
line=`perf daemon --config ${config} -x: | head -1`
check_line_first ${line} daemon ${base} ${base}/output ${base}/lock "0"
# check 1st session
# pid:size:-e cpu-clock:base/size:base/size/output:base/size/control:base/size/ack:0
local line
line=`perf daemon --config ${config} -x: | head -2 | tail -1`
check_line_other "${line}" size "-e cpu-clock -m 1 sleep 10" ${base}/session-size \
${base}/session-size/output ${base}/session-size/control \
${base}/session-size/ack "0"
# check 2nd session
# pid:time:-e task-clock:base/time:base/time/output:base/time/control:base/time/ack:0
local line
line=`perf daemon --config ${config} -x: | head -3 | tail -1`
check_line_other "${line}" time "-e task-clock -m 1 sleep 10" ${base}/session-time \
${base}/session-time/output ${base}/session-time/control \
${base}/session-time/ack "0"
# stop daemon
daemon_exit ${config}
rm -rf ${base}
rm -f ${config}
}
test_reconfig()
{
echo "test daemon reconfig"
local config
config=$(mktemp /tmp/perf.daemon.config.XXX)
local base
base=$(mktemp -d /tmp/perf.daemon.base.XXX)
# prepare config
cat <<EOF > ${config}
[daemon]
base=BASE
[session-size]
run = -e cpu-clock -m 1 sleep 10
[session-time]
run = -e task-clock -m 1 sleep 10
EOF
sed -i -e "s|BASE|${base}|" ${config}
# start daemon
daemon_start ${config} size
# check 2nd session
# pid:time:-e task-clock:base/time:base/time/output:base/time/control:base/time/ack:0
local line
line=`perf daemon --config ${config} -x: | head -3 | tail -1`
check_line_other "${line}" time "-e task-clock -m 1 sleep 10" ${base}/session-time \
${base}/session-time/output ${base}/session-time/control ${base}/session-time/ack "0"
local pid
pid=`echo "${line}" | awk 'BEGIN { FS = ":" } ; { print $1 }'`
# prepare new config
local config_new=${config}.new
cat <<EOF > ${config_new}
[daemon]
base=BASE
[session-size]
run = -e cpu-clock -m 1 sleep 10
[session-time]
run = -e cpu-clock -m 1 sleep 10
EOF
# TEST 1 - change config
sed -i -e "s|BASE|${base}|" ${config_new}
cp ${config_new} ${config}
# wait for old session to finish
tail --pid=${pid} -f /dev/null
# wait for new one to start
local state="FAIL"
while [ "${state}" != "OK" ]; do
state=`perf daemon ping --config ${config} --session time | awk '{ print $1 }'`
done
# check reconfigured 2nd session
# pid:time:-e task-clock:base/time:base/time/output:base/time/control:base/time/ack:0
local line
line=`perf daemon --config ${config} -x: | head -3 | tail -1`
check_line_other "${line}" time "-e cpu-clock -m 1 sleep 10" ${base}/session-time \
${base}/session-time/output ${base}/session-time/control ${base}/session-time/ack "0"
# TEST 2 - empty config
local config_empty=${config}.empty
cat <<EOF > ${config_empty}
[daemon]
base=BASE
EOF
# change config
sed -i -e "s|BASE|${base}|" ${config_empty}
cp ${config_empty} ${config}
# wait for sessions to finish
local state="OK"
while [ "${state}" != "FAIL" ]; do
state=`perf daemon ping --config ${config} --session time | awk '{ print $1 }'`
done
local state="OK"
while [ "${state}" != "FAIL" ]; do
state=`perf daemon ping --config ${config} --session size | awk '{ print $1 }'`
done
local one
one=`perf daemon --config ${config} -x: | wc -l`
if [ ${one} -ne "1" ]; then
echo "FAILED: wrong list output"
error=1
fi
# TEST 3 - config again
cp ${config_new} ${config}
# wait for size to start
local state="FAIL"
while [ "${state}" != "OK" ]; do
state=`perf daemon ping --config ${config} --session size | awk '{ print $1 }'`
done
# wait for time to start
local state="FAIL"
while [ "${state}" != "OK" ]; do
state=`perf daemon ping --config ${config} --session time | awk '{ print $1 }'`
done
# stop daemon
daemon_exit ${config}
rm -rf ${base}
rm -f ${config}
rm -f ${config_new}
rm -f ${config_empty}
}
test_stop()
{
echo "test daemon stop"
local config
config=$(mktemp /tmp/perf.daemon.config.XXX)
local base
base=$(mktemp -d /tmp/perf.daemon.base.XXX)
# prepare config
cat <<EOF > ${config}
[daemon]
base=BASE
[session-size]
run = -e cpu-clock -m 1 sleep 10
[session-time]
run = -e task-clock -m 1 sleep 10
EOF
sed -i -e "s|BASE|${base}|" ${config}
# start daemon
daemon_start ${config} size
local pid_size
pid_size=`perf daemon --config ${config} -x: | head -2 | tail -1 |
awk 'BEGIN { FS = ":" } ; { print $1 }'`
local pid_time
pid_time=`perf daemon --config ${config} -x: | head -3 | tail -1 |
awk 'BEGIN { FS = ":" } ; { print $1 }'`
# check that sessions are running
if [ ! -d "/proc/${pid_size}" ]; then
echo "FAILED: session size not up"
fi
if [ ! -d "/proc/${pid_time}" ]; then
echo "FAILED: session time not up"
fi
# stop daemon
daemon_exit ${config}
# check that sessions are gone
if [ -d "/proc/${pid_size}" ]; then
echo "FAILED: session size still up"
fi
if [ -d "/proc/${pid_time}" ]; then
echo "FAILED: session time still up"
fi
rm -rf ${base}
rm -f ${config}
}
test_signal()
{
echo "test daemon signal"
local config
config=$(mktemp /tmp/perf.daemon.config.XXX)
local base
base=$(mktemp -d /tmp/perf.daemon.base.XXX)
# prepare config
cat <<EOF > ${config}
[daemon]
base=BASE
[session-test]
run = -e cpu-clock --switch-output -m 1 sleep 10
EOF
sed -i -e "s|BASE|${base}|" ${config}
# start daemon
daemon_start ${config} test
# send 2 signals then exit. Do this in a loop watching the number of
# files to avoid races. If the loop retries more than 600 times then
# give up.
local retries=0
local signals=0
local success=0
while [ ${retries} -lt 600 ] && [ ${success} -eq 0 ]; do
local files
files=`ls ${base}/session-test/*perf.data* 2> /dev/null | wc -l`
if [ ${signals} -eq 0 ]; then
perf daemon signal --config ${config} --session test
signals=1
elif [ ${signals} -eq 1 ] && [ $files -ge 1 ]; then
perf daemon signal --config ${config}
signals=2
elif [ ${signals} -eq 2 ] && [ $files -ge 2 ]; then
daemon_exit ${config}
signals=3
elif [ ${signals} -eq 3 ] && [ $files -ge 3 ]; then
success=1
fi
retries=$((${retries} +1))
done
if [ ${success} -eq 0 ]; then
error=1
echo "FAILED: perf data no generated"
fi
rm -rf ${base}
rm -f ${config}
}
test_ping()
{
echo "test daemon ping"
local config
config=$(mktemp /tmp/perf.daemon.config.XXX)
local base
base=$(mktemp -d /tmp/perf.daemon.base.XXX)
# prepare config
cat <<EOF > ${config}
[daemon]
base=BASE
[session-size]
run = -e cpu-clock -m 1 sleep 10
[session-time]
run = -e task-clock -m 1 sleep 10
EOF
sed -i -e "s|BASE|${base}|" ${config}
# start daemon
daemon_start ${config} size
size=`perf daemon ping --config ${config} --session size | awk '{ print $1 }'`
type=`perf daemon ping --config ${config} --session time | awk '{ print $1 }'`
if [ ${size} != "OK" ] || [ ${type} != "OK" ]; then
error=1
echo "FAILED: daemon ping failed"
fi
# stop daemon
daemon_exit ${config}
rm -rf ${base}
rm -f ${config}
}
test_lock()
{
echo "test daemon lock"
local config
config=$(mktemp /tmp/perf.daemon.config.XXX)
local base
base=$(mktemp -d /tmp/perf.daemon.base.XXX)
# prepare config
cat <<EOF > ${config}
[daemon]
base=BASE
[session-size]
run = -e cpu-clock -m 1 sleep 10
EOF
sed -i -e "s|BASE|${base}|" ${config}
# start daemon
daemon_start ${config} size
# start second daemon over the same config/base
failed=`perf daemon start --config ${config} 2>&1 | awk '{ print $1 }'`
# check that we failed properly
if [ ${failed} != "failed:" ]; then
error=1
echo "FAILED: daemon lock failed"
fi
# stop daemon
daemon_exit ${config}
rm -rf ${base}
rm -f ${config}
}
error=0
test_list
test_reconfig
test_stop
test_signal
test_ping
test_lock
exit ${error}
@@ -0,0 +1,91 @@
#!/bin/bash
# Test that perf report includes file offsets and event type names in diagnostic messages.
# SPDX-License-Identifier: GPL-2.0
#
# The file_offset diagnostic series adds "at offset 0x...: TYPE (N)"
# to all skip/stop/error messages. This test corrupts an event's size
# field in a perf.data file, then verifies the resulting warning
# includes the file offset and event type.
err=0
cleanup() {
[ -n "${perfdata}" ] && rm -f "${perfdata}" "${perfdata}.old"
rm -f "${corrupted}" "${stderrfile}"
trap - EXIT TERM INT
}
trap 'cleanup; exit 1' TERM INT
trap cleanup EXIT
perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) || exit 2
corrupted=$(mktemp /tmp/__perf_test.perf.data.XXXXX) || exit 2
stderrfile=$(mktemp /tmp/__perf_test.perf.data.XXXXX) || exit 2
if ! perf record -o "${perfdata}" -- perf test -w noploop 2>/dev/null; then
echo "Skip: perf record failed"
cleanup
exit 2
fi
# Find the file offset of the first MMAP2 event via perf report -D.
# Format: "timestamp 0xOFFSET [0xSIZE]: PERF_RECORD_MMAP2 ..."
mmap2_line=$(perf report -D -i "${perfdata}" 2>/dev/null | grep "PERF_RECORD_MMAP2" | head -1)
if [ -z "${mmap2_line}" ]; then
echo "Skip: no MMAP2 events found in perf.data"
cleanup
exit 2
fi
mmap2_offset=$(echo "${mmap2_line}" | awk '{print $2}')
mmap2_offset_dec=$((mmap2_offset))
# Copy the file and corrupt the MMAP2 event's size field.
# perf_event_header layout: type(u32) misc(u16) size(u16)
# Set size to 16 — below the MMAP2 minimum, which triggers
# the "event size too small" warning.
#
# perf.data uses native byte order, so write the u16 in the
# host's endianness to work on both LE and BE architectures.
cp "${perfdata}" "${corrupted}"
if printf '\x01\x02' | od -A n -t x2 | grep -q "0201"; then
# Little-endian
printf '\x10\x00'
else
# Big-endian
printf '\x00\x10'
fi | dd of="${corrupted}" bs=1 seek=$((mmap2_offset_dec + 6)) conv=notrunc 2>/dev/null
perf report -i "${corrupted}" --stdio > /dev/null 2> "${stderrfile}"
# Check that warnings include "at offset 0x..."
if grep -q "at offset 0x" "${stderrfile}"; then
echo "File offset in diagnostics [Success]"
else
echo "File offset in diagnostics [Failed: no 'at offset 0x...' found]"
echo " stderr was:"
head -5 "${stderrfile}"
err=1
fi
# Check that the event type name and numeric id appear: "MMAP2 (10)"
if grep -q "MMAP2 (10)" "${stderrfile}"; then
echo "Event type name in diagnostics [Success]"
else
echo "Event type name in diagnostics [Failed: no 'MMAP2 (10)' found]"
echo " stderr was:"
head -5 "${stderrfile}"
err=1
fi
# Check that the reported offset matches the actual corruption point
if grep -q "at offset ${mmap2_offset}:" "${stderrfile}"; then
echo "Correct offset reported [Success]"
else
echo "Correct offset reported [Failed: expected offset ${mmap2_offset}]"
echo " stderr was:"
head -5 "${stderrfile}"
err=1
fi
cleanup
exit ${err}
+93
View File
@@ -0,0 +1,93 @@
#!/bin/bash
# perf data type profiling tests
# SPDX-License-Identifier: GPL-2.0
set -e
# The logic below follows the same line as the annotate test, but looks for a
# data type profiling manifestation
# Values in testtypes and testprogs should match
testtypes=("# data-type: struct Buf" "# data-type: struct buf")
testprogs=("perf test -w code_with_type" "perf test -w datasym")
err=0
perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
perfout=$(mktemp /tmp/__perf_test.perf.out.XXXXX)
# Check for support of perf mem before trap handler
perf mem record -o /dev/null -- true 2>&1 | \
grep -q "failed: no PMU supports the memory events" && exit 2
cleanup() {
rm -rf "${perfdata}" "${perfout}"
rm -rf "${perfdata}".old
trap - EXIT TERM INT
}
trap_cleanup() {
echo "Unexpected signal in ${FUNCNAME[1]}"
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
test_basic_annotate() {
mode=$1
runtime=$2
echo "${mode} ${runtime} perf annotate test"
case "x${runtime}" in
"xRust")
if ! perf check feature -q rust
then
echo "Skip: code_with_type workload not built in 'perf test'"
return
fi
index=0 ;;
"xC")
index=1 ;;
esac
if [ "x${mode}" == "xBasic" ]
then
perf mem record -o "${perfdata}" ${testprogs[$index]} 2> /dev/null
else
perf mem record -o - ${testprogs[$index]} 2> /dev/null > "${perfdata}"
fi
if [ "x$?" != "x0" ]
then
echo "${mode} annotate [Failed: perf record]"
err=1
return
fi
# Generate the annotated output file
if [ "x${mode}" == "xBasic" ]
then
perf annotate --code-with-type -i "${perfdata}" --stdio --percent-limit 1 2> /dev/null > "${perfout}"
else
perf annotate --code-with-type -i - --stdio 2> /dev/null --percent-limit 1 < "${perfdata}" > "${perfout}"
fi
# check if it has the target data type
if ! grep -q "${testtypes[$index]}" "${perfout}"
then
echo "${mode} annotate [Failed: missing target data type]"
cat "${perfout}"
err=1
return
fi
echo "${mode} annotate test [Success]"
}
test_basic_annotate Basic Rust
test_basic_annotate Pipe Rust
test_basic_annotate Basic C
test_basic_annotate Pipe C
cleanup
exit $err
+86
View File
@@ -0,0 +1,86 @@
#!/bin/bash
# Test that perf report handles truncated perf.data gracefully (no crash, no segfault — clean error exit).
# SPDX-License-Identifier: GPL-2.0
#
# Exercises the bounds checking and minimum-size validation added
# by the perf-data-validation hardening series.
err=0
cleanup() {
[ -n "${perfdata}" ] && rm -f "${perfdata}" "${perfdata}.old"
rm -f "${truncated}" "${stderrfile}"
trap - EXIT TERM INT
}
trap 'cleanup; exit 1' TERM INT
trap cleanup EXIT
perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) || exit 2
truncated=$(mktemp /tmp/__perf_test.perf.data.XXXXX) || exit 2
stderrfile=$(mktemp /tmp/__perf_test.perf.data.XXXXX) || exit 2
# Record a simple workload
if ! perf record -o "${perfdata}" -- perf test -w noploop 2>/dev/null; then
echo "Skip: perf record failed"
cleanup
exit 2
fi
file_size=$(wc -c < "${perfdata}")
if [ "${file_size}" -lt 512 ]; then
echo "Skip: perf.data too small (${file_size} bytes)"
cleanup
exit 2
fi
# Test truncation at various offsets that exercise different
# parsing stages:
# 8 — file header magic only, no attrs or data
# 64 — partial file header (attr section incomplete)
# 256 — into the first events (partial event headers)
# 75% — mid-stream truncation (partial event data)
for cut_at in 8 64 256 $((file_size * 3 / 4)); do
if [ "${cut_at}" -ge "${file_size}" ]; then
continue
fi
dd if="${perfdata}" of="${truncated}" bs="${cut_at}" count=1 2>/dev/null
# perf report should exit with an error, not crash.
# Capture stderr to detect sanitizer violations.
perf report -i "${truncated}" --stdio > /dev/null 2> "${stderrfile}"
exit_code=$?
# A truncated file should never parse successfully
if [ ${exit_code} -eq 0 ]; then
echo "FAIL: perf report exited 0 (success) on ${cut_at}-byte truncated file — expected an error"
err=1
continue
fi
# Detect sanitizer violations — ASAN/MSAN/TSAN/UBSAN exit
# with code 1 by default, which would otherwise look like a
# clean error exit. Check stderr for their markers.
if grep -qE "^(==[0-9]+==ERROR:|SUMMARY: [A-Za-z]*Sanitizer)" "${stderrfile}" 2>/dev/null; then
sanitizer=$(grep -oE "(Address|Memory|Thread|UndefinedBehavior)Sanitizer" "${stderrfile}" | head -1)
echo "FAIL: perf report triggered ${sanitizer:-sanitizer} on ${cut_at}-byte truncated file"
err=1
continue
fi
# Detect crash signals portably — signal numbers differ
# across architectures (e.g. SIGBUS is 7 on x86/ARM but
# 10 on MIPS/SPARC). Use kill -l to map the number to a
# name on the running system.
if [ ${exit_code} -gt 128 ] && [ ${exit_code} -lt 200 ]; then
sig_name=$(kill -l $((exit_code - 128)) 2>/dev/null)
case ${sig_name} in
KILL|ILL|ABRT|BUS|FPE|SEGV|TRAP|SYS)
echo "FAIL: perf report crashed (SIG${sig_name}) on ${cut_at}-byte truncated file"
err=1
;;
esac
fi
done
cleanup
exit ${err}
+108
View File
@@ -0,0 +1,108 @@
#!/bin/bash
# perf diff tests
# SPDX-License-Identifier: GPL-2.0
set -e
err=0
perfdata1=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
perfdata2=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
perfdata3=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
testprog="perf test -w thloop"
shelldir=$(dirname "$0")
# shellcheck source=lib/perf_has_symbol.sh
. "${shelldir}"/lib/perf_has_symbol.sh
testsym="test_loop"
skip_test_missing_symbol ${testsym}
cleanup() {
rm -rf "${perfdata1}"
rm -rf "${perfdata1}".old
rm -rf "${perfdata2}"
rm -rf "${perfdata2}".old
rm -rf "${perfdata3}"
rm -rf "${perfdata3}".old
trap - EXIT TERM INT
}
trap_cleanup() {
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
make_data() {
file="$1"
if ! perf record -o "${file}" ${testprog} 2> /dev/null
then
echo "Workload record [Failed record]" >&2
echo 1
return
fi
if ! perf report -i "${file}" -q | grep -q "${testsym}"
then
echo "Workload record [Failed missing output]" >&2
echo 1
return
fi
echo 0
}
test_two_files() {
echo "Basic two file diff test"
err=$(make_data "${perfdata1}")
if [ "$err" != 0 ]
then
return
fi
err=$(make_data "${perfdata2}")
if [ "$err" != 0 ]
then
return
fi
if ! perf diff "${perfdata1}" "${perfdata2}" | grep -q "${testsym}"
then
echo "Basic two file diff test [Failed diff]"
err=1
return
fi
echo "Basic two file diff test [Success]"
}
test_three_files() {
echo "Basic three file diff test"
err=$(make_data "${perfdata1}")
if [ "$err" != 0 ]
then
return
fi
err=$(make_data "${perfdata2}")
if [ "$err" != 0 ]
then
return
fi
err=$(make_data "${perfdata3}")
if [ $err != 0 ]
then
return
fi
if ! perf diff "${perfdata1}" "${perfdata2}" "${perfdata3}" | grep -q "${testsym}"
then
echo "Basic three file diff test [Failed diff]"
err=1
return
fi
echo "Basic three file diff test [Success]"
}
test_two_files
test_three_files
cleanup
exit $err
+78
View File
@@ -0,0 +1,78 @@
#!/bin/bash
# DRM PMU
# SPDX-License-Identifier: GPL-2.0
set -e
output=$(mktemp /tmp/perf.drm_pmu.XXXXXX.txt)
cleanup() {
rm -f "${output}"
trap - EXIT TERM INT
}
trap_cleanup() {
echo "Unexpected signal in ${FUNCNAME[1]}"
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
# Array to store file descriptors and device names
declare -A device_fds
# Open all devices and store file descriptors. Opening the device will create a
# /proc/$$/fdinfo file containing the DRM statistics.
fd_count=3 # Start with file descriptor 3
for device in /dev/dri/*
do
if [[ ! -c "$device" ]]
then
continue
fi
major=$(stat -c "%Hr" "$device")
if [[ "$major" != 226 ]]
then
continue
fi
echo "Opening $device"
eval "exec $fd_count<\"$device\""
echo "fdinfo for: $device (FD: $fd_count)"
cat "/proc/$$/fdinfo/$fd_count"
echo
device_fds["$device"]="$fd_count"
fd_count=$((fd_count + 1))
done
if [[ ${#device_fds[@]} -eq 0 ]]
then
echo "No DRM devices found [Skip]"
cleanup
exit 2
fi
# For each DRM event
err=0
for p in $(perf list --raw-dump drm-)
do
echo -n "Testing perf stat of $p. "
perf stat -e "$p" --pid=$$ true > "$output" 2>&1
if ! grep -q "$p" "$output"
then
echo "Missing DRM event in: [Failed]"
cat "$output"
err=1
else
echo "[OK]"
fi
done
# Close all file descriptors
for fd in "${device_fds[@]}"; do
eval "exec $fd<&-"
done
# Finished
cleanup
exit $err
+80
View File
@@ -0,0 +1,80 @@
#!/bin/bash
# perf evlist tests
# SPDX-License-Identifier: GPL-2.0
set -e
err=0
perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
cleanup() {
rm -f "${perfdata}"
trap - EXIT TERM INT
}
trap_cleanup() {
echo "Unexpected signal in ${FUNCNAME[1]}"
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
test_evlist_simple() {
echo "Simple evlist test"
if ! perf record -e cpu-clock -o "${perfdata}" true 2> /dev/null
then
echo "Simple evlist [Failed record]"
err=1
return
fi
if ! perf evlist -i "${perfdata}" | grep -q "cpu-clock"
then
echo "Simple evlist [Failed to list event]"
err=1
return
fi
echo "Simple evlist test [Success]"
}
test_evlist_group() {
echo "Group evlist test"
if ! perf record -e "{cpu-clock,task-clock}" -o "${perfdata}" \
-- perf test -w noploop 2> /dev/null
then
echo "Group evlist [Skipped event group recording failed]"
return
fi
if ! perf evlist -i "${perfdata}" -g | grep -q "{.*cpu-clock.*,.*task-clock.*}"
then
echo "Group evlist [Failed to list event group]"
err=1
return
fi
echo "Group evlist test [Success]"
}
test_evlist_verbose() {
echo "Event configuration evlist test"
if ! perf record -e cycles -o "${perfdata}" true 2> /dev/null
then
echo "Event configuration evlist [Failed record]"
err=1
return
fi
if ! perf evlist -i "${perfdata}" -v | grep -q "config:"
then
echo "Event configuration evlist [Failed to list verbose info]"
err=1
return
fi
echo "Event configuration evlist test [Success]"
}
test_evlist_simple
test_evlist_group
test_evlist_verbose
cleanup
exit $err
+87
View File
@@ -0,0 +1,87 @@
#!/bin/bash
# perf ftrace tests
# SPDX-License-Identifier: GPL-2.0
set -e
# perf ftrace commands only works for root
if [ "$(id -u)" != 0 ]; then
echo "perf ftrace test [Skipped: no permission]"
exit 2
fi
output=$(mktemp /tmp/__perf_test.ftrace.XXXXXX)
cleanup() {
rm -f "${output}"
trap - EXIT TERM INT
}
trap_cleanup() {
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
# this will be set in test_ftrace_trace()
target_function=
test_ftrace_list() {
echo "perf ftrace list test"
perf ftrace -F > "${output}"
# this will be used in test_ftrace_trace()
sleep_functions=$(grep 'sys_.*sleep$' "${output}")
echo "syscalls for sleep:"
echo "${sleep_functions}"
echo "perf ftrace list test [Success]"
}
test_ftrace_trace() {
echo "perf ftrace trace test"
perf ftrace trace --graph-opts depth=5 sleep 0.1 > "${output}"
# it should have some function name contains 'sleep'
grep "^#" "${output}"
grep -F 'sleep()' "${output}"
# find actual syscall function name
for FN in ${sleep_functions}; do
if grep -q "${FN}" "${output}"; then
target_function="${FN}"
echo "perf ftrace trace test [Success]"
return
fi
done
echo "perf ftrace trace test [Failure: sleep syscall not found]"
exit 1
}
test_ftrace_latency() {
echo "perf ftrace latency test"
echo "target function: ${target_function}"
perf ftrace latency -T "${target_function}" sleep 0.1 > "${output}"
grep "^#" "${output}"
grep "###" "${output}"
echo "perf ftrace latency test [Success]"
}
test_ftrace_profile() {
echo "perf ftrace profile test"
perf ftrace profile --graph-opts depth=5 sleep 0.1 > "${output}"
grep ^# "${output}"
time_re="[[:space:]]+1[[:digit:]]{5}\.[[:digit:]]{3}"
# 100283.000 100283.000 100283.000 1 __x64_sys_clock_nanosleep
# Check for one *sys_*nanosleep line with a Count of just 1 that takes a bit more than 0.1 seconds
# Strip the _x64_ part to work with other architectures, strip the clock part to support
# C libraries that use the nanosleep syscall instead of clock_nanosleep
grep -E "^${time_re}${time_re}${time_re}[[:space:]]+1[[:space:]]+.*sys_.*nanosleep" "${output}"
echo "perf ftrace profile test [Success]"
}
test_ftrace_list
test_ftrace_trace
test_ftrace_latency
test_ftrace_profile
cleanup
exit 0
+74
View File
@@ -0,0 +1,74 @@
#!/bin/bash
# perf header tests
# SPDX-License-Identifier: GPL-2.0
set -e
err=0
perfdata=$(mktemp /tmp/__perf_test_header.perf.data.XXXXX)
script_output=$(mktemp /tmp/__perf_test_header.perf.data.XXXXX.script)
cleanup() {
rm -f "${perfdata}"
rm -f "${perfdata}".old
rm -f "${script_output}"
trap - EXIT TERM INT
}
trap_cleanup() {
echo "Unexpected signal in ${FUNCNAME[1]}"
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
check_header_output() {
declare -a fields=(
"captured"
"hostname"
"os release"
"arch"
"cpuid"
"nrcpus"
"event"
"cmdline"
"perf version"
"sibling (cores|dies|threads)"
"sibling threads"
"total memory"
)
for i in "${fields[@]}"
do
if ! grep -q -E "$i" "${script_output}"
then
echo "Failed to find expected $i in output"
err=1
fi
done
}
test_file() {
echo "Test perf header file"
perf record -o "${perfdata}" -- perf test -w noploop
perf report --header-only -I -i "${perfdata}" > "${script_output}"
check_header_output
echo "Test perf header file [Done]"
}
test_pipe() {
echo "Test perf header pipe"
perf record -o - -- perf test -w noploop | perf report --header-only -I -i - > "${script_output}"
check_header_output
echo "Test perf header pipe [Done]"
}
test_file
test_pipe
cleanup
exit $err
+45
View File
@@ -0,0 +1,45 @@
#!/bin/bash
# perf inject to convert DWARF callchains to regular ones
# SPDX-License-Identifier: GPL-2.0
if ! perf check feature -q dwarf; then
echo "SKIP: DWARF support is not available"
exit 2
fi
TESTDATA=$(mktemp /tmp/perf-test.XXXXXX)
err=0
cleanup()
{
trap - EXIT TERM INT
rm -f ${TESTDATA}*
}
trap_cleanup()
{
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
echo "recording data with DWARF callchain"
perf record -F 999 --call-graph dwarf -o "${TESTDATA}" -- perf test -w noploop
echo "convert DWARF callchain using perf inject"
perf inject -i "${TESTDATA}" --convert-callchain -o "${TESTDATA}.new"
perf report -i "${TESTDATA}" --no-children -q --percent-limit=1 > ${TESTDATA}.out
perf report -i "${TESTDATA}.new" --no-children -q --percent-limit=1 > ${TESTDATA}.new.out
echo "compare the both result excluding inlined functions"
if diff -u "${TESTDATA}.out" "${TESTDATA}.new.out" | grep "^- " | grep -qv "(inlined)"; then
echo "Found some differences"
diff -u "${TESTDATA}.out" "${TESTDATA}.new.out"
err=1
fi
cleanup
exit $err
+533
View File
@@ -0,0 +1,533 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# perf inject --aslr test
set -e
set -o pipefail
shelldir=$(dirname "$0")
# shellcheck source=lib/perf_has_symbol.sh
. "${shelldir}"/lib/perf_has_symbol.sh
sym="noploop"
skip_test_missing_symbol ${sym}
# Create global temp directory
temp_dir=$(mktemp -d /tmp/perf-test-aslr.XXXXXXXXXX)
prog="perf test -w noploop"
[ "$(uname -m)" = "s390x" ] && prog="$prog 3"
err=0
kprog="dd if=/dev/urandom of=/dev/null bs=1M count=50"
cleanup() {
local exit_code=${1:-$?}
trap - EXIT TERM INT
if [ "${exit_code}" -ne 0 ] || [ "${err}" -ne 0 ]; then
echo "Test failed! Preserving temp directory: ${temp_dir}"
return
fi
# Check if temp_dir is set and looks sane before removing
if [[ "${temp_dir}" =~ ^/tmp/perf-test-aslr\. ]]; then
rm -rf "${temp_dir}"
fi
}
trap_cleanup() {
local exit_code=$?
echo "Unexpected signal in ${FUNCNAME[1]}"
cleanup ${exit_code}
exit ${exit_code}
}
trap trap_cleanup EXIT TERM INT
get_noploop_addr() {
local file=$1
perf script -i "$file" | awk '
BEGIN { found=0 }
{
for (i=1; i<=NF; i++) {
if ($i ~ /noploop\+/) {
if (!found) {
print $(i-1)
found=1
}
}
}
}'
}
test_basic_aslr() {
echo "Test basic ASLR remapping"
local data
data=$(mktemp "${temp_dir}/perf.data.basic.XXXXXX")
local data2
data2=$(mktemp "${temp_dir}/perf.data2.basic.XXXXXX")
perf record -e task-clock:u -o "${data}" ${prog}
perf inject -v --aslr -i "${data}" -o "${data2}"
orig_addr=$(get_noploop_addr "${data}")
new_addr=$(get_noploop_addr "${data2}")
echo "Basic ASLR: orig_addr=$orig_addr, new_addr=$new_addr"
if [ -z "$orig_addr" ]; then
echo "Basic ASLR test [Failed - no noploop samples in original file]"
err=1
elif [ -z "$new_addr" ]; then
echo "Basic ASLR test [Failed - could not find remapped address]"
err=1
elif [ "$orig_addr" = "$new_addr" ]; then
echo "Basic ASLR test [Failed - addresses are not remapped]"
err=1
else
echo "Basic ASLR test [Success]"
fi
}
test_pipe_aslr() {
echo "Test pipe mode ASLR remapping"
local data
data=$(mktemp "${temp_dir}/perf.data.pipe.XXXXXX")
local data2
data2=$(mktemp "${temp_dir}/perf.data2.pipe.XXXXXX")
# Use tee to save the original pipe data for comparison
perf record -e task-clock:u -o - ${prog} | tee "${data}" | perf inject --aslr -o "${data2}"
orig_addr=$(get_noploop_addr "${data}")
new_addr=$(get_noploop_addr "${data2}")
echo "Pipe ASLR: orig_addr=$orig_addr, new_addr=$new_addr"
if [ -z "$orig_addr" ]; then
echo "Pipe ASLR test [Failed - no noploop samples in original file]"
err=1
elif [ -z "$new_addr" ]; then
echo "Pipe ASLR test [Failed - could not find remapped address]"
err=1
elif [ "$orig_addr" = "$new_addr" ]; then
echo "Pipe ASLR test [Failed - addresses are not remapped]"
err=1
else
echo "Pipe ASLR test [Success]"
fi
}
test_callchain_aslr() {
echo "Test Callchain ASLR remapping"
local data
data=$(mktemp "${temp_dir}/perf.data.callchain.XXXXXX")
local data2
data2=$(mktemp "${temp_dir}/perf.data2.callchain.XXXXXX")
perf record -g -e task-clock:u -o "${data}" ${prog}
perf inject --aslr -i "${data}" -o "${data2}"
orig_addr=$(get_noploop_addr "${data}")
new_addr=$(get_noploop_addr "${data2}")
echo "Callchain ASLR: orig_addr=$orig_addr, new_addr=$new_addr"
if [ -z "$orig_addr" ]; then
echo "Callchain ASLR test [Failed - no noploop samples in original file]"
err=1
elif [ -z "$new_addr" ]; then
echo "Callchain ASLR test [Failed - could not find remapped address]"
err=1
elif [ "$orig_addr" = "$new_addr" ]; then
echo "Callchain ASLR test [Failed - addresses are not remapped]"
err=1
else
# Extract callchain addresses (indented lines starting with hex addresses)
orig_callchain=$(perf script -i "${data}" | awk '/^[[:space:]]+[0-9a-f]+/ {print $1}')
new_callchain=$(perf script -i "${data2}" | awk '/^[[:space:]]+[0-9a-f]+/ {print $1}')
if [ -z "$orig_callchain" ]; then
echo "Callchain ASLR test [Failed - no callchain samples in original file]"
err=1
elif [ -z "$new_callchain" ]; then
echo "Callchain ASLR test [Failed - callchain data was dropped]"
err=1
elif [ "$orig_callchain" = "$new_callchain" ]; then
echo "Callchain ASLR test [Failed - callchain addresses were not remapped]"
err=1
else
echo "Callchain ASLR test [Success]"
fi
fi
}
test_report_aslr() {
echo "Test perf report consistency"
local data
data=$(mktemp "${temp_dir}/perf.data.report.XXXXXX")
local data2
data2=$(mktemp "${temp_dir}/perf.data2.report.XXXXXX")
local data_clean
data_clean=$(mktemp "${temp_dir}/perf.data.clean.XXXXXX")
perf record -e task-clock:u -o "${data}" ${prog}
# Use -b to inject build-ids and force ordered events processing in both
perf inject -b -i "${data}" -o "${data_clean}"
perf inject -v -b --aslr -i "${data}" -o "${data2}"
local report1="${temp_dir}/report1_basic"
local report2="${temp_dir}/report2_basic"
local report1_clean="${temp_dir}/report1_basic.clean"
local report2_clean="${temp_dir}/report2_basic.clean"
local diff_file="${temp_dir}/diff_basic"
perf report -i "${data_clean}" --stdio > "${report1}"
perf report -i "${data2}" --stdio > "${report2}"
# Strip headers and compare lines with percentages
grep '%' "${report1}" | grep -v '^#' | \
grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report1_clean}" || true
grep '%' "${report2}" | grep -v '^#' | \
grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report2_clean}" || true
diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true
if [ ! -s "${report1_clean}" ]; then
echo "Report ASLR test [Failed - no samples captured]"
err=1
elif [ -s "${diff_file}" ]; then
echo "Report ASLR test [Failed - reports differ]"
echo "Showing first 20 lines of diff:"
head -n 20 "${diff_file}"
err=1
else
echo "Report ASLR test [Success]"
fi
}
test_pipe_report_aslr() {
echo "Test pipe mode perf report consistency"
local data
data=$(mktemp "${temp_dir}/perf.data.pipe_report.XXXXXX")
local data2
data2=$(mktemp "${temp_dir}/perf.data2.pipe_report.XXXXXX")
local data_clean
data_clean=$(mktemp "${temp_dir}/perf.data.clean.XXXXXX")
# Use tee to save the original pipe data, then process it with inject -b
perf record -e task-clock:u -o - ${prog} | \
tee "${data}" | \
perf inject -b --aslr -o "${data2}"
perf inject -b -i "${data}" -o "${data_clean}"
local report1="${temp_dir}/report1_pipe"
local report2="${temp_dir}/report2_pipe"
local report1_clean="${temp_dir}/report1_pipe.clean"
local report2_clean="${temp_dir}/report2_pipe.clean"
local diff_file="${temp_dir}/diff_pipe"
perf report -i "${data_clean}" --stdio > "${report1}"
perf report -i "${data2}" --stdio > "${report2}"
# Strip headers and compare lines with percentages
grep '%' "${report1}" | grep -v '^#' | \
grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report1_clean}" || true
grep '%' "${report2}" | grep -v '^#' | \
grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report2_clean}" || true
diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true
if [ ! -s "${report1_clean}" ]; then
echo "Pipe Report ASLR test [Failed - no samples captured]"
err=1
elif [ -s "${diff_file}" ]; then
echo "Pipe Report ASLR test [Failed - reports differ]"
echo "Showing first 20 lines of diff:"
head -n 20 "${diff_file}"
err=1
else
echo "Pipe Report ASLR test [Success]"
fi
}
test_pipe_out_report_aslr() {
echo "Test pipe output mode perf report consistency"
local data
data=$(mktemp "${temp_dir}/perf.data.pipe_out_report.XXXXXX")
local data_clean
data_clean=$(mktemp "${temp_dir}/perf.data.clean.XXXXXX")
perf record -e task-clock:u -o "${data}" ${prog}
perf inject -b -i "${data}" -o "${data_clean}"
local report1="${temp_dir}/report1_pipe_out"
local report2="${temp_dir}/report2_pipe_out"
local report1_clean="${temp_dir}/report1_pipe_out.clean"
local report2_clean="${temp_dir}/report2_pipe_out.clean"
local diff_file="${temp_dir}/diff_pipe_out"
perf report -i "${data_clean}" --stdio > "${report1}"
perf inject -b --aslr -i "${data}" -o - | perf report -i - --stdio > "${report2}"
# Strip headers and compare lines with percentages
grep '%' "${report1}" | grep -v '^#' | \
grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report1_clean}" || true
grep '%' "${report2}" | grep -v '^#' | \
grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report2_clean}" || true
diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true
if [ ! -s "${report1_clean}" ]; then
echo "Pipe Output Report ASLR test [Failed - no samples captured]"
err=1
elif [ -s "${diff_file}" ]; then
echo "Pipe Output Report ASLR test [Failed - reports differ]"
echo "Showing first 20 lines of diff:"
head -n 20 "${diff_file}"
err=1
else
echo "Pipe Output Report ASLR test [Success]"
fi
}
test_dropped_samples() {
echo "Test dropped samples (phys-data)"
local data
data=$(mktemp "${temp_dir}/perf.data.dropped.XXXXXX")
local data2
data2=$(mktemp "${temp_dir}/perf.data2.dropped.XXXXXX")
# Check if --phys-data is supported by recording a short run
if ! perf record -e task-clock:u --phys-data -o "${data}" -- sleep 0.1 > /dev/null 2>&1; then
echo "Skipping dropped samples test as --phys-data is not supported"
return
fi
perf record -e task-clock:u --phys-data -o "${data}" ${prog}
perf inject --aslr -i "${data}" -o "${data2}"
# Verify that the original file actually contained samples!
orig_samples=$(perf script -i "${data}" | wc -l)
if [ "$orig_samples" -eq 0 ]; then
echo "Dropped samples test [Failed - no samples in original file]"
err=1
else
# Verify that samples are dropped.
samples_count=$(perf script -i "${data2}" | wc -l)
if [ "$samples_count" -gt 0 ]; then
echo "Dropped samples test [Failed - samples were not dropped]"
err=1
else
echo "Dropped samples test [Success]"
fi
fi
}
test_kernel_aslr() {
echo "Test kernel ASLR remapping"
local kdata
kdata=$(mktemp "${temp_dir}/perf.data.kernel.XXXXXX")
local kdata2
kdata2=$(mktemp "${temp_dir}/perf.data2.kernel.XXXXXX")
local log_file
log_file=$(mktemp "${temp_dir}/kernel_record.log.XXXXXX")
# Try to record kernel samples
if ! perf record -e task-clock:k -o "${kdata}" ${kprog} > "${log_file}" 2>&1; then
echo "Skipping kernel ASLR test as recording failed (maybe no permissions)"
return
fi
# Check for warning about kernel map restriction
if grep -q "Couldn't record kernel reference relocation symbol" "${log_file}"; then
echo "Skipping kernel ASLR test as kernel map could not be recorded (permissions restricted)"
return
fi
perf inject -v --aslr -i "${kdata}" -o "${kdata2}"
# Check if kernel addresses are remapped.
# Find the field that ends with :k: (the event name) and take the next field!
orig_addr=$(perf script -i "${kdata}" | awk '
BEGIN { found=0 }
{
for (i=1; i<NF; i++) {
if ($i ~ /:[k]+:?$/) {
if (!found) {
print $(i+1)
found=1
}
}
}
}')
new_addr=$(perf script -i "${kdata2}" | awk '
BEGIN { found=0 }
{
for (i=1; i<NF; i++) {
if ($i ~ /:[k]+:?$/) {
if (!found) {
print $(i+1)
found=1
}
}
}
}')
echo "Kernel ASLR: orig_addr=$orig_addr, new_addr=$new_addr"
if [ -z "$orig_addr" ]; then
echo "Kernel ASLR test [Failed - no kernel samples in original file]"
err=1
elif [ -z "$new_addr" ]; then
echo "Kernel ASLR test [Failed - could not find remapped address]"
err=1
elif [ "$orig_addr" = "$new_addr" ]; then
echo "Kernel ASLR test [Failed - addresses are not remapped]"
err=1
else
echo "Kernel ASLR test [Success]"
fi
}
test_kernel_report_aslr() {
echo "Test kernel perf report consistency"
local kdata
kdata=$(mktemp "${temp_dir}/perf.data.kernel_report.XXXXXX")
local kdata2
kdata2=$(mktemp "${temp_dir}/perf.data2.kernel_report.XXXXXX")
local data_clean
data_clean=$(mktemp "${temp_dir}/perf.data.clean.XXXXXX")
local log_file
log_file=$(mktemp "${temp_dir}/kernel_report_record.log.XXXXXX")
# Try to record kernel samples
if ! perf record -e task-clock:k -o "${kdata}" ${kprog} > "${log_file}" 2>&1; then
echo "Skipping kernel report test as recording failed (maybe no permissions)"
return
fi
# Check for warning about kernel map restriction
if grep -q "Couldn't record kernel reference relocation symbol" "${log_file}"; then
echo "Skipping kernel report test as kernel map could not be recorded (permissions restricted)"
return
fi
# Use -b to inject build-ids and force ordered events processing in both
perf inject -b -i "${kdata}" -o "${data_clean}"
perf inject -v -b --aslr -i "${kdata}" -o "${kdata2}"
local report1="${temp_dir}/report_kernel1"
local report2="${temp_dir}/report_kernel2"
local report1_clean="${temp_dir}/report_kernel1.clean"
local report2_clean="${temp_dir}/report_kernel2.clean"
perf report -i "${data_clean}" --stdio > "${report1}"
perf report -i "${kdata2}" --stdio > "${report2}"
# Strip headers and compare lines with percentages
grep '%' "${report1}" | grep -v '^#' > "${report1_clean}" || true
grep '%' "${report2}" | grep -v '^#' > "${report2_clean}" || true
# Normalize kernel DSOs and addresses in clean reports
# This allows kernel modules to be either a module or kernel.kallsyms
local report1_norm="${temp_dir}/report_kernel1.norm"
local report2_norm="${temp_dir}/report_kernel2.norm"
local diff_file="${temp_dir}/diff_kernel"
grep -v -E '0x[0-9a-f]{8,}|0000000000000000' "${report1_clean}" | \
awk '{gsub(/\[[a-zA-Z0-9_.-]{2,}\](\.[a-zA-Z0-9_]+)?/, "[kernel]", $0); print}' | \
sort > "${report1_norm}" || true
grep -v -E '0x[0-9a-f]{8,}|0000000000000000' "${report2_clean}" | \
awk '{gsub(/\[[a-zA-Z0-9_.-]{2,}\](\.[a-zA-Z0-9_]+)?/, "[kernel]", $0); print}' | \
sort > "${report2_norm}" || true
diff -u -w "${report1_norm}" "${report2_norm}" > "${diff_file}" || true
if [ ! -s "${report1_norm}" ]; then
echo "Kernel Report ASLR test [Failed - no samples captured]"
err=1
elif [ -s "${diff_file}" ]; then
echo "Kernel Report ASLR test [Failed - reports differ]"
echo "Showing first 20 lines of diff:"
head -n 20 "${diff_file}"
err=1
else
echo "Kernel Report ASLR test [Success]"
fi
}
test_regs_stripping() {
echo "Test user register stripping"
local rdata="${temp_dir}/perf.data.regs"
local rdata2="${temp_dir}/perf.data.regs.injected"
local rdata_clean="${temp_dir}/perf.data.regs.clean"
if ! perf record -e cycles:u --user-regs -o "${rdata}" ${prog} > /dev/null 2>&1; then
echo "Skipping user registers test as recording failed (unsupported flag/platform)"
return
fi
perf inject -b -i "${rdata}" -o "${rdata_clean}"
perf inject -v -b --aslr -i "${rdata}" -o "${rdata2}"
local report1="${temp_dir}/report_regs1"
local report2="${temp_dir}/report_regs2"
local report1_clean="${temp_dir}/report_regs1.clean"
local report2_clean="${temp_dir}/report_regs2.clean"
local diff_file="${temp_dir}/diff_regs"
perf report -i "${rdata_clean}" --stdio > "${report1}" 2>/dev/null || true
perf report -i "${rdata2}" --stdio > "${report2}" 2>/dev/null || true
grep '%' "${report1}" | grep -v '^#' | \
grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | \
sort > "${report1_clean}" || true
grep '%' "${report2}" | grep -v '^#' | \
grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | \
sort > "${report2_clean}" || true
diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true
if [ ! -s "${report1_clean}" ]; then
echo "User registers stripping test [Failed - profile trace starved/empty]"
err=1
return
elif [ -s "${diff_file}" ]; then
echo "User registers stripping test [Failed - report parsing differs]"
echo "Showing first 20 lines of diff:"
head -n 20 "${diff_file}"
err=1
return
fi
local script_dump="${temp_dir}/script_regs_dump"
perf script -D -i "${rdata2}" > "${script_dump}" 2>/dev/null || true
if grep -q "user regs:" "${script_dump}"; then
echo "User registers stripping test [Failed - register dumps still present]"
err=1
else
echo "User registers stripping test [Success]"
fi
}
test_basic_aslr
test_pipe_aslr
test_callchain_aslr
test_report_aslr
test_pipe_report_aslr
test_pipe_out_report_aslr
test_dropped_samples
case "$(uname -m)" in
aarch64*|arm*)
echo "Skipping kernel ASLR tests on ARM"
;;
*)
test_kernel_aslr
test_kernel_report_aslr
;;
esac
test_regs_stripping
cleanup ${err}
exit $err
+81
View File
@@ -0,0 +1,81 @@
#!/bin/bash
# python profiling with jitdump
# SPDX-License-Identifier: GPL-2.0
SHELLDIR=$(dirname $0)
# shellcheck source=lib/setup_python.sh
. "${SHELLDIR}"/lib/setup_python.sh
OUTPUT=$(${PYTHON} -Xperf_jit -c 'import os, sys; print(os.getpid(), sys.is_stack_trampoline_active())' 2> /dev/null)
PID=${OUTPUT% *}
HAS_PERF_JIT=${OUTPUT#* }
rm -f /tmp/jit-${PID}.dump 2> /dev/null
if [ "${HAS_PERF_JIT}" != "True" ]; then
echo "SKIP: python JIT dump is not available"
exit 2
fi
PERF_DATA=$(mktemp /tmp/__perf_test.perf.data.XXXXXX)
cleanup() {
echo "Cleaning up files..."
rm -f ${PERF_DATA} ${PERF_DATA}.jit /tmp/jit-${PID}.dump /tmp/jitted-${PID}-*.so 2> /dev/null
trap - EXIT TERM INT
}
trap_cleanup() {
echo "Unexpected termination"
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
echo "Run python with -Xperf_jit"
cat <<EOF | perf record -k 1 -g --call-graph dwarf -o "${PERF_DATA}" \
-- ${PYTHON} -Xperf_jit
def foo(n):
result = 0
for _ in range(n):
result += 1
return result
def bar(n):
foo(n)
def baz(n):
bar(n)
if __name__ == "__main__":
baz(1000000)
EOF
# extract PID of the target process from the data
_PID=$(perf report -i "${PERF_DATA}" -F pid -q -g none | cut -d: -f1 -s)
PID=$(echo -n $_PID) # remove newlines
echo "Generate JIT-ed DSOs using perf inject"
DEBUGINFOD_URLS='' perf inject -i "${PERF_DATA}" -j -o "${PERF_DATA}.jit"
echo "Add JIT-ed DSOs to the build-ID cache"
for F in /tmp/jitted-${PID}-*.so; do
perf buildid-cache -a "${F}"
done
echo "Check the symbol containing the function/module name"
NUM=$(perf report -i "${PERF_DATA}.jit" -s sym | grep -cE 'py::(foo|bar|baz):<stdin>')
echo "Found ${NUM} matching lines"
echo "Remove JIT-ed DSOs from the build-ID cache"
for F in /tmp/jitted-${PID}-*.so; do
perf buildid-cache -r "${F}"
done
cleanup
if [ "${NUM}" -eq 0 ]; then
exit 1
fi
+56
View File
@@ -0,0 +1,56 @@
#!/bin/bash
# perf kallsyms tests
# SPDX-License-Identifier: GPL-2.0
err=0
test_kallsyms() {
echo "Basic perf kallsyms test"
# Check if /proc/kallsyms is readable
if [ ! -r /proc/kallsyms ]; then
echo "Basic perf kallsyms test [Skipped: /proc/kallsyms not readable]"
err=2
return
fi
# Use a symbol that is definitely a function and present in all kernels, e.g. schedule
symbol="schedule"
# Run perf kallsyms
# It prints "address symbol_name"
output=$(perf kallsyms $symbol 2>&1)
ret=$?
if [ $ret -ne 0 ] || [ -z "$output" ]; then
# If empty or failed, it might be due to permissions (kptr_restrict)
# Check if we can grep the symbol from /proc/kallsyms directly
if grep -q "$symbol" /proc/kallsyms 2>/dev/null; then
# If it's in /proc/kallsyms but perf kallsyms returned empty/error,
# it likely means perf couldn't parse it or access it correctly (e.g. kptr_restrict=2).
echo "Basic perf kallsyms test [Skipped: $symbol found in /proc/kallsyms but perf kallsyms failed (output: '$output')]"
err=2
return
else
echo "Basic perf kallsyms test [Skipped: $symbol not found in /proc/kallsyms]"
err=2
return
fi
fi
if echo "$output" | grep -q "not found"; then
echo "Basic perf kallsyms test [Failed: output '$output' does not contain $symbol]"
err=1
return
fi
if perf kallsyms ErlingHaaland | grep -vq "not found"; then
echo "Basic perf kallsyms test [Failed: ErlingHaaland found in the output]"
err=1
return
fi
echo "Basic perf kallsyms test [Success]"
}
test_kallsyms
exit $err
+182
View File
@@ -0,0 +1,182 @@
#!/bin/bash
# perf kvm tests
# SPDX-License-Identifier: GPL-2.0
set -e
err=0
perfdata=$(mktemp /tmp/__perf_kvm_test.perf.data.XXXXX)
qemu_pid_file=$(mktemp /tmp/__perf_kvm_test.qemu.pid.XXXXX)
log_file=$(mktemp /tmp/__perf_kvm_test.live_log.XXXXX)
cleanup() {
rm -f "${perfdata}" "${log_file}"
if [ -f "${qemu_pid_file}" ]; then
if [ -s "${qemu_pid_file}" ]; then
qemu_pid=$(cat "${qemu_pid_file}")
if [ -n "${qemu_pid}" ]; then
kill "${qemu_pid}" 2>/dev/null || true
fi
fi
rm -f "${qemu_pid_file}"
fi
trap - EXIT TERM INT
}
trap_cleanup() {
echo "Unexpected signal in ${FUNCNAME[1]}"
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
skip() {
echo "Skip: $1"
cleanup
exit 2
}
test_kvm_stat() {
echo "Testing perf kvm stat"
echo "Recording kvm events for pid ${qemu_pid}..."
if ! perf kvm stat record -p "${qemu_pid}" -o "${perfdata}" sleep 1; then
echo "Failed to record kvm events"
err=1
return
fi
echo "Reporting kvm events..."
if ! perf kvm -i "${perfdata}" stat report 2>&1 | grep -q "VM-EXIT"; then
echo "Failed to find VM-EXIT in report"
perf kvm -i "${perfdata}" stat report 2>&1
err=1
return
fi
echo "perf kvm stat test [Success]"
}
test_kvm_record_report() {
echo "Testing perf kvm record/report"
echo "Recording kvm profile for pid ${qemu_pid}..."
# Use --host to avoid needing guest symbols/mounts for this simple test
# We just want to verify the command runs and produces data
# We run in background and kill it because 'perf kvm record' appends options
# after the command, which breaks 'sleep' (e.g. it gets '-e cycles').
perf kvm --host record -p "${qemu_pid}" -o "${perfdata}" &
rec_pid=$!
sleep 1
kill -INT "${rec_pid}"
wait "${rec_pid}" || true
echo "Reporting kvm profile..."
# Check for some standard output from report
if ! perf kvm -i "${perfdata}" report --stdio 2>&1 | grep -q "Event count"; then
echo "Failed to report kvm profile"
perf kvm -i "${perfdata}" report --stdio 2>&1
err=1
return
fi
echo "perf kvm record/report test [Success]"
}
test_kvm_buildid_list() {
echo "Testing perf kvm buildid-list"
# We reuse the perf.data from the previous record test
if ! perf kvm --host -i "${perfdata}" buildid-list 2>&1 | grep -q "."; then
echo "Failed to list buildids"
perf kvm --host -i "${perfdata}" buildid-list 2>&1
err=1
return
fi
echo "perf kvm buildid-list test [Success]"
}
test_kvm_stat_live() {
echo "Testing perf kvm stat live"
# Run perf kvm live for 5 seconds, monitoring that PID
# Use sleep to keep stdin open but silent, preventing EOF loop or interactive spam
if ! sleep 10 | timeout 5s perf kvm stat live -p "${qemu_pid}" > "${log_file}" 2>&1; then
retval=$?
if [ $retval -ne 124 ] && [ $retval -ne 0 ]; then
echo "perf kvm stat live [Failed: perf kvm stat live failed to start or run (ret=$retval)]"
head -n 50 "${log_file}"
err=1
return
fi
fi
# Check for some sample data (percentage)
if ! grep -E -q "[0-9]+\.[0-9]+%" "${log_file}"; then
echo "perf kvm stat live [Failed: no sample percentage found]"
head -n 50 "${log_file}"
err=1
return
fi
echo "perf kvm stat live test [Success]"
}
setup_qemu() {
# Find qemu
if [ "$(uname -m)" = "x86_64" ]; then
qemu="qemu-system-x86_64"
elif [ "$(uname -m)" = "aarch64" ]; then
qemu="qemu-system-aarch64"
elif [ "$(uname -m)" = "s390x" ]; then
qemu="qemu-system-s390x"
elif [ "$(uname -m)" = "ppc64le" ]; then
qemu="qemu-system-ppc64"
else
qemu="qemu-system-$(uname -m)"
fi
if ! which -s "$qemu"; then
skip "$qemu not found"
fi
if [ ! -r /dev/kvm ] || [ ! -w /dev/kvm ]; then
skip "/dev/kvm not accessible"
fi
if ! perf kvm stat record -o /dev/null -a sleep 0.01 >/dev/null 2>&1; then
skip "No permission to record kvm events"
fi
echo "Starting $qemu..."
# Start qemu in background, detached, with pidfile
# We use -display none -daemonize and a monitor to keep it alive/controllable if needed
# We don't need a real kernel, just KVM active.
if ! $qemu -enable-kvm -display none -daemonize -pidfile "${qemu_pid_file}" -monitor none; then
echo "Failed to start qemu"
err=1
return
fi
# Wait a bit for qemu to start
sleep 1
qemu_pid=$(cat "${qemu_pid_file}")
if ! kill -0 "${qemu_pid}" 2>/dev/null; then
echo "Qemu process failed to stay alive"
err=1
return
fi
}
setup_qemu
if [ $err -eq 0 ]; then
test_kvm_stat
test_kvm_record_report
test_kvm_buildid_list
test_kvm_stat_live
fi
cleanup
exit $err
+79
View File
@@ -0,0 +1,79 @@
#!/bin/bash
# perf kwork tests
# SPDX-License-Identifier: GPL-2.0
set -e
# Root permissions required for tracing events.
if [ "$(id -u)" != 0 ]; then
echo "[Skip] No root permission"
exit 2
fi
err=0
perfdata=$(mktemp /tmp/__perf_test_kwork.perf.data.XXXXX)
cleanup() {
rm -f "${perfdata}"
rm -f "${perfdata}".old
trap - EXIT TERM INT
}
trap_cleanup() {
echo "Unexpected signal in ${FUNCNAME[1]}"
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
test_kwork_record() {
echo "Kwork record"
perf kwork record -o "${perfdata}" -- sleep 1
echo "Kwork record [Success]"
}
test_kwork_report() {
echo "Kwork report"
if ! perf kwork report -i "${perfdata}" | grep -q "Kwork Name"; then
echo "Kwork report [Failed missing output]"
err=1
fi
echo "Kwork report [Success]"
}
test_kwork_latency() {
echo "Kwork latency"
if ! perf kwork latency -i "${perfdata}" | grep -q "Avg delay"; then
echo "Kwork latency [Failed missing output]"
err=1
fi
echo "Kwork latency [Success]"
}
test_kwork_timehist() {
echo "Kwork timehist"
if ! perf kwork timehist -i "${perfdata}" | grep -q "Kwork name"; then
echo "Kwork timehist [Failed missing output]"
err=1
fi
echo "Kwork timehist [Success]"
}
test_kwork_top() {
echo "Kwork top"
if ! perf kwork top -i "${perfdata}" | grep -q "COMMAND"; then
echo "Kwork top [Failed missing output]"
err=1
fi
echo "Kwork top [Success]"
}
test_kwork_record
test_kwork_report
test_kwork_latency
test_kwork_timehist
test_kwork_top
cleanup
exit $err
@@ -0,0 +1,470 @@
# SPDX-License-Identifier: GPL-2.0
import configparser
import os
import sys
import glob
import optparse
import platform
import tempfile
import logging
import re
import shutil
import subprocess
def data_equal(a, b):
# Allow multiple values in assignment separated by '|'
a_list = a.split('|')
b_list = b.split('|')
for a_item in a_list:
for b_item in b_list:
if (a_item == b_item):
return True
elif (a_item == '*') or (b_item == '*'):
return True
return False
class Fail(Exception):
def __init__(self, test, msg):
self.msg = msg
self.test = test
def getMsg(self):
return '\'%s\' - %s' % (self.test.path, self.msg)
class Notest(Exception):
def __init__(self, test, arch):
self.arch = arch
self.test = test
def getMsg(self):
return '[%s] \'%s\'' % (self.arch, self.test.path)
class Unsup(Exception):
def __init__(self, test):
self.test = test
def getMsg(self):
return '\'%s\'' % self.test.path
class Event(dict):
terms = [
'cpu',
'flags',
'type',
'size',
'config',
'sample_period',
'sample_type',
'read_format',
'disabled',
'inherit',
'pinned',
'exclusive',
'exclude_user',
'exclude_kernel',
'exclude_hv',
'exclude_idle',
'mmap',
'comm',
'freq',
'inherit_stat',
'enable_on_exec',
'task',
'watermark',
'precise_ip',
'mmap_data',
'sample_id_all',
'exclude_host',
'exclude_guest',
'exclude_callchain_kernel',
'exclude_callchain_user',
'wakeup_events',
'bp_type',
'config1',
'config2',
'branch_sample_type',
'sample_regs_user',
'sample_stack_user',
]
def add(self, data):
for key, val in data:
log.debug(" %s = %s" % (key, val))
self[key] = val
def __init__(self, name, data, base):
log.debug(" Event %s" % name);
self.name = name;
self.group = ''
self.add(base)
self.add(data)
def equal(self, other):
for t in Event.terms:
log.debug(" [%s] %s %s" % (t, self[t], other[t]));
if t not in self or t not in other:
return False
if not data_equal(self[t], other[t]):
return False
return True
def optional(self):
if 'optional' in self and self['optional'] == '1':
return True
return False
def diff(self, other):
for t in Event.terms:
if t not in self or t not in other:
continue
if not data_equal(self[t], other[t]):
log.warning("expected %s=%s, got %s" % (t, self[t], other[t]))
def parse_version(version):
if not version:
return None
return [int(v) for v in version.split(".")[0:2]]
# Test file description needs to have following sections:
# [config]
# - just single instance in file
# - needs to specify:
# 'command' - perf command name
# 'args' - special command arguments
# 'ret' - Skip test if Perf doesn't exit with this value (0 by default)
# 'test_ret'- If set to 'true', fail test instead of skipping for 'ret' argument
# 'arch' - architecture specific test (optional)
# comma separated list, ! at the beginning
# negates it.
# 'auxv' - Truthy statement that is evaled in the scope of the auxv map. When false,
# the test is skipped. For example 'auxv["AT_HWCAP"] == 10'. (optional)
# 'kernel_since' - Inclusive kernel version from which the test will start running. Only the
# first two values are supported, for example "6.1" (optional)
# 'kernel_until' - Exclusive kernel version from which the test will stop running. (optional)
# [eventX:base]
# - one or multiple instances in file
# - expected values assignments
class Test(object):
def __init__(self, path, options):
parser = configparser.ConfigParser()
parser.read(path)
log.warning("running '%s'" % path)
self.path = path
self.test_dir = options.test_dir
self.perf = options.perf
self.command = parser.get('config', 'command')
self.args = parser.get('config', 'args')
try:
self.ret = parser.get('config', 'ret')
except:
self.ret = 0
self.test_ret = parser.getboolean('config', 'test_ret', fallback=False)
try:
self.arch = parser.get('config', 'arch')
log.warning("test limitation '%s'" % self.arch)
except:
self.arch = ''
self.auxv = parser.get('config', 'auxv', fallback=None)
self.kernel_since = parse_version(parser.get('config', 'kernel_since', fallback=None))
self.kernel_until = parse_version(parser.get('config', 'kernel_until', fallback=None))
self.expect = {}
self.result = {}
log.debug(" loading expected events");
self.load_events(path, self.expect)
def is_event(self, name):
if name.find("event") == -1:
return False
else:
return True
def skip_test_kernel_since(self):
if not self.kernel_since:
return False
return not self.kernel_since <= parse_version(platform.release())
def skip_test_kernel_until(self):
if not self.kernel_until:
return False
return not parse_version(platform.release()) < self.kernel_until
def skip_test_auxv(self):
def new_auxv(a, pattern):
items = list(filter(None, pattern.split(a)))
# AT_HWCAP is hex but doesn't have a prefix, so special case it
if items[0] == "AT_HWCAP":
value = int(items[-1], 16)
else:
try:
value = int(items[-1], 0)
except:
value = items[-1]
return (items[0], value)
if not self.auxv:
return False
auxv = subprocess.check_output("LD_SHOW_AUXV=1 sleep 0", shell=True) \
.decode(sys.stdout.encoding)
pattern = re.compile(r"[: ]+")
auxv = dict([new_auxv(a, pattern) for a in auxv.splitlines()])
return not eval(self.auxv)
def skip_test_arch(self, myarch):
# If architecture not set always run test
if self.arch == '':
# log.warning("test for arch %s is ok" % myarch)
return False
# Allow multiple values in assignment separated by ','
arch_list = self.arch.split(',')
# Handle negated list such as !s390x,ppc
if arch_list[0][0] == '!':
arch_list[0] = arch_list[0][1:]
log.warning("excluded architecture list %s" % arch_list)
for arch_item in arch_list:
# log.warning("test for %s arch is %s" % (arch_item, myarch))
if arch_item == myarch:
return True
return False
for arch_item in arch_list:
# log.warning("test for architecture '%s' current '%s'" % (arch_item, myarch))
if arch_item == myarch:
return False
return True
def restore_sample_rate(self, value=10000):
try:
# Check value of sample_rate
with open("/proc/sys/kernel/perf_event_max_sample_rate", "r") as fIn:
curr_value = fIn.readline()
# If too low restore to reasonable value
if not curr_value or int(curr_value) < int(value):
with open("/proc/sys/kernel/perf_event_max_sample_rate", "w") as fOut:
fOut.write(str(value))
except IOError as e:
log.warning("couldn't restore sample_rate value: I/O error %s" % e)
except ValueError as e:
log.warning("couldn't restore sample_rate value: Value error %s" % e)
except TypeError as e:
log.warning("couldn't restore sample_rate value: Type error %s" % e)
def load_events(self, path, events):
parser_event = configparser.ConfigParser()
parser_event.read(path)
# The event record section header contains 'event' word,
# optionaly followed by ':' allowing to load 'parent
# event' first as a base
for section in filter(self.is_event, parser_event.sections()):
parser_items = parser_event.items(section);
base_items = {}
# Read parent event if there's any
if (':' in section):
base = section[section.index(':') + 1:]
parser_base = configparser.ConfigParser()
parser_base.read(self.test_dir + '/' + base)
base_items = parser_base.items('event')
e = Event(section, parser_items, base_items)
events[section] = e
def run_cmd(self, tempdir):
junk1, junk2, junk3, junk4, myarch = (os.uname())
if self.skip_test_arch(myarch):
raise Notest(self, myarch)
if self.skip_test_auxv():
raise Notest(self, "auxv skip")
if self.skip_test_kernel_since():
raise Notest(self, "old kernel skip")
if self.skip_test_kernel_until():
raise Notest(self, "new kernel skip")
self.restore_sample_rate()
cmd = "PERF_TEST_ATTR=%s %s %s -o %s/perf.data %s" % (tempdir,
self.perf, self.command, tempdir, self.args)
ret = os.WEXITSTATUS(os.system(cmd))
log.info(" '%s' ret '%s', expected '%s'" % (cmd, str(ret), str(self.ret)))
if not data_equal(str(ret), str(self.ret)):
if self.test_ret:
raise Fail(self, "Perf exit code failure")
else:
raise Unsup(self)
def compare(self, expect, result):
match = {}
log.debug(" compare");
# For each expected event find all matching
# events in result. Fail if there's not any.
for exp_name, exp_event in expect.items():
exp_list = []
res_event = {}
log.debug(" matching [%s]" % exp_name)
for res_name, res_event in result.items():
log.debug(" to [%s]" % res_name)
if (exp_event.equal(res_event)):
exp_list.append(res_name)
log.debug(" ->OK")
else:
log.debug(" ->FAIL");
log.debug(" match: [%s] matches %s" % (exp_name, str(exp_list)))
# we did not any matching event - fail
if not exp_list:
if exp_event.optional():
log.debug(" %s does not match, but is optional" % exp_name)
else:
if not res_event:
log.debug(" res_event is empty");
else:
exp_event.diff(res_event)
raise Fail(self, 'match failure');
match[exp_name] = exp_list
# For each defined group in the expected events
# check we match the same group in the result.
for exp_name, exp_event in expect.items():
group = exp_event.group
if (group == ''):
continue
for res_name in match[exp_name]:
res_group = result[res_name].group
if res_group not in match[group]:
raise Fail(self, 'group failure')
log.debug(" group: [%s] matches group leader %s" %
(exp_name, str(match[group])))
log.debug(" matched")
def resolve_groups(self, events):
for name, event in events.items():
group_fd = event['group_fd'];
if group_fd == '-1':
continue;
for iname, ievent in events.items():
if (ievent['fd'] == group_fd):
event.group = iname
log.debug('[%s] has group leader [%s]' % (name, iname))
break;
def run(self):
tempdir = tempfile.mkdtemp();
try:
# run the test script
self.run_cmd(tempdir);
# load events expectation for the test
log.debug(" loading result events");
for f in glob.glob(tempdir + '/event*'):
self.load_events(f, self.result);
# resolve group_fd to event names
self.resolve_groups(self.expect);
self.resolve_groups(self.result);
# do the expectation - results matching - both ways
self.compare(self.expect, self.result)
self.compare(self.result, self.expect)
finally:
# cleanup
shutil.rmtree(tempdir)
def run_tests(options):
for f in glob.glob(options.test_dir + '/' + options.test):
try:
Test(f, options).run()
except Unsup as obj:
log.warning("unsupp %s" % obj.getMsg())
except Notest as obj:
log.warning("skipped %s" % obj.getMsg())
def setup_log(verbose):
global log
level = logging.CRITICAL
if verbose == 1:
level = logging.WARNING
if verbose == 2:
level = logging.INFO
if verbose >= 3:
level = logging.DEBUG
log = logging.getLogger('test')
log.setLevel(level)
ch = logging.StreamHandler()
ch.setLevel(level)
formatter = logging.Formatter('%(message)s')
ch.setFormatter(formatter)
log.addHandler(ch)
USAGE = '''%s [OPTIONS]
-d dir # tests dir
-p path # perf binary
-t test # single test
-v # verbose level
''' % sys.argv[0]
def main():
parser = optparse.OptionParser(usage=USAGE)
parser.add_option("-t", "--test",
action="store", type="string", dest="test")
parser.add_option("-d", "--test-dir",
action="store", type="string", dest="test_dir")
parser.add_option("-p", "--perf",
action="store", type="string", dest="perf")
parser.add_option("-v", "--verbose",
default=0, action="count", dest="verbose")
options, args = parser.parse_args()
if args:
parser.error('FAILED wrong arguments %s' % ' '.join(args))
return -1
setup_log(options.verbose)
if not options.test_dir:
print('FAILED no -d option specified')
sys.exit(-1)
if not options.test:
options.test = 'test*'
try:
run_tests(options)
except Fail as obj:
print("FAILED %s" % obj.getMsg())
sys.exit(-1)
sys.exit(0)
if __name__ == '__main__':
main()
@@ -0,0 +1,21 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
perf_has_symbol()
{
if perf test -vv -F "Symbols" 2>&1 | grep "[[:space:]]$1$"; then
echo "perf does have symbol '$1'"
return 0
fi
echo "perf does not have symbol '$1'"
return 1
}
skip_test_missing_symbol()
{
if ! perf_has_symbol "$1" ; then
echo "perf is missing symbols - skipping test"
exit 2
fi
return 0
}
@@ -0,0 +1,114 @@
#!/usr/bin/python
# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
# Basic sanity check of perf JSON output as specified in the man page.
import argparse
import sys
import json
ap = argparse.ArgumentParser()
ap.add_argument('--no-args', action='store_true')
ap.add_argument('--interval', action='store_true')
ap.add_argument('--system-wide-no-aggr', action='store_true')
ap.add_argument('--system-wide', action='store_true')
ap.add_argument('--event', action='store_true')
ap.add_argument('--per-core', action='store_true')
ap.add_argument('--per-thread', action='store_true')
ap.add_argument('--per-cache', action='store_true')
ap.add_argument('--per-cluster', action='store_true')
ap.add_argument('--per-die', action='store_true')
ap.add_argument('--per-node', action='store_true')
ap.add_argument('--per-socket', action='store_true')
ap.add_argument('--metric-only', action='store_true')
ap.add_argument('--file', type=argparse.FileType('r'), default=sys.stdin)
args = ap.parse_args()
Lines = args.file.readlines()
def isfloat(num):
try:
float(num)
return True
except ValueError:
return False
def isint(num):
try:
int(num)
return True
except ValueError:
return False
def is_counter_value(num):
return isfloat(num) or num == '<not counted>' or num == '<not supported>'
def is_metric_value(num):
return isfloat(num) or num == 'none'
def check_json_output(expected_items):
checks = {
'counters': lambda x: isfloat(x),
'core': lambda x: True,
'counter-value': lambda x: is_counter_value(x),
'cgroup': lambda x: True,
'cpu': lambda x: isint(x),
'cache': lambda x: True,
'cluster': lambda x: True,
'die': lambda x: True,
'event': lambda x: True,
'event-runtime': lambda x: isfloat(x),
'interval': lambda x: isfloat(x),
'metric-unit': lambda x: True,
'metric-value': lambda x: is_metric_value(x),
'metric-threshold': lambda x: x in ['unknown', 'good', 'less good', 'nearly bad', 'bad'],
'metricgroup': lambda x: True,
'node': lambda x: True,
'pcnt-running': lambda x: isfloat(x),
'socket': lambda x: True,
'thread': lambda x: True,
'unit': lambda x: True,
}
input = '[\n' + ','.join(Lines) + '\n]'
for item in json.loads(input):
if expected_items != -1:
count = len(item)
if count not in expected_items and count >= 1 and count <= 7 and 'metric-value' in item:
# Events that generate >1 metric may have isolated metric
# values and possibly other prefixes like interval, core,
# counters, or event-runtime/pcnt-running from multiplexing.
pass
elif count not in expected_items and count >= 1 and count <= 5 and 'metricgroup' in item:
pass
elif count - 1 in expected_items and 'metric-threshold' in item:
pass
elif count in expected_items and 'insn per cycle' in item:
pass
elif count not in expected_items:
raise RuntimeError(f'wrong number of fields. counted {count} expected {expected_items}'
f' in \'{item}\'')
for key, value in item.items():
if key not in checks:
if args.metric_only:
continue
raise RuntimeError(f'Unexpected key: key={key} value={value}')
if not checks[key](value):
raise RuntimeError(f'Check failed for: key={key} value={value}')
try:
if args.no_args or args.system_wide or args.event:
expected_items = [5, 7]
elif args.interval or args.per_thread or args.system_wide_no_aggr:
expected_items = [6, 8]
elif args.per_core or args.per_socket or args.per_node or args.per_die or args.per_cluster or args.per_cache:
expected_items = [7, 9]
elif args.metric_only:
expected_items = [1, 2]
else:
# If no option is specified, don't check the number of items.
expected_items = -1
check_json_output(expected_items)
except:
print('Test failed for input:\n' + '\n'.join(Lines))
raise
@@ -0,0 +1,603 @@
# SPDX-License-Identifier: GPL-2.0
import re
import csv
import json
import argparse
from pathlib import Path
import subprocess
class TestError:
def __init__(self, metric: list[str], wl: str, value: list[float], low: float, up=float('nan'), description=str()):
self.metric: list = metric # multiple metrics in relationship type tests
self.workloads = [wl] # multiple workloads possible
self.collectedValue: list = value
self.valueLowBound = low
self.valueUpBound = up
self.description = description
def __repr__(self) -> str:
if len(self.metric) > 1:
return "\nMetric Relationship Error: \tThe collected value of metric {0}\n\
\tis {1} in workload(s): {2} \n\
\tbut expected value range is [{3}, {4}]\n\
\tRelationship rule description: \'{5}\'".format(self.metric, self.collectedValue, self.workloads,
self.valueLowBound, self.valueUpBound, self.description)
elif len(self.collectedValue) == 0:
return "\nNo Metric Value Error: \tMetric {0} returns with no value \n\
\tworkload(s): {1}".format(self.metric, self.workloads)
else:
return "\nWrong Metric Value Error: \tThe collected value of metric {0}\n\
\tis {1} in workload(s): {2}\n\
\tbut expected value range is [{3}, {4}]"\
.format(self.metric, self.collectedValue, self.workloads,
self.valueLowBound, self.valueUpBound)
class Validator:
def __init__(self, rulefname, reportfname='', t=5, debug=False, datafname='', fullrulefname='',
workload='true', metrics='', cputype='cpu'):
self.rulefname = rulefname
self.reportfname = reportfname
self.rules = None
self.collectlist: str = metrics
self.metrics = self.__set_metrics(metrics)
self.skiplist = set()
self.tolerance = t
self.cputype = cputype
self.workloads = [x for x in workload.split(",") if x]
self.wlidx = 0 # idx of current workloads
self.allresults = dict() # metric results of all workload
self.alltotalcnt = dict()
self.allpassedcnt = dict()
self.results = dict() # metric results of current workload
# vars for test pass/failure statistics
# metrics with no results or negative results, neg result counts failed tests
self.ignoremetrics = set()
self.totalcnt = 0
self.passedcnt = 0
# vars for errors
self.errlist = list()
# vars for Rule Generator
self.pctgmetrics = set() # Percentage rule
# vars for debug
self.datafname = datafname
self.debug = debug
self.fullrulefname = fullrulefname
def __set_metrics(self, metrics=''):
if metrics != '':
return set(metrics.split(","))
else:
return set()
def read_json(self, filename: str) -> dict:
try:
with open(Path(filename).resolve(), "r") as f:
data = json.loads(f.read())
except OSError as e:
print(f"Error when reading file {e}")
sys.exit()
return data
def json_dump(self, data, output_file):
parent = Path(output_file).parent
if not parent.exists():
parent.mkdir(parents=True)
with open(output_file, "w+") as output_file:
json.dump(data,
output_file,
ensure_ascii=True,
indent=4)
def get_results(self, idx: int = 0):
return self.results.get(idx)
def get_bounds(self, lb, ub, error, alias={}, ridx: int = 0) -> list:
"""
Get bounds and tolerance from lb, ub, and error.
If missing lb, use 0.0; missing ub, use float('inf); missing error, use self.tolerance.
@param lb: str/float, lower bound
@param ub: str/float, upper bound
@param error: float/str, error tolerance
@returns: lower bound, return inf if the lower bound is a metric value and is not collected
upper bound, return -1 if the upper bound is a metric value and is not collected
tolerance, denormalized base on upper bound value
"""
# init ubv and lbv to invalid values
def get_bound_value(bound, initval, ridx):
val = initval
if isinstance(bound, int) or isinstance(bound, float):
val = bound
elif isinstance(bound, str):
if bound == '':
val = float("inf")
elif bound in alias:
vall = self.get_value(alias[ub], ridx)
if vall:
val = vall[0]
elif bound.replace('.', '1').isdigit():
val = float(bound)
else:
print("Wrong bound: {0}".format(bound))
else:
print("Wrong bound: {0}".format(bound))
return val
ubv = get_bound_value(ub, -1, ridx)
lbv = get_bound_value(lb, float('inf'), ridx)
t = get_bound_value(error, self.tolerance, ridx)
# denormalize error threshold
denormerr = t * ubv / 100 if ubv != 100 and ubv > 0 else t
return lbv, ubv, denormerr
def get_value(self, name: str, ridx: int = 0) -> list:
"""
Get value of the metric from self.results.
If result of this metric is not provided, the metric name will be added into self.ignoremetics.
All future test(s) on this metric will fail.
@param name: name of the metric
@returns: list with value found in self.results; list is empty when value is not found.
"""
results = []
data = self.results[ridx] if ridx in self.results else self.results[0]
if name not in self.ignoremetrics:
if name in data:
results.append(data[name])
elif name.replace('.', '1').isdigit():
results.append(float(name))
else:
self.ignoremetrics.add(name)
return results
def check_bound(self, val, lb, ub, err):
return True if val <= ub + err and val >= lb - err else False
# Positive Value Sanity check
def pos_val_test(self):
"""
Check if metrics value are non-negative.
One metric is counted as one test.
Failure: when metric value is negative or not provided.
Metrics with negative value will be added into self.ignoremetrics.
"""
negmetric = dict()
pcnt = 0
tcnt = 0
rerun = list()
results = self.get_results()
if not results:
return
for name, val in results.items():
if val < 0:
negmetric[name] = val
rerun.append(name)
else:
pcnt += 1
tcnt += 1
# The first round collect_perf() run these metrics with simple workload
# "true". We give metrics a second chance with a longer workload if less
# than 20 metrics failed positive test.
if len(rerun) > 0 and len(rerun) < 20:
second_results = dict()
self.second_test(rerun, second_results)
for name, val in second_results.items():
if name not in negmetric:
continue
if val >= 0:
del negmetric[name]
pcnt += 1
if len(negmetric.keys()):
self.ignoremetrics.update(negmetric.keys())
self.errlist.extend(
[TestError([m], self.workloads[self.wlidx], negmetric[m], 0) for m in negmetric.keys()])
return
def evaluate_formula(self, formula: str, alias: dict, ridx: int = 0):
"""
Evaluate the value of formula.
@param formula: the formula to be evaluated
@param alias: the dict has alias to metric name mapping
@returns: value of the formula is success; -1 if the one or more metric value not provided
"""
stack = []
b = 0
errs = []
sign = "+"
f = str()
# TODO: support parenthesis?
for i in range(len(formula)):
if i+1 == len(formula) or formula[i] in ('+', '-', '*', '/'):
s = alias[formula[b:i]] if i + \
1 < len(formula) else alias[formula[b:]]
v = self.get_value(s, ridx)
if not v:
errs.append(s)
else:
f = f + "{0}(={1:.4f})".format(s, v[0])
if sign == "*":
stack[-1] = stack[-1] * v
elif sign == "/":
stack[-1] = stack[-1] / v
elif sign == '-':
stack.append(-v[0])
else:
stack.append(v[0])
if i + 1 < len(formula):
sign = formula[i]
f += sign
b = i + 1
if len(errs) > 0:
return -1, "Metric value missing: "+','.join(errs)
val = sum(stack)
return val, f
# Relationships Tests
def relationship_test(self, rule: dict):
"""
Validate if the metrics follow the required relationship in the rule.
eg. lower_bound <= eval(formula)<= upper_bound
One rule is counted as ont test.
Failure: when one or more metric result(s) not provided, or when formula evaluated outside of upper/lower bounds.
@param rule: dict with metric name(+alias), formula, and required upper and lower bounds.
"""
alias = dict()
for m in rule['Metrics']:
alias[m['Alias']] = m['Name']
lbv, ubv, t = self.get_bounds(
rule['RangeLower'], rule['RangeUpper'], rule['ErrorThreshold'], alias, ridx=rule['RuleIndex'])
val, f = self.evaluate_formula(
rule['Formula'], alias, ridx=rule['RuleIndex'])
lb = rule['RangeLower']
ub = rule['RangeUpper']
if isinstance(lb, str):
if lb in alias:
lb = alias[lb]
if isinstance(ub, str):
if ub in alias:
ub = alias[ub]
if val == -1:
self.errlist.append(TestError([m['Name'] for m in rule['Metrics']], self.workloads[self.wlidx], [],
lb, ub, rule['Description']))
elif not self.check_bound(val, lbv, ubv, t):
self.errlist.append(TestError([m['Name'] for m in rule['Metrics']], self.workloads[self.wlidx], [val],
lb, ub, rule['Description']))
else:
self.passedcnt += 1
self.totalcnt += 1
return
# Single Metric Test
def single_test(self, rule: dict):
"""
Validate if the metrics are in the required value range.
eg. lower_bound <= metrics_value <= upper_bound
One metric is counted as one test in this type of test.
One rule may include one or more metrics.
Failure: when the metric value not provided or the value is outside the bounds.
This test updates self.total_cnt.
@param rule: dict with metrics to validate and the value range requirement
"""
lbv, ubv, t = self.get_bounds(
rule['RangeLower'], rule['RangeUpper'], rule['ErrorThreshold'])
metrics = rule['Metrics']
passcnt = 0
totalcnt = 0
failures = dict()
rerun = list()
for m in metrics:
totalcnt += 1
result = self.get_value(m['Name'])
if len(result) > 0 and self.check_bound(result[0], lbv, ubv, t) or m['Name'] in self.skiplist:
passcnt += 1
else:
failures[m['Name']] = result
rerun.append(m['Name'])
if len(rerun) > 0 and len(rerun) < 20:
second_results = dict()
self.second_test(rerun, second_results)
for name, val in second_results.items():
if name not in failures:
continue
if self.check_bound(val, lbv, ubv, t):
passcnt += 1
del failures[name]
else:
failures[name] = [val]
self.results[0][name] = val
self.totalcnt += totalcnt
self.passedcnt += passcnt
if len(failures.keys()) != 0:
self.errlist.extend([TestError([name], self.workloads[self.wlidx], val,
rule['RangeLower'], rule['RangeUpper']) for name, val in failures.items()])
return
def create_report(self):
"""
Create final report and write into a JSON file.
"""
print(self.errlist)
if self.debug:
allres = [{"Workload": self.workloads[i], "Results": self.allresults[i]}
for i in range(0, len(self.workloads))]
self.json_dump(allres, self.datafname)
def check_rule(self, testtype, metric_list):
"""
Check if the rule uses metric(s) that not exist in current platform.
@param metric_list: list of metrics from the rule.
@return: False when find one metric out in Metric file. (This rule should not skipped.)
True when all metrics used in the rule are found in Metric file.
"""
if testtype == "RelationshipTest":
for m in metric_list:
if m['Name'] not in self.metrics:
return False
return True
# Start of Collector and Converter
def convert(self, data: list, metricvalues: dict):
"""
Convert collected metric data from the -j output to dict of {metric_name:value}.
"""
for json_string in data:
try:
result = json.loads(json_string)
if "metric-unit" in result and result["metric-unit"] != "(null)" and result["metric-unit"] != "":
name = result["metric-unit"].split(" ")[1] if len(result["metric-unit"].split(" ")) > 1 \
else result["metric-unit"]
metricvalues[name.lower()] = float(result["metric-value"])
except ValueError as error:
continue
return
def _run_perf(self, metric, workload: str):
tool = 'perf'
command = [tool, 'stat', '--cputype', self.cputype, '-j', '-M', f"{metric}", "-a"]
wl = workload.split()
command.extend(wl)
print(" ".join(command))
cmd = subprocess.run(command, stderr=subprocess.PIPE, encoding='utf-8')
data = [x+'}' for x in cmd.stderr.split('}\n') if x]
if data[0][0] != '{':
data[0] = data[0][data[0].find('{'):]
return data
def collect_perf(self, workload: str):
"""
Collect metric data with "perf stat -M" on given workload with -a and -j.
"""
self.results = dict()
print(f"Starting perf collection")
print(f"Long workload: {workload}")
collectlist = dict()
if self.collectlist != "":
collectlist[0] = {x for x in self.collectlist.split(",")}
else:
collectlist[0] = set(list(self.metrics))
# Create metric set for relationship rules
for rule in self.rules:
if rule["TestType"] == "RelationshipTest":
metrics = [m["Name"] for m in rule["Metrics"]]
if not any(m not in collectlist[0] for m in metrics):
collectlist[rule["RuleIndex"]] = [
",".join(list(set(metrics)))]
for idx, metrics in collectlist.items():
if idx == 0:
wl = "true"
else:
wl = workload
for metric in metrics:
data = self._run_perf(metric, wl)
if idx not in self.results:
self.results[idx] = dict()
self.convert(data, self.results[idx])
return
def second_test(self, collectlist, second_results):
workload = self.workloads[self.wlidx]
for metric in collectlist:
data = self._run_perf(metric, workload)
self.convert(data, second_results)
# End of Collector and Converter
# Start of Rule Generator
def parse_perf_metrics(self):
"""
Read and parse perf metric file:
1) find metrics with '1%' or '100%' as ScaleUnit for Percent check
2) create metric name list
"""
command = ['perf', 'list', '-j', '--details', 'metrics']
cmd = subprocess.run(command, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, encoding='utf-8')
try:
data = json.loads(cmd.stdout)
for m in data:
if 'MetricName' not in m:
print("Warning: no metric name")
continue
if 'Unit' in m and m['Unit'] != self.cputype:
continue
name = m['MetricName'].lower()
self.metrics.add(name)
if 'ScaleUnit' in m and (m['ScaleUnit'] == '1%' or m['ScaleUnit'] == '100%'):
self.pctgmetrics.add(name.lower())
except ValueError as error:
print(f"Error when parsing metric data")
sys.exit()
return
def remove_unsupported_rules(self, rules):
new_rules = []
for rule in rules:
add_rule = True
for m in rule["Metrics"]:
if m["Name"] in self.skiplist or m["Name"] not in self.metrics:
add_rule = False
break
if add_rule:
new_rules.append(rule)
return new_rules
def create_rules(self):
"""
Create full rules which includes:
1) All the rules from the "relationshi_rules" file
2) SingleMetric rule for all the 'percent' metrics
Reindex all the rules to avoid repeated RuleIndex
"""
data = self.read_json(self.rulefname)
rules = data['RelationshipRules']
self.skiplist = set([name.lower() for name in data['SkipList']])
self.rules = self.remove_unsupported_rules(rules)
pctgrule = {'RuleIndex': 0,
'TestType': 'SingleMetricTest',
'RangeLower': '0',
'RangeUpper': '100',
'ErrorThreshold': self.tolerance,
'Description': 'Metrics in percent unit have value with in [0, 100]',
'Metrics': [{'Name': m.lower()} for m in self.pctgmetrics]}
self.rules.append(pctgrule)
# Re-index all rules to avoid repeated RuleIndex
idx = 1
for r in self.rules:
r['RuleIndex'] = idx
idx += 1
if self.debug:
# TODO: need to test and generate file name correctly
data = {'RelationshipRules': self.rules, 'SupportedMetrics': [
{"MetricName": name} for name in self.metrics]}
self.json_dump(data, self.fullrulefname)
return
# End of Rule Generator
def _storewldata(self, key):
'''
Store all the data of one workload into the corresponding data structure for all workloads.
@param key: key to the dictionaries (index of self.workloads).
'''
self.allresults[key] = self.results
self.alltotalcnt[key] = self.totalcnt
self.allpassedcnt[key] = self.passedcnt
# Initialize data structures before data validation of each workload
def _init_data(self):
testtypes = ['PositiveValueTest',
'RelationshipTest', 'SingleMetricTest']
self.results = dict()
self.ignoremetrics = set()
self.errlist = list()
self.totalcnt = 0
self.passedcnt = 0
def test(self):
'''
The real entry point of the test framework.
This function loads the validation rule JSON file and Standard Metric file to create rules for
testing and namemap dictionaries.
It also reads in result JSON file for testing.
In the test process, it passes through each rule and launch correct test function bases on the
'TestType' field of the rule.
The final report is written into a JSON file.
'''
if not self.collectlist:
self.parse_perf_metrics()
if not self.metrics:
print("No metric found for testing")
return 0
self.create_rules()
for i in range(0, len(self.workloads)):
self.wlidx = i
self._init_data()
self.collect_perf(self.workloads[i])
# Run positive value test
self.pos_val_test()
for r in self.rules:
# skip rules that uses metrics not exist in this platform
testtype = r['TestType']
if not self.check_rule(testtype, r['Metrics']):
continue
if testtype == 'RelationshipTest':
self.relationship_test(r)
elif testtype == 'SingleMetricTest':
self.single_test(r)
else:
print("Unsupported Test Type: ", testtype)
print("Workload: ", self.workloads[i])
print("Total Test Count: ", self.totalcnt)
print("Passed Test Count: ", self.passedcnt)
self._storewldata(i)
self.create_report()
return len(self.errlist) > 0
# End of Class Validator
def main() -> None:
parser = argparse.ArgumentParser(
description="Launch metric value validation")
parser.add_argument(
"-rule", help="Base validation rule file", required=True)
parser.add_argument(
"-output_dir", help="Path for validator output file, report file", required=True)
parser.add_argument("-debug", help="Debug run, save intermediate data to files",
action="store_true", default=False)
parser.add_argument(
"-wl", help="Workload to run while data collection", default="true")
parser.add_argument("-m", help="Metric list to validate", default="")
parser.add_argument("-cputype", help="Only test metrics for the given CPU/PMU type",
default="cpu")
args = parser.parse_args()
outpath = Path(args.output_dir)
reportf = Path.joinpath(outpath, 'perf_report.json')
fullrule = Path.joinpath(outpath, 'full_rule.json')
datafile = Path.joinpath(outpath, 'perf_data.json')
validator = Validator(args.rule, reportf, debug=args.debug,
datafname=datafile, fullrulefname=fullrule, workload=args.wl,
metrics=args.m, cputype=args.cputype)
ret = validator.test()
return ret
if __name__ == "__main__":
import sys
sys.exit(main())
@@ -0,0 +1,398 @@
{
"SkipList": [
"tsx_aborted_cycles",
"tsx_transactional_cycles",
"C2_Pkg_Residency",
"C6_Pkg_Residency",
"C1_Core_Residency",
"C6_Core_Residency",
"tma_false_sharing",
"tma_remote_cache",
"tma_contested_accesses"
],
"RelationshipRules": [
{
"RuleIndex": 1,
"Formula": "a+b",
"TestType": "RelationshipTest",
"RangeLower": "c",
"RangeUpper": "c",
"ErrorThreshold": 5.0,
"Description": "Intel(R) Optane(TM) Persistent Memory(PMEM) bandwidth total includes Intel(R) Optane(TM) Persistent Memory(PMEM) read bandwidth and Intel(R) Optane(TM) Persistent Memory(PMEM) write bandwidth",
"Metrics": [
{
"Name": "pmem_memory_bandwidth_read",
"Alias": "a"
},
{
"Name": "pmem_memory_bandwidth_write",
"Alias": "b"
},
{
"Name": "pmem_memory_bandwidth_total",
"Alias": "c"
}
]
},
{
"RuleIndex": 2,
"Formula": "a+b",
"TestType": "RelationshipTest",
"RangeLower": "c",
"RangeUpper": "c",
"ErrorThreshold": 5.0,
"Description": "DDR memory bandwidth total includes DDR memory read bandwidth and DDR memory write bandwidth",
"Metrics": [
{
"Name": "memory_bandwidth_read",
"Alias": "a"
},
{
"Name": "memory_bandwidth_write",
"Alias": "b"
},
{
"Name": "memory_bandwidth_total",
"Alias": "c"
}
]
},
{
"RuleIndex": 3,
"Formula": "a+b",
"TestType": "RelationshipTest",
"RangeLower": "100",
"RangeUpper": "100",
"ErrorThreshold": 5.0,
"Description": "Total memory read accesses includes memory reads from last level cache (LLC) addressed to local DRAM and memory reads from the last level cache (LLC) addressed to remote DRAM.",
"Metrics": [
{
"Name": "numa_reads_addressed_to_local_dram",
"Alias": "a"
},
{
"Name": "numa_reads_addressed_to_remote_dram",
"Alias": "b"
}
]
},
{
"RuleIndex": 4,
"Formula": "a",
"TestType": "SingleMetricTest",
"RangeLower": "0.125",
"RangeUpper": "",
"ErrorThreshold": "",
"Description": "",
"Metrics": [
{
"Name": "cpi",
"Alias": "a"
}
]
},
{
"RuleIndex": 5,
"Formula": "",
"TestType": "SingleMetricTest",
"RangeLower": "0",
"RangeUpper": "1",
"ErrorThreshold": 5.0,
"Description": "Ratio values should be within value range [0,1)",
"Metrics": [
{
"Name": "loads_per_instr",
"Alias": ""
},
{
"Name": "stores_per_instr",
"Alias": ""
},
{
"Name": "l1d_mpi",
"Alias": ""
},
{
"Name": "l1d_demand_data_read_hits_per_instr",
"Alias": ""
},
{
"Name": "l1_i_code_read_misses_with_prefetches_per_instr",
"Alias": ""
},
{
"Name": "l2_demand_data_read_hits_per_instr",
"Alias": ""
},
{
"Name": "l2_mpi",
"Alias": ""
},
{
"Name": "l2_demand_data_read_mpi",
"Alias": ""
},
{
"Name": "l2_demand_code_mpi",
"Alias": ""
}
]
},
{
"RuleIndex": 6,
"Formula": "a+b+c+d",
"TestType": "RelationshipTest",
"RangeLower": "100",
"RangeUpper": "100",
"ErrorThreshold": 5.0,
"Description": "Sum of TMA level 1 metrics should be 100%",
"Metrics": [
{
"Name": "tma_frontend_bound",
"Alias": "a"
},
{
"Name": "tma_bad_speculation",
"Alias": "b"
},
{
"Name": "tma_backend_bound",
"Alias": "c"
},
{
"Name": "tma_retiring",
"Alias": "d"
}
]
},
{
"RuleIndex": 7,
"Formula": "a+b",
"TestType": "RelationshipTest",
"RangeLower": "c",
"RangeUpper": "c",
"ErrorThreshold": 5.0,
"Description": "Sum of the level 2 children should equal level 1 parent",
"Metrics": [
{
"Name": "tma_fetch_latency",
"Alias": "a"
},
{
"Name": "tma_fetch_bandwidth",
"Alias": "b"
},
{
"Name": "tma_frontend_bound",
"Alias": "c"
}
]
},
{
"RuleIndex": 8,
"Formula": "a+b",
"TestType": "RelationshipTest",
"RangeLower": "c",
"RangeUpper": "c",
"ErrorThreshold": 5.0,
"Description": "Sum of the level 2 children should equal level 1 parent",
"Metrics": [
{
"Name": "tma_branch_mispredicts",
"Alias": "a"
},
{
"Name": "tma_machine_clears",
"Alias": "b"
},
{
"Name": "tma_bad_speculation",
"Alias": "c"
}
]
},
{
"RuleIndex": 9,
"Formula": "a+b",
"TestType": "RelationshipTest",
"RangeLower": "c",
"RangeUpper": "c",
"ErrorThreshold": 5.0,
"Description": "Sum of the level 2 children should equal level 1 parent",
"Metrics": [
{
"Name": "tma_memory_bound",
"Alias": "a"
},
{
"Name": "tma_core_bound",
"Alias": "b"
},
{
"Name": "tma_backend_bound",
"Alias": "c"
}
]
},
{
"RuleIndex": 10,
"Formula": "a+b",
"TestType": "RelationshipTest",
"RangeLower": "c",
"RangeUpper": "c",
"ErrorThreshold": 5.0,
"Description": "Sum of the level 2 children should equal level 1 parent",
"Metrics": [
{
"Name": "tma_light_operations",
"Alias": "a"
},
{
"Name": "tma_heavy_operations",
"Alias": "b"
},
{
"Name": "tma_retiring",
"Alias": "c"
}
]
},
{
"RuleIndex": 11,
"Formula": "a+b+c",
"TestType": "RelationshipTest",
"RangeLower": "100",
"RangeUpper": "100",
"ErrorThreshold": 5.0,
"Description": "The all_requests includes the memory_page_empty, memory_page_misses, and memory_page_hits equals.",
"Metrics": [
{
"Name": "memory_page_empty_vs_all_requests",
"Alias": "a"
},
{
"Name": "memory_page_misses_vs_all_requests",
"Alias": "b"
},
{
"Name": "memory_page_hits_vs_all_requests",
"Alias": "c"
}
]
},
{
"RuleIndex": 12,
"Formula": "a-b",
"TestType": "RelationshipTest",
"RangeLower": "0",
"RangeUpper": "",
"ErrorThreshold": 5.0,
"Description": "CPU utilization in kernel mode should always be <= cpu utilization",
"Metrics": [
{
"Name": "cpu_utilization",
"Alias": "a"
},
{
"Name": "cpu_utilization_in_kernel_mode",
"Alias": "b"
}
]
},
{
"RuleIndex": 13,
"Formula": "a-b",
"TestType": "RelationshipTest",
"RangeLower": "0",
"RangeUpper": "",
"ErrorThreshold": 5.0,
"Description": "Total L2 misses per instruction should be >= L2 demand data read misses per instruction",
"Metrics": [
{
"Name": "l2_mpi",
"Alias": "a"
},
{
"Name": "l2_demand_data_read_mpi",
"Alias": "b"
}
]
},
{
"RuleIndex": 14,
"Formula": "a-b",
"TestType": "RelationshipTest",
"RangeLower": "0",
"RangeUpper": "",
"ErrorThreshold": 5.0,
"Description": "Total L2 misses per instruction should be >= L2 demand code misses per instruction",
"Metrics": [
{
"Name": "l2_mpi",
"Alias": "a"
},
{
"Name": "l2_demand_code_mpi",
"Alias": "b"
}
]
},
{
"RuleIndex": 15,
"Formula": "b+c+d",
"TestType": "RelationshipTest",
"RangeLower": "a",
"RangeUpper": "a",
"ErrorThreshold": 5.0,
"Description": "L3 data read, rfo, code misses per instruction equals total L3 misses per instruction.",
"Metrics": [
{
"Name": "llc_mpi",
"Alias": "a"
},
{
"Name": "llc_data_read_mpi_demand_plus_prefetch",
"Alias": "b"
},
{
"Name": "llc_rfo_read_mpi_demand_plus_prefetch",
"Alias": "c"
},
{
"Name": "llc_code_read_mpi_demand_plus_prefetch",
"Alias": "d"
}
]
},
{
"RuleIndex": 16,
"Formula": "a",
"TestType": "SingleMetricTest",
"RangeLower": "0",
"RangeUpper": "8",
"ErrorThreshold": 0.0,
"Description": "Setting generous range for allowable frequencies",
"Metrics": [
{
"Name": "uncore_freq",
"Alias": "a"
}
]
},
{
"RuleIndex": 17,
"Formula": "a",
"TestType": "SingleMetricTest",
"RangeLower": "0",
"RangeUpper": "8",
"ErrorThreshold": 0.0,
"Description": "Setting generous range for allowable frequencies",
"Metrics": [
{
"Name": "cpu_operating_frequency",
"Alias": "a"
}
]
}
]
}
@@ -0,0 +1,13 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Arnaldo Carvalho de Melo <acme@kernel.org>, 2017
skip_if_no_perf_probe() {
perf probe 2>&1 | grep -q 'is not a perf-command' && return 2
return 0
}
skip_if_no_perf_trace() {
perf trace -h 2>&1 | grep -q -e 'is not a perf-command' -e 'trace command not available' && return 2
return 0
}
@@ -0,0 +1,52 @@
#!/bin/bash
# Arnaldo Carvalho de Melo <acme@kernel.org>, 2017
perf probe -l 2>&1 | grep -q probe:vfs_getname
had_vfs_getname=$?
cleanup_probe_vfs_getname() {
if [ $had_vfs_getname -eq 1 ] ; then
perf probe -q -d probe:vfs_getname*
fi
}
add_probe_vfs_getname() {
add_probe_verbose=$1
if [ $had_vfs_getname -eq 1 ] ; then
result_initname_re="[[:space:]]+([[:digit:]]+)[[:space:]]+initname.*"
line=$(perf probe -L getname_flags 2>&1 | grep -E "$result_initname_re" | sed -r "s/$result_initname_re/\1/")
# Search the old regular expressions so that this will
# pass on older kernels as well.
if [ -z "$line" ] ; then
result_filename_re="[[:space:]]+([[:digit:]]+)[[:space:]]+result->uptr.*"
line=$(perf probe -L getname_flags 2>&1 | grep -E "$result_filename_re" | sed -r "s/$result_filename_re/\1/")
fi
if [ -z "$line" ] ; then
result_aname_re="[[:space:]]+([[:digit:]]+)[[:space:]]+result->aname = NULL;"
line=$(perf probe -L getname_flags 2>&1 | grep -E "$result_aname_re" | sed -r "s/$result_aname_re/\1/")
fi
if [ -z "$line" ] ; then
echo "Could not find probeable line"
return 2
fi
perf probe -q "vfs_getname=getname_flags:${line} pathname=result->name:string" || \
perf probe $add_probe_verbose "vfs_getname=getname_flags:${line} pathname=filename:ustring" || return 1
fi
}
skip_if_no_debuginfo() {
add_probe_vfs_getname -v 2>&1 | grep -E -q "^(Failed to find the path for the kernel|Debuginfo-analysis is not supported)|(file has no debug information)" && return 2
return 1
}
# check if perf is compiled with libtraceevent support
skip_no_probe_record_support() {
if [ $had_vfs_getname -eq 1 ] ; then
perf check feature -q libtraceevent && return 1
return 2
fi
}
@@ -0,0 +1,16 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
if [ "x$PYTHON" = "x" ]
then
python3 --version >/dev/null 2>&1 && PYTHON=python3
fi
if [ "x$PYTHON" = "x" ]
then
python --version >/dev/null 2>&1 && PYTHON=python
fi
if [ "x$PYTHON" = "x" ]
then
echo Skipping test, python not detected please set environment variable PYTHON.
exit 2
fi

Some files were not shown because too many files have changed in this diff Show More