首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >奇怪的C++性能差异?

奇怪的C++性能差异?
EN

Stack Overflow用户
提问于 2010-02-05 18:59:52
回答 8查看 513关注 0票数 6

我只是偶然发现了一个似乎有违反直觉的性能影响的变化。有人能为这种行为提供一个可能的解释吗?

原始代码:

代码语言:javascript
复制
for (int i = 0; i < ct; ++i) {
    // do some stuff...

    int iFreq = getFreq(i);
    double dFreq = iFreq;

    if (iFreq != 0) {
        // do some stuff with iFreq...
        // do some calculations with dFreq...
    }
}

在“性能传递”期间清理这些代码时,我决定将dFreq的定义移到if块中,因为它只在if中使用。有几个涉及dFreq的计算,所以我没有完全消除它,因为它确实节省了从intdouble的多个运行时转换的成本。我期望没有任何表现上的差异,如果有的话,一个微不足道的改善。但其性能下降了近10%。我已经测量了很多次了,这确实是我所做的唯一的更改。上面显示的代码片段在其他几个循环中执行。在运行过程中,我会得到非常一致的时间安排,并且可以确定我所描述的更改会使性能下降10%。我预计性能会提高,因为intdouble的转换只有在iFreq != 0时才会发生。

加密代码:

代码语言:javascript
复制
for (int i = 0; i < ct; ++i) {
    // do some stuff...

    int iFreq = getFreq(i);

    if (iFreq != 0) {
        // do some stuff with iFreq...
        double dFreq = iFreq;
        // do some stuff with dFreq...
    }
}

有人能解释一下吗?我使用的是VC++ 9.0和/O2。我只想弄明白我在这里不算什么。

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2010-02-05 19:32:17

在使用dFreq进行计算之前,您应该将转换到iFreq的过程直接放在if()中。如果指令在代码中更高,则转换可以与整数计算并行执行。一个好的编译器可能会把它推到更高的位置,而一个不太好的编译器可能会把它留在原地。由于您将其移动到整数计算之后,它可能无法与整数代码并行运行,从而导致减速。如果它确实并行运行,那么可能没有什么改进,这取决于CPU (发出一个FP指令,其结果从未被使用过,在最初的版本中几乎没有效果)。

如果您真的想要提高性能,许多人已经完成了基准测试,并按此顺序排列了以下编译器:

( 1) ICC - Intel编译器2) GCC -一个好的第二名3) MSVC生成的代码与其他代码相比可能很差。

如果他们有-O3的话,你也可以试试它。

票数 7
EN

Stack Overflow用户

发布于 2010-02-05 19:10:23

也许getFreq的结果在第一种情况下保存在寄存器中,在第二种情况下写到内存中?也可能是,性能下降与CPU机制如流水线和/或分支预测有关。您可以检查生成的程序集代码。

票数 6
EN

Stack Overflow用户

发布于 2010-02-05 21:25:16

在我看来,这就像一个管道货摊

代码语言:javascript
复制
int iFreq = getFreq(i);
    double dFreq = iFreq;

    if (iFreq != 0) {

允许双倍转换与其他代码并行进行,因为没有立即使用dFreq。它为编译器在存储iFreq和使用它之间提供了一些东西,因此这种转换很可能是“免费的”。

代码语言:javascript
复制
int iFreq = getFreq(i);

if (iFreq != 0) {
    // do some stuff with iFreq...
    double dFreq = iFreq;
    // do some stuff with dFreq...
}

在转换为double之后,可能会碰到存储/引用暂停,因为您马上就开始使用double值了。

现代处理器每个时钟周期都可以做多个事情,但前提是这些东西是独立的。引用相同寄存器的两个连续指令通常会导致失速。实际转换为double可能需要3个时钟,但除了第一个时钟之外,所有的时钟都可以与其他工作并行进行,前提是您不引用一两条指令的转换结果。

C++编译器正在非常擅长于重新排序指令来利用这一点,看起来您的更改失败了一些很好的优化。

另一种(不太可能)的可能性是,当到浮动的转换在分支之前时,编译器能够完全删除分支。在现代处理器中,无分支代码通常是主要的性能胜利。

看看编译器为这两种情况实际发出了哪些指令是很有趣的。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2209603

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档