奇怪的C ++性能(VC 2010)

时间:2010-05-26 02:15:31

标签: c++ performance assembly

我有用C ++编写的循环,用MSVC2010编译需要很长时间才能运行。 (300毫秒)

    for (int i=0; i<h; i++) {
    for (int j=0; j<w; j++) {
        if (buf[i*w+j] > 0) {
            const int sy = max(0, i - hr);
            const int ey = min(h, i + hr + 1);
            const int sx = max(0, j - hr);
            const int ex = min(w, j + hr + 1);
            float val = 0;
            for (int k=sy; k < ey; k++) {
                for (int m=sx; m < ex; m++) {
                    val += original[k*w + m] * ds[k - i + hr][m - j + hr];
                }
            }
            heat_map[i*w + j] = val;
        }
    }
}

对我来说这似乎有点奇怪,所以我做了一些测试,然后将一些位改为内联汇编:(具体来说,代码总和为“val”)

    for (int i=0; i<h; i++) {
    for (int j=0; j<w; j++) {
        if (buf[i*w+j] > 0) {
            const int sy = max(0, i - hr);
            const int ey = min(h, i + hr + 1);
            const int sx = max(0, j - hr);
            const int ex = min(w, j + hr + 1);
            __asm {
                fldz
            }
            for (int k=sy; k < ey; k++) {
                for (int m=sx; m < ex; m++) {
                    float val = original[k*w + m] * ds[k - i + hr][m - j + hr];
                    __asm {
                        fld val
                        fadd
                    }
                }
            }
            float val1;
            __asm {
                fstp val1
            }
            heat_map[i*w + j] = val1;
        }
    }
}

现在它运行的时间只有一半,150毫秒。它完全一样,但为什么它快两倍?在这两种情况下,它都在发布模式下运行并进行了优化。我在原始的C ++代码中做错了吗?

2 个答案:

答案 0 :(得分:5)

我建议您尝试使用编译器支持的不同浮点计算模型 - precisestrictfast(请参阅/fp选项) - 使用之前的原始代码做出任何结论。我怀疑您的原始代码是使用一些过于严格的浮点模型编译的(在代码的第二个版本中未跟随您的程序集),这就是原始速度慢得多的原因。

换句话说,如果原始模型确实过于严格,那么您只是将苹果与橙子进行比较。这两个版本并没有真正做同样的事情,即使它第一眼看上去也是如此。

请注意,例如,在代码的第一个版本中,中间和以float值累加。如果使用precise模型进行编译,则中间结果必须舍入为float类型的精度,即使变量val已被优化并且使用了内部FPU寄存器代替。在您的汇编代码中,您不需要对累积结果进行舍入,这可能有助于提高其性能。

我建议您在/fp:fast模式下编译两个版本的代码,看看他们的表现在这种情况下的比较。

答案 1 :(得分:3)

要检查的一些事项:

  • 您需要检查实际上相同的代码。在内部,您的内联汇编语句与编译器生成的语句完全相同吗?我可以看到三个潜在差异(潜在因为它们可能会被优化)。第一个是val初始设置为零,第二个是额外变量val1(不太可能,因为它很可能只是改变堆栈指针的常量减法),第三个是你的内联程序集版本可能不会将临时结果放回val

  • 您需要确保样本空间很大。你没有提到你是否只完成了每个版本的一次运行或一百次运行,但运行越多越好,以便消除统计中“噪音”的影响。

  • 更好的测量方法是CPU时间而不是经过的时间。经过的时间会受到环境变化的影响(例如您的病毒检查程序或您的某项服务决定在您测试时执行某些操作)。大样本空间将缓解,但不一定能解决这个问题。