banner
Alex Wu

Alex Wu

college student in CS | web3 | Gopher | lifelong grower | cat lover https://wureny.xyz/
github
x
email

cpu性能提高术

概要#

CPU の性能は、レスポンスタイムとスループットの 2 つの指標で評価されます。

この記事では、以下のポイントに重点を置いて説明します。

  1. パイプライン技術
  2. パイプライン技術で遭遇する 3 つのハザードのうまい利用
  3. アウトオブオーダー実行
  4. スーパースカラ技術によるスループットの向上

パイプライン技術#

CPU の命令の実行は、次の 3 つのステップに簡単に分割できます。

  1. 命令のフェッチ
  2. 命令のデコード
  3. 命令の実行

命令のフェッチには、クロック信号によって PC レジスタをインクリメントする必要があるため、1 つの命令の完了には少なくとも 1 つのクロックサイクルが必要です。

最初の設計では、最高のパフォーマンスを実現したいので、1 つのクロックサイクル内で 1 つの命令の処理を完了する必要があります。各命令の複雑さは異なるため、クロックサイクルの長さは最も時間のかかる命令の実行時間に達する必要があります。

この設計の欠点は明らかです:非常に時間とリソースの浪費です。

実行する命令の複雑さに関係なく、次の命令を実行するためには、完全なクロックサイクルを待たなければなりません。この間、CPU の多くのリソース(例:ALU)が長時間アイドル状態になる可能性があり、リソースの浪費が発生します。

したがって、CPU は、命令の実行時に時間と CPU ハードウェアリソースの浪費をできるだけ避けるための技術が必要です。

現代の CPU は、この問題を解決するためにパイプライン技術を使用することが一般的です。

単純に言えば、パイプラインは、複数の命令の重複実行を実現するプロセスです。タスクをいくつかのステップに分割し、1 つのパイプラインが 1 つの命令の各ステップを処理できるようにします。同じ時点で、1 つのタスクは 1 つのステップにのみ存在し、最初のタスクがパイプラインに入り、ステップ 1 からステップ 2 に到達すると、パイプラインのステップ 1 の処理が空きます。 2 番目のタスクがステップ 1 に入り、最初のタスクが完全に終了するのを待つ必要はありません。

具体的な命令のパイプライン化には、パイプライン段階数、つまり前述のステップ数を定義する必要があります。

異なる CPU には異なる段階数があります。一部はパフォーマンスに敏感で、非常に細かく分割されており、10 以上の段階があります。他のものは数段階しかありません。

ARMv8 のサブセットである LEGv8 を例にとると、5 つの処理ステップに分割されます。

  1. 命令レジスタから命令を取得する
  2. レジスタを読み取り、アドレスデコーダを介してデコードする
  3. 命令を実行する
  4. メモリの読み書き
  5. レジスタに書き戻す

各パイプライン段階の操作は、1 つのクロックサイクルを占有し、1 つの命令にはパイプライン段階数のクロックサイクルが必要です。

クロックサイクルの長さは、1 つの命令の実行時間を達成する必要はなくなります。最も複雑なパイプライン段階の操作の長さに達する必要があります。

同時に、パイプライン段階数も多すぎるわけにはいかないため、パイプラインの深さを増やすことにはコストがかかります。

各パイプライン段階の出力は、追加のパイプラインレジスタに保存する必要があります。パイプラインレジスタの読み書き速度は非常に速いですが、段階数が増えると、例えば 30〜40 段階に達すると、応答時間が低下し、消費電力が増加します。

パイプラインの 3 つのハザード#

パイプラインでは、次のクロックサイクルで次の命令を実行できない場合があります。これをハザード(hazard)と呼びます。

ハザードは、問題に対処することで CPU のスループットを向上させることができます。

パイプライン技術では、次の 3 つのハザードに遭遇することがあります:構造ハザード、データハザード、制御ハザード。

構造ハザード#

構造ハザードの本質は、ハードウェアリソースが不足しているためにリソース競合が発生する問題です。

パイプラインでは、異なるステージにある 2 つの命令が同じ回路リソースを必要とする場合、そしてその回路リソースがちょうど 1 つしかない場合、構造ハザードが発生し、命令の正常な実行が妨げられます。

前述の 5 つのステップを例に挙げると、2 番目のステップと 4 番目のステップの両方がアドレスデコーダを使用する必要があります。アドレスデコーダが 1 つしかないため、命令のアドレスとデータのアドレスの間でリソース競合が発生します。

解決策は 2 つあります。

1 つはメモリを 2 つの部分に分割し、1 つはデータを、もう 1 つは命令を格納し、それぞれが独自のデコーダを持つことです。明らかな欠点は、メモリが 2 分割されているため、動的な割り当てができないことです。

もう 1 つは、CPU 内部の高速キャッシュを命令キャッシュとデータキャッシュの 2 つに分割することです。これにより、構造ハザードのリソース競合の問題が解決され、メモリの動的な割り当ても妨げられません。前者の設計はハーバードアーキテクチャと呼ばれ、後者の設計は現代のフォン・ノイマンアーキテクチャで採用されています。

データハザード#

データハザードは、1 つのステップが完了するまで他のステップが待たなければならない(つまり、データ依存性が存在する)場合に発生し、パイプラインが停止することを意味します。

以下のコードを例に挙げます。

a :=1
b :=2
a = a+1
b = a+1

変数 b の最終値は、変数 a が add 1 を実行した後の結果に依存し、この順序を保証する必要があります。

最も単純な解決策は、パイプラインバブルを使用することです。つまり、デコードが完了した後、その命令がデータ依存性を持つかどうかをチェックし、データ依存性が存在する場合は、NOP 操作(何もしないことを表す)を挿入してパイプラインを停止し、データ依存性の問題が解決されるまで待機します(パイプラインはクロック信号によって動作するため、実際には停止することはありませんが、この NOP 操作に依存します)。この方法は、CPU のパフォーマンスにかなりのコストがかかります。

より高度な戦略は、オペランドフォワーディングまたはオペランドバイパスと呼ばれるものです。

次の 2 つの命令を例に挙げます。

add $t0, $s2,$s1
add $s2, $s1,$t0

2 番目の命令の実行は、t0 の値に依存しています。以前のパイプラインバブル戦略に従うと、最初の命令の実行結果が t0 に書き込まれるのを待たなければなりません。しかし、実際には、2 番目の命令は s2 + s1 の結果を t0 の入力として直接受け取ることができます。回路にいくつかのワイヤを追加するだけで実現できます。これがオペランドフォワーディングの具体的な表現であり、追加されたワイヤはバイパスと呼ばれます。

オペランドフォワーディングにより、NOP の数を効果的に減らすことができ、パイプラインの効率をさらに向上させることができます。

制御ハザード#

高度なプログラムでは、for ループや if ステートメントがアセンブリコードに変換されると、比較命令(cmp)やジャンプ命令(jmp)などが生成されます。次の命令が PC レジスタの値なのか、jmp に対応するアドレスなのかを CPU は cmp 命令の実行が完了するまで待たなければなりません。他の命令が実行中である場合に制御ハザードが発生します。

パイプラインの停止を防ぐためには、cmp の結果が出る前に予測を行う必要があります。これが分岐予測技術です。

分岐予測技術にはさまざまな種類がありますが、最も単純なものは静的分岐予測です。CPU はジャンプが発生しないと判断し、常に順番に実行します。予測が誤っている場合、後続の命令を破棄する必要があり、この破棄操作には一定のパフォーマンスのコストがかかります。

より高度な戦略は動的予測です。一般的な動的予測手法の 1 つは、1 ビットの飽和カウンタを使用した 1 レベルの分岐予測です。実質的には、現在の分岐の比較結果を記録するために 1 ビットを使用し、次の分岐の予測に使用します。たとえば、今回ジャンプが発生した場合、次回もジャンプすると予測します。それ以外の場合は、順番に実行を続けます。2 ビットの飽和カウンタと呼ばれるもう 1 つの手法もあり、ステートマシンを導入し、次の分岐の予測が前の 2 つの結果に依存するようにします。分岐予測に関する詳細な情報は、ウィキペディアを参照してください。

アウトオブオーダー実行#

前述のオペランドフォワーディングにより、不要な NOP 操作を大幅に減らすことができますが、いくつかの場合では、NOP は避けられません。スループットをさらに向上させるために、CPU は NOP の段階で依存関係のない実行できる命令を実行することができます。これがアウトオブオーダー実行と呼ばれる技術です。

以下はプロセス図です:

cpu アウトオブオーダー実行.png

リザベーションステーションでは、命令が依存するデータが到着するのを待ってから、FU に送信して実行することができます。この段階がアウトオブオーダー実行です。

FU は ALU ですが、異なる ALU には異なる機能があるため、アウトオブオーダー実行段階ではこれを最大限活用する必要があります。

実行が完了したら、リオーダーバッファに入れて元の命令の順序に並べます。

次に、命令の計算結果はメモリバッファに送信され、最後に CPU のキャッシュまたはメモリに書き込まれます。

メモリアクセスと書き込みの段階では、順序通りである必要があります。これは、マルチコアによるデータの不整合を防ぐためです。各 CPU コアには独自のキャッシュとレジスタがあり、書き込みの順序が異なる場合、予期しないエラーが発生する可能性があります。

このプロセスでは、外部から見ると順序通りですが、内部の各 FU はアイドル状態になることはありません。CPU のスループットがさらに向上します。

スーパースカラ技術#

前述のさまざまな CPU パフォーマンス向上技術をすべて使用しても、IPC(1 つのクロックサイクルで実行できる命令数)は 1 を超えることはありません。なぜなら、CPU は 1 つのクロックサイクルで 1 つの命令しか取得できないからです。

命令の実行段階が並列化できるようになったのであれば、命令のフェッチとデコードも並列化できるはずです。つまり、複数の命令を一度にメモリから取得し、複数の命令デコーダに送ってデコードすることが考えられます。

この技術はマルチエミットとスーパースカラと呼ばれます。

cpu スーパースカラ.png

現代の CPU は、この技術を採用しており、IPC は通常 2 以上になります。

結論#

この記事の目的は、CPU のパフォーマンス向上の一般的な技術を紹介することです。

記事は、パイプラインの紹介から始まり、パイプラインの 3 つのハザードに触れ、キャッシュの分割、パイプラインバブル、オペランドフォワーディング、分岐予測などの内容を含みます。さらに、アウトオブオーダー実行とスーパースカラ技術についても説明し、リソースの最大限の活用による CPU のスループットの向上を実現します。

これらの内容を理解することで、現代の CPU のパフォーマンス向上について広い視野を持つことができます。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。