我正在处理非常长整数的乘法算术问题(约100,000个十进制数字)。作为我的库的一部分,我需要添加两个长数字。
性能测试显示,我的代码运行时间中有多达25%用于add()和sub()例程,因此它们尽可能快是很重要的。但是我还没有看到太多潜力。也许你可以给我一些帮助、建议、见解或想法。我会测试它们并回复你。
到目前为止,我的加法例程做了一些设置,然后使用了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个不同偏移的块,然后进入循环。
我之前尝试过从内存中加载值,但没有帮助。我猜这是因为良好的预取。我使用的是英特尔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 Foghttp://www.agner.org/optimize/)。是应该优选还是应该避免?
- (编辑)我可以使用SSE寄存器从内存中加载和存储单词并高效地在通用寄存器和SSE寄存器之间交换单词吗?
非常感谢任何评论。