[解決済み] 8192個の要素にループをかけると、プログラムが遅くなるのはなぜですか?
質問
以下は、問題のプログラムの抜粋です。行列は
img[][]
はサイズSIZE×SIZEで、初期化されます。
img[j][i] = 2 * j + i
次に、行列を作ります。
res[][]
この中の各フィールドは、imgマトリックス内のその周りの9つのフィールドの平均となるように作られています。簡単のために、境界線は0にしたままです。
for(i=1;i<SIZE-1;i++)
for(j=1;j<SIZE-1;j++) {
res[j][i]=0;
for(k=-1;k<2;k++)
for(l=-1;l<2;l++)
res[j][i] += img[j+l][i+k];
res[j][i] /= 9;
}
プログラムは以上です。念のため、以下はその前の部分です。この後、コードは出てきません。見ての通り、ただの初期化です。
#define SIZE 8192
float img[SIZE][SIZE]; // input image
float res[SIZE][SIZE]; //result of mean filter
int i,j,k,l;
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
img[j][i] = (2*j+i)%8196;
基本的にこのプログラムは、SIZEが2048の倍数のとき、実行時間などが遅くなります。
SIZE = 8191: 3.44 secs
SIZE = 8192: 7.20 secs
SIZE = 8193: 3.18 secs
コンパイラはGCCです。 私が知っている限りでは、これはメモリ管理のためですが、私はそのテーマについてあまりよく知らないので、ここで質問しています。
また、これを修正する方法もあればいいのですが、この実行時間を説明してくれる人がいれば、もう十分満足です。
malloc/freeは既に知っていますが、問題は使用するメモリの量ではなく、単に実行時間なので、それがどう役に立つのかわかりません。
解決方法は?
この違いは、以下の関連質問と同じスーパーアライメントの問題によるものです。
でもそれは、コードにもうひとつ問題があるからに他なりません。
元のループからスタート
for(i=1;i<SIZE-1;i++)
for(j=1;j<SIZE-1;j++) {
res[j][i]=0;
for(k=-1;k<2;k++)
for(l=-1;l<2;l++)
res[j][i] += img[j+l][i+k];
res[j][i] /= 9;
}
まず、2つの内側のループが些細なものであることに気づく。これらは次のように展開することができる。
for(i=1;i<SIZE-1;i++) {
for(j=1;j<SIZE-1;j++) {
res[j][i]=0;
res[j][i] += img[j-1][i-1];
res[j][i] += img[j ][i-1];
res[j][i] += img[j+1][i-1];
res[j][i] += img[j-1][i ];
res[j][i] += img[j ][i ];
res[j][i] += img[j+1][i ];
res[j][i] += img[j-1][i+1];
res[j][i] += img[j ][i+1];
res[j][i] += img[j+1][i+1];
res[j][i] /= 9;
}
}
これで、興味のある2つのアウターループが残ったわけです。
さて、この問題でも問題は同じであることがわかります。 2次元配列の反復処理において、ループの順序がパフォーマンスに影響するのはなぜですか?
行列を行単位ではなく、列単位で反復している。
この問題を解決するには、2つのループを入れ替える必要があります。
for(j=1;j<SIZE-1;j++) {
for(i=1;i<SIZE-1;i++) {
res[j][i]=0;
res[j][i] += img[j-1][i-1];
res[j][i] += img[j ][i-1];
res[j][i] += img[j+1][i-1];
res[j][i] += img[j-1][i ];
res[j][i] += img[j ][i ];
res[j][i] += img[j+1][i ];
res[j][i] += img[j-1][i+1];
res[j][i] += img[j ][i+1];
res[j][i] += img[j+1][i+1];
res[j][i] /= 9;
}
}
これにより、非シーケンシャルなアクセスは完全に排除され、大きな2のべき乗でランダムにスローダウンすることがなくなりました。
Core i7 920 @ 3.5 GHz
オリジナルのコードです。
8191: 1.499 seconds
8192: 2.122 seconds
8193: 1.582 seconds
Outer-Loopsを入れ替えたもの。
8191: 0.376 seconds
8192: 0.357 seconds
8193: 0.351 seconds
関連
-
[解決済み] 警告:暗黙の定数変換でのオーバーフロー
-
[解決済み】Eclipse IDEでC++エラー「nullptrはこのスコープで宣言されていません」が発生する件
-
[解決済み] 0.1fを0にすると、なぜ10倍もパフォーマンスが落ちるのですか?
-
[解決済み] INNER JOINよりもCROSS APPLYを使用すべきなのはどのような場合ですか?
-
[解決済み] MongoDBとその逆の上にCouchDBを使用するとき
-
[解決済み] プログラムがクラッシュしたときにスタックトレースを自動的に生成する方法
-
[解決済み] なぜGCCは、速度の代わりにサイズに最適化すると、15-20%速いコードを生成するのですか?
-
[解決済み] Intel CPU の _mm_popcnt_u64 で、32 ビットのループカウンターを 64 ビットに置き換えると、パフォーマンスが著しく低下します。
-
[解決済み】PyPyが6.3倍速いなら、CPythonよりPyPyを使うべきじゃないのか?
-
[解決済み】240以上の要素を持つ配列に対してループ処理を行うと、パフォーマンスに大きな影響があるのはなぜですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】コンストラクターでのエラー:識別子を期待されますか?
-
[解決済み】C++コンパイルタイムエラー:数値定数の前に期待される識別子
-
[解決済み】致命的なエラー LNK1169: ゲームプログラミングで1つ以上の多重定義されたシンボルが発見された
-
[解決済み] 非静的データメンバの無効な使用
-
[解決済み】クラスのコンストラクタへの未定義参照、.cppファイルの修正も含む
-
[解決済み】C++ - 適切なデフォルトコンストラクタがない [重複]。
-
[解決済み】C++ - ステートメントがオーバーロードされた関数のアドレスを解決できない。
-
[解決済み】デバッグアサーションに失敗しました
-
[解決済み] 2次元配列の反復処理において、ループの順序がパフォーマンスに影響するのはなぜですか?
-
[解決済み】512x512の行列の転置は、513x513の行列の転置よりずっと遅いのはなぜ?