24

C++ のパフォーマンスを深く理解するのに役立つリソース (理想的には本) を探しています。ここにもう少し背景があります:

私は、非常に高いスループット要件や低レイテンシ要件を持つサーバー ソフトウェアを作成しています。私たちは C++ で書きます。現時点では議論の余地はありません。私の同僚のほとんどは、C++ のパフォーマンスをよりよく理解しているようです。彼らはより優れたメンタル モデルを持っているため、特定のコードが大規模に実行されたときにパフォーマンスが低下する時期を知ることができます。私はこの理解に欠けているので、自分のメンタル モデルを改善しようとしています。

私は特に興味があります:

  • キャッシュの影響と、オブジェクトのレイアウトによるキャッシュの局所性がコードのパフォーマンスに与える影響について理解する。これは、私のチームの他のメンバーによって提起されたように見える一番の問題です。
  • メモリ割り当てがパフォーマンスにどのように影響するかを理解する。TCMalloc (または他の malloc) を使用する必要がありますか? また、どのように知る必要がありますか? さまざまな割り当ておよび割り当て解除パラメーターをどのように調整すればよいですか?
  • オブジェクトのコピーによるオーバーヘッドが問題になる時期をどのように知ることができますか (したがって、たとえば、ポインターに切り替える必要があります)。
  • また、いつ使用するかについての知識がある限り、一般的に「最適化」にも興味があります。

あまり興味のないこと:

  • 「ハイ パフォーマンス コンピューティング」は、より数学/シミュレーション指向のアプリケーションを示すように思われる用語です。
  • 私は C++ に行き詰まっているので、他の言語と比較した C++ のパフォーマンスの議論。

出発点として、この本Efficient C++がこの法案に適合するかどうか知っている人はいますか?

4

4 に答える 4

30

私の推奨事項をいくつかのセクションに分割させてください。

C++ の最適化

出発点として、Agner Fog のOptimizing software in C++を強くお勧めします。このマニュアルは、一般的な C++ 最適化トピックの優れた概要を提供します。

ハードウェアの一般的な理解

C++ パフォーマンスの優れたメンタル モデルを得るには、基盤となるハードウェアについても理解する必要があります。次のステートメントを検討してください。

a[7] = 5;

C++ 言語側では、コード行はパフォーマンスの観点から退屈です: メモリへの書き込みは 1 回だけです。しかし、実際のハードウェアでは、そのメモリ書き込みのパフォーマンスは桁違いに異なる場合があります。そのレベルで何が起こっているかを理解するには、キャッシュ、プロセッサ パイプライン、TLB、分岐予測などの概念について学ぶ必要があります。

プロセッサ キャッシュの簡単な紹介として、プロセッサ キャッシュ効果のギャラリーの記事をお勧めします。キャッシュとコンピュータ メモリに関するより深く長い (100 ページを超える) 議論は、What Every Programmer Should Know About Memoryです。

最新のコンピューター ハードウェアを全体的に理解するには、Computer Architecture: A Quantitative Approach が一般的に推奨される本です。私は自分で本を読んだのではなく、ブログを読んだり実験したりして学びました。しかし、明らかにこの本が非常に有用であることに気付いた人もいます。

特定のプロセッサについて

最適化スキルを向上させるための旅のある時点で、さまざまなプロセッサの詳細を認識することが役立つことがわかります。多くの例の 1 つとして、異なる Intel プロセッサと AMD プロセッサでは、_mm_storeu_ps C++ 組み込み関数などのアライメントされていない SSE 命令を使用すると、非常に異なるペナルティがあります。

さまざまなプロセッサの詳細を学ぶには、Intel、AMD、および VIA CPU のマイクロアーキテクチャ: アセンブリ プログラマおよびコンパイラ メーカー向けの最適化ガイドをお勧めします。実際、 Agner Fogのすべての最適化マニュアルをお勧めします。また、ハードウェア ベンダーは、特定のハードウェアに関するドキュメントを提供しています。

ツールの使い方を学ぶ

C++ とハードウェア パフォーマンスの優れたメンタル モデルを持つことは、コードを最適化するときに非常に役立ちます。しかし、適切なツールの使い方を学ぶことは、少なくとも同じくらい役に立ちます。おそらく、最適化のための最良のアドバイスは「最初に測定することです!」です。単純なコード ブロックであっても、考えただけでパフォーマンスを理解することは非常に困難です。コードを実行し、さまざまな方法で測定することで、多くの情報を得ることができます。

これらは、一般的な有用な測定の一部です。

  • タイミング: コードを実行して時間を測定するだけ
  • サンプリング プロファイラー
  • インストルメンテーション プロファイラ
  • プロセッサ カウンタ

私は間違いなくあなたの元の質問の範囲から外れているので、特定のツールの推奨事項には入りません。また、ツールはそれ自体が大きなトピックです。ツールは、ハードウェア プラットフォーム、ソフトウェア プラットフォーム、およびコストによって異なります (無料のものもあれば、高価なものもあります)。

ただし、C++ コードを最適化するには、適切なツールを知って使用する必要があることに注意する必要があります。

于 2012-09-10T18:50:38.367 に答える
11

Valgrind を最初のツールにする必要があります。

Valgrind には多くのツールがありますが、cachegrind は、アルゴリズムが適切なデータ局所性を持っているかどうかを確認する優れた方法です。これにより、メモリのボトルネックが特定されます。Callgrind は、処理のボトルネックを特定するのに役立つもう 1 つの valgrind モジュールです。

参考文献:

Cachegrind: http://valgrind.org/docs/manual/cg-manual.html

Callgrind: http://valgrind.org/docs/manual/cl-manual.html

于 2012-09-10T17:24:38.217 に答える
1

以前の回答は、最も重要な考えを示しました。

1 つだけ警告があります。プロファイリング (valgrind) を実行してください。その後、キャッシュの最適化を試みたり、SSE を調べたり… (少なくとも最初のうちは) 改善がほとんどないため、さらに多くの努力が必要になります。

また、C++ は巨大な言語であり、コンパイラは魔法のように機能します。テンプレート、インライン化などにより、コンパイラは、C などの他の言語では不可能な優れた最適化を行うことができます。したがって、低レベルのデータ構造の使用を検討するときは十分に注意してください。その結果、パフォーマンスが低下する可能性があります (さらにバグが増え、メモリ管理の問題が増えます)。

STL と BOOST を使用すると、おそらくいくつかの間違いを回避するのに役立ちます。

于 2012-09-10T19:26:03.017 に答える
1

そのレベルで何が起こっているかを理解するには、キャッシュ、プロセッサ パイプライン、TLB、分岐予測などの概念について学ぶ必要があります。

これらについて、非常にカジュアルな方法でさらに議論したいと思います。

  1. キャッシュ - 基本的に、作業セットをキャッシュ内に収めることができれば、アプリケーションの速度が大幅に向上します。
  2. 分岐 - 分岐はメモリ読み取りでブロックを必要とするため、非常に長い時間がかかります。たとえば、不要な書き込みを行う場合x=1よりも高速になる可能性があります。if (needWrite) x=1;
  3. 分岐予測 - 前述の理由により、CPU はパターン マッチング アルゴリズムを使用して、分岐の結果が何であるかを「推測」しようとします。この簡単な推測を行うと、速度が向上します。
  4. プロセッサ パイプライン、命令レベルの並列処理、スーパースカラー、レジスタの名前変更などに関しては、ほとんどの場合、コンパイラで最適化する必要があると思います。
于 2012-09-10T21:11:52.100 に答える