1. ホーム
  2. c++

[解決済み] C++のクラスで仮想メソッドを持つことのパフォーマンスコストは?

2022-08-30 10:31:57

質問

C++のクラス(またはその親クラス)に少なくとも1つの仮想メソッドがあることは、そのクラスが仮想テーブルを持ち、すべてのインスタンスが仮想ポインタを持つことを意味します。

ですから、メモリ コストは非常に明確です。 最も重要なのはインスタンスのメモリ コストです (特にインスタンスが小さい場合、たとえば整数を含むだけの場合、この場合、すべてのインスタンスに仮想ポインタを持つと、インスタンスのサイズが 2 倍になる可能性があります)。 仮想テーブルによって使用されるメモリ領域については、実際のメソッドコードによって使用される領域と比較して、通常は無視できるものだと思います。

ここで私の疑問が生じます。メソッドを仮想化するための測定可能なパフォーマンス コスト (すなわち、速度への影響) はあるのでしょうか。 実行時に、すべてのメソッド呼び出し時に仮想テーブルを検索するので、このメソッドへの呼び出しが非常に頻繁で、このメソッドが非常に短い場合、測定可能なパフォーマンスのヒットがある可能性がありますか? プラットフォームに依存すると思いますが、どなたかベンチマークを実行されたことはありますか?

私が質問している理由は、プログラマーがメソッドの仮想定義を忘れたことによるバグに遭遇したことです。 この種のミスを見るのは初めてではありません。 そして、私は考えました:なぜ、私たちは を追加する必要があるのでしょうか。 の代わりに、必要なときに仮想キーワードを を削除します。 であることが確実な場合に、仮想キーワードを削除します。 ではなく は必要ないのでしょうか? もしパフォーマンスコストが低いのであれば、私のチームでは単純に以下のように推奨すると思います:単純に ごとに メソッドをデフォルトで仮想化し、デストラクタも含め、すべてのクラスで仮想化し、必要なときだけ削除することです。 それはあなたにとってクレイジーに聞こえますか?

どのように解決するのか?

I タイムを計測しました を 3ghz のインオーダーの PowerPC プロセッサで実行しました。そのアーキテクチャでは、仮想関数呼び出しは直接 (非仮想) 関数呼び出しよりも 7 ナノ秒長くかかります。

したがって、関数が些細な Get()/Set() アクセッサのようなものでない限り、コストについて心配する価値はあまりなく、インライン以外のものは無駄のようなものです。0.5ns にインライン化された関数の 7ns のオーバーヘッドは深刻ですが、実行に 500ms かかる関数の 7ns のオーバーヘッドは無意味なものです。

仮想関数の大きなコストは、vtable内の関数ポインタのルックアップ(これは通常1サイクル)ではなく、間接ジャンプが通常ブランチ予測できないことです。間接ジャンプ(関数ポインタを介した呼び出し)が終了し、新しい命令ポインタが計算されるまで、プロセッサは命令をフェッチできないため、大きなパイプラインバブルが発生する可能性があります。つまり、仮想関数呼び出しのコストは、アセンブリを見ただけではわからないほど大きいのです...しかし、それでもわずか7ナノ秒なのです。

編集してください。 Andrew, Not Sure, and others raise the very good point that a virtual function call may cause an instruction cache miss: if you jump to a code address that is not in cache, then the whole program comes to a dead halt while the instructions are fetched from main memory. これは 常に であり、Xenon では約 650 サイクル (私のテストによる) の大幅なストールです。

しかし、これは仮想関数に固有の問題ではありません。なぜなら、直接の関数呼び出しでさえ、キャッシュにない命令にジャンプするとミスが発生するからです。重要なのは、関数が最近実行されたかどうか (キャッシュにある可能性が高くなる)、そして、アーキテクチャが静的分岐 (仮想分岐ではない) を予測し、それらの命令を前もってキャッシュにフェッチできるかどうかということです。私の PPC はそうではありませんが、おそらく Intel の最新のハードウェアはそうでしょう。

私のタイミングは、実行におけるキャッシュミスの影響を制御し (私は CPU パイプラインを分離して調査しようとしていたので、意図的に)、そのコストを割り引いています。