无心人 发表于 2008-4-9 17:30:24

25结论似乎是错误的
抱歉!

无心人 发表于 2008-4-9 20:04:03

指出你的一个错误吧

你似乎480bit乘都是循环展开的
但我们需要的是可以处理任何输入的通用函数

不要说循环展开等于通用的比较结果
考虑展开情况下你可以充分的隔离依赖指令
使指令延迟的副作用最小
而且还能动用最大化的mm寄存器
所以很多优化在循环情况下是不能使用的
所以必须使用循环版本

最简单的,乘法延迟>=6,要在6个时钟后才能用
所以循环情况下,最小的每双字的消耗就是6
而展开情况下,可充分利用每时钟能发送一条乘法的优势
使乘法延迟的损耗最小化
循环时的时间你算过么? 我想你的P4 2.6应该在590ms左右

liangbch 发表于 2008-4-9 20:35:30

遇到麻烦了!!!
将yaos写的代码添加到测试环境,这样一来,总共被测函数达到7个,奇怪的是,但打开这些函数的其中几个,会对基为 2^30 SSE2版本的性能造成影响。
比如 UInt480x480_MMX 和 UInt480x480_yaos(yaos写的代码,稍加封装)测试其中的一个或者几个,竟然对 UInt480x480_base30_MMX 性能造成明些的影响。

UInt480x480_MMX        UInt480x480_yaos        UInt480x480_base30_MMX 用时间
关闭(不测试)        关闭(不测试)        394ms
关闭(不测试)        打开(测试)        394ms       
打开(测试)        关闭(不测试)        396ms
打开(测试)        打开(测试)        575ms

   另外,打开或者 UInt480x480_ALU2 或 UInt480x480_ALU 也会对最后2个基为2^30 SSE2版本造成影响。测试发现,关闭UInt480x480_ALU2 会造成 基为 2^30 SSE2版本变慢。

还有一点,我的完全 使用循环展开 的版本(基同为为2^32) 竟比 yaos的慢,我也不能给出合理的解释。

下面为在PIV2.6G下的测试结果.
关闭最后3个基为 2^30 的函数后的测试结果。

Test function: UInt480x480_ALU(..) 1000000 times...
Elapsed time: 1287.924 ms

Test function: UInt480x480_ALU2(..) 1000000 times...
Elapsed time: 1244.897 ms

Test function: UInt480x480_MMX(..) 1000000 times...
Elapsed time: 996.383 ms

Test function: UInt480x480_yaos(..) 1000000 times...
Elapsed time: 752.210 ms


关闭最后UInt480x480_MMX和 UInt480x480_yaos 后的测试结果。
Test function: UInt480x480_ALU(..) 1000000 times...
Elapsed time: 1282.592 ms

Test function: UInt480x480_ALU2(..) 1000000 times...
Elapsed time: 1243.553 ms

Test function: UInt480x480_base30_ALU(..) 1000000 times...
Elapsed time: 1252.155 ms

Test function: UInt480x480_base30_MMX(..) 1000000 times...
Elapsed time: 397.942 ms

Test function: UInt480x480_base30_SSE2(..) 1000000 times...
Elapsed time: 533.329 ms

   代码暂缓公布,回去写几个通用版本,可以在参数中指定被乘数和乘数的长度。将使用部分循环展开技术。接口类似为:
voidMul_func(DWORD*result,const DWORD*left, const DWORD*right, DWORD sLeft,DWORD sRight);

无心人 发表于 2008-4-9 20:46:00

呵呵
我说快也快不了多少么
循环版是一个乘两个加
极端有规律的

你线程最大化优先级了么?
======================
部分循环展开
就是一次乘4个吧
要处理非4倍数的部分

liangbch 发表于 2008-4-9 20:51:00

原帖由 无心人 于 2008-4-9 20:46 发表 http://images.5d6d.net/dz60/common/back.gif
部分循环展开
就是一次乘4个吧
要处理非4倍数的部分
回楼上,不是的,因为我使用的循环结构和你的不同,所以不能使用 4路循环展开。

无心人 发表于 2008-4-9 20:56:56

那我想做4路展开
如果你的代码时间不能达到我时间的80%以内
你的代码是很没效率的, 因为加法是肯定慢的
加法不可能快于2^32的基

liangbch 发表于 2008-4-10 13:08:52

33# 楼提到,“还有一点,我的完全 使用循环展开 的版本(基同为为232) 竟比 yaos的慢,我也不能给出合理的解释。”
   现在终于找到原因了,我写的那个UInt480x480_MMX有冗余指令,稍作优化后,速度迅速提升,从之前的989.54ms提升到
481.540 ms,竟快了1倍多,提速太多了。我无法给出合理的解释。

将现在的基为2^32的函数 Int480x480_MMX 和 基为2^30的函数UInt480x480_base30_MMX做一个对比,则后者比前者快了25%。

   我也写了一个可类似yaos的非循环展开的版本,速度比yaos的那个版本快了8%左右。可参考楼下给出的源代码。

这个数据(提速到125%)可比以前的250%更合理一点,但单从指令条数分析,速度应该提升到200%以上才对。但MMX指令的版本怪就怪在 速度的变化无法琢磨,无法用理论的方法给出合理的解释。无论如何,让我们见识了一个可以大幅提高大数乘法运行速度的新途径,提高的幅度太大了,太出人所料了。

6个版本的速度对比。
Test function: UInt480x480_ALU(..) 1000000 times...
Elapsed time: 1244.770 ms

Test function: UInt480x480_ALU2(..) 1000000 times...
Elapsed time: 1216.745 ms

Test function: UInt480x480_MMX(..) 1000000 times...
Elapsed time: 481.540 ms

Test function: UInt480x480_base30_ALU(..) 1000000 times...
Elapsed time: 1222.405 ms

Test function: UInt480x480_base30_MMX(..) 1000000 times...
Elapsed time: 385.115 ms

Test function: UInt480x480_base30_SSE2(..) 1000000 times...
Elapsed time: 527.090 ms


5个基同为2^32的版本的速度对比:
Test function: UInt480x480_ALU(..) 1000000 times...
Elapsed time: 1248.710 ms

Test function: UInt480x480_ALU2(..) 1000000 times...
Elapsed time: 1219.125 ms

Test function: UInt480x480_MMX(..) 1000000 times...
Elapsed time: 482.380 ms

Test function: UInt480x480_MMX2(..) 1000000 times...
Elapsed time: 693.360 ms

Test function: UInt480x480_yaos(..) 1000000 times...
Elapsed time: 725.490 ms

liangbch 发表于 2008-4-10 13:11:17

本压缩包包含2个工程文件,geneCodes.dsp 和binMulTest.dsp。前者用来生成后者的部分原代码。
运行geneCodes.exe,将生成3个.c文件(本来可生成6个文件的,在上载该压缩包前作了处理,屏蔽了3个基为2^323个函数的输出)

使用后者之前,先运行geneCodes.exe,生成后者所需的3个文件.然后可打开binMulTest.dsp 并编译即可生成用来一个名为
binMulTest.exe,该程序可计算2个480bit的乘积,使用了几种不同的算法,给给出他们的速度.需要注意的是,binMulTest的源代码中并没有包含基为2^30的几个函数,而事先编译好的binMulTest.exe 则包含了所有6个函数的速度测试。

无心人 发表于 2008-4-10 15:56:07

我这里差别也是不大
ALU 1696
ALU2 1668
MMX 646
30_MMX 549
30_SSE2 777

无心人 发表于 2008-4-10 20:15:26

写了一个四路并行乘法
有时间调试下看效果如何?
   mov esi,
   mov edi,
   mov ebx,
   mov ecx,
   mov edx,
   cmp ecx, edx
   jbenoExchange
   xchg esi,
   xchg edi,
   xchg ecx,
   xchg edx,
noExchange:
   test ecx, -1
   je exit1//长度0
   test edx, -1
   je exit1//长度0
   mov ecx, 0
   pxor mm0, mm0
   movd mm7,
   add esi, 4
   mov eax, edx
   shr edx, 2
   je firstLoop2 //不足4个
firstLoop1:
   movd mm1,
   pmuludq mm1, mm7
   movd mm2,
   pmuludq mm2, mm7
   movd mm3,
   pmuludq mm3, mm7
   movd mm4,
   pmuludq mm4, mm7
   add edi, 16
   paddq mm0, mm1
   movd , mm0
   psrlq mm0, 32
   paddq mm0, mm2
   movd , mm0
   psrlq mm0, 32
   paddq mm0, mm3
   movd , mm0
   psrlq mm0, 32
   paddq mm0, mm4
   movd , mm0
   psrlq mm0, 32
   add ebx, 16
   sub edx, 1
   jne firstLoop1
firstLoop2:
   mov edx, eax
   and edx, 3
   je exitFirstLoop
firstLoop3:
   movd mm1,
   pmuludq mm1, mm7
   add edi, 4
   paddq mm0, mm1
   movd , mm0
   psrlq mm0, 32
   add ebx, 4
   sub edx, 1
   jne firstLoop3
exitFirstLoop:
   movd , mm0
   add ecx, 1
   cmp ecx,
   jae exit1 //左操作数就一个双字
   add esi, 4
outLoop1:
   movd mm7,
   mov ebx,
   lea ebx,
   mov edi,
   mov edx,
   pxor mm0, mm0
   mov eax, edx
   shr edx, 2
   je innerLoop2
innerLoop1:
   movd mm1,
   pmuludq mm1, mm7
   movd mm5,
   movd mm2,
   pmuludq mm2, mm7
   movd mm6,
   movd mm3,
   pmuludq mm3, mm7
   movd mm4,
   pmuludq mm4, mm7
   add edi, 16
   paddq mm0, mm1
   paddq mm0, mm5
   movd , mm0
   movd mm5,
   psrlq mm0, 32
   paddq mm0, mm2
   paddq mm0, mm6
   movd , mm0
   movd mm6,
   psrlq mm0, 32
   paddq mm0, mm3
   paddq mm0, mm5
   movd , mm0
   psrlq mm0, 32
   paddq mm0, mm4
   paddq mm0, mm6
   movd , mm0
   psrlq mm0, 32
   add ebx, 16
   sub edx, 1
   jne innertLoop1
innerLoop2:
   mov edx, eax
   and edx, 3
   je outLoop2
innerLoop3:
   movd mm1,
   pmuludq mm1, mm7
   movd mm5,
   add edi, 4
   paddq mm0, mm1
   paddq mm0, mm5
   movd , mm0
   psrlq mm0, 32
   add ebx, 4
   sub edx, 1
   jne firstLoop2
outLoop2:
   movd , mm0
   add ecx, 1
   cmp ecx,
   jb outLoop1
exit1:
页: 1 2 3 [4] 5 6 7
查看完整版本: 大数运算基选择测试