我正在研究非常长的整数(大约 100,000 个十进制数字)的乘法运算。作为我图书馆的一部分,我要添加两个长数字。
分析表明,我的代码在 add() 和 sub() 例程中运行的时间高达 25%,因此它们尽可能快很重要。但我还没有看到很大的潜力。也许你可以给我一些帮助、建议、见解或想法。我会测试它们并回复你。
到目前为止,我的 add 例程做了一些设置,然后使用了 8 次展开循环:
mov rax, QWORD PTR [rdx+r11*8-64]
mov r10, QWORD PTR [r8+r11*8-64]
adc rax, r10
mov QWORD PTR [rcx+r11*8-64], rax
接下来还有 7 个具有不同偏移量的块,然后循环。
我之前尝试从内存中加载值,但这没有帮助。我想这是因为良好的预取。我使用 Intel i7-3770 Ivy Bridge 4 核 CPU。但我想编写适用于任何现代 CPU 的代码。
编辑:我做了一些计时:它在大约 2.25 个周期/字中增加了 1k 个字。如果我移除 ADC,那么只剩下 MOV,它仍然需要大约 1.95 个周期/字。所以主要的瓶颈似乎是内存访问。一个库的memcpy()
工作周期约为 0.65 个周期/字,但只有一个输入,而不是两个。不过,我猜,由于它使用了 SSE 寄存器,它的速度要快得多。
一些问题:
- 使用“加载、加载、添加、存储”结构有用还是“加载、添加到内存”有帮助?到目前为止,我的测试没有显示出任何优势。
- 像往常一样,SSE(2,3,4) 没有帮助?
- 寻址(缩放索引加基数加偏移量)影响严重吗?我可以
ADD r11, 8
改用。 - 循环展开怎么样?我读到展开对 Sandy Bridge 架构不利(Agner Fog http://www.agner.org/optimize/)。是首选还是避免?
- (编辑)我可以使用 SSE 寄存器从内存中以更大的块加载和存储字,并有效地与通用寄存器和 SSE 寄存器交换字吗?
我非常感谢任何评论。