【问题标题】:Prevent code being moved by GCC in benchmark code防止 GCC 在基准代码中移动代码
【发布时间】:2012-01-29 14:18:40
【问题描述】:

我正在尝试微调我们正在使用的一些基准代码,并且想知道是否有一种方法可以明确地与 GCC 沟通如何订购某些代码位。例如,给定这些代码块:

  1. 开始定时器
  2. 身体
  3. 停止定时器
  4. 发布

我想告诉 GCC,每个块必须按上述顺序保持,没有任何指令泄漏到另一个块中。理想情况下,计时器将仅测量第 3 步,但出于实际原因,测量至少第 3 步和最多第 2-4 步就足够了。我只是想确保我注意到测量第 1 步或第 5 步的任何部分。

目前我在 Timer 函数中使用 __sync_synchronize 来发出完整的内存栅栏。我希望,除了作为一个栅栏之外,这个函数被标记为防止重新排序。

__sync_synchronize 的调用是否足够?同样从逻辑上讲,根据标准的文本,C++11 围栏命令是否也足够?

【问题讨论】:

  • 让我想知道:你为什么要这样做?此外,标准中没有关于代码位顺序的任何内容(无论是什么)
  • @VJovic,因为我需要计时一些代码的性能。而且绝对在 C++11 标准中有很多关于排序代码(同步、发生之前等)的内容
  • 我可能误解了这个问题,但是如果编译器重新排序代码块执行,那么它是编译器或链接器中的错误。那么,你到底在问什么?
  • 问题出在优化器上。由于 Body 可能对其他代码没有数据/执行依赖性,因此优化器可能会决定移动它,因为它不会违反任何“as-if”要求/可见的副作用。跨度>
  • 禁用优化器?然后将不会重新排序。虽然有些 CPU 也可以重新排序指令。

标签: c++ gcc


【解决方案1】:

如果Start-Timer 是一个函数调用,而Stop-Timer 是另一个函数调用,则优化器几乎没有机会移动Body,或者将PrePost 中的材料溢出到Body .

Pre 的所有副作用必须在调用Start-Timer 函数之前完成(那里有一个序列点)。 Stop-Timer 的所有副作用必须在执行 Post 之前完成(那里也有一个序列点)。因此,编译器必须让 Start-TimerStop-Timer 的代码对生成的代码可见,从而导致材料四处溢出,即使在那时我也不相信它可以这样做。

所以,总而言之,如果您使用函数调用来启动和停止计时器,我认为您不必担心。

【讨论】:

  • 这是我主要关心的问题,因为 Timer 函数很小并且几乎可以保证是内联的。因此优化器对那里发生的事情有充分的了解。此外,Pre PostBody 可以很好地属于一个函数,因此优化器再次拥有完整的知识。
  • 把定时器函数放在一个单独的源文件中。这一直有效,直到“整个程序优化”的东西发生。即便如此,我认为序列点要求限制了 GCC 可以做的事情(因为计时器会产生副作用,在某处记录时间)。
  • 如果可行,那么只需在计时器函数本身中调用clock_gettime 就足够了。我看不出它对该函数调用有任何了解。
【解决方案2】:

制作两个版本的代码:一个带有您要测量的真实代码,一个带有存根。测量两者。减去。那么,我认为,你不必关心 GCC 做了什么。

【讨论】:

  • 我正在尝试解决测量的正确性。如果它是错误的,那么空存根的测量也将是错误的。
  • 怎么样?减法会减去任何错误,除非您认为优化器会在这两种情况下做一些完全不同的事情。
猜你喜欢
  • 1970-01-01
  • 2011-09-02
  • 1970-01-01
  • 2013-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多