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

rdtsc前调用cpuid防乱序的实现方法与调用位置咨询

问题原因说明

你遇到的时间戳差值为负的问题主要来自两个核心原因:

  • 处理器乱序执行机制导致两次rdtsc指令的实际执行顺序和代码编写顺序不一致,后调用的rdtsc可能被提前调度,返回更小的时间戳
  • 现有封装代码存在数据类型错误:将存储时间戳高32位的d强制转换为uint16_t会直接丢弃其高16位,当时间戳数值超过2^48时会出现溢出错误,也会引发异常差值
cpuid调用实现方案

cpuid是x86平台的序列化指令,执行时会等待所有此前的指令全部执行完成后,才会执行后续指令,可以精准控制rdtsc的执行顺序。
建议直接将cpuid逻辑添加到rdtsc函数内部,无需每次调用时在主函数手动添加,复用性更高,也能避免漏加导致的错误。需要注意cpuid执行时会修改eax、ebx、ecx、edx四个通用寄存器,需要在内联汇编的破坏列表中声明,避免编译器寄存器分配冲突。

修正后的完整rdtsc封装代码如下:

#include <stdint.h>

inline uint64_t rdtsc() {
    uint32_t a, d;
    // 先执行cpuid序列化,保证此前所有指令执行完成后再采样时间戳
    asm volatile ("cpuid\n\t"
                  "rdtsc\n\t"
                  : "=a"(a), "=d"(d)
                  :
                  : "ebx", "ecx");
    // 修复原代码的类型转换错误,将高32位左移32位后拼接低32位
    return ((uint64_t)d << 32) | a;
}

如果是测量某段代码的执行耗时,为了保证要测量的代码不会被乱序到结束采样的rdtsc之后,结束采样建议搭配rdtscp指令使用,写法如下:

uint32_t a, d;
uint64_t start = rdtsc();
// 此处放置需要测量耗时的代码段
asm volatile ("rdtscp\n\t"
              "cpuid\n\t"
              : "=a"(a), "=d"(d)
              :
              : "ebx", "ecx");
uint64_t end = ((uint64_t)d << 32) | a;
uint64_t cost = end - start;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 08:15:03