循环展开 vs 循环分块

22

请问这两种优化技术是相同的还是不同的?

此外,这是程序员还是编译器的责任呢?

2个回答

27
这两种技术是不同的。请参阅循环展开循环瓷砖的描述。
循环展开是为了消除循环的开销。它通常只适用于迭代次数较小且在编译时已知的相当小的循环。大多数情况下由编译器完成。
在早期,计算机速度较慢,编译器比较简陋的时候,程序员会手动展开循环,但现在除了一些非常受限制的嵌入式系统外,程序员做这件事情可能很少见。
循环瓷砖通常与非常大的数据集一起使用。目的是:将一些数据加载到缓存内存中,并在分页新数据之前执行所有操作。
根据正在执行的操作和数据的内部组织方式,简单的循环可能会跳转到不同的数据页面,导致大量的缓存未命中(和页面加载)。仔细规划执行顺序可以显著改善某些问题的运行时间。
虽然编译器可能会执行循环瓷砖,但有时程序员可能会手动执行,可能做得比编译器更好。
一般来说,不要尝试进行这些类型的优化,因为它们会给代码增加很多复杂性(和错误),并且通常只提供适度的性能提升。但是,如果您的代码运行缓慢,并且分析表明存在特定类型的瓶颈,则应考虑像循环瓷砖这样的东西,并且可能会带来大的性能提升。

2
这些优化对于性能来说非常关键。我很想看到没有这些优化的高效matmul。我同意它可能会增加复杂性,因此可能会出现潜在的错误,但是即使是这些错误也可以通过良好的实践来管理。平铺和展开是所有处理重型数学的程序员都应该熟悉的优化技巧。 - Christian Sarofeen
即使迭代次数很大或未知,展开小循环仍然至关重要。编译器可以展开8次,并添加代码来处理最后的0-7次迭代。(它们可以这样做。您必须检查它们是否实际上这样做了。) - maxy

23

这是两种完全不同的性能优化。

循环展开是一种代码优化,其中代码在循环内被复制,并且总循环次数减少。好处是减少循环开销(通常仅适用于非常小的循环),以及通过减少超标量CPU中依赖关系停顿来实现更好的指令调度。这可以手动和/或作为编译器优化来完成。

平铺是一种内存优化,旨在通过处理瓷砖(较大数据结构中的小块)来更好地利用缓存,通常在图像或其他2D数据结构的上下文中实现。这通常在源代码级别上实现,作为算法实现的整体设计的一部分。


1
循环展开是一种速度优化。这两种优化(实际上,所有的优化)都应用于代码。 - user395760
6
它们都是针对“性能”(即速度)的优化,但循环展开是通过提高代码效率来实现的,而分块则通过更好地利用缓存/内存层次结构来提高性能。 - Paul R

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接