【问题标题】:C loop unrolling limitations?C循环展开限制?
【发布时间】:2015-03-20 02:01:11
【问题描述】:

我正在对 C for 循环进行优化,我刚刚阅读了展开和累加器。如果数据在循环中不相互依赖,那么展开和累加器的使用确实利用了并行性,并且代码完成得更快。

所以我天真的想法是,为什么不添加更多的累加器并展开更多次?

我这样做了,并注意到每个元素的平均周期减少的回报递减。

我的问题是为什么?

A:是不是因为我们的寄存器用完了,需要同时处理,信息需要存储在内存中?

B:还是因为“清理循环”必须在展开循环之后处理更多元素?

是A和B的组合吗?

【问题讨论】:

  • 不要忘记展开会给指令缓存带来更大的负担。
  • L1 指令缓存不是大到足以处理 16 个无符号整数吗?当我从 8 到 16 个累加器/展开时,收益可以忽略不计。
  • @filposs:跟踪缓存肯定不是。我认为它只适合大约 50-100 µops。
  • 所谓的“收益递减”,不是说一段时间后它会变慢吗?否则,你期待什么,真的吗?你展开的越多,循环就会永远越来越快? (通常,“收益递减”意味着您获得的收益越来越少,而不是越来越差。)
  • @filposs:那么我不禁想知道你在期待什么。您是否期望每个循环“迭代”越展开越快,直到达到零时间?

标签: c optimization


【解决方案1】:

我不确定我是否只是在这里陈述显而易见的事情,但是您看到展开收益递减的主要原因仅仅是因为您在很大程度上消除了循环,而 CPU 上的剩余时间几乎全部用于您正在做的“有用”工作。

展开的好处是您消除了循环本身的开销——即索引增量、比较、分支等。 - 并不是说​​它使循环的有用工作更快。当您达到循环开销大部分被消除的程度时,很明显您不会看到更多展开带来的进一步改进。

另一方面,进一步展开的某些方面肯定会降低性能,例如寄存器溢出到内存,I-cache 工作效率较低,循环对于跟踪缓存来说太大(在处理器上运动等)等。

【讨论】:

  • 对你来说很明显,对初学者来说不那么明显。谢谢
  • 对不起,我只是假设这将是您正在阅读的任何材料的第一段。 :)
【解决方案2】:

更有可能,A。我不久前就看到了。我自己也做了同样的问题,我得出的结论是我的寄存器用完了,所以没有更多的快速累加器。用于处理未展开的其余元素的清理代码运行的时间比展开的主循环要少得多。

【讨论】:

  • 寄存器用完后究竟会发生什么?我是硬件方面的新手。它不会存储在 DRAM 中,对吗?因为从 DRAM 中检索某些东西需要大约 1000 个周期。我们的信息是否存储在更靠近处理器的缓存中?
  • @fliposs:是的,通常。如今,大多数处理器在必须进入主内存之前都有 L1、L2 和 L3 缓存。这是一个有趣的演讲,可以帮助您入门:youtube.com/watch?v=WDIkqP4JbkE
  • 当编译器用完寄存器来存储变量时,它只是使用内存位置。在硬件级别发生的事情,最终存储到 DRAM 中的变量,缓存甚至磁盘中的虚拟内存,对于编译器来说是无关紧要的。程序员可以通过在其定义中添加关键字register 来建议(在某些情况下强制)将变量存储在 CPU 寄存器中。
  • 将寄存器值写回内存并读回非常昂贵。在现代机器上,即使在理想的缓存命中条件下,我们也在谈论单程 5-10 个周期。展开循环不会直接导致过度使用寄存器,但会导致巨大的循环体,使编译器在管理寄存器生命周期方面非常困难。
猜你喜欢
  • 2016-08-03
  • 2021-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-29
相关资源
最近更新 更多