You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apple M2(ARM64)下如何用C内嵌汇编获取CPU周期数

关于Apple Silicon上访问PMCCNTR_EL0与周期计数的问题

Apple是否限制了PMCCNTR_EL0的访问?

是的,Apple Silicon(覆盖iOS和macOS平台)在用户态程序中明确限制了直接访问PMU(性能监控单元)寄存器,PMCCNTR_EL0就在受限范围内。即便硬件本身支持FEAT_PMUv3特性,系统的安全沙箱机制也会阻止用户态代码读取这类寄存器,目的是防止恶意程序通过硬件信息做指纹识别或利用PMU执行敏感操作。

C语言中实现函数运行周期统计的替代方案

既然无法直接读取PMCCNTR_EL0,推荐用Apple官方提供的高精度计时API完成基准测试,以下是纯C语言的实现方案:

方案1:使用mach_absolute_time()(推荐)

这个API返回系统的高精度绝对时间值,配合mach_timebase_info()可以将其转换为实际的处理器周期数(或纳秒)。

#include <stdint.h>
#include <mach/mach_time.h>

// 预存时间基准转换系数
static uint64_t timebase_numer = 0;
static uint64_t timebase_denom = 0;

void init_timebase() {
    mach_timebase_info_data_t info;
    mach_timebase_info(&info);
    timebase_numer = info.numer;
    timebase_denom = info.denom;
}

uint64_t get_cycle_count() {
    // 首次调用时初始化时间基准
    if (timebase_numer == 0 || timebase_denom == 0) {
        init_timebase();
    }
    // 获取绝对时间并转换为处理器周期数
    return mach_absolute_time() * timebase_numer / timebase_denom;
}

// 示例测试函数,替换为你的目标函数
void function_to_benchmark() {
    for (int i = 0; i < 1000; i++);
}

int main() {
    const int iterations = 1000000;
    uint64_t count_array[iterations];
    
    for (int i = 0; i < iterations; i++) {
        uint64_t c1 = get_cycle_count();
        function_to_benchmark();
        uint64_t c2 = get_cycle_count();
        count_array[i] = c2 - c1;
    }
    
    // 后续可对count_array做统计分析
    return 0;
}

说明

  • mach_absolute_time()返回的是系统启动后的时钟滴答数,通过mach_timebase_info()拿到的numer和denom,能将其转换为纳秒或处理器周期(具体取决于硬件的时间基准)。
  • 这是Apple官方推荐的方案,兼容性和稳定性远高于直接访问硬件寄存器,不会因系统版本更新失效。

为什么之前的C++方案无法复用?

常见的C实现可能依赖了C独有特性,比如inline汇编的特殊写法、类封装、命名空间等,而纯C语言不支持这些语法。上面的方案完全基于标准C和Apple系统API,无需依赖C++特性,可直接在C程序中使用。

内容的提问来源于stack exchange,提问作者Aymane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 15:53:27