news 2026/9/10 5:26:39

Marvell Odyssey DDR PMU:Linux perf 框架下的 DDR 子系统性能监控驱动解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Marvell Odyssey DDR PMU:Linux perf 框架下的 DDR 子系统性能监控驱动解析

Marvell Odyssey DDR PMU:Linux perf 框架下的 DDR 子系统性能监控驱动解析

【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux

本文以 Linux 内核文档 mrvl-odyssey-ddr-pmu.rst 为主体,讲解 Marvell Odyssey SoC 中 DRAM Subsystem(DSS)性能监控单元(PMU UNCORE)的事件体系、sysfs 暴露方式与 perf 使用方法,并结合驱动源码 marvell_cn10k_ddr_pmu.c 深入剖析 8 个可编程计数器与 2 个固定计数器的编程模型、事件位图映射、manual/auto 运行模式以及溢出处理机制,帮助读者在 Odyssey 平台上完成 DDR 带宽、调度争用、刷新与低功耗状态等指标的量化测量。

1. DSS PMU 硬件模型:三个观测面、十路计数器

根据文档描述,Odyssey 的 DRAM 子系统(DSS)提供8 个可编程性能计数器,软件可以将这些计数器编程为监控任意已定义的性能事件。这些事件的统计位置覆盖 DDR 数据通路上的三个关键观测面:

  • DFI 接口(DDR 控制器与 PHY 之间):反映真正流向内存颗粒的读/写数据访问、DFI 总线周期、错误与重试等;
  • HIF 接口(DDR 控制器与 CHI 互连之间):反映来自 SoC 互连的请求访问、读改写(RMW)、高低优先级调度等;
  • DDR 控制器内部(CAM 等模块):反映 activate/precharge/read/write 等行级操作、读写转换、RAW/WAR/WAW 冒险、写合并等调度细节。

此外,DSS 还提供2 个固定性能事件计数器:一个统计 DDR 读(ddr reads),一个统计 DDR 写(ddr writes),无需编程即可自由运行(free-run)。这一硬件结构在驱动中体现为明确的常量定义(marvell_cn10k_ddr_pmu.c):

/* 8 Generic event counter + 2 fixed event counters */ #define DDRC_PERF_NUM_GEN_COUNTERS 8 #define DDRC_PERF_NUM_FIX_COUNTERS 2 #define DDRC_PERF_READ_COUNTER_IDX DDRC_PERF_NUM_GEN_COUNTERS #define DDRC_PERF_WRITE_COUNTER_IDX (DDRC_PERF_NUM_GEN_COUNTERS + 1) #define DDRC_PERF_NUM_COUNTERS (DDRC_PERF_NUM_GEN_COUNTERS + \ DDRC_PERF_NUM_FIX_COUNTERS)

文档还指出,计数器可工作在manual(手动)或 auto(自动)模式:manual 模式下由驱动显式 start/stop 控制计数窗口,auto 模式则允许硬件在到达溢出值后自行回卷。从源码看,Odyssey 与 CN20K 变体走的是"手动启用 + 溢出后 stop/start 复位"的路径(见第 5 节的溢出处理),而 CN10K 变体在 probe 阶段整体切到 manual 模式。

2. 驱动注册与平台数据:为什么 sysfs 设备名是 mrvl_ddr_pmu_<地址>

该驱动是一个平台驱动,统一服务于 CN10K、Odyssey 与 CN20K 三个 SoC 变体,通过设备匹配数据区分(marvell_cn10k_ddr_pmu.c):

/* SoC variant flags for struct ddr_pmu_platform_data (mutually exclusive in pdata) */ #define IS_CN10K BIT(0) #define IS_ODY BIT(1) #define IS_CN20K BIT(2)

匹配表定义了两种发现路径(marvell_cn10k_ddr_pmu.c):

变体Device Tree compatibleACPI HID
CN10Kmarvell,cn10k-ddr-pmuMRVL000A
CN20Kmarvell,cn20k-ddr-pmuMRVL000B
Odyssey—(仅 ACPI)MRVL000C

值得注意的是,Odyssey 变体的平台数据只在CONFIG_ACPI下定义odyssey_ddr_pmu_pdata,marvell_cn10k_ddr_pmu.c),说明当前代码中 Odyssey 平台以 ACPI 固件描述 DDR 控制器寄存器区域。probe 阶段完成以下关键动作(cn10k_ddr_perf_probe):

  1. devm_platform_get_and_ioremap_resource(pdev, 0, &res)映射 DDR 控制器的 MMIO 基址;
  2. 依据silicon_flags选择对应变体的struct ddr_pmu_ops回调与 sysfs attr_groups(Odyssey 使用odyssey_attr_groups);
  3. 以寄存器区域起始地址命名 PMU:name = "mrvl_ddr_pmu_%llx"(res->start),并通过perf_pmu_register(&ddr_pmu->pmu, name, -1)注册。

这解释了文档中 sysfs 路径里mrvl_ddr_pmu_<>占位符的由来——<>就是 DDR 控制器 MMIO 基址的十六进制值,例如基址为0x6820_0000的系统上会出现/sys/bus/event_source/devices/mrvl_ddr_pmu_68200000/

每个变体的寄存器布局由struct ddr_pmu_platform_data描述(marvell_cn10k_ddr_pmu.c),它保存计数器值基址、事件配置基址、op-mode/start/end 控制寄存器、freerun 控制与固定计数器值寄存器等偏移。Odyssey 专属的寄存器偏移汇总如下(取自 marvell_cn10k_ddr_pmu.c、[L153-L178] 中的ODY_*定义):

寄存器偏移用途
ODY_DDRC_PERF_CNT_OP_MODE_CTRL0x20020计数器运行模式控制(manual=0x1)
ODY_DDRC_PERF_CNT_START_OP_CTRL0x200A0计数器启动操作控制(写 0x1 启动)
ODY_DDRC_PERF_CNT_END_OP_CTRL0x200E0计数器结束操作控制(写 0x1 停止)
ODY_DDRC_PERF_CNT_END_STATUS0x20120结束状态寄存器
ODY_DDRC_PERF_CFG_BASE0x20160事件配置寄存器基址(每计数器 8 字节)
ODY_DDRC_PERF_CNT_VALUE_BASE0x201C0计数器值寄存器基址(每计数器 8 字节)
ODY_DDRC_PERF_CNT_FREERUN_CTRL0x20240固定计数器使能/清除控制
ODY_DDRC_PERF_CNT_FREERUN_CLR0x20248固定计数器清除寄存器(Odyssey 独有)
ODY_DDRC_PERF_CNT_VALUE_WR_OP0x20250DDR 写固定计数器值
ODY_DDRC_PERF_CNT_VALUE_RD_OP0x20258DDR 读固定计数器值

3. 事件暴露:sysfs 的 events/ 与 format/ 目录

PMU 驱动通过 attribute_group 在 sysfs 下暴露可用事件与格式选项(文档原文路径):

/sys/bus/event_source/devices/mrvl_ddr_pmu_<>/events/ /sys/bus/event_source/devices/mrvl_ddr_pmu_<>/format/
  • events/目录下每个文件对应一个具名事件,内容形如event=0x10(由 cn10k_ddr_pmu_event_show 输出),数值即事件 ID;
  • format/目录下只有一个event文件,定义为config:0-8(marvell_cn10k_ddr_pmu.c),即事件 ID 编码在perf_event_attr.config的低 8 位。
PMU_FORMAT_ATTR(event, "config:0-8"); static struct attribute *cn10k_ddr_perf_format_attrs[] = { &format_attr_event.attr, NULL, };

Odyssey 变体的具名事件表为odyssey_ddr_perf_events_attrs(marvell_cn10k_ddr_pmu.c),通过宏CN10K_DDR_PMU_EVENT_ATTR(_name, _id)将 sysfs 事件名与硬件事件 ID 绑定。文档给出的perf list | grep ddr完整输出如下(mrvl_ddr_pmu_<>/为 PMU 前缀):

$ perf list | grep ddr mrvl_ddr_pmu_<>/ddr_act_bypass_access/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_bsm_alloc/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_bsm_starvation/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_cam_active_access/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_cam_mwr/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_cam_rd_active_access/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_cam_rd_or_wr_access/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_cam_read/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_cam_wr_access/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_cam_write/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_capar_error/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_crit_ref/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_ddr_reads/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_ddr_writes/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_dfi_cmd_is_retry/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_dfi_cycles/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_dfi_parity_poison/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_dfi_rd_data_access/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_dfi_wr_data_access/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_dqsosc_mpc/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_dqsosc_mrr/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_enter_mpsm/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_enter_powerdown/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_enter_selfref/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_hif_pri_rdaccess/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_hif_rd_access/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_hif_rd_or_wr_access/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_hif_rmw_access/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_hif_wr_access/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_hpri_sched_rd_crit_access/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_load_mode/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_lpri_sched_rd_crit_access/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_precharge/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_precharge_for_other/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_precharge_for_rdwr/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_raw_hazard/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_rd_bypass_access/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_rd_crc_error/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_rd_uc_ecc_error/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_rdwr_transitions/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_refresh/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_retry_fifo_full/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_spec_ref/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_tcr_mrr/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_war_hazard/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_waw_hazard/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_win_limit_reached_rd/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_win_limit_reached_wr/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_wr_crc_error/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_wr_trxn_crit_access/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_write_combine/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_zqcl/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_zqlatch/ [Kernel PMU event] mrvl_ddr_pmu_<>/ddr_zqstart/ [Kernel PMU event]

按观测面归类,这些事件可分为几组实用指标:

  • 带宽/数据量ddr_ddr_readsddr_ddr_writes(固定计数器),ddr_dfi_rd_data_access/ddr_dfi_wr_data_access(DFI 侧真实数据访问),ddr_hif_rd_or_wr_access(HIF 侧请求量);
  • 调度与争用ddr_raw_hazardddr_war_hazardddr_waw_hazard(RAW/WAR/WAW 冒险)、ddr_rdwr_transitions(读写切换次数)、ddr_write_combine(写合并)、ddr_bsm_alloc/ddr_bsm_starvation(BSM 分配与饥饿);
  • 刷新与训练ddr_refreshddr_crit_refddr_spec_refddr_load_modeddr_zqcl/ddr_zqstart/ddr_zqlatch/ddr_tcr_mrr/ddr_dqsosc_mrr/ddr_dqsosc_mpc(ZQ 校准与 DQOSC 训练类操作);
  • 低功耗状态ddr_enter_selfrefddr_enter_powerdownddr_enter_mpsm(进入自刷新/掉电/MPSM 的次数);
  • 质量与错误ddr_rd_crc_errorddr_wr_crc_errorddr_capar_errorddr_rd_uc_ecc_errorddr_dfi_parity_poisonddr_dfi_cmd_is_retryddr_retry_fifo_fullddr_dfi_cycles
  • 控制器行级操作ddr_cam_active_accessddr_cam_rd_active_accessddr_cam_rd_or_wr_accessddr_cam_readddr_cam_writeddr_cam_mwrddr_cam_wr_accessddr_precharge*等。

4. 事件 ID 到硬件位图的映射

事件 ID 是写入硬件事件位图的选择码。驱动源码中保留了全部可编程事件的 ID 定义(marvell_cn10k_ddr_pmu.c),并特别注释"这些 event-id 编号不得改动,它们用于编程硬件事件位图"。Odyssey 相关的常用 ID 摘录:

事件名(sysfs)事件 ID 宏
ddr_hif_rd_or_wr_accessEVENT_HIF_RD_OR_WR1
ddr_hif_wr_accessEVENT_HIF_WR2
ddr_hif_rd_accessEVENT_HIF_RD3
ddr_hif_rmw_accessEVENT_HIF_RMW4
ddr_hif_pri_rdaccessEVENT_HIF_HI_PRI_RD5
ddr_rd_bypass_accessEVENT_READ_BYPASS6
ddr_act_bypass_accessEVENT_ACT_BYPASS7
ddr_dfi_wr_data_accessEVENT_DFI_WR_DATA_CYCLES8
ddr_dfi_rd_data_accessEVENT_DFI_RD_DATA_CYCLES9
ddr_hpri_sched_rd_crit_accessEVENT_HPR_XACT_WHEN_CRITICAL10
ddr_lpri_sched_rd_crit_accessEVENT_LPR_XACT_WHEN_CRITICAL11
ddr_wr_trxn_crit_accessEVENT_WR_XACT_WHEN_CRITICAL12
ddr_cam_active_accessEVENT_OP_IS_ACTIVATE13
ddr_cam_rd_or_wr_accessEVENT_OP_IS_RD_OR_WR14
ddr_cam_rd_active_accessEVENT_OP_IS_RD_ACTIVATE15
ddr_cam_readEVENT_OP_IS_RD16
ddr_cam_writeEVENT_OP_IS_WR17
ddr_cam_mwrEVENT_OP_IS_MWR18
ddr_prechargeEVENT_OP_IS_PRECHARGE19
ddr_enter_selfrefEVENT_OP_IS_ENTER_SELFREF27
ddr_enter_powerdownEVENT_OP_IS_ENTER_POWERDOWN31
ddr_enter_mpsmEVENT_OP_IS_ENTER_MPSM35
ddr_refreshEVENT_OP_IS_REFRESH39
ddr_crit_refEVENT_OP_IS_CRIT_REF40
ddr_spec_refEVENT_OP_IS_SPEC_REF41
ddr_load_modeEVENT_OP_IS_LOAD_MODE42
ddr_zqclEVENT_OP_IS_ZQCL43
ddr_dqsosc_mpcEVENT_OP_IS_DQSOSC_MPC51
ddr_dqsosc_mrrEVENT_OP_IS_DQSOSC_MRR52
ddr_tcr_mrrEVENT_OP_IS_TCR_MRR53
ddr_zqstartEVENT_OP_IS_ZQSTART54
ddr_zqlatchEVENT_OP_IS_ZQLATCH55
ddr_dfi_parity_poisonEVENT_DFI_PARITY_POISON56
ddr_wr_crc_errorEVENT_WR_CRC_ERROR57
ddr_capar_errorEVENT_CAPAR_ERROR58
ddr_rd_crc_errorEVENT_RD_CRC_ERROR59
ddr_rd_uc_ecc_errorEVENT_RD_UC_ECC_ERROR60
ddr_dfi_cmd_is_retryEVENT_DFI_CMD_IS_RETRY61
ddr_dfi_cyclesEVENT_DFI_CYCLES45
ddr_retry_fifo_fullEVENT_RETRY_FIFO_FULL46
ddr_bsm_allocEVENT_BSM_ALLOC47
ddr_bsm_starvationEVENT_BSM_STARVATION48
ddr_win_limit_reached_rdEVENT_VISIBLE_WIN_LIMIT_REACHED_RD49
ddr_win_limit_reached_wrEVENT_VISIBLE_WIN_LIMIT_REACHED_WR50
ddr_ddr_reads(固定计数器)EVENT_DDR_READS101
ddr_ddr_writes(固定计数器)EVENT_DDR_WRITES100

映射函数 ddr_perf_get_event_bitmap 将事件 ID 转换为硬件位图,其中有两个特殊分支值得注意:

  1. 常规事件:位图为单 bit,*event_bitmap = (1ULL << (eventid - 1)),即事件 ID 直接对应硬件事件选择寄存器的第eventid-1位;
  2. 低功耗进入事件EVENT_OP_IS_ENTER_SELFREF/ENTER_POWERDOWN/ENTER_MPSM对应位图(0xFULL << (eventid - 1)),即这些事件在硬件中占用 4 个连续位(对应每通道/每 rank 的进入指示),驱动会把 4 个 bit 一起置起再写入选件配置寄存器;
  3. ID 冲突消解:事件 ID 58~61 在 CN20K 上被"perf width"事件(ddr_read16/32ddr_write16/32)占用,与 Odyssey 的 DFI 错误事件同名段。ddr_perf_get_event_bitmap依据silicon_flagsIS_CN20K/IS_ODY)区分两条路径,两者最终都落到1ULL << (eventid - 1)的同一位图规则,从而避免同一数值 ID 跨变体误编程。

固定计数器不使用事件位图:cn10k_ddr_perf_alloc_counter(marvell_cn10k_ddr_pmu.c)中,config == EVENT_DDR_READS(101)直接绑定到索引 8 的读计数器,EVENT_DDR_WRITES(100)绑定到索引 9 的写计数器;其余事件按先到先占分配 8 个通用计数器槽位,槽满则返回-ENOENT(对 perf 表现为分配失败-EAGAIN)。

5. 计数生命周期:从 perf stat 到寄存器操作

5.1 事件初始化约束

cn10k_ddr_perf_event_init 对事件施加了三点约束,使用 perf 时应知晓:

  • 不支持采样is_sampling_event(event)为真时直接返回-EOPNOTSUPP并打印 "Sampling not supported!"。该 PMU 只做计数(counting),不能做采样(sampling),因此只能用perf stat,不能用perf record -e mrvl_ddr_pmu_xxx/...
  • 不支持 per-task:要求事件绑定 CPU(event->cpu < 0时拒绝),并把事件所有权固定到 PMU 所在的 CPU(event->cpu = pmu->cpu),"同一事件不能同时在多个 CPU 上被观测";
  • 禁止跨 PMU 混组:group leader 与其他 PMU 混合会返回-EINVAL

5.2 事件 add 流程(编程计数器)

cn10k_ddr_perf_event_add 完成了文档所说"软件可以编程这些计数器"的全部寄存器操作:

  1. 分配计数器槽位(固定计数器直配索引 8/9,通用计数器空闲槽优先);
  2. 首个事件添加时启动高精度轮询定时器(hrtimer_start,周期由poll_period_sec决定);
  3. 通用计数器:调用ddr_perf_get_event_bitmap得到事件位图后写入DDRC_PERF_CFG(cfg_base, counter)(基址 + 8×counter),即把事件选择与计数器编号绑定;
  4. 固定计数器:调用变体 ops 的 clear 回调清零(Odyssey 写ODY_DDRC_PERF_CNT_FREERUN_CLR的读/写清除位,见 ddr_pmu_ody_read_clear_freerun)。

5.3 start/stop 与 manual 模式

cn10k_ddr_perf_counter_enable 实现了文档提到的 manual/auto 两种运行模式下的使能逻辑:

  • 通用计数器先读改写配置寄存器的高位EVENT_ENABLEBIT_ULL(63));
  • IS_ODYIS_CN20K:enable 时向ODY_DDRC_PERF_CNT_OP_MODE_CTRL偏移的 op-mode 寄存器写入OP_MODE_CTRL_VAL_MANUAL(0x1),随后向 start-op 寄存器写START_OP_CTRL_VAL_START(0x1)启动计数;disable 时写 end-op 寄存器END_OP_CTRL_VAL_END(0x1)停止。也就是说Odyssey 的计数窗口完全由驱动手动开关
  • 固定计数器走变体 ops:Odyssey 的读/写 free-run 使能位位于ODY_DDRC_PERF_CNT_FREERUN_CTRL(bit0=写、bit1=读,见 ddr_pmu_ody_enable_read_freerun),与 CN10K 使用独立FREERUN_EN寄存器的做法不同。

5.4 周期性读取与溢出处理

计数器读取并非只在事件 stop 时发生。驱动用一个 hrtimer 周期性(默认 100 秒)调用 cn10k_ddr_pmu_overflow_handler,源码注释解释了默认值的选择依据:"48 位计数器在最高 5.6 GT/s 下以最大速率增长,溢出可能需要数小时",100 秒的轮询足以避免读数丢失:

static unsigned long cn10k_ddr_pmu_poll_period_sec = 100; module_param_named(poll_period_sec, cn10k_ddr_pmu_poll_period_sec, ulong, 0644);

该轮询周期是模块参数,可在加载模块时调整:modprobe marvell_cn10k_ddr_pmu poll_period_sec=10。溢出处理逻辑分两类:

  • 固定计数器(读/写 free-run):新读数小于旧读数视为回卷,更新累加值;
  • 通用计数器:读数达到counter_max_val时触发变体溢出回调。Odyssey 的实现 ddr_pmu_ody_overflow_hander 注释说明:计数器到达最大值后会冻结在该值,驱动先更新该事件的累计值,再对该计数器执行 stop + start,使其从 0 重新开始计数;
  • 每次读数通过 cn10k_ddr_perf_event_update 以 CAS 方式(local64_xchg循环)无锁地把硬件增量按counter_max_val掩码累加进event->count

Odyssey 的计数器位宽体现在平台数据counter_max_val = GENMASK_ULL(63, 0)(64 位全值域,marvell_cn10k_ddr_pmu.c),而 CN10K 为 49 位(GENMASK_ULL(48, 0),溢出值BIT_ULL(48))。

5.5 CPU 迁移

PMU 是全局(uncore)设备,其"宿主 CPU"在 probe 时取raw_smp_processor_id()。当该 CPU 下线时,cn10k_ddr_pmu_offline_cpu 通过 CPU hotplug 回调perf_pmu_migrate_context把事件上下文迁到任一仍在线的 CPU 上,保证持续测量不因核下线而中断。

6. 实战:用 perf 测量 DDR 事件

文档给出的标准用法即perf list过滤 +perf stat计数。在 Odyssey 系统上,先确认 PMU 已注册:

$ ls /sys/bus/event_source/devices/ | grep mrvl_ddr_pmu mrvl_ddr_pmu_<hex基址> $ cat /sys/bus/event_source/devices/mrvl_ddr_pmu_<hex基址>/cpumask

cpumask属性(cn10k_ddr_perf_cpumask_show)显示当前 PMU 事件被绑定到的 CPU。

文档示例:统计 CAM 侧的读/写/激活/转换类事件

$ perf stat -e ddr_cam_read,ddr_cam_write,ddr_cam_active_access,ddr_cam_rd_or_wr_access,ddr_cam_rd_active_access,ddr_cam_mwr <workload>

典型组合测量思路(均为文档中已暴露事件,可自由组合,但通用事件同批最多 8 个):

# 1. 总 DDR 读/写量(两个固定计数器,可同时启用,不占用通用计数器) $ perf stat -e mrvl_ddr_pmu_x/ / : ddr_ddr_reads,ddr_ddr_writes <workload> # 2. HIF 侧请求量 + 读改写 $ perf stat -e ddr_hif_rd_or_wr_access,ddr_hif_rmw_access <workload> # 3. DFI 侧真实数据访问,评估控制器效率(HIF 请求 / DFI 数据 比值) $ perf stat -e ddr_dfi_rd_data_access,ddr_dfi_wr_data_access <workload> # 4. 调度健康度:读写切换、冒险、可见窗口限制 $ perf stat -e ddr_rdwr_transitions,ddr_raw_hazard,ddr_war_hazard,ddr_waw_hazard \ ddr_win_limit_reached_rd,ddr_win_limit_reached_wr <workload> # 5. 刷新/训练开销与低功耗进入频次 $ perf stat -e ddr_refresh,ddr_spec_ref,ddr_crit_ref,ddr_enter_selfref, ddr_enter_powerdown,ddr_enter_mpsm <workload> # 6. 链路质量:CRC/ECC/奇偶错误与重试 $ perf stat -e ddr_rd_crc_error,ddr_wr_crc_error,ddr_capar_error, ddr_rd_uc_ecc_error,ddr_dfi_parity_poison,ddr_dfi_cmd_is_retry, ddr_retry_fifo_full,ddr_dfi_cycles <workload>

注意约束:由于不支持采样与 per-task,上述测量只能得到整机(per-CPU 绑定 PMU 宿主 CPU)维度的计数;事件名在perf stat -e中可用短名(如ddr_cam_read),也可写成完整的mrvl_ddr_pmu_<>/ddr_cam_read/形式。若同批通用事件超过 8 个,驱动将返回分配失败,需要分批测量。

7. 构建与部署

内核配置项定义在 drivers/perf/Kconfig:

config MARVELL_CN10K_DDR_PMU tristate "Enable MARVELL CN10K DRAM Subsystem(DSS) PMU Support" depends on ARCH_THUNDER || (COMPILE_TEST && 64BIT) help Enable perf support for Marvell DDR Performance monitoring event on CN10K platform.

即在 Thunder(ARM64 64 位)架构下启用CONFIG_MARVELL_CN10K_DDR_PMU(y/m),drivers/perf/Makefile 中对应obj-$(CONFIG_MARVELL_CN10K_DDR_PMU) += marvell_cn10k_ddr_pmu.o。Odyssey 平台通过 ACPI 表(HIDMRVL000C)描述 DDR 控制器 MMIO 区域,驱动 probe 后在 dmesg 中打印DDR PMU Driver for ddrc@<基址>,此时即可按第 6 节的方法使用 perf 工具链。

8. 小结

  • Odyssey DSS PMU 提供 8 路可编程 + 2 路固定(读/写)计数器,事件覆盖 DFI、HIF 与控制器内部三个观测面,全部经 sysfsevents/format/目录对 perf 框架暴露;
  • 事件 ID 编码于perf_event_attr.config:0-8;驱动把 ID 翻译成硬件事件位图(低功耗进入事件占 4 个连续位;58~61 段 ID 按silicon_flags区分 Odyssey/CN20K 语义);
  • Odyssey 计数器运行在 manual 模式,由驱动 start/stop 控制,配合默认 100 秒(poll_period_sec可调)的高精度定时器轮询,处理固定计数器回卷与通用计数器"冻结后 stop/start 复位"的溢出;
  • 该 PMU 仅支持计数(perf stat),不支持采样与 per-task,通用事件同批上限 8 个,这是使用该方法论做 DDR 性能剖析时的硬边界。

相关源码与文档路径:Documentation/admin-guide/perf/mrvl-odyssey-ddr-pmu.rst、drivers/perf/marvell_cn10k_ddr_pmu.c、drivers/perf/Kconfig、drivers/perf/Makefile。

【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 5:25:58

OmniPic 3.2.0:一键提取网页所有图片的浏览器扩展实操指南

1. 先搞清楚这个小工具到底解决什么问题 做前端、搞设计、或者经常在网上扒素材的朋友&#xff0c;应该都有过这种经历&#xff1a;打开一个排版很漂亮的网站&#xff0c;一眼扫过去发现里面好几张图都想要&#xff0c;但页面上一张一张右键另存为&#xff0c;存到一半又觉得太…

作者头像 李华
网站建设 2026/9/10 5:23:30

AutoHedge:面向AI服务的智能韧性治理中枢

1. AutoHedge不是“自动对冲”&#xff0c;而是AI工程侧的智能服务韧性中枢 AutoHedge这个词&#xff0c;乍看容易让人联想到金融领域的自动对冲策略——毕竟hedge在量化交易里太常见了。但结合当前热搜词里高频出现的Swarm、API、OpenAI、Python&#xff0c;再叠加docker swar…

作者头像 李华
网站建设 2026/9/10 5:23:06

vue-vben-admin 页面切换后出现空白页怎么排查

vue-vben-admin 页面切换后出现空白页怎么排查 【免费下载链接】vue-vben-admin A modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. Its fast! 项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin 在基于 vue-vben…

作者头像 李华
网站建设 2026/9/10 5:22:38

图数据结构核心解析:存储、遍历与最短路径算法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华