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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox