快速初始化c

时间:2019-07-02 03:43:22

标签: c performance x86

编者注:

事实证明这是一个测量问题。两种方式都在同一程序中测试apparently,首先运行4字节存储方式(并支付页面错误和TLB丢失的代价),然后使用TLB +缓存运行慢速的1字节存储循环预备和获胜2倍,而不是预期4倍的损失。

这两个asm循环都是不好的,如果启用了完全优化(-O3)进行编译,它们的运行速度将提高4到8倍,因此gcc会使用SSE2或AVX一次存储16或32个字节,具体取决于-march=个目标选项。


我正在编写一些代码来初始化c中的int数组(在Ubuntu,intel core i5中为sizeof(int)= 4),通常是这样的:

for(size_t i=0;i<N;i++) a[i] = value;

但是后来,我发现了另一种更快的方法:

unsigned char *p = a;
for(size_t i=0;i<N;i++)
{
    *p = value;
    *(p+1) = value >> 8;
    *(p+2) = value >> 16;
    *(p+3) = value >> 24;
    p += 4;
}

我不明白,为什么四个movb比一个movl快?

更新:我正在使用gcc 7.4.0,选项:-O2

组装:

mov    %rax,%r12
mov    %rbp,%rax
nopl   0x0(%rax,%rax,1)
LOOP:
movl   $0x12345678,(%rax)
add    $0x4,%rax
cmp    %rax,%rbx
jne    LOOP

第二种方法:

mov    %rax,%r12
mov    %rbp,%rax
nopl   0x0(%rax)
LOOP:
movb   $0x78,(%rax)
movb   $0x56,0x1(%rax)
add    $0x4,%rax
movb   $0x34,-0x2(%rax)
movb   $0x12,-0x1(%rax)
cmp    %rax,%rbx
jne    LOOP

%rax是起始地址,%rbx是最终地址,编译器将索引版本转换为指针版本。

我检查了值= 0x12345678,第二种方法快了2倍。

0 个答案:

没有答案