元ネタ: unnonouno: 動的型情報で仮想関数呼び出しを速くできるか

Javaだと実行時の情報を使って更なる最適化ができるという話が途中にありますが、同じようなことはC++でもできます。元の記事のようにインライン展開したコードを手書きしてやる必要はありません。

というわけで、Visual C++ 2010のProfile-Guided Optimization (PGO)でいってみましょう。

元のコードを再掲します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Parent {
 public:
  virtual ~Parent() {}
  virtual void fun() = 0;
};
 
class Child : public Parent {
 public:
  void fun() {}
};
 
int main() {
  Parent* c = new Child();
  for (int i = 0; i < 1000000000; ++i)
    c->fun();
}

これをPGOのインストルメントモード(/LTCG:PGINSTRUMENT)でビルド、プロファイルを取るために何回か実行、そして、プロファイル結果を反映させての最適化ビルド(/LTCG:PGOPTIMIZE)を行いました。

その結果、通常のリリースビルド(/O2 /Oi, /LTCG)では2.37~2.38秒ほどだったところ、0.82~0.83秒になりました(Cygwin bashのtimeで計測)。

Visual Studioのデバッガでステップ実行して、逆アセンブルの結果を見てみます。PGO最適化後はこんなコードが生成されていました。

    Parent* c = new Child();
00311012  push        4
00311014  call        dword ptr [__imp_operator new (3120A4h)]
0031101A  add         esp,4
0031101D  test        eax,eax
0031101F  je          main+38h (311048h)
00311021  mov         dword ptr [eax],offset Child::`vftable' (31210Ch)
00311027  mov         esi,eax

    {
        for (int i = 0; i < 1000000000; ++i)
00311029  mov         edi,3B9ACA00h
0031102E  mov         edi,edi
            c->fun();
00311030  mov         eax,dword ptr [esi]
00311032  mov         eax,dword ptr [eax+4]
00311035  cmp         eax,offset Child::fun (311000h)
0031103A  jne         __controlfp_s+6 (31195Ah)

    {
        for (int i = 0; i < 1000000000; ++i)
00311040  dec         edi
00311041  jne         main+20h (311030h)
    }

(省略)

            c->fun();
0031195A  mov         ecx,esi
0031195C  call        eax
0031195E  jmp         main+30h (311040h)

00311035のcmpでvtblの項目がChild::funであるか比較、違っていればjneで0031195Aへ飛んでc->fun()を実行します。Child::funだった場合、次の行(00311040)ではdecを行なっており、Child::funがインライン展開されて空になったものと思います。

というわけで、インストルメントビルド→プロファイル収集のための実行→最適化ビルドと手間は必要ですが、C++でも実行時の情報に基づく最適化は実現できるという話でした。

なお、ここではVisual C++ 2010を用いましたが、同様のプロファイルに基づく最適化はGCCにもあります。Profile feedback in GCCによれば、GCC 4.1からのようです。ほかには、Intel C++にもあるでしょう。

スポンサード リンク

この記事のカテゴリ

  • ⇒ C++でも実行時の情報で最適化
  • ⇒ C++でも実行時の情報で最適化