我测试下吧 测试环境:
CPU:
Intel Pentium4 2.6G
L1 data 8KB, L1 trace 12KB
L2 cache 512KB
RAM:
DDR 768MB
OS: windows XP
compiler: VC++6.0 release
Test case1: n=0 to 65535
iSqt_c1_lbc#: 0.00082 s
iSqt_FPU1_lbc#: 0.00095 s
iSqt_FPU3_lbc#: 0.00127 s
iSqt_FPU2_lbc#: 0.00146 s
iSqt_c2_lbc#: 0.00151 s
iSqt_gxq_c#: 0.00173 s
iSqt_FPU1_yaos#: 0.00220 s
iSqt_FPU_yaos#: 0.00235 s
iSqt_FPU2_yaos#: 0.00246 s
iSqt_ref#: 0.00306 s
iSqt_16#: 0.00398 s
iSqt_gxq_90#: 0.00434 s(新增,90楼那个版本)
iSqt_GxQ_asm#: 0.00449 s
Test case2: n=0- 2^28-1
iSqt_FPU1_lbc#: 3.97569 s
iSqt_FPU3_lbc#: 5.32763 s
iSqt_FPU2_lbc#: 7.59953 s
iSqt_gxq_c#: 7.64778 s
iSqt_c1_lbc#: 8.14219 s
iSqt_FPU1_yaos#: 9.24091 s
iSqt_FPU_yaos#: 9.51267 s
iSqt_c2_lbc#: 10.19276 s
iSqt_FPU2_yaos#: 10.54652 s
iSqt_ref#: 12.78721 s
iSqt_16#: 14.57529 s
iSqt_gxq_90#: 18.04432 s (新增,90楼那个版本)
iSqt_GxQ_asm#: 18.64220 s 宝宝:
今天看你42# FPU3代码除了你么处理esp外, 你也么恢复ecx啊
另外,似乎是连续的两个fntstcw, fldcw造成的你的代码速度比俺的快
依据的什么原理??
回复 93# 无心人 的帖子
为什么我的版本比你的快,我没有仔细分析过,连续使用两个fntstcw没有什么特别的道理,我的原则是指令数尽可能少,另外要做到浮点寄存器栈的平衡。我确实没有回回复ecx寄存器,我记得按照函数调用规则,如果你在子程序中修改了esi,edi,ebx,esp,ebp 等寄存器,你必须恢复它,但是你可以在子程序中仍以修改eax,edx,ecx 的值,调用者不能假定这些寄存器没有变化。
但是如果指定了__fastcall关键字,是否必须保证调用子程序后不修改ecx的值,我刚刚查阅了一些资料,但依然没有找到确切的答案。我是假定在__fastcall子程序中可以修改ecx 的值的。 :)
几乎同样的功能
几乎同样的指令
一个9.24
一个5.32
到底差距在哪里啊?
我写的三个ALU汇编版本
__declspec(naked)UINT32 __fastcall iSqrt_ALU( UINT32 n )
{
__asm push esi;
__asm push edi;
__asm xor eax, eax;
#if 1 /* Ver1: 指令数最少,但含跳转 */
#define SQRT_CORE_ASM(x) \
__asm lea edx, \
__asm shr eax, 1 \
__asm cmp ecx, edx \
__asm jb L_##x \
__asm sub ecx, edx \
__asm add eax, (1UL<<(x)) \
__asm L_##x:
#elif 0 /* Ver2: 常规指令,无跳转 */
#define SQRT_CORE_ASM(x) \
__asm mov edi, 1UL<<(x) \
__asm lea edx, \
__asm shr eax, 1 \
__asm cmp ecx, edx \
__asm sbb esi, esi \
__asm not esi \
__asm and edx, esi \
__asm and edi, esi \
__asm sub ecx, edx \
__asm add eax, edi
#else /* Ver3: 含CMOVcc指令,无跳转 */
#define SQRT_CORE_ASM(x) \
__asm lea edx, \
__asm shr eax, 1 \
__asm mov esi, ecx \
__asm sub ecx, edx \
__asm lea edi, \
__asm cmovb ecx, esi \
__asm cmovaeeax, edi
#endif
SQRT_CORE_ASM(30);
SQRT_CORE_ASM(28);
SQRT_CORE_ASM(26);
SQRT_CORE_ASM(24);
SQRT_CORE_ASM(22);
SQRT_CORE_ASM(20);
SQRT_CORE_ASM(18);
SQRT_CORE_ASM(16);
SQRT_CORE_ASM(14);
SQRT_CORE_ASM(12);
SQRT_CORE_ASM(10);
SQRT_CORE_ASM(8);
SQRT_CORE_ASM(6);
SQRT_CORE_ASM(4);
SQRT_CORE_ASM(2);
SQRT_CORE_ASM(0);
#undef SQRT_CORE_ASM
__asm pop edi;
__asm pop esi;
__asm ret;
}其对应的C代码是一样的,只是采用了不同的汇编手法。
测试结果如下:
n: 0-0x10000
iSqt_ref#: 0.00098 s
iSqt_c1_lbc#: 0.00071 s
iSqt_c2_lbc#: 0.00133 s
iSqt_FPU1_lbc#: 0.00092 s
iSqt_FPU2_lbc#: 0.00134 s
iSqt_FPU3_lbc#: 0.00118 s
iSqt_FPU_yaos#: 0.00217 s
iSqt_FPU1_yaos#: 0.00217 s
iSqt_FPU2_yaos#: 0.00208 s
iSqt_gxq_c#: 0.00140 s
iSqt_GxQ_asm#: 0.00471 s
iSqt_ALU_v1#: 0.00115 s
iSqt_ALU_v2#: 0.00580 s
iSqt_ALU_v3#: 0.00426 s
iSqt_16#: 0.00298 s
n: 0-0x4000000
iSqt_ref#: 1.03851 s
iSqt_c1_lbc#: 2.05060 s
iSqt_c2_lbc#: 1.94235 s
iSqt_FPU1_lbc#: 0.99109 s
iSqt_FPU2_lbc#: 1.41954 s
iSqt_FPU3_lbc#: 1.24257 s
iSqt_FPU_yaos#: 2.31683 s
iSqt_FPU1_yaos#: 2.38967 s
iSqt_FPU2_yaos#: 2.22774 s
iSqt_gxq_c#: 1.11229 s
iSqt_GxQ_asm#: 5.01363 s
iSqt_ALU_v1#: 1.17843 s
iSqt_ALU_v2#: 6.18305 s
iSqt_ALU_v3#: 4.54953 s
iSqt_16#: 2.95849 s
测试平台为:Windows XP SP3, P4 2.93GHz 46#代码存在冗余
需要修改 如果我的Core2Xeon测试
应该是你的V3版本最好了
__declspec(naked)
DWORD __fastcall iSqrt_FPU1_yaos(DWORD n)
{
__asm
{
sub esp, 8
mov , ecx
fnstcw word ptr
fnstcw word ptr
or word ptr , 0x0E60
mov eax, ecx
shr eax, 31
fld qword ptr
fild dword ptr
faddp st(1), st
fsqrt
fldcw word ptr
fistp dword ptr
fldcw word ptr
mov eax,
add esp, 8
ret
}
}
宝宝的代码里我的函数FPU1应该是这样的
稍微优化了点
执行时间减少了至少40%
我明天去学校看我机器里的代码
可能存在版本差异 今天早上
翻MMX的书
看到说,内存的内部和全部
即128位内部的64位,64位内部的32位等等。。。
如果同时发生写和读
将发生阻塞
可能是我程序代码速度慢的原因