繁体   English   中英

低级的C / C ++性能?

[英]Low level C/C++ performance?

更新:我只是设法击败了我自己的32如果代码:

void test(char *file_char, unsigned int size)
{
    char* file_ = file_char;
    char* size_x = file_char+size;
    char to_find = 0;

    for(unsigned int i = 0; i < 10000; i++)
    {
        file_char = file_;

        while(*file_char++ != to_find);//skip all characters till we find a 0

        if(*file_char)//some if in order to avoid compiler removing our test code
            cout << "found";
    }
}

上面的代码要求0在数组中至少出现一次,否则将出现错误,但比if代码和MUCH紧凑得多。

有什么方法可以使上述代码更快? (具有一个char数组并尝试查找char出现的位置)?

我写了一些代码,我真的很困惑。

在里面:

int main()
{
    FILE *file;
    file = fopen("C:\\data.txt", "rb");

    static const int size = 60000;

    char *file_char = (char*)malloc(size);

    unsigned int i = 0;
    while(i < size)
        fread(&file_char[i++], 1, 1, file);

    clock_t clock_ = clock();
    test(file_char, size);
    std::cout << ((double)clock()-clock_)/1000;
    return 0;
}

下面的代码执行需要3.5秒:

void test(char *file_char, unsigned int size)
{
    for(unsigned int i = 0; i < 100000; i++)
    {
        unsigned int pos = 0;
        char to_find = 0;
        while(pos < size)
            if(file_char[pos++] == to_find)
                std::cout << "found";
    }
}

但是下面的代码需要1.8秒,时间却减少了一半!

void test(char *file_char, unsigned int size)
{
    for(unsigned int i = 0; i < 100000; i++)
    {
        unsigned int pos = 0;
        char to_find = 0;
        while(pos < size)
        {
            if(file_char[pos] == to_find)
                std::cout << "found";
            else if(file_char[pos+1] == to_find)
                std::cout << "found";
            else if(file_char[pos+2] == to_find)
                std::cout << "found";
            else if(file_char[pos+3] == to_find)
                std::cout << "found";
            else if(file_char[pos+4] == to_find)
                std::cout << "found";
            else if(file_char[pos+5] == to_find)
                std::cout << "found";
            else if(file_char[pos+6] == to_find)
                std::cout << "found";
            else if(file_char[pos+7] == to_find)
                std::cout << "found";
            else if(file_char[pos+8] == to_find)
                std::cout << "found";
            else if(file_char[pos+9] == to_find)
                std::cout << "found";
            else if(file_char[pos+10] == to_find)
                std::cout << "found";
            else if(file_char[pos+11] == to_find)
                std::cout << "found";
            else if(file_char[pos+12] == to_find)
                std::cout << "found";
            else if(file_char[pos+13] == to_find)
                std::cout << "found";
            else if(file_char[pos+14] == to_find)
                std::cout << "found";
            else if(file_char[pos+15] == to_find)
                std::cout << "found";
            else if(file_char[pos+16] == to_find)
                std::cout << "found";
            else if(file_char[pos+17] == to_find)
                std::cout << "found";
            else if(file_char[pos+18] == to_find)
                std::cout << "found";
            else if(file_char[pos+19] == to_find)
                std::cout << "found";
            else if(file_char[pos+20] == to_find)
                std::cout << "found";
            else if(file_char[pos+21] == to_find)
                std::cout << "found";
            else if(file_char[pos+22] == to_find)
                std::cout << "found";
            else if(file_char[pos+23] == to_find)
                std::cout << "found";
            else if(file_char[pos+24] == to_find)
                std::cout << "found";
            else if(file_char[pos+25] == to_find)
                std::cout << "found";
            else if(file_char[pos+26] == to_find)
                std::cout << "found";
            else if(file_char[pos+27] == to_find)
                std::cout << "found";
            else if(file_char[pos+28] == to_find)
                std::cout << "found";
            else if(file_char[pos+29] == to_find)
                std::cout << "found";
            else if(file_char[pos+30] == to_find)
                std::cout << "found";
            else if(file_char[pos+31] == to_find)
                std::cout << "found";

            pos+=32;
        }
    }
}

我使用的是Visual Studio 2012 x64,该程序从不提示任何内容,因为没有char为0。如何解释? 如何在不使用32 if的情况下存档相同的性能?

编辑1:如果我创建64 ifs,则没有速度超过32 ifs版本。

编辑2:如果我删除else并保留ifs,则程序需要4秒钟。

现在,如何解释以上不合理的结果?

循环基本上包括两个比较: pos < sizefile_char[pos] == to_find 通过展开循环,可以将比较次数从2 * size减少到(size + size / 32)。

我认为这两个代码是不同的。

在第一个中,您每次都要检查“ if”比较。

在第二个中,如果第一个好,则跳过以下所有! (因为其他),因此您节省了很多比较(但缺少检查)。

对于相同的代码,必须删除所有的“ else”。

为了确定,我已经进行了一些测试。

使用g ++(在Linux和Windows下),我得到与Visual Studio相同的结果:

版本1 (无显式循环展开)

g++ -O3 7.5秒

版本2 (显式循环展开)

g++ -O3

但启用了-funroll-loops选项(通常默认情况下未启用此优化,因为它可能会或可能不会使其运行得更快):

版本1 (无显式循环展开)

g++ -O3 -funroll-loops 2.2s

版本2 (显式循环展开)

g++ -O3 -funroll-loops 2.2s

因此,这与循环展开有关。

编辑

您可以更改最后一个示例以显式插入哨兵,例如:

int main()
{
  static const int size = 60000;

  char *file_char = (char*)malloc(size+1);  // The last element is the sentry

  // ...Fill file_char[]...

  file_char[size] = 0;  // the sentry

  // ...
}

因此test功能不会失败(当然,您必须检查是否找到了哨兵或“好”零,但如果是,则为零)。

版本3 (哨兵)

g++ -O3 0.68秒

g++ -O3 -funroll-loops 0.72s

在您的第二个示例中,一旦匹配成功,它将跳过其余的比较...如果您可以保证您每32个索引中只有一个to_find,那将是可行的...但是您也可以重新写入(可能有一个1 off错误):

void test(char *file_char, unsigned int size)
{
    for(unsigned int i = 0; i < 100000; i++)
    {
        unsigned int pos = 0;
        char to_find = 0;
        int skip = 32;
        while(pos < size)
        {
            if(file_char[pos++] == to_find)
            {
                std::cout << "found";
                pos+=skip;
            }
            skip--;
            if (!skip)
            {skip = 32;}
        }
    }
}

这是一种通常由某些优化编译器应用的优化技术,称为循环展开优化。 在第一个for循环代码中必须运行10,000次迭代,而在第二个代码中,迭代次数减少为floor(10,000 / 32)。 在许多迭代过程中,执行了for循环的结尾,该循环被编译为到循环开始的跳转指令(无条件跳转在机器代码中非常昂贵,因为它可能导致刷新CPU中的指令缓冲区)循环测试和循环计数器更新指令的使用频率要低得多。在相当多的迭代中,这代表了执行时间的显着改善。 同样,尽管循环中其他测试的数量大大增加,但它们将被编译为类似于以下内容的跳转表:

if(condition1)转到

if(condition2)转到

...

发现:

这会带来更好的性能。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM