【发布时间】:2019-08-02 11:29:07
【问题描述】:
我有 2 个 (strcpy) 函数的源代码,我想知道哪一个更快,性能更高...
unsigned
strcpy(const char * str, char * des) {
register const char * ptr = str;
while ((*des = *str)) {
str++;
des++;
}
return (str - ptr);
}
unsigned
strcpy2(const char * str, char * des) {
register unsigned i = 0;
while ((des[i] = str[i])) i++;
return i;
}
第一个使用 str 和 des 地址,第二个使用 index ... 第一个有一个额外的(++),所以乍一看,第一个函数的性能低于第二个,因为对每个字符都做了额外的(++)但是当我在 GCC 中使用(-O3)优化时,结果(汇编代码)告诉我别的东西(第一个strcpy性能更高,动作更少)
strcpy:
movzbl (%rdi), %eax
movb %al, (%rsi)
testb %al, %al
je .L4
movq %rdi, %rax
.L3:
movzbl 1(%rax), %edx
addq $1, %rax
addq $1, %rsi
movb %dl, (%rsi)
testb %dl, %dl
jne .L3
subl %edi, %eax
ret
.L4:
xorl %eax, %eax
ret
strcpy2:
movzbl (%rdi), %eax
testb %al, %al
movb %al, (%rsi)
movl $0, %eax
je .L10
.L9:
leal 1(%rax), %ecx
movzbl (%rdi,%rcx), %edx
movq %rcx, %rax
movb %dl, (%rsi,%rcx)
testb %dl, %dl
jne .L9
ret
.L10:
ret
是真的吗?第一个 strcpy 具有更高的性能(性能 = 更少的操作和更快)?
【问题讨论】:
-
两者都附加了一个多余的终止零。
-
我的意思是循环之后的赋值是多余的。您可以删除它。
-
@Jason,人类在从源代码估计程序性能方面非常糟糕(汇编也是源代码)。此外,相对性能可能会因程序运行的硬件而异。测试是最好、最可靠的方法。
-
第二版 asm 有严重的优化缺失(与不自动矢量化不同,因为 gcc 从不为搜索循环这样做)。 lea+mov 显然比
inc更糟糕,这将使其在除 Sandybridge/Ivybridge 之外的 CPU 上降至 4 个融合域 uop,其中存储的索引寻址模式将取消分层。 Micro fusion and addressing modes。 显然,这些都很糟糕,一次只能复制 1 个字节,甚至无法在 Intel CPU 上管理每个时钟周期 1 个字节。 SSE2 是 x86-64 的基准。 -
@JohnBollinger:为自己说话;我很确定 Intel Haswell 和更高版本将以每字节 1.25 个周期为大型副本运行这些循环中的任何一个,在前端遇到瓶颈。对于具有页面错误和缓存未命中的大型副本,它会减慢一小部分速度,但对于硬件预取来说,它的速度足以在大部分时间轻松跟上。
标签: c performance gcc x86-64 micro-optimization