编者注:
事实证明这是一个测量问题。两种方式都在同一程序中测试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倍。