高手们,能帮我理解为什么调用数学库函数比编写内联汇编代码执行相同操作更有效吗?我写了这个简单的测试:
#include <stdio.h>
#define __USE_GNU
#include <math.h>
void main( void ){
float ang;
int i;
for( i = 0; i< 1000000; i++){
ang = M_PI_2 * i/2000000;
/*__asm__ ( "fld %0;"
"fptan;"
"fxch;"
"fstp %0;" : "=m" (ang) : "m" (ang)
) ;*/
ang = tanf(ang);
}
printf("Tan(ang): %f\n", ang);
}
这段代码以两种不同的方式计算角度的正切值,一种是调用动态链接库libm.a中的tanf函数,另一种是使用内联汇编代码。请注意,我会交替注释代码的部分。
该代码多次执行该操作,以在Linux终端中使用time命令获得有意义的结果。
使用math库的版本大约需要0.040秒。
使用汇编代码的版本需要大约0.440秒,是前者的十倍。
以下是反汇编的结果。两者均已使用-O3选项进行编译。
LIBM
4005ad: b8 db 0f c9 3f mov $0x3fc90fdb,%eax
4005b2: 89 45 f8 mov %eax,-0x8(%rbp)
4005b5: f3 0f 10 45 f8 movss -0x8(%rbp),%xmm0
4005ba: e8 e1 fe ff ff callq 4004a0 <tanf@plt>
4005bf: f3 0f 11 45 f8 movss %xmm0,-0x8(%rbp)
4005c4: 83 45 fc 01 addl $0x1,-0x4(%rbp)
4005c8: 83 7d fc 00 cmpl $0x0,-0x4(%rbp)
4005cc: 7e df jle 4005ad <main+0x19>
ASM
40050d: b8 db 0f c9 3f mov $0x3fc90fdb,%eax
400512: 89 45 f8 mov %eax,-0x8(%rbp)
400515: d9 45 f8 flds -0x8(%rbp)
400518: d9 f2 fptan
40051a: d9 c9 fxch %st(1)
40051c: d9 5d f8 fstps -0x8(%rbp)
40051f: 83 45 fc 01 addl $0x1,-0x4(%rbp)
400523: 83 7d fc 00 cmpl $0x0,-0x4(%rbp)
400527: 7e e4 jle 40050d <main+0x19>
有什么想法吗?谢谢。
我想我有一个想法。浏览glibc代码,我发现tanf函数是通过多项式逼近和使用sse扩展来实现的。我猜这比fptan指令的微码更快。