循环提升仍然是C代码的有效手动优化吗?

blu*_*lds 18 c c++ optimization gcc

使用最新的gcc编译器,我还需要考虑这些类型的手动循环优化,还是编译器会为我做好充分的处理?

Nor*_*sey 47

如果你的探查器告诉你循环有问题,那么,需要注意的是循环中的内存引用,知道它在循环中是不变的,但编译器没有.这是一个人为的例子,将一个元素冒泡到数组的末尾:

for ( ; i < a->length - 1; i++)
    swap_elements(a, i, i+1);
Run Code Online (Sandbox Code Playgroud)

可能知道调用swap_elements不会更改值a->length,但如果定义swap_elements在另一个源文件中,则编译器很可能不会.因此,提升a->length循环计算是值得的:

int n = a->length;
for ( ; i < n - 1; i++)
    swap_elements(a, i, i+1);
Run Code Online (Sandbox Code Playgroud)

在性能关键的内循环中,我的学生可以通过像这样的转换获得可测量的加速.

注意,没有必要提升计算n-1; 任何优化编译器都能完全发现局部变量之间的循环不变计算.它的内存引用和函数调用可能更难.并且代码n-1更明显正确.

正如其他人所指出的那样,在你进行分析并发现循环是一个真正重要的性能瓶颈之前,你没有任何业务可以做这些.

  • 回答这个问题的+1,实际上是在教学过程中教给OP一些东西,而不是用反刍的建议击败提问者.我希望我能更多地投票. (16认同)
  • 没关系,tgamblin,我为你投了赞成票. (2认同)

Jas*_*ams 18

编写代码,对其进行概要分析,并且只有在找到不够快的东西时才考虑优化代码,并且您无法想到可以首先减少/避免瓶颈的替代算法.

对于现代编译器,这个建议更为重要 - 如果您编写简单的干净代码,编译器的优化器通常可以更好地优化代码,而不是尝试给它时髦的"预优化"代码.

  • 加一.完美答案.我们应该专注于完成我们的工作(编写正确,可读,可维护的代码)并让编译器完成其工作(了解平台并为该平台生成语义正确的高效代码). (7认同)
  • -1表示优化问题的另一个恶意答案.再一次,过早优化的鹦鹉出来并获得投票,因为StackOverflow上没有人会想到性能. (7认同)
  • @Steve Jessop:这并没有否定这个反身的非答案已经在这里重复了一百万次的事实.告诉人们描述我没有问题,因为这是一个很好的经验法则.但是,看看诺曼的回答如下.它提到需要描述但实际上*教OP一些东西*.这也是唯一的答案,具体说明何时应该关心以及什么时候不应该关心.这个答案只是反刍和变幻莫测,所有喜欢用勺子喂养的最佳做法的人都会投票. (7认同)
  • 我想认为"预优化是根本",并且"简介优先"的口头禅已经在这个论坛上遭到了足够的打击,这是一个给定的,也许这个人已经考虑过这个,也许这个人只是想要他的问题回答了编译器的功能和质量,而不是辩论它的必要性. (6认同)
  • 另外,不要忘记在**优化之后对**进行分析,以确保优化确实是优化. (3认同)
  • 循环提升是不变量从循环内部移动到循环外部.这是一个很好的代码审查清单项目; 无论是个人还是团队.我不依赖编译器进行这种优化.这种优化减少了程序的执行时间,因为它是校验2GB的数据. (3认同)
  • @David Thornley:如果它在一个紧密的循环中,你实际上发现了性能问题,那不是微优化.我们是否应该让每个提出表现问题的人通过让委员会审查他们的动机来证明其必要性?即使OP过早地进行优化,提供信息的答案也会使*不是*的人受益.对不起,你不得不向很多人解释为什么他们的问题是愚蠢的,但恕我直言,你应该停止假设人们的动机.我相信,与我相信有意义的变量名称相比,人们更加尊重他人. (3认同)

Ada*_*eld 5

检查生成的组件并亲自查看.查看循环不变代码的计算是在循环内部还是在编译器生成的汇编代码中的循环外部完成的.如果没有进行环路吊装,请自行吊装.

但正如其他人所说,你应该首先找到你的瓶颈.一旦你确定这实际上是一个瓶颈,那么你应该检查编译器是否在热点中执行循环提升(也就是循环不变的代码运动).如果不是,请帮助它.