Skip to content

Commit 86d1095

Browse files
captain5050namhyung
authored andcommitted
perf test: Fixes for check branch stack sampling
When filtering branch stack samples on user events they sample in user land but may have come from the kernel. Aarch64 avoids leaking the kernel address for kaslr reasons but other platforms, for now, don't. Be more permissive in allowing kernel addresses in the source of user branch stacks. When filtering branch stack samples on kernel events they sample in kernel land but may have come from user land. Avoid the target being a user address but allow the source to be in user land. Aarch64 may not leak the user land addresses (making them 0) but other platforms do. As the kernel address sampling implies privelege, just allow this. Increase the duration of the system call sampling test to make the likelihood of sampling a system call higher (increased from 1000 to 8000 loops - a number found through experimentation on an Intel Tigerlake laptop), also make the period of the event a prime number. Put unneeded perf record output into a temporary file so that the test output isn't cluttered. More clearly state which test is running and the pass, fail or skipped result of the test. These changes make the test on an Intel tigerlake laptop reliably pass rather than reliably fail. Signed-off-by: Ian Rogers <irogers@google.com> Reviewed-by: James Clark <james.clark@linaro.org> Signed-off-by: Namhyung Kim <namhyung@kernel.org>
1 parent c7fe4e5 commit 86d1095

1 file changed

Lines changed: 96 additions & 50 deletions

File tree

tools/perf/tests/shell/test_brstack.sh

Lines changed: 96 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,22 @@ is_arm64() {
3838
[ "$(uname -m)" = "aarch64" ];
3939
}
4040

41+
has_kaslr_bug() {
42+
[ "$(uname -m)" != "aarch64" ];
43+
}
44+
4145
check_branches() {
4246
if ! tr -s ' ' '\n' < "$TMPDIR/perf.script" | grep -E -m1 -q "$1"; then
43-
echo "Branches missing $1"
47+
echo "ERROR: Branches missing $1"
4448
err=1
4549
fi
4650
}
4751

4852
test_user_branches() {
4953
echo "Testing user branch stack sampling"
5054

55+
start_err=$err
56+
err=0
5157
perf record -o "$TMPDIR/perf.data" --branch-filter any,save_type,u -- ${TESTPROG} > "$TMPDIR/record.txt" 2>&1
5258
perf script -i "$TMPDIR/perf.data" --fields brstacksym > "$TMPDIR/perf.script"
5359

@@ -73,59 +79,88 @@ test_user_branches() {
7379
perf script -i "$TMPDIR/perf.data" --fields brstack | \
7480
tr ' ' '\n' > "$TMPDIR/perf.script"
7581

76-
# There should be no kernel addresses with the u option, in either
77-
# source or target addresses.
78-
if grep -E -m1 "0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then
79-
echo "ERROR: Kernel address found in user mode"
82+
# There should be no kernel addresses in the target with the u option.
83+
local regex="0x[89a-f][0-9a-f]{15}"
84+
if has_kaslr_bug; then
85+
# If the system has a kaslr bug that may leak kernel addresses
86+
# in the source of something like an ERET/SYSRET. Make the regex
87+
# more specific and just check the target address is in user
88+
# code.
89+
regex="^0x[0-9a-f]{0,16}/0x[89a-f][0-9a-f]{15}/"
90+
fi
91+
if grep -q -E -m1 "$regex" $TMPDIR/perf.script; then
92+
echo "Testing user branch stack sampling [Failed kernel address found in user mode]"
8093
err=1
8194
fi
8295
# some branch types are still not being tested:
8396
# IND COND_CALL COND_RET SYSRET SERROR NO_TX
97+
if [ $err -eq 0 ]; then
98+
echo "Testing user branch stack sampling [Passed]"
99+
err=$start_err
100+
else
101+
echo "Testing user branch stack sampling [Failed]"
102+
fi
84103
}
85104

86105
test_trap_eret_branches() {
87106
echo "Testing trap & eret branches"
107+
88108
if ! is_arm64; then
89-
echo "skip: not arm64"
109+
echo "Testing trap & eret branches [Skipped not arm64]"
110+
return
111+
fi
112+
start_err=$err
113+
err=0
114+
perf record -o $TMPDIR/perf.data --branch-filter any,save_type,u,k -- \
115+
perf test -w traploop 1000 > "$TMPDIR/record.txt" 2>&1
116+
perf script -i $TMPDIR/perf.data --fields brstacksym | \
117+
tr ' ' '\n' > $TMPDIR/perf.script
118+
119+
# BRBINF<n>.TYPE == TRAP are mapped to PERF_BR_IRQ by the BRBE driver
120+
check_branches "^trap_bench\+[^ ]+/[^ ]/IRQ/"
121+
check_branches "^[^ ]+/trap_bench\+[^ ]+/ERET/"
122+
if [ $err -eq 0 ]; then
123+
echo "Testing trap & eret branches [Passed]"
124+
err=$start_err
90125
else
91-
perf record -o $TMPDIR/perf.data --branch-filter any,save_type,u,k -- \
92-
perf test -w traploop 1000
93-
perf script -i $TMPDIR/perf.data --fields brstacksym | \
94-
tr ' ' '\n' > $TMPDIR/perf.script
95-
96-
# BRBINF<n>.TYPE == TRAP are mapped to PERF_BR_IRQ by the BRBE driver
97-
check_branches "^trap_bench\+[^ ]+/[^ ]/IRQ/"
98-
check_branches "^[^ ]+/trap_bench\+[^ ]+/ERET/"
126+
echo "Testing trap & eret branches [Failed]"
99127
fi
100128
}
101129

102130
test_kernel_branches() {
103-
echo "Testing that k option only includes kernel source addresses"
131+
echo "Testing kernel branch sampling"
104132

105-
if ! perf record --branch-filter any,k -o- -- true > /dev/null; then
106-
echo "skip: not enough privileges"
133+
if ! perf record --branch-filter any,k -o- -- true > "$TMPDIR/record.txt" 2>&1; then
134+
echo "Testing that k option [Skipped not enough privileges]"
135+
return
136+
fi
137+
start_err=$err
138+
err=0
139+
perf record -o $TMPDIR/perf.data --branch-filter any,k -- \
140+
perf bench syscall basic --loop 1000 > "$TMPDIR/record.txt" 2>&1
141+
perf script -i $TMPDIR/perf.data --fields brstack | \
142+
tr ' ' '\n' > $TMPDIR/perf.script
143+
144+
# Example of branch entries:
145+
# "0xffffffff93bda241/0xffffffff93bda20f/M/-/-/..."
146+
# Source addresses come first in user or kernel code. Next is the target
147+
# address that must be in the kernel.
148+
149+
# Look for source addresses with top bit set
150+
if ! grep -q -E -m1 "^0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then
151+
echo "Testing kernel branch sampling [Failed kernel branches missing]"
152+
err=1
153+
fi
154+
# Look for no target addresses without top bit set
155+
if grep -q -E -m1 "^0x[0-9a-f]{0,16}/0x[0-7][0-9a-f]{1,15}/" $TMPDIR/perf.script; then
156+
echo "Testing kernel branch sampling [Failed user branches found]"
157+
err=1
158+
fi
159+
if [ $err -eq 0 ]; then
160+
echo "Testing kernel branch sampling [Passed]"
161+
err=$start_err
107162
else
108-
perf record -o $TMPDIR/perf.data --branch-filter any,k -- \
109-
perf bench syscall basic --loop 1000
110-
perf script -i $TMPDIR/perf.data --fields brstack | \
111-
tr ' ' '\n' > $TMPDIR/perf.script
112-
113-
# Example of branch entries:
114-
# "0xffffffff93bda241/0xffffffff93bda20f/M/-/-/..."
115-
# Source addresses come first and target address can be either
116-
# userspace or kernel even with k option, as long as the source
117-
# is in kernel.
118-
119-
#Look for source addresses with top bit set
120-
if ! grep -E -m1 "^0x[89a-f][0-9a-f]{15}" $TMPDIR/perf.script; then
121-
echo "ERROR: Kernel branches missing"
122-
err=1
123-
fi
124-
# Look for no source addresses without top bit set
125-
if grep -E -m1 "^0x[0-7][0-9a-f]{0,15}" $TMPDIR/perf.script; then
126-
echo "ERROR: User branches found with kernel filter"
127-
err=1
128-
fi
163+
echo "Testing kernel branch sampling [Failed]"
129164
fi
130165
}
131166

@@ -136,14 +171,15 @@ test_filter() {
136171
test_filter_expect=$2
137172

138173
echo "Testing branch stack filtering permutation ($test_filter_filter,$test_filter_expect)"
139-
perf record -o "$TMPDIR/perf.data" --branch-filter "$test_filter_filter,save_type,u" -- ${TESTPROG} > "$TMPDIR/record.txt" 2>&1
174+
perf record -o "$TMPDIR/perf.data" --branch-filter "$test_filter_filter,save_type,u" -- \
175+
${TESTPROG} > "$TMPDIR/record.txt" 2>&1
140176
perf script -i "$TMPDIR/perf.data" --fields brstack > "$TMPDIR/perf.script"
141177

142178
# fail if we find any branch type that doesn't match any of the expected ones
143179
# also consider UNKNOWN branch types (-)
144180
if [ ! -s "$TMPDIR/perf.script" ]
145181
then
146-
echo "Empty script output"
182+
echo "Testing branch stack filtering [Failed empty script output]"
147183
err=1
148184
return
149185
fi
@@ -154,26 +190,36 @@ test_filter() {
154190
> "$TMPDIR/perf.script-filtered" || true
155191
if [ -s "$TMPDIR/perf.script-filtered" ]
156192
then
157-
echo "Unexpected branch filter in script output"
193+
echo "Testing branch stack filtering [Failed unexpected branch filter]"
158194
cat "$TMPDIR/perf.script"
159195
err=1
160196
return
161197
fi
198+
echo "Testing branch stack filtering [Passed]"
162199
}
163200

164201
test_syscall() {
165202
echo "Testing syscalls"
166203
# skip if perf doesn't have enough privileges
167-
if ! perf record --branch-filter any,k -o- -- true > /dev/null; then
168-
echo "skip: not enough privileges"
204+
if ! perf record --branch-filter any,k -o- -- true > "$TMPDIR/record.txt" 2>&1; then
205+
echo "Testing syscalls [Skipped: not enough privileges]"
206+
return
207+
fi
208+
start_err=$err
209+
err=0
210+
perf record -o $TMPDIR/perf.data --branch-filter \
211+
any_call,save_type,u,k -c 10007 -- \
212+
perf bench syscall basic --loop 8000 > "$TMPDIR/record.txt" 2>&1
213+
perf script -i $TMPDIR/perf.data --fields brstacksym | \
214+
tr ' ' '\n' > $TMPDIR/perf.script
215+
216+
check_branches "getppid[^ ]*/SYSCALL/"
217+
218+
if [ $err -eq 0 ]; then
219+
echo "Testing syscalls [Passed]"
220+
err=$start_err
169221
else
170-
perf record -o $TMPDIR/perf.data --branch-filter \
171-
any_call,save_type,u,k -c 10000 -- \
172-
perf bench syscall basic --loop 1000
173-
perf script -i $TMPDIR/perf.data --fields brstacksym | \
174-
tr ' ' '\n' > $TMPDIR/perf.script
175-
176-
check_branches "getppid[^ ]*/SYSCALL/"
222+
echo "Testing syscalls [Failed]"
177223
fi
178224
}
179225
set -e

0 commit comments

Comments
 (0)