gpt4 book ai didi

c++ - rdtscp、rdtsc : memory and cpuid/rdtsc? 的区别

转载 作者:IT老高 更新时间:2023-10-28 13:22:50 29 4
gpt4 key购买 nike

假设我们正在尝试使用 tsc 进行性能监控,并且我们希望防止指令重新排序。

这些是我们的选择:

1: rdtscp 是一个序列化调用。它可以防止围绕对 rdtscp 的调用进行重新排序。

__asm__ __volatile__("rdtscp; "         // serializing read of tsc
"shl $32,%%rdx; " // shift higher 32 bits stored in rdx up
"or %%rdx,%%rax" // and or onto rax
: "=a"(tsc) // output to tsc variable
:
: "%rcx", "%rdx"); // rcx and rdx are clobbered

但是,rdtscp 仅在较新的 CPU 上可用。所以在这种情况下,我们必须使用 rdtsc。但是 rdtsc 是非序列化的,因此单独使用它不会阻止 CPU 对其进行重新排序。

所以我们可以使用这两个选项中的任何一个来防止重新排序:

2: 这是对 cpuidrdtsc 的调用。 cpuid 是一个序列化调用。

volatile int dont_remove __attribute__((unused)); // volatile to stop optimizing
unsigned tmp;
__cpuid(0, tmp, tmp, tmp, tmp); // cpuid is a serialising call
dont_remove = tmp; // prevent optimizing out cpuid

__asm__ __volatile__("rdtsc; " // read of tsc
"shl $32,%%rdx; " // shift higher 32 bits stored in rdx up
"or %%rdx,%%rax" // and or onto rax
: "=a"(tsc) // output to tsc
:
: "%rcx", "%rdx"); // rcx and rdx are clobbered

3:这是对 rdtsc 的调用,其中 memory 在 clobber 列表中,可防止重新排序

__asm__ __volatile__("rdtsc; "          // read of tsc
"shl $32,%%rdx; " // shift higher 32 bits stored in rdx up
"or %%rdx,%%rax" // and or onto rax
: "=a"(tsc) // output to tsc
:
: "%rcx", "%rdx", "memory"); // rcx and rdx are clobbered
// memory to prevent reordering

我对第三种方案的理解如下:

调用 __volatile__ 可防止优化器移除 asm 或将其移至任何可能需要 asm 结果(或更改输入)的指令。但是,它仍然可以移动它以进行不相关的操作。所以 __volatile__ 是不够的。

告诉编译器内存正在被破坏:: "memory")"memory" clobber 意味着 GCC 不能对整个 asm 中的内存内容保持不变做出任何假设,因此不会围绕它重新排序。

所以我的问题是:

  • 1:我对__volatile__"memory"的理解是否正确?
  • 2:后两个调用做同样的事情吗?
  • 3:使用 "memory" 看起来比使用另一个序列化指令要简单得多。为什么有人会使用第三个选项而不是第二个选项?

最佳答案

正如评论中提到的,编译器屏障处理器屏障之间是有区别的。 asm 语句中的 volatilememory 充当编译器屏障,但处理器仍然可以自由地重新排序指令。

处理器屏障是必须明确给出的特殊指令,例如rdtscp, cpuid, 内存栅栏指令(mfence, lfence, ...)等

顺便说一句,虽然在 rdtsc 之前使用 cpuid 作为屏障很常见,但从性能角度来看,它也可能非常糟糕,因为虚拟机平台经常陷入和模拟 cpuid 指令,以便在集群中的多台机器上强加一组通用的 CPU 功能(以确保实时迁移工作)。因此,最好使用内存围栏指令之一。

Linux 内核在 AMD 平台上使用 mfence;rdtsc,在 Intel 平台上使用 lfence;rdtsc。如果您不想费心区分这些,mfence;rdtsc 两者都可以使用,尽管速度稍慢,因为 mfence 是比 lfence .

编辑 2019-11-25:从 Linux 内核 5.4 开始,lfence 用于在 Intel 和 AMD 上序列化 rdtsc。请参阅此提交“x86:删除 X86_FEATURE_MFENCE_RDTSC”:https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=be261ffce6f13229dad50f59c5e491f933d3167f

关于c++ - rdtscp、rdtsc : memory and cpuid/rdtsc? 的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12631856/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com