- 注册时间
- 2007-12-28
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 12785
- 在线时间
- 小时
|
发表于 2008-4-11 10:41:45
|
显示全部楼层
理论上,CPU存在多个执行单元,调整指令顺序,减少指令依赖可以提升速度。然而我之前的种种实验表明,这种调整指令顺序,提高并行度的做法并无多大效果,不知何故。
另一种行之有效的优化循环的办法是减少控制指令,这种做法在某些CPU效果相当明显,我们以本贴子中出现过的程序为例给予说明。
UInt480x480_yaos,UInt480x480_MMX2,UInt480x480_MMX3 这三个函数均为以普通方式计算大数乘法的函数,
程序的逻辑也相同,不过 UInt480x480_yaos多做了一些额外的工作,即需要先将目标buffer清零。
先看看他们在2种CPU的速度表现,计算2个长为15个DWORD的乘积,运行100万次
PIV 2.6 PM1.7
UInt480x480_yaos 698.655 ms 1053.610 ms
UInt480x480_MMX2 671.515 ms 863.055 ms
UInt480x480_MMX3 585.015 ms 798.775 ms
再分析一下这几个程序的差异,这几个程序均为2重循环,在循环体中,包括真正干活的指令和循环控制的指令,循环控制的指令又分调整数组指针或计数器的指令 和 比较/跳转指令.这3个程序中内循环指令条数分别为11,10,9,其中循环控制指令分别为4,3,2条。
第一个程序,循环控制指令是 “lea edi, [edi+4]”,“lea ebx, [ebx+4]”,“sub ecx, 1”,“jnz mbinmul3”,共4条。第一个程序,循环控制指令是“inc eax”,“cmp eax,dword ptr [esp + 16+STACK_BASE]”,“jb innerLoop”。第三个程序循环控制指令是“inc eax”,“jnz innerLoop”。
第三个程序的速度已经非常逼近完全循环展开的版本,尤其是在PM CPU。在PIV/PM,速度分别达到完全循环展开程序的82%/%95.
下面给出这三个程序调用到的子程序的完整的代码。- 程序UInt480x480_yaos 调用到的子程序的代码
- void lMul_yaos(uint32 *result,
- const uint32 *left,
- const uint32 *right,
- uint32 sLeft,
- uint32 sRight)
- {
- __asm {
- mov edx, sLeft
- mov esi, dword ptr [left]
- mov edi, dword ptr [right]
- mov ebx, dword ptr [result]
- mbinmul2:
- mov eax, ebx
- pxor mm0, mm0
- mov ecx, sRight
- movd mm1, dword ptr [esi]
- movd mm4, edi
- mbinmul3:
- movd mm2, dword ptr [edi]
- lea edi, [edi+4]
- movd mm3, dword ptr [ebx]
- pmuludq mm2, mm1
- paddq mm0, mm3
- paddq mm0, mm2
- movd dword ptr [ebx], mm0
- psrlq mm0, 32
- lea ebx, [ebx+4]
- sub ecx, 1
- jnz mbinmul3
-
- movd edi, mm4
- movd dword ptr [ebx], mm0
- mov ebx, eax
- lea esi, [esi+4]
- lea ebx, [ebx+4]
- sub edx, 1
- jnz mbinmul2
- emms
- }
- }
复制代码- 程序UInt480x480_MMX2 调用到的子程序的代码
-
- _declspec(naked)
- void UIntMul_basecase_MMX2( unsigned long * result,
- const unsigned long * left,
- const unsigned long * right,
- unsigned long leftLen,
- unsigned long rightLen )
- {
- #define STACK_BASE 12
- __asm
- {
- push esi
- push edi
- push ebp
-
- mov ebp, dword ptr [esp + 4+STACK_BASE] ; result
- mov esi, dword ptr [esp + 8+STACK_BASE] ; left
- mov edi, dword ptr [esp + 12+STACK_BASE] ; right
- mov ecx, dword ptr [esp + 20+STACK_BASE] ; rightLen
-
- //next10:
- cmp ecx,0
- jz thisExit
-
- //loop1_Init:
- xor eax,eax // j=0;i<leftLen
- pxor mm0,mm0
- movd mm2,[edi]
- jmp loop1_Cmp
-
- loop1:
- movd mm1,[esi+eax*4]
- pmuludq mm1,mm2
- paddq mm0, mm1
- movd [ebp+eax*4],mm0
- inc eax
- psrlq mm0, 32 //carry
-
- loop1_Cmp:
- cmp eax,dword ptr [esp + 16+STACK_BASE] //leftLen
- jb loop1
- movd [ebp+eax*4],mm0
-
- //outLoopInit:
- mov ecx,1 // i=1;i<rightLen
- jmp outLoopCmp
-
- outLoop:
- add ebp,4
- pxor mm0,mm0
- movd mm2,[edi+ecx*4]
- xor eax,eax
- jmp innerLoopCmp
-
- innerLoop:
- movd mm1,[esi+eax*4]
- movd mm3,[ebp+eax*4]
- pmuludq mm1,mm2
- paddq mm0, mm1
- paddq mm0, mm3
- movd [ebp+eax*4],mm0
- inc eax
- psrlq mm0, 32 //carry
-
- innerLoopCmp:
- cmp eax,dword ptr [esp + 16+STACK_BASE] //leftLen
- jb innerLoop
- movd [ebp+eax*4],mm0
- inc ecx
- outLoopCmp:
- cmp ecx,dword ptr [esp + 20+STACK_BASE] //rightLen
- jb outLoop
-
- thisExit:
-
- pop ebp
- pop edi
- pop esi
-
- emms
- ret
- }
- }
复制代码- 程序UInt480x480_MMX3 调用到的子程序的代码:
-
- _declspec(naked)
- void UIntMul_basecase_MMX3( unsigned long * result,
- const unsigned long * left,
- const unsigned long * right,
- unsigned long leftLen,
- unsigned long rightLen )
- {
- #define STACK_BASE 12
- __asm
- {
- push esi
- push edi
- push ebp
-
- mov ebp, dword ptr [esp + 4+STACK_BASE] ; result
- mov esi, dword ptr [esp + 8+STACK_BASE] ; left
- mov edi, dword ptr [esp + 12+STACK_BASE] ; right
- mov ecx, dword ptr [esp + 20+STACK_BASE] ; rightLen
-
- //next10:
- cmp ecx,0
- jz thisExit
-
- //loop1_Init:
- xor eax,eax // j=0;i<leftLen
- pxor mm0,mm0
- movd mm2,[edi]
- jmp loop1_Cmp
-
- loop1:
- movd mm1,[esi+eax*4]
- pmuludq mm1,mm2
- paddq mm0, mm1
- movd [ebp+eax*4],mm0
- inc eax
- psrlq mm0, 32 //carry
-
- loop1_Cmp:
- cmp eax,dword ptr [esp + 16+STACK_BASE] //leftLen
- jb loop1
- movd [ebp+eax*4],mm0
-
- //outLoopInit:
- mov ecx,1 // i=1;i<rightLen
- mov eax,dword ptr [esp + 16+STACK_BASE] //leftLen
- lea esi,[esi+eax*4]
- lea ebp,[ebp+eax*4]
- jmp outLoopCmp
-
- outLoop:
- add ebp,4
- pxor mm0,mm0
- movd mm2,[edi+ecx*4]
- mov eax,dword ptr [esp + 16+STACK_BASE] //leftLen
- neg eax
- jmp innerLoopCmp
-
- innerLoop:
- movd mm1,[esi+eax*4]
- movd mm3,[ebp+eax*4]
- pmuludq mm1,mm2
- paddq mm0, mm1
- paddq mm0, mm3
- movd [ebp+eax*4],mm0
- psrlq mm0, 32 //carry
- inc eax
- innerLoopCmp:
- jnz innerLoop
- movd [ebp+eax*4],mm0
- inc ecx
- outLoopCmp:
- cmp ecx,dword ptr [esp + 20+STACK_BASE] //rightLen
- jb outLoop
-
- thisExit:
-
- pop ebp
- pop edi
- pop esi
-
- emms
- ret
- }
- }
复制代码 |
|