编辑:( 我正在删除有关的详细信息,restrict
因为它偏离了所提出的实际问题并引起了混乱。假设restict
使用了 OP。)
对于优化编译器而言,您问题中的转换确实微不足道,但这不是阿克顿的论文所建议的。
这是论文中所做的转换:
这段代码...
for (size_t i=0;i<count*stride;i+=stride)
{
velocity_x[i] += acceleration_x[i] * time_step;
velocity_y[i] += acceleration_y[i] * time_step;
velocity_z[i] += acceleration_z[i] * time_step;
position_x[i] += velocity_x[i] * time_step;
position_y[i] += velocity_y[i] * time_step;
position_z[i] += velocity_z[i] * time_step;
}
...被转换成这段代码:
for (size_t i=0;i<count*stride;i+=stride)
{
const float ax = acceleration_x[i];
const float ay = acceleration_y[i];
const float az = acceleration_z[i];
const float vx = velocity_x[i];
const float vy = velocity_y[i];
const float vz = velocity_z[i];
const float px = position_x[i];
const float py = position_y[i];
const float pz = position_z[i];
const float nvx = vx + ( ax * time_step );
const float nvy = vy + ( ay * time_step );
const float nvz = vz + ( az * time_step );
const float npx = px + ( vx * time_step );
const float npy = py + ( vy * time_step );
const float npz = pz + ( vz * time_step );
velocity_x[i] = nvx;
velocity_y[i] = nvy;
velocity_z[i] = nvz;
position_x[i] = npx;
position_y[i] = npy;
position_z[i] = npz;
}
优化是什么?
优化不是- 正如建议的那样 - 将 1 个表达式分离为 3 个表达式。
优化是在对任何特定数据块进行操作的指令之间插入有用的指令。
如果您跟踪数据从velocity_x[i]
到移动到vx
,则 CPU 在每个步骤之间执行其他工作。nvx
velocity_x[i]
为什么这是优化?
现代 CPU 通常具有流水线架构。
由于指令是分阶段执行的,CPU 允许同时处理多条指令。但是,当一条指令需要另一条尚未完全执行的指令的结果时,这条流水线就会停止。在停止的指令可以运行之前,不会执行进一步的指令。
为什么我的优化编译器不自动执行此操作?
有些人会。
GCC 在这种优化方面相对较差。
我使用 gcc 4.7(x86-64 架构,在 -O3 优化)反汇编了上面的两个循环。产生了类似的程序集,但指令的顺序不同,第一个版本产生了严重的停顿,其中单个浮点数将在几条指令的范围内加载、更改和存储。
你可以在这里阅读一些关于 gcc 指令调度的信息,或者只是在网上搜索gcc 指令调度来查看很多关于这个问题的令人沮丧的文章。