メモリアクセスを連続に
とりあえず、問題設定としてはNxNサイズの正方行列A,B,CについてC=ABと積を計算すること。
C=Oの初期化は別にされてるとして、それ以降の計算。基本的にはこうなる。
これは見ての通り、i,j,k について対称な(どの演算を先にやっても結果は変わらない)ので、
for( i = 0 ; i < N ; i++ ) {
for( j = 0 ; j < N ; j++ ) {
for( k = 0 ; k < N ; k++ ) {
c[i][j] += a[i][k] * b[k][j];
}
}
}
順番を変えてみる。具体的には
の6パターンの変化が考えられる。とりあえずこれを適当に実装して時間を計ってみた。
for(i=0;i<N;i++)for(j=0;j<N;j++)for(k=0;k<N;k++)c[i][j]+=a[i][k]*b[k][j];
for(i=0;i<N;i++)for(k=0;k<N;k++)for(j=0;j<N;j++)c[i][j]+=a[i][k]*b[k][j];
for(j=0;j<N;j++)for(i=0;i<N;i++)for(k=0;k<N;k++)c[i][j]+=a[i][k]*b[k][j];
for(j=0;j<N;j++)for(k=0;k<N;k++)for(i=0;i<N;i++)c[i][j]+=a[i][k]*b[k][j];
for(k=0;k<N;k++)for(i=0;i<N;i++)for(j=0;j<N;j++)c[i][j]+=a[i][k]*b[k][j];
for(k=0;k<N;k++)for(j=0;j<N;j++)for(i=0;i<N;i++)c[i][j]+=a[i][k]*b[k][j];
ijk | ikj | jik | jki | kij | kji |
---|---|---|---|---|---|
17.06 | 2.42 | 17.22 | 34.20 | 2.60 | 34.61 |
見ての通り、メモリを連続にアクセスしやすいikjやkijのループが速くなっている。