无心人 发表于 2008-4-16 17:10:58



知道了

liangbch 发表于 2008-5-4 15:40:57

增加了2个版本,先给出在PIV 2.6上的测试结果

说明:
   binAdd_base30_ALU_4way_unroll2 为 binAdd_base30_ALU_4way_unroll的改进版,指令数更少,速度更快些。
   binAdd_base30_ALU_8way_unroll2 为 binAdd_base30_ALU_8way_unroll的改进版,指令数更少,速度更快些,但基本与binAdd_base30_ALU_4way_unroll2 持平。




Test function: binAdd_ALU(..) 100000 times...
Elapsed time: 1904.675 ms

Test function: binAdd_GMP_ALU_8way_unroll(..) 100000 times...
Elapsed time: 1357.660 ms

Test function: binAdd_Yaos_MMX_4way_unroll(..) 100000 times...
Elapsed time: 772.390 ms

Test function: binAdd_base30_ALU(..) 100000 times...
Elapsed time: 1203.820 ms

Test function: binAdd_base30_ALU_4way_unroll(..) 100000 times...
Elapsed time: 1225.580 ms

Test function: binAdd_base30_ALU_4way_unroll2(..) 100000 times...
Elapsed time: 1190.035 ms

Test function: binAdd_base30_ALU_8way_unroll(..) 100000 times...
Elapsed time: 1213.810 ms

Test function: binAdd_base30_ALU_8way_unroll2(..) 100000 times...
Elapsed time: 1189.320 ms

Test function: binAdd_Base30_MMX_4way_unroll(..) 100000 times...
Elapsed time: 903.745 ms

再给出测试代码:
//基为2^30的版本另一个版本,采用4路循环展开_declspec(naked)
DWORD binAdd_base30_ALU_4way_unroll2(DWORD *dst,
const DWORD *src1,
const DWORD *src2,
int   size)
{
#undefBASE30_MASK
#define BASE30_MASK 0x3fffffff
_asm
{
push edi
push esi
push ebx
subesp,4

mov ebx,
mov esi,
mov edi,
mov edx,

lea eax,
mov ,eax

xor ecx,ecx //clear carry
and edx,3
jza10

loop00:
add ecx,
add ecx,
mov ecx,eax
and eax,BASE30_MASK
shr ecx,30
mov ,eax
lea esi,
lea edi,
lea ebx,
dec edx
jnz loop00
a10:
jmp cmp00

ALIGN 8
loop01:
add ecx,
add ecx,
mov eax, ecx
and eax,BASE30_MASK
shr ecx,30
mov ,eax

add ecx,
add ecx,
mov edx, ecx
and edx,BASE30_MASK
shr ecx,30
mov ,edx


add ecx,
add ecx,
mov eax, ecx
and eax,BASE30_MASK
shr ecx,30
mov ,eax


add ecx,
add ecx,
mov edx, ecx
and edx,BASE30_MASK
shr ecx,30
mov ,edx


lea esi,
lea edi,
lea ebx,
cmp00:
cmp esi,
jb loop01

thisExit:
add esp,4

pop ebx
pop esi
pop edi
mov eax,0
adc eax,0
ret
}
} //基为2^30的版本另一个版本,指令数更少,采用8路循环展开_declspec(naked)
DWORD binAdd_base30_ALU_8way_unroll2(DWORD *dst,
const DWORD *src1,
const DWORD *src2,
int   size)
{
#undefBASE30_MASK
#define BASE30_MASK 0x3fffffff
_asm
{
push edi
push esi
push ebx
subesp,4

mov ebx,
mov esi,
mov edi,
mov edx,

lea eax,
mov ,eax

xor ecx,ecx
and edx,7
jza10

loop00:
add ecx,
add ecx,
mov eax,ecx
and eax,BASE30_MASK
shr ecx,30
mov ,eax
lea esi,
lea edi,
lea ebx,
dec edx
jnz loop00
a10:
jmp cmp00

ALIGN 8
loop01:
add ecx,
add ecx,
mov eax,ecx
and eax,BASE30_MASK
shr ecx,30
mov ,eax


add ecx,
add ecx,
mov edx,ecx
and edx,BASE30_MASK
shr ecx,30
mov ,edx


add ecx,
add ecx,
mov eax,ecx
and eax,BASE30_MASK
shr ecx,30
mov ,eax


add ecx,
add ecx,
mov edx,ecx
and edx,BASE30_MASK
shr ecx,30
mov ,edx


add ecx,
add ecx,
mov eax,ecx
and eax,BASE30_MASK
shr ecx,30
mov ,eax


add ecx,
add ecx,
mov edx,ecx
and edx,BASE30_MASK
shr ecx,30
mov ,edx


add ecx,
add ecx,
mov eax,ecx
and eax,BASE30_MASK
shr ecx,30
mov ,eax


add ecx,
add ecx,
mov edx,ecx
and edx,BASE30_MASK
shr ecx,30
mov ,edx


lea esi,
lea edi,
lea ebx,
cmp00:
cmp esi,
jb loop01

thisExit:
add esp,4
pop ebx
pop esi
pop edi
mov eax,0
adc eax,0
ret
}
}

无心人 发表于 2008-5-8 16:56:16

:)

刚把加法的SSE2加4路展开给通用化了
并顺便实现了8路展开

1024双字加,重复100万次
4路SSE2加: 2547.029
8路SSE2加: 2456.956

8路的仅提高3.5%时间
所以4路的为最佳形式了

附四路八路通用加法代码

DWORD longAdd4p(DWORD result[], DWORD left[], DWORD right[], DWORD len)
{
    __asm
{
mov esi,
mov edi,
mov ebx,
mov ecx,
mov edx, ecx
pxor mm0, mm0
shr ecx, 2
jeloop20
loop1:
movd mm1,
movd mm2,
paddq mm1,mm2
movd mm3,
movd mm4,
paddq mm3, mm4
movd mm5,
movd mm6,
paddq mm5, mm6
movd mm7,
movd mm3,
paddq mm7, mm3
paddq mm0, mm1
movd , mm0
psrlq mm0, 32
paddq mm0, mm3
movd , mm0
psrlq mm0, 32
paddq mm0, mm5
movd , mm0
psrlq mm0, 32
paddq mm0, mm7
movd , mm0
psrlq mm0, 32
add esi, 16
add edi, 16
add ebx, 16
sub ecx, 1
jne loop1
loop20:
mov ecx, edx
and ecx, 3
jz exit1
loop2:
movd mm1,
movd mm2,
paddq mm0, mm1
paddq mm0, mm2
movd , mm0
psrlq mm0, 32
add esi, 4
add edi, 4
add ebx, 4
sub ecx, 1
jne loop2
exit1:
movd eax, mm0
emms
}
}

DWORD longAdd8p(DWORD result[], DWORD left[], DWORD right[], DWORD len)
{
    __asm
{
mov esi,
mov edi,
mov ebx,
mov ecx,
mov edx, ecx
pxor mm0, mm0
shr ecx, 3
jeloop20
loop1:
movd mm1,
movd mm2,
paddq mm1,mm2
movd mm3,
movd mm4,
paddq mm3, mm4
movd mm5,
movd mm6,
paddq mm5, mm6
movd mm7,
movd mm3,
paddq mm7, mm3
movd mm2,
movd mm4,
paddq mm2, mm4
paddq mm0, mm1
movd , mm0
psrlq mm0, 32
movd mm6,
movd mm1,
paddq mm6, mm1
paddq mm0, mm3
movd , mm0
psrlq mm0, 32
paddq mm0, mm5
movd , mm0
psrlq mm0, 32
movd mm4,
movd mm5,
paddq mm4, mm5
paddq mm0, mm7
movd , mm0
psrlq mm0, 32
movd mm1,
movd mm3,
paddq mm1, mm3
paddq mm0, mm2
movd , mm0
psrlq mm0, 32
paddq mm0, mm6
movd , mm0
psrlq mm0, 32
paddq mm0, mm4
movd , mm0
psrlq mm0, 32
paddq mm0, mm1
movd , mm0
psrlq mm0, 32
add esi, 32
add edi, 32
add ebx, 32
sub ecx, 1
jne loop1
loop20:
mov ecx, edx
and ecx, 7
jz exit1
loop2:
movd mm1,
movd mm2,
paddq mm0, mm1
paddq mm0, mm2
movd , mm0
psrlq mm0, 32
add esi, 4
add edi, 4
add ebx, 4
sub ecx, 1
jne loop2
exit1:
movd eax, mm0
emms
}
}

liangbch 发表于 2008-5-8 17:08:55

原帖由 liangbch 于 2008-4-8 18:05 发表 http://images.5d6d.net/dz60/common/back.gif
对于编写高性能的程序,常常需要权衡程序效率和复杂度之间的平衡。1路->4路,性能提高明显, 4路 -〉8路 则性能提高的就很有限了。从GMP的源代码可以看出,他使用的循环展开一般为4-6路。个人觉得4路循环展开应该是一 ...

看来我在16#的断言没有错。

无心人 发表于 2008-5-8 17:30:44

如果实现求圆周率程序
8路展开也许还有用处的

liangbch 发表于 2008-5-9 10:45:16

8路循环展开也不是没有用武之地,对于循环体内代码很少的情况下,8路循环展开还是有优势的,如内存清0,内存复制。memcpy 源代码就使用了8路循环展开。

无心人 发表于 2008-5-9 10:55:52

:)

那可以考虑和16路展开比较

liangbch 发表于 2008-5-9 11:50:49

可以预计16路循环展开对性能的提升极为有限。

哈哈,我还是想说一句,我的原则是有所为,有所不为,为了1%的性能提高,而花费%20的时间和精力,我一般不会去做。

无心人 发表于 2008-5-9 14:36:58

我做4路加法消耗20-30分钟
4路改8路仅修改了10分钟

所以如果你改16路不划算
证明你代码存在难修改的问题
结构化不好

:lol

liangbch 发表于 2008-5-9 15:48:20

哈哈,上面只是一个比方,我也不知道改一个函数需要耗费多少成本。
不过8路改16路应该很简单,逻辑上应该没有多大变化,但相应的也需要写一堆测试代码。
8路改为16路,提速效果应该不大,我不想尝试了。我下一步想要做的是,实现2^30的basecase乘法。
页: 1 2 3 4 [5] 6
查看完整版本: B计划之长加法最佳算法讨论