1

你如何告诉编译器根据迭代次数或其他属性展开循环?或者,如何在 Visual Studio 2005 中打开循环展开优化

编辑:例如

//Code Snippet 1
    vector<int> b;
    for(int i=0;i<3;++i) b.push_back(i);

相对于

//Code Snippet 2
    vector<int> b;
    b.push_back(0);
    b.push_back(1);
    b.push_back(2);

push_back() 就是一个例子,我可以用任何可能需要很长时间的东西来替换它。

但是我在某处读到我可以使用代码 1,如果循环满足某些条件,编译器可以将其展开为代码 2。所以我的问题是:你是怎么做到的?已经有一个关于 SO 的讨论,关于哪个更有效,但无论如何,对此的任何评论都是值得赞赏的。

4

5 回答 5

7

通常你只是让编译器完成它的工作。如果在编译时知道循环的数量,并且打开了编译器优化,编译器将平衡代码大小与分支减少并展开任何不可滚动的循环。

如果这真的不是你想要的,也有可能用达夫的设备自己做:(来自维基百科)

send(to, from, count)
register short *to, *from;
register count;
{
    register n=(count+7)/8;
    switch(count%8){
    case 0: do{ *to = *from++;
    case 7:     *to = *from++;
    case 6:     *to = *from++;
    case 5:     *to = *from++;
    case 4:     *to = *from++;
    case 3:     *to = *from++;
    case 2:     *to = *from++;
    case 1:     *to = *from++;
        }while(--n>0);
    }
}

这使您可以使用运行时确定的迭代计数展开。

如果它仍然是你想要的编译时展开,并且内置优化不是你想要的(如果你想要更细粒度的控制),你可以创建一个 C++ 模板来做你想做的事。这是一个非常简单的模板应用程序,因为它都是在编译时完成的,所以您不会丢失任何函数内联或编译器可能额外执行的其他优化。

于 2009-09-02T16:11:01.897 回答
6

它通常相当简单:“您启用优化”。

如果您告诉编译器优化您的代码,那么循环展开是它尝试应用的众多优化之一。

但请记住,展开并不总是会产生更快的代码。它可能会导致缓存未命中(在数据和指令缓存中)。并且使用现代 CPU 中的高级分支预测,构成循环的分支的成本通常可以忽略不计。

有时,编译器可能会确定展开会产生较慢的代码,然后它不会这样做。

于 2009-09-02T17:09:08.787 回答
5

请注意,您说:

push_back() 就是一个例子,我可以用任何可能需要很长时间的东西来替换它。

事实上,如果 push_back() (或任何你替换它的东西)需要很长时间,那么循环展开就会浪费精力。循环通常不是特别慢。循环展开有意义的时间是循环内完成的工作非常小 - 在这种情况下,循环结构可能开始主导该段执行的处理。

我相信你会得到许多其他答案——除非你真的发现它是一个瓶颈,否则不要担心这种事情。99%的时候,不会。

于 2009-09-02T17:37:07.497 回答
5

循环展开不会神奇地使循环中执行的代码运行得更快。它所做的只是节省一些用于比较循环变量的 CPU 周期。因此,只有在循环体本身几乎什么都不做的非常紧凑的循环中才有意义。

关于您的示例:虽然push_back()需要摊销恒定时间,但这确实包括偶尔的分配-复制-释放周期以及实际对象的复制。我非常怀疑循环中的比较与此相比起重要作用。如果你用其他需要很长时间的东西替换它,同样适用。

当然,这在任何特定 CPU 上都可能是错误的,而在任何其他 CPU 上都是正确的。由于现代 CPU 架构及其缓存、指令流水线和分支预测方案的特性,很难在优化代码方面超越编译器。您会尝试通过展开来优化具有“沉重”主体的循环,这似乎暗示您对此知之甚少。(我很努力的这么说,以免你被冒犯。我是第一个承认我自己在这个游戏中比较松的人。)

如果您遇到性能问题,IME 在 10 个案例中有 9 个消除愚蠢的错误(如复制复杂对象)并优化算法和数据结构是您应该关注的。

(如果您仍然认为您的问题属于 1-out-of-10 类别,请尝试 Intel 的编译器。上次我查看它时,您可以免费下载测试版本,它插入 VS,非常容易设置,并在我测试的应用程序中带来了大约 0.5% 的速度增益。)

于 2009-09-02T17:29:42.160 回答
3

右键单击项目,选择属性并导航: alt text http://img200.imageshack.us/img200/8685/propsm.jpg

WRT 循环展开,请注意,由于缓存命中/未命中,MS Visual Studio 优化大小而不是速度实际上会产生更快的代码,这一点已被普遍接受。

于 2009-09-02T17:59:33.770 回答