bre*_*nzo 8 c++ optimization assembly gcc compiler-optimization
我在物理引擎中有一个循环,它检测如下碰撞:
// now check for collisions
// we only allow 1 collision per 2 partcles per frame so the
// one with the lower index will always "collide" first
for (size_t j = 0; j < m_particles.size(); j++) {
for (size_t k = j + 1; k < m_particles.size(); k++) {
m_particles[j].collide(m_particles[k]);
}
}
Run Code Online (Sandbox Code Playgroud)
我进行了更改,在内部对粒子使用双缓冲区。(顺便说一句;这样做是为了我可以检测到错误并返回 1 个时间步来纠正)。双缓冲区是用两个指针实现的,我在这个循环之后交换了这两个指针。所以现在我们有:
// now check for collisions
// we only allow 1 collision per 2 partcles per frame so the
// one with the lower index will always "collide" first
for (size_t j = 0; j < m_current_particles->size(); j++) {
for (size_t k = j + 1; k < m_current_particles->size(); k++) {
(*m_current_particles)[j].collide((*m_current_particles)[k]);
}
}
std::swap(m_current_particles, m_previous_particles);
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,容器都是std::vector.
使用相同的驱动程序,第二个速度慢 10 倍以上。函数内部没有任何collide()变化,我可以通过创建一个仅切换到双缓冲区而没有其他任何更改的构建来重现。
collide()最终我打开了分析工具,果然……尽管来源相同,但该功能的程序集完全不同。在任何一种情况下,都有一个显式的子callq例程collide,因此在前一种情况下,它不会将碰撞函数内联到循环中。
在前一种情况下:
operator粒子 Vector(我自己的向量实现,而不是 )成员上的所有 Vector重载std::vector均已转换为内联汇编。%xmm寄存器在性能回归的情况下:
%xmm寄存器,一切都是%rax,%rbx等等。尽我所能,我无法说服编译器使用新代码生成类似于原始程序集的内容。
inline被调用的collide()内容(尽管我听说这些天编译器基本上会忽略你,如果你这样做)。auto& local_particles = m_current_particles本地变量,以防编译器对指针的范围感到不安。这是否只是编译器疯狂的大脑在前一种情况下以正确的方式排列的情况,或者我的调用约定以某种方式破坏了我在这两个来源之间坚持的不变量?
这是调用图的相关部分:
前一个案例(所有内容都已内联):
回归(显式调用是显而易见的):
需要折叠以合理地适应,下面的调用collide()是operator-Vector 和 Vector 构造函数本身的重载,用于创建临时对象。
编辑:在前一种情况下使用 -O2 ,它会内联昂贵的向量减法运算符,但不会内联临时的 ctor 调用。运行速度大约是 -O3 的 1.3 倍。回归情况下的-O2 和-O3 看起来本质上是相同的。
| 归档时间: |
|
| 查看次数: |
279 次 |
| 最近记录: |