解决rdtsc的解决方案执行

solution to rdtsc out of order execution?

本文关键字:执行 解决方案 rdtsc 解决      更新时间:2023-10-16

我试图用rdtsc替换cpu cpu周期而不是服务器时间来替换rdtsc的clock_gettime(clock_realtime,& ts)。基准标记代码的执行时间对于软件至关重要。我尝试在X86_64 3.20GHz Ubuntu机器上运行代码,并在隔离核心上进行以下数字:

案例1:时钟获取时间: 24纳米秒

void gettime(Timespec &ts) {
        clock_gettime(CLOCK_REALTIME, &ts);
}

案例2:rdtsc(无MFENCE和编译器屏障): 10 NS

void rdtsc(uint64_t& tsc) {
        unsigned int lo,hi;
        __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
        tsc = ((uint64_t)hi << 32) | lo;
}

案例3:rdtsc(带有MFENCE和编译器屏障): 30 NS

void rdtsc(uint64_t& tsc) {
        unsigned int lo,hi;
        __asm__ __volatile__ ("mfence;rdtsc" : "=a" (lo), "=d" (hi) :: "memory");
        tsc = ((uint64_t)hi << 32) | lo;
}

问题是我知道RDTSC是一个非序列化呼叫,可以由CPU重新排序,替代方案是RDTSCP,它是一个序列化调用,但是可以在rdtscp呼叫之前对RDTSCP调用后的说明进行重新排序。使用内存屏障正在增加执行时间。

  • 基准延迟敏感代码的最优化和最佳方法是什么?
  • 无论如何是否有优化我提到的案例?

您希望 lfence;rdtsc to start 时钟,而rdtscp;lfence停止时钟,因此障碍物在定时间隔之外。

(或有时您希望lfence;rdtsc;lfence开始时钟,以增加开销为代价。)

mfence是错误的指示;不能保证将指令流序列化(但实际上,它在Skylake上使用最新的微型码来修复勘误表)。Lfence序列化指令流而无需等待商店缓冲区空的空白,只是为了抢劫。在Intel上始终是正确的,但是仅在启用幽灵缓解措施的情况下,它使lfence不仅仅是NOP。(我猜AMD不会从WC内存中重新订购movntdqa加载,因此lfence在那里无意义,并且仅作为仅作为针对投机执行的执行屏障或RDTSC的执行障碍。)p>另请参见如何从C 中获取X86_64中的CPU周期计数?其中有有关序列化rdtsc的部分。但是,您也不需要内联ASM;使用__rdtsc()_mm_lfence()。(但是像往常一样,使用Microbenchs,检查编译器的ASM输出以确保它可以完成您想要的工作并不是一个坏主意。)


您无法避免开销,与几个说明的成本相比,这总是很重要的。

也通过C函数clflush以无效缓存线,以减去测量开销的示例。

,但还请注意,将代码进行循环测试更有用,因为在结果准备之前的执行延迟比等待指令实际上从ROB中退休。请参阅NASM中的rdtscp始终返回相同的值(按单个指令),以示例(在ASM中)测量单个INSN的吞吐量/潜伏期。