From: Kunwu Chan <kunwu.chan@gmail.com>
To: will@kernel.org, mark.rutland@arm.com, sj@kernel.org,
akpm@linux-foundation.org, shuah@kernel.org,
kunwu.chan@linux.dev
Cc: linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-perf-users@vger.kernel.org, damon@lists.linux.dev,
linux-mm@kvack.org, linux-kselftest@vger.kernel.org,
"Lian Wang (ProcessMission)" <lianux.mm@gmail.com>,
Kunwu Chan <kunwu.chan@gmail.com>
Subject: [RFC PATCH 4/4] selftests/damon: add DAMON perf AUX backend test
Date: Sun, 16 Aug 2026 22:22:21 +0800 [thread overview]
Message-ID: <20260816142222.689624-5-kunwu.chan@linux.dev> (raw)
In-Reply-To: <20260816142222.689624-1-kunwu.chan@linux.dev>
From: "Lian Wang (ProcessMission)" <lianux.mm@gmail.com>
Register a DAMON kselftest for the ARM SPE AUX backend. When kernel
sources are available, check the backend integration and the required
AUX-before-ring lifecycle ordering. Independently run the SPE parser
KUnit suite through debugfs when it is built.
On an ARM SPE system with no pre-existing kdamond, create one controlled
userspace target and collect counter deltas from a five-second session.
Stop the session explicitly, then verify positive end-to-end pipeline
counters and final enqueue/dequeue closure. Use a private mktemp result
directory and restore only the DAMON state created by this test.
This is a smoke and lifecycle test; full-ring pause/resume validation
remains a separate hardware stress test.
Co-developed-by: Kunwu Chan <kunwu.chan@gmail.com>
Signed-off-by: Kunwu Chan <kunwu.chan@gmail.com>
Signed-off-by: Lian Wang (ProcessMission) <lianux.mm@gmail.com>
---
tools/testing/selftests/damon/Makefile | 1 +
.../selftests/damon/damon_perf_aux_test.sh | 414 ++++++++++++++++++
2 files changed, 415 insertions(+)
create mode 100755 tools/testing/selftests/damon/damon_perf_aux_test.sh
diff --git a/tools/testing/selftests/damon/Makefile b/tools/testing/selftests/damon/Makefile
index 1db8fa95ba2d..204a0b60d84a 100644
--- a/tools/testing/selftests/damon/Makefile
+++ b/tools/testing/selftests/damon/Makefile
@@ -24,4 +24,5 @@ TEST_PROGS += sysfs_no_op_commit_break.py
EXTRA_CLEAN = __pycache__
TEST_PROGS += damon_perf_obs_test.sh
+TEST_PROGS += damon_perf_aux_test.sh
include ../lib.mk
diff --git a/tools/testing/selftests/damon/damon_perf_aux_test.sh b/tools/testing/selftests/damon/damon_perf_aux_test.sh
new file mode 100755
index 000000000000..86ccaca6310c
--- /dev/null
+++ b/tools/testing/selftests/damon/damon_perf_aux_test.sh
@@ -0,0 +1,414 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# DAMON Perf AUX Backend - Automated Test
+#
+# Validates the AUX trace-buffer backend framework and the ARM SPE
+# backend:
+# 1. Source-level structure checks (files, Makefile, ops interface)
+# 2. SPE parser: runs the KUnit suite against byte-exact binary
+# fixtures (mm/damon/perf/spe_parser_test.c) through debugfs
+# 3. Architecture checks (exact PMU match, SPSC ring contract,
+# lifecycle ordering)
+# 4. Runtime smoke test: live DAMON session configured with an ARM
+# SPE event. Only runs when no kdamonds exist; the pre-test
+# sysfs state is restored on exit.
+#
+# Usage: sudo ./damon_perf_aux_test.sh [pmu-name]
+#
+# Requirements:
+# - CONFIG_DAMON_PERF_OBSERVE=y
+# - CONFIG_DAMON_PERF_SPE_KUNIT_TEST=y and CONFIG_KUNIT_DEBUGFS=y
+# for section 2 (skipped otherwise)
+# - CONFIG_ARM_SPE_PMU=y for section 4 (skipped otherwise)
+# - Root privileges
+
+set -e
+PASSED=0; FAILED=0; SKIPPED=0
+pass() { echo " [PASS] $1"; PASSED=$((PASSED + 1)); }
+fail() { echo " [FAIL] $1"; FAILED=$((FAILED + 1)); }
+skip() { echo " [SKIP] $*"; SKIPPED=$((SKIPPED + 1)); }
+
+PMU_NAME="${1:-arm_spe_0}"
+RESULTS_DIR=$(mktemp -d "${TMPDIR:-/tmp}/damon_aux_test.XXXXXX") || exit 1
+exec > >(tee "$RESULTS_DIR/output.log") 2>&1
+
+ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
+if [[ -z "$ROOT" ]]; then
+ ROOT="/usr/src/linux"
+fi
+SRC_DIR="$ROOT/mm/damon/perf"
+
+ADMIN="/sys/kernel/mm/damon/admin"
+
+echo "=========================================="
+echo " DAMON Perf AUX Backend Test"
+echo "=========================================="
+
+# ---- Section 1: Source structure ----
+if [[ -d "$SRC_DIR" && -f "$ROOT/mm/damon/core.c" ]]; then
+echo ""
+echo "--- 1. Backend Source Files ---"
+for f in aux_backend.h aux_backend.c spe_parser.h spe_backend.c spe_parser_test.c; do
+ if [[ -f "$SRC_DIR/$f" ]]; then
+ pass "Source file: $f"
+ else
+ fail "Source file: $f"
+ fi
+done
+
+echo ""
+echo "--- 2. Makefile Registration ---"
+for obj in aux_backend.o spe_backend.o spe_parser_test.o; do
+ if grep -q "$obj" "$SRC_DIR/Makefile" 2>/dev/null; then
+ pass "Makefile registers: $obj"
+ else
+ fail "Makefile registers: $obj"
+ fi
+done
+
+echo ""
+echo "--- 3. Backend Ops Interface ---"
+OPS_COUNT=$(grep -c '(\*match_pmu)\|(\*init)\|(\*cleanup)\|(\*arm)\|(\*disarm)\|(\*drain)' \
+ "$SRC_DIR/aux_backend.h" 2>/dev/null || echo 0)
+if [[ "$OPS_COUNT" -ge 6 ]]; then
+ pass "Backend ops interface: 6 ops defined ($OPS_COUNT found)"
+else
+ fail "Backend ops interface: expected 6 ops, found $OPS_COUNT"
+fi
+if grep -q 'DAMON_PERF_BACKEND_AUX' "$SRC_DIR/aux_backend.h" 2>/dev/null; then
+ pass "DAMON_PERF_BACKEND_AUX flag defined"
+else
+ fail "DAMON_PERF_BACKEND_AUX flag"
+fi
+
+echo ""
+echo "--- 4. SPE Parser Constants ---"
+for c in SPE_BUFFER_MIN_PAGES SPE_BUFFER_MAX_RECORDS SPE_HDR_MASK1 SPE_HDR_PAD \
+ SPE_HDR_END SPE_HDR_TIMESTAMP SPE_HDR_EXTENDED SPE_ADDR_DATA_VIRT \
+ SPE_OP_CLASS_LDST; do
+ if grep -q "$c" "$SRC_DIR/spe_parser.h" 2>/dev/null; then
+ pass "Parser constant: $c"
+ else
+ fail "Parser constant: $c"
+ fi
+done
+else
+ skip "source structure" "kernel source tree not available"
+fi
+
+# ---- Section 2: Parser correctness (KUnit, binary fixtures) ----
+echo ""
+echo "--- 5. SPE Parser: KUnit suite (binary fixtures) ---"
+KUNIT_DIR="/sys/kernel/debug/kunit/damon_perf_spe_parser"
+if [[ -d "$KUNIT_DIR" ]]; then
+ # Writing to "run" triggers a fresh run; "results" then holds the
+ # TAP output of the byte-exact fixture cases.
+ if [[ -f "$KUNIT_DIR/run" ]]; then
+ echo run > "$KUNIT_DIR/run" 2>/dev/null || true
+ fi
+ RES="$KUNIT_DIR/results"
+ if [[ -f "$RES" ]]; then
+ if grep -Eq "^[[:space:]]*not ok" "$RES"; then
+ fail "KUnit parser suite has failing cases"
+ grep -E "^[[:space:]]*not ok" "$RES" | sed 's/^/ /'
+ elif grep -Eq "^[[:space:]]*ok " "$RES"; then
+ pass "KUnit parser suite: all cases pass"
+ else
+ fail "KUnit parser suite produced no completed cases"
+ fi
+ echo " $(grep '# Totals:' "$RES" | tail -1)"
+ # Spot-check the fixtures that cover the review-critical paths:
+ # record content, consumed-length accounting, truncation,
+ # alignment, extended packets, and error resync.
+ for c in "store record" "bad packet resync" \
+ "alignment packet at odd position" \
+ "alignment packet at aligned position" \
+ "extended address packet" \
+ "invalid extended header resync" \
+ "truncated trailing record retained" \
+ "truncated packet retained" \
+ "pad-only window"; do
+ if grep -Eq "^[[:space:]]*ok .*$c" "$RES"; then
+ pass "fixture: $c"
+ else
+ fail "fixture: $c"
+ fi
+ done
+ else
+ skip "KUnit results" "no results file (suite did not run)"
+ fi
+else
+ skip "KUnit parser suite" "CONFIG_KUNIT_DEBUGFS missing or suite not built"
+fi
+
+# ---- Section 3: Architecture checks ----
+echo ""
+echo "--- 6. Architecture Correctness ---"
+
+if [[ ! -d "$SRC_DIR" || ! -f "$ROOT/mm/damon/core.c" ]]; then
+ skip "architecture source checks" "kernel source tree not available"
+else
+
+# Exact PMU match by pmu object, not by name-prefix matching.
+if grep -q 'arm_spe_pmu_match' "$SRC_DIR/spe_backend.c" 2>/dev/null; then
+ pass "PMU match: exact match via arm_spe_pmu_match()"
+else
+ fail "PMU match: arm_spe_pmu_match() missing"
+fi
+if grep -q 'strncmp.*arm_spe' "$SRC_DIR/spe_backend.c" 2>/dev/null; then
+ fail "PMU match: strncmp name-prefix matching must not be used"
+else
+ pass "PMU match: no strncmp name-prefix matching"
+fi
+
+# Backend selection: gated on the ITRACE capability, then matched by PMU.
+if grep -q 'PERF_PMU_CAP_ITRACE' "$SRC_DIR/aux_backend.c" 2>/dev/null; then
+ pass "PMU selection: gated by PERF_PMU_CAP_ITRACE"
+else
+ fail "PMU selection: ITRACE gate missing"
+fi
+
+# Lifecycle ordering: arm() before perf_event_enable(), disarm() after
+# perf_event_disable().
+ARM_LINE=$(awk '/^int damon_perf_event_arm\(/ { in_fn=1 } \
+ in_fn && /ops->arm/ { print NR; exit }' "$ROOT/mm/damon/vaddr.c")
+ENABLE_LINE=$(awk '/^int damon_perf_event_arm\(/ { in_fn=1 } \
+ in_fn && /perf_event_enable/ { print NR; exit }' "$ROOT/mm/damon/vaddr.c")
+if [[ -n "$ARM_LINE" && -n "$ENABLE_LINE" && "$ARM_LINE" -lt "$ENABLE_LINE" ]]; then
+ pass "Lifecycle: ops->arm() before perf_event_enable()"
+else
+ fail "Lifecycle: arm() must precede perf_event_enable()"
+fi
+
+DISABLE_LINE=$(awk '/^void damon_perf_event_disarm\(/ { in_fn=1 } \
+ in_fn && /perf_event_disable/ { print NR; exit }' "$ROOT/mm/damon/vaddr.c")
+DISARM_LINE=$(awk '/^void damon_perf_event_disarm\(/ { in_fn=1 } \
+ in_fn && /ops->disarm/ { print NR; exit }' "$ROOT/mm/damon/vaddr.c")
+if [[ -n "$DISABLE_LINE" && -n "$DISARM_LINE" && "$DISABLE_LINE" -lt "$DISARM_LINE" ]]; then
+ pass "Lifecycle: ops->disarm() after perf_event_disable()"
+else
+ fail "Lifecycle: disarm() must follow perf_event_disable()"
+fi
+
+# The stop path calls the common check after disarming. That common check
+# must drain AUX before it starts consuming the SPSC rings.
+DISARM_LOOP=$(grep -n 'damon_perf_event_disarm' "$ROOT/mm/damon/core.c" 2>/dev/null | \
+ tail -1 | cut -d: -f1)
+FINAL_CHECK=$(awk -v start="$DISARM_LOOP" 'NR > start && \
+ /kdamond_check_reported_accesses\(ctx\)/ { print NR; exit }' \
+ "$ROOT/mm/damon/core.c")
+if [[ -n "$DISARM_LOOP" && -n "$FINAL_CHECK" && \
+ "$DISARM_LOOP" -lt "$FINAL_CHECK" ]]; then
+ pass "Lifecycle: final common drain after disarm"
+else
+ fail "Lifecycle: final common drain must follow disarm"
+fi
+
+# Per-tick and final: AUX must publish before the SPSC loop reads rings.
+CHECK_FN=$(grep -n '^static unsigned int kdamond_check_reported_accesses' \
+ "$ROOT/mm/damon/core.c" | cut -d: -f1)
+DRAIN_TICK=$(awk -v start="$CHECK_FN" 'NR > start && \
+ /damon_perf_aux_drain\(ctx\)/ { print NR; exit }' "$ROOT/mm/damon/core.c")
+RING_DRAIN=$(awk -v start="$CHECK_FN" 'NR > start && \
+ /for_each_online_cpu\(cpu\)/ { print NR; exit }' "$ROOT/mm/damon/core.c")
+if [[ -n "$DRAIN_TICK" && -n "$RING_DRAIN" && \
+ "$DRAIN_TICK" -lt "$RING_DRAIN" ]]; then
+ pass "Tick: AUX drain before SPSC ring drain"
+else
+ fail "Tick: AUX drain must precede the ring drain"
+fi
+
+# Per-(event,cpu) parser state scoped via aux_priv.
+if grep -q 'aux_priv' "$ROOT/mm/damon/ops-common.h" 2>/dev/null; then
+ pass "State scoping: per-(event,cpu) via aux_priv"
+else
+ fail "State scoping: aux_priv in ops-common.h"
+fi
+
+# SPSC ring contract: kdamond is the only process-context producer and
+# writes only to its own CPU's ring. A remote-write helper must not
+# exist.
+if grep -q 'damon_report_access_on_cpu' "$ROOT/mm/damon/core.c" 2>/dev/null; then
+ fail "SPSC: damon_report_access_on_cpu() must not exist"
+else
+ pass "SPSC: no remote-writer helper (current-CPU NMI-safe enqueue only)"
+fi
+if grep -q '^void damon_report_access' "$ROOT/mm/damon/core.c" 2>/dev/null; then
+ pass "SPSC: damon_report_access() present"
+else
+ fail "SPSC: damon_report_access() missing"
+fi
+fi
+
+# ---- Section 4: Runtime smoke test ----
+echo ""
+echo "--- 7. Runtime Smoke Test (live DAMON + SPE) ---"
+
+CREATED=0
+WORK_PID=""
+NR_SAVED=""
+if [[ -f "$ADMIN/kdamonds/nr_kdamonds" ]]; then
+ NR_SAVED=$(cat "$ADMIN/kdamonds/nr_kdamonds")
+fi
+
+restore_damon_state() {
+ # Tear down only what this test created, then restore the saved
+ # number of kdamonds. A kdamond that was running before the test
+ # is never touched (section 7 skips in that case).
+ if [[ "$CREATED" == "1" ]]; then
+ echo off > "$ADMIN/kdamonds/0/state" 2>/dev/null || true
+ echo 0 > "$ADMIN/kdamonds/nr_kdamonds" 2>/dev/null || true
+ if [[ -n "$NR_SAVED" && "$NR_SAVED" -gt 0 ]]; then
+ echo "$NR_SAVED" > "$ADMIN/kdamonds/nr_kdamonds" 2>/dev/null || true
+ fi
+ fi
+ if [[ -n "$WORK_PID" ]]; then
+ kill "$WORK_PID" 2>/dev/null || true
+ wait "$WORK_PID" 2>/dev/null || true
+ WORK_PID=""
+ fi
+}
+trap restore_damon_state EXIT
+
+if [[ -z "$NR_SAVED" ]]; then
+ skip "runtime smoke" "DAMON admin interface not available"
+elif [[ "$NR_SAVED" -gt 0 ]]; then
+ skip "runtime smoke" "existing kdamonds present (nr_kdamonds=$NR_SAVED);" \
+ "refusing to disturb them"
+elif [[ ! -d "/sys/bus/event_source/devices/$PMU_NAME" ]]; then
+ skip "runtime smoke" "no $PMU_NAME PMU (kernel without ARM SPE or not booted with it)"
+else
+ SPE_TYPE=$(cat "/sys/bus/event_source/devices/$PMU_NAME/type")
+ pass "SPE PMU $PMU_NAME present (type=$SPE_TYPE)"
+ DMESG_LINES_BEFORE=$(dmesg 2>/dev/null | wc -l)
+
+ # Keep a userspace memory workload alive as both the DAMON target and
+ # an SPE data source. The EXIT trap owns and terminates only this PID.
+ dd if=/dev/zero of=/dev/null bs=1M 2>/dev/null &
+ WORK_PID=$!
+
+ # arm_spe_pmu_event_init() rejects freq mode, so the event must be
+ # configured in period mode.
+ echo 1 > "$ADMIN/kdamonds/nr_kdamonds"
+ CREATED=1
+ echo 1 > "$ADMIN/kdamonds/0/contexts/nr_contexts"
+ echo 1 > "$ADMIN/kdamonds/0/contexts/0/targets/nr_targets"
+ echo "$WORK_PID" > "$ADMIN/kdamonds/0/contexts/0/targets/0/pid_target"
+ echo 1 > "$ADMIN/kdamonds/0/contexts/0/monitoring_attrs/sample/perf_events/nr_perf_events"
+ echo "$SPE_TYPE" > "$ADMIN/kdamonds/0/contexts/0/monitoring_attrs/sample/perf_events/0/type"
+ echo 0 > "$ADMIN/kdamonds/0/contexts/0/monitoring_attrs/sample/perf_events/0/freq"
+ echo 256 > "$ADMIN/kdamonds/0/contexts/0/monitoring_attrs/sample/perf_events/0/sample_period"
+ echo 3 > "$ADMIN/kdamonds/0/contexts/0/monitoring_attrs/sample/perf_events/0/config"
+ PE="$ADMIN/kdamonds/0/contexts/0/monitoring_attrs/sample/perf_events"
+ FREQ_VAL=$(cat "$PE/0/freq" 2>/dev/null || true)
+ if [[ "$FREQ_VAL" == "0" ]]; then
+ pass "SPE event in period mode (freq=0, period=256)"
+ else
+ fail "SPE event must use period mode (freq=0), read back $FREQ_VAL"
+ fi
+
+ STATS="/sys/kernel/debug/damon/perf_stats"
+ if [[ -r "$STATS" ]]; then
+ cp "$STATS" "$RESULTS_DIR/perf_stats-before.log"
+ fi
+
+ echo on > "$ADMIN/kdamonds/0/state"
+ sleep 5
+
+ STATE_NOW=$(cat "$ADMIN/kdamonds/0/state" 2>/dev/null || true)
+ if [[ "$STATE_NOW" == "on" ]]; then
+ pass "kdamond with SPE event is running"
+ else
+ fail "kdamond with SPE event failed to start (state=$STATE_NOW)"
+ fi
+
+ if [[ -r "$STATS" && -f "$RESULTS_DIR/perf_stats-before.log" ]]; then
+ cp "$STATS" "$RESULTS_DIR/perf_stats-running.log"
+ fi
+
+ # Stop explicitly so the final snapshot covers disable -> AUX drain ->
+ # SPSC ring drain, rather than leaving that path to the EXIT trap.
+ echo off > "$ADMIN/kdamonds/0/state"
+ for _ in $(seq 1 50); do
+ [[ "$(cat "$ADMIN/kdamonds/0/state" 2>/dev/null || true)" == "off" ]] && break
+ sleep 0.1
+ done
+ STATE_NOW=$(cat "$ADMIN/kdamonds/0/state" 2>/dev/null || true)
+ if [[ "$STATE_NOW" == "off" ]]; then
+ pass "kdamond stopped after final drain"
+ else
+ fail "kdamond did not stop (state=$STATE_NOW)"
+ fi
+
+ # Check only messages added during this run, not stale boot history.
+ DMESG_AFTER="$RESULTS_DIR/dmesg-after.log"
+ dmesg 2>/dev/null > "$DMESG_AFTER" || true
+ DMESG_LINES_AFTER=$(wc -l < "$DMESG_AFTER")
+ if [[ "$DMESG_LINES_AFTER" -ge "$DMESG_LINES_BEFORE" ]]; then
+ NEW_DMESG=$(tail -n "+$((DMESG_LINES_BEFORE + 1))" "$DMESG_AFTER")
+ else
+ NEW_DMESG=$(cat "$DMESG_AFTER")
+ fi
+ FAIL_LINES=$(printf '%s\n' "$NEW_DMESG" | \
+ grep -Ei "damon-perf.*(fail|warn|error)|WARNING:|BUG:|Oops:|lockdep" || true)
+ if [[ -n "$FAIL_LINES" ]]; then
+ fail "no damon-perf failures in dmesg"
+ echo "$FAIL_LINES" | sed 's/^/ /'
+ else
+ pass "no damon-perf failures in dmesg"
+ fi
+
+ if [[ -r "$STATS" && -f "$RESULTS_DIR/perf_stats-before.log" ]]; then
+ cp "$STATS" "$RESULTS_DIR/perf_stats-final.log"
+ pass "debugfs perf_stats readable"
+
+ stat_value() {
+ awk -v name="$2" '$1 == name { print $2; exit }' "$1"
+ }
+ for counter in callback valid enqueue dequeue match update; do
+ before=$(stat_value "$RESULTS_DIR/perf_stats-before.log" "$counter")
+ after=$(stat_value "$RESULTS_DIR/perf_stats-final.log" "$counter")
+ if [[ "$before" =~ ^[0-9]+$ && "$after" =~ ^[0-9]+$ ]]; then
+ delta=$((after - before))
+ else
+ delta=""
+ fi
+ if [[ "$delta" =~ ^[0-9]+$ && "$delta" -gt 0 ]]; then
+ pass "AUX pipeline: $counter delta=$delta"
+ else
+ fail "AUX pipeline: expected positive $counter delta, got ${delta:-missing}"
+ fi
+ done
+
+ enqueue_before=$(stat_value "$RESULTS_DIR/perf_stats-before.log" enqueue)
+ enqueue_final=$(stat_value "$RESULTS_DIR/perf_stats-final.log" enqueue)
+ dequeue_before=$(stat_value "$RESULTS_DIR/perf_stats-before.log" dequeue)
+ dequeue_final=$(stat_value "$RESULTS_DIR/perf_stats-final.log" dequeue)
+ enqueue_delta=$((enqueue_final - enqueue_before))
+ dequeue_delta=$((dequeue_final - dequeue_before))
+ if [[ "$enqueue_delta" -eq "$dequeue_delta" ]]; then
+ pass "final ring closure: enqueue=$enqueue_delta dequeue=$dequeue_delta"
+ else
+ fail "final ring closure: enqueue=$enqueue_delta dequeue=$dequeue_delta"
+ fi
+ else
+ fail "debugfs perf_stats unavailable; cannot validate AUX data path"
+ fi
+ # Cleanup happens in the EXIT trap (restore_damon_state).
+fi
+
+# ---- Summary ----
+echo ""
+echo "=========================================="
+echo " SUMMARY: $PASSED passed, $FAILED failed, $SKIPPED skipped"
+echo "=========================================="
+echo "Results saved to: $RESULTS_DIR"
+
+if [[ "$FAILED" -gt 0 ]]; then
+ echo "Overall: FAIL"
+ exit 1
+else
+ echo "Overall: PASS"
+ exit 0
+fi
--
2.43.0
next prev parent reply other threads:[~2026-08-16 14:23 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-16 14:22 [RFC PATCH 0/4] mm/damon/perf: add ARM SPE AUX backend Kunwu Chan
2026-08-16 14:22 ` [RFC PATCH 1/4] mm/damon/perf: introduce AUX backend interface and Kconfig Kunwu Chan
2026-08-16 14:22 ` [RFC PATCH 2/4] mm/damon/perf: add AUX trace-buffer PMU backend for ARM SPE Kunwu Chan
2026-08-16 14:22 ` [RFC PATCH 3/4] mm/damon/perf: add KUnit tests for the SPE record parser Kunwu Chan
2026-08-16 14:22 ` Kunwu Chan [this message]
2026-08-16 16:56 ` [RFC PATCH 0/4] mm/damon/perf: add ARM SPE AUX backend SJ Park
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260816142222.689624-5-kunwu.chan@linux.dev \
--to=kunwu.chan@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=damon@lists.linux.dev \
--cc=kunwu.chan@linux.dev \
--cc=lianux.mm@gmail.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=shuah@kernel.org \
--cc=sj@kernel.org \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.