[PATCH 1/2] perf jevents: add iommu page table walk metrics
From: Jacob Lefkowitz via B4 Relay
Date: Thu Oct 29 2026 - 15:08:31 EST
From: Jacob Lefkowitz <jlefkowi@xxxxxxxxxx>
Adds page table walk metrics specfically to perf jevents for AMD
platforms to enhance observability into IOMMU overhead. The metrics
are supported on Zen 2 and neweer processors. They are implemented
using the amd_iommu PMU events.
The list of metrics added here are:
- lpm_iommu_ptw_reads_per_tlb_miss
- lpm_iommu_ptw_nested_read_ratio
- lpm_iommu_ptw_guest_read_ratio
- lpm_iommu_trans_per_sec
The changes here have been tested with 'sleep 10' as the workload:
perf stat -M iommuptw --per-socket --metric-only -j -a -- sleep 10
{"socket" : "S0", "counters" : 8,
"reads/tlb_miss lpm_iommu_ptw_reads_per_tlb_miss" : "0.5",
"% lpm_iommu_ptw_nested_read_ratio" : "100.0",
"% lpm_iommu_ptw_guest_read_ratio" : "0.0",
"trans/s lpm_iommu_trans_per_sec" : "971.5"}
{"socket" : "S1", "counters" : 0,
"reads/tlb_miss lpm_iommu_ptw_reads_per_tlb_miss" : "none",
"% lpm_iommu_ptw_nested_read_ratio" : "100.0",
"% lpm_iommu_ptw_guest_read_ratio" : "100.0",
"trans/s lpm_iommu_trans_per_sec" : "none"}
Signed-off-by: Jacob Lefkowitz <jlefkowi@xxxxxxxxxx>
---
tools/perf/pmu-events/amd_metrics.py | 49 +++++++++++++++++++++++++++++++++++-
1 file changed, 48 insertions(+), 1 deletion(-)
diff --git a/tools/perf/pmu-events/amd_metrics.py b/tools/perf/pmu-events/amd_metrics.py
index 42569b9153f4..dcffd6e268fa 100755
--- a/tools/perf/pmu-events/amd_metrics.py
+++ b/tools/perf/pmu-events/amd_metrics.py
@@ -5,7 +5,7 @@ import math
import os
from typing import Optional, Union
from common_metrics import Cycles
-from metric import (d_ratio, has_event, max, Event, JsonEncodeMetric,
+from metric import (d_ratio, has_event, max, min, Event, JsonEncodeMetric,
JsonEncodeMetricGroupDescriptions, Literal, LoadEvents,
Metric, MetricGroup, Select)
@@ -318,6 +318,52 @@ def AmdIotlb() -> Optional[MetricGroup]:
)
+def AmdIommuptw() -> Optional[MetricGroup]:
+ global _zen_model
+
+ if _zen_model < 2:
+ return None
+
+ walks = Event("amd_iommu/mem_iommu_tlb_pte_mis/") + Event(
+ "amd_iommu/mem_iommu_tlb_pde_mis/"
+ )
+ pt_rd = Event("amd_iommu/page_tbl_read_tot/")
+ pt_rd_nst = Event("amd_iommu/page_tbl_read_nst/")
+ pt_rd_gst = Event("amd_iommu/page_tbl_read_gst/")
+ trans = Event("amd_iommu/mem_trans_total/")
+
+ return MetricGroup(
+ "iommuptw",
+ [
+ Metric(
+ "lpm_iommu_ptw_reads_per_tlb_miss",
+ "Average IOMMU page table reads per IOTLB miss",
+ d_ratio(pt_rd, walks),
+ "reads/tlb_miss"
+ ),
+ Metric(
+ "lpm_iommu_ptw_nested_read_ratio",
+ "Share of IOMMU page table reads from nested (host) tables", # 0 without nested translation
+ min(d_ratio(pt_rd_nst, pt_rd), 1),
+ "100%"
+ ),
+ Metric(
+ "lpm_iommu_ptw_guest_read_ratio",
+ "Share of IOMMU page table reads from guest tables", # 0 without nested translation
+ min(d_ratio(pt_rd_gst, pt_rd), 1),
+ "100%"
+ ),
+ Metric(
+ "lpm_iommu_trans_per_sec",
+ "IOMMU translation requests per second",
+ d_ratio(trans, interval_sec),
+ "trans/s"
+ )
+ ],
+ description="IOMMU page table walk metrics"
+ )
+
+
def AmdItlb():
l2h = Event("bp_l1_tlb_miss_l2_tlb_hit", "bp_l1_tlb_miss_l2_hit")
l2m = Event("bp_l1_tlb_miss_l2_tlb_miss.all", "l2_itlb_misses",)
@@ -526,6 +572,7 @@ def main() -> None:
AmdCtxSw(),
AmdDtlb(),
AmdIotlb(),
+ AmdIommuptw(),
AmdItlb(),
AmdLdSt(),
AmdUpc(),
--
2.53.0