代码之家  ›  专栏  ›  技术社区  ›  Jacob

使用Visual Studio 2005展开小循环

  •  1
  • Jacob  · 技术社区  · 16 年前

    你怎么告诉编译器 unroll loops 基于迭代次数或其他属性?或者, 如何在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。所以我的问题是:你是怎么做到的?已经有一个关于哪个更有效的讨论了,但是任何关于这个的评论都是值得赞赏的。

    5 回复  |  直到 16 年前
        1
  •  6
  •   Stack Overflow is garbage    16 年前

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

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

    但请记住,展开不是 总是 将生成更快的代码。它可能会导致缓存未命中(在数据和指令缓存中)。随着现代CPU中先进的分支预测技术的出现,组成循环的分支的成本通常可以忽略不计。

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

        2
  •  7
  •   Salman A    16 年前

    通常只需让编译器完成它的工作。如果在编译时知道循环数,并且启用了编译器优化,则编译器将平衡代码大小和分支缩减,并展开任何不可展开的循环。

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

    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++模板来做你想做的事情。这是一个非常普通的模板应用程序,因为它都是在编译时完成的,所以您不会丢失任何函数内联或编译器可能做的其他优化。

        3
  •  5
  •   sbi    16 年前

    循环展开不会神奇地使循环中执行的代码运行得更快。它所做的只是节省一些用于比较循环变量的CPU周期。所以它只在非常紧密的循环中才有意义,在这个循环中,循环体本身几乎不做任何事情。

    关于你的例子:while push_back() 采用摊余固定时间,这包括偶尔分配拷贝释放周期加上实际对象的复制。我非常怀疑,与之相比,循环中的比较起着重要的作用。如果你用其他东西替换它需要很长时间,这同样适用。

    当然,这在任何特定的CPU上都可能是错误的,在任何其他CPU上都是正确的。随着现代CPU体系结构及其缓存、指令管道和分支预测方案的特点,它已经成为 非常 在优化代码方面很难胜过编译器。你试图通过展开来优化一个“重”体的循环,这似乎是一个暗示,你不知道在这方面做得太多。(我正努力这么说,这样你就不会被冒犯了。我是第一个承认自己在这场比赛中更放松的人。)

    如果您的性能有问题,那么您应该看看10种情况中有9种情况下的IME,消除愚蠢的错误(如复制复杂对象),优化算法和数据结构。

    (如果您仍然认为您的问题属于10分之一的类别,请尝试使用英特尔的编译器。上一次我看它的时候,你可以免费下载一个测试版本,它插在vs上,非常容易设置,在我测试过的应用程序中带来了大约0.5%的速度增益。)

        4
  •  5
  •   Michael Burr    16 年前

    注意你说:

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

    事实上,如果push_back()(或者用什么替换它)需要很长时间,那么展开循环就是浪费精力。循环通常不是特别慢;循环展开的时间很有意义,因为循环内部完成的工作非常小——在这种情况下,循环结构可能开始主导执行过程的处理。

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

        5
  •  3
  •   Tom    16 年前

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

    WRT循环展开,请注意,人们普遍认为,使用MS Visual Studio优化大小而不是速度实际上会由于缓存命中/未命中而产生更快的代码。

    推荐文章