このクラスのベンチマーク:
struct Sieve {
std::vector<bool> isPrime;
Sieve (int n = 1) {
isPrime.assign (n+1, true);
isPrime[0] = isPrime[1] = false;
for (int i = 2; i <= (int)sqrt((double)n); ++i)
if (isPrime[i])
for (int j = i*i; j <= n; j += i)
isPrime[j] = false;
}
};
多数のコンストラクターを呼び出すと、64 ビット バイナリーと 32 ビット バージョン (リリース ビルド) でパフォーマンス (CPU 時間) が 3 倍以上悪くなります。
Sieve s(100000000);
テストsizeof(bool)
しましたが1
、両方のバージョンに対応しています。64ビット版と32ビット版で代用vector<bool>
すると性能は同じになります。vector<char>
何故ですか?
S(100000000)
(リリース モード、最初は 32 ビット、2 番目は 64 ビット))の実行時間は次のとおりです。
vector<bool>
0.97秒
vector<char>
3.12秒 0.99秒 0.99秒 1.57秒
vector<int>
1.59秒
また、VS2010 (Wouter Huysentruit の応答によって促された) でサニティ テストを行ったところ、0.98 秒 0.88 秒が生成されました。したがって、VS2012 の実装には問題があります。
Microsoft Connectにバグ レポートを送信しました
編集
int
以下の多くの回答は、インデックス作成に使用することの欠陥についてコメントしています。これは事実かもしれませんが、偉大な魔法使い自身でさえfor (int i = 0; i < v.size(); ++i)
彼の著書で標準を使用しているため、そのようなパターンによってパフォーマンスが大幅に低下することはありません。さらに、この問題は、Going Native 2013 カンファレンスで提起され、C++ 専門家の主宰グループはsize_t
、インデックス作成および戻り値の型として使用するという初期の推奨事項についてsize()
、誤りとしてコメントしました。彼らは言った:「ごめんなさい、私たちは若かった...」
この質問のタイトルは次のように言い換えることができます: VS2010 から VS2012 にアップグレードすると、このコードのパフォーマンスが 3 倍以上低下します。
編集
インデックスのメモリ アライメントを見つけようと大雑把な試みを行ったi
ところj
、このインストルメント化されたバージョンであることがわかりました。
struct Sieve {
vector<bool> isPrime;
Sieve (int n = 1) {
isPrime.assign (n+1, true);
isPrime[0] = isPrime[1] = false;
for (int i = 2; i <= sqrt((double)n); ++i) {
if (i == 17) cout << ((int)&i)%16 << endl;
if (isPrime[i])
for (int j = i*i; j <= n; j += i) {
if (j == 4) cout << ((int)&j)%16 << endl;
isPrime[j] = false;
}
}
}
};
自動的に魔法のように高速に実行されるようになりました (32 ビット バージョンよりわずか 10% 遅くなります)。int
このことと VS2010 のパフォーマンスにより、オプティマイザーが .NETではなくインデックスを処理する固有の問題を抱えているという理論を受け入れるのが難しくなりますsize_t
。