- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
假设我们正在尝试使用 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: 这是对 cpuid
和 rdtsc
的调用。 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 中的内存内容保持不变做出任何假设,因此不会围绕它重新排序。
所以我的问题是:
__volatile__
和"memory"
的理解是否正确?"memory"
看起来比使用另一个序列化指令要简单得多。为什么有人会使用第三个选项而不是第二个选项?最佳答案
正如评论中提到的,编译器屏障和处理器屏障之间是有区别的。 asm 语句中的 volatile
和 memory
充当编译器屏障,但处理器仍然可以自由地重新排序指令。
处理器屏障是必须明确给出的特殊指令,例如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/
这是要修改的正确 Linux 内核代码吗?我如何进行更改以模拟 CPUID 代码以及我需要更改哪个函数。谢谢 #include #include #include #include #incl
我的CPU是Intel Core2Quad Q9300 2.5GHz。 CPU-Z 给我的值是 Family:6、Model:7 和 Stepping:7。尝试使用 EAX=1 的 cpuid 指令编
我在 Intel Vol.2 的多个指令条目中找到了推测数据缓存过程的描述。 例如,lfence : Processors are free to fetch and cache data specu
考虑到我正在使用 C++ 进行编码,如果可能的话,我想使用类似 Intrinsics 的解决方案来阅读有关硬件的有用信息,我的担忧/考虑是: 我对汇编不太了解,仅获取此类信息将是一笔可观的投资(虽然它
这里先给大家分享一个分配静态ip地址的代码 ? 1
cpuid用作序列化指令以在基准测试时防止 ooo 执行,因为基准测试指令的执行可能会在 rdtsc 之前重新排序如果单独使用。我的问题是以下说明是否仍然可行 rdtsc将在 cpuid 之间重新排序
有时我遇到用rdtsc指令读取TSC的代码,但是恰好在之前调用cpuid。 为什么需要调用cpuid?我意识到这可能与具有TSC值的不同内核有关,但是当您依次调用这两个指令时会发生什么呢? 最佳答案
我已经看到相关问题包括here和 here ,但似乎唯一提到的用于序列化 rdtsc 的指令是 cpuid。 不幸的是,cpuid 在我的系统上大约需要 1000 个周期,所以我想知道是否有人知道更便
我正在寻找一种巧妙的方法来捕获和摆弄 Linux 进程的 CPUID 指令。尝试使用 ptrace() 并修补进程创建的所有可执行 mmap 区域中的所有 cpuid 操作码,并用 int3 替换它们
CPUID 可用作序列化指令,如 here 所述和 here .在 C++ 中以这种方式使用它的最小/最简单的 asm 语法是什么? // Is that enough? // What to do
我正在尝试使用 C++ 中的 CPUID 访问信息。到目前为止,我已经制作了这段代码,不能再继续了。我在这里和网上找到了一些有用的文章,但它们似乎对我没有帮助。 我应该只使用 x88 的指令和寄存器。
我正在使用 CPUID 指令在我的操作系统中打印一些关于 CPU 的信息。 读取和打印供应商字符串(GenuineIntel)效果很好,但读取品牌字符串给我一些奇怪的字符串。 ok cpu-info
我正在尝试开发一个 C 函数来获取一些主板信息(名称、ID 等),但我找不到这些信息的存储位置。我查看了 CPUID,但在那里找不到与主板相关的任何信息(尽管有很多关于 CPU 的信息)。 有谁知道我
我正在为我的爱好操作系统开发 CPU 检测和一般环境检测代码。是否存在需要多次调用 CPUID 的情况?也就是说如果系统有多个核心,操作系统是否需要在每个核心上调用CPUID? NUMA 也是如此。
我正在尝试分析 x86-64 处理器上的代码执行时间。我指的是this英特尔白皮书并浏览了其他 SO 线程,讨论使用 RDTSCP 与 CPUID+RDTSC 的主题 here和 here . 在上述
我在较新的基于 i7 的计算机上遇到基于 CPUID 的代码的问题。它检测到 CPU 为具有 8 个 HT 单元的单核,而不是每个具有 2 个 HT 单元的 4 个核。 我一定是误解了从 CPU 返回
我正在尝试编译 C++ 代码。但我在 power8 架构上遇到错误。在 x86_64 架构中运行良好。以下是我遇到的错误。 error: impossible register constrain
如何以编程方式获取运行给定线程的核心?类似于 Unix 的 getcpuid。这适用于 Linux 和 C。 最佳答案 是否sched_getcpu()没有给你不同的核心值(value)? 关于c -
在为 Windows 编写新代码时,我偶然发现了来自 Windows API 的 _cpuinfo()。因为我主要处理 Linux 环境 (GCC),所以我想访问 CPUInfo。 我尝试了以下方法:
我正在做一些 Linux 内核计时,特别是在中断处理路径中。我一直在使用 RDTSC 进行计时,但我最近了解到它不一定准确,因为指令可能会乱序发生。 然后我尝试了: RDTSC + CPUID(此处为
我是一名优秀的程序员,十分优秀!