在Apple Silicon内核模块中用Perf工具测量指令周期可行吗?
在Asahi Linux M2设备上测量内核模块代码运行周期的方案
一、用Asahi的Perf驱动实现测量(推荐)
Asahi团队开发的apple_m1_cpu_pmu驱动已经完全适配M1/M2的私有PMC寄存器,可以直接用Perf工具测量内核模块中指定代码段的运行周期,具体操作如下:
确认Perf环境就绪
- Asahi Linux默认已开启
CONFIG_PERF_EVENTS和CONFIG_APPLE_M1_CPU_PMU内核配置项,无需额外修改。 - 安装perf工具:根据你的包管理器执行命令,Arch系用
sudo pacman -S linux-tools,Debian/Ubuntu用sudo apt install linux-tools-common linux-tools-$(uname -r)。
- Asahi Linux默认已开启
在内核模块中标记目标代码段
要精准测量指定汇编指令的周期,在代码前后插入Perf事件标记,内核中可使用perf_event_markerAPI:#include <linux/perf_event.h> // 标记代码段开始 perf_event_marker("my_asm_code_start"); // 你的目标汇编指令组 asm volatile ( "mov x0, #0x10\n" "ldr x1, [x0]\n" // 其他需要测量的指令 ::: "x0", "x1" ); // 标记代码段结束 perf_event_marker("my_asm_code_end");捕获并分析周期数据
加载内核模块后,用perf记录系统事件:sudo perf record -e cpu-clock -g -a sleep 10(
sleep 10让perf持续捕获10秒,期间触发模块中的目标代码)过滤标记事件查看周期:
sudo perf script | grep "my_asm_code"也可用
perf report打开可视化界面,通过标记定位代码段的具体周期消耗。若要直接测量硬件周期,将事件换成cpu-cycles即可:sudo perf record -e cpu-cycles -a -g -- sleep 10
二、替代方案:简化PMC寄存器操作
如果不想依赖Perf工具,可以复用Asahi驱动中的PMC初始化逻辑,自行实现周期读取:
提取简化版PMC初始化代码
参考apple_m1_cpu_pmu.c的核心逻辑,实现简化初始化函数,主要完成:- 配置PMCR0寄存器启用PMC0
- 设置计数事件为CPU周期(对应苹果PMC的事件编码)
直接读取PMC计算周期
初始化完成后,在代码前后读取PMC0的值,差值即为运行周期:static inline u64 read_pmc0(void) { u64 val; asm volatile("mrs %0, pmc0" : "=r" (val)); return val; } static void init_my_pmc(void) { // 配置PMCR0,启用PMC0并设置周期计数事件 u64 pmcr0 = read_sysreg_s(SYS_APPLE_PMCR0_EL1); pmcr0 |= (1 << 0); // 启用PMC0 pmcr0 &= ~(0xff << 8); // 清除原有事件编码 pmcr0 |= (0x01 << 8); // 设置为CPU周期计数事件(编码以实际为准) write_sysreg_s(pmcr0, SYS_APPLE_PMCR0_EL1); } // 在模块代码中使用 init_my_pmc(); u64 start = read_pmc0(); // 目标汇编指令 asm volatile(...); u64 end = read_pmc0(); pr_info("Assembly code cycles: %llu\n", end - start);注意:需确保代码在同一CPU核心执行,可通过
preempt_disable()/preempt_enable()绑定核心。
三、精度优化建议
- 关闭CPU动态调频:执行
sudo cpupower frequency-set -g performance,避免调频导致周期波动。 - 多次测量取平均值:减少系统调度、中断等干扰因素的影响。
- 禁用内核抢占:在测量代码前后添加
preempt_disable()和preempt_enable(),防止代码被调度到其他核心。
内容的提问来源于stack exchange,提问作者Milad Esrafilian
相关产品推荐
相关产品推荐

