以前にファイルから読み取った行列に対してステンシル計算を実行しています。2 種類の行列 (NonZero タイプと Zero タイプ) を使用します。どちらのタイプも境界の値 (通常は 1000) を共有しますが、残りの要素は Zero タイプの場合は 0、NonZero タイプの場合は 1 です。
このコードは、ファイルの行列を同じサイズの 2 つの割り当てられた行列に格納します。次に、1 つの行列のすべての要素で、それ自体の値と隣接要素の値を使用して演算を実行し (x 4 と mul x 1 を加算)、結果を 2 番目の行列に格納します。計算が完了すると、行列のポインターが交換され、同じ操作が有限回実行されます。ここにコアコードがあります:
#define GET(I,J) rMat[(I)*cols + (J)]
#define PUT(I,J) wMat[(I)*cols + (J)]
for (cur_time=0; cur_time<timeSteps; cur_time++) {
for (i=1; i<rows-1; i++) {
for (j=1; j<cols-1; j++) {
PUT(i,j) = 0.2f*(GET(i-1,j) + GET(i,j-1) + GET(i,j) + GET(i,j+1) + GET(i+1,j));
}
}
// Change pointers for next iteration
auxP = wMat;
wMat = rMat;
rMat = auxP;
}
私が公開しているケースでは、固定量の 500 timeSteps (外側の反復) と 8192 行と 8192 列のマトリックス サイズを使用していますが、timeSteps の数またはマトリックス サイズを変更しても問題は解決しません。アルゴリズムのこの具体的な部分の時間のみを測定することに注意してください。そのため、ファイルからの行列の読み取りやその他の時間測定には影響しません。
それが起こるのは、使用するマトリックスのタイプに応じて異なる時間が得られ、Zero タイプを使用するとパフォーマンスが大幅に低下することです (他のすべてのマトリックスは NonZero タイプと同じように動作します。値)。
私はそれが乗算演算であることを確信しています。それを削除して加算のみを残した場合、それらは同じように実行されます。ゼロ行列タイプでは、ほとんどのタイプで合計の結果が 0 になるため、演算は「0.2*0」になることに注意してください。
浮動小数点演算はオペランドの値とは無関係であると考えていたので、この動作は確かに奇妙です。ここではそうではありません。問題が発生した場合に備えて、SIGFPE例外をキャプチャして表示しようとしましたが、結果は得られませんでした。
参考までに、Intel Nehalem プロセッサと gcc 4.4.3 を使用しています。