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

Apple M2架构下读取ARM TSC(PMCCNTR_EL0)出现异常值的问题

问题原因分析

你遇到的问题本质是Apple M2(Apple Silicon)对PMCCNTR_EL0寄存器的访问限制,以及计数器未正确启用导致的无效值:

  • Apple Silicon的性能监控单元(PMU)默认处于禁用状态,且用户态程序没有访问PMCCNTR_EL0的权限,直接读取会得到无意义的随机值或未初始化的寄存器内容。
  • 你看到的超大数值是uint64_t类型的溢出结果:当after的值小于before时,无符号整数相减会产生溢出,得到一个接近UINT64_MAX的数。
正确解决方案(Apple Silicon 读取核心周期计数器)

要在Apple M2上精准测量核心时钟周期数,需要先启用PMU的用户态访问权限,并正确配置计数器,步骤如下:

1. 启用用户态PMU访问(需要root权限)

macOS默认禁止用户态访问PMU,需要通过系统配置解除限制:

  • 重启Mac,按住Command + R进入恢复模式
  • 打开终端,执行:
    csrutil enable --without pmu
    
  • 重启回到正常系统

2. 正确初始化PMCCNTR_EL0计数器

在读取计数器前,需要初始化PMU,确保计数器以核心时钟频率递增:

#include <cstdint>
#include <iostream>

// 初始化PMU,启用PMCCNTR_EL0计数器
void InitPMU() {
    uint64_t pmcr;
    // 读取PMCR_EL0寄存器,配置计数器
    asm volatile("mrs %0, PMCR_EL0" : "=r"(pmcr));
    // 置位P位(启用计数器)、C位(重置计数器)、D位(禁止分频)
    pmcr |= (1 << 0) | (1 << 2) | (1 << 3);
    asm volatile("msr PMCR_EL0, %0" : : "r"(pmcr));
    // 重置计数器为0
    asm volatile("msr PMCCNTR_EL0, %0" : : "r"(0ULL));
}

uint64_t ReadTSC() {
    uint64_t tsc;
    // ISB确保之前的指令完成,保证读取的是最新值
    asm volatile("isb; mrs %0, PMCCNTR_EL0" : "=r"(tsc));
    return tsc;
}

int main() {
    // 必须先初始化PMU
    InitPMU();
    
    uint64_t before = ReadTSC();
    std::cout << "foo\n";
    uint64_t after = ReadTSC();
    
    std::cout << "Print took: " << after - before << std::endl;
    return 0;
}

3. 编译与运行

编译时需要指定Apple M2架构,并且以root权限运行:

g++ -std=c++17 -mcpu=apple-m2 test.cpp -o test
sudo ./test
替代方案(无需root权限)

如果无法获取root权限,可以使用Apple提供的mach_absolute_time(),它返回的抽象时间单位可转换为核心周期数,无需墙钟时间转换:

#include <cstdint>
#include <iostream>
#include <mach/mach_time.h>

uint64_t ReadCoreCycles() {
    mach_timebase_info_data_t info;
    mach_timebase_info(&info);
    // 将抽象时间单位转换为核心周期数
    return mach_absolute_time() * info.numer / info.denom;
}

int main() {
    uint64_t before = ReadCoreCycles();
    std::cout << "foo\n";
    uint64_t after = ReadCoreCycles();
    
    std::cout << "Print took: " << after - before << std::endl;
    return 0;
}

这个方法是Apple提供的用户态安全接口,无需特殊权限即可精准反映核心执行的周期数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 01:55:06