Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 相同的操作需要不同的时间_C++_Assembly - Fatal编程技术网

C++ 相同的操作需要不同的时间

C++ 相同的操作需要不同的时间,c++,assembly,C++,Assembly,我正在为我的n-body模拟器优化我的代码,在分析我的代码时,我看到了以下几点: 这两条线, 其中pNode是指向我已定义的Node类型的对象的指针,包含(与其他内容一起)2个浮动、CenterOfMassx和CenterOfMassy 其中pBody是指向我定义的Body类型的对象的指针,它包含(与其他内容一起)2个浮动、posX和posY 应该花费相同的时间,但不要。事实上,第一行占函数样本的0.46%,而第二行占5.20% 现在我可以看到第二行有3条指令,第一行只有一条 我的问题是,

我正在为我的n-body模拟器优化我的代码,在分析我的代码时,我看到了以下几点:

这两条线,


其中
pNode
是指向我已定义的
Node
类型的对象的指针,包含(与其他内容一起)2个浮动、
CenterOfMassx
CenterOfMassy

其中
pBody
是指向我定义的
Body
类型的对象的指针,它包含(与其他内容一起)2个浮动、
posX
posY


应该花费相同的时间,但不要。事实上,第一行占函数样本的0.46%,而第二行占5.20%

现在我可以看到第二行有3条指令,第一行只有一条


我的问题是,为什么这些看起来做相同的事情,但实际上做不同的事情

根据扩展的程序集,在对
pBody
的数据成员执行减法之前,指令会重新排序以加载
pNodes
的数据成员。其目的可能是利用内存缓存


因此,执行顺序不再与C代码相同。将第1条C语句中的1条movss与第2条C语句中的1条movss+2条subss进行比较是不公平的。

如前所述,探查器在第一行中只列出了一条汇编指令,在第二行中列出了三条。然而,由于优化器可以大量移动代码,这不是很有意义。看起来代码经过了优化,首先将所有值加载到寄存器中,然后执行减法运算。因此,它从第一行执行一个动作,然后从第二行执行一个动作(负载),然后从第一行执行一个动作,从第二行执行一个动作(减法)。因为这很难表示,所以当显示与代码内联的反汇编时,它只是对哪一行对应于哪一个汇编代码进行了最佳近似

请注意,第一个加载已执行,并且在执行下一个加载指令时,它可能仍在CPU管道中。第二个加载不依赖于第一个加载中使用的寄存器。然而,第一个减法确实如此。此指令要求上一条load指令在管道中足够远,以便结果可以用作减法运算的操作数之一。当管道允许加载完成时,这可能会导致CPU暂停

所有这些都强化了内存优化在现代CPU上比CPU优化更重要的概念。例如,如果您之前已将所需的值加载到寄存器15指令中,则减法可能会发生得更快

一般来说,优化的最佳方法是使缓存与要使用的内存保持一致,并确保它尽快更新,而不是在需要内存之前。除此之外,优化是复杂的

当然,所有这些都因现代CPU而变得更加复杂,这些CPU可能会提前40-60条指令


进一步优化这一点,您可以考虑使用一个以优化方式执行向量和矩阵运算的库。使用这些库中的一个,可以使用两条矢量指令而不是4条标量指令。

性能计数器不是周期精确的。有时错误的指令会受到指责。但在本例中,它可能指向产生其他所有东西都在等待的结果的指令

因此,在等待内存访问和FP sub的结果时,它可能已经用尽了可以做的事情。如果发生了缓存未命中,请寻找方法来构造代码以获得更好的内存局部性,或者至少让内存访问按顺序进行。硬件预取器可以检测到步幅达到一定限制的顺序访问模式

此外,您还可以将其矢量化。它从顺序地址加载两个标量,然后从顺序地址减去两个标量。这样做会更快

movq xmm0, [esi+30h]   # or movlps, but that wouldn't break the dep
movq xmm1, [edi]       # on the old value of xmm0 / xmm1
subps xmm0, xmm1

这将
diffX
diffY
保留在
xmm0
的元素0和1中,而不是两个不同的reg,因此好处取决于周围的代码。

那么,为什么代码行会变成不同的汇编指令,有没有办法把第二行的速度提高到第一行的速度?每一行变成两条相同的asm指令,但它们被重新排序。一个源代码行获取一个insn,另一个获取3,因为否则asm指令将必须无序显示。顺便说一句,这不是为了利用缓存。这是为了更好地隐藏加载的延迟。如果
pNode
距离
pBody
很远,与交错相比,它不是通过在
*pBody
之前加载
*pNode
来利用缓存吗?
movq xmm0, [esi+30h]   # or movlps, but that wouldn't break the dep
movq xmm1, [edi]       # on the old value of xmm0 / xmm1
subps xmm0, xmm1