代码之家  ›  专栏  ›  技术社区  ›  aJ.

编译器优化导致性能降低

  •  5
  • aJ.  · 技术社区  · 14 年前

    我有一个奇怪的问题。我有以下代码:

    template<clss index, class policy>
    inline int CBase<index,policy>::func(const A& test_in, int* srcPtr ,int* dstPtr)
    {
        int width = test_in.width();
        int height = test_in.height();
    
        double d = 0.0; //here is the problem
        for(int y = 0; y < height; y++)
        {
    
            //Pointer initializations
    
            //multiplication involving y
            //ex: int z = someBigNumber*y + someOtherBigNumber;
            for(int x = 0; x < width; x++)
            {
                //multiplication involving x
            //ex: int z = someBigNumber*x + someOtherBigNumber;
                if(soemCondition)
                {
                    // floating point calculations
                }
                *dstPtr++ = array[*srcPtr++];
            }
        }
    }
    

    内部循环执行了将近200000次,整个函数需要100毫秒才能完成。(使用aqtimer分析)

    我发现一个未使用的变量 double d = 0.0; 在外环外,并将其拆下。在这一改变之后,突然之间,这个方法要花费500毫秒来执行相同数量的执行。(慢5倍)。

    这种行为在具有不同处理器类型的不同机器中是可重复的。 (Core2,双核处理器)。

    我使用的VC6编译器具有优化级别 O2 。 下面是使用的其他编译器选项:

     -MD -O2 -Z7 -GR -GX -G5 -X -GF -EHa
    

    我怀疑编译器优化并删除了编译器优化 /O2 . 在该函数正常运行后,它将以100ms作为旧代码。

    有人能解释一下这种奇怪的行为吗?

    为什么在删除未使用的变量时编译器优化会降低性能?

    注意:程序集代码(更改前后)看起来相同。

    3 回复  |  直到 14 年前
        1
  •  5
  •   Andreas Brinck    14 年前

    如果程序集代码在更改之前和之后看起来相同,则错误以某种方式与函数的计时方式有关。

        2
  •  4
  •   Stack Overflow is garbage    14 年前

    vc6简直就是一辆马车。众所周知,在某些情况下,它会生成不正确的代码,而且它的优化器也没有那么先进。这个编译器已经有十多年的历史了,而且已经有很多年没有得到支持了。

    所以实际上,答案是“你在使用一个错误的编译器。希望出现错误行为,特别是在启用优化时。”

    我不认为升级到一个现代的编译器(或者仅仅在一个编译器上测试代码)是一个选项吗?

    显然,生成的程序集不能相同,否则就不会有性能差异。

    唯一的问题是 哪里 不同之处在于。有了错误的编译器,很可能是代码中一些完全不相关的部分突然被不同的方式编译并中断。不过,很可能为此函数生成的程序集代码是 同样,这些差异是如此微妙以至于你没有注意到它们。

        3
  •  1
  •   Thomas Matthews    14 年前

    宣布 width height 作为const{unsigned}整数。{ 这个 未签名 应使用,因为高度和宽度从不为负。 }

    const int width = test_in.width();
    const int height = test_in.height();
    

    这有助于编译器进行优化。其值为 const ,它可以将它们放入代码或寄存器中,知道它们不会更改。此外,它还免除了编译器猜测变量是否正在更改的麻烦。

    我建议打印出未使用的版本的程序集代码 double 没有。这将使您深入了解编译器的思想过程。