Linux x86/x64 GCC下__rdtsc用法及流水线刷新与__rdtscp疑问
在Linux x64平台用GCC做准确CPU周期测量的正确姿势
一、不用汇编时如何刷新流水线配合__rdtsc
要解决CPU乱序执行导致的TSC测量不准问题,核心是在调用__rdtsc前强制CPU完成所有前置指令、刷新流水线。GCC提供的内置__cpuid函数可以直接做到这一点——它对应x86的cpuid指令,属于强序列化指令,会让CPU暂停乱序执行逻辑,确保所有前置指令执行完毕后才继续后续操作。
使用时只需用临时变量承接__cpuid的输出即可(比如传入参数0,避免触发特殊CPU功能):
#include <cpuid.h> // 序列化流水线,确保前置指令全部执行完成 void serialize_pipeline() { unsigned int eax, ebx, ecx, edx; __cpuid(0, eax, ebx, ecx, edx); } // 周期测量示例 void measure_cycles() { unsigned long long start, end; serialize_pipeline(); start = __rdtsc(); // 这里放入你需要测量的代码段 for (int i = 0; i < 1000; i++); serialize_pipeline(); end = __rdtsc(); printf("消耗周期: %llu\n", end - start); }
另外,也可以用GCC的__sync_synchronize()内置函数——它会生成mfence这类内存栅栏指令,同样能起到序列化流水线的效果,不过cpuid的序列化强度更高,更适合高精度周期测量场景。
二、__rdtscp能否替代「刷新操作+__rdtsc」?
答案是完全可以,但要明确它的特性:
__rdtscp对应x86的rdtscp指令,这条指令本身就带有序列化语义:它会确保在读取TSC计数器前,所有前置指令都已执行完成、所有内存操作都已提交到内存。也就是说,调用__rdtscp前不需要额外的cpuid或栅栏指令来刷新流水线。- 和「
__cpuid+__rdtsc」的组合相比,__rdtscp的开销更小——cpuid指令的执行延迟比rdtscp高不少,用__rdtscp能降低测量自身带来的误差。 - 注意:
rdtscp只会序列化它之前的指令流,不会阻止后续指令提前执行,但这不影响周期测量的准确性——不管是测量代码段的起始还是结束时间,__rdtscp的序列化语义都能保证TSC读取时机的正确性。
用__rdtscp的测量示例:
void measure_with_rdtscp() { unsigned long long start, end; unsigned int aux; // rdtscp会返回一个辅助值,可直接忽略 start = __rdtscp(&aux); // 自带序列化,无需前置刷新 // 被测代码段 for (int i = 0; i < 1000; i++); end = __rdtscp(&aux); printf("消耗周期: %llu\n", end - start); }
需要注意:部分极老版本的GCC可能不支持__rdtscp,确保你的GCC版本在4.4及以上(现代Linux发行版基本都满足)。
内容的提问来源于stack exchange,提问作者doraemon
相关产品推荐
相关产品推荐

