* [PATCH v4 05/19] perf test: Add deterministic workload
From: James Clark @ 2026-06-09 14:30 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v4-0-44f9fb9e5c42@linaro.org>
Add a workload that does the same thing every time for testing CPU trace
decoding.
Reviewed-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: James Clark <james.clark@linaro.org>
---
tools/perf/Documentation/perf-test.txt | 4 +--
tools/perf/tests/builtin-test.c | 1 +
tools/perf/tests/tests.h | 1 +
tools/perf/tests/workloads/Build | 2 ++
tools/perf/tests/workloads/deterministic.c | 39 ++++++++++++++++++++++++++++++
5 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
index 213eb62603eb..c50a4b2d2d29 100644
--- a/tools/perf/Documentation/perf-test.txt
+++ b/tools/perf/Documentation/perf-test.txt
@@ -57,7 +57,7 @@ OPTIONS
--workload=::
Run a built-in workload, to list them use '--list-workloads', current
ones include: noploop, thloop, leafloop, sqrtloop, brstack, datasym,
- context_switch_loop and landlock.
+ context_switch_loop, deterministic and landlock.
Used with the shell script regression tests.
@@ -66,7 +66,7 @@ OPTIONS
seconds: leafloop, noploop, sqrtloop, thloop
nrloops: brstack, context_switch_loop
- The datasym and landlock workloads don't accept any.
+ The datasym, landlock and deterministic workloads don't accept any.
--list-workloads::
List the available workloads to use with -w/--workload.
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 9284f897de3c..ef7e3f52a383 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -164,6 +164,7 @@ static struct test_workload *workloads[] = {
&workload__inlineloop,
&workload__jitdump,
&workload__context_switch_loop,
+ &workload__deterministic,
#ifdef HAVE_RUST_SUPPORT
&workload__code_with_type,
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 7cd4da4e96d3..bcfe9c33fc66 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -246,6 +246,7 @@ DECLARE_WORKLOAD(traploop);
DECLARE_WORKLOAD(inlineloop);
DECLARE_WORKLOAD(jitdump);
DECLARE_WORKLOAD(context_switch_loop);
+DECLARE_WORKLOAD(deterministic);
#ifdef HAVE_RUST_SUPPORT
DECLARE_WORKLOAD(code_with_type);
diff --git a/tools/perf/tests/workloads/Build b/tools/perf/tests/workloads/Build
index 7134a031cb7c..90f2d8aa4941 100644
--- a/tools/perf/tests/workloads/Build
+++ b/tools/perf/tests/workloads/Build
@@ -11,6 +11,7 @@ perf-test-y += traploop.o
perf-test-y += inlineloop.o
perf-test-y += jitdump.o
perf-test-y += context_switch_loop.o
+perf-test-y += deterministic.o
ifeq ($(CONFIG_RUST_SUPPORT),y)
perf-test-y += code_with_type.o
@@ -23,3 +24,4 @@ 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_inlineloop.o = -g -O2
+CFLAGS_deterministic.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
diff --git a/tools/perf/tests/workloads/deterministic.c b/tools/perf/tests/workloads/deterministic.c
new file mode 100644
index 000000000000..8a78519fd075
--- /dev/null
+++ b/tools/perf/tests/workloads/deterministic.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/compiler.h>
+#include "../tests.h"
+
+int dt_work = 1234;
+
+static void function1(void)
+{
+ dt_work += 7;
+ dt_work += 7;
+ dt_work += 7;
+}
+
+static void function2(void)
+{
+ dt_work += 7;
+ dt_work += 7;
+ dt_work += 7;
+}
+
+static int deterministic(int argc __maybe_unused,
+ const char **argv __maybe_unused)
+{
+ dt_work += 7;
+ dt_work += 7;
+ dt_work += 7;
+
+ function1();
+
+ dt_work += 7;
+ dt_work += 7;
+ dt_work += 7;
+
+ function2();
+
+ return 0;
+}
+
+DEFINE_WORKLOAD(deterministic);
--
2.34.1
^ permalink raw reply related
* [PATCH v4 06/19] perf test cs-etm: Replace unroll loop thread with deterministic decode test
From: James Clark @ 2026-06-09 14:30 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v4-0-44f9fb9e5c42@linaro.org>
Testing a long sequence without branches seems like it would be better
as a decoder unit test, and this test doesn't test decoding either, so
it's not clear what bugs this is trying to catch.
The new deterministic workload has somewhat long sequences when built
unoptimized, and we can always increase them later if we want to. But
now we test that decoding always gives the same result for the same
sequence of code which we've never had before.
Signed-off-by: James Clark <james.clark@linaro.org>
---
tools/perf/tests/shell/coresight/deterministic.sh | 72 ++++++++++++++++++++++
.../tests/shell/coresight/unroll_loop_thread_10.sh | 22 -------
2 files changed, 72 insertions(+), 22 deletions(-)
diff --git a/tools/perf/tests/shell/coresight/deterministic.sh b/tools/perf/tests/shell/coresight/deterministic.sh
new file mode 100755
index 000000000000..75d4973056f0
--- /dev/null
+++ b/tools/perf/tests/shell/coresight/deterministic.sh
@@ -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
diff --git a/tools/perf/tests/shell/coresight/unroll_loop_thread_10.sh b/tools/perf/tests/shell/coresight/unroll_loop_thread_10.sh
deleted file mode 100755
index cb3e97a0a89f..000000000000
--- a/tools/perf/tests/shell/coresight/unroll_loop_thread_10.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash -e
-# CoreSight / Unroll Loop Thread 10 (exclusive)
-
-# SPDX-License-Identifier: GPL-2.0
-# Carsten Haitzler <carsten.haitzler@arm.com>, 2021
-
-TEST="unroll_loop_thread"
-
-# shellcheck source=../lib/coresight.sh
-. "$(dirname $0)"/../lib/coresight.sh
-
-ARGS="10"
-DATV="10"
-# shellcheck disable=SC2153
-DATA="$DATD/perf-$TEST-$DATV.data"
-
-perf record $PERFRECOPT -o "$DATA" "$BIN" $ARGS
-
-perf_dump_aux_verify "$DATA" 10 10 10
-
-err=$?
-exit $err
--
2.34.1
^ permalink raw reply related
* [PATCH v4 07/19] perf test cs-etm: Remove asm_pure_loop test
From: James Clark @ 2026-06-09 14:31 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v4-0-44f9fb9e5c42@linaro.org>
It's not obvious what this test is for so remove it. It's not a stress
test because it doesn't output lots of data and it's not a functional
test because it only looks for raw trace output. It seems to imply that
a program written in assembly influences whether trace would be
generated by the CPU or not, but the CPU doesn't know what language the
program is written in.
We already have lots of Coresight tests that test the full pipeline
including decoding, and in many more modes of operation than this one,
so if no trace was collected they will already fail leaving this one
redundant.
Reviewed-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: James Clark <james.clark@linaro.org>
---
tools/perf/tests/shell/coresight/asm_pure_loop.sh | 22 ----------------------
1 file changed, 22 deletions(-)
diff --git a/tools/perf/tests/shell/coresight/asm_pure_loop.sh b/tools/perf/tests/shell/coresight/asm_pure_loop.sh
deleted file mode 100755
index 0301904b9637..000000000000
--- a/tools/perf/tests/shell/coresight/asm_pure_loop.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash -e
-# CoreSight / ASM Pure Loop (exclusive)
-
-# SPDX-License-Identifier: GPL-2.0
-# Carsten Haitzler <carsten.haitzler@arm.com>, 2021
-
-TEST="asm_pure_loop"
-
-# shellcheck source=../lib/coresight.sh
-. "$(dirname $0)"/../lib/coresight.sh
-
-ARGS=""
-DATV="out"
-# shellcheck disable=SC2153
-DATA="$DATD/perf-$TEST-$DATV.data"
-
-perf record $PERFRECOPT -o "$DATA" "$BIN" $ARGS
-
-perf_dump_aux_verify "$DATA" 10 10 10
-
-err=$?
-exit $err
--
2.34.1
^ permalink raw reply related
* [PATCH v4 08/19] perf test cs-etm: Replace memcpy test with raw dump stress test
From: James Clark @ 2026-06-09 14:31 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v4-0-44f9fb9e5c42@linaro.org>
Like asm_pure_loop, this memcpy test only checks that 10 of each of a
few trace packet types occur after recording a lot of trace, which isn't
more specific than other existing Coresight tests.
Assume it was supposed to be a stress test for dumping and replace it
with one that doesn't require a custom binary and checks for a specific
amount of raw output. Don't bother checking for packets because the
other tests that test decoding will catch issues with malformed data.
This also adds coverage for exit snapshot mode which was missing.
Signed-off-by: James Clark <james.clark@linaro.org>
---
.../tests/shell/coresight/memcpy_thread_16k_10.sh | 22 ----------
.../perf/tests/shell/coresight/raw_dump_stress.sh | 47 ++++++++++++++++++++++
2 files changed, 47 insertions(+), 22 deletions(-)
diff --git a/tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh b/tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh
deleted file mode 100755
index 1f765d69acc3..000000000000
--- a/tools/perf/tests/shell/coresight/memcpy_thread_16k_10.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash -e
-# CoreSight / Memcpy 16k 10 Threads (exclusive)
-
-# SPDX-License-Identifier: GPL-2.0
-# Carsten Haitzler <carsten.haitzler@arm.com>, 2021
-
-TEST="memcpy_thread"
-
-# shellcheck source=../lib/coresight.sh
-. "$(dirname $0)"/../lib/coresight.sh
-
-ARGS="16 10 1"
-DATV="16k_10"
-# shellcheck disable=SC2153
-DATA="$DATD/perf-$TEST-$DATV.data"
-
-perf record $PERFRECOPT -o "$DATA" "$BIN" $ARGS
-
-perf_dump_aux_verify "$DATA" 10 10 10
-
-err=$?
-exit $err
diff --git a/tools/perf/tests/shell/coresight/raw_dump_stress.sh b/tools/perf/tests/shell/coresight/raw_dump_stress.sh
new file mode 100755
index 000000000000..b4b4f2503fee
--- /dev/null
+++ b/tools/perf/tests/shell/coresight/raw_dump_stress.sh
@@ -0,0 +1,47 @@
+#!/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"
+
+size=$(stat -c%s "$tmpdir/rawdump")
+if [ $size -gt $((50 * 1024 * 1024)) ]; then
+ echo "PASS: Raw dump file is larger than 50MB"
+ cleanup
+ exit 0
+fi
+
+echo "FAIL: Got less than 50MB (${size} bytes)"
+cleanup
+exit 1
--
2.34.1
^ permalink raw reply related
* [PATCH v4 09/19] perf test: Add named_threads workload
From: James Clark @ 2026-06-09 14:31 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v4-0-44f9fb9e5c42@linaro.org>
Add a workload that runs X threads that run a unique function named
"named_threads_thread[x]" which performs a multiplication in a loop for
Y loops. Each thread sets its name to "thread[x]".
This can be used to test that processor trace decoding handles
concurrent threads correctly and the correct symbols and thread names
are assigned to samples.
Signed-off-by: James Clark <james.clark@linaro.org>
---
tools/perf/Documentation/perf-test.txt | 5 +-
tools/perf/tests/builtin-test.c | 1 +
tools/perf/tests/tests.h | 1 +
tools/perf/tests/workloads/Build | 1 +
tools/perf/tests/workloads/named_threads.c | 109 +++++++++++++++++++++++++++++
5 files changed, 116 insertions(+), 1 deletion(-)
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
index c50a4b2d2d29..81c8525f5946 100644
--- a/tools/perf/Documentation/perf-test.txt
+++ b/tools/perf/Documentation/perf-test.txt
@@ -57,7 +57,7 @@ OPTIONS
--workload=::
Run a built-in workload, to list them use '--list-workloads', current
ones include: noploop, thloop, leafloop, sqrtloop, brstack, datasym,
- context_switch_loop, deterministic and landlock.
+ context_switch_loop, deterministic, named_threads and landlock.
Used with the shell script regression tests.
@@ -66,6 +66,9 @@ OPTIONS
seconds: leafloop, noploop, sqrtloop, thloop
nrloops: brstack, context_switch_loop
+ 'named_threads' accepts the number of threads and the number of loops to
+ do in each thread.
+
The datasym, landlock and deterministic workloads don't accept any.
--list-workloads::
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index ef7e3f52a383..afc06cec4954 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -155,6 +155,7 @@ static struct test_suite *generic_tests[] = {
static struct test_workload *workloads[] = {
&workload__noploop,
&workload__thloop,
+ &workload__named_threads,
&workload__leafloop,
&workload__sqrtloop,
&workload__brstack,
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index bcfe9c33fc66..7cedf05be544 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -237,6 +237,7 @@ struct test_workload workload__##work = { \
/* The list of test workloads */
DECLARE_WORKLOAD(noploop);
DECLARE_WORKLOAD(thloop);
+DECLARE_WORKLOAD(named_threads);
DECLARE_WORKLOAD(leafloop);
DECLARE_WORKLOAD(sqrtloop);
DECLARE_WORKLOAD(brstack);
diff --git a/tools/perf/tests/workloads/Build b/tools/perf/tests/workloads/Build
index 90f2d8aa4941..75b377934a0e 100644
--- a/tools/perf/tests/workloads/Build
+++ b/tools/perf/tests/workloads/Build
@@ -2,6 +2,7 @@
perf-test-y += noploop.o
perf-test-y += thloop.o
+perf-test-y += named_threads.o
perf-test-y += leafloop.o
perf-test-y += sqrtloop.o
perf-test-y += brstack.o
diff --git a/tools/perf/tests/workloads/named_threads.c b/tools/perf/tests/workloads/named_threads.c
new file mode 100644
index 000000000000..d051d41a3cfe
--- /dev/null
+++ b/tools/perf/tests/workloads/named_threads.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/compiler.h>
+#include "../tests.h"
+
+#define MAX_THREADS 25
+
+static int iterations = 500;
+int named_threads_work = 1234;
+
+typedef void *(*thread_fn_t)(void *);
+
+#define DEFINE_THREAD(n) \
+noinline void *named_threads_thread##n(void *arg __maybe_unused) \
+{ \
+ pthread_setname_np(pthread_self(), "thread" #n); \
+ for (int i = 0; i < iterations; i++) \
+ named_threads_work += 3; \
+ \
+ return NULL; \
+}
+
+#define THREAD_LIST(macro) \
+ macro(1) \
+ macro(2) \
+ macro(3) \
+ macro(4) \
+ macro(5) \
+ macro(6) \
+ macro(7) \
+ macro(8) \
+ macro(9) \
+ macro(10) \
+ macro(11) \
+ macro(12) \
+ macro(13) \
+ macro(14) \
+ macro(15) \
+ macro(16) \
+ macro(17) \
+ macro(18) \
+ macro(19) \
+ macro(20) \
+ macro(21) \
+ macro(22) \
+ macro(23) \
+ macro(24) \
+ macro(25)
+
+#define DECLARE_THREAD(n) void *named_threads_thread##n(void *arg);
+
+THREAD_LIST(DECLARE_THREAD)
+THREAD_LIST(DEFINE_THREAD)
+
+#define THREAD_ENTRY(n) named_threads_thread##n,
+
+static thread_fn_t thread_fns[MAX_THREADS] = {
+ THREAD_LIST(THREAD_ENTRY)
+};
+
+/*
+ * Creates argv[0] threads that run a unique function named "thread[x]" which performs
+ * a multiplication in a loop for argv[1] loops.
+ */
+static int named_threads(int argc, const char **argv)
+{
+ pthread_t threads[MAX_THREADS];
+ int nr_threads = 1;
+ int err = 0;
+
+ if (argc > 0)
+ nr_threads = atoi(argv[0]);
+
+ if (nr_threads <= 0 || nr_threads > MAX_THREADS) {
+ fprintf(stderr, "Error: num threads must be 1 - %d\n", MAX_THREADS);
+ return 1;
+ }
+
+ if (argc > 1)
+ iterations = atoi(argv[1]);
+
+ if (iterations < 0) {
+ fprintf(stderr, "Error: iterations must be non-negative\n");
+ return 1;
+ }
+
+ for (int i = 0; i < nr_threads; i++) {
+ int ret;
+
+ ret = pthread_create(&threads[i], NULL, thread_fns[i], NULL);
+ if (ret) {
+ fprintf(stderr, "Error: failed to create thread%d: %s\n",
+ i + 1, strerror(ret));
+ return 1;
+ }
+ }
+
+ for (int i = 0; i < nr_threads; i++)
+ pthread_join(threads[i], NULL);
+
+ return err;
+}
+
+DEFINE_WORKLOAD(named_threads);
--
2.34.1
^ permalink raw reply related
* [PATCH v4 10/19] perf test cs-etm: Test decoding for concurrent threads test
From: James Clark @ 2026-06-09 14:31 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v4-0-44f9fb9e5c42@linaro.org>
The thread_loop test only looks for context IDs in the raw trace.
There's a lot more that can go wrong when decoding these, so replace it
with a test that looks at the final output for matching thread names and
symbols.
In the future we might use timestamps and context switch events to track
threads, so looking at context IDs in the raw trace wouldn't always
work.
Reviewed-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: James Clark <james.clark@linaro.org>
---
.../tests/shell/coresight/concurrent_threads.sh | 45 ++++++++++++++++++++++
.../shell/coresight/thread_loop_check_tid_10.sh | 23 -----------
.../shell/coresight/thread_loop_check_tid_2.sh | 23 -----------
3 files changed, 45 insertions(+), 46 deletions(-)
diff --git a/tools/perf/tests/shell/coresight/concurrent_threads.sh b/tools/perf/tests/shell/coresight/concurrent_threads.sh
new file mode 100755
index 000000000000..3349fff8c767
--- /dev/null
+++ b/tools/perf/tests/shell/coresight/concurrent_threads.sh
@@ -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
diff --git a/tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh b/tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh
deleted file mode 100755
index 7f43a93a2ac2..000000000000
--- a/tools/perf/tests/shell/coresight/thread_loop_check_tid_10.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash -e
-# CoreSight / Thread Loop 10 Threads - Check TID (exclusive)
-
-# SPDX-License-Identifier: GPL-2.0
-# Carsten Haitzler <carsten.haitzler@arm.com>, 2021
-
-TEST="thread_loop"
-
-# shellcheck source=../lib/coresight.sh
-. "$(dirname $0)"/../lib/coresight.sh
-
-ARGS="10 1"
-DATV="check-tid-10th"
-# shellcheck disable=SC2153
-DATA="$DATD/perf-$TEST-$DATV.data"
-STDO="$DATD/perf-$TEST-$DATV.stdout"
-
-SHOW_TID=1 perf record -s $PERFRECOPT -o "$DATA" "$BIN" $ARGS > $STDO
-
-perf_dump_aux_tid_verify "$DATA" "$STDO"
-
-err=$?
-exit $err
diff --git a/tools/perf/tests/shell/coresight/thread_loop_check_tid_2.sh b/tools/perf/tests/shell/coresight/thread_loop_check_tid_2.sh
deleted file mode 100755
index a94d2079ed06..000000000000
--- a/tools/perf/tests/shell/coresight/thread_loop_check_tid_2.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash -e
-# CoreSight / Thread Loop 2 Threads - Check TID (exclusive)
-
-# SPDX-License-Identifier: GPL-2.0
-# Carsten Haitzler <carsten.haitzler@arm.com>, 2021
-
-TEST="thread_loop"
-
-# shellcheck source=../lib/coresight.sh
-. "$(dirname $0)"/../lib/coresight.sh
-
-ARGS="2 20"
-DATV="check-tid-2th"
-# shellcheck disable=SC2153
-DATA="$DATD/perf-$TEST-$DATV.data"
-STDO="$DATD/perf-$TEST-$DATV.stdout"
-
-SHOW_TID=1 perf record -s $PERFRECOPT -o "$DATA" "$BIN" $ARGS > $STDO
-
-perf_dump_aux_tid_verify "$DATA" "$STDO"
-
-err=$?
-exit $err
--
2.34.1
^ permalink raw reply related
* [PATCH v4 11/19] perf test cs-etm: Remove duplicate branch tests
From: James Clark @ 2026-06-09 14:31 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v4-0-44f9fb9e5c42@linaro.org>
We already test branch output in perf script mode, but then retest it in
Perf report mode. This is more of a test of Perf itself than Coresight
because Perf uses the same samples to generate both outputs. Also we're
already testing instruction output in Perf report mode.
Remove this test for a speedup. On the systemwide test also remove the
Perf report test because systemwide mode records a lot more data so
running multiple tests on it has a big runtime impact.
Reviewed-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: James Clark <james.clark@linaro.org>
---
tools/perf/tests/shell/test_arm_coresight.sh | 18 +-----------------
1 file changed, 1 insertion(+), 17 deletions(-)
diff --git a/tools/perf/tests/shell/test_arm_coresight.sh b/tools/perf/tests/shell/test_arm_coresight.sh
index bbf89e944e7b..39553702c1f3 100755
--- a/tools/perf/tests/shell/test_arm_coresight.sh
+++ b/tools/perf/tests/shell/test_arm_coresight.sh
@@ -52,17 +52,6 @@ perf_script_branch_samples() {
grep -E " +$1 +[0-9]+ .* +branches:(.*:)? +" > /dev/null 2>&1
}
-perf_report_branch_samples() {
- echo "Looking at perf.data file for reporting branch samples:"
-
- # Below is an example of the branch samples reporting:
- # 73.04% 73.04% touch libc-2.27.so [.] _dl_addr
- # 7.71% 7.71% touch libc-2.27.so [.] getenv
- # 2.59% 2.59% touch ld-2.27.so [.] strcmp
- perf report --stdio -i ${perfdata} 2>&1 | \
- grep -E " +[0-9]+\.[0-9]+% +[0-9]+\.[0-9]+% +$1 " > /dev/null 2>&1
-}
-
perf_report_instruction_samples() {
echo "Looking at perf.data file for instruction samples:"
@@ -123,7 +112,6 @@ arm_cs_iterate_devices() {
record_touch_file $device_name $2 &&
perf_script_branch_samples touch &&
- perf_report_branch_samples touch &&
perf_report_instruction_samples touch
err=$?
@@ -154,9 +142,7 @@ arm_cs_etm_system_wide_test() {
# System-wide mode should include perf samples so test for that
# instead of ls
- perf_script_branch_samples perf &&
- perf_report_branch_samples perf &&
- perf_report_instruction_samples perf
+ perf_script_branch_samples perf
err=$?
arm_cs_report "CoreSight system wide testing" $err
@@ -179,7 +165,6 @@ arm_cs_etm_snapshot_test() {
wait $PERFPID
perf_script_branch_samples dd &&
- perf_report_branch_samples dd &&
perf_report_instruction_samples dd
err=$?
@@ -191,7 +176,6 @@ arm_cs_etm_basic_test() {
perf record -o ${perfdata} "$@" -m,8M -- ls > /dev/null 2>&1
perf_script_branch_samples ls &&
- perf_report_branch_samples ls &&
perf_report_instruction_samples ls
err=$?
--
2.34.1
^ permalink raw reply related
* [PATCH v4 12/19] perf test cs-etm: Skip if not root
From: James Clark @ 2026-06-09 14:31 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v4-0-44f9fb9e5c42@linaro.org>
Use the common idiom for skipping tests if not running as root, which is
required for these tests.
Signed-off-by: James Clark <james.clark@linaro.org>
---
tools/perf/tests/shell/test_arm_coresight.sh | 6 ++++++
tools/perf/tests/shell/test_arm_coresight_disasm.sh | 6 +++---
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/tools/perf/tests/shell/test_arm_coresight.sh b/tools/perf/tests/shell/test_arm_coresight.sh
index 39553702c1f3..8ed2c934c87d 100755
--- a/tools/perf/tests/shell/test_arm_coresight.sh
+++ b/tools/perf/tests/shell/test_arm_coresight.sh
@@ -20,6 +20,12 @@ skip_if_no_cs_etm_event() {
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)
diff --git a/tools/perf/tests/shell/test_arm_coresight_disasm.sh b/tools/perf/tests/shell/test_arm_coresight_disasm.sh
index 0dfb4fadf531..339ae4831868 100755
--- a/tools/perf/tests/shell/test_arm_coresight_disasm.sh
+++ b/tools/perf/tests/shell/test_arm_coresight_disasm.sh
@@ -42,7 +42,7 @@ sep="\s\|\s"
branch_search="\sbl${sep}b${sep}b.ne${sep}b.eq${sep}cbz\s"
## Test kernel ##
-if [ -e /proc/kcore ]; then
+if [ "$(id -u)" == 0 ] && [ -e /proc/kcore ]; then
echo "Testing kernel disassembly"
perf record -o ${perfdata} -e cs_etm//k --kcore -- touch $file > /dev/null 2>&1
perf script -i ${perfdata} -s python:${script_path} -- \
@@ -50,8 +50,8 @@ if [ -e /proc/kcore ]; then
grep -q -e ${branch_search} ${file}
echo "Found kernel branches"
else
- # kcore is required for correct kernel decode due to runtime code patching
- echo "No kcore, skipping kernel test"
+ # 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 ##
--
2.34.1
^ permalink raw reply related
* [PATCH v4 13/19] perf test cs-etm: Reduce snapshot size
From: James Clark @ 2026-06-09 14:31 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v4-0-44f9fb9e5c42@linaro.org>
The default buffer size for root is 4MB which is very slow to decode. We
only need a few KB to verify that the dd process is hit so reduce the
size to 128KB.
Reviewed-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: James Clark <james.clark@linaro.org>
---
tools/perf/tests/shell/test_arm_coresight.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/perf/tests/shell/test_arm_coresight.sh b/tools/perf/tests/shell/test_arm_coresight.sh
index 8ed2c934c87d..da2f599393e2 100755
--- a/tools/perf/tests/shell/test_arm_coresight.sh
+++ b/tools/perf/tests/shell/test_arm_coresight.sh
@@ -156,7 +156,7 @@ arm_cs_etm_system_wide_test() {
arm_cs_etm_snapshot_test() {
echo "Recording trace with snapshot mode"
- perf record -o ${perfdata} -e cs_etm// -S \
+ perf record -o ${perfdata} -e cs_etm// -S -m,128K \
-- dd if=/dev/zero of=/dev/null > /dev/null 2>&1 &
PERFPID=$!
--
2.34.1
^ permalink raw reply related
* [PATCH v4 14/19] perf test cs-etm: Speed up basic test
From: James Clark @ 2026-06-09 14:31 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v4-0-44f9fb9e5c42@linaro.org>
Like the name says, this should be the most basic test possible. Kernel
recording is slow and already has coverage on the systemwide test. Perf
report output also has coverage elsewhere. 'ls' also produces more trace
than 'true'.
We only want to test if the combination of recording options works at
all, so fix all of these things to make it as fast as possible.
Reviewed-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: James Clark <james.clark@linaro.org>
---
tools/perf/tests/shell/test_arm_coresight.sh | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/tools/perf/tests/shell/test_arm_coresight.sh b/tools/perf/tests/shell/test_arm_coresight.sh
index da2f599393e2..83295a8fe179 100755
--- a/tools/perf/tests/shell/test_arm_coresight.sh
+++ b/tools/perf/tests/shell/test_arm_coresight.sh
@@ -179,10 +179,9 @@ arm_cs_etm_snapshot_test() {
arm_cs_etm_basic_test() {
echo "Recording trace with '$*'"
- perf record -o ${perfdata} "$@" -m,8M -- ls > /dev/null 2>&1
+ perf record -o ${perfdata} "$@" -- true > /dev/null 2>&1
- perf_script_branch_samples ls &&
- perf_report_instruction_samples ls
+ perf_script_branch_samples true
err=$?
arm_cs_report "CoreSight basic testing with '$*'" $err
@@ -246,12 +245,12 @@ 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/ --per-thread
-arm_cs_etm_basic_test -e cs_etm/timestamp=1/ --per-thread
-arm_cs_etm_basic_test -e cs_etm/timestamp=0/ -a
-arm_cs_etm_basic_test -e cs_etm/timestamp=1/ -a
-arm_cs_etm_basic_test -e cs_etm/timestamp=0/
-arm_cs_etm_basic_test -e cs_etm/timestamp=1/
+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
--
2.34.1
^ permalink raw reply related
* [PATCH v4 15/19] perf test cs-etm: Remove unused Coresight workloads
From: James Clark @ 2026-06-09 14:31 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v4-0-44f9fb9e5c42@linaro.org>
These are now unused and had various issues like not working with out of
source builds and being slow to compile. Delete them.
Signed-off-by: James Clark <james.clark@linaro.org>
---
Documentation/trace/coresight/coresight-perf.rst | 78 +-----------
MAINTAINERS | 1 -
tools/perf/Makefile.perf | 14 +--
tools/perf/tests/shell/coresight/Makefile | 29 -----
.../perf/tests/shell/coresight/Makefile.miniconfig | 14 ---
.../tests/shell/coresight/asm_pure_loop/.gitignore | 1 -
.../tests/shell/coresight/asm_pure_loop/Makefile | 34 ------
.../shell/coresight/asm_pure_loop/asm_pure_loop.S | 30 -----
.../tests/shell/coresight/memcpy_thread/.gitignore | 1 -
.../tests/shell/coresight/memcpy_thread/Makefile | 33 -----
.../shell/coresight/memcpy_thread/memcpy_thread.c | 80 ------------
.../tests/shell/coresight/thread_loop/.gitignore | 1 -
.../tests/shell/coresight/thread_loop/Makefile | 33 -----
.../shell/coresight/thread_loop/thread_loop.c | 85 -------------
.../shell/coresight/unroll_loop_thread/.gitignore | 1 -
.../shell/coresight/unroll_loop_thread/Makefile | 33 -----
.../unroll_loop_thread/unroll_loop_thread.c | 75 ------------
tools/perf/tests/shell/lib/coresight.sh | 134 ---------------------
18 files changed, 5 insertions(+), 672 deletions(-)
diff --git a/Documentation/trace/coresight/coresight-perf.rst b/Documentation/trace/coresight/coresight-perf.rst
index 30be89320621..0a77741a431e 100644
--- a/Documentation/trace/coresight/coresight-perf.rst
+++ b/Documentation/trace/coresight/coresight-perf.rst
@@ -112,78 +112,6 @@ Example for triggering AUX pause and resume with PMU event::
Perf test - Verify kernel and userspace perf CoreSight work
-----------------------------------------------------------
-When you run perf test, it will do a lot of self tests. Some of those
-tests will cover CoreSight (only if enabled and on ARM64). You
-generally would run perf test from the tools/perf directory in the
-kernel tree. Some tests will check some internal perf support like:
-
- Check Arm CoreSight trace data recording and synthesized samples
- Check Arm SPE trace data recording and synthesized samples
-
-Some others will actually use perf record and some test binaries that
-are in tests/shell/coresight and will collect traces to ensure a
-minimum level of functionality is met. The scripts that launch these
-tests are in the same directory. These will all look like:
-
- CoreSight / ASM Pure Loop
- CoreSight / Memcpy 16k 10 Threads
- CoreSight / Thread Loop 10 Threads - Check TID
- etc.
-
-These perf record tests will not run if the tool binaries do not exist
-in tests/shell/coresight/\*/ and will be skipped. If you do not have
-CoreSight support in hardware then either do not build perf with
-CoreSight support or remove these binaries in order to not have these
-tests fail and have them skip instead.
-
-These tests will log historical results in the current working
-directory (e.g. tools/perf) and will be named stats-\*.csv like:
-
- stats-asm_pure_loop-out.csv
- stats-memcpy_thread-16k_10.csv
- ...
-
-These statistic files log some aspects of the AUX data sections in
-the perf data output counting some numbers of certain encodings (a
-good way to know that it's working in a very simple way). One problem
-with CoreSight is that given a large enough amount of data needing to
-be logged, some of it can be lost due to the processor not waking up
-in time to read out all the data from buffers etc.. You will notice
-that the amount of data collected can vary a lot per run of perf test.
-If you wish to see how this changes over time, simply run perf test
-multiple times and all these csv files will have more and more data
-appended to it that you can later examine, graph and otherwise use to
-figure out if things have become worse or better.
-
-This means sometimes these tests fail as they don't capture all the
-data needed. This is about tracking quality and amount of data
-produced over time and to see when changes to the Linux kernel improve
-quality of traces.
-
-Be aware that some of these tests take quite a while to run, specifically
-in processing the perf data file and dumping contents to then examine what
-is inside.
-
-You can change where these csv logs are stored by setting the
-PERF_TEST_CORESIGHT_STATDIR environment variable before running perf
-test like::
-
- export PERF_TEST_CORESIGHT_STATDIR=/var/tmp
- perf test
-
-They will also store resulting perf output data in the current
-directory for later inspection like::
-
- perf-asm_pure_loop-out.data
- perf-memcpy_thread-16k_10.data
- ...
-
-You can alter where the perf data files are stored by setting the
-PERF_TEST_CORESIGHT_DATADIR environment variable such as::
-
- PERF_TEST_CORESIGHT_DATADIR=/var/tmp
- perf test
-
-You may wish to set these above environment variables if you wish to
-keep the output of tests outside of the current working directory for
-longer term storage and examination.
+There are a set of Perf tests for CoreSight which can be run with::
+
+ sudo perf test coresight
diff --git a/MAINTAINERS b/MAINTAINERS
index b539be153f6a..7efb893edcbb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2751,7 +2751,6 @@ F: tools/perf/arch/arm/util/cs-etm.h
F: tools/perf/arch/arm/util/pmu.c
F: tools/perf/tests/shell/*coresight*
F: tools/perf/tests/shell/coresight/*
-F: tools/perf/tests/shell/lib/*coresight*
F: tools/perf/util/cs-etm-decoder/*
F: tools/perf/util/cs-etm.*
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index ab661a1d271c..f29c267bf842 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -508,16 +508,7 @@ arm64-sysreg-defs-clean:
$(Q)$(MAKE) -C $(arm64_gen_sysreg_dir) O=$(arm64_gen_sysreg_outdir) \
prefix= subdir= clean > /dev/null
-TESTS_CORESIGHT_DIR := $(srctree)/tools/perf/tests/shell/coresight
-
-tests-coresight-targets: FORCE
- $(Q)$(MAKE) -C $(TESTS_CORESIGHT_DIR)
-
-tests-coresight-targets-clean:
- $(call QUIET_CLEAN, coresight)
- $(Q)$(MAKE) -C $(TESTS_CORESIGHT_DIR) O=$(OUTPUT) clean >/dev/null
-
-all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS) tests-coresight-targets
+all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS)
# Create python binding output directory if not already present
$(shell [ -d '$(OUTPUT)python' ] || mkdir -p '$(OUTPUT)python')
@@ -896,7 +887,6 @@ install-tests: all install-gtk
$(INSTALL) tests/shell/base_report/*.txt '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/base_report'; \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/coresight' ; \
$(INSTALL) tests/shell/coresight/*.sh '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/shell/coresight'
- $(Q)$(MAKE) -C tests/shell/coresight install-tests
install-bin: install-tools install-tests
@@ -939,7 +929,7 @@ endif
clean:: $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean $(LIBSYMBOL)-clean $(LIBPERF)-clean \
arm64-sysreg-defs-clean fixdep-clean python-clean bpf-skel-clean \
- tests-coresight-targets-clean pmu-events-clean
+ pmu-events-clean
$(call QUIET_CLEAN, core-objs) $(RM) $(LIBPERF_A) $(OUTPUT)perf-archive \
$(OUTPUT)perf-iostat $(LANG_BINDINGS)
$(Q)find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '*.a' -delete -o \
diff --git a/tools/perf/tests/shell/coresight/Makefile b/tools/perf/tests/shell/coresight/Makefile
deleted file mode 100644
index fa08fd9a5991..000000000000
--- a/tools/perf/tests/shell/coresight/Makefile
+++ /dev/null
@@ -1,29 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-# Carsten Haitzler <carsten.haitzler@arm.com>, 2021
-include ../../../../../tools/scripts/Makefile.include
-include ../../../../../tools/scripts/Makefile.arch
-include ../../../../../tools/scripts/utilities.mak
-
-SUBDIRS = \
- asm_pure_loop \
- memcpy_thread \
- thread_loop \
- unroll_loop_thread
-
-all: $(SUBDIRS)
-$(SUBDIRS):
- @$(MAKE) -C $@ >/dev/null
-
-INSTALLDIRS = $(SUBDIRS:%=install-%)
-
-install-tests: $(INSTALLDIRS)
-$(INSTALLDIRS):
- @$(MAKE) -C $(@:install-%=%) install-tests >/dev/null
-
-CLEANDIRS = $(SUBDIRS:%=clean-%)
-
-clean: $(CLEANDIRS)
-$(CLEANDIRS):
- $(call QUIET_CLEAN, test-$(@:clean-%=%)) $(MAKE) -C $(@:clean-%=%) clean >/dev/null
-
-.PHONY: all clean $(SUBDIRS) $(CLEANDIRS) $(INSTALLDIRS)
diff --git a/tools/perf/tests/shell/coresight/Makefile.miniconfig b/tools/perf/tests/shell/coresight/Makefile.miniconfig
deleted file mode 100644
index 5f72a9cb43f3..000000000000
--- a/tools/perf/tests/shell/coresight/Makefile.miniconfig
+++ /dev/null
@@ -1,14 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-# Carsten Haitzler <carsten.haitzler@arm.com>, 2021
-
-ifndef DESTDIR
-prefix ?= $(HOME)
-endif
-
-DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
-INSTALL = install
-INSTDIR_SUB = tests/shell/coresight
-
-include ../../../../../scripts/Makefile.include
-include ../../../../../scripts/Makefile.arch
-include ../../../../../scripts/utilities.mak
diff --git a/tools/perf/tests/shell/coresight/asm_pure_loop/.gitignore b/tools/perf/tests/shell/coresight/asm_pure_loop/.gitignore
deleted file mode 100644
index 468673ac32e8..000000000000
--- a/tools/perf/tests/shell/coresight/asm_pure_loop/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-asm_pure_loop
diff --git a/tools/perf/tests/shell/coresight/asm_pure_loop/Makefile b/tools/perf/tests/shell/coresight/asm_pure_loop/Makefile
deleted file mode 100644
index 206849e92bc9..000000000000
--- a/tools/perf/tests/shell/coresight/asm_pure_loop/Makefile
+++ /dev/null
@@ -1,34 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# Carsten Haitzler <carsten.haitzler@arm.com>, 2021
-
-include ../Makefile.miniconfig
-
-# Binary to produce
-BIN=asm_pure_loop
-# Any linking/libraries needed for the binary - empty if none needed
-LIB=
-
-all: $(BIN)
-
-$(BIN): $(BIN).S
-ifdef CORESIGHT
-ifeq ($(ARCH),arm64)
-# Build line - this is raw asm with no libc to have an always exact binary
- $(Q)$(CC) $(BIN).S -nostdlib -static -o $(BIN) $(LIB)
-endif
-endif
-
-install-tests: all
-ifdef CORESIGHT
-ifeq ($(ARCH),arm64)
-# Install the test tool in the right place
- $(call QUIET_INSTALL, tests) \
- $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$(INSTDIR_SUB)/$(BIN)'; \
- $(INSTALL) $(BIN) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$(INSTDIR_SUB)/$(BIN)/$(BIN)'
-endif
-endif
-
-clean:
- $(Q)$(RM) -f $(BIN)
-
-.PHONY: all clean install-tests
diff --git a/tools/perf/tests/shell/coresight/asm_pure_loop/asm_pure_loop.S b/tools/perf/tests/shell/coresight/asm_pure_loop/asm_pure_loop.S
deleted file mode 100644
index 577760046772..000000000000
--- a/tools/perf/tests/shell/coresight/asm_pure_loop/asm_pure_loop.S
+++ /dev/null
@@ -1,30 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Tamas Zsoldos <tamas.zsoldos@arm.com>, 2021 */
-
-.globl _start
-_start:
- mov x0, 0x0000ffff
- mov x1, xzr
-loop:
- nop
- nop
- cbnz x1, noskip
- nop
- nop
- adrp x2, skip
- add x2, x2, :lo12:skip
- br x2
- nop
- nop
-noskip:
- nop
- nop
-skip:
- sub x0, x0, 1
- cbnz x0, loop
-
- mov x0, #0
- mov x8, #93 // __NR_exit syscall
- svc #0
-
-.section .note.GNU-stack, "", @progbits
diff --git a/tools/perf/tests/shell/coresight/memcpy_thread/.gitignore b/tools/perf/tests/shell/coresight/memcpy_thread/.gitignore
deleted file mode 100644
index f8217e56091e..000000000000
--- a/tools/perf/tests/shell/coresight/memcpy_thread/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-memcpy_thread
diff --git a/tools/perf/tests/shell/coresight/memcpy_thread/Makefile b/tools/perf/tests/shell/coresight/memcpy_thread/Makefile
deleted file mode 100644
index 2db637eb2c26..000000000000
--- a/tools/perf/tests/shell/coresight/memcpy_thread/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# Carsten Haitzler <carsten.haitzler@arm.com>, 2021
-include ../Makefile.miniconfig
-
-# Binary to produce
-BIN=memcpy_thread
-# Any linking/libraries needed for the binary - empty if none needed
-LIB=-pthread
-
-all: $(BIN)
-
-$(BIN): $(BIN).c
-ifdef CORESIGHT
-ifeq ($(ARCH),arm64)
-# Build line
- $(Q)$(CC) $(BIN).c -o $(BIN) $(LIB)
-endif
-endif
-
-install-tests: all
-ifdef CORESIGHT
-ifeq ($(ARCH),arm64)
-# Install the test tool in the right place
- $(call QUIET_INSTALL, tests) \
- $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$(INSTDIR_SUB)/$(BIN)'; \
- $(INSTALL) $(BIN) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$(INSTDIR_SUB)/$(BIN)/$(BIN)'
-endif
-endif
-
-clean:
- $(Q)$(RM) -f $(BIN)
-
-.PHONY: all clean install-tests
diff --git a/tools/perf/tests/shell/coresight/memcpy_thread/memcpy_thread.c b/tools/perf/tests/shell/coresight/memcpy_thread/memcpy_thread.c
deleted file mode 100644
index 7e879217be30..000000000000
--- a/tools/perf/tests/shell/coresight/memcpy_thread/memcpy_thread.c
+++ /dev/null
@@ -1,80 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Carsten Haitzler <carsten.haitzler@arm.com>, 2021
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <pthread.h>
-
-struct args {
- unsigned long loops;
- unsigned long size;
- pthread_t th;
- void *ret;
-};
-
-static void *thrfn(void *arg)
-{
- struct args *a = arg;
- unsigned long i, len = a->loops;
- unsigned char *src, *dst;
-
- src = malloc(a->size * 1024);
- dst = malloc(a->size * 1024);
- if ((!src) || (!dst)) {
- printf("ERR: Can't allocate memory\n");
- exit(1);
- }
- for (i = 0; i < len; i++)
- memcpy(dst, src, a->size * 1024);
-
- return NULL;
-}
-
-static pthread_t new_thr(void *(*fn) (void *arg), void *arg)
-{
- pthread_t t;
- pthread_attr_t attr;
-
- pthread_attr_init(&attr);
- pthread_create(&t, &attr, fn, arg);
- return t;
-}
-
-int main(int argc, char **argv)
-{
- unsigned long i, len, size, thr;
- struct args args[256];
- long long v;
-
- if (argc < 4) {
- printf("ERR: %s [copysize Kb] [numthreads] [numloops (hundreds)]\n", argv[0]);
- exit(1);
- }
-
- v = atoll(argv[1]);
- if ((v < 1) || (v > (1024 * 1024))) {
- printf("ERR: max memory 1GB (1048576 KB)\n");
- exit(1);
- }
- size = v;
- thr = atol(argv[2]);
- if ((thr < 1) || (thr > 256)) {
- printf("ERR: threads 1-256\n");
- exit(1);
- }
- v = atoll(argv[3]);
- if ((v < 1) || (v > 40000000000ll)) {
- printf("ERR: loops 1-40000000000 (hundreds)\n");
- exit(1);
- }
- len = v * 100;
- for (i = 0; i < thr; i++) {
- args[i].loops = len;
- args[i].size = size;
- args[i].th = new_thr(thrfn, &(args[i]));
- }
- for (i = 0; i < thr; i++)
- pthread_join(args[i].th, &(args[i].ret));
- return 0;
-}
diff --git a/tools/perf/tests/shell/coresight/thread_loop/.gitignore b/tools/perf/tests/shell/coresight/thread_loop/.gitignore
deleted file mode 100644
index 6d4c33eaa9e8..000000000000
--- a/tools/perf/tests/shell/coresight/thread_loop/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-thread_loop
diff --git a/tools/perf/tests/shell/coresight/thread_loop/Makefile b/tools/perf/tests/shell/coresight/thread_loop/Makefile
deleted file mode 100644
index ea846c038e7a..000000000000
--- a/tools/perf/tests/shell/coresight/thread_loop/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# Carsten Haitzler <carsten.haitzler@arm.com>, 2021
-include ../Makefile.miniconfig
-
-# Binary to produce
-BIN=thread_loop
-# Any linking/libraries needed for the binary - empty if none needed
-LIB=-pthread
-
-all: $(BIN)
-
-$(BIN): $(BIN).c
-ifdef CORESIGHT
-ifeq ($(ARCH),arm64)
-# Build line
- $(Q)$(CC) $(BIN).c -o $(BIN) $(LIB)
-endif
-endif
-
-install-tests: all
-ifdef CORESIGHT
-ifeq ($(ARCH),arm64)
-# Install the test tool in the right place
- $(call QUIET_INSTALL, tests) \
- $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$(INSTDIR_SUB)/$(BIN)'; \
- $(INSTALL) $(BIN) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$(INSTDIR_SUB)/$(BIN)/$(BIN)'
-endif
-endif
-
-clean:
- $(Q)$(RM) -f $(BIN)
-
-.PHONY: all clean install-tests
diff --git a/tools/perf/tests/shell/coresight/thread_loop/thread_loop.c b/tools/perf/tests/shell/coresight/thread_loop/thread_loop.c
deleted file mode 100644
index 86f3f548b006..000000000000
--- a/tools/perf/tests/shell/coresight/thread_loop/thread_loop.c
+++ /dev/null
@@ -1,85 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Carsten Haitzler <carsten.haitzler@arm.com>, 2021
-
-// define this for gettid()
-#define _GNU_SOURCE
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <pthread.h>
-#include <sys/syscall.h>
-#ifndef SYS_gettid
-// gettid is 178 on arm64
-# define SYS_gettid 178
-#endif
-#define gettid() syscall(SYS_gettid)
-
-struct args {
- unsigned int loops;
- pthread_t th;
- void *ret;
-};
-
-static void *thrfn(void *arg)
-{
- struct args *a = arg;
- int i = 0, len = a->loops;
-
- if (getenv("SHOW_TID")) {
- unsigned long long tid = gettid();
-
- printf("%llu\n", tid);
- }
- asm volatile(
- "loop:\n"
- "add %w[i], %w[i], #1\n"
- "cmp %w[i], %w[len]\n"
- "blt loop\n"
- : /* out */
- : /* in */ [i] "r" (i), [len] "r" (len)
- : /* clobber */
- );
- return (void *)(long)i;
-}
-
-static pthread_t new_thr(void *(*fn) (void *arg), void *arg)
-{
- pthread_t t;
- pthread_attr_t attr;
-
- pthread_attr_init(&attr);
- pthread_create(&t, &attr, fn, arg);
- return t;
-}
-
-int main(int argc, char **argv)
-{
- unsigned int i, len, thr;
- struct args args[256];
-
- if (argc < 3) {
- printf("ERR: %s [numthreads] [numloops (millions)]\n", argv[0]);
- exit(1);
- }
-
- thr = atoi(argv[1]);
- if ((thr < 1) || (thr > 256)) {
- printf("ERR: threads 1-256\n");
- exit(1);
- }
- len = atoi(argv[2]);
- if ((len < 1) || (len > 4000)) {
- printf("ERR: max loops 4000 (millions)\n");
- exit(1);
- }
- len *= 1000000;
- for (i = 0; i < thr; i++) {
- args[i].loops = len;
- args[i].th = new_thr(thrfn, &(args[i]));
- }
- for (i = 0; i < thr; i++)
- pthread_join(args[i].th, &(args[i].ret));
- return 0;
-}
diff --git a/tools/perf/tests/shell/coresight/unroll_loop_thread/.gitignore b/tools/perf/tests/shell/coresight/unroll_loop_thread/.gitignore
deleted file mode 100644
index 2cb4e996dbf3..000000000000
--- a/tools/perf/tests/shell/coresight/unroll_loop_thread/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-unroll_loop_thread
diff --git a/tools/perf/tests/shell/coresight/unroll_loop_thread/Makefile b/tools/perf/tests/shell/coresight/unroll_loop_thread/Makefile
deleted file mode 100644
index 6264c4e3abd1..000000000000
--- a/tools/perf/tests/shell/coresight/unroll_loop_thread/Makefile
+++ /dev/null
@@ -1,33 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# Carsten Haitzler <carsten.haitzler@arm.com>, 2021
-include ../Makefile.miniconfig
-
-# Binary to produce
-BIN=unroll_loop_thread
-# Any linking/libraries needed for the binary - empty if none needed
-LIB=-pthread
-
-all: $(BIN)
-
-$(BIN): $(BIN).c
-ifdef CORESIGHT
-ifeq ($(ARCH),arm64)
-# Build line
- $(Q)$(CC) $(BIN).c -o $(BIN) $(LIB)
-endif
-endif
-
-install-tests: all
-ifdef CORESIGHT
-ifeq ($(ARCH),arm64)
-# Install the test tool in the right place
- $(call QUIET_INSTALL, tests) \
- $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$(INSTDIR_SUB)/$(BIN)'; \
- $(INSTALL) $(BIN) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$(INSTDIR_SUB)/$(BIN)/$(BIN)'
-endif
-endif
-
-clean:
- $(Q)$(RM) -f $(BIN)
-
-.PHONY: all clean install-tests
diff --git a/tools/perf/tests/shell/coresight/unroll_loop_thread/unroll_loop_thread.c b/tools/perf/tests/shell/coresight/unroll_loop_thread/unroll_loop_thread.c
deleted file mode 100644
index 8f4e1c985ca3..000000000000
--- a/tools/perf/tests/shell/coresight/unroll_loop_thread/unroll_loop_thread.c
+++ /dev/null
@@ -1,75 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-// Carsten Haitzler <carsten.haitzler@arm.com>, 2021
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <pthread.h>
-
-struct args {
- pthread_t th;
- unsigned int in;
- void *ret;
-};
-
-static void *thrfn(void *arg)
-{
- struct args *a = arg;
- unsigned int i, in = a->in;
-
- for (i = 0; i < 10000; i++) {
- asm volatile (
-// force an unroll of thia add instruction so we can test long runs of code
-#define SNIP1 "add %w[in], %w[in], #1\n"
-// 10
-#define SNIP2 SNIP1 SNIP1 SNIP1 SNIP1 SNIP1 SNIP1 SNIP1 SNIP1 SNIP1 SNIP1
-// 100
-#define SNIP3 SNIP2 SNIP2 SNIP2 SNIP2 SNIP2 SNIP2 SNIP2 SNIP2 SNIP2 SNIP2
-// 1000
-#define SNIP4 SNIP3 SNIP3 SNIP3 SNIP3 SNIP3 SNIP3 SNIP3 SNIP3 SNIP3 SNIP3
-// 10000
-#define SNIP5 SNIP4 SNIP4 SNIP4 SNIP4 SNIP4 SNIP4 SNIP4 SNIP4 SNIP4 SNIP4
-// 100000
- SNIP5 SNIP5 SNIP5 SNIP5 SNIP5 SNIP5 SNIP5 SNIP5 SNIP5 SNIP5
- : /* out */
- : /* in */ [in] "r" (in)
- : /* clobber */
- );
- }
-
- return NULL;
-}
-
-static pthread_t new_thr(void *(*fn) (void *arg), void *arg)
-{
- pthread_t t;
- pthread_attr_t attr;
-
- pthread_attr_init(&attr);
- pthread_create(&t, &attr, fn, arg);
- return t;
-}
-
-int main(int argc, char **argv)
-{
- unsigned int i, thr;
- struct args args[256];
-
- if (argc < 2) {
- printf("ERR: %s [numthreads]\n", argv[0]);
- exit(1);
- }
-
- thr = atoi(argv[1]);
- if ((thr > 256) || (thr < 1)) {
- printf("ERR: threads 1-256\n");
- exit(1);
- }
- for (i = 0; i < thr; i++) {
- args[i].in = rand();
- args[i].th = new_thr(thrfn, &(args[i]));
- }
- for (i = 0; i < thr; i++)
- pthread_join(args[i].th, &(args[i].ret));
- return 0;
-}
diff --git a/tools/perf/tests/shell/lib/coresight.sh b/tools/perf/tests/shell/lib/coresight.sh
deleted file mode 100644
index 184d62e7e5bd..000000000000
--- a/tools/perf/tests/shell/lib/coresight.sh
+++ /dev/null
@@ -1,134 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-# Carsten Haitzler <carsten.haitzler@arm.com>, 2021
-
-# This is sourced from a driver script so no need for #!/bin... etc. at the
-# top - the assumption below is that it runs as part of sourcing after the
-# test sets up some basic env vars to say what it is.
-
-# This currently works with ETMv4 / ETF not any other packet types at thi
-# point. This will need changes if that changes.
-
-# perf record options for the perf tests to use
-PERFRECMEM="-m ,16M"
-PERFRECOPT="$PERFRECMEM -e cs_etm//u"
-
-TOOLS=$(dirname $0)
-DIR="$TOOLS/$TEST"
-BIN="$DIR/$TEST"
-# If the test tool/binary does not exist and is executable then skip the test
-if ! test -x "$BIN"; then exit 2; fi
-# If CoreSight is not available, skip the test
-perf list pmu | grep -q cs_etm || exit 2
-DATD="."
-# If the data dir env is set then make the data dir use that instead of ./
-if test -n "$PERF_TEST_CORESIGHT_DATADIR"; then
- DATD="$PERF_TEST_CORESIGHT_DATADIR";
-fi
-# If the stat dir env is set then make the data dir use that instead of ./
-STATD="."
-if test -n "$PERF_TEST_CORESIGHT_STATDIR"; then
- STATD="$PERF_TEST_CORESIGHT_STATDIR";
-fi
-
-# Called if the test fails - error code 1
-err() {
- echo "$1"
- exit 1
-}
-
-# Check that some statistics from our perf
-check_val_min() {
- STATF="$4"
- if test "$2" -lt "$3"; then
- echo ", FAILED" >> "$STATF"
- err "Sanity check number of $1 is too low ($2 < $3)"
- fi
-}
-
-perf_dump_aux_verify() {
- # Some basic checking that the AUX chunk contains some sensible data
- # to see that we are recording something and at least a minimum
- # amount of it. We should almost always see Fn packets in just about
- # anything but certainly we will see some trace info and async
- # packets
- DUMP="$DATD/perf-tmp-aux-dump.txt"
- perf report --stdio --dump -i "$1" | \
- grep -o -e I_ATOM_F -e I_ASYNC -e I_TRACE_INFO > "$DUMP"
- # Simply count how many of these packets we find to see that we are
- # producing a reasonable amount of data - exact checks are not sane
- # as this is a lossy process where we may lose some blocks and the
- # compiler may produce different code depending on the compiler and
- # optimization options, so this is rough just to see if we're
- # either missing almost all the data or all of it
- ATOM_FX_NUM=$(grep -c I_ATOM_F "$DUMP")
- ASYNC_NUM=$(grep -c I_ASYNC "$DUMP")
- TRACE_INFO_NUM=$(grep -c I_TRACE_INFO "$DUMP")
- rm -f "$DUMP"
-
- # Arguments provide minimums for a pass
- CHECK_FX_MIN="$2"
- CHECK_ASYNC_MIN="$3"
- CHECK_TRACE_INFO_MIN="$4"
-
- # Write out statistics, so over time you can track results to see if
- # there is a pattern - for example we have less "noisy" results that
- # produce more consistent amounts of data each run, to see if over
- # time any techinques to minimize data loss are having an effect or
- # not
- STATF="$STATD/stats-$TEST-$DATV.csv"
- if ! test -f "$STATF"; then
- echo "ATOM Fx Count, Minimum, ASYNC Count, Minimum, TRACE INFO Count, Minimum" > "$STATF"
- fi
- echo -n "$ATOM_FX_NUM, $CHECK_FX_MIN, $ASYNC_NUM, $CHECK_ASYNC_MIN, $TRACE_INFO_NUM, $CHECK_TRACE_INFO_MIN" >> "$STATF"
-
- # Actually check to see if we passed or failed.
- check_val_min "ATOM_FX" "$ATOM_FX_NUM" "$CHECK_FX_MIN" "$STATF"
- check_val_min "ASYNC" "$ASYNC_NUM" "$CHECK_ASYNC_MIN" "$STATF"
- check_val_min "TRACE_INFO" "$TRACE_INFO_NUM" "$CHECK_TRACE_INFO_MIN" "$STATF"
- echo ", Ok" >> "$STATF"
-}
-
-perf_dump_aux_tid_verify() {
- # Specifically crafted test will produce a list of Tread ID's to
- # stdout that need to be checked to see that they have had trace
- # info collected in AUX blocks in the perf data. This will go
- # through all the TID's that are listed as CID=0xabcdef and see
- # that all the Thread IDs the test tool reports are in the perf
- # data AUX chunks
-
- # The TID test tools will print a TID per stdout line that are being
- # tested
- TIDS=$(cat "$2")
- # Scan the perf report to find the TIDs that are actually CID in hex
- # and build a list of the ones found
- FOUND_TIDS=$(perf report --stdio --dump -i "$1" | \
- grep -o "CID=0x[0-9a-z]\+" | sed 's/CID=//g' | \
- uniq | sort | uniq)
- # No CID=xxx found - maybe your kernel is reporting these as
- # VMID=xxx so look there
- if test -z "$FOUND_TIDS"; then
- FOUND_TIDS=$(perf report --stdio --dump -i "$1" | \
- grep -o "VMID=0x[0-9a-z]\+" | sed 's/VMID=//g' | \
- uniq | sort | uniq)
- fi
-
- # Iterate over the list of TIDs that the test says it has and find
- # them in the TIDs found in the perf report
- MISSING=""
- for TID2 in $TIDS; do
- FOUND=""
- for TIDHEX in $FOUND_TIDS; do
- TID=$(printf "%i" $TIDHEX)
- if test "$TID" -eq "$TID2"; then
- FOUND="y"
- break
- fi
- done
- if test -z "$FOUND"; then
- MISSING="$MISSING $TID"
- fi
- done
- if test -n "$MISSING"; then
- err "Thread IDs $MISSING not found in perf AUX data"
- fi
-}
--
2.34.1
^ permalink raw reply related
* [PATCH v4 16/19] perf test cs-etm: Make disassembly test use kcore
From: James Clark @ 2026-06-09 14:31 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v4-0-44f9fb9e5c42@linaro.org>
Hits in modules return empty disassembly with vmlinux as an input to
objdump. Make the disassembly test more reliable by always using kcore.
And update the comments to say that this is supported by the script.
Signed-off-by: James Clark <james.clark@linaro.org>
---
tools/perf/scripts/python/arm-cs-trace-disasm.py | 20 ++++++++++----------
tools/perf/tests/shell/test_arm_coresight_disasm.sh | 2 +-
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/tools/perf/scripts/python/arm-cs-trace-disasm.py b/tools/perf/scripts/python/arm-cs-trace-disasm.py
index ba208c90d631..8f6fa4a007b4 100755
--- a/tools/perf/scripts/python/arm-cs-trace-disasm.py
+++ b/tools/perf/scripts/python/arm-cs-trace-disasm.py
@@ -18,29 +18,29 @@ from perf_trace_context import perf_sample_srccode, perf_config_get
# Below are some example commands for using this script.
# Note a --kcore recording is required for accurate decode
-# due to the alternatives patching mechanism. However this
-# script only supports reading vmlinux for disassembly dump,
-# meaning that any patched instructions will appear
-# as unpatched, but the instruction ranges themselves will
-# be correct. In addition to this, source line info comes
-# from Perf, and when using kcore there is no debug info. The
-# following lists the supported features in each mode:
+# due to the alternatives patching mechanism. In addition to this,
+# source line info comes from Perf, and when using kcore there is
+# no debug info. The following lists the supported features in each mode:
#
# +-----------+-----------------+------------------+------------------+
# | Recording | Accurate decode | Source line dump | Disassembly dump |
# +-----------+-----------------+------------------+------------------+
# | --kcore | yes | no | yes |
-# | normal | no | yes | yes |
+# | normal | no | yes (inaccurate) | yes (inaccurate) |
# +-----------+-----------------+------------------+------------------+
#
# Output disassembly with objdump and auto detect vmlinux
-# (when running on same machine.)
+# (when running on same machine.):
# perf script -s scripts/python/arm-cs-trace-disasm.py -d
#
# Output disassembly with llvm-objdump:
# perf script -s scripts/python/arm-cs-trace-disasm.py \
# -- -d llvm-objdump-11 -k path/to/vmlinux
#
+# Output accurate disassembly by passing kcore to script:
+# perf script -s scripts/python/arm-cs-trace-disasm.py \
+# -- -d -k perf.data/kcore_dir/kcore
+#
# Output only source line and symbols:
# perf script -s scripts/python/arm-cs-trace-disasm.py
@@ -57,7 +57,7 @@ def int_arg(v):
args = argparse.ArgumentParser()
args.add_argument("-k", "--vmlinux",
- help="Set path to vmlinux file. Omit to autodetect if running on same machine")
+ help="Set path to vmlinux or kcore file. Omit to autodetect if running on same machine")
args.add_argument("-d", "--objdump", nargs="?", const=default_objdump(),
help="Show disassembly. Can also be used to change the objdump path"),
args.add_argument("-v", "--verbose", action="store_true", help="Enable debugging log")
diff --git a/tools/perf/tests/shell/test_arm_coresight_disasm.sh b/tools/perf/tests/shell/test_arm_coresight_disasm.sh
index 339ae4831868..87797d239f76 100755
--- a/tools/perf/tests/shell/test_arm_coresight_disasm.sh
+++ b/tools/perf/tests/shell/test_arm_coresight_disasm.sh
@@ -46,7 +46,7 @@ if [ "$(id -u)" == 0 ] && [ -e /proc/kcore ]; then
echo "Testing kernel disassembly"
perf record -o ${perfdata} -e cs_etm//k --kcore -- touch $file > /dev/null 2>&1
perf script -i ${perfdata} -s python:${script_path} -- \
- -d --stop-sample=30 2> /dev/null > ${file}
+ -d --stop-sample=30 -k ${perfdata}/kcore_dir/kcore 2> /dev/null > ${file}
grep -q -e ${branch_search} ${file}
echo "Found kernel branches"
else
--
2.34.1
^ permalink raw reply related
* [PATCH v4 17/19] perf test cs-etm: Add all branch instructions to test
From: James Clark @ 2026-06-09 14:31 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v4-0-44f9fb9e5c42@linaro.org>
If we reduce the number of samples searched to speed up the test, then
there will be less chance of hitting one of these branches. Extend the
regex to cover all branches so the test will always pass.
Reviewed-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: James Clark <james.clark@linaro.org>
---
tools/perf/tests/shell/test_arm_coresight_disasm.sh | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/tools/perf/tests/shell/test_arm_coresight_disasm.sh b/tools/perf/tests/shell/test_arm_coresight_disasm.sh
index 87797d239f76..f78dfb6bf73e 100755
--- a/tools/perf/tests/shell/test_arm_coresight_disasm.sh
+++ b/tools/perf/tests/shell/test_arm_coresight_disasm.sh
@@ -38,8 +38,7 @@ cleanup_files()
trap cleanup_files EXIT TERM INT
# Ranges start and end on branches, so check for some likely branch instructions
-sep="\s\|\s"
-branch_search="\sbl${sep}b${sep}b.ne${sep}b.eq${sep}cbz\s"
+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
@@ -47,7 +46,7 @@ if [ "$(id -u)" == 0 ] && [ -e /proc/kcore ]; then
perf record -o ${perfdata} -e cs_etm//k --kcore -- touch $file > /dev/null 2>&1
perf script -i ${perfdata} -s python:${script_path} -- \
-d --stop-sample=30 -k ${perfdata}/kcore_dir/kcore 2> /dev/null > ${file}
- grep -q -e ${branch_search} ${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
@@ -59,7 +58,7 @@ echo "Testing userspace disassembly"
perf record -o ${perfdata} -e cs_etm//u -- touch $file > /dev/null 2>&1
perf script -i ${perfdata} -s python:${script_path} -- \
-d --stop-sample=30 2> /dev/null > ${file}
-grep -q -e ${branch_search} ${file}
+grep -q -E ${branch_search} ${file}
echo "Found userspace branches"
glb_err=0
--
2.34.1
^ permalink raw reply related
* [PATCH v4 18/19] perf test cs-etm: Speed up disassembly test
From: James Clark @ 2026-06-09 14:31 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v4-0-44f9fb9e5c42@linaro.org>
We can use exit snapshot to limit the amount of trace to decode here
too. Also each call to objdump is quite expensive on kcore so limit it
to 2 samples instead of 30. We only want to see if there is no data at
all.
Reviewed-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: James Clark <james.clark@linaro.org>
---
tools/perf/tests/shell/test_arm_coresight_disasm.sh | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tools/perf/tests/shell/test_arm_coresight_disasm.sh b/tools/perf/tests/shell/test_arm_coresight_disasm.sh
index f78dfb6bf73e..f2fb1aa92252 100755
--- a/tools/perf/tests/shell/test_arm_coresight_disasm.sh
+++ b/tools/perf/tests/shell/test_arm_coresight_disasm.sh
@@ -43,9 +43,9 @@ branch_search='[[:space:]](bl|b(\.(eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le|al)
## Test kernel ##
if [ "$(id -u)" == 0 ] && [ -e /proc/kcore ]; then
echo "Testing kernel disassembly"
- perf record -o ${perfdata} -e cs_etm//k --kcore -- touch $file > /dev/null 2>&1
+ 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=30 -k ${perfdata}/kcore_dir/kcore 2> /dev/null > ${file}
+ -d --stop-sample=2 -k ${perfdata}/kcore_dir/kcore 2> /dev/null > ${file}
grep -q -E ${branch_search} ${file}
echo "Found kernel branches"
else
@@ -55,9 +55,9 @@ fi
## Test user ##
echo "Testing userspace disassembly"
-perf record -o ${perfdata} -e cs_etm//u -- touch $file > /dev/null 2>&1
+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=30 2> /dev/null > ${file}
+ -d --stop-sample=2 2> /dev/null > ${file}
grep -q -E ${branch_search} ${file}
echo "Found userspace branches"
--
2.34.1
^ permalink raw reply related
* [PATCH v4 19/19] perf test cs-etm: Move existing tests to coresight folder
From: James Clark @ 2026-06-09 14:31 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v4-0-44f9fb9e5c42@linaro.org>
There is a subfolder for Coresight tests so might as well keep them all
in here.
Reviewed-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: James Clark <james.clark@linaro.org>
---
MAINTAINERS | 1 -
tools/perf/tests/shell/{ => coresight}/test_arm_coresight.sh | 0
tools/perf/tests/shell/{ => coresight}/test_arm_coresight_disasm.sh | 2 +-
3 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 7efb893edcbb..ff8935b459ea 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2749,7 +2749,6 @@ F: tools/perf/arch/arm/util/auxtrace.c
F: tools/perf/arch/arm/util/cs-etm.c
F: tools/perf/arch/arm/util/cs-etm.h
F: tools/perf/arch/arm/util/pmu.c
-F: tools/perf/tests/shell/*coresight*
F: tools/perf/tests/shell/coresight/*
F: tools/perf/util/cs-etm-decoder/*
F: tools/perf/util/cs-etm.*
diff --git a/tools/perf/tests/shell/test_arm_coresight.sh b/tools/perf/tests/shell/coresight/test_arm_coresight.sh
similarity index 100%
rename from tools/perf/tests/shell/test_arm_coresight.sh
rename to tools/perf/tests/shell/coresight/test_arm_coresight.sh
diff --git a/tools/perf/tests/shell/test_arm_coresight_disasm.sh b/tools/perf/tests/shell/coresight/test_arm_coresight_disasm.sh
similarity index 96%
rename from tools/perf/tests/shell/test_arm_coresight_disasm.sh
rename to tools/perf/tests/shell/coresight/test_arm_coresight_disasm.sh
index f2fb1aa92252..ccb90dda2475 100755
--- a/tools/perf/tests/shell/test_arm_coresight_disasm.sh
+++ b/tools/perf/tests/shell/coresight/test_arm_coresight_disasm.sh
@@ -24,7 +24,7 @@ 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
+script_path=$(dirname "$0")/../../../scripts/python/arm-cs-trace-disasm.py
cleanup_files()
{
--
2.34.1
^ permalink raw reply related
* Re: [RFC v1 0/9] kho: granular compatibility and header decoupling
From: Pratyush Yadav @ 2026-06-09 14:33 UTC (permalink / raw)
To: Pasha Tatashin
Cc: Mike Rapoport, linux-kselftest, shuah, akpm, linux-mm, skhan,
linux-doc, jasonmiu, linux-kernel, corbet, ran.xiaokai, kexec,
pratyush, graf
In-Reply-To: <aidnjw5pH_z45gJT@plex>
On Tue, Jun 09 2026, Pasha Tatashin wrote:
> On 06-08 21:11, Mike Rapoport wrote:
>> On Mon, Jun 08, 2026 at 04:12:56PM +0000, Pasha Tatashin wrote:
>> > On 06-08 13:26, Mike Rapoport wrote:
>> > > On 2026-06-07 13:43:09+00:00, Pasha Tatashin wrote:
>> >
>> > Keeping all of that in a single KHO file is the wrong approach and goes
>> > against how other logically separated subsystems in Linux are organized
>> > (e.g., mm/vmap.c, mm/vmalloc.c, etc.). Yes, there are some messier
>> > places in the kernel as well, but keeping this in its own dedicated
>> > kho_vmalloc.c file makes complete sense to me.
>>
>> Either I hallucinated or b4 ate a paragraph from my reply ;)
>>
>> Regarding the code movement
>> - splitting radix tree makes perfect sense to me, just the documentation
>> part needs more care than mechanical move
+1, separating radix and KHO block makes sense.
>
> Agreed. I'll also pay closer attention to the documentation.
>
>> - I'm fine with abi/vmalloc.h, presuming KHOSER_PTR() is not part of it
>
> Yes, I will move KHOSER_PTR() to the shared compat.h in v2 so it's not
> tied to vmalloc.
>
>> - I can live with kho_vmalloc.c although I still consider it unnecessary
>> churn
>
> Appreciate it.
>
>> - I'm against moving vmalloc APIs from kexec_handover.h because they are
>> very close in nature to folio and pages. I don't see core KHO as
>> responsible for preserving physically contiguous ranges but rather as
>> preserving allocations. Not sure we'll ever support kmalloc(), but still.
FWIW, I agree with Mike here. I also see kho_preserve_vmalloc() as a
memory preservation primitive, same as kho_preserve_folio() or
kho_preserve_pages(). So I think it belongs in the main KHO header.
I also think it would also be nice to have vmalloc in kexec_handover.c,
but I can live with either way.
>
> That is a very reasonable compromise. I am fine with keeping the
> consumer-facing function declarations in kexec_handover.h so they remain
> grouped with folios and pages.
>
>> > However, overall enforcing the use of KHOSER is unrelated to this work.
>> > I have my own thoughts on this, and perhaps with proper versioning,
>> > using KHOSER_PTR everywhere would be appropriate, but let's keep that as
>> > a separate work.
>>
>> This is a separate work, indeed. But regardless of the versioning it's
>> already better than plain u64 because it provides type safety.
It would be even nicer to have some sort of type safety for KHO vmalloc.
On preservation and restore, you lose the the type of the array, and it
is very easy to make mistakes. I gave it a try some time ago but
unfortunately couldn't come up with anything good.
--
Regards,
Pratyush Yadav
^ permalink raw reply
* [PATCH v4 0/2] docs/mm/damon: fix docs and update zh_CN
From: Doehyun Baek @ 2026-06-09 14:34 UTC (permalink / raw)
To: Dongliang Mu
Cc: Jonathan Corbet, Shuah Khan, SeongJae Park, Alex Shi, Yanteng Si,
Hu Haowen, linux-doc, linux-kernel, damon, Doehyun Baek
In-Reply-To: <20260523094420.741003-1-doehyunbaek@gmail.com>
First of all, thank you very much, Dongliang, for your time and
dedication in reviewing the previous versions.
This v4 sends the original English DAMON documentation fixes as the
first patch, and the Simplified Chinese translation update as the
second patch.
For zh_CN, I translated the current DAMON usage.rst paragraph by
paragraph, and added missing pieces such as stat.rst and the related
index/design references. The zh_TW changes from earlier versions are
dropped from this series.
The translation text is paragraph-by-paragraph. Some references cannot
point to the exact zh_CN design sections because zh_CN design.rst is still
behind the English design document. I added selected translated design
sections/anchors needed by this series. If requested, I will also update
the Chinese design.rst further.
Changes from v3:
- Split English documentation fixes into the first patch.
- Reworked zh_CN usage.rst as a paragraph-by-paragraph translation of
the current English document.
- Added zh_CN stat.rst and related index/design references.
- Dropped the zh_TW translation patch from this series.
Tested with:
- make SPHINXDIRS='translations/zh_CN' htmldocs
Doehyun Baek (2):
docs/mm/damon: fix DAMON documentation details
docs/zh_CN: update DAMON documentation translation
Documentation/admin-guide/mm/damon/usage.rst | 12 +-
Documentation/mm/damon/design.rst | 12 +-
.../zh_CN/admin-guide/mm/damon/index.rst | 1 +
.../zh_CN/admin-guide/mm/damon/stat.rst | 80 +++
.../zh_CN/admin-guide/mm/damon/usage.rst | 541 ++++++++++++------
.../translations/zh_CN/mm/damon/design.rst | 145 ++++-
6 files changed, 615 insertions(+), 176 deletions(-)
create mode 100644 Documentation/translations/zh_CN/admin-guide/mm/damon/stat.rst
--
2.43.0
^ permalink raw reply
* [PATCH v4 1/2] docs/mm/damon: fix DAMON documentation details
From: Doehyun Baek @ 2026-06-09 14:34 UTC (permalink / raw)
To: Dongliang Mu
Cc: Jonathan Corbet, Shuah Khan, SeongJae Park, Alex Shi, Yanteng Si,
Hu Haowen, linux-doc, linux-kernel, damon, Doehyun Baek
In-Reply-To: <cover.1781015560.git.doehyunbaek@gmail.com>
Fix minor DAMON documentation issues. Correct the sysfs scheme file name
apply_interval_us, the scheme directory count, the DAMON_STAT module count,
a malformed reference, a misplaced label indentation, and a few typos.
Signed-off-by: Doehyun Baek <doehyunbaek@gmail.com>
---
Documentation/admin-guide/mm/damon/usage.rst | 12 ++++++------
Documentation/mm/damon/design.rst | 12 ++++++------
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst
index 534e1199cf09..e6ad1b4106ef 100644
--- a/Documentation/admin-guide/mm/damon/usage.rst
+++ b/Documentation/admin-guide/mm/damon/usage.rst
@@ -232,7 +232,7 @@ writing to and reading from the files.
Under ``nr_regions`` directory, two files for the lower-bound and upper-bound
of DAMON's monitoring regions (``min`` and ``max``, respectively), which
controls the monitoring overhead, exist. You can set and get the values by
-writing to and rading from the files.
+writing to and reading from the files.
For more details about the intervals and monitoring regions range, please refer
to the Design document (:doc:`/mm/damon/design`).
@@ -250,7 +250,7 @@ Please refer to the :ref:`design document of the feature
<damon_design_monitoring_intervals_autotuning>` for the internal of the tuning
mechanism. Reading and writing the four files under ``intervals_goal``
directory shows and updates the tuning parameters that described in the
-:ref:design doc <damon_design_monitoring_intervals_autotuning>` with the same
+:ref:`design doc <damon_design_monitoring_intervals_autotuning>` with the same
names. The tuning starts with the user-set ``sample_us`` and ``aggr_us``. The
tuning-applied current values of the two intervals can be read from the
``sample_us`` and ``aggr_us`` files after writing ``update_tuned_intervals`` to
@@ -337,10 +337,10 @@ to ``N-1``. Each directory represents each DAMON-based operation scheme.
schemes/<N>/
------------
-In each scheme directory, eight directories (``access_pattern``, ``quotas``,
+In each scheme directory, nine directories (``access_pattern``, ``quotas``,
``watermarks``, ``core_filters``, ``ops_filters``, ``filters``, ``dests``,
``stats``, and ``tried_regions``) and three files (``action``, ``target_nid``
-and ``apply_interval``) exist.
+and ``apply_interval_us``) exist.
The ``action`` file is for setting and getting the scheme's :ref:`action
<damon_design_damos_action>`. The keywords that can be written to and read
@@ -677,7 +677,7 @@ show results using tracepoint supporting tools like ``perf``. For example::
Each line of the perf script output represents each monitoring region. The
first five fields are as usual other tracepoint outputs. The sixth field
-(``target_id=X``) shows the ide of the monitoring target of the region. The
+(``target_id=X``) shows the id of the monitoring target of the region. The
seventh field (``nr_regions=X``) shows the total number of monitoring regions
for the target. The eighth field (``X-Y:``) shows the start (``X``) and end
(``Y``) addresses of the region in bytes. The ninth field (``X``) shows the
@@ -687,7 +687,7 @@ counter). Finally the tenth field (``X``) shows the ``age`` of the region
(refer to :ref:`design <damon_design_age_tracking>` for more details of the
counter).
-If the event was ``damon:damos_beofre_apply``, the ``perf script`` output would
+If the event was ``damon:damos_before_apply``, the ``perf script`` output would
be somewhat like below::
kdamond.0 47293 [000] 80801.060214: damon:damos_before_apply: ctx_idx=0 scheme_idx=0 target_idx=0 nr_regions=11 121932607488-135128711168: 0 136
diff --git a/Documentation/mm/damon/design.rst b/Documentation/mm/damon/design.rst
index afc7d52bda2f..aff89f73ca56 100644
--- a/Documentation/mm/damon/design.rst
+++ b/Documentation/mm/damon/design.rst
@@ -79,7 +79,7 @@ To know how user-space can do the configuration via :ref:`DAMON sysfs interface
documentation.
- .. _damon_design_vaddr_target_regions_construction:
+.. _damon_design_vaddr_target_regions_construction:
VMA-based Target Address Range Construction
-------------------------------------------
@@ -858,11 +858,11 @@ control parameters for the usage would also need to be optimized for the
purpose.
To support such cases, yet more DAMON API user kernel modules that provide more
-simple and optimized user space interfaces are available. Currently, two
-modules for proactive reclamation and LRU lists manipulation are provided. For
-more detail, please read the usage documents for those
-(:doc:`/admin-guide/mm/damon/stat`, :doc:`/admin-guide/mm/damon/reclaim` and
-:doc:`/admin-guide/mm/damon/lru_sort`).
+simple and optimized user space interfaces are available. Currently, three
+modules for access monitoring statistics, proactive reclamation, and LRU lists
+manipulation are provided. For more detail, please read the usage documents for
+those (:doc:`/admin-guide/mm/damon/stat`, :doc:`/admin-guide/mm/damon/reclaim`
+and :doc:`/admin-guide/mm/damon/lru_sort`).
.. _damon_design_special_purpose_modules_exclusivity:
--
2.43.0
^ permalink raw reply related
* [PATCH v4 2/2] docs/zh_CN: update DAMON documentation translation
From: Doehyun Baek @ 2026-06-09 14:34 UTC (permalink / raw)
To: Dongliang Mu
Cc: Jonathan Corbet, Shuah Khan, SeongJae Park, Alex Shi, Yanteng Si,
Hu Haowen, linux-doc, linux-kernel, damon, Doehyun Baek
In-Reply-To: <cover.1781015560.git.doehyunbaek@gmail.com>
Update the translation of .../admin-guide/mm/damon/usage.rst into Chinese.
Translate .../admin-guide/mm/damon/stat.rst into Chinese.
Update .../admin-guide/mm/damon/index.rst for the stat translation.
Translate selected .../mm/damon/design.rst sections into Chinese.
Update the translation through commit d9cfe515d36e
("Docs/admin-guide/mm/damon/usage: document goal_tuner sysfs file")
Signed-off-by: Doehyun Baek <doehyunbaek@gmail.com>
---
.../zh_CN/admin-guide/mm/damon/index.rst | 1 +
.../zh_CN/admin-guide/mm/damon/stat.rst | 80 +++
.../zh_CN/admin-guide/mm/damon/usage.rst | 541 ++++++++++++------
.../translations/zh_CN/mm/damon/design.rst | 145 ++++-
4 files changed, 603 insertions(+), 164 deletions(-)
create mode 100644 Documentation/translations/zh_CN/admin-guide/mm/damon/stat.rst
diff --git a/Documentation/translations/zh_CN/admin-guide/mm/damon/index.rst b/Documentation/translations/zh_CN/admin-guide/mm/damon/index.rst
index 6f8676a50b38..39e8bac2ce59 100644
--- a/Documentation/translations/zh_CN/admin-guide/mm/damon/index.rst
+++ b/Documentation/translations/zh_CN/admin-guide/mm/damon/index.rst
@@ -23,6 +23,7 @@
usage
reclaim
lru_sort
+ stat
diff --git a/Documentation/translations/zh_CN/admin-guide/mm/damon/stat.rst b/Documentation/translations/zh_CN/admin-guide/mm/damon/stat.rst
new file mode 100644
index 000000000000..8267fa2e5fd0
--- /dev/null
+++ b/Documentation/translations/zh_CN/admin-guide/mm/damon/stat.rst
@@ -0,0 +1,80 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. include:: ../../../disclaimer-zh_CN.rst
+
+:Original: Documentation/admin-guide/mm/damon/stat.rst
+
+:翻译:
+
+ Doehyun Baek <doehyunbaek@gmail.com>
+
+:校译:
+
+======================
+数据访问监测结果统计
+======================
+
+数据访问监测结果统计(DAMON_STAT)是一个静态内核模块,旨在用于简单的访问模式监测。它使用
+DAMON 监测系统整块物理内存上的访问,并提供简化的访问监测结果统计信息,即空闲时间百分位数和
+估计的内存带宽。
+
+.. _damon_stat_monitoring_accuracy_overhead_zh_CN:
+
+监测精度和开销
+==============
+
+DAMON_STAT 使用监测间隔 :ref:`自动调优 <damon_design_monitoring_intervals_autotuning_zh_CN>` 来提高
+精度并最小化开销。它会自动调优间隔,目标是在每个快照中捕获 4 % 的可观测访问事件,同时将所得
+采样间隔限制在最小 5 毫秒、最大 10 秒。在少数生产服务器系统上,它只消耗了 0.x % 的单 CPU
+时间,同时捕获了质量合理的访问模式。调优得到的间隔可以通过 ``aggr_interval_us`` :ref:`参数
+<damon_stat_aggr_interval_us_zh_CN>` 获取。
+
+接口:模块参数
+==============
+
+要使用这个功能,首先应确保你的系统运行在构建时启用了 ``CONFIG_DAMON_STAT=y`` 的内核上。通过
+将 ``CONFIG_DAMON_STAT_ENABLED_DEFAULT`` 设置为 true,可以在构建时默认启用该功能。
+
+为了让系统管理员在启动时和/或运行时启用或禁用它,并读取监测结果,DAMON_STAT 提供了模块参数。
+下面的章节描述各个参数。
+
+enabled
+-------
+
+启用或禁用 DAMON_STAT。
+
+你可以把该参数的值设置为 ``Y`` 来启用 DAMON_STAT。设置为 ``N`` 会禁用 DAMON_STAT。默认值由
+``CONFIG_DAMON_STAT_ENABLED_DEFAULT`` 构建配置选项设置。
+
+请注意,该模块(damon_stat)不能与其他基于 DAMON 的专用模块同时运行。更多细节请参考
+:ref:`DAMON 设计文档的专用模块互斥性 <damon_design_special_purpose_modules_exclusivity_zh_CN>`。
+
+.. _damon_stat_aggr_interval_us_zh_CN:
+
+aggr_interval_us
+----------------
+
+自动调优后的聚集时间间隔,单位是微秒。
+
+用户可以读取 DAMON_STAT 使用的 DAMON 实例的聚集间隔。该值会被 :ref:`自动调优
+<damon_stat_monitoring_accuracy_overhead_zh_CN>`,因此会动态变化。
+
+estimated_memory_bandwidth
+--------------------------
+
+系统的估计内存带宽消耗(字节/秒)。
+
+DAMON_STAT 读取当前 DAMON 结果快照上的观测访问事件,并将其转换为以字节/秒为单位的内存带宽
+消耗估计。该结果指标通过这个只读参数向用户公开。由于 DAMON 使用采样,所以这只是访问强度的估计,
+而不是精确的内存带宽。
+
+memory_idle_ms_percentiles
+--------------------------
+
+系统的逐字节空闲时间(毫秒)百分位数。
+
+DAMON_STAT 基于当前 DAMON 结果快照,计算内存中每个字节到当前为止未被访问的时间(空闲时间)。
+对于访问频率(nr_accesses)大于零的区域,当前访问频率级别保持了多久再乘以 ``-1``,就是该区域
+每个字节的空闲时间。如果某个区域的访问频率(nr_accesses)为零,则该区域保持零访问频率的时间
+(age)就是该区域每个字节的空闲时间。然后,DAMON_STAT 通过这个只读参数公开这些空闲时间值的
+百分位数。读取该参数会返回 101 个以毫秒为单位、用逗号分隔的空闲时间值。每个值分别表示第 0、
+第 1、第 2、第 3、……、第 99 和第 100 百分位的空闲时间。
diff --git a/Documentation/translations/zh_CN/admin-guide/mm/damon/usage.rst b/Documentation/translations/zh_CN/admin-guide/mm/damon/usage.rst
index 9d7cb51be493..cc7ec144c2e2 100644
--- a/Documentation/translations/zh_CN/admin-guide/mm/damon/usage.rst
+++ b/Documentation/translations/zh_CN/admin-guide/mm/damon/usage.rst
@@ -13,32 +13,37 @@
详细用法
========
-DAMON 为不同的用户提供了下面这些接口。
-
-- *DAMON用户空间工具。*
- `这 <https://github.com/damonitor/damo>`_ 为有这特权的人, 如系统管理员,希望有一个刚好
- 可以工作的人性化界面。
- 使用它,用户可以以人性化的方式使用DAMON的主要功能。不过,它可能不会为特殊情况进行高度调整。
- 它同时支持虚拟和物理地址空间的监测。更多细节,请参考它的 `使用文档
+DAMON 为不同的用户提供如下接口。
+
+- *专用 DAMON 模块。*
+ :ref:`这 <damon_modules_special_purpose_zh_CN>` 适用于构建、发布和/或管理带有专用 DAMON 用法内核
+ 的人员。使用该接口,用户可以在构建、启动或运行时,以简单的方式为给定目的使用 DAMON 的主要
+ 功能。
+- *DAMON 用户空间工具。*
+ `这 <https://github.com/damonitor/damo>`_ 适用于系统管理员等希望获得开箱即用、人性化界面的
+ 特权用户。使用该工具,用户可以以人性化的方式使用 DAMON 的主要功能。不过,它可能不会针对特殊
+ 场景进行高度调优。更多细节请参考它的 `使用文档
<https://github.com/damonitor/damo/blob/next/USAGE.md>`_。
-- *sysfs接口。*
- :ref:`这 <sysfs_interface>` 是为那些希望更高级的使用DAMON的特权用户空间程序员准备的。
- 使用它,用户可以通过读取和写入特殊的sysfs文件来使用DAMON的主要功能。因此,你可以编写和使
- 用你个性化的DAMON sysfs包装程序,代替你读/写sysfs文件。 `DAMON用户空间工具
- <https://github.com/damonitor/damo>`_ 就是这种程序的一个例子 它同时支持虚拟和物理地址
- 空间的监测。
+- *sysfs 接口。*
+ :ref:`这 <sysfs_interface_zh_CN>` 适用于希望更优化地使用 DAMON 的特权用户空间程序员。使用该
+ 接口,用户可以通过读取和写入特殊的 sysfs 文件来使用 DAMON 的主要功能。因此,你可以编写并使用
+ 个性化的 DAMON sysfs 包装程序,由它代替你读写 sysfs 文件。`DAMON 用户空间工具
+ <https://github.com/damonitor/damo>`_ 就是这类程序的一个例子。
- *内核空间编程接口。*
- :doc:`这 </mm/damon/api>` 这是为内核空间程序员准备的。使用它,用户可以通过为你编写内
- 核空间的DAMON应用程序,最灵活有效地利用DAMON的每一个功能。你甚至可以为各种地址空间扩展DAMON。
- 详细情况请参考接口 :doc:`文件 </mm/damon/api>`。
+ :doc:`这 </mm/damon/api>` 适用于内核空间程序员。使用该接口,用户可以通过为自己编写内核空间
+ DAMON 应用程序,以最灵活、最高效的方式利用 DAMON 的每一项功能。你甚至可以为各种地址空间扩展
+ DAMON。详细信息请参考接口 :doc:`文档 </mm/damon/api>`。
+
+.. _sysfs_interface_zh_CN:
+
+sysfs 接口
+==========
-sysfs接口
-=========
-DAMON的sysfs接口是在定义 ``CONFIG_DAMON_SYSFS`` 时建立的。它在其sysfs目录下创建多
-个目录和文件, ``<sysfs>/kernel/mm/damon/`` 。你可以通过对该目录下的文件进行写入和
-读取来控制DAMON。
+定义 ``CONFIG_DAMON_SYSFS`` 时会构建 DAMON sysfs 接口。它会在自己的 sysfs 目录
+``<sysfs>/kernel/mm/damon/`` 下创建多个目录和文件。你可以通过写入和读取该目录下的文件来控制
+DAMON。
-对于一个简短的例子,用户可以监测一个给定工作负载的虚拟地址空间,如下所示::
+作为一个简短示例,用户可以如下监测给定工作负载的虚拟地址空间。::
# cd /sys/kernel/mm/damon/admin/
# echo 1 > kdamonds/nr_kdamonds && echo 1 > kdamonds/0/contexts/nr_contexts
@@ -50,258 +55,441 @@ DAMON的sysfs接口是在定义 ``CONFIG_DAMON_SYSFS`` 时建立的。它在其s
文件层次结构
------------
-DAMON sysfs接口的文件层次结构如下图所示。在下图中,父子关系用缩进表示,每个目录有
-``/`` 后缀,每个目录中的文件用逗号(",")分开。 ::
+DAMON sysfs 接口的文件层次结构如下所示。在下图中,父子关系用缩进表示,每个目录都带有 ``/``
+后缀,每个目录中的文件用逗号(",")分隔。
- /sys/kernel/mm/damon/admin
- │ kdamonds/nr_kdamonds
- │ │ 0/state,pid
- │ │ │ contexts/nr_contexts
- │ │ │ │ 0/operations
- │ │ │ │ │ monitoring_attrs/
+.. parsed-literal::
+
+ :ref:`/sys/kernel/mm/damon <sysfs_root_zh_CN>`/admin
+ │ :ref:`kdamonds <sysfs_kdamonds_zh_CN>`/nr_kdamonds
+ │ │ :ref:`0 <sysfs_kdamond_zh_CN>`/state,pid,refresh_ms
+ │ │ │ :ref:`contexts <sysfs_contexts_zh_CN>`/nr_contexts
+ │ │ │ │ :ref:`0 <sysfs_context_zh_CN>`/avail_operations,operations,addr_unit
+ │ │ │ │ │ :ref:`monitoring_attrs <sysfs_monitoring_attrs_zh_CN>`/
│ │ │ │ │ │ intervals/sample_us,aggr_us,update_us
+ │ │ │ │ │ │ │ intervals_goal/access_bp,aggrs,min_sample_us,max_sample_us
│ │ │ │ │ │ nr_regions/min,max
- │ │ │ │ │ targets/nr_targets
- │ │ │ │ │ │ 0/pid_target
- │ │ │ │ │ │ │ regions/nr_regions
- │ │ │ │ │ │ │ │ 0/start,end
+ │ │ │ │ │ :ref:`targets <sysfs_targets_zh_CN>`/nr_targets
+ │ │ │ │ │ │ :ref:`0 <sysfs_target_zh_CN>`/pid_target,obsolete_target
+ │ │ │ │ │ │ │ :ref:`regions <sysfs_regions_zh_CN>`/nr_regions
+ │ │ │ │ │ │ │ │ :ref:`0 <sysfs_region_zh_CN>`/start,end
│ │ │ │ │ │ │ │ ...
│ │ │ │ │ │ ...
- │ │ │ │ │ schemes/nr_schemes
- │ │ │ │ │ │ 0/action
- │ │ │ │ │ │ │ access_pattern/
+ │ │ │ │ │ :ref:`schemes <sysfs_schemes_zh_CN>`/nr_schemes
+ │ │ │ │ │ │ :ref:`0 <sysfs_scheme_zh_CN>`/action,target_nid,apply_interval_us
+ │ │ │ │ │ │ │ :ref:`access_pattern <sysfs_access_pattern_zh_CN>`/
│ │ │ │ │ │ │ │ sz/min,max
│ │ │ │ │ │ │ │ nr_accesses/min,max
│ │ │ │ │ │ │ │ age/min,max
- │ │ │ │ │ │ │ quotas/ms,bytes,reset_interval_ms
+ │ │ │ │ │ │ │ :ref:`quotas <sysfs_quotas_zh_CN>`/ms,bytes,reset_interval_ms,effective_bytes,goal_tuner
│ │ │ │ │ │ │ │ weights/sz_permil,nr_accesses_permil,age_permil
- │ │ │ │ │ │ │ watermarks/metric,interval_us,high,mid,low
- │ │ │ │ │ │ │ stats/nr_tried,sz_tried,nr_applied,sz_applied,qt_exceeds
- │ │ │ │ │ │ │ tried_regions/
- │ │ │ │ │ │ │ │ 0/start,end,nr_accesses,age
+ │ │ │ │ │ │ │ │ :ref:`goals <sysfs_schemes_quota_goals_zh_CN>`/nr_goals
+ │ │ │ │ │ │ │ │ │ 0/target_metric,target_value,current_value,nid,path
+ │ │ │ │ │ │ │ :ref:`watermarks <sysfs_watermarks_zh_CN>`/metric,interval_us,high,mid,low
+ │ │ │ │ │ │ │ :ref:`{core_,ops_,}filters <sysfs_filters_zh_CN>`/nr_filters
+ │ │ │ │ │ │ │ │ 0/type,matching,allow,memcg_path,addr_start,addr_end,target_idx,min,max
+ │ │ │ │ │ │ │ :ref:`dests <damon_sysfs_dests_zh_CN>`/nr_dests
+ │ │ │ │ │ │ │ │ 0/id,weight
+ │ │ │ │ │ │ │ :ref:`stats <sysfs_schemes_stats_zh_CN>`/nr_tried,sz_tried,nr_applied,sz_applied,sz_ops_filter_passed,qt_exceeds,nr_snapshots,max_nr_snapshots
+ │ │ │ │ │ │ │ :ref:`tried_regions <sysfs_schemes_tried_regions_zh_CN>`/total_bytes
+ │ │ │ │ │ │ │ │ 0/start,end,nr_accesses,age,sz_filter_passed
│ │ │ │ │ │ │ │ ...
│ │ │ │ │ │ ...
│ │ │ │ ...
│ │ ...
+.. _sysfs_root_zh_CN:
+
根
--
-DAMON sysfs接口的根是 ``<sysfs>/kernel/mm/damon/`` ,它有一个名为 ``admin`` 的
-目录。该目录包含特权用户空间程序控制DAMON的文件。拥有根权限的用户空间工具或deamons可以
-使用这个目录。
+DAMON sysfs 接口的根是 ``<sysfs>/kernel/mm/damon/``,它有一个名为 ``admin`` 的目录。该目录
+包含供特权用户空间程序控制 DAMON 的文件。具有 root 权限的用户空间工具或守护进程可以使用该目录。
+
+.. _sysfs_kdamonds_zh_CN:
kdamonds/
---------
-与监测相关的信息包括请求规格和结果被称为DAMON上下文。DAMON用一个叫做kdamond的内核线程
-执行每个上下文,多个kdamonds可以并行运行。
+在 ``admin`` 目录下,存在一个名为 ``kdamonds`` 的目录,其中包含控制 kdamonds 的文件(更多细节
+请参考 :doc:`设计文档 </mm/damon/design>`)。开始时,该目录只有一个文件 ``nr_kdamonds``。向该
+文件写入一个数字(``N``)会创建 ``0`` 到 ``N-1`` 这些子目录。
+每个目录代表一个 kdamond。
-在 ``admin`` 目录下,有一个目录,即``kdamonds``,它有控制kdamonds的文件存在。在开始
-时,这个目录只有一个文件,``nr_kdamonds``。向该文件写入一个数字(``N``),就会创建名为
-``0`` 到 ``N-1`` 的子目录数量。每个目录代表每个kdamond。
+.. _sysfs_kdamond_zh_CN:
kdamonds/<N>/
-------------
-在每个kdamond目录中,存在两个文件(``state`` 和 ``pid`` )和一个目录( ``contexts`` )。
+每个 kdamond 目录中存在三个文件(``state``、``pid`` 和 ``refresh_ms``)以及一个目录
+(``contexts``)。
+
+读取 ``state`` 时,如果 kdamond 当前正在运行,则返回 ``on``,否则返回 ``off``。
+
+用户可以向 ``state`` 文件写入以下命令来控制 kdamond。
+
+- ``on``:开始运行。
+- ``off``:停止运行。
+- ``commit``:重新读取除 ``state`` 文件以外的 sysfs 文件中的用户输入。如果没有指定目标区域,
+ 监测 :ref:`目标区域 <sysfs_regions_zh_CN>` 输入也会被忽略。
+- ``update_tuned_intervals``:使用自动调优后的 ``采样间隔`` 和 ``聚集间隔`` 更新该 kdamond 的
+ ``sample_us`` 和 ``aggr_us`` 文件内容。更多细节请参考 :ref:`intervals_goal 小节
+ <damon_usage_sysfs_monitoring_intervals_goal_zh_CN>`。
+- ``commit_schemes_quota_goals``:读取基于 DAMON 的操作方案的 :ref:`配额目标
+ <sysfs_schemes_quota_goals_zh_CN>`。
+- ``update_schemes_stats``:更新该 kdamond 的每个基于 DAMON 的操作方案的统计文件内容。关于统计
+ 信息的细节,请参考 :ref:`stats 小节 <sysfs_schemes_stats_zh_CN>`。
+- ``update_schemes_tried_regions``:更新该 kdamond 的每个基于 DAMON 的操作方案的动作尝试区域目
+ 录。关于基于 DAMON 的操作方案动作尝试区域目录的细节,请参考 :ref:`tried_regions 小节
+ <sysfs_schemes_tried_regions_zh_CN>`。
+- ``update_schemes_tried_bytes``:只更新 ``.../tried_regions/total_bytes`` 文件。
+- ``clear_schemes_tried_regions``:清除该 kdamond 的每个基于 DAMON 的操作方案的动作尝试区域目
+ 录。
+- ``update_schemes_effective_quotas``:更新该 kdamond 的每个基于 DAMON 的操作方案的
+ ``effective_bytes`` 文件内容。更多细节请参考 :ref:`quotas 目录 <sysfs_quotas_zh_CN>`。
-读取 ``state`` 时,如果kdamond当前正在运行,则返回 ``on`` ,如果没有运行则返回 ``off`` 。
-写入 ``on`` 或 ``off`` 使kdamond处于状态。向 ``state`` 文件写 ``update_schemes_stats`` ,
-更新kdamond的每个基于DAMON的操作方案的统计文件的内容。关于统计信息的细节,请参考
-:ref:`stats section <sysfs_schemes_stats>`. 将 ``update_schemes_tried_regions`` 写到
-``state`` 文件,为kdamond的每个基于DAMON的操作方案,更新基于DAMON的操作方案动作的尝试区域目录。
-将`clear_schemes_tried_regions`写入`state`文件,清除kdamond的每个基于DAMON的操作方案的动作
-尝试区域目录。 关于基于DAMON的操作方案动作尝试区域目录的细节,请参考:ref:tried_regions 部分
-<sysfs_schemes_tried_regions>`。
+如果状态为 ``on``,读取 ``pid`` 会显示 kdamond 线程的 pid。
-如果状态为 ``on``,读取 ``pid`` 显示kdamond线程的pid。
+用户可以要求内核周期性地更新显示自动调优参数和 DAMOS 统计信息的文件,而不是手动向 ``state``
+文件写入 ``update_tuned_intervals`` 等关键字。为此,用户应向 ``refresh_ms`` 文件写入期望的更新
+时间间隔(毫秒)。如果间隔为零,则禁用周期性更新。读取该文件会显示当前设置的时间间隔。
-``contexts`` 目录包含控制这个kdamond要执行的监测上下文的文件。
+``contexts`` 目录包含用于控制该 kdamond 将执行的监测上下文的文件。
+
+.. _sysfs_contexts_zh_CN:
kdamonds/<N>/contexts/
----------------------
-在开始时,这个目录只有一个文件,即 ``nr_contexts`` 。向该文件写入一个数字( ``N`` ),就会创
-建名为``0`` 到 ``N-1`` 的子目录数量。每个目录代表每个监测背景。目前,每个kdamond只支持
-一个上下文,所以只有 ``0`` 或 ``1`` 可以被写入文件。
+开始时,该目录只有一个文件 ``nr_contexts``。向该文件写入一个数字(``N``)会创建名为 ``0`` 到
+``N-1`` 的子目录。每个目录代表一个监测上下文(更多细节请参考 :doc:`设计文档 </mm/damon/design>`)。
+目前,每个 kdamond 只支持一个上下文,因此只能向该文件写入 ``0`` 或 ``1``。
+
+.. _sysfs_context_zh_CN:
contexts/<N>/
-------------
-在每个上下文目录中,存在一个文件(``operations``)和三个目录(``monitoring_attrs``,
-``targets``, 和 ``schemes``)。
+每个上下文目录中存在三个文件(``avail_operations``、``operations`` 和 ``addr_unit``)以及三个
+目录(``monitoring_attrs``、``targets`` 和 ``schemes``)。
+
+DAMON 支持多种监测操作,包括用于虚拟地址空间和物理地址空间的操作。读取 ``avail_operations``
+文件可以获取当前运行内核中可用的监测操作集列表。根据内核配置,该文件会列出不同的可用操作集。
+所有可用操作集及其简要说明请参考 :doc:`设计文档 </mm/damon/design>`。
+
+你可以向 ``operations`` 文件写入 ``avail_operations`` 文件中列出的关键字之一,并从
+``operations`` 文件读取,来设置和获取 DAMON 将为该上下文使用哪种监测操作。
-DAMON支持多种类型的监测操作,包括对虚拟地址空间和物理地址空间的监测。你可以通过向文件
-中写入以下关键词之一,并从文件中读取,来设置和获取DAMON将为上下文使用何种类型的监测操作。
+``addr_unit`` 文件用于设置和获取操作集的地址单位参数。
- - vaddr: 监测特定进程的虚拟地址空间
- - paddr: 监视系统的物理地址空间
+.. _sysfs_monitoring_attrs_zh_CN:
contexts/<N>/monitoring_attrs/
------------------------------
-用于指定监测属性的文件,包括所需的监测质量和效率,都在 ``monitoring_attrs`` 目录中。
-具体来说,这个目录下有两个目录,即 ``intervals`` 和 ``nr_regions`` 。
+用于指定监测属性(包括所需监测质量和效率)的文件位于 ``monitoring_attrs`` 目录中。具体来说,
+该目录中存在两个目录:``intervals`` 和 ``nr_regions``。
+
+在 ``intervals`` 目录下,存在三个 DAMON 间隔文件:采样间隔(``sample_us``)、聚集间隔
+(``aggr_us``)和更新间隔(``update_us``)。你可以通过写入和读取这些文件来设置和获取以微秒为
+单位的值。
+
+在 ``nr_regions`` 目录下,存在两个用于 DAMON 监测区域下限和上限的文件(分别为 ``min`` 和
+``max``),它们控制监测开销。你可以通过写入和读取这些文件来设置和获取这些值。
+
+关于间隔和监测区域范围的更多细节,请参考设计文档(:doc:`/mm/damon/design`)。
+
+.. _damon_usage_sysfs_monitoring_intervals_goal_zh_CN:
-在 ``intervals`` 目录下,存在DAMON的采样间隔(``sample_us``)、聚集间隔(``aggr_us``)
-和更新间隔(``update_us``)三个文件。你可以通过写入和读出这些文件来设置和获取微秒级的值。
+contexts/<N>/monitoring_attrs/intervals/intervals_goal/
+-------------------------------------------------------
-在 ``nr_regions`` 目录下,有两个文件分别用于DAMON监测区域的下限和上限(``min`` 和 ``max`` ),
-这两个文件控制着监测的开销。你可以通过向这些文件的写入和读出来设置和获取这些值。
+在 ``intervals`` 目录下,还存在一个用于自动调优 ``sample_us`` 和 ``aggr_us`` 的目录,即
+``intervals_goal`` 目录。该目录下有四个用于自动调优控制的文件,即 ``access_bp``、``aggrs``、
+``min_sample_us`` 和 ``max_sample_us``。关于调优机制的内部细节,请参考该功能的 :ref:`设计文档
+<damon_design_monitoring_intervals_autotuning_zh_CN>`。读取和写入 ``intervals_goal`` 目录下的这四个
+文件,会显示和更新 :ref:`设计文档 <damon_design_monitoring_intervals_autotuning_zh_CN>` 中描述的同名
+调优参数。调优从用户设置的 ``sample_us`` 和 ``aggr_us`` 开始。向 ``state`` 文件写入
+``update_tuned_intervals`` 后,可以从 ``sample_us`` 和 ``aggr_us`` 文件读取应用调优后的两个当前
+间隔值。
-关于间隔和监测区域范围的更多细节,请参考设计文件 (:doc:`/mm/damon/design`)。
+.. _sysfs_targets_zh_CN:
contexts/<N>/targets/
---------------------
-在开始时,这个目录只有一个文件 ``nr_targets`` 。向该文件写入一个数字(``N``),就可以创建
-名为 ``0`` 到 ``N-1`` 的子目录的数量。每个目录代表每个监测目标。
+开始时,该目录只有一个文件 ``nr_targets``。向该文件写入一个数字(``N``)会创建名为 ``0`` 到
+``N-1`` 的子目录。每个目录代表一个监测目标。
+
+.. _sysfs_target_zh_CN:
targets/<N>/
------------
-在每个目标目录中,存在一个文件(``pid_target``)和一个目录(``regions``)。
+每个目标目录中存在两个文件(``pid_target`` 和 ``obsolete_target``)以及一个目录
+(``regions``)。
+
+如果你向 ``contexts/<N>/operations`` 写入了 ``vaddr``,则每个目标都应该是一个进程。你可以通过
+向 ``pid_target`` 文件写入进程 pid 来指定 DAMON 要监测的进程。
-如果你把 ``vaddr`` 写到 ``contexts/<N>/operations`` 中,每个目标应该是一个进程。你
-可以通过将进程的pid写到 ``pid_target`` 文件中来指定DAMON的进程。
+用户可以向 ``obsolete_target`` 文件写入非零值并提交它(向 ``state`` 文件写入 ``commit``),
+从目标数组中间选择性地删除目标。DAMON 会从它的内部目标数组中删除匹配的目标。用户负责重新构造
+目标目录,使它们正确表示改变后的内部目标数组。
+
+.. _sysfs_regions_zh_CN:
targets/<N>/regions
-------------------
-当使用 ``vaddr`` 监测操作集时( ``vaddr`` 被写入 ``contexts/<N>/operations`` 文
-件),DAMON自动设置和更新监测目标区域,这样就可以覆盖目标进程的整个内存映射。然而,用户可
-能希望将初始监测区域设置为特定的地址范围。
+对于 ``fvaddr`` 或 ``paddr`` 监测操作集,用户需要设置监测目标地址范围。对于 ``vaddr`` 操作集,
+这不是强制要求,但用户可以选择性地将初始监测区域设置为特定地址范围。更多细节请参考
+:ref:`设计文档 <damon_design_vaddr_target_regions_construction_zh_CN>`。
-相反,当使用 ``paddr`` 监测操作集时,DAMON不会自动设置和更新监测目标区域( ``paddr``
-被写入 ``contexts/<N>/operations`` 中)。因此,在这种情况下,用户应该自己设置监测目标
+在这些情况下,用户可以按照自己的意愿,通过向该目录下的文件写入适当的值来显式设置初始监测目标
区域。
-在这种情况下,用户可以按照自己的意愿明确设置初始监测目标区域,将适当的值写入该目录下的文件。
+开始时,该目录只有一个文件 ``nr_regions``。向该文件写入一个数字(``N``)会创建名为 ``0`` 到
+``N-1`` 的子目录。每个目录代表一个初始监测目标区域。
+
+在线提交新的 DAMON 参数时(向 :ref:`kdamond <sysfs_kdamond_zh_CN>` 的 ``state`` 文件写入
+``commit``),如果 ``nr_regions`` 为零,提交逻辑会忽略目标区域。换句话说,会保留该目标当前的
+监测结果。
-开始时,这个目录只有一个文件, ``nr_regions`` 。向该文件写入一个数字(``N``),就可以创
-建名为 ``0`` 到 ``N-1`` 的子目录。每个目录代表每个初始监测目标区域。
+.. _sysfs_region_zh_CN:
regions/<N>/
------------
-在每个区域目录中,你会发现两个文件( ``start`` 和 ``end`` )。你可以通过向文件写入
-和从文件中读出,分别设置和获得初始监测目标区域的起始和结束地址。
+在每个区域目录中,你会看到两个文件(``start`` 和 ``end``)。你可以通过写入和读取这些文件,分
+别设置和获取初始监测目标区域的起始地址和结束地址。
-每个区域不应该与其他区域重叠。 目录“N”的“结束”应等于或小于目录“N+1”的“开始”。
+各区域之间不应重叠。目录 ``N`` 的 ``end`` 应小于或等于目录 ``N+1`` 的 ``start``。
+
+.. _sysfs_schemes_zh_CN:
contexts/<N>/schemes/
---------------------
-对于一版的基于DAMON的数据访问感知的内存管理优化,用户通常希望系统对特定访问模式的内存区
-域应用内存管理操作。DAMON从用户那里接收这种形式化的操作方案,并将这些方案应用于目标内存
-区域。用户可以通过读取和写入这个目录下的文件来获得和设置这些方案。
+这是用于基于 DAMON 的操作方案(DAMON-based Operation Schemes,DAMOS)的目录。用户可以通过
+读取和写入该目录下的文件来获取和设置方案。更多背景请参考 :doc:`设计文档 </mm/damon/design>`。
+
+开始时,该目录只有一个文件 ``nr_schemes``。向该文件写入一个数字(``N``)会创建名为 ``0`` 到
+``N-1`` 的子目录。每个目录代表一个基于 DAMON 的操作方案。
-在开始时,这个目录只有一个文件,``nr_schemes``。向该文件写入一个数字(``N``),就可以
-创建名为``0``到``N-1``的子目录的数量。每个目录代表每个基于DAMON的操作方案。
+.. _sysfs_scheme_zh_CN:
schemes/<N>/
------------
-在每个方案目录中,存在五个目录(``access_pattern``、``quotas``、``watermarks``、
-``stats`` 和 ``tried_regions``)和一个文件(``action``)。
+每个方案目录中存在九个目录(``access_pattern``、``quotas``、``watermarks``、
+``core_filters``、``ops_filters``、``filters``、``dests``、``stats`` 和 ``tried_regions``)
+以及三个文件(``action``、``target_nid`` 和 ``apply_interval_us``)。
+
+``action`` 文件用于设置和获取方案的动作。可写入和读取该文件的关键字及其含义与 :doc:`设计文档
+</mm/damon/design>` 中的列表相同。
+
+``target_nid`` 文件用于设置迁移目标节点。只有当 ``action`` 为 ``migrate_hot`` 或
+``migrate_cold`` 时,该文件才有意义。
-``action`` 文件用于设置和获取你想应用于具有特定访问模式的内存区域的动作。可以写入文件
-和从文件中读取的关键词及其含义如下。
+``apply_interval_us`` 文件用于以微秒为单位设置和获取方案的 ``apply_interval``。
- - ``willneed``: 对有 ``MADV_WILLNEED`` 的区域调用 ``madvise()`` 。
- - ``cold``: 对具有 ``MADV_COLD`` 的区域调用 ``madvise()`` 。
- - ``pageout``: 为具有 ``MADV_PAGEOUT`` 的区域调用 ``madvise()`` 。
- - ``hugepage``: 为带有 ``MADV_HUGEPAGE`` 的区域调用 ``madvise()`` 。
- - ``nohugepage``: 为带有 ``MADV_NOHUGEPAGE`` 的区域调用 ``madvise()``。
- - ``lru_prio``: 在其LRU列表上对区域进行优先排序。
- - ``lru_deprio``: 对区域的LRU列表进行降低优先处理。
- - ``stat``: 什么都不做,只计算统计数据
+.. _sysfs_access_pattern_zh_CN:
schemes/<N>/access_pattern/
---------------------------
-每个基于DAMON的操作方案的目标访问模式由三个范围构成,包括以字节为单位的区域大小、每个
-聚合区间的监测访问次数和区域年龄的聚合区间数。
+该目录用于给定的基于 DAMON 的操作方案的目标访问模式。
-在 ``access_pattern`` 目录下,存在三个目录( ``sz``, ``nr_accesses``, 和 ``age`` ),
-每个目录有两个文件(``min`` 和 ``max`` )。你可以通过向 ``sz``, ``nr_accesses``, 和
-``age`` 目录下的 ``min`` 和 ``max`` 文件分别写入和读取来设置和获取给定方案的访问模式。
+在 ``access_pattern`` 目录下,存在三个目录(``sz``、``nr_accesses`` 和 ``age``),每个目录都有
+两个文件(``min`` 和 ``max``)。你可以分别向 ``sz``、``nr_accesses`` 和 ``age`` 目录下的
+``min`` 和 ``max`` 文件写入并读取,以设置和获取给定方案的访问模式。注意,``min`` 和 ``max`` 构
+成闭区间。
+
+.. _sysfs_quotas_zh_CN:
schemes/<N>/quotas/
-------------------
-每个 ``动作`` 的最佳 ``目标访问模式`` 取决于工作负载,所以不容易找到。更糟糕的是,将某些动作
-的方案设置得过于激进会造成严重的开销。为了避免这种开销,用户可以为每个方案限制时间和大小配额。
-具体来说,用户可以要求DAMON尽量只使用特定的时间(``时间配额``)来应用动作,并且在给定的时间间
-隔(``重置间隔``)内,只对具有目标访问模式的内存区域应用动作,而不使用特定数量(``大小配额``)。
+该目录用于给定的基于 DAMON 的操作方案的配额。
+
+在 ``quotas`` 目录下,存在五个文件(``ms``、``bytes``、``reset_interval_ms``、
+``effective_bytes`` 和 ``goal_tuner``)以及两个目录(``weights`` 和 ``goals``)。
+
+你可以分别向这三个文件写入数值,设置以毫秒为单位的 ``时间配额``、以字节为单位的 ``大小配额``
+以及以毫秒为单位的 ``重置间隔``。随后,DAMON 会尝试最多只使用 ``时间配额`` 毫秒,将 ``action``
+应用于符合 ``access_pattern`` 的内存区域,并且在 ``reset_interval_ms`` 内最多只对 ``bytes`` 字
+节的内存区域应用该动作。如果 ``ms`` 和 ``bytes`` 都设置为零,除非至少设置了一个 :ref:`目标
+<sysfs_schemes_quota_goals_zh_CN>`,否则会禁用配额限制。
+
+你可以通过向 ``goal_tuner`` 文件写入算法名称,设置要使用的基于目标的有效配额自动调优算法。读
+取该文件会返回当前选择的调优器算法。关于该功能的背景设计和可选算法名称,请参考
+:doc:`设计文档 </mm/damon/design>` 中的自动配额调优目标。关于目标设置,请参考 :ref:`goals 目录
+<sysfs_schemes_quota_goals_zh_CN>`。
+
+时间配额会在内部转换为大小配额。在转换后的大小配额和用户指定的大小配额之间,会应用较小者。基
+于用户指定的 :ref:`目标 <sysfs_schemes_quota_goals_zh_CN>`,有效大小配额会被进一步调整。读取
+``effective_bytes`` 会返回当前有效大小配额。该文件不会实时更新,因此用户应要求 DAMON sysfs 接
+口更新该文件内容:向相关的 ``kdamonds/<N>/state`` 文件写入特殊关键字
+``update_schemes_effective_quotas``。
+
+在 ``weights`` 目录下,存在三个文件(``sz_permil``、``nr_accesses_permil`` 和 ``age_permil``)。
+你可以通过向 ``weights`` 目录下的这三个文件写入数值,以千分之一为单位设置大小、访问频率和年龄
+的优先级权重。
+
+.. _sysfs_schemes_quota_goals_zh_CN:
+
+schemes/<N>/quotas/goals/
+-------------------------
-当预计超过配额限制时,DAMON会根据 ``目标访问模式`` 的大小、访问频率和年龄,对找到的内存区域
-进行优先排序。为了进行个性化的优先排序,用户可以为这三个属性设置权重。
+该目录用于给定的基于 DAMON 的操作方案的自动配额调优目标。
-在 ``quotas`` 目录下,存在三个文件(``ms``, ``bytes``, ``reset_interval_ms``)和一个
-目录(``weights``),其中有三个文件(``sz_permil``, ``nr_accesses_permil``, 和
-``age_permil``)。
+开始时,该目录只有一个文件 ``nr_goals``。向该文件写入一个数字(``N``)会创建名为 ``0`` 到
+``N-1`` 的子目录。每个目录代表一个目标及其当前达成情况。在多个反馈中,会使用最好的一个。
-你可以设置以毫秒为单位的 ``时间配额`` ,以字节为单位的 ``大小配额`` ,以及以毫秒为单位的 ``重
-置间隔`` ,分别向这三个文件写入数值。你还可以通过向 ``weights`` 目录下的三个文件写入数值来设
-置大小、访问频率和年龄的优先权,单位为千分之一。
+每个目标目录包含五个文件,即 ``target_metric``、``target_value``、``current_value``、``nid``
+和 ``path``。用户可以通过写入和读取这些文件,设置和获取 :doc:`设计文档 </mm/damon/design>` 中
+指定的配额自动调优目标的五个参数。注意,用户还应向 :ref:`kdamond 目录 <sysfs_kdamond_zh_CN>` 的
+``state`` 文件写入 ``commit_schemes_quota_goals``,
+以将反馈传递给 DAMON。
+
+.. _sysfs_watermarks_zh_CN:
schemes/<N>/watermarks/
-----------------------
-为了便于根据系统状态激活和停用每个方案,DAMON提供了一个称为水位的功能。该功能接收五个值,称为
-``度量`` 、``间隔`` 、``高`` 、``中`` 、``低`` 。``度量值`` 是指可以测量的系统度量值,如
-自由内存比率。如果系统的度量值 ``高`` 于memoent的高值或 ``低`` 于低值,则该方案被停用。如果
-该值低于 ``中`` ,则该方案被激活。
+该目录用于给定的基于 DAMON 的操作方案的水位。
-在水位目录下,存在五个文件(``metric``, ``interval_us``,``high``, ``mid``, and ``low``)
-用于设置每个值。你可以通过向这些文件的写入来分别设置和获取这五个值。
+在 ``watermarks`` 目录下,存在五个文件(``metric``、``interval_us``、``high``、``mid`` 和
+``low``),用于设置度量、检查该度量的时间间隔以及三个水位。你可以通过写入这些文件分别设置并获
+取这五个值。
-可以写入 ``metric`` 文件的关键词和含义如下。
+可写入 ``metric`` 文件的关键字及其含义如下。
- - none: 忽略水位
- - free_mem_rate: 系统的自由内存率(千分比)。
+ - none:忽略水位
+ - free_mem_rate:系统空闲内存率(千分比)
``interval`` 应以微秒为单位写入。
+.. _sysfs_filters_zh_CN:
+
+schemes/<N>/{core\_,ops\_,}filters/
+-----------------------------------
+
+这些目录用于给定的基于 DAMON 的操作方案的过滤器。
+
+``core_filters`` 和 ``ops_filters`` 目录分别用于由 DAMON 核心层和操作集层处理的过滤器。
+``filters`` 目录可用于安装不区分处理层的过滤器。通过 ``core_filters`` 和 ``ops_filters`` 请求
+的过滤器会在 ``filters`` 的过滤器之前安装。三个目录具有相同的文件。
+
+使用 ``filters`` 目录时,通过目录下文件预期给定过滤器的求值顺序可能会有些混乱。因此,建议用户
+使用 ``core_filters`` 和 ``ops_filters`` 目录。``filters`` 目录未来可能会被弃用。
+
+开始时,该目录只有一个文件 ``nr_filters``。向该文件写入一个数字(``N``)会创建名为 ``0`` 到
+``N-1`` 的子目录。每个目录代表一个过滤器。过滤器按数字顺序求值。
+
+每个过滤器目录包含九个文件,即 ``type``、``matching``、``allow``、``memcg_path``、
+``addr_start``、``addr_end``、``min``、``max`` 和 ``target_idx``。可以向 ``type`` 文件写入过滤
+器类型。可用类型名称、含义以及它们由哪一层处理,请参考 :doc:`设计文档 </mm/damon/design>`。
+
+对于 ``memcg`` 类型,可以通过向 ``memcg_path`` 文件写入从 cgroups 挂载点开始的内存 cgroup 路径
+来指定关注的内存 cgroup。对于 ``addr`` 类型,可以分别向 ``addr_start`` 和 ``addr_end`` 文件写入
+范围(开区间)的起始和结束地址。对于 ``hugepage_size`` 类型,可以分别向 ``min`` 和 ``max`` 文件
+写入范围(闭区间)的最小和最大大小。对于 ``target`` 类型,可以向 ``target_idx`` 文件写入 DAMON
+上下文监测目标列表中的目标索引。
+
+可以向 ``matching`` 文件写入 ``Y`` 或 ``N``,指定过滤器是否用于匹配 ``type`` 的内存。可以向
+``allow`` 文件写入 ``Y`` 或 ``N``,指定是否允许对满足 ``type`` 和 ``matching`` 的内存应用动作。
+
+下面的示例将一个 DAMOS 动作限制为只应用于所有内存 cgroup 中的非匿名页,但排除
+``/having_care_already``。::
+
+ # cd ops_filters/0/
+ # echo 2 > nr_filters
+ # # disallow anonymous pages
+ echo anon > 0/type
+ echo Y > 0/matching
+ echo N > 0/allow
+ # # further filter out all cgroups except one at '/having_care_already'
+ echo memcg > 1/type
+ echo /having_care_already > 1/memcg_path
+ echo Y > 1/matching
+ echo N > 1/allow
+
+更多细节,包括多个不同 ``allow`` 的过滤器如何工作、每个过滤器何时受支持以及统计信息差异,请参考
+:doc:`DAMOS 过滤器设计文档 </mm/damon/design>`。
+
+.. _damon_sysfs_dests_zh_CN:
+
+schemes/<N>/dests/
+------------------
+
+该目录用于指定给定的基于 DAMON 的操作方案动作的目标。如果给定方案的动作不支持多个目标,则忽略
+该目录。只有 ``DAMOS_MIGRATE_{HOT,COLD}`` 动作支持多个目标。
+
+开始时,该目录只有一个文件 ``nr_dests``。向该文件写入一个数字(``N``)会创建名为 ``0`` 到
+``N-1`` 的子目录。每个目录代表一个动作目标。
+
+每个目标目录包含两个文件,即 ``id`` 和 ``weight``。用户可以向 ``id`` 文件写入目标标识符,也可
+以从该文件读取目标标识符。对于 ``DAMOS_MIGRATE_{HOT,COLD}`` 动作,应向 ``id`` 文件写入迁移目
+标节点的节点 id。用户可以向 ``weight`` 文件写入和读取给定目标之间的目标权重。权重可以是任意整
+数。当 DAMOS 对内存区域中的每个实体应用动作时,它会基于这些目标的相对权重选择动作目标。
+
+.. _sysfs_schemes_stats_zh_CN:
+
schemes/<N>/stats/
------------------
-DAMON统计每个方案被尝试应用的区域的总数量和字节数,每个方案被成功应用的区域的两个数字,以及
-超过配额限制的总数量。这些统计数据可用于在线分析或调整方案。
+DAMON 会统计每个方案的信息。这些统计信息可用于方案的在线分析或调优。关于统计信息的更多细节,
+请参考 :doc:`设计文档 </mm/damon/design>`。
-可以通过读取 ``stats`` 目录下的文件(``nr_tried``, ``sz_tried``, ``nr_applied``,
-``sz_applied``, 和 ``qt_exceeds``))分别检索这些统计数据。这些文件不是实时更新的,所以
-你应该要求DAMON sysfs接口通过在相关的 ``kdamonds/<N>/state`` 文件中写入一个特殊的关键字
-``update_schemes_stats`` 来更新统计信息的文件内容。
+可以通过读取 ``stats`` 目录下的文件分别检索这些统计信息:``nr_tried``、``sz_tried``、
+``nr_applied``、``sz_applied``、``sz_ops_filter_passed``、``qt_exceeds``、``nr_snapshots`` 和
+``max_nr_snapshots``。
+
+这些文件默认不会实时更新。用户应要求 DAMON sysfs 接口使用 ``refresh_ms`` 周期性地更新这些文件,
+或者通过向相关的 ``kdamonds/<N>/state`` 文件写入特殊关键字 ``update_schemes_stats`` 来执行一次
+性更新。更多细节请参考 :ref:`kdamond 目录 <sysfs_kdamond_zh_CN>`。
+
+.. _sysfs_schemes_tried_regions_zh_CN:
schemes/<N>/tried_regions/
--------------------------
-当一个特殊的关键字 ``update_schemes_tried_regions`` 被写入相关的 ``kdamonds/<N>/state``
-文件时,DAMON会在这个目录下创建从 ``0`` 开始命名的整数目录。每个目录包含的文件暴露了关于每个
-内存区域的详细信息,在下一个 :ref:`聚集区间 <sysfs_monitoring_attrs>`,相应的方案的 ``动作``
-已经尝试在这个目录下应用。这些信息包括地址范围、``nr_accesses`` 以及区域的 ``年龄`` 。
+该目录开始时有一个文件 ``total_bytes``。
+
+当向相关的 ``kdamonds/<N>/state`` 文件写入特殊关键字 ``update_schemes_tried_regions`` 时,
+DAMON 会更新 ``total_bytes`` 文件,使读取该文件返回方案尝试区域的总大小,并在该目录下创建从
+``0`` 开始命名的整数目录。每个目录包含的文件会暴露对应方案的 ``action`` 在下一个对应方案的
+应用间隔中,已经尝试应用到的每个内存区域的详细信息。该信息包括区域的地址范围、``nr_accesses``
+和 ``age``。
+
+向相关的 ``kdamonds/<N>/state`` 文件写入 ``update_schemes_tried_bytes`` 只会更新
+``total_bytes`` 文件,而不会创建子目录。
-当另一个特殊的关键字 ``clear_schemes_tried_regions`` 被写入相关的 ``kdamonds/<N>/state``
-文件时,这些目录将被删除。
+当向相关的 ``kdamonds/<N>/state`` 文件写入另一个特殊关键字 ``clear_schemes_tried_regions`` 时,
+这些目录会被删除。
+
+该目录的预期用途是调查方案行为,以及像查询一样高效地检索数据访问监测结果。特别是对于后一种用
+例,用户可以将 ``action`` 设置为 ``stat``,并将 ``access pattern`` 设置为他们想查询的感兴趣模
+式。
+
+.. _sysfs_schemes_tried_region_zh_CN:
tried_regions/<N>/
------------------
-在每个区域目录中,你会发现四个文件(``start``, ``end``, ``nr_accesses``, and ``age``)。
-读取这些文件将显示相应的基于DAMON的操作方案 ``动作`` 试图应用的区域的开始和结束地址、``nr_accesses``
-和 ``年龄`` 。
+在每个区域目录中,你会看到五个文件(``start``、``end``、``nr_accesses``、``age`` 和
+``sz_filter_passed``)。读取这些文件会显示对应的基于 DAMON 的操作方案 ``action`` 已经尝试应用
+到的区域属性。
-用例
+示例
~~~~
-下面的命令应用了一个方案:”如果一个大小为[4KiB, 8KiB]的内存区域在[10, 20]的聚合时间间隔内
-显示出每一个聚合时间间隔[0, 5]的访问量,请分页该区域。对于分页,每秒最多只能使用10ms,而且每
-秒分页不能超过1GiB。在这一限制下,首先分页出具有较长年龄的内存区域。另外,每5秒钟检查一次系统
-的可用内存率,当可用内存率低于50%时开始监测和分页,但如果可用内存率大于60%,或低于30%,则停
-止监测。“ ::
+以下命令会应用一个方案,其含义是:“如果一个大小在 [4KiB, 8KiB] 之间的内存区域,在 [10, 20]
+个聚集间隔内,每个聚集间隔显示 [0, 5] 次访问,则换出该区域。对于换出操作,每秒最多只使用 10ms,
+并且每秒换出的内存不超过 1GiB。在这些限制下,优先换出年龄更长的内存区域。同时,每 5 秒检查一
+次系统空闲内存率;当空闲内存率低于 50% 时开始监测和换出,但如果空闲内存率高于 60% 或低于 30%,
+则停止。”::
# cd <sysfs>/kernel/mm/damon/admin
# # populate directories
@@ -327,19 +515,46 @@ tried_regions/<N>/
# echo 500 > watermarks/mid
# echo 300 > watermarks/low
-请注意,我们强烈建议使用用户空间的工具,如 `damo <https://github.com/damonitor/damo>`_ ,
-而不是像上面那样手动读写文件。以上只是一个例子。
+请注意,强烈建议使用像 `damo <https://github.com/damonitor/damo>`_ 这样的用户空间工具,而不是像
+上面那样手动读取和写入文件。上面的内容只是一个示例。
+.. _tracepoint_zh_CN:
监测结果的监测点
================
-DAMON通过一个tracepoint ``damon:damon_aggregated`` 提供监测结果. 当监测开启时,你可
-以记录追踪点事件,并使用追踪点支持工具如perf显示结果。比如说::
+用户可以通过 :ref:`tried_regions <sysfs_schemes_tried_regions_zh_CN>` 获取监测结果。该接口对获
+取快照很有用,但用于完整记录所有监测结果时可能效率较低。为此,DAMON 提供两个 tracepoint,即
+``damon:damon_aggregated`` 和 ``damon:damos_before_apply``。``damon:damon_aggregated`` 提供
+完整监测结果,而 ``damon:damos_before_apply`` 提供每个基于 DAMON 的操作方案(DAMOS)即将应用
+到的区域的监测结果。因此,``damon:damos_before_apply`` 更适合记录 DAMOS 的内部行为,或者基于
+DAMOS 目标访问模式进行类似查询的高效监测结果记录。
- # echo on > monitor_on_DEPRECATED
+监测开启时,你可以记录 tracepoint 事件,并使用支持 tracepoint 的工具(如 ``perf``)显示结果。
+例如::
+
+ # echo on > kdamonds/0/state
# perf record -e damon:damon_aggregated &
# sleep 5
# kill 9 $(pidof perf)
- # echo off > monitor_on_DEPRECATED
+ # echo off > kdamonds/0/state
# perf script
+ kdamond.0 46568 [027] 79357.842179: damon:damon_aggregated: target_id=0 nr_regions=11 122509119488-135708762112: 0 864
+ [...]
+
+perf 脚本输出中的每一行代表一个监测区域。前五个字段与通常的 tracepoint 输出相同。第六个字段
+(``target_id=X``)显示该区域所属监测目标的 id。第七个字段(``nr_regions=X``)显示该目标的监测
+区域总数。第八个字段(``X-Y:``)显示该区域以字节为单位的起始地址(``X``)和结束地址(``Y``)。
+第九个字段(``X``)显示该区域的 ``nr_accesses`` (关于该计数器的更多细节请参考 :ref:`设计文档
+<damon_design_region_based_sampling_zh_CN>`)。最后,第十个字段(``X``)显示该区域的 ``age`` (关于该
+计数器的更多细节请参考 :ref:`设计文档 <damon_design_age_tracking_zh_CN>`)。
+
+如果事件是 ``damon:damos_before_apply``,perf 脚本输出大致如下::
+
+ kdamond.0 47293 [000] 80801.060214: damon:damos_before_apply: ctx_idx=0 scheme_idx=0 target_idx=0 nr_regions=11 121932607488-135128711168: 0 136
+ [...]
+
+输出中的每一行代表在跟踪时刻每个基于 DAMON 的操作方案即将应用到的每个监测区域。前五个字段与
+通常情况相同。除了 ``damon_aggregated`` tracepoint 的输出外,它还显示该方案所属 DAMON 上下文
+在该上下文所属 kdamond 的上下文列表中的索引(``ctx_idx=X``),以及该方案在该上下文的方案列表
+中的索引(``scheme_idx=X``)。
diff --git a/Documentation/translations/zh_CN/mm/damon/design.rst b/Documentation/translations/zh_CN/mm/damon/design.rst
index 16e3db34a7dd..cb6479783863 100644
--- a/Documentation/translations/zh_CN/mm/damon/design.rst
+++ b/Documentation/translations/zh_CN/mm/damon/design.rst
@@ -38,6 +38,8 @@ DAMON提供了数据访问监控功能,同时使其准确性和开销可控。
DAMON目前为物理和虚拟地址空间提供了基元的实现。下面两个小节描述了这些工作的方式。
+.. _damon_design_vaddr_target_regions_construction_zh_CN:
+
基于VMA的目标地址范围构造
-------------------------
@@ -103,6 +105,8 @@ DAMON的输出显示了在给定的时间内哪些页面的访问频率是多少
这种机制的监测开销将随着目标工作负载规模的增长而任意增加。
+.. _damon_design_region_based_sampling_zh_CN:
+
基于区域的抽样调查
------------------
@@ -115,6 +119,8 @@ DAMON的输出显示了在给定的时间内哪些页面的访问频率是多少
然而,如果假设没有得到保证,这个方案就不能保持输出的质量。
+.. _damon_design_adaptive_regions_adjustment_zh_CN:
+
适应性区域调整
--------------
@@ -128,6 +134,17 @@ DAMON的输出显示了在给定的时间内哪些页面的访问频率是多少
通过这种方式,DAMON提供了其最佳的质量和最小的开销,同时保持了用户为其权衡设定的界限。
+.. _damon_design_age_tracking_zh_CN:
+
+年龄跟踪
+--------
+
+通过分析监测结果,用户还可以发现某个区域当前的访问模式已经保持了多长时间。这可用于更好地理解
+访问模式。例如,可以利用访问频率和时近性实现页面放置算法。为了让这种访问模式保持时间分析更容
+易,DAMON 在每个区域中维护另一个名为 ``age`` 的计数器。对于每个 ``聚集间隔``,DAMON 检查该
+区域的大小和访问频率(``nr_accesses``)是否发生了显著变化。如果发生了变化,该计数器会被重置为
+零。否则,该计数器会增加。
+
动态目标空间更新处理
--------------------
@@ -137,4 +154,130 @@ DAMON的输出显示了在给定的时间内哪些页面的访问频率是多少
由于在某些情况下变化可能相当频繁,DAMON允许监控操作检查动态变化,包括内存映射变化,
并仅在用户指定的时间间隔( ``更新间隔`` )中的每个时间段,将其应用于监控操作相关的
-数据结构,如抽象的监控目标内存区。
\ No newline at end of file
+数据结构,如抽象的监控目标内存区。
+
+
+.. _damon_design_monitoring_params_tuning_guide_zh_CN:
+
+监测参数调优指南
+----------------
+
+简而言之,应设置 ``聚集间隔``,使其能够为使用目的捕获有意义数量的访问。访问数量可以用聚集后
+监测结果快照中各区域的 ``nr_accesses`` 和 ``age`` 来衡量。该间隔的默认值 ``100ms`` 在许多情况
+下被证明过短。应按 ``聚集间隔`` 的比例设置 ``采样间隔``。默认推荐比例为 ``1/20``。
+
+``聚集间隔`` 应设置为工作负载可在该间隔内为监测目的产生一定数量访问的时间间隔。如果该间隔过短,
+只能捕获少量访问。结果是,监测结果会看起来像所有内容都同样只是很少被访问。对许多目的而言,这
+将毫无用处。不过,如果该间隔过长,根据给定目的的时间尺度,区域通过 :ref:`区域调整机制
+<damon_design_adaptive_regions_adjustment_zh_CN>` 收敛所需的时间可能过长。如果工作负载实际只产生
+很少访问,而用户却认为监测目的所需的访问数量很高,就可能发生这种情况。对于这种情况,应仔细重
+新考虑每个 ``聚集间隔`` 要捕获的目标访问数量。还要注意,捕获的访问数量不仅用 ``nr_accesses``
+表示,也用 ``age`` 表示。例如,即使监测结果中的每个区域都显示 ``nr_accesses`` 为零,仍然可以
+用 ``age`` 值作为时近性信息来区分区域。
+
+因此,``聚集间隔`` 的最佳值取决于工作负载的访问密集程度。用户应根据每个聚集后的监测结果快照
+中捕获的访问数量来调优该间隔。
+
+请注意,该间隔的默认值是 100 毫秒,在许多情况下都太短,尤其是在大型系统上。
+
+``采样间隔`` 定义每次聚集的分辨率。如果它设置得过大,监测结果会看起来像每个区域都同样很少被
+访问,或者同样频繁地被访问。也就是说,区域将无法根据访问模式区分,因此结果在许多用例中都会无
+用。如果 ``采样间隔`` 过小,它不会降低分辨率,但会增加监测开销。如果它已经足以为给定目的提供
+足够的监测结果分辨率,就不应再不必要地降低。建议将它按 ``聚集间隔`` 的比例设置。默认比例设为
+``1/20``,并且仍然推荐该比例。
+
+基于手动调优指南,DAMON 提供了更直观的、基于调节项的间隔自动调优机制。更多细节请参考
+:ref:`该功能的设计文档 <damon_design_monitoring_intervals_autotuning_zh_CN>`。
+
+基于上述指南的示例调优,请参考 Documentation/mm/damon/monitoring_intervals_tuning_example.rst。
+
+
+.. _damon_design_monitoring_intervals_autotuning_zh_CN:
+
+监测间隔自动调优
+----------------
+
+DAMON 基于 :ref:`调优指南的思路 <damon_design_monitoring_params_tuning_guide_zh_CN>`,提供了
+对 ``采样间隔`` 和 ``聚集间隔`` 的自动调优机制。该调优机制允许用户设置希望 DAMON 在给定时间间隔
+内观测到的访问事件数量目标。用户可以把该目标指定为 DAMON 观测到的访问事件数量与理论最大事件数
+量之间的比例(``access_bp``),该比例在给定数量的聚集中测量(``aggrs``)。
+
+DAMON 观测到的访问事件基于 DAMON :ref:`区域假设 <damon_design_region_based_sampling_zh_CN>`
+按字节粒度计算。例如,如果发现大小为 ``X`` 字节、``nr_accesses`` 为 ``Y`` 的区域,就意味着
+DAMON 观测到了 ``X * Y`` 个访问事件。该区域的理论最大访问事件也以相同方式计算,但会把 ``Y``
+替换为理论最大 ``nr_accesses``,即 ``聚集间隔 / 采样间隔``。
+
+该机制会计算 ``aggrs`` 次聚集期间的访问事件比例。如果观测到的访问比例低于或高于目标值,就按
+相同比例增大或减小 ``采样间隔`` 和 ``聚集间隔``。间隔变化比例按当前采样比例与目标比例之间的
+距离决定。
+
+用户还可以通过两个参数(``min_sample_us`` 和 ``max_sample_us``)进一步设置调优机制可设置的
+最小和最大 ``采样间隔``。由于调优机制总是以相同比例改变 ``采样间隔`` 和 ``聚集间隔``,所以
+每次调优变化后的最小和最大 ``聚集间隔`` 也可以自动一起设置。
+
+该调优默认关闭,需要由用户显式设置。根据经验法则和帕累托原则,推荐使用 4% 的访问样本比例目标。
+请注意,这里应用了两次帕累托原则(80/20 规则)。也就是说,假设以 4%(20% 的 20%)的 DAMON
+观测访问事件比例(来源),捕获 64%(80% 乘以 80%)的真实访问事件(结果)。
+
+要了解用户空间如何通过 :ref:`DAMON sysfs 接口 <sysfs_interface_zh_CN>` 使用该功能,请参考文档
+的 :ref:`intervals_goal <damon_usage_sysfs_monitoring_intervals_goal_zh_CN>` 部分。
+
+
+.. _damon_modules_zh_CN:
+
+模块
+====
+
+由于 DAMON 的核心是供内核组件使用的框架,它本身不向用户空间提供任何直接接口。相反,这些接口
+应由每个使用 DAMON API 的内核组件来实现。DAMON 子系统本身实现了这类 DAMON API 用户模块,
+它们分别用于通用目的的 DAMON 控制和特定目的的数据访问感知系统操作,并为用户空间提供稳定的应
+用二进制接口(ABI)。用户空间可以使用这些接口构建高效的数据访问感知应用程序。
+
+
+通用目的用户接口模块
+--------------------
+
+DAMON 模块为运行时的通用目的 DAMON 用法提供用户空间 ABI。
+
+与许多其他 ABI 一样,这些模块会在类似 ``sysfs`` 的伪文件系统上创建文件,允许用户通过写入和读
+取这些文件来向 DAMON 指定请求并获取回答。作为这类 I/O 的响应,DAMON 用户接口模块会通过 DAMON
+API 按用户请求控制 DAMON 并获取结果,然后把结果返回给用户空间。
+
+这些 ABI 是为用户空间应用程序开发而设计的,而不是为人工手动操作而设计的。建议人工用户使用这类
+用户空间工具。一个用 Python 编写的此类用户空间工具可在 Github
+(https://github.com/damonitor/damo)、Pypi(https://pypistats.org/packages/damo)以及多个发行
+版(https://repology.org/project/damo/versions)中获取。
+
+目前,该类型有一个模块可用,即 ``DAMON sysfs interface``。关于接口细节,请参考 ABI
+:ref:`文档 <sysfs_interface_zh_CN>`。
+
+
+.. _damon_modules_special_purpose_zh_CN:
+
+专用访问感知内核模块
+--------------------
+
+DAMON 模块为特定目的的 DAMON 用法提供用户空间 ABI。
+
+DAMON 用户接口模块用于在运行时完整控制所有 DAMON 功能。对于每种专用的、系统范围的数据访问感知
+系统操作,例如主动回收或 LRU 链表均衡,可以通过移除该特定目的不需要的调节项来简化接口,并扩展
+为启动时甚至编译时控制。用于该用途的 DAMON 控制参数默认值也需要针对该目的进行优化。
+
+为支持这些场景,DAMON 还提供了更多使用 DAMON API 的内核模块,它们提供更简单且更优化的用户空间
+接口。目前提供了用于访问监测统计、主动回收和 LRU 链表操作的三个模块。更多细节请阅读这些模块的
+使用文档(:doc:`/admin-guide/mm/damon/stat`, :doc:`/admin-guide/mm/damon/reclaim` 和
+:doc:`/admin-guide/mm/damon/lru_sort`)。
+
+.. _damon_design_special_purpose_modules_exclusivity_zh_CN:
+
+请注意,这些模块当前以互斥方式运行。如果其中一个模块已经在运行,其他模块在收到启动请求时将返回
+``-EBUSY``。
+
+示例 DAMON 模块
+----------------
+
+DAMON 模块提供 DAMON 内核 API 用法示例。
+
+内核程序员可以使用 DAMON 内核 API 构建自己的专用或通用目的 DAMON 模块。为了帮助他们容易理解
+如何使用 DAMON 内核 API,Linux 源码树的 ``samples/damon/`` 目录下提供了一些示例模块。请注意,
+这些模块不是为实际产品使用而开发的,而只是为了展示如何以简单方式使用 DAMON 内核 API。
--
2.43.0
^ permalink raw reply related
* [PATCH v5 00/19] perf cs-etm: Queue context packets for frontend
From: James Clark @ 2026-06-09 14:40 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
Fix thread tracking when decoding Coresight trace and add a new test for
it.
The new test is added as a Perf test workload instead of a custom binary
with its own build system, but this requires a new feature in Perf test
to pass in control pipes which can enable and disable events. This
scopes the recording to just the workload and helps to reduce the amount
of data recorded in tracing tests.
With this new feature we can re-write all of the Coresight tests to make
use of it and remove the remaining binaries which fixes the following
issues:
* They didn't work in out of source builds
* A lot of the tests unnecessarily required root and didn't skip
without it
* They were mainly qualitative tests which didn't look for specific
behavior
Most importantly, the long build and runtime has been reduced. On a
Radxa Orion O6, unroll_loop_thread.c took 37s to compile which is longer
than the entire Perf build. Now the build time is negligible and the
before and after test runtimes for all the Coresight tests are:
| N1SDP | Orion O6
-----------------------------------
Before | 4m 0s | 14m 49s
After | 26s | 56s
-----------------------------------
Signed-off-by: James Clark <james.clark@linaro.org>
---
Changes in v5:
- Forgot to include this change:
- Test for actual length of expected raw dump (Leo)
- Link to v4: https://lore.kernel.org/r/20260609-james-cs-context-tracking-fix-v4-0-44f9fb9e5c42@linaro.org
Changes in v4:
- Rename workload-ctl to record-ctl and improve docs (Leo)
- Use new packet argument everywhere in
cs_etm__synth_instruction_sample() (Sashiko)
- Test for actual length of expected raw dump (Leo)
- Use -fno-inline instead of keyword (Leo)
- Don't test any brace or call lines in deterministic test
- Make sure context switch loop test does cleanup on failure (Sashiko)
- Remove undef int overflows in workloads (Sashiko)
- Link to v3: https://lore.kernel.org/r/20260603-james-cs-context-tracking-fix-v3-0-c392945d9ed5@linaro.org
Changes in v3:
- Minor sashiko comments
- Close some more pipes
- Fix warning messages
- Error handling improvements
- Pass packet into cs_etm__synth_instruction_sample()
- Fixup stale comment (Leo)
- Link to v2: https://lore.kernel.org/r/20260602-james-cs-context-tracking-fix-v2-0-85b5ce6f55c6@linaro.org
Changes in v2:
- Add --workload-ctl option to Perf test
- Re-write all the Coresight tests and speed them up
- Pass packet to memory access function so frontend can use either the
previous or current packet's EL
- Link to v1: https://lore.kernel.org/r/20260526-james-cs-context-tracking-fix-v1-0-ebd602e18287@linaro.org
---
James Clark (19):
perf cs-etm: Queue context packets for frontend
perf test: Add workload-ctl option
perf test: Add a workload that forces context switches
perf test cs-etm: Test process attribution
perf test: Add deterministic workload
perf test cs-etm: Replace unroll loop thread with deterministic decode test
perf test cs-etm: Remove asm_pure_loop test
perf test cs-etm: Replace memcpy test with raw dump stress test
perf test: Add named_threads workload
perf test cs-etm: Test decoding for concurrent threads test
perf test cs-etm: Remove duplicate branch tests
perf test cs-etm: Skip if not root
perf test cs-etm: Reduce snapshot size
perf test cs-etm: Speed up basic test
perf test cs-etm: Remove unused Coresight workloads
perf test cs-etm: Make disassembly test use kcore
perf test cs-etm: Add all branch instructions to test
perf test cs-etm: Speed up disassembly test
perf test cs-etm: Move existing tests to coresight folder
Documentation/trace/coresight/coresight-perf.rst | 78 +------
MAINTAINERS | 2 -
tools/perf/Documentation/perf-test.txt | 24 ++-
tools/perf/Makefile.perf | 14 +-
tools/perf/scripts/python/arm-cs-trace-disasm.py | 20 +-
tools/perf/tests/builtin-test.c | 187 +++++++++++++++-
tools/perf/tests/shell/coresight/Makefile | 29 ---
.../perf/tests/shell/coresight/Makefile.miniconfig | 14 --
tools/perf/tests/shell/coresight/asm_pure_loop.sh | 22 --
.../tests/shell/coresight/asm_pure_loop/.gitignore | 1 -
.../tests/shell/coresight/asm_pure_loop/Makefile | 34 ---
.../shell/coresight/asm_pure_loop/asm_pure_loop.S | 30 ---
.../tests/shell/coresight/concurrent_threads.sh | 45 ++++
.../tests/shell/coresight/context_switch_thread.sh | 69 ++++++
tools/perf/tests/shell/coresight/deterministic.sh | 72 +++++++
.../tests/shell/coresight/memcpy_thread/.gitignore | 1 -
.../tests/shell/coresight/memcpy_thread/Makefile | 33 ---
.../shell/coresight/memcpy_thread/memcpy_thread.c | 80 -------
.../tests/shell/coresight/memcpy_thread_16k_10.sh | 22 --
.../perf/tests/shell/coresight/raw_dump_stress.sh | 65 ++++++
.../shell/{ => coresight}/test_arm_coresight.sh | 43 ++--
.../{ => coresight}/test_arm_coresight_disasm.sh | 23 +-
.../tests/shell/coresight/thread_loop/.gitignore | 1 -
.../tests/shell/coresight/thread_loop/Makefile | 33 ---
.../shell/coresight/thread_loop/thread_loop.c | 85 --------
.../shell/coresight/thread_loop_check_tid_10.sh | 23 --
.../shell/coresight/thread_loop_check_tid_2.sh | 23 --
.../shell/coresight/unroll_loop_thread/.gitignore | 1 -
.../shell/coresight/unroll_loop_thread/Makefile | 33 ---
.../unroll_loop_thread/unroll_loop_thread.c | 75 -------
.../tests/shell/coresight/unroll_loop_thread_10.sh | 22 --
tools/perf/tests/shell/lib/coresight.sh | 134 ------------
tools/perf/tests/tests.h | 3 +
tools/perf/tests/workloads/Build | 4 +
tools/perf/tests/workloads/context_switch_loop.c | 110 ++++++++++
tools/perf/tests/workloads/deterministic.c | 39 ++++
tools/perf/tests/workloads/named_threads.c | 109 ++++++++++
tools/perf/util/cs-etm-decoder/cs-etm-decoder.c | 21 +-
tools/perf/util/cs-etm.c | 236 ++++++++++++---------
tools/perf/util/cs-etm.h | 8 +-
40 files changed, 926 insertions(+), 942 deletions(-)
---
base-commit: 351a37f2fda4db668cff8ba12f2992d73dccdaea
change-id: 20260515-james-cs-context-tracking-fix-754998bae7ed
Best regards,
--
James Clark <james.clark@linaro.org>
^ permalink raw reply
* [PATCH v5 01/19] perf cs-etm: Queue context packets for frontend
From: James Clark @ 2026-06-09 14:40 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v5-0-d53a7d096a19@linaro.org>
PE_CONTEXT elements update the context ID and exception level, but the
decoder may still have prior packets cached for frontend processing.
Updating the context immediately in the decoder backend can make those
cached packets get consumed with the wrong thread or EL state.
Add a CS_ETM_CONTEXT packet carrying the TID and EL to the frontend,
this keeps context changes ordered with the rest of the packet stream
and avoids mismatches when synthesizing samples from cached packets.
Separate the memory access function into one for the frontend and one
for decoding. The frontend also needs memory access to attach the
instruction to samples. Because the frontend does memory access for
both previous and current packets, change all the frontend memory access
function signatures to take both a tidq and packet. But backend always
uses the current backend EL and thread from the tidq.
Treat context packets as a boundary for branch sample generation and
remove tidq->prev_packet_thread because it's not possible to branch to a
different thread, so only tracking the current thread is required for
sample generation.
Fixes: e573e978fb12 ("perf cs-etm: Inject capabilitity for CoreSight traces")
Reported-by: Amir Ayupov <aaupov@meta.com>
Closes: https://lore.kernel.org/linux-perf-users/20260515021135.1729028-1-aaupov@meta.com/
Co-authored-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: James Clark <james.clark@linaro.org>
---
tools/perf/util/cs-etm-decoder/cs-etm-decoder.c | 21 ++-
tools/perf/util/cs-etm.c | 236 ++++++++++++++----------
tools/perf/util/cs-etm.h | 8 +-
3 files changed, 163 insertions(+), 102 deletions(-)
diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
index dee3020ceaa9..26940f1f1b0b 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
@@ -402,6 +402,8 @@ cs_etm_decoder__buffer_packet(struct cs_etm_queue *etmq,
packet_queue->packet_buffer[et].flags = 0;
packet_queue->packet_buffer[et].exception_number = UINT32_MAX;
packet_queue->packet_buffer[et].trace_chan_id = trace_chan_id;
+ packet_queue->packet_buffer[et].el = ocsd_EL_unknown;
+ packet_queue->packet_buffer[et].tid = -1;
if (packet_queue->packet_count == CS_ETM_PACKET_MAX_BUFFER - 1)
return OCSD_RESP_WAIT;
@@ -449,6 +451,7 @@ cs_etm_decoder__buffer_range(struct cs_etm_queue *etmq,
packet->last_instr_type = elem->last_i_type;
packet->last_instr_subtype = elem->last_i_subtype;
packet->last_instr_cond = elem->last_instr_cond;
+ packet->el = elem->context.exception_level;
if (elem->last_i_type == OCSD_INSTR_BR || elem->last_i_type == OCSD_INSTR_BR_INDIRECT)
packet->last_instr_taken_branch = elem->last_instr_exec;
@@ -525,7 +528,9 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,
const ocsd_generic_trace_elem *elem,
const uint8_t trace_chan_id)
{
+ struct cs_etm_packet *packet;
pid_t tid = -1;
+ int ret;
/*
* Process the PE_CONTEXT packets if we have a valid contextID or VMID.
@@ -546,12 +551,18 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,
break;
}
- if (cs_etm__etmq_set_tid_el(etmq, tid, trace_chan_id,
- elem->context.exception_level))
+ if (cs_etm__etmq_update_decode_context(etmq, trace_chan_id,
+ elem->context.exception_level, tid))
return OCSD_RESP_FATAL_SYS_ERR;
- if (tid == -1)
- return OCSD_RESP_CONT;
+ ret = cs_etm_decoder__buffer_packet(etmq, packet_queue, trace_chan_id,
+ CS_ETM_CONTEXT);
+ if (ret != OCSD_RESP_CONT && ret != OCSD_RESP_WAIT)
+ return ret;
+
+ packet = &packet_queue->packet_buffer[packet_queue->tail];
+ packet->tid = tid;
+ packet->el = elem->context.exception_level;
/*
* A timestamp is generated after a PE_CONTEXT element so make sure
@@ -559,7 +570,7 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,
*/
cs_etm_decoder__reset_timestamp(packet_queue);
- return OCSD_RESP_CONT;
+ return ret;
}
static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 40c6ddfa8c8d..5e92359f51a7 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -85,15 +85,22 @@ struct cs_etm_traceid_queue {
u64 period_instructions;
size_t last_branch_pos;
union perf_event *event_buf;
- struct thread *thread;
- struct thread *prev_packet_thread;
- ocsd_ex_level prev_packet_el;
- ocsd_ex_level el;
struct branch_stack *last_branch;
struct branch_stack *last_branch_rb;
struct cs_etm_packet *prev_packet;
struct cs_etm_packet *packet;
struct cs_etm_packet_queue packet_queue;
+
+ struct thread *decode_thread;
+ ocsd_ex_level decode_el;
+
+ /*
+ * The frontend accesses the EL from '[prev_]packet' because it needs
+ * previous EL for branch and current EL for instruction samples. It's
+ * not possible to change thread in a single branch sample so no need to
+ * store or access the thread through the packet.
+ */
+ struct thread *frontend_thread;
};
enum cs_etm_format {
@@ -614,10 +621,11 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
queue = &etmq->etm->queues.queue_array[etmq->queue_nr];
tidq->trace_chan_id = trace_chan_id;
- tidq->el = tidq->prev_packet_el = ocsd_EL_unknown;
- tidq->thread = machine__findnew_thread(&etm->session->machines.host, -1,
+ tidq->decode_el = ocsd_EL_unknown;
+ tidq->frontend_thread = machine__findnew_thread(&etm->session->machines.host, -1,
+ queue->tid);
+ tidq->decode_thread = machine__findnew_thread(&etm->session->machines.host, -1,
queue->tid);
- tidq->prev_packet_thread = machine__idle_thread(&etm->session->machines.host);
tidq->packet = zalloc(sizeof(struct cs_etm_packet));
if (!tidq->packet)
@@ -750,21 +758,10 @@ static void cs_etm__packet_swap(struct cs_etm_auxtrace *etm,
/*
* Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
* the next incoming packet.
- *
- * Threads and exception levels are also tracked for both the
- * previous and current packets. This is because the previous
- * packet is used for the 'from' IP for branch samples, so the
- * thread at that time must also be assigned to that sample.
- * Across discontinuity packets the thread can change, so by
- * tracking the thread for the previous packet the branch sample
- * will have the correct info.
*/
tmp = tidq->packet;
tidq->packet = tidq->prev_packet;
tidq->prev_packet = tmp;
- tidq->prev_packet_el = tidq->el;
- thread__put(tidq->prev_packet_thread);
- tidq->prev_packet_thread = thread__get(tidq->thread);
}
}
@@ -937,8 +934,8 @@ static void cs_etm__free_traceid_queues(struct cs_etm_queue *etmq)
/* Free this traceid_queue from the array */
tidq = etmq->traceid_queues[idx];
- thread__zput(tidq->thread);
- thread__zput(tidq->prev_packet_thread);
+ thread__zput(tidq->frontend_thread);
+ thread__zput(tidq->decode_thread);
zfree(&tidq->event_buf);
zfree(&tidq->last_branch);
zfree(&tidq->last_branch_rb);
@@ -1083,47 +1080,43 @@ static u8 cs_etm__cpu_mode(struct cs_etm_queue *etmq, u64 address,
}
}
-static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
- u64 address, size_t size, u8 *buffer,
- const ocsd_mem_space_acc_t mem_space)
+static u32 __cs_etm__mem_access(struct cs_etm_queue *etmq,
+ u64 address, size_t size, u8 *buffer,
+ const ocsd_mem_space_acc_t mem_space,
+ ocsd_ex_level el, struct thread *thread)
{
u8 cpumode;
u64 offset;
int len;
struct addr_location al;
struct dso *dso;
- struct cs_etm_traceid_queue *tidq;
int ret = 0;
if (!etmq)
return 0;
addr_location__init(&al);
- tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
- if (!tidq)
- goto out;
/*
- * We've already tracked EL along side the PID in cs_etm__set_thread()
- * so double check that it matches what OpenCSD thinks as well. It
- * doesn't distinguish between EL0 and EL1 for this mem access callback
- * so we had to do the extra tracking. Skip validation if it's any of
- * the 'any' values.
+ * We track EL for the frontend and the backend when receiving context
+ * and range packets. OpenCSD doesn't distinguish between EL0 and EL1
+ * for this mem access callback so we had to do the extra tracking. Skip
+ * validation if it's any of the 'any' values.
*/
if (!(mem_space == OCSD_MEM_SPACE_ANY ||
mem_space == OCSD_MEM_SPACE_N || mem_space == OCSD_MEM_SPACE_S)) {
if (mem_space & OCSD_MEM_SPACE_EL1N) {
/* Includes both non secure EL1 and EL0 */
- assert(tidq->el == ocsd_EL1 || tidq->el == ocsd_EL0);
+ assert(el == ocsd_EL1 || el == ocsd_EL0);
} else if (mem_space & OCSD_MEM_SPACE_EL2)
- assert(tidq->el == ocsd_EL2);
+ assert(el == ocsd_EL2);
else if (mem_space & OCSD_MEM_SPACE_EL3)
- assert(tidq->el == ocsd_EL3);
+ assert(el == ocsd_EL3);
}
- cpumode = cs_etm__cpu_mode(etmq, address, tidq->el);
+ cpumode = cs_etm__cpu_mode(etmq, address, el);
- if (!thread__find_map(tidq->thread, cpumode, address, &al))
+ if (!thread__find_map(thread, cpumode, address, &al))
goto out;
dso = map__dso(al.map);
@@ -1138,7 +1131,7 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
map__load(al.map);
- len = dso__data_read_offset(dso, maps__machine(thread__maps(tidq->thread)),
+ len = dso__data_read_offset(dso, maps__machine(thread__maps(thread)),
offset, buffer, size);
if (len <= 0) {
@@ -1158,6 +1151,30 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
return ret;
}
+static u32 cs_etm__frontend_mem_access(struct cs_etm_queue *etmq,
+ struct cs_etm_traceid_queue *tidq,
+ struct cs_etm_packet *packet,
+ u64 address, size_t size, u8 *buffer)
+{
+ return __cs_etm__mem_access(etmq, address, size, buffer, 0, packet->el,
+ tidq->frontend_thread);
+}
+
+static u32 cs_etm__decoder_mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
+ u64 address, size_t size, u8 *buffer,
+ const ocsd_mem_space_acc_t mem_space)
+{
+ struct cs_etm_traceid_queue *tidq;
+
+ tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
+ if (!tidq)
+ return 0;
+
+ return __cs_etm__mem_access(etmq, address, size, buffer,
+ mem_space, tidq->decode_el,
+ tidq->decode_thread);
+}
+
static struct cs_etm_queue *cs_etm__alloc_queue(void)
{
struct cs_etm_queue *etmq = zalloc(sizeof(*etmq));
@@ -1333,12 +1350,13 @@ void cs_etm__reset_last_branch_rb(struct cs_etm_traceid_queue *tidq)
}
static inline int cs_etm__t32_instr_size(struct cs_etm_queue *etmq,
- u8 trace_chan_id, u64 addr)
+ struct cs_etm_traceid_queue *tidq,
+ struct cs_etm_packet *packet, u64 addr)
{
u8 instrBytes[2];
- cs_etm__mem_access(etmq, trace_chan_id, addr, ARRAY_SIZE(instrBytes),
- instrBytes, 0);
+ cs_etm__frontend_mem_access(etmq, tidq, packet, addr,
+ ARRAY_SIZE(instrBytes), instrBytes);
/*
* T32 instruction size is indicated by bits[15:11] of the first
* 16-bit word of the instruction: 0b11101, 0b11110 and 0b11111
@@ -1371,16 +1389,16 @@ u64 cs_etm__last_executed_instr(const struct cs_etm_packet *packet)
}
static inline u64 cs_etm__instr_addr(struct cs_etm_queue *etmq,
- u64 trace_chan_id,
- const struct cs_etm_packet *packet,
+ struct cs_etm_traceid_queue *tidq,
+ struct cs_etm_packet *packet,
u64 offset)
{
if (packet->isa == CS_ETM_ISA_T32) {
u64 addr = packet->start_addr;
while (offset) {
- addr += cs_etm__t32_instr_size(etmq,
- trace_chan_id, addr);
+ addr += cs_etm__t32_instr_size(etmq, tidq, packet,
+ addr);
offset--;
}
return addr;
@@ -1490,34 +1508,51 @@ cs_etm__get_trace(struct cs_etm_queue *etmq)
return etmq->buf_len;
}
-static void cs_etm__set_thread(struct cs_etm_queue *etmq,
- struct cs_etm_traceid_queue *tidq, pid_t tid,
- ocsd_ex_level el)
+/*
+ * Convert a raw thread number to a thread struct and assign it to **thread.
+ */
+static int cs_etm__etmq_update_thread(struct cs_etm_queue *etmq,
+ ocsd_ex_level el, pid_t tid,
+ struct thread **thread)
{
struct machine *machine = cs_etm__get_machine(etmq, el);
+ if (!machine || !*thread)
+ return -EINVAL;
+
if (tid != -1) {
- thread__zput(tidq->thread);
- tidq->thread = machine__find_thread(machine, -1, tid);
+ thread__zput(*thread);
+ *thread = machine__find_thread(machine, -1, tid);
}
/* Couldn't find a known thread */
- if (!tidq->thread)
- tidq->thread = machine__idle_thread(machine);
+ if (!*thread)
+ *thread = machine__idle_thread(machine);
- tidq->el = el;
+ return 0;
}
-int cs_etm__etmq_set_tid_el(struct cs_etm_queue *etmq, pid_t tid,
- u8 trace_chan_id, ocsd_ex_level el)
+/*
+ * Set the thread and EL of the decode context which is ahead in time of the
+ * frontend context.
+ */
+int cs_etm__etmq_update_decode_context(struct cs_etm_queue *etmq,
+ u8 trace_chan_id,
+ ocsd_ex_level el, pid_t tid)
{
struct cs_etm_traceid_queue *tidq;
+ int ret;
tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
if (!tidq)
return -EINVAL;
- cs_etm__set_thread(etmq, tidq, tid, el);
+ ret = cs_etm__etmq_update_thread(etmq, el, tid,
+ &tidq->decode_thread);
+ if (ret)
+ return ret;
+
+ tidq->decode_el = el;
return 0;
}
@@ -1527,8 +1562,8 @@ bool cs_etm__etmq_is_timeless(struct cs_etm_queue *etmq)
}
static void cs_etm__copy_insn(struct cs_etm_queue *etmq,
- u64 trace_chan_id,
- const struct cs_etm_packet *packet,
+ struct cs_etm_traceid_queue *tidq,
+ struct cs_etm_packet *packet,
struct perf_sample *sample)
{
/*
@@ -1545,14 +1580,14 @@ static void cs_etm__copy_insn(struct cs_etm_queue *etmq,
* cs_etm__t32_instr_size().
*/
if (packet->isa == CS_ETM_ISA_T32)
- sample->insn_len = cs_etm__t32_instr_size(etmq, trace_chan_id,
+ sample->insn_len = cs_etm__t32_instr_size(etmq, tidq, packet,
sample->ip);
/* Otherwise, A64 and A32 instruction size are always 32-bit. */
else
sample->insn_len = 4;
- cs_etm__mem_access(etmq, trace_chan_id, sample->ip, sample->insn_len,
- (void *)sample->insn, 0);
+ cs_etm__frontend_mem_access(etmq, tidq, packet, sample->ip,
+ sample->insn_len, (void *)sample->insn);
}
u64 cs_etm__convert_sample_time(struct cs_etm_queue *etmq, u64 cs_timestamp)
@@ -1579,6 +1614,7 @@ static inline u64 cs_etm__resolve_sample_time(struct cs_etm_queue *etmq,
static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq,
+ struct cs_etm_packet *packet,
u64 addr, u64 period)
{
int ret = 0;
@@ -1588,23 +1624,23 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
perf_sample__init(&sample, /*all=*/true);
event->sample.header.type = PERF_RECORD_SAMPLE;
- event->sample.header.misc = cs_etm__cpu_mode(etmq, addr, tidq->el);
+ event->sample.header.misc = cs_etm__cpu_mode(etmq, addr, packet->el);
event->sample.header.size = sizeof(struct perf_event_header);
/* Set time field based on etm auxtrace config. */
sample.time = cs_etm__resolve_sample_time(etmq, tidq);
sample.ip = addr;
- sample.pid = thread__pid(tidq->thread);
- sample.tid = thread__tid(tidq->thread);
+ sample.pid = thread__pid(tidq->frontend_thread);
+ sample.tid = thread__tid(tidq->frontend_thread);
sample.id = etmq->etm->instructions_id;
sample.stream_id = etmq->etm->instructions_id;
sample.period = period;
- sample.cpu = tidq->packet->cpu;
+ sample.cpu = packet->cpu;
sample.flags = tidq->prev_packet->flags;
sample.cpumode = event->sample.header.misc;
- cs_etm__copy_insn(etmq, tidq->trace_chan_id, tidq->packet, &sample);
+ cs_etm__copy_insn(etmq, tidq, packet, &sample);
if (etm->synth_opts.last_branch)
sample.branch_stack = tidq->last_branch;
@@ -1649,15 +1685,15 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
event->sample.header.type = PERF_RECORD_SAMPLE;
event->sample.header.misc = cs_etm__cpu_mode(etmq, ip,
- tidq->prev_packet_el);
+ tidq->prev_packet->el);
event->sample.header.size = sizeof(struct perf_event_header);
/* Set time field based on etm auxtrace config. */
sample.time = cs_etm__resolve_sample_time(etmq, tidq);
sample.ip = ip;
- sample.pid = thread__pid(tidq->prev_packet_thread);
- sample.tid = thread__tid(tidq->prev_packet_thread);
+ sample.pid = thread__pid(tidq->frontend_thread);
+ sample.tid = thread__tid(tidq->frontend_thread);
sample.addr = cs_etm__first_executed_instr(tidq->packet);
sample.id = etmq->etm->branches_id;
sample.stream_id = etmq->etm->branches_id;
@@ -1666,8 +1702,7 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
sample.flags = tidq->prev_packet->flags;
sample.cpumode = event->sample.header.misc;
- cs_etm__copy_insn(etmq, tidq->trace_chan_id, tidq->prev_packet,
- &sample);
+ cs_etm__copy_insn(etmq, tidq, tidq->prev_packet, &sample);
/*
* perf report cannot handle events without a branch stack
@@ -1788,7 +1823,6 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
{
struct cs_etm_auxtrace *etm = etmq->etm;
int ret;
- u8 trace_chan_id = tidq->trace_chan_id;
u64 instrs_prev;
/* Get instructions remainder from previous packet */
@@ -1874,10 +1908,10 @@ static int cs_etm__sample(struct cs_etm_queue *etmq,
* been executed, but PC has not advanced to next
* instruction)
*/
- addr = cs_etm__instr_addr(etmq, trace_chan_id,
- tidq->packet, offset - 1);
+ addr = cs_etm__instr_addr(etmq, tidq, tidq->packet,
+ offset - 1);
ret = cs_etm__synth_instruction_sample(
- etmq, tidq, addr,
+ etmq, tidq, tidq->packet, addr,
etm->instructions_sample_period);
if (ret)
return ret;
@@ -1959,7 +1993,7 @@ static int cs_etm__flush(struct cs_etm_queue *etmq,
addr = cs_etm__last_executed_instr(tidq->prev_packet);
err = cs_etm__synth_instruction_sample(
- etmq, tidq, addr,
+ etmq, tidq, tidq->prev_packet, addr,
tidq->period_instructions);
if (err)
return err;
@@ -2014,7 +2048,7 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq,
addr = cs_etm__last_executed_instr(tidq->prev_packet);
err = cs_etm__synth_instruction_sample(
- etmq, tidq, addr,
+ etmq, tidq, tidq->prev_packet, addr,
tidq->period_instructions);
if (err)
return err;
@@ -2051,9 +2085,9 @@ static int cs_etm__get_data_block(struct cs_etm_queue *etmq)
return etmq->buf_len;
}
-static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
- struct cs_etm_packet *packet,
- u64 end_addr)
+static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq,
+ struct cs_etm_traceid_queue *tidq,
+ struct cs_etm_packet *packet, u64 end_addr)
{
/* Initialise to keep compiler happy */
u16 instr16 = 0;
@@ -2075,8 +2109,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
* so below only read 2 bytes as instruction size for T32.
*/
addr = end_addr - 2;
- cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr16),
- (u8 *)&instr16, 0);
+ cs_etm__frontend_mem_access(etmq, tidq, packet, addr,
+ sizeof(instr16), (u8 *)&instr16);
if ((instr16 & 0xFF00) == 0xDF00)
return true;
@@ -2091,8 +2125,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
* +---------+---------+-------------------------+
*/
addr = end_addr - 4;
- cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr32),
- (u8 *)&instr32, 0);
+ cs_etm__frontend_mem_access(etmq, tidq, packet, addr,
+ sizeof(instr32), (u8 *)&instr32);
if ((instr32 & 0x0F000000) == 0x0F000000 &&
(instr32 & 0xF0000000) != 0xF0000000)
return true;
@@ -2108,8 +2142,8 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
* +-----------------------+---------+-----------+
*/
addr = end_addr - 4;
- cs_etm__mem_access(etmq, trace_chan_id, addr, sizeof(instr32),
- (u8 *)&instr32, 0);
+ cs_etm__frontend_mem_access(etmq, tidq, packet, addr,
+ sizeof(instr32), (u8 *)&instr32);
if ((instr32 & 0xFFE0001F) == 0xd4000001)
return true;
@@ -2125,7 +2159,6 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
static bool cs_etm__is_syscall(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq, u64 magic)
{
- u8 trace_chan_id = tidq->trace_chan_id;
struct cs_etm_packet *packet = tidq->packet;
struct cs_etm_packet *prev_packet = tidq->prev_packet;
@@ -2140,7 +2173,7 @@ static bool cs_etm__is_syscall(struct cs_etm_queue *etmq,
*/
if (magic == __perf_cs_etmv4_magic) {
if (packet->exception_number == CS_ETMV4_EXC_CALL &&
- cs_etm__is_svc_instr(etmq, trace_chan_id, prev_packet,
+ cs_etm__is_svc_instr(etmq, tidq, prev_packet,
prev_packet->end_addr))
return true;
}
@@ -2178,7 +2211,6 @@ static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq,
u64 magic)
{
- u8 trace_chan_id = tidq->trace_chan_id;
struct cs_etm_packet *packet = tidq->packet;
struct cs_etm_packet *prev_packet = tidq->prev_packet;
@@ -2204,7 +2236,7 @@ static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq,
* (SMC, HVC) are taken as sync exceptions.
*/
if (packet->exception_number == CS_ETMV4_EXC_CALL &&
- !cs_etm__is_svc_instr(etmq, trace_chan_id, prev_packet,
+ !cs_etm__is_svc_instr(etmq, tidq, prev_packet,
prev_packet->end_addr))
return true;
@@ -2228,7 +2260,6 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq,
{
struct cs_etm_packet *packet = tidq->packet;
struct cs_etm_packet *prev_packet = tidq->prev_packet;
- u8 trace_chan_id = tidq->trace_chan_id;
u64 magic;
int ret;
@@ -2309,11 +2340,11 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq,
if (prev_packet->flags == (PERF_IP_FLAG_BRANCH |
PERF_IP_FLAG_RETURN |
PERF_IP_FLAG_INTERRUPT) &&
- cs_etm__is_svc_instr(etmq, trace_chan_id,
- packet, packet->start_addr))
+ cs_etm__is_svc_instr(etmq, tidq, packet, packet->start_addr)) {
prev_packet->flags = PERF_IP_FLAG_BRANCH |
PERF_IP_FLAG_RETURN |
PERF_IP_FLAG_SYSCALLRET;
+ }
break;
case CS_ETM_DISCONTINUITY:
/*
@@ -2394,6 +2425,7 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq,
PERF_IP_FLAG_RETURN |
PERF_IP_FLAG_INTERRUPT;
break;
+ case CS_ETM_CONTEXT:
case CS_ETM_EMPTY:
default:
break;
@@ -2469,6 +2501,19 @@ static int cs_etm__process_traceid_queue(struct cs_etm_queue *etmq,
*/
cs_etm__sample(etmq, tidq);
break;
+ case CS_ETM_CONTEXT:
+ /*
+ * Update context but don't swap packet. Keep the
+ * previous one for branch source address info, if
+ * tracing the kernel the context packet will be emitted
+ * between two ranges.
+ */
+ ret = cs_etm__etmq_update_thread(etmq, tidq->packet->el,
+ tidq->packet->tid,
+ &tidq->frontend_thread);
+ if (ret)
+ goto out;
+ break;
case CS_ETM_EXCEPTION:
case CS_ETM_EXCEPTION_RET:
/*
@@ -2497,6 +2542,7 @@ static int cs_etm__process_traceid_queue(struct cs_etm_queue *etmq,
}
}
+out:
return ret;
}
@@ -2620,7 +2666,7 @@ static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm,
if (!tidq)
continue;
- if (tid == -1 || thread__tid(tidq->thread) == tid)
+ if (tid == -1 || thread__tid(tidq->frontend_thread) == tid)
cs_etm__run_per_thread_timeless_decoder(etmq);
} else
cs_etm__run_per_cpu_timeless_decoder(etmq);
@@ -3328,7 +3374,7 @@ static int cs_etm__create_queue_decoders(struct cs_etm_queue *etmq)
*/
if (cs_etm_decoder__add_mem_access_cb(etmq->decoder,
0x0L, ((u64) -1L),
- cs_etm__mem_access))
+ cs_etm__decoder_mem_access))
goto out_free_decoder;
zfree(&t_params);
diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h
index aa9bb4a32eca..b81099c2b301 100644
--- a/tools/perf/util/cs-etm.h
+++ b/tools/perf/util/cs-etm.h
@@ -158,6 +158,7 @@ enum cs_etm_sample_type {
CS_ETM_DISCONTINUITY,
CS_ETM_EXCEPTION,
CS_ETM_EXCEPTION_RET,
+ CS_ETM_CONTEXT,
};
enum cs_etm_isa {
@@ -184,6 +185,8 @@ struct cs_etm_packet {
u8 last_instr_size;
u8 trace_chan_id;
int cpu;
+ int el;
+ pid_t tid;
};
#define CS_ETM_PACKET_MAX_BUFFER 1024
@@ -259,8 +262,9 @@ enum cs_etm_pid_fmt {
#include <opencsd/ocsd_if_types.h>
int cs_etm__get_cpu(struct cs_etm_queue *etmq, u8 trace_chan_id, int *cpu);
enum cs_etm_pid_fmt cs_etm__get_pid_fmt(struct cs_etm_queue *etmq);
-int cs_etm__etmq_set_tid_el(struct cs_etm_queue *etmq, pid_t tid,
- u8 trace_chan_id, ocsd_ex_level el);
+int cs_etm__etmq_update_decode_context(struct cs_etm_queue *etmq,
+ u8 trace_chan_id, ocsd_ex_level el,
+ pid_t tid);
bool cs_etm__etmq_is_timeless(struct cs_etm_queue *etmq);
void cs_etm__etmq_set_traceid_queue_timestamp(struct cs_etm_queue *etmq,
u8 trace_chan_id);
--
2.34.1
^ permalink raw reply related
* [PATCH v5 02/19] perf test: Add workload-ctl option
From: James Clark @ 2026-06-09 14:40 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v5-0-d53a7d096a19@linaro.org>
Add a --workload-ctl=fifo:ctl-fifo[,ack-fifo] option for 'perf test
-w'. When set, run_workload() opens the named FIFO, writes enable before
invoking the builtin workload, writes disable before returning, and
waits for ack responses when an ack FIFO is provided to ensure that the
workload doesn't run until the events are enabled.
This can be used to limit the scope of the recording to only the
workload execution and avoid recording Perf setup and teardown code if
Perf record is started with events disabled (-D 1).
Assisted-by: Codex:GPT-5.5
Signed-off-by: James Clark <james.clark@linaro.org>
---
tools/perf/Documentation/perf-test.txt | 12 +++
tools/perf/tests/builtin-test.c | 184 ++++++++++++++++++++++++++++++++-
2 files changed, 194 insertions(+), 2 deletions(-)
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
index 32da0d1fa86a..2f4a91f5b9dc 100644
--- a/tools/perf/Documentation/perf-test.txt
+++ b/tools/perf/Documentation/perf-test.txt
@@ -69,3 +69,15 @@ OPTIONS
--list-workloads::
List the available workloads to use with -w/--workload.
+
+--record-ctl=fifo:ctl-fifo[,ack-fifo]::
+ This option is used to communicate with a perf record session in order
+ to control the recording scope to only the workload and avoid recording
+ setup and teardown code. When specifying this option, the same FIFO path
+ must be specified in the record session via:
+
+ perf record -D -1 --control=fifo:ctl-fifo[,ack-fifo] ...
+
+ Perf test sends 'enable' and 'disable' commands through ctl-fifo to
+ control event recording. If 'ack-fifo' is provided, the workload runner
+ waits for an 'ack' response after each command.
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index b64fc2204f22..86ea427eb0aa 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -56,6 +56,7 @@ static unsigned int runs_per_test = 1;
static unsigned int failure_snippet_lines = 10;
const char *dso_to_test;
const char *test_objdump_path = "objdump";
+static const char *workload_control;
/*
* List of architecture specific tests. Not a weak symbol as the array length is
@@ -168,6 +169,11 @@ static struct test_workload *workloads[] = {
#endif
};
+struct workload_control {
+ int ctl_fd;
+ int ack_fd;
+};
+
#define workloads__for_each(workload) \
for (unsigned i = 0; i < ARRAY_SIZE(workloads) && ({ workload = workloads[i]; 1; }); i++)
@@ -1387,13 +1393,185 @@ static int workloads__fprintf_list(FILE *fp)
return printed;
}
+static int perf_control_open_fifo(struct workload_control *ctl, const char *str)
+{
+ char *s, *p;
+ int ret;
+
+ if (strncmp(str, "fifo:", 5))
+ return -EINVAL;
+
+ str += 5;
+ if (!*str || *str == ',')
+ return -EINVAL;
+
+ s = strdup(str);
+ if (!s)
+ return -ENOMEM;
+
+ p = strchr(s, ',');
+ if (p)
+ *p = '\0';
+
+ ctl->ctl_fd = open(s, O_WRONLY | O_CLOEXEC);
+ if (ctl->ctl_fd < 0) {
+ ret = -errno;
+ pr_err("Failed to open workload control FIFO '%s': %m\n", s);
+ free(s);
+ return ret;
+ }
+
+ if (p && *++p) {
+ ctl->ack_fd = open(p, O_RDONLY | O_CLOEXEC);
+ if (ctl->ack_fd < 0) {
+ ret = -errno;
+ pr_err("Failed to open workload control ack FIFO '%s': %m\n", p);
+ close(ctl->ctl_fd);
+ ctl->ctl_fd = -1;
+ free(s);
+ return ret;
+ }
+ }
+
+ free(s);
+ return 0;
+}
+
+static int perf_control_open(struct workload_control *ctl)
+{
+ int ret;
+
+ if (!workload_control)
+ return 0;
+
+ ret = perf_control_open_fifo(ctl, workload_control);
+
+ if (ret == -EINVAL) {
+ pr_err("Unsupported workload control spec '%s', expected fifo:ctl-fifo[,ack-fifo]\n",
+ workload_control);
+ }
+
+ return ret;
+}
+
+static void perf_control_close(struct workload_control *ctl)
+{
+ if (ctl->ctl_fd >= 0) {
+ close(ctl->ctl_fd);
+ ctl->ctl_fd = -1;
+ }
+ if (ctl->ack_fd >= 0) {
+ close(ctl->ack_fd);
+ ctl->ack_fd = -1;
+ }
+}
+
+static int perf_control_write_cmd(int fd, const char *cmd)
+{
+ size_t len = strlen(cmd);
+ ssize_t ret;
+
+ while (len) {
+ ret = write(fd, cmd, len);
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+ pr_err("Failed to write perf control command: %m\n");
+ return -1;
+ }
+
+ if (!ret) {
+ pr_err("Failed to write perf control command: short write\n");
+ return -1;
+ }
+
+ cmd += ret;
+ len -= ret;
+ }
+
+ return 0;
+}
+
+static int perf_control_read_ack(int fd)
+{
+ char buf[16];
+ ssize_t ret;
+
+ do {
+ ret = read(fd, buf, sizeof(buf) - 1);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret < 0) {
+ pr_err("Failed to read perf control ack: %m\n");
+ return -1;
+ }
+
+ if (!ret) {
+ pr_err("Unexpected EOF while reading perf control ack\n");
+ return -1;
+ }
+
+ buf[ret] = '\0';
+ for (ssize_t i = 0; i < ret; i++) {
+ if (buf[i] == '\n' || buf[i] == '\0') {
+ buf[i] = '\0';
+ break;
+ }
+ }
+
+ if (strcmp(buf, "ack")) {
+ pr_err("Unexpected perf control ack: %s\n", buf);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int perf_control_send(struct workload_control *ctl, const char *cmd)
+{
+ if (ctl->ctl_fd < 0)
+ return 0;
+
+ if (perf_control_write_cmd(ctl->ctl_fd, cmd))
+ return -1;
+
+ if (ctl->ack_fd >= 0 && perf_control_read_ack(ctl->ack_fd))
+ return -1;
+
+ return 0;
+}
+
static int run_workload(const char *work, int argc, const char **argv)
{
struct test_workload *twl;
workloads__for_each(twl) {
- if (!strcmp(twl->name, work))
- return twl->func(argc, argv);
+ struct workload_control ctl = {
+ .ctl_fd = -1,
+ .ack_fd = -1,
+ };
+ int control_ret, ret;
+
+ if (strcmp(twl->name, work))
+ continue;
+
+ ret = perf_control_open(&ctl);
+ if (ret)
+ return ret;
+
+ if (perf_control_send(&ctl, "enable\n")) {
+ perf_control_close(&ctl);
+ return -1;
+ }
+
+ ret = twl->func(argc, argv);
+
+ control_ret = perf_control_send(&ctl, "disable\n");
+ perf_control_close(&ctl);
+ if (control_ret)
+ return -1;
+
+ return ret;
}
pr_info("No workload found: %s\n", work);
@@ -1486,6 +1664,8 @@ int cmd_test(int argc, const char **argv)
OPT_UINTEGER('r', "runs-per-test", &runs_per_test,
"Run each test the given number of times, default 1"),
OPT_STRING('w', "workload", &workload, "work", "workload to run for testing, use '--list-workloads' to list the available ones."),
+ OPT_STRING(0, "record-ctl", &workload_control, "fifo:ctl-fifo[,ack-fifo]",
+ "Write enable to the fifo just before running the workload and disable after, with optional ack from ack-fifo"),
OPT_BOOLEAN(0, "list-workloads", &list_workloads, "List the available builtin workloads to use with -w/--workload"),
OPT_STRING(0, "dso", &dso_to_test, "dso", "dso to test"),
OPT_STRING(0, "objdump", &test_objdump_path, "path",
--
2.34.1
^ permalink raw reply related
* [PATCH v5 03/19] perf test: Add a workload that forces context switches
From: James Clark @ 2026-06-09 14:40 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v5-0-d53a7d096a19@linaro.org>
This workload launches two processes that block when reading and writing
to each other forcing the other process to be scheduled for each
read/write pair.
Signed-off-by: James Clark <james.clark@linaro.org>
---
tools/perf/Documentation/perf-test.txt | 7 +-
tools/perf/tests/builtin-test.c | 1 +
tools/perf/tests/tests.h | 1 +
tools/perf/tests/workloads/Build | 1 +
tools/perf/tests/workloads/context_switch_loop.c | 110 +++++++++++++++++++++++
5 files changed, 117 insertions(+), 3 deletions(-)
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
index 2f4a91f5b9dc..213eb62603eb 100644
--- a/tools/perf/Documentation/perf-test.txt
+++ b/tools/perf/Documentation/perf-test.txt
@@ -55,15 +55,16 @@ OPTIONS
-w::
--workload=::
- Run a built-in workload, to list them use '--list-workloads', current ones include:
- noploop, thloop, leafloop, sqrtloop, brstack, datasym and landlock.
+ Run a built-in workload, to list them use '--list-workloads', current
+ ones include: noploop, thloop, leafloop, sqrtloop, brstack, datasym,
+ context_switch_loop and landlock.
Used with the shell script regression tests.
Some accept an extra parameter:
seconds: leafloop, noploop, sqrtloop, thloop
- nrloops: brstack
+ nrloops: brstack, context_switch_loop
The datasym and landlock workloads don't accept any.
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 86ea427eb0aa..9284f897de3c 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -163,6 +163,7 @@ static struct test_workload *workloads[] = {
&workload__traploop,
&workload__inlineloop,
&workload__jitdump,
+ &workload__context_switch_loop,
#ifdef HAVE_RUST_SUPPORT
&workload__code_with_type,
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index bf8ff7d54727..7cd4da4e96d3 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -245,6 +245,7 @@ DECLARE_WORKLOAD(landlock);
DECLARE_WORKLOAD(traploop);
DECLARE_WORKLOAD(inlineloop);
DECLARE_WORKLOAD(jitdump);
+DECLARE_WORKLOAD(context_switch_loop);
#ifdef HAVE_RUST_SUPPORT
DECLARE_WORKLOAD(code_with_type);
diff --git a/tools/perf/tests/workloads/Build b/tools/perf/tests/workloads/Build
index 0eb6d99528eb..7134a031cb7c 100644
--- a/tools/perf/tests/workloads/Build
+++ b/tools/perf/tests/workloads/Build
@@ -10,6 +10,7 @@ perf-test-y += landlock.o
perf-test-y += traploop.o
perf-test-y += inlineloop.o
perf-test-y += jitdump.o
+perf-test-y += context_switch_loop.o
ifeq ($(CONFIG_RUST_SUPPORT),y)
perf-test-y += code_with_type.o
diff --git a/tools/perf/tests/workloads/context_switch_loop.c b/tools/perf/tests/workloads/context_switch_loop.c
new file mode 100644
index 000000000000..5431af6147e6
--- /dev/null
+++ b/tools/perf/tests/workloads/context_switch_loop.c
@@ -0,0 +1,110 @@
+
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/compiler.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "../tests.h"
+
+static int loops = 100;
+static char buf;
+int context_switch_loop_work = 1234;
+
+#define write_block(fd) \
+ do { \
+ if (write(fd, &buf, 1) <= 0) \
+ return 1; \
+ } while (0)
+
+#define read_block(fd) \
+ do { \
+ if (read(fd, &buf, 1) <= 0) \
+ return 1; \
+ } while (0)
+
+/* Not static to avoid LTO clobbering the function name */
+int context_switch_loop_proc1(int in_fd, int out_fd);
+int context_switch_loop_proc1(int in_fd, int out_fd)
+{
+ for (int i = 0; i < loops; i++) {
+ read_block(in_fd);
+ context_switch_loop_work += i * 3;
+ write_block(out_fd);
+ }
+ return 0;
+}
+
+int context_switch_loop_proc2(int in_fd, int out_fd);
+int context_switch_loop_proc2(int in_fd, int out_fd)
+{
+ for (int i = 0; i < loops; i++) {
+ write_block(out_fd);
+ context_switch_loop_work += i * 7;
+ read_block(in_fd);
+ }
+ return 0;
+}
+
+/*
+ * Launches two processes that take turns to execute a multiplication N times
+ */
+static int context_switch_loop(int argc, const char **argv)
+{
+ int a_to_b[2], b_to_a[2];
+ pid_t proc1_pid;
+ int status;
+ int ret;
+
+ if (argc > 0) {
+ loops = atoi(argv[0]);
+ if (loops < 0) {
+ fprintf(stderr, "Invalid number of loops: %s\n", argv[0]);
+ return 1;
+ }
+ }
+
+ if (pipe(a_to_b) || pipe(b_to_a)) {
+ perror("Pipe error");
+ return 1;
+ }
+
+ proc1_pid = fork();
+ if (proc1_pid < 0) {
+ perror("Fork error");
+ return 1;
+ }
+
+ if (!proc1_pid) {
+ close(a_to_b[0]);
+ close(b_to_a[1]);
+ prctl(PR_SET_NAME, "proc1", 0, 0, 0);
+ ret = context_switch_loop_proc1(b_to_a[0], a_to_b[1]);
+ close(a_to_b[1]);
+ close(b_to_a[0]);
+ exit(ret);
+ }
+
+ close(a_to_b[1]);
+ close(b_to_a[0]);
+ prctl(PR_SET_NAME, "proc2", 0, 0, 0);
+ ret = context_switch_loop_proc2(a_to_b[0], b_to_a[1]);
+ close(a_to_b[0]);
+ close(b_to_a[1]);
+
+ if (ret) {
+ kill(proc1_pid, SIGKILL);
+ return ret;
+ }
+
+ if (waitpid(proc1_pid, &status, 0) != proc1_pid || !WIFEXITED(status) ||
+ WEXITSTATUS(status))
+ return 1;
+
+ return 0;
+}
+
+DEFINE_WORKLOAD(context_switch_loop);
--
2.34.1
^ permalink raw reply related
* [PATCH v5 04/19] perf test cs-etm: Test process attribution
From: James Clark @ 2026-06-09 14:40 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v5-0-d53a7d096a19@linaro.org>
Run the context switch workload on one CPU and trace it to test that
symbols are attributed to the correct process and that the attribution
changes at the exact point that the context switch happened.
Reviewed-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: James Clark <james.clark@linaro.org>
---
.../tests/shell/coresight/context_switch_thread.sh | 69 ++++++++++++++++++++++
1 file changed, 69 insertions(+)
diff --git a/tools/perf/tests/shell/coresight/context_switch_thread.sh b/tools/perf/tests/shell/coresight/context_switch_thread.sh
new file mode 100755
index 000000000000..2b9c44b86c59
--- /dev/null
+++ b/tools/perf/tests/shell/coresight/context_switch_thread.sh
@@ -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
--
2.34.1
^ permalink raw reply related
* [PATCH v5 05/19] perf test: Add deterministic workload
From: James Clark @ 2026-06-09 14:40 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, Leo Yan, Arnaldo Carvalho de Melo,
Namhyung Kim, Jiri Olsa, Ian Rogers, Amir Ayupov, Jonathan Corbet,
Shuah Khan, Paschalis Mpeis
Cc: coresight, linux-perf-users, linux-kernel,
Arnaldo Carvalho de Melo, linux-doc, James Clark
In-Reply-To: <20260609-james-cs-context-tracking-fix-v5-0-d53a7d096a19@linaro.org>
Add a workload that does the same thing every time for testing CPU trace
decoding.
Reviewed-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: James Clark <james.clark@linaro.org>
---
tools/perf/Documentation/perf-test.txt | 4 +--
tools/perf/tests/builtin-test.c | 1 +
tools/perf/tests/tests.h | 1 +
tools/perf/tests/workloads/Build | 2 ++
tools/perf/tests/workloads/deterministic.c | 39 ++++++++++++++++++++++++++++++
5 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/tools/perf/Documentation/perf-test.txt b/tools/perf/Documentation/perf-test.txt
index 213eb62603eb..c50a4b2d2d29 100644
--- a/tools/perf/Documentation/perf-test.txt
+++ b/tools/perf/Documentation/perf-test.txt
@@ -57,7 +57,7 @@ OPTIONS
--workload=::
Run a built-in workload, to list them use '--list-workloads', current
ones include: noploop, thloop, leafloop, sqrtloop, brstack, datasym,
- context_switch_loop and landlock.
+ context_switch_loop, deterministic and landlock.
Used with the shell script regression tests.
@@ -66,7 +66,7 @@ OPTIONS
seconds: leafloop, noploop, sqrtloop, thloop
nrloops: brstack, context_switch_loop
- The datasym and landlock workloads don't accept any.
+ The datasym, landlock and deterministic workloads don't accept any.
--list-workloads::
List the available workloads to use with -w/--workload.
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 9284f897de3c..ef7e3f52a383 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -164,6 +164,7 @@ static struct test_workload *workloads[] = {
&workload__inlineloop,
&workload__jitdump,
&workload__context_switch_loop,
+ &workload__deterministic,
#ifdef HAVE_RUST_SUPPORT
&workload__code_with_type,
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 7cd4da4e96d3..bcfe9c33fc66 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -246,6 +246,7 @@ DECLARE_WORKLOAD(traploop);
DECLARE_WORKLOAD(inlineloop);
DECLARE_WORKLOAD(jitdump);
DECLARE_WORKLOAD(context_switch_loop);
+DECLARE_WORKLOAD(deterministic);
#ifdef HAVE_RUST_SUPPORT
DECLARE_WORKLOAD(code_with_type);
diff --git a/tools/perf/tests/workloads/Build b/tools/perf/tests/workloads/Build
index 7134a031cb7c..90f2d8aa4941 100644
--- a/tools/perf/tests/workloads/Build
+++ b/tools/perf/tests/workloads/Build
@@ -11,6 +11,7 @@ perf-test-y += traploop.o
perf-test-y += inlineloop.o
perf-test-y += jitdump.o
perf-test-y += context_switch_loop.o
+perf-test-y += deterministic.o
ifeq ($(CONFIG_RUST_SUPPORT),y)
perf-test-y += code_with_type.o
@@ -23,3 +24,4 @@ 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_inlineloop.o = -g -O2
+CFLAGS_deterministic.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
diff --git a/tools/perf/tests/workloads/deterministic.c b/tools/perf/tests/workloads/deterministic.c
new file mode 100644
index 000000000000..8a78519fd075
--- /dev/null
+++ b/tools/perf/tests/workloads/deterministic.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/compiler.h>
+#include "../tests.h"
+
+int dt_work = 1234;
+
+static void function1(void)
+{
+ dt_work += 7;
+ dt_work += 7;
+ dt_work += 7;
+}
+
+static void function2(void)
+{
+ dt_work += 7;
+ dt_work += 7;
+ dt_work += 7;
+}
+
+static int deterministic(int argc __maybe_unused,
+ const char **argv __maybe_unused)
+{
+ dt_work += 7;
+ dt_work += 7;
+ dt_work += 7;
+
+ function1();
+
+ dt_work += 7;
+ dt_work += 7;
+ dt_work += 7;
+
+ function2();
+
+ return 0;
+}
+
+DEFINE_WORKLOAD(deterministic);
--
2.34.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox