この for ループの最初の 2 行をコメント アウトし、3 番目のコメントを解除すると、42% 高速化されるのはなぜですか?
int count = 0;
for (uint i = 0; i < 1000000000; ++i) {
var isMultipleOf16 = i % 16 == 0;
count += isMultipleOf16 ? 1 : 0;
//count += i % 16 == 0 ? 1 : 0;
}
タイミングの背後には、大幅に異なるアセンブリ コードがあります。ループ内の命令は 13 対 7 です。プラットフォームは、.NET 4.0 x64 を実行する Windows 7 です。コードの最適化が有効になっており、テスト アプリが VS2010 の外部で実行されました。[更新: Repro project、プロジェクト設定の検証に役立ちます。]
中間ブール値を排除することは基本的な最適化であり、私の 1980 年代のDragon Bookで最も単純なものの 1 つです。CIL の生成時または x64 マシン コードの JIT 時に最適化が適用されなかったのはなぜですか?
「本当にコンパイラ、このコードを最適化してください」スイッチはありますか? 時期尚早の最適化はお金への愛情に似ているという意見には同情しますが、ルーチン全体にこのような問題が散在する複雑なアルゴリズムをプロファイリングしようとすると、フラストレーションがたまることがわかりました。ホットスポットを処理することはできますが、通常はコンパイラーから当然と思われていることを手動で微調整することで大幅に改善できる、より広いウォーム領域のヒントはありません。ここで何かが欠けていることを願っています。
更新:速度の違いは x86 でも発生しますが、メソッドがジャストインタイムでコンパイルされる順序によって異なります。JIT オーダーがパフォーマンスに影響する理由を参照してください。
アセンブリ コード(要求に応じて):
var isMultipleOf16 = i % 16 == 0;
00000037 mov eax,edx
00000039 and eax,0Fh
0000003c xor ecx,ecx
0000003e test eax,eax
00000040 sete cl
count += isMultipleOf16 ? 1 : 0;
00000043 movzx eax,cl
00000046 test eax,eax
00000048 jne 0000000000000050
0000004a xor eax,eax
0000004c jmp 0000000000000055
0000004e xchg ax,ax
00000050 mov eax,1
00000055 lea r8d,[rbx+rax]
count += i % 16 == 0 ? 1 : 0;
00000037 mov eax,ecx
00000039 and eax,0Fh
0000003c je 0000000000000042
0000003e xor eax,eax
00000040 jmp 0000000000000047
00000042 mov eax,1
00000047 lea edx,[rbx+rax]