gcc 和 cpu_relax、smb_mb 等?

标签 gcc optimization memory-barriers barrier

我一直在阅读有关编译器优化与 CPU 优化的文章,以及 volatile vs 内存障碍。

我不清楚的一件事是,我目前的理解是 CPU 优化和编译器优化是正交的。 IE。可以相互独立发生。

然而,文章volatile considered harmful说明 volatile不应该使用。莱纳斯的 post提出类似的主张。 IIUC 的主要原因是将变量标记为 volatile在访问该变量时禁用所有编译器优化(即,即使它们无害),同时仍不提供针对内存重新排序的保护。从本质上讲,重点是不应该小心处理数据,而是需要小心处理特定的访问模式。

现在,volatile considered harmful文章给出了以下等待标志的忙循环示例:

while (my_variable != what_i_want) {}

并指出编译器可以优化对 my_variable 的访问以便它只发生一次而不是循环。文章声称的解决方案如下:
while (my_variable != what_i_want)
    cpu_relax();

据说cpu_relax充当 编译器屏障 (文章的早期版本说它是 内存屏障 )。

我在这里有几个差距:

1) 是否暗示 gcc 对 cpu_relax 有特殊的了解调用,并将其转换为对编译器和 CPU 的提示?

2) 其他指令如 smb_mb() 也是如此和喜欢?

3) 鉴于 cpu_relax,这是如何工作的本质上定义为 C 宏?如果我手动展开 cpu_relax gcc 还会将它视为编译器障碍吗?我如何知道 gcc 尊重哪些调用?

4)cpu_relax的范围是什么?就gcc而言?换句话说,gcc 看到 cpu_relax 时无法优化的读取范围是多少?操作说明?从 CPU 的角度来看,范围很广(内存屏障在读或写缓冲区中放置一个标记)。我猜 gcc 使用较小的范围 - 也许是 C 范围?

最佳答案

  • 是的,gcc 对 cpu_relax 的语义有特殊的了解。或者它扩展到的任何东西,并且必须将其转换为硬件也尊重语义的东西。
  • 是的,任何类型的内存防护原语都需要编译器和硬件特别尊重。
  • 看看宏扩展到什么,例如用“gcc -E”编译并检查输出。您必须阅读编译器文档以了解原语的语义。
  • 内存栅栏的范围与编译器可能移动加载或存储的范围一样宽。从不跨子例程调用移动加载或存储的非优化编译器可能不需要过多注意表示为子例程调用的内存栅栏。跨翻译单元进行过程间优化的优化编译器需要在更大的范围内跟踪内存栅栏。
  • 关于gcc 和 cpu_relax、smb_mb 等?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47975191/

    相关文章:

    c++ - "Bad"GCC优化性能

    c++ - 减少所需的 libc 版本

    optimization - 将 CSV 保存为 .MAT 或二进制文件

    java - Java 的 mysql 执行时间

    x86 - 内存重新排序:是否可以使用较早的存储将负载重新排序到其他但周围的位置?

    c++ - 检测二进制文件的 GCC 编译时标志

    c++ - 模板化类的模板化成员函数

    c++ - 列出 n 个对象的所有 k-排列的有效方法,同时满足特定标准

    c++ - 用于取消标志的 std::atomic_bool:std::memory_order_relaxed 是正确的内存顺序吗?

    assembly - 哪个是 x86 : lock+addl or xchgl? 上更好的写屏障