C优化:条件存储,以避免弄脏缓存行

问题描述 投票:11回答:2

libuv source中,我发现了这段代码:

  /* The if statement lets the compiler compile it to a conditional store.
   * Avoids dirtying a cache line.
   */
  if (loop->stop_flag != 0)
    loop->stop_flag = 0;

有人能解释一下吗?

什么是缓存行?

另外,我猜条件存储是一些汇编指令,它检查一些东西,如果成功,写一些值。对?

这种结构什么时候有意义?我想并不总是,因为否则编译器会一直使用条件存储,对吧?

c libuv
2个回答
5
投票

缓存按快速内存块组织,由于历史原因,称为行。当您写入高速缓存行时,它被标记为“脏”,这意味着在高速缓存控制器硬件中设置了一个位,表示该行需要在其他部分之前复制到其他级别的高速缓存和/或主存储器。系统可以访问它。

通常,存储器层次结构的每个级别:寄存器,L1,L2,L3 ......高速缓存,主存储器和交换空间具有相同信息的不同副本。即使一个或多个副本可能已更改,也要确保系统的不同部分(处理器,DMA,视频子系统等)看到相同的值称为一致性问题。

一般解决方案是暂停将更新的值复制到层次结构的不同级别。这称为同花。

刷新可能花费10到 - 在最坏的情况下它会导致页面错误 - 可能是数百万个处理器周期。

由于成本高昂,硬件设计人员竭尽全力最大限度地减少冲洗需求。程序员也在这里采取了这个原因。

评论说“如果缓存已经在标志中包含零,那么不要在零上写零,因为这会将缓存行标记为脏,这可能会导致不必要的刷新。”

“条件商店”是一个略显模糊的术语。它只是指正常存储周围的零跳转,这是编译器将从if语句生成的代码。在X86中,它看起来像:

    ;; assume edi holds value of pointer 'loop'
    ;; and flag is a constant offset for the 'stop_flag' field.
    cmp dword ptr [edi, flag], 0
    jz no_store
    mov [edi, flag], 0
no_store:
   ... code continues

如果缺少if语句,则只有最后一个mov指令。

NB一位评论者指出,在重要的处理器架构上确实存在单一的“条件移动/存储”指令。我还没有看到gcc生产一个。

这是否值得进行优化是非常值得商榷的。条件语具有刷新指令管道的风险(不同类型的刷新)。如果没有明确的证据证明需要,就不要牺牲速度的清晰度。


0
投票

“缓存”意味着隐藏某些东西。计算中Cache的功能是通过尽可能地抢占主存储器访问来隐藏到主存储器的距离。

这只适用于以前使用过的数据,你还没有将它从缓存中推出,而没有其他人在你之前把它拿走。任何其他actor(其他CPU,IO-Bus,......)必须能够获取当前值并对其进行更改,即使您已将其缓存。使用高速缓存一致性协议完成此任务。更高的一致性意味着更高的成本。

您的代码尝试做的是使编译器发出条件移动,因此CPU检查0,如果不是0则仅写入。在Intel / AMD IS和许多其他中有一整套条件移动指令。

所以现在,一步一步:

  • 测试0:如果您的CPU没有测试数据的副本,则必须要求一个。这比以前糟糕得多。让我们希望你不要打主内存。
  • 准备写一个值: 你拥有这些数据:很棒,你已经完成了。 您不拥有数据:缓存调用其兄弟和更高层,以通知他们现在拥有此片段。没有其他人可以保留副本。
  • 写一个值:缓存保存更改并标记缓存行(缓存的最低粒度)脏,需要写回。

那么,值得吗?这取决于。

旁白:为什么要提供条件存储指令,如果你可以使用条件跳转和存储来合成它们?优点是使用较少的指令并且没有刷新指令流水线的风险(部分按照说明执行)。更新:看起来他们无法从x86 / x86_64上的register / immediate移动到内存。

© www.soinside.com 2019 - 2024. All rights reserved.