C++ 我的循环还能再优化吗?
下面是我最里面的循环,它运行了几千次,输入大小为20-1000或更多。这段代码占用99-99.5%的执行时间。我能做些什么来帮助你从中挤出更多的表现吗 我不打算将此代码移到类似使用树代码(Barnes-Hut)的地方,而是要优化内部发生的实际计算,因为在Barnes-Hut算法中也会发生相同的计算 感谢您的帮助 编辑:我在Windows7 64位上运行,在核心2 Duo T5850(2.16GHz)上运行VisualStudio2008EditionC++ 我的循环还能再优化吗?,c++,math,optimization,loops,physics,C++,Math,Optimization,Loops,Physics,下面是我最里面的循环,它运行了几千次,输入大小为20-1000或更多。这段代码占用99-99.5%的执行时间。我能做些什么来帮助你从中挤出更多的表现吗 我不打算将此代码移到类似使用树代码(Barnes-Hut)的地方,而是要优化内部发生的实际计算,因为在Barnes-Hut算法中也会发生相同的计算 感谢您的帮助 编辑:我在Windows7 64位上运行,在核心2 Duo T5850(2.16GHz)上运行VisualStudio2008Edition typedef双实数; 结构粒子 { 矢量位
typedef双实数;
结构粒子
{
矢量位置、水平、加速度、加速度;
向量oldPos、oldVel、oldAcc、oldJerk;
实际质量;
};
类向量
{
私人:
实vec[3];
公众:
//此处定义的运算符
};
真实重力::相互作用(粒子*p,大小\u t个粒子)
{
PROFILE_FUNC();
实际tau_q=1e300;
对于(大小i=0;i
是。尝试查看程序集输出。它可能会提供编译器哪里出错的线索
现在,请始终首先应用算法优化,并且只有当没有更快的算法可用时,才应按汇编进行逐段优化。然后,先做内部循环
首先,您可能想分析一下这是否真的是瓶颈
tau_q=minimum(...,...)
许多编译器将mininum函数识别为可以使用谓词操作而不是实际分支来执行的函数,从而避免了管道刷新
4b。[编辑分割4a和4b分开]您可以考虑存储Tauiq.Q2而不是Tauq q,并与R2/V2进行比较,而不是R2*R2/V2*V2。然后,避免在内部循环中对每次迭代执行两次乘法,以换取在最后计算tau..q2的一次平方运算。为此,分别收集tau_q1和tau_q2的最小值(非平方),并在循环完成时在单个标量操作中取这些结果的最小值]
在此之外,你需要考虑一个循环展开,b)矢量化(使用SIMD指令;或者手工编码汇编程序或使用英特尔编译器,它应该是相当好的,但是我没有经验),C)使用多核(使用OpenMP)。< /P> < UL>
-O2
或者可能是-O3
这一行
real r3i=常数::G*pow(r2,-1.5)代码>会受伤的。任何类型的sqrt查找或具有平方根的特定于平台的帮助都会有所帮助
如果你有simd能力,把向量减法和平方分解成自己的循环,一次计算它们会有帮助。质量/挺举计算也一样
我想到的是——你的计算精度是否足够高?把东西带到第四次方和第四次方,真的可以通过下/溢出混合器来搅动你的可用位。我确信你的答案在完成时确实是你的答案
除此之外,它是一个数学量很大的函数,需要一些CPU时间。汇编程序对此的优化不会产生比编译器已经能为您做的更多的结果
另一个想法。由于这似乎与重力有关,有没有办法根据距离检查剔除你繁重的数学题?基本上是半径/
tau_q=minimum(...,...)
for (size_t i = 0; i < numParticles; i++)
{
for (size_t j = i+1; j < numParticles; j++)
{
float InvSqrt(float x)
{
union {
float f;
int i;
} tmp;
tmp.f = x;
tmp.i = 0x5f3759df - (tmp.i >> 1);
float y = tmp.f;
return y * (1.5f - 0.5f * x * y * y);
}
struct ParticleData
{
Vector pos, vel, acc, jerk;
};
ParticleData* currentParticles = ...
ParticleData* oldParticles = ...
real* masses = ...
struct ParticleData
{
// data_x[0] == pos.x, data_x[1] = vel.x, data_x[2] = acc.x, data_x[3] = jerk.x
Vector4 data_x;
// data_y[0] == pos.y, data_y[1] = vel.y, etc.
Vector4 data_y;
// data_z[0] == pos.z, data_y[1] = vel.z, etc.
Vector4 data_z;
};
Vector r;
Vector v;
real r2;
real v2;
Vector da;
Vector dj;
real r3i;
real mij;
real tau_est_q1;
real tau_est_q2;
for (size_t i = 0; i < numParticles; i++)
{
for (size_t j = i+1; j < numParticles; j++)
{
r = p[j].pos - p[i].pos;
v = p[j].vel - p[i].vel;
r2 = lengthsq(r);
v2 = lengthsq(v);
// Calculate inverse of |r|^3
r3i = Constants::G * pow(r2, -1.5);
// da = r / |r|^3
// dj = (v / |r|^3 - 3 * (r . v) * r / |r|^5
da = r * r3i;
dj = (v - r * (3 * dot(r, v) / r2)) * r3i;
// Calculate new acceleration and jerk
p[i].acc += da * p[j].mass;
p[i].jerk += dj * p[j].mass;
p[j].acc -= da * p[i].mass;
p[j].jerk -= dj * p[i].mass;
// Collision estimation
// Metric 1) tau = |r|^2 / |a(j) - a(i)|
// Metric 2) tau = |r|^4 / |v|^4
mij = p[i].mass + p[j].mass;
tau_est_q1 = r2 / (lengthsq(da) * mij * mij);
tau_est_q2 = (r2*r2) / (v2*v2);
if (tau_est_q1 < tau_q)
tau_q = tau_est_q1;
if (tau_est_q2 < tau_q)
tau_q = tau_est_q2;
}
}
a = b/c
d = e/f
icf = 1/(c*f)
a = bf*icf
d = ec*icf