Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
x86上的C 64位循环性能_C_Performance_Algorithm_64 Bit - Fatal编程技术网

x86上的C 64位循环性能

x86上的C 64位循环性能,c,performance,algorithm,64-bit,C,Performance,Algorithm,64 Bit,对于一些使用原始套接字的IPv4 ICMP处理代码,我需要一个Internet校验和函数(一个补码校验和),我偶然发现了在64位Intel处理器(使用gcc 4.8.2)上无法解释的行为。我想知道是否有人能解释一下 我使用32位累加器实现了第一个校验和函数,并执行16位求和。然后,我使用64位累加器和32位求和实现了相同的功能,认为求和越少,执行速度越快。结果是第一个实现的运行速度是第二个实现的两倍(O3优化)。我就是不明白为什么 下面的代码实际上并没有执行精确的校验和(我简化了它),但说明了这

对于一些使用原始套接字的IPv4 ICMP处理代码,我需要一个Internet校验和函数(一个补码校验和),我偶然发现了在64位Intel处理器(使用gcc 4.8.2)上无法解释的行为。我想知道是否有人能解释一下

我使用32位累加器实现了第一个校验和函数,并执行16位求和。然后,我使用64位累加器和32位求和实现了相同的功能,认为求和越少,执行速度越快。结果是第一个实现的运行速度是第二个实现的两倍(O3优化)。我就是不明白为什么

下面的代码实际上并没有执行精确的校验和(我简化了它),但说明了这个问题。两者都编译为64位,在64位本机平台上运行(LP64:short 16位,int 32位,long 64位,指针64位)

  • 32位累加器和16位和

    unsigned short
    cksum_16_le(unsigned char* data, size_t size)
    {
        unsigned short word;
        unsigned int sum = 0;
        unsigned int i;
    
        for(i = 0; i < size - 1; i += 2)
            sum += *((unsigned short*) (data + i));
    
        sum = (sum & 0xffff) + (sum >> 16);
        sum = (sum & 0xffff) + (sum >> 16);
    
        return ~sum;
    }
    
    我不喜欢这样的替身

    64位累加器和32位和

    unsigned short
    cksum_32_le(unsigned char* data, size_t size)
    {
        unsigned long word;
        unsigned long sum = 0;
        unsigned int i;
    
        for(i = 0; i < size - 3; i += 4)
            sum += *((unsigned int*) (data + i));
    
        sum = (sum & 0xffffffff) + (sum >> 32);
        sum = (sum & 0xffffffff) + (sum >> 32);
        sum = (sum & 0xffff) + (sum >> 16);
        sum = (sum & 0xffff) + (sum >> 16);
    
        return ~sum;
    }
    
    既然你写了:

    两者都编译为64位,在64位本机平台上运行(LP64:short 16位,int 32位,long>64位,指针64位)

    我建议使用(unsigned long*)。有些人建议在反汇编代码中检查实际情况。我想这是因为你的int*cast加了长累加器


    没有O2O3标志怎么办?您能告诉我在正常编译模式下的速度是多少吗?

    我认为它无法展开“for”循环,因为从char*转换为unsigned int*。类型转换通常会阻止编译器优化代码,因为在这种情况下无法进行完美的别名分析。如果您首先声明一个附加的本地指针来在循环之前强制转换“数据”指针,这样循环中就没有任何强制转换,编译器应该能够优化“for”循环。

    可能的答案是:“i 这与while循环无关。当您重写while循环时,您也更改了迭代条件并消除了上述原因


    我也更喜欢在循环之外进行类型转换,但这也揭示了一个限制-您的数据必须

    我以前也遇到过类似的问题;我在两个代码中都找不到任何问题。但对我有效的是改变编译器

    我猜GCC正在编写不推荐的程序集

    如果你可以反编译你的应用程序,我们可以对这个问题有更多的了解,但是这里没有足够的信息

    当我反编译代码时,我发现它多次重写了整个方法。但那可能只适合我

    希望这对你有所帮助,这里几乎没有这方面的信息


    如果我不得不猜测我会同意Learner的观点,我非常确定反编译的代码会指向for循环。我对这个问题很感兴趣,所以请回复。

    您是否使编译器的工作变得困难。在内部循环中,您自己通过选择索引步长和强制转换来计算字节偏移量。这可能会阻止循环展开或任何其他试图假定对齐的优化。也可能不允许编译器使用寻址模式并计算有效地址本身(或LEA-it)


    如果我这样做,我会将循环顶部的数据指针投射到您的步幅类型,并将循环计数器增加1。编译器可能会更高兴一点

    您是否尝试过将其分解并查看它们各自变成了什么?我们是否可以假设原始缓冲区在两个示例中正确对齐了段落?您是否确保
    数据
    正确对齐?如果它是2字节对齐的,则int版本的性能将受到影响。我还建议使用固定宽度的类型,以避免任何关于类型大小的歧义,即
    uint32\u t
    uint64\u t
    ,等等。同时尝试让函数接受
    无符号int*
    ;也许在
    char*
    版本中,编译器决定生成较少的最佳代码,因为它无法确定您是否传入了对齐指针。程序的整个要点是求32位值的和。将强制转换更改为读取64位值会产生错误的结果。那么这是正常的。正如其他人所评论的,这是一个填充问题。此外,如果ur整数只有32位大,则保存/添加两个64位整数将需要额外的操作/检查以获得正确的结果,尤其是当数字超过32位时。请“弃用”。不“贬值”。
    uint64_t sum = 0;
    const uint32_t* dptr = (const uint32_t*) data;
    
    while (size > 3)
    {
        sum += (uint32_t) *dptr++;
        size -= 4;
    }
    
    sum += *((unsigned int*) (data + i));