| 
注册时间2007-12-28最后登录1970-1-1威望 星金币 枚贡献 分经验 点鲜花 朵魅力 点上传 次下载 次积分12787在线时间 小时 
 | 
 
 发表于 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
 }
}
 | 
 |