ホームページ  >  記事  >  システムチュートリアル  >  x86 パイプライン レベルでのパフォーマンスの最適化

x86 パイプライン レベルでのパフォーマンスの最適化

WBOY
WBOY転載
2024-01-03 18:32:261148ブラウズ
###導入### 分岐に直面したときに正しい道を選択するにはどうすればよいですか?命令の選択が間違っている場合、パイプライン全体は残りの命令が実行されるまで待機し、それらの命令をクリアして、正しい位置から再度開始する必要があります。パイプラインのレベルが深くなるほど、引き起こされる被害も大きくなります。 ###序文### パフォーマンス最適化の鍵は、CPU に適切にサービスを提供することです。究極の性能を追求するプログラマーにとって、CPUの内部機構の理解は避けては通れないテーマです。これは、時間の経過とともに蓄積する必要がある継続的なプロセスですが、デジタル回路に深く入る必要はありません。CPU 設計の専門家が必ずしもソフトウェア設計に熟練している必要がないのと同じように、CPU の専門家である必要はありません。高レベルのソフトウェア、パフォーマンス ソフトウェアを作成するため。

人類の一部のエリートから一般大衆への貴重な贈り物として、市場で自由に購入できるCPUは、実は購入できない核兵器と同様に人類の最先端の技術レベルを表しています。 x86 CPU の専門家であっても、自分の専門分野についてしか詳しく話すことはできません。私たちにとって、すべてを理解することは不可能ですが、パイプライン、キャッシュ、命令セットという 3 つの部分が非常に重要です。この3つのパートのうち、実行のヒントとなるのが「組立ライン」です。したがって、前の記事の例に従って、まずパイプラインを見てみましょう。

基本コンセプト


PU の主な仕事は、指示に従ってデータの操作を実行することです。この文は基本的に組み立てラインとは何かを説明しています。この記事をクリックする人は「組立ライン」という概念について何も知らないと思いますが、冒頭に教科書のような分厚い文章を並べて、さまざまな概念の定義を列挙するつもりはありません。基本を徹底的に放棄し、劣ったものを追求します。テクノロジーの発展はまさに物事の矛盾の動きですが、今回はCPUの進化の歴史という観点からパイプラインの各構成要素を紹介していきたいと思います。

インテルが 40 年前に最初の 8086 プロセッサーを製造してから今日に至るまで、CPU の変遷により、以前のプロセッサーは「シングルチップ コンピューター」としか呼べないように感じられてきました。しかし、それが淘宝網で 1 個あたり数セントのシングルチップ マイクロコンピューターだとしても、今日の i7 プロセッサーとの類似点は依然としていくつかあります。 8086 プロセッサには、現在でも使用されている 14 個のレジスタがあります: 4 つの汎用レジスタ (General Purpose Register)、4 つのセグメント レジスタ (Segment Register)、4 つのインデックス レジスタ (Index Register)、および 1 つのフラグ レジスタ (EFLAGS Register) が使用されています。最後のレジスタである命令ポインタ レジスタは、次に実行する必要がある命令のアドレスを保存するために使用されます。この命令ポインタレジスタはパイプラインの動作過程に直接関係しており、その存在が継続することはパイプラインの基本原理の時間的一貫性を示すものでもある。

40年前から現在まで、CPUが実行する命令はすべて、命令ポインタをもとにコードセグメント内で実行する命令のアドレスを取得(フェッチ)し、デコードするというプロセスをたどっています。アドレスのアドレスを(デコード)命令します。デコード後、実際の実行 (Execute) フェーズに入り、その後に「ライトバック」フェーズが続き、処理の最終結果がメモリまたはレジスタに書き戻され、命令ポインタ レジスタが次のポイントに更新されます。次の指示へ。これは基本的に人間のロジックと完全に一致する設計ソリューションです。

最初は、そして最も自然なことですが、CPU はすべての命令を次々に処理します。以上の処理により各命令が実行され、次の命令が実行されます。当時の主な矛盾は、ソフトウェアのパフォーマンス要件の増大と CPU の処理速度の遅れとの間の矛盾でした。ムーアの法則の正しい指導の下、CPU 構築作業は歴史的な成果を達成し、主な矛盾は変化しました。CPU の実行速度がメモリの読み書き速度をゆっくりと超えました。そのため、毎回メモリから命令をフェッチするのは次第に耐え難くなったため、1982 年にプロセッサに命令キャッシュが導入されました。

CPU がますます高速になるにつれて、競合する当事者間の妥協策として、データ キャッシュもプロセッサに導入されています。しかし、これらは恒久的な解決策ではありません。矛盾の主な側面は、CPU が飽和状態で動作していないことです。そこで 1989 年に、i486 プロセッサは 5 ステージのパイプラインを積極的に導入しました。国内需要を刺激することで CPU の余剰能力を消化するという考えです。一度に 1 つの命令だけを処理するのではなく、一度に 5 つの命令を処理できるようになります。

x86 パイプライン レベルでのパフォーマンスの最適化x86 パイプライン レベルから、パフォーマンスを最適化する方法について話しましょう

あなたがどう思うか分かりませんが、私はいつもこの絵を理解するのに苦労します。簡単に理解するには、各指示を、5 つの処理ステップを含む組立ラインに流れ込む、処理される製品として想像してください。これにより、CPU の各プロセスが常に飽和したワークロードを維持できるようになり、命令のスループットとプログラムのパフォーマンスが根本的に向上します。 パイプラインによってもたらされる問題

コードの各行が単に XOR 命令に抽象化されている場合、上記の i486 パイプライン図によれば、最初の命令がパイプラインのフェッチ ステージに入り、次に D1 ステージに入り、その時点で 2 番目の命令がフェッチに入ります。 。次のマシン サイクルでは、最初の命令が D2 に入り、2 番目の命令が D1 に入り、3 番目の命令がフェッチされます。ここまではすべて正常ですが、次のマシン サイクルで最初の命令が実行ステージに入ると、2 番目の命令は引き続き次のステージに進むことができません。これは、必要な変数 a の最終結果が最初の命令になければならないためです。命令の実行後に取得されます。したがって、2 番目の命令はパイプライン上でブロックされ、最初の命令が完了するまで続行されません。 2 番目の命令の実行中に、3 番目の命令でも同様の現象が発生します。パイプラインのブロッキングが発生すると、パイプラインでの命令の実行が個々の実行から分離され、これをパイプラインの「バブル」と呼びます。

クロックサイクル: 発振サイクルとも呼ばれます。これは、クロック周波数 (メイン周波数) と最小期間の逆数です。 マシン サイクル: パイプラインの各ステージは基本操作と呼ばれ、基本操作を完了するのに必要な時間はマシン サイクルです。 命令サイクル: 命令の実行に必要な時間。通常は複数のマシン サイクルで構成されます

上記の状況に加えて、気泡の発生には別の一般的な理由があります。各命令の実行に必要な時間(命令サイクル)は異なります。単純な命令の前に時間がかかる複雑な命令がある場合、単純な命令は複雑な命令を待つ必要があります。また、プログラム中にifのような分岐があった場合はどうなるでしょうか?このような状況では、パイプラインがフル稼働できなくなり、パフォーマンスが相対的に低下します。

問題に直面すると、人は常に、問題を解決するためにより複雑なメカニズムを導入する傾向があります。多段階の組立ラインがその一例です。複雑さは技術の進歩を反映している可能性がありますが、「複雑さ」自体は新たな問題です。だからこそ矛盾はなくならず、テクノロジーの進歩は止まらないのかもしれない。しかし、「学べば学ぶほど、タオにとって失うものは大きくなります。」 ますます複雑化するメカニズムは、特定の機会に必ず大きなブレークスルーをもたらしますが、おそらくその時はまだ来ていません。 「バブル」問題に直面して、プロセッサはより複雑な解決策を導入しました。インテルが 1995 年に Pentium Pro プロセッサをリリースしたとき、アウトオブオーダー コア (OOO コア) が追加されました。

アウトオブオーダー実行コア (OOO コア)

実際、アウトオブオーダー実行の考え方は非常にシンプルです。次の命令がブロックされたら、次の命令から別の実行可能な命令を見つけるだけです。しかし、これを実現するのは非常に複雑です。まず、プログラムの最終結果が逐次実行と一致していることを確認する必要があり、同時にさまざまなデータの依存関係を特定する必要があります。望ましい効果を達成するには、並列実行に加えて、厚みを使用せずに望ましい効果を達成するために命令の粒度をさらに洗練する必要があります。このようにして、「マイクロオペレーション」(マイクロオペレーション) )のコンセプトを導入。パイプラインのデコード ステージでは、アセンブリ命令がさらに分解され、最終生成物は一連のマイクロ操作になります。

アウトオブオーダー処理コア導入後の命令μ-ops処理フロー。最初の図では、異なる色のモジュールが、異なる色のパイプライン処理ステージに対応しています。

フェッチ ステージには多くの変更はありませんが、デコード ステージでは 4 つの命令を並行してデコードでき、デコードの最終生成物は前述の μ-ops です。次の Register Alias Table と Reorder Buffer は、アウトオブオーダー実行コアの前処理段階とみなすことができます。

並行して実行されるマイクロ操作、または順不同で実行される操作の場合、同じレジスタが同時に読み書きされる可能性が非常に高くなります。したがって、プロセッサ内では、元のレジスタはソフトウェア エンジニアには見えない内部レジスタとして「エイリアス化」され、読み書きがそれぞれのレジスタに干渉することなく、元は同じレジスタ上で実行されていた操作を一時的に異なるレジスタ上で実行できるようになります。 other (注: これには、2 つの操作にデータの依存関係がないことが必要です)。対応するマイクロ操作のオペランドも一時的なエイリアス レジスターに変更されており、これは空間対時間戦略と同等であり、同時にマイクロ命令はエイリアス レジスターに基づいて変換されます。

次に、マイクロオペレーションがリオーダーバッファに入ります。この時点で、マイクロ命令の準備が整いました。これらはリザベーション ステーション (RS) に入れられ、並行して実行されます。この図から、かなりの数の実行ユニット (ポート X) が確認できます。各実行ユニットは、読み取り (ロード)、書き込み (ストア)、整数計算 (ALU、SEE) などの特定のタスクを実行します。関連する各マイクロ命令は、必要なデータの準備ができた後に実行できます。このような時間のかかる命令やデータ依存関係のある命令は、それ自体の観点からは何の変化もありませんが、それらがもたらすブロッキング オーバーヘッドは、後続の命令の並列性と順不同 (進み) によって相殺されます。全体的なスループットが向上します。

アウトオブオーダー実行コアの魅力は、このメカニズムの効率を最大限に高めることができ、外部から見ると命令が順番に実行されることです。詳細については、この記事の範囲を超えています。しかし、アウトオブオーダー実行コアは非常に成功しているため、ワークロードが大きい場合でも、このメカニズムを導入した CPU のアウトオブオーダー実行コアはほとんどの時間アイドル状態であり、飽和にはほど遠い状態です。そこで、コアにμ-opsを届けるために別のフロントエンド(FetchやDecodeを含むFront-end)が導入され、システムの観点から見ると、これを2つの処理コアに抽象化できるのがハイパースレッドです。 N 個の物理コアと 2N 個の論理コア。

アウトオブオーダー実行では、シーケンシャルコード実行の効果が 100% 得られるとは限りません。場合によっては、プログラマは実行順序を保証するためにメモリ バリアを導入する必要があります。

しかし、複雑なものは常に新しい問題を引き起こし、今回は競合がフェッチ段階に移されました。枝に直面したときに正しい道を選択するにはどうすればよいでしょうか?命令の選択が間違っている場合、パイプライン全体は残りの命令が実行されるまで待機し、それらの命令をクリアして、正しい位置から再度開始する必要があります。パイプラインのレベルが深くなるほど、引き起こされる被害も大きくなります。後続の記事では、プログラミング レベルでの最適化方法をいくつか紹介します。
著者について###

Zhang Pan は雲山のネットワーク エンジニアで、x86 ネットワーク ソフトウェアの開発とパフォーマンスの最適化に注力しています。ONF/OPNFV/ONOS やその他の組織やコミュニティに深く関わっています。かつては ONF テスト作業の副会長を務めていました。グループ。

以上がx86 パイプライン レベルでのパフォーマンスの最適化の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はlinuxprobe.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。