我编写了一个函数Str::Compare
,它基本上是以另一种方式重写的strcmp
。
在比较这两个函数时,在循环中重复500'000'000次,strcmp
执行速度太快, x750 快一倍。
此代码是在C库中编译的,-Os
参数为active:
int Str::Compare(char* String_1, char* String_2)
{
char TempChar_1, TempChar_2;
do
{
TempChar_1 = *String_1++;
TempChar_2 = *String_2++;
} while(TempChar_1 && TempChar_1 == TempChar_2);
return TempChar_1 - TempChar_2;
}
该功能的执行时间为3.058s
,而strcmp
的执行时间仅为0.004s
。
为什么会这样?
这也是我实现基准测试循环的方式:
int main()
{
char Xx[] = {"huehuehuehuehuehuehuehuehuehuehuehuehuehue"},
Yy[] = {"huehuehuehuehuehuehuehuehuehuehuehuehuehue"};
for(int i = 0; i < 500000000; ++i)
Str::Compare(Xx, Yy);
}
修改:
在测试我写的一些代码和优化时,我们提高了Str::Compare
速度。
如果在strcmp
x750 之前,现在只有 x250 。这是新代码:
int Str::Compare(char* String_1, char* String_2)
{
char TempChar_1, TempChar_2, TempChar_3;
while(TempChar_1 && !TempChar_3)
{
TempChar_1 = *String_1++;
TempChar_2 = *String_2++;
TempChar_3 = TempChar_1 ^ TempChar_2;
}
return TempChar_1 - TempChar_2;
}
新执行时间为0.994s
。
答案 0 :(得分:24)
我很好奇并建立了一个测试程序:
#include <string.h>
compare(char* String_1, char* String_2)
{
char TempChar_1,
TempChar_2;
do
{
TempChar_1 = *String_1++;
TempChar_2 = *String_2++;
} while(TempChar_1 && TempChar_1 == TempChar_2);
return TempChar_1 - TempChar_2;
}
int main(){
int i=strcmp("foo","bar");
int j=compare("foo","bar");
return i;
}
我使用gcc 4.7.3将其编译为汇编程序gcc -S -Os test.c
,导致以下汇编程序:
.file "test.c"
.text
.globl compare
.type compare, @function
compare:
.LFB24:
.cfi_startproc
xorl %edx, %edx
.L2:
movsbl (%rdi,%rdx), %eax
movsbl (%rsi,%rdx), %ecx
incq %rdx
cmpb %cl, %al
jne .L4
testb %al, %al
jne .L2
.L4:
subl %ecx, %eax
ret
.cfi_endproc
.LFE24:
.size compare, .-compare
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "bar"
.LC1:
.string "foo"
.section .text.startup,"ax",@progbits
.globl main
.type main, @function
main:
.LFB25:
.cfi_startproc
movl $.LC0, %esi
movl $.LC1, %edi
call compare
movl $1, %eax
ret
.cfi_endproc
.LFE25:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3"
.section .note.GNU-stack,"",@progbits
我在x86汇编程序中表现不佳,但据我所知,删除了对strcmp的调用,只需用常量表达式(movl $1, %eax
)替换。因此,如果为测试使用常量表达式,gcc可能会将strcmp优化为常量。
答案 1 :(得分:5)
在比较性能时,我发现最好将测试函数和测试驱动程序放在不同的编译单元中。将测试函数放在单独的编译单元中,并将它们编译为您想要的任何优化级别,但编译未优化的测试驱动程序。否则你会遇到你在这里看到的那种问题。
问题是strcmp
比较了两个const
C风格的字符串。如果你在strcmp(string_a, string_b)
上循环500,000,000次,那么优化编译器将足够聪明以减少该循环以优化该循环,然后可能足够智能以优化剩余的一个strcmp
调用。
您的compare函数需要两个非const字符串。就编译器而言,您的功能可能会产生副作用。编译器不知道,因此无法将循环优化为零。它必须生成代码才能执行500,000,000次比较。
答案 2 :(得分:-1)
我相信大多数标准库都是用汇编语言编写的。这可能是您看到标准库比您的速度更快的原因。