这是代码:

#include <iostream>
#include <time.h>

using namespace std;

#define ARR_LENGTH 1000000
#define TEST_NUM 0
typedef unsigned int uint;

uint arr[ARR_LENGTH];

uint inc_time(uint x) {
    uint y = 0, tm = clock();
    for (uint i = 0; i < x; i++) y++;
        return clock() - tm;
}

int main() {
    uint div = 0, mod = 0, tm = 0, overall = 0, inc_tm;
    srand(time(NULL));
    for (uint i = 0; i < ARR_LENGTH; i++) arr[i] = (uint)rand() + 2;

    tm = clock();
    for (uint i = 0; i < ARR_LENGTH - 1; i++)
        if (arr[i] % arr[i+1] != TEST_NUM) mod++;
    overall = clock() - tm;
    inc_tm = inc_time(mod);
    cout << "mods - " << mod << endl;
    cout << "Overall time - " << overall<< endl;
    cout << "   wasted on increment - " << inc_tm << endl;
    cout << "   wasted on condition - " << overall - inc_tm << endl << endl;

    tm = clock();
    for (uint i = 0; i < ARR_LENGTH - 1; i++)
        if (arr[i]/arr[i+1] != TEST_NUM) div++;
    overall = clock()-tm;
    inc_tm = inc_time(div);
    cout << "divs - " << div << endl;
    cout << "Overall time - " << overall << endl;
    cout << "   wasted on increment - " << inc_tm << endl;
    cout << "   wasted on condition - " << overall - inc_tm << endl << endl;

    return 0;
}


如果您使用的是Visual Studio,则只需以DEBUG(不是RELEASE)模式进行编译,并且如果您使用GCC而不是禁用无效代码消除(-fno-dce),则某些代码部分将无法工作。

因此,问题是:当您将TEST_NUM常量设置为非零(例如5)时,两个条件(模和除)都几乎同时执行,但是当您将TEST_NUM设置为0时,第二个条件执行慢(最多3倍!)。为什么?

这是反汇编清单:disassembly listing image http://img213.imageshack.us/slideshow/webplayer.php?id=wp000076.jpg

在0的情况下,使用test指令代替cmp X, 0,但是即使将cmp X, 5(在5的情况下)修补为cmp X, 0,您也会看到它不会影响模运算,但是会影响除法运算。

在更改TEST_NUM常数时,请仔细观察操作计数和时间如何变化。

如果有人可以,请说明如何发生?
谢谢。

最佳答案

对于TEST_NUM == 0,第一个条件很少为真。分支预测将认识到这一点并预测条件始终为假。这种预测在大多数情况下都是正确的,因此很少需要执行昂贵的错误预测分支。

'TEST_NUM == 5'的情况几乎相同:第一个条件很少为真。

对于第二个条件abd TEST_NUM == 0,每个arr[i] < arr[i+1]的除法结果为零,概率约为0.5。对于分支预测器而言,这是最坏的情况-在每第二种情况下分支将被预测为错误。平均而言,您将获得错误的预测分支所需的一半时钟周期(取决于体系结构,这可能在10到20个周期之间)。

如果值为TEST_NUM == 5,则第二个条件现在很少为真,则概率约为0.1(此处不太确定)。这是更好的“可预测的”。通常,预测器将预测(几乎)始终为假,介于两者之间,但有一些随机的真实值,但这取决于处理器的内部情况。但是无论如何,错误的预测分支得到的额外周期并不那么频繁,每五分之一的情况下最糟。

关于performance - x86“cmp”指令的奇怪行为,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8376629/

10-11 18:32