TL; DR:データの乗算/キャストがsize_t
遅いのはなぜですか?また、これがプラットフォームごとに異なるのはなぜですか?
完全には理解できないパフォーマンスの問題が発生しています。コンテキストは、128x128のuint16_t画像が読み取られ、数100Hzのレートで後処理されるカメラフレームグラバーです。
後処理では、2 ^ 16の要素を持つヒストグラムを生成しframe->histo
ますuint32_t
。thismaxval
基本的に、すべての強度値を集計します。このヒストグラムを使用して、合計と2乗合計を計算します。
double sum=0, sumsquared=0;
size_t thismaxval = 1 << 16;
for(size_t i = 0; i < thismaxval; i++) {
sum += (double)i * frame->histo[i];
sumsquared += (double)(i * i) * frame->histo[i];
}
プロファイルを使用してコードをプロファイリングすると、次のようになります(サンプル、パーセンテージ、コード)。
58228 32.1263 : sum += (double)i * frame->histo[i];
116760 64.4204 : sumsquared += (double)(i * i) * frame->histo[i];
または、最初の行がCPU時間の32%を占め、2番目の行が64%を占めます。
私はいくつかのベンチマークを行いましたが、問題があるのはデータ型/キャストのようです。コードをに変更すると
uint_fast64_t isum=0, isumsquared=0;
for(uint_fast32_t i = 0; i < thismaxval; i++) {
isum += i * frame->histo[i];
isumsquared += (i * i) * frame->histo[i];
}
実行速度は約10倍です。ただし、このパフォーマンスへの影響はプラットフォームによっても異なります。ワークステーションでは、Core i7 CPU 950@3.07GHzのコードは10倍高速です。Intel Core i7 Sandy Bridge 2.7 GHz(2620M)を搭載した私のMacbook8,1では、コードはわずか2倍高速です。
今私は疑問に思っています:
- 元のコードが非常に遅く、簡単に高速化されるのはなぜですか?
- なぜこれはプラットフォームごとに大きく異なるのですか?
アップデート:
私は上記のコードをでコンパイルしました
g++ -O3 -Wall cast_test.cc -o cast_test
Update2:
最適化されたコードをプロファイラー(Mac上のInstruments 、 Sharkなど)で実行したところ、次の2つが見つかりました。
1)ループ自体にかなりの時間がかかる場合があります。thismaxval
タイプsize_t
です。
for(size_t i = 0; i < thismaxval; i++)
総実行時間の17%を占めるfor(uint_fast32_t i = 0; i < thismaxval; i++)
3.5%かかりますfor(int i = 0; i < thismaxval; i++)
プロファイラーには表示されません。0.1%未満だと思います
2)データ型とキャストは次のように重要です。
sumsquared += (double)(i * i) * histo[i];
15%(ありsize_t i
)sumsquared += (double)(i * i) * histo[i];
36%(ありuint_fast32_t i
)isumsquared += (i * i) * histo[i];
13%(withuint_fast32_t i
、uint_fast64_t isumsquared
)isumsquared += (i * i) * histo[i];
11%(withint i
、uint_fast64_t isumsquared
)
驚いたことに、int
より速いですuint_fast32_t
か?
Update4:
1台のマシンで、さまざまなデータ型とさまざまなコンパイラを使用して、さらにいくつかのテストを実行しました。結果は以下のとおりです。
testd 0-2の場合、関連するコードは次のとおりです。
for(loop_t i = 0; i < thismaxval; i++)
sumsquared += (double)(i * i) * histo[i];
sumsquared
double、およびloop_t
size_t
、uint_fast32_t
を使用しint
、テスト0、1、および2の場合。
テスト3〜5の場合、コードは次のとおりです。
for(loop_t i = 0; i < thismaxval; i++)
isumsquared += (i * i) * histo[i];
isumsquared
タイプと再び、uint_fast64_t
そしてテスト3、4、5の場合。loop_t
size_t
uint_fast32_t
int
私が使用したコンパイラは、gcc 4.2.1、gcc 4.4.7、gcc 4.6.3、およびgcc4.7.0です。タイミングはコードの合計CPU時間のパーセンテージで表されるため、絶対的なパフォーマンスではなく、相対的なパフォーマンスを示します(ただし、実行時間は21秒で非常に一定でした)。プロファイラーが2行のコードを正しく分離したかどうかはよくわからないため、CPU時間は両方の2行です。
gcc:4.2.1 4.4.7 4.6.3 4.7.0 ---------------------------------- テスト0:21.85 25.15 22.05 21.85 テスト1:21.9 25.05 22 22 テスト2:26.35 25.1 21.95 19.2 テスト3:7.15 8.35 18.55 19.95 テスト4:11.1 8.45 7.35 7.1 テスト5:7.1 7.8 6.9 7.05
また:
これに基づくと、使用する整数型に関係なく、キャストにはコストがかかるようです。
また、gcc 4.6および4.7はループ3(size_tおよびuint_fast64_t)を適切に最適化できないようです。