news 2026/9/10 12:08:47

Linux 内核 APM X-Gene SoC PMU(xgene-pmu)驱动完全指南:从 sysfs 事件到 perf 实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux 内核 APM X-Gene SoC PMU(xgene-pmu)驱动完全指南:从 sysfs 事件到 perf 实战

Linux 内核 APM X-Gene SoC PMU(xgene-pmu)驱动完全指南:从 sysfs 事件到 perf 实战

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

本指南基于 Linux 内核源码树中的 Documentation/admin-guide/perf/xgene-pmu.rst 编写,全面讲解 APM X-Gene SoC 上由xgene-pmu驱动管理的系统级 Performance Monitoring Unit(PMU):L3 缓存、I/O 桥、内存控制器桥与内存控制器四类设备。读完本文,你将掌握如何在 X-Gene 平台上用perf工具枚举 SoC 事件、配置 agent 过滤、执行perf stat系统级计数,并理解驱动在寄存器与 perf 子系统之间的底层实现机制。

X-Gene SoC PMU 概述:四类系统设备 PMU

X-Gene SoC PMU 由多个相互独立的系统设备 PMU 组成,包括L3 cache(L3C)I/O bridge(IOB)memory controller bridge(MCB)memory controller(MC)。这些 PMU 设备采用与 ARM 核 PMU 类似的松散架构模型,并共享同一个顶层中断与状态 CSR(Control/Status Register)区域——这一点在驱动代码中体现为公共的 PCPPMU 寄存器组(PCPPMU_INTSTATUS_REG/PCPPMU_INTMASK_REG,见 drivers/perf/xgene_pmu.c)。

从驱动的角度看,xgene-pmu是一个平台设备驱动,它注册的是一组独立的 perf PMU(而非单个 PMU),每个 PMU 对应一个xgene_pmu_dev实例,命名规则为l3c%diob%diob_slow%dmcb%dmc%d(见 xgene_pmu_dev_name())。

驱动支持三个硬件版本,由枚举PCP_PMU_V1 / PCP_PMU_V2 / PCP_PMU_V3区分(drivers/perf/xgene_pmu.c):

版本计数器宽度每 PMU 计数器数事件 ID 位宽(示例)匹配方式
V132 位1L3C: config 0-7DTapm,xgene-pmu/ ACPIAPMC0D5B
V232 位4L3C: config 0-7DTapm,xgene-pmu-v2/ ACPIAPMC0D5C
V364 位4L3C: config 0-39ACPIAPMC0D83

版本差异在驱动中由两套 ops 表(xgene_pmu_opsxgene_pmu_v3_ops)实现,其中 V3 使用 64 位计数器读写(两个 32 位寄存器拼接,并带进位一致性重读保护),且不再支持 agent 掩码寄存器(write_agentmsk/write_agent1msk为空实现),见 drivers/perf/xgene_pmu.c 与 drivers/perf/xgene_pmu.c。

PMU(perf)驱动与 sysfs 事件发现

xgene-pmu驱动为上述每类 PMU 注册独立的 perf 驱动,每个驱动的可用事件与配置选项通过 sysfs 暴露,目录为:

/sys/bus/event_source/devices/<l3cX/iobX/mcbX/mcX>/

目录下主要包含三类属性组(对应驱动中的 attribute group):

  • format目录:描述perf_event_attr结构中config(事件 ID)与config1(agent ID)字段的位格式;
  • events目录:提供所有受支持事件类型的配置模板,可直接用于 perf 工具;
  • cpumask属性:包含一个 CPU ID,所有 PMU 事件由该 CPU 统一处理。

例如l3c0/bank-fifo-full/等价于l3c0/config=0x0b/。在驱动中,事件模板由XGENE_PMU_EVENT_ATTR宏生成(drivers/perf/xgene_pmu.c),events目录下的每个属性实际输出config=0x%llx形式的字符串(xgene_pmu_event_show()),perf 工具读取后即自动展开为原始配置。

format 目录:config 与 config1 的位布局

驱动为 V1/V2 定义了 4 组 format 属性(drivers/perf/xgene_pmu.c):

PMUformat 属性字段布局
l3cl3c_eventidconfig:0-7
l3cl3c_agentidconfig1:0-9
iobiob_eventidconfig:0-7
iobiob_agentidconfig1:0-63
mcbmcb_eventidconfig:0-5
mcbmcb_agentidconfig1:0-9
mcmc_eventidconfig:0-28

可见:config字段存放事件 ID(各 PMU 位宽不同,如 MCB 只支持 0-5 位,即 0x00~0x05 的事件号);config1字段存放 agent 掩码,其中 IOB 使用完整的 64 位(由config1的低 32 位与高 32 位两个寄存器PMU_PMAMR0/PMU_PMAMR1承载,见 drivers/perf/xgene_pmu.c)。V3 的 format 则只暴露config事件 ID 字段,位宽显著扩大(如 L3C 为config:0-39,MC 为config:0-44),见 drivers/perf/xgene_pmu.c。

events 目录:V1/V2 事件表

以下是 V1/V2 各 PMU 在events目录下暴露的完整事件清单(对应 drivers/perf/xgene_pmu.c 中的事件数组):

l3c(L3 cache)事件:

事件名config 值含义
cycle-count0x00周期计数
cycle-count-div-640x01周期计数(除以 64)
read-hit0x02读命中
read-miss0x03读未命中
write-need-replacement0x06写操作需要替换
write-not-need-replacement0x07写操作不需要替换
tq-full0x08事务队列满
ackq-full0x09ACK 队列满
wdb-full0x0a写数据缓冲满
bank-fifo-full0x0bbank FIFO 满
odb-full0x0c出站数据缓冲满
wbq-full0x0d写回队列满
bank-conflict-fifo-issue0x0ebank 冲突 FIFO 发射
bank-fifo-issue0x0fbank FIFO 发射

iob(I/O bridge)事件:cycle-count(0x00)、cycle-count-div-64(0x01)、axi0-read(0x02)、axi0-read-partial(0x03)、axi1-read(0x04)、axi1-read-partial(0x05)、csw-read-block(0x06)、csw-read-partial(0x07)、axi0-write(0x10)、axi0-write-partial(0x11)、axi1-write(0x13)、axi1-write-partial(0x14)、csw-inbound-dirty(0x16)。

mcb(内存控制器桥)事件:cycle-count(0x00)、cycle-count-div-64(0x01)、csw-read(0x02)、csw-write-request(0x03)、mcb-csw-stall(0x04)、cancel-read-gack(0x05)。

mc(内存控制器)事件:覆盖命令发送(act-cmd-sentpre-cmd-sentrd-cmd-sentrda-cmd-sentwr-cmd-sentwra-cmd-sentpde-cmd-sentsre-cmd-sentprea-cmd-sentref-cmd-sentrd-rda-cmd-sentwr-wra-cmd-sent)、冲突(in-rd-collisionin-wr-collisioncollision-queue-not-emptycollision-queue-full)、MCU 请求(mcu-requestmcu-rd-requestmcu-hp-rd-requestmcu-wr-requestmcu-rd-proceed-allmcu-rd-proceed-cancelmcu-rd-responsemcu-rd-proceed-speculative-allmcu-rd-proceed-speculative-cancelmcu-wr-proceed-allmcu-wr-proceed-cancel),config 值从 0x00 到 0x1c。

V3 的事件表更为庞大,例如 L3C V3 提供 40 个事件(含index-flush-evictionclean-evictiondirty-evictionbloomfilter-clearinggeneration-flipvcc-droop-detected等),IOB 分为 fast(49 个,含 snoop、barrier 相关)与 slow(9 个)两套,MCB V3 有 36 个事件,MC V3 有 45 个事件(含各种 hazard:raw-hazardwar-hazardwaw-hazardrar-hazard以及rank-activerank-idlerank-pdrank-sref等),完整清单见 drivers/perf/xgene_pmu.c。

agent ID:按数据通路来源过滤事件

X-Gene SoC 的绝大多数 PMU 都有特定的agent ID 列表,用于监控特定数据通路的性能。例如,L3 cache 的 agent 可以是某个具体 CPU 或某个 I/O 桥。每个 PMU 都有一组 2 个寄存器(PMU_PMAMR0/PMU_PMAMR1,偏移 0xA00 / 0xA04)用于掩码请求来源的 agent:

  • 若与 agent 编号对应的位被置 1,则仅当事件由该 agent 的请求引发时才被计数;
  • 每个 agent ID 位与config1字段中的对应位是反向映射的;
  • 默认情况下事件对所有 agent 请求计数(config1 = 0x0)。

也就是说,config1中的某个位为 0 表示"该 agent 被计入",为 1 表示"该 agent 被排除"。在驱动实现中,xgene_perf_enable_event()config1取反后写入掩码寄存器:write_agentmsk(pmu_dev, ~GET_AGENTID(event))(drivers/perf/xgene_pmu.c),与文档描述的"inversely mapped"完全一致;IOB 额外将config1的高 32 位写入第二个掩码寄存器PMU_PMAMR1。各 PMU 具体支持哪些 agent,需查阅 APM X-Gene 用户手册(User Manual)。

cpumask:单 CPU 承载全部事件

由于 SoC 系统级 PMU 的计数器是所有核共享的,perf 核心的诸多操作(如事件轮转)都运行在单一 CPU 上下文上。为避免 off-core PMU 事件被分配到不同 CPU 导致的问题,驱动强制将所有事件绑定到cpumask属性指定的唯一 CPU上(xgene_perf_event_init() 中将event->cpu重写为cpumask_first(&pmu_dev->parent->cpu))。

cpumask属性本身由cpumask_show()输出(drivers/perf/xgene_pmu.c)。该 CPU 的选择由 CPU 热插拔回调维护:在 CPU 上线时选定一个"读者 CPU",并将溢出中断的亲和性(irq_set_affinity)一并绑定到该 CPU;当该 CPU 下线时,通过perf_pmu_migrate_context()把所有 PMU 的 perf 上下文迁移到另一个在线 CPU,见 drivers/perf/xgene_pmu.c。因此用户在使用时无需手动指定-C,驱动会自动使用 cpumask 指定的 CPU。

perf 工具实战:枚举与计数

在内核开启CONFIG_ARM_APM_XGENE_PMUdrivers/perf下的xgene-pmu驱动,平台驱动见 drivers/perf/xgene_pmu.c)后,即可用 perf 工具访问这些 PMU。

1. 枚举可用事件:

/ # perf list | grep -e l3c -e iob -e mcb -e mc l3c0/ackq-full/ [Kernel PMU event] <...> mcb1/mcb-csw-stall/ [Kernel PMU event]

perf list输出中的事件名直接来自 sysfsevents目录,与驱动源码中的XGENE_PMU_EVENT_ATTR定义一一对应。

2. 系统级计数统计(1 秒):

/ # perf stat -a -e l3c0/read-miss/,mcb1/csw-write-request/ sleep 1

-a表示系统级(all CPUs)模式,这是必须的——SoC PMU 计数器跨核共享,不支持 per-task 会话。

3. 结合 agent 过滤:

/ # perf stat -a -e l3c0/read-miss,config1=0xfffffffffffffffe/ sleep 1

config1=0xfffffffffffffffe表示仅统计来自 agent 0(bit 0 为 0)的读未命中,屏蔽其余所有 agent 的请求。从驱动的反向掩码逻辑可以理解:~0xfffffffffffffffe = 0x1,写入PMU_PMAMR0后只有 bit 0 使能。

4. 事件组使用:驱动要求同组事件必须来自同一 PMU(软件事件除外),混用不同 PMU 的事件组会被xgene_perf_event_init()拒绝(drivers/perf/xgene_pmu.c)。

驱动不支持的能力与原因

原文档明确指出驱动存在以下限制,结合源码可以进一步解释其根因:

  • 不支持采样(sampling)perf record无法工作。在xgene_perf_event_init()中,is_sampling_event(event)直接返回-EINVAL(drivers/perf/xgene_pmu.c);
  • 不支持 per-task(不带-a)会话PERF_ATTACH_TASK同样被拒绝,且 PMU 注册时task_ctx_nr = perf_invalid_context(drivers/perf/xgene_pmu.c);
  • 另外 PMU 的 capabilities 为PERF_PMU_CAP_NO_EXCLUDE,即不支持排除用户态/内核态(exclude_user/exclude_kernel)等过滤。

这些限制的根源在于:SoC 系统 PMU 计数器是跨所有核共享的全局硬件资源,无法按进程隔离,也不具备按指令地址采样的能力。事件初始化时若传入event->cpu < 0(即未绑定具体 CPU)也会返回-EINVAL

中断处理与计数器溢出

顶层中断处理由xgene_pmu_isr()完成:读取共享 PCPPMU 中断状态寄存器,按版本解析 MCU/MCB/L3C/IOB 中断源,再分别遍历各 PMU 列表调用_xgene_pmu_isr()(drivers/perf/xgene_pmu.c)。

_xgene_pmu_isr()中(drivers/perf/xgene_pmu.c):

  1. 停止计数器(写PMU_PMCR的 E 位);
  2. 读取溢出状态寄存器PMU_PMOVSR(V3 用PMU_PMOVSSET)并只取PMU_OVERFLOW_MASK(0xF)低 4 位;
  3. 按版本清除中断标志(V1 写 0x0,V2 回写 pmovsr,V3 写PMU_PMOVSCLR);
  4. 对每个溢出的计数器调用xgene_perf_event_update()累加计数,再调用xgene_perf_event_set_period()重设周期;
  5. 重新启动计数器。

32 位计数器以2^31为编程周期(1ULL << 31),以应对极端中断延迟下计数器被追上的风险;64 位计数器(V3)则不预期溢出(drivers/perf/xgene_pmu.c)。计数增量计算使用(new - prev) & max_period的环绕减法(drivers/perf/xgene_pmu.c)。

设备树(DT)与 ACPI 支持

驱动同时支持 Flattened Device Tree(FDT)与 ACPI 两种固件接口:

  • 设备树of_match_table匹配apm,xgene-pmu(V1)与apm,xgene-pmu-v2(V2),完整绑定说明见 Documentation/devicetree/bindings/perf/apm,xgene-pmu.yaml。父节点需要regmap-cswregmap-mcbaregmap-mcbb三个 syscon phandle,用于探测活动的 MCB/MC 数量;子节点按 compatible(apm,xgene-pmu-l3c/-iob/-mcb/-mc)枚举,MCB/MC 子节点用enable-bit-index指定其在活动掩码中的位号(如 4 个 MC 子节点分别用 0~3),未指定时默认为 0("总是使能",见 drivers/perf/xgene_pmu.c);
  • ACPI:匹配APMC0D5B(V1)、APMC0D5C(V2)、APMC0D83(V3)三个 PNP ID,子设备通过acpi_walk_namespace递归枚举,类型由APMC0D5D~APMC0D60APMC0D84~APMC0D88映射(drivers/perf/xgene_pmu.c)。

驱动在 probe 阶段会读取 CSW(Crossbar Switch)与 MCBA/MCBB 寄存器来判断实际活动的 MCB 数量(单/双 MCB)与 MC 数量(MCBADDRMR_DUALMCU_MODE_MASK位判断 dual-MCU 模式),从而只注册硬件实际存在的 PMU 设备(drivers/perf/xgene_pmu.c);V3 下 L3C 最多 8 个(掩码 0xFF),MC 数量则由 CSW 路由位推断。这也是为什么不同机器上/sys/bus/event_source/devices/下出现的l3cX/mcbX/mcX数量会不同。

小结

X-Gene SoC PMU 通过xgene-pmu驱动将 L3C、IOB、MCB、MC 四类系统设备以标准 perf PMU 的形式接入 Linux perf 子系统。使用时只需三步:用perf list枚举事件、用perf stat -a做系统级计数、需要时通过config1按 agent 过滤数据通路。其底层实现——共享中断 CSR、反向 agent 掩码、单 CPU 亲和性绑定、32/64 位计数器溢出处理——体现了 off-core 系统 PMU 与核内 PMU 在设计上的典型差异,值得嵌入式与服务器性能工程师深入参考。

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

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

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

LSTM-SVR组合模型权重优化:多输入单输出回归预测实战

简介&#xff1a;面向多输入单输出回归预测任务&#xff0c;这份资源提供基于LSTM与SVR的MATLAB组合模型实现&#xff0c;重点解决两种模型融合时的权重优化问题&#xff0c;适合有一定编程基础的研究生、工程师用于预测建模实验、算法对比或课程设计参考。压缩包共14个文件&am…

作者头像 李华