私はいくつかのC++( RK4 )を使用して最適化しようとしています
__builtin_prefetch
構造全体をプリフェッチする方法がわかりません。
const void *addr
がどれだけ読み取られているのかわかりません。 from
とto
の次の値をロードしたいと思います。
for (int i = from; i < to; i++)
{
double kv = myLinks[i].kv;
particle* from = con[i].Pfrom;
particle* to = con[i].Pto;
//Prefetch values at con[i++].Pfrom & con[i].Pto;
double pos = to->px- from->px;
double delta = from->r + to->r - pos;
double k1 = axcel(kv, delta, from->mass) * dt; //axcel is an inlined function
double k2 = axcel(kv, delta + 0.5 * k1, from->mass) * dt;
double k3 = axcel(kv, delta + 0.5 * k2, from->mass) * dt;
double k4 = axcel(kv, delta + k3, from->mass) * dt;
#define likely(x) __builtin_expect((x),1)
if (likely(!from->bc))
{
from->x += (( k1 + 2 * k2 + 2 * k3 + k4) / 6);
}
}
リンク: http://www.ibm.com/developerworks/linux/library/l-gcc-hacks/
FETCH
マシン命令を1つだけ発行すると思います。これは基本的に、プロセッサ固有のサイズのラインキャッシュをフェッチします。
たとえば、__builtin_prefetch (con[i+3].Pfrom)
を使用できます。私の(小さな)経験では、このようなループでは、事前にいくつかの要素をプリフェッチすることをお勧めします。
__builtin_prefetch
をあまり頻繁に使用しないでください(つまり、それらの多くをループ内に配置しないでください)。必要に応じてパフォーマンスの向上を測定し、GCC最適化を使用します(少なくとも-O2
)。運が良ければ、手動の__builtin_prefetch
を使用すると、ループのパフォーマンスが10%または20%向上する可能性があります(ただし、ループのパフォーマンスが低下する可能性もあります)。
このようなループが重要な場合は、OpenCLまたはCUDAを備えたGPUで実行することを検討してください(ただし、OpenCLまたはCUDA言語でいくつかのルーチンを再コーディングし、特定のハードウェアに調整する必要があります)。
最近のGCCコンパイラ(最新リリースは4.6.2)も使用してください。これらの領域で多くの進歩が見られます。
(2018年1月に追加:)
ハードウェア(プロセッサ)とコンパイラの両方がキャッシュに関して多くの進歩を遂げたため、__builtin_prefetch
の使用は今日(2018年)あまり役に立たないようです。必ずベンチマークを付けてください。
キャッシュラインを読み取ります。キャッシュラインのサイズは異なる場合がありますが、最近のCPUでは64バイトになる可能性があります。複数のキャッシュラインを読み取る必要がある場合は、 prefetch_range
。