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
相关产品推荐
相关产品推荐

