16

最近、Herb Sutter は"Modern C++: What You Need to Know"について素晴らしい講演を行いました。この講演の主なテーマは、効率と、データの局所性とメモリへのアクセスがどのように重要かということでした。彼はまた、メモリ (配列/ベクトル) の線形アクセスが CPU によってどのように愛されるかについても説明しています。彼は、このトピックに関する別の古典的な参考文献「Bob Nystrom によるゲーム パフォーマンス」から 1 つの例を取り上げました。

これらの記事を読んだ後、プログラムのパフォーマンスに影響を与える 2 種類のキャッシュがあることがわかりました。

  1. データキャッシュ
  2. 命令キャッシュ

Cachegrindツールは、プログラムの両方のキャッシュ タイプ インストルメンテーション情報も測定します。最初のポイントは、多くの記事/ブログで説明されており、データキャッシュの効率 (データの局所性) を達成する方法です。

しかし、トピック命令キャッシュと、パフォーマンスを向上させるためにプログラムで注意すべきことについては、あまり情報が得られませんでした。私の理解によると、私たち(プログラマー)は、どの命令またはどの順序が実行されるかをあまり制御できません。

小さな C++ プログラムで、このカウンター (つまり、命令キャッシュ) が私たちのプログラムの書き方によってどのように変化するかを説明できれば、本当に素晴らしいことです。この点に関して、プログラマーがより良いパフォーマンスを達成するために従うべきベストプラクティスは何ですか?

私たちのプログラムが(ベクトルとリスト)を同じように行う場合、データキャッシュのトピックについて理解できることを意味し、2番目のポイントについて説明することができます。この質問の主な意図は、このトピックを可能な限り理解することです。

4

1 に答える 1

13

実行の流れを変更するコードは、命令キャッシュに影響を与えます。これには、関数呼び出しとループ、および関数ポインターの逆参照が含まれます。

分岐命令またはジャンプ命令が実行されると、プロセッサは、コードが既に命令キャッシュにあるかどうか、または (分岐先から) 命令キャッシュをリロードする必要があるかどうかを判断するために余分な時間を費やさなければなりません。

たとえば、一部のプロセッサには、小さなループの実行コードを保持するのに十分な大きさの命令キャッシュがある場合があります。一部のプロセッサには大きな命令キャッシュがなく、単純に再ロードされます。命令キャッシュのリロードには、命令の実行に費やされる可能性のある時間がかかります。

次のトピックを検索:

  • ループ展開
  • 条件付き命令実行 (ARM プロセッサで利用可能)
  • インライン関数
  • 命令パイプライン

編集 1: パフォーマンスを向上させるためのプログラミング手法 パフォーマンス
を向上させ、命令キャッシュのリロードを減らすには、次の手順を実行します。

"if" ステートメントを減らす "if" ステートメント を最小限に抑えるようにコードを設計します。これには、より多くの数学を使用するか、比較を単純化するブール代数が含まれる場合があります (本当に必要ですか?)。コンパイラが条件付きアセンブリ言語命令を使用できるように、"then" 句と "else" 句の内容を減らすことをお勧めします。

小さな関数をインラインまたはマクロとして定義する 関数
の呼び出しには、戻り位置の格納や命令キャッシュのリロードなどのオーバーヘッドが伴います。ステートメントの量が少ない関数については、インラインにすることをコンパイラーに提案してみてください。インライン化とは、関数呼び出しを行うのではなく、コードの内容を実行場所に貼り付けることを意味します。関数呼び出しが回避されるため、命令キャッシュをリロードする必要もありません。

ループのアンロール
小さな繰り返しの場合は、ループせずにループの内容を繰り返します (一部のコンパイラは、より高い最適化レベル設定でこれを行う場合があります)。繰り返されるコンテンツが多いほど、ループの先頭への分岐の数が少なくなり、命令キャッシュを再ロードする必要が少なくなります。

「if」ステートメントではなく、テーブル ルックアップを使用する
プログラムによっては、データを値にマッピングするために「if-else-if」ラダーを使用するものがあります。各「if」ステートメントは、命令キャッシュでの実行の中断です。場合によっては、ちょっとした計算で、値を配列のようなテーブルに配置し、インデックスを数学的に計算することができます。インデックスが分かれば、プロセッサは命令キャッシュを中断することなくデータを取得できます。

データまたはデータ構造の変更 データ
のタイプが一定である場合、プログラムはデータを中心に最適化できます。たとえば、メッセージ パケットを処理するプログラムは、パケット ID (関数ポインターの配列と考えてください) に基づいて操作を行うことができます。関数は、パケット処理用に最適化されます。

リンク リストを配列または他のランダム アクセス コンテナーに変更します。配列の要素には、割り込み実行ではなく、数学を使用してアクセスできます。アイテムを見つけるには、リンクされたリストをトラバース (ループ) する必要があります。

于 2014-04-07T19:39:31.543 に答える