問題のより高いレベルの説明から始めるべきだと思います。
しかし、2番目のオプションとして、配列インデックスを交換して、4つの(場合によっては異なる)ベクトルを組み合わせた非常に高速なSSE内部ループのコーディングを容易にすることをお勧めします。
double times[N+1][nsims], *tend = times[N+1];
double *j,*k,*i,*l;
for (j=times[2];j<tend;j+=nsims)
for (k=j;k<tend;k+=nsims)
if (strcmp( )) ... /* One _can_ move this elsewhere, but why bother? */
for (i=times[2];i<tend;i+=nsims)
for (l=i;l<tend;l+=nsims) {
interm = efficient_sse_implementation(j,k,i,l, nsims);
...
}
個別のアレイが4つ未満の場合は、異なるカーネルを作成することで、ごくわずかな最適化を実現することもできます。(その場合、ストライドごとに1つのメモリ操作をスキップできます。)
編集
この場合、パターンの構造はfor(j=2;j<=N;j++) for (k=j;k<=N;k++)
2回繰り返されますが、それだけで、はるかに高いレベルの最適化の可能性が示唆されます。実行される操作は何ですか。それで苦労している間、このパターンはまだ別の方法を示唆しています:780(またはそれくらい)の副産物をキャッシュしますが、同時にループブロッキングを実行します。このアプローチは、私が氏にコメントしたものと同じ問題を抱えているべきではありません。gcbenison。
for (A=0;A<50000;A+=100) {
int k=0;
for (i=2;i<=N;i++)
for (j=i;j<=N;j++,k++)
for (a=0;a<100;a++) precalc[k][a]=times[i][A+a]*times[j][A+a];
for (i=0;i<k;i++) // Now i loops from 0..779 or so
for (j=0;j<k;j++) {
for (a=0;a<100;a++) partial_product+=precalc[i][a]*precalc[j][a];
// accumulate also partial_product to moment
}
}
免責事項:これは未試行ですが、最適なブロックサイズ(必ずしも100ではない)が存在します(前のものよりもさらに悪い場合があります)。また、このアプローチでは、事前に計算されたテーブルに大量のメモリが使用されることに注意してください。(100のブロックサイズを選択すると、624000バイトのメモリが必要になります。これはかなり良い音です。256k未満になるには、ブロック長は42になります)。
編集2:
//EDIT_1のループがとの両方P[2][a]*P[3][a]
を計算することに注意してくださいP[3][a]*P[2][a]
。
for (i=0;i<k;i++) // Now i loops from 0..779 or so, but... we can limit the
for (j=i;j<k;j++) { // calculation to the upper triangle of the 780^2 matrix
for (a=0;a<100;a++) partial_product+=precalc[i][a]*precalc[j][a];
moment[i]+=partial_product;
moment[lower_triangle(i)]+=partial_product; // <-- 50% speed increase
}
編集3:そしてここに試してみることがあります:
gcc -O4 -DCACHELEVEL=2 -DPOPULATE=1 -DARRAY_OPT=1 && time ./a.out
POPULATE
配列を初期化します(ゼロ以外の内容が重要であると想定)
ARRAY_OPT=1
配列のインデックスを(おそらく)より良い順序に切り替えます
CACHELEVEL=2
または中間結果のキャッシュを3回切り替えます。
STRCMP
memcmp vs. strcmpvs'1'をテストするためのソースコードにあります
NOT TODO 1:キャッシュされた値を使用したLOOP_BLOCKING-パフォーマンスを低下させます
TODO 2:上三角計算のみ
TODO 3changed_times[n]
:との意味を調べます-moments[0][p]
現在目立つように、計算は保存されません!
#include <stddef.h>
#define N 40
#define nsims 8000
#if ARRAY_OPT
#define TIMES(n,a) times[n][a]
double times[N+1][nsims]; // [nsims];
#else
#define TIMES(n,a) times[a][n]
double times[nsims][N+1];
#endif
#define STRCMP 1
// vs.
// #define STRCMP1 strcmp(mmethod, "emp")==0
void init()
{
#ifdef POPULATE
int i,a;
for (i=0;i<=N;i++)
for (a=0;a<nsims;a++)
TIMES(i,a) = (double)((i^a)&7) - 3.5;
#endif
}
double moments[4000] = { 0 };
double cache1[nsims];
double cache2[nsims];
int main()
{
int j,k,i,l,a, pcount=0;
init();
int changed_times[N+1]={0};
char *mmethod="emp";
double moment,interm;
for(j=2;j<=N;j++) {
for(k=j;k<=N;k++) {
#if CACHELEVEL == 2
for (a=0;a<nsims;a++) cache1[a]=TIMES(j,a)*TIMES(k,a);
#endif
moment=0;
for(i=2;i<=N;i++) {
#if CACHELEVEL == 3
for (a=0;a<nsims;a++) cache2[a]=TIMES(j,a)*TIMES(k,a)*TIMES(i,a);
#else
for (a=0;a<nsims;a++) cache2[a]=cache1[a]*TIMES(i,a);
#endif
for(l=i;l<=N;l++) {
if(STRCMP) {
for(a=0;a<nsims;a++) {
#if CACHELEVEL >= 2
interm += (double) cache2[a]*TIMES(l,a);
#else
interm=interm + (double) TIMES(k,a) * TIMES(j,a) * TIMES(i,a) * TIMES(l,a);
#endif
}
interm = (double) interm/(double)nsims;
moment = moment + (interm*i*l);
interm=0;
}
}
}
//if(!(changed_times[k]==0
// && changed_times[j]==0
// && changed_times[l]==0
// && changed_times[i]==0))
//{
// moments[0][pcount]=(double) moment;
// changed_times[k]++;changed_times[j]++; /* or what? */
// changed_times[l]++;changed_times[i]++;
//} else {
// moments[0][pcount]=moments[0][pcount];
//}
pcount++;
}
}
printf("%d %f\n",pcount, moment);
}