免責事項: 今日まで、ルーフライン パフォーマンス モデルについて聞いたことがありません。私が知る限り、アルゴリズムの「算術強度」の理論的限界を計算しようとします。これは、アクセスされたデータのバイトあたりの FLOPS の数です。このような尺度は、 のサイズが大きくなるにつれて同様のアルゴリズムを比較するのN
に役立ちますが、実際のパフォーマンスを予測するのにはあまり役立ちません。
一般的な経験則として、最新のプロセッサは、データをフェッチ/保存するよりもはるかに高速に命令を実行できます (データがキャッシュのサイズよりも大きくなり始めると、これは劇的に顕著になります)。したがって、予想に反して、演算強度の高いループは、演算強度の低いループよりもはるかに高速に実行される場合があります。スケーリングの際に最も重要なN
のは、アクセスされるデータの総量です (これは、現在の一般的なデスクトップ システムやサーバー システムに当てはまるように、メモリがプロセッサよりも大幅に低速である限り当てはまります)。
要するに、x86 CPU は残念ながら複雑すぎて、このような単純なモデルで正確に説明することはできません。メモリへのアクセスは、RAM にアクセスする前に、キャッシングのいくつかのレイヤー (通常は L1、L2、および L3) を通過します。すべてのデータが L1 に収まる可能性があります。ループを 2 回目に実行すると、RAM アクセスがまったくない可能性があります。
データキャッシュだけではありません。コードもメモリ内にあり、命令キャッシュにロードする必要があることを忘れないでください。各読み取り/書き込みは、ハードウェア TLB によってサポートされている仮想アドレスとの間でも行われます (極端な場合、ページ フォールトがトリガーされ、OS がループの途中でディスクにページを書き込む可能性があります)。 )。これはすべて、プログラムがハードウェアをすべて独り占めしていることを前提としています (非リアルタイム OS では、他のプロセスとスレッドが同じ限られたリソースを求めて競合しているため、これは当てはまりません)。
最後に、実行自体はメモリの読み書きで (直接) 行われるのではなく、データが最初にレジスタにロードされます (その後、結果が格納されます)。
コンパイラーがレジスターを割り当てる方法、ループ展開、自動ベクトル化、命令スケジューリング モデル (命令間のデータ依存を避けるためのインターリーブ命令) などもすべて、アルゴリズムの実際のスループットに影響します。
最後に、生成されるコード、CPU モデル、処理されるデータ量、およびさまざまなキャッシュの状態に応じて、アルゴリズムのレイテンシは桁違いに異なります。したがって、他の多くの (非線形) 要因が関係しているため、コード (または生成されたアセンブリ) だけを検査しても、ループの動作強度を判断することはできません。
ただし、実際の質問に対処するために、ここで概説した定義からわかる限り、2 番目のループは反復ごとに平均して 1 回の追加の 4 バイト アクセスとしてカウントされるため、その OI は θ(3N FLOPS / 4N バイト)。直観的には、キャッシュには既にデータがロードされており、メイン メモリに戻る代わりに書き込みによってキャッシュを直接変更できるため、これは理にかなっています (ただし、データは最終的に書き戻す必要がありますが、その要件は最初から変更されていません)。ループ)。