summaryrefslogtreecommitdiff
path: root/tools/perf/tests/shell/test_mem_phys_addr_python.sh
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2026-09-25 23:19:44 -0700
committerArnaldo Carvalho de Melo <acme@redhat.com>2026-09-26 20:49:28 +0200
commit6ceccefad0751966ec63713e2855095caf296c54 (patch)
tree68ab680e260e653069d0579130eb2e4316b2ba0e /tools/perf/tests/shell/test_mem_phys_addr_python.sh
parent4425182d426b2180e98d0b537f46cdb03078876d (diff)
downloadlinux-next-6ceccefad0751966ec63713e2855095caf296c54.tar.gz
linux-next-6ceccefad0751966ec63713e2855095caf296c54.zip
perf python: Port mem-phys-addr to perf module
Port mem-phys-addr.py to a standalone script in tools/perf/python/ using the perf.session API to read perf.data files and profile physical memory access types against /proc/iomem. Improvements compared to the legacy script: - Parse the full indentation hierarchy of /proc/iomem into a parent-child tree of frozen IomemEntry dataclasses (instead of only top-level indent-0 ranges), resolving physical addresses to the most specific sub-range (such as Kernel code/data/bss inside System RAM) and rolling child counts up into parent totals. - Support profiling multiple memory events in a single perf.data session (keyed by evsel name) instead of assuming a single global event. - Add argparse CLI options (-i/--input and --iomem to allow supplying an offline /proc/iomem snapshot from a target system). Add a shell test (test_mem_phys_addr_python.sh) to verify the standalone script. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers <irogers@google.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/tests/shell/test_mem_phys_addr_python.sh')
-rwxr-xr-xtools/perf/tests/shell/test_mem_phys_addr_python.sh102
1 files changed, 102 insertions, 0 deletions
diff --git a/tools/perf/tests/shell/test_mem_phys_addr_python.sh b/tools/perf/tests/shell/test_mem_phys_addr_python.sh
new file mode 100755
index 000000000000..d094a0611a24
--- /dev/null
+++ b/tools/perf/tests/shell/test_mem_phys_addr_python.sh
@@ -0,0 +1,102 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# mem-phys-addr python test
+
+set -e
+
+shelldir=$(dirname "$0")
+# shellcheck source=lib/setup_python.sh
+. "${shelldir}"/lib/setup_python.sh
+
+# If we don't have the perf python module, we can't test
+if ! "$PYTHON" -c 'import perf' > /dev/null 2>&1; then
+ echo "Skipping test, perf python module not found"
+ exit 2
+fi
+
+script_dir="$(dirname "$0")/../../python"
+script_path="${script_dir}/mem-phys-addr.py"
+
+if [ ! -f "$script_path" ]; then
+ echo "Skipping test, mem-phys-addr.py not found at $script_path"
+ exit 2
+fi
+
+err=0
+temp_data=""
+temp_iomem=""
+temp_out=""
+
+cleanup() {
+ rm -f "${temp_data}" "${temp_iomem}" "${temp_out}"
+}
+
+trap 'cleanup' EXIT TERM INT
+
+temp_data=$(mktemp /tmp/perf.data.XXXXXX)
+temp_iomem=$(mktemp /tmp/perf.iomem.XXXXXX)
+temp_out=$(mktemp /tmp/perf.out.XXXXXX)
+
+cat << 'EOF' > "${temp_iomem}"
+00000000-ffffffffffffffff : System RAM
+ 00000000-7fffffffffffffff : Low RAM
+ 00001000-00ffffff : Kernel code
+ 8000000000000000-ffffffffffffffff : High RAM
+EOF
+
+test_iomem_hierarchy() {
+ echo "Testing mem-phys-addr.py hierarchical iomem resolution..."
+ "$PYTHON" - "$script_path" "${temp_iomem}" << 'PYEOF' > "${temp_out}"
+import importlib.util
+import sys
+
+spec = importlib.util.spec_from_file_location("mem_phys_addr", sys.argv[1])
+mod = importlib.util.module_from_spec(spec)
+sys.modules[spec.name] = mod
+spec.loader.exec_module(mod)
+
+mod.parse_iomem(sys.argv[2])
+entry_kernel = mod.find_memory_type(0x100000)
+entry_high = mod.find_memory_type(0x9000000000000000)
+assert entry_kernel is not None and entry_kernel.label == "Kernel code"
+assert entry_high is not None and entry_high.label == "High RAM"
+mod.event_counts["cpu/mem-loads/"][entry_kernel] += 3
+mod.event_counts["cpu/mem-loads/"][entry_high] += 1
+mod.print_memory_type()
+PYEOF
+ if ! grep -q "System RAM" "${temp_out}" || \
+ ! grep -q "Kernel code" "${temp_out}" || \
+ ! grep -q "High RAM" "${temp_out}"; then
+ echo "Hierarchical iomem resolution test failed."
+ err=1
+ else
+ echo "Hierarchical iomem resolution test passed."
+ fi
+}
+
+test_file_mode() {
+ echo "Testing mem-phys-addr.py file mode..."
+
+ # Generate memory access events (try unprivileged user-space first, then system-wide)
+ if ! perf record --phys-data -d -o "${temp_data}" \
+ -- perf test -w datasym >/dev/null 2>&1 && \
+ ! perf record -d -o "${temp_data}" -- perf test -w datasym >/dev/null 2>&1 && \
+ ! perf record -d -a -o "${temp_data}" -- sleep 0.2 >/dev/null 2>&1; then
+ echo "Skipping file mode record test, perf record -d not supported"
+ return 0
+ fi
+
+ # Run the script with custom --iomem
+ if ! "$PYTHON" "$script_path" -i "${temp_data}" --iomem "${temp_iomem}" > "${temp_out}" || \
+ [ ! -s "${temp_out}" ]; then
+ echo "File mode test failed."
+ err=1
+ else
+ echo "File mode test passed."
+ fi
+}
+
+test_iomem_hierarchy
+test_file_mode
+
+exit $err