c++ 我的循环可以再优化吗?

下面是我的最内圈,运行几千次,输入大小为20 – 1000或更多。这段代码占用99-99.5%的执行时间。有什么可以做的,以帮助挤压更多的表现呢?

我不是希望把这个代码移动到像使用树形代码(Barnes-Hut)这样的代码,而是为了优化里面的实际计算,因为在Barnes-Hut算法中发生相同的计算。

任何帮助是赞赏!

编辑:我在Windows 7 64位与Visual Studio 2008版在Core 2 Duo T5850(2.16 GHz)上运行

typedef double real;

struct Particle
{
    Vector pos, vel, acc, jerk;
    Vector oldPos, oldVel, oldAcc, oldJerk;
    real mass;
};

class Vector
{
private:
    real vec[3];

public:
    // Operators defined here
};

real Gravity::interact(Particle *p, size_t numParticles)
{
    PROFILE_FUNC();
    real tau_q = 1e300;

    for (size_t i = 0; i < numParticles; i++)
    {
        p[i].jerk = 0;
        p[i].acc = 0;
    }

    for (size_t i = 0; i < numParticles; i++)
    {
        for (size_t j = i+1; j < numParticles; j++)
        {
            Vector r = p[j].pos - p[i].pos;
            Vector v = p[j].vel - p[i].vel;
            real r2 = lengthsq(r);
            real v2 = lengthsq(v);

            // Calculate inverse of |r|^3
            real r3i = Constants::G * pow(r2, -1.5);

            // da = r / |r|^3
            // dj = (v / |r|^3 - 3 * (r . v) * r / |r|^5
            Vector da = r * r3i;
            Vector 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
            real mij = p[i].mass + p[j].mass;
            real tau_est_q1 = r2 / (lengthsq(da) * mij * mij);
            real 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;
        }
    }

    return sqrt(sqrt(tau_q));
}
>将对callsq()的调用内联。
>将pow(r2,-1.5)更改为1 /(r2 * sqrt(r2))以降低计算的成本r ^ 1.5
>使用标题(p_i_acc,等等)在内部的最循环而不是p [i] .acc来收集你的结果。编译器可能不知道p [i]不是用p [j]进行别名,并且可能会迫使每个循环迭代上的p [i]寻址不必要。

4a。尝试用…替换if(…)tau_q =

    tau_q=minimum(...,...)

许多编译器将mininate函数识别为可以使用预定义的操作而不是真正的分支,这样可以避免管道冲洗。

4b。 [编辑分开4a和4b分开]您可以考虑将tau _ .. q2替换为tau_q,并与r2 / v2进行比较,而不是r2 * r2 / v2 * v2。那么你可以避免在内部循环中为每个迭代执行两个乘法,在交换单个平方运算以在末尾计算tau..q2。为此,分别收集最小值τ_q1和tau_q2(不是平方),并且在循环完成时将单个标量运算中的最小值取最小值]

> [编辑:我建议以下,但实际上它对OP的代码是无效的,因为他在循环中更新的方式。]将两个循环相互叠在一起。使用两个循环和足够大的粒子集,您可以跳过缓存,并强制从第二个循环中的那些初始值的非缓存重新引用。折叠是微不足道的。

除此之外,您需要考虑a)循环展开,b)向量化(使用SIMD指令;手编码汇编器或使用英特尔编译器,这应该是相当不错的[但我没有经验],c )进行多核(使用OpenMP)。

翻译自:https://stackoverflow.com/questions/2725674/can-my-loop-be-optimized-any-more

转载注明原文:c++ 我的循环可以再优化吗?