rdtsc无法准确测量指令周期数,因其读取的是tsc而非实际核心周期;应使用perf统计cycles和instructions,或查阅intel/amd手册中的latency/throughput理论值。

直接用 rdtsc 无法准确得到指令周期数
在现代 x86/x64 CPU 上,rdtsc 指令读取的是“时间戳计数器”(TSC),它反映的是自上电以来的时钟周期(或经过频率缩放的“参考周期”),但不是单条指令执行所需的精确核心周期数。尤其在开启 Turbo Boost、变频、多核调度、乱序执行、分支预测和微码更新后,同一条指令在不同上下文下实际消耗的流水线周期可能差几倍。
真正能反映指令级开销的是“uop(微操作)数量 + 流水线资源竞争”,这必须通过硬件性能监控单元(PMU)获取,而非靠简单计时。
用 perf 统计 cycles 和 instructions 更可靠
Linux 下最实用的方式是用 perf 工具采集硬件事件,它通过 PMU 直接统计真实执行的周期与指令数(含推测执行部分,但可加 --all-user 过滤内核干扰):
perf stat -e cycles,instructions,cpu-cycles,instructions:u ./my_program
关键点:
-
cycles和cpu-cycles在现代内核中通常等价,代表处理器核心实际运行的周期数 -
instructions:u表示仅用户态指令,排除系统调用和中断开销 - 多次运行取中位数,避免被上下文切换或缓存预热干扰
- 若想锁定单个函数,需配合
-g或用perf record+perf report定位热点
用 __rdtscp 做粗略对比时必须加序列化
如果只是比较两段代码的相对开销(比如 A 函数比 B 快多少),可用 __rdtscp 配合序列化屏障减少乱序干扰:
unsigned int lo, hi; __rdtscp(&lo); // 读 TSC 并序列化后续指令 // your code here __rdtscp(&lo); // 再读一次 uint64_t cycles = ((uint64_t)hi <p>注意:</p>
- 必须用
__rdtscp而非__rdtsc,后者不保证指令顺序 - 不能在循环里反复调用——每次调用本身就有 ~20–40 cycles 开销
- 结果受 L1/L2 缓存命中率、TLB 状态、分支预测正确率影响极大,同一段代码跑 10 次可能相差 ±15%
- Intel 手册明确指出:TSC 不适合测量“指令延迟”,只适合测量“经过时间”
查 Intel/AMD 官方手册里的 Latency 和 Throughput
对确定指令(如 add、imul、div),最权威的周期数来自厂商文档:
- Intel:查阅《Intel® 64 and IA-32 Architectures Optimization Reference Manual》附录 C,找对应指令的
Latency(依赖链延迟)和Throughput(每周期最多发射条数) - AMD:看《Software Optimization Guide for AMD Family 19h Processors》中的 instruction tables
- 注意区分:整数加法通常是 1-cycle latency / 4-per-cycle throughput;而
idiv可能高达 30+ cycles latency,且吞吐只有 1/10–1/20 - 这些值是理想流水线下的理论值,实际受寄存器重命名、端口争用、宏融合等影响
真正难的不是读数,而是判断你的代码是否触发了端口 5 的瓶颈,或者有没有意外导致 microcode assist —— 这些只能靠 perf 的 uops_issued.any、uops_executed.core 等事件交叉验证。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











