[PATCH v2 13/14] perf tests: Check CoreSight abort entry and exit
Leo Yan
leo.yan at arm.com
Wed Sep 23 08:21:53 PDT 2026
Add page_fault_loop to repeatedly discard an anonymous page with
MADV_DONTNEED and read it again. Each demand fault is resolved without
signal delivery, so the load must be retried at the same PC.
For example, an expected int/iret pair is:
int 5ccadc => ffff800080010c00 insn: 00 00 40 39
...
iret ffff800080012284 => 5ccadc insn: e0 03 9f d6
The LDRB W0, [X0] at 0x5ccadc faults before completing. After resolving
the page fault, the kernel returns via ERET to the same PC to retry it.
Assisted-by: Codex:gpt-6
Signed-off-by: Leo Yan <leo.yan at arm.com>
---
tools/perf/tests/builtin-test.c | 1 +
.../perf/tests/shell/coresight/abort_entry_exit.sh | 21 ++++++++++++
tools/perf/tests/tests.h | 1 +
tools/perf/tests/workloads/Build | 2 ++
tools/perf/tests/workloads/page_fault_loop.c | 37 ++++++++++++++++++++++
5 files changed, 62 insertions(+)
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 8eab221f115e75a3ef90be975d4ed0558ceb2b16..1af8dfd45d1a2ff5c3206234cd75fb173e122d88 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -172,6 +172,7 @@ static struct test_workload *workloads[] = {
&workload__landlock,
&workload__traploop,
&workload__branch_not_taken_loop,
+ &workload__page_fault_loop,
&workload__inlineloop,
&workload__jitdump,
&workload__context_switch_loop,
diff --git a/tools/perf/tests/shell/coresight/abort_entry_exit.sh b/tools/perf/tests/shell/coresight/abort_entry_exit.sh
new file mode 100755
index 0000000000000000000000000000000000000000..483cf39b3966e89591d4e06d03a3fc6709fc3dc9
--- /dev/null
+++ b/tools/perf/tests/shell/coresight/abort_entry_exit.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# CoreSight abort entry and exit (exclusive)
+
+# shellcheck source=../lib/coresight_exception.sh
+. "$(dirname "$0")/../lib/coresight_exception.sh"
+
+test_abort_entry_exit()
+{
+ # A demand page fault retries the load at the same PC after resolution.
+ if ! record_trace page_fault_loop; then
+ cat "$tmpdir/record.log"
+ echo "Failed to record the page fault workload"
+ return 1
+ fi
+ decode_trace || return 1
+ check_exception_pairs "int" "iret" 0 || return 1
+}
+
+setup_exception_test || exit $?
+test_abort_entry_exit
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 0a61129b31ab6997616f7d04d29af73961f4f861..0fc02c5b060133ef27b80de5c868d798d65a7c53 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -247,6 +247,7 @@ DECLARE_WORKLOAD(datasym);
DECLARE_WORKLOAD(landlock);
DECLARE_WORKLOAD(traploop);
DECLARE_WORKLOAD(branch_not_taken_loop);
+DECLARE_WORKLOAD(page_fault_loop);
DECLARE_WORKLOAD(inlineloop);
DECLARE_WORKLOAD(jitdump);
DECLARE_WORKLOAD(context_switch_loop);
diff --git a/tools/perf/tests/workloads/Build b/tools/perf/tests/workloads/Build
index ca22a82073ed08de5d4a27d0a3b33ddcba2e3f3e..e18fdaa6fd1927ed406e703a7ecbcc19a111caf3 100644
--- a/tools/perf/tests/workloads/Build
+++ b/tools/perf/tests/workloads/Build
@@ -10,6 +10,7 @@ perf-test-y += datasym.o
perf-test-y += landlock.o
perf-test-y += traploop.o
perf-test-y += branch_not_taken_loop.o
+perf-test-y += page_fault_loop.o
perf-test-y += inlineloop.o
perf-test-y += jitdump.o
perf-test-y += context_switch_loop.o
@@ -27,6 +28,7 @@ CFLAGS_brstack.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
CFLAGS_datasym.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
CFLAGS_traploop.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
CFLAGS_branch_not_taken_loop.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
+CFLAGS_page_fault_loop.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
CFLAGS_inlineloop.o = -g -O2
CFLAGS_deterministic.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
CFLAGS_named_threads.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
diff --git a/tools/perf/tests/workloads/page_fault_loop.c b/tools/perf/tests/workloads/page_fault_loop.c
new file mode 100644
index 0000000000000000000000000000000000000000..4afbc4ab0a55400360facdc3a99ea5a5a9d52596
--- /dev/null
+++ b/tools/perf/tests/workloads/page_fault_loop.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/compiler.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include "../tests.h"
+
+static int page_fault_loop(int argc __maybe_unused, const char **argv __maybe_unused)
+{
+ size_t size = getpagesize();
+ char *page;
+ int ret = 1;
+
+ page = mmap(NULL, size, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (page == MAP_FAILED) {
+ perror("mmap");
+ return 1;
+ }
+
+ for (int i = 0; i < 256; i++) {
+ /* Drop the PTE so the kernel must resolve a fault on each read. */
+ if (madvise(page, size, MADV_DONTNEED)) {
+ perror("madvise");
+ goto out;
+ }
+ if (READ_ONCE(*page)) {
+ fprintf(stderr, "Anonymous page is not zero-filled\n");
+ goto out;
+ }
+ }
+ ret = 0;
+out:
+ munmap(page, size);
+ return ret;
+}
+
+DEFINE_WORKLOAD(page_fault_loop);
--
2.34.1
More information about the linux-arm-kernel
mailing list