Intelコンパイラでインライン展開上限の設定と挙動
はじめに
C++での高速化ではインライン展開が重要ですが、一方で現実的には全ての関数呼び出しがinline展開されるわけではありません。
そのインライン展開具合の調整法の一つとして、コンパイラオプションで設定値を変えることができますが、どうやら単純ではない模様です。今回はその情報共有目的の記事です。
※今回はIntelコンパイラ(icc,icpc)を対象とした話題です。gccやclangは扱いません。
はじめに
Intelコンパイラにおいてインライン展開具合を設定できるものとして、次のコンパイラオプションがあります(他にもあります)。
-
-inline-max-size=n
:呼び出される側の関数のサイズが設定値n
以下であればインライン展開される(されやすい) -
-inline-max-total-size=n
:インライン展開した場合に呼び出す側の関数のサイズが設定値n
を超えるならインライン展開しない(されにくい) -
inline-factor=N
:倍率N
[パーセント(ただし整数)]をdefault値に掛ける形で上記二つの設定を同時に行える。
これらの設定値のdefault値は、最適化レポートファイル*.optrpt
の冒頭に記載されます。私が検証した環境では、-inline-max-size
、-inline-max-total-size
、-inline-factor
のdefault値はそれぞれ230、2000、100でした。
例
実際にインライン展開されたかどうかは、最適化レポートファイル*.optrpt
を見ることで分かります。ただし、コンパイラオプションに-qopt-report=5 -qopt-report-phase=ipo
などを指定してください。
今回は、例として次のオプションでコンパイルした場合を示します。
icpc -O2 -ip -inline-max-size=230 -qopt-report=5 -qopt-report-phase=ipo hoge.cpp
この場合にhoge.optrpt
に出力された最適化レポートは次のようなものでした(見やすさのために適当に編集していますが、実際のコードのコンパイル結果から抽出しています)
...(略)...
INLINING OPTION VALUES:
-inline-factor: 100
-inline-min-size: 30
-inline-max-size: 230 (user-specified)
-inline-max-total-size: 2000
-inline-max-per-routine: disabled
-inline-max-per-compile: disabled
...
(略)
...
INLINE REPORT: (funcA(int) const) [2147/3416=62.9%] ..hoge.cpp(55,135)
-> INLINE (MANUAL): (56,18) funcB(int, double) const (isz = 49) (sz = 66)
-> fuga.h:(809,9) funcC(int) const (isz = 452) (sz = 473)
[[ Inlining would exceed -inline-max-size value (473>230) <1>]]
-> INLINE (MANUAL): fuga.h:(809,43) funcD(int) const (isz = 16) (sz = 25)
-> INLINE (MANUAL): fuga.h:(220,50) funcE(double) (isz = 4) (sz = 15)
構造としてはfuncA
がfuncB
と呼び出し、funcB
からfuncC
とfuncD
を呼び出し、さらにfuncD
からfuncE
を呼び出しています。
ここでfuncC
だけはインライン展開されなかったことが分かります。その原因として「funcC
のサイズが473であり、-inline-max-size
の値である230を超えた」ためと記されています。
ここでfuncC
のサイズとは、funcC
の中で呼ばれた関数がインライン展開されている場合には、それらを含んだサイズになります。実際に、funcC
の中では数十個の細かな関数がcallされて、それらが全てインライン展開されたために、合計サイズが473まで大きくなっています。
また、コンパイルオプションで明示的に-inline-max-size=230
を指定したので、冒頭の設定値の通知部分で(user-specified)
と表示されています。
問題
先の例では敢えて明示的に-inline-max-size=230
を指定していましたが、これを指定しなかった場合はどうなるでしょうか。
少なくとも私は、-inline-max-size
のdefault値は230なので結果は変わらないと思っていました。しかし、やってみるとfuncC
がインライン展開される場合があるのです。
例えばコンパイルオプション
icpc -O2 -ip -qopt-report=5 -qopt-report-phase=ipo hoge.cpp
から、次の最適化レポートが出力されました。
...(略)...
INLINING OPTION VALUES:
-inline-factor: 100
-inline-min-size: 30
-inline-max-size: 230
-inline-max-total-size: 2000
-inline-max-per-routine: disabled
-inline-max-per-compile: disabled
...
(略)
...
INLINE REPORT: (funcA(int) const) [2147/3416=62.9%] ..hoge.cpp(55,135)
-> INLINE (MANUAL): (56,18) funcB(int, double) const (isz = 49) (sz = 66)
-> INLINE (MANUAL): fuga.h:(809,9) funcC(int) const (isz = 452) (sz = 473)
-> INLINE (MANUAL): fuga.h:(530,48) funcF(double) (isz = 24) (sz = 32)
... (略) funcCから呼び出した数十個の関数...
-> INLINE (MANUAL): fuga.h:(809,43) funcD(int) const (isz = 16) (sz = 25)
-> INLINE (MANUAL): fuga.h:(220,50) funcE(double) (isz = 4) (sz = 15)
今度はfuncC
もインライン展開されています。
しかしfuncC
のサイズは先と変わらず473です。-inline-max-size
の設定値も230と表示されています。しかしそれらが加味されずにインライン展開されてしまっています。
同様の問題は-inline-max-size
以外にも-inline-max-total-size
や-inline-factor
を明示的に指定するかどうかでも起こります。
想像される原因
さて、この違いは何が原因なのでしょうか。
Intelコンパイラのマニュアル1によれば、「-inline-max-size
等はコンパイラがルーチンを大・中・小に分類する指標であり、中・小に分類されたものはインライン展開されやすい」と読めます。つまり、インライン展開をするかどうかを絶対的に指定できるわけではなさそうです
そして、たとえ同じ設定値であったとしても、「コンパイラオプションに明示的に指定した場合はインライン展開の判断への影響力が大きくなる」のだと想像できます。
おわりに
ということで、-inline-max-size
や-inline-factor
での指定では注意が必要です。例えば前回書いた記事2でも-inline-factor
で設定値を変更して計算速度のベンチを行っていますが、-inline-factor=100
を明記した場合と未指定の場合で結果が違う可能性が出てきました(うわ~再調査か~)。
個人的には結構ハマり、チューニングにおいてかなり混乱していました。
誰かのお役に立てば幸いです。
追記1
ここでの議論を踏まえて、高速化のためにはどうすればよいのか。
そもそも重要な観点は
- サイズは小さいが沢山呼ばれる関数はインライン展開がされた方が良い
- インライン展開し過ぎてバイナリサイズが大きくなると速度は低下する
の2点です。
前者を促進するためには
(1-1)明示的に-inline-max-size
をdefaultより大きい値で指定するか、(1-2)-inline-max-size
は指定せずにコンパイラが(勝手にdefault値の制限以上に)アグレッシブにインライン展開するのを期待するのが良さそうです。
一方で後者を踏まえてバイナリサイズを抑制するには
(2-1)明示的に-inline-max-total-size
を小さめ(ただしdefaultと同じかちょっと大きい程度)に指定するのが良いでしょう。ただし、(2-NG)-inline-max-total-size
を指定しないのは問題が出やすいです。こちらの値についてもコンパイラが勝手にdefault値の制限以上にアグレッシブにインライン展開してしまうので、バイナリサイズが大きくなってしまいます。
また、この2点の観点から-inline-max-size
と-inline-max-total-size
を共に大きくしていくのは問題があることになります。つまり、-inline-factor
はあまり使わない方が良さそうです。
蛇足
コンパイラオプションで-inline-factor
などを調整するよりも、Intelコンパイラなら#pragma forceinline recursive
などを使った方が良いかもしれない。
Author And Source
この問題について(Intelコンパイラでインライン展開上限の設定と挙動), 我々は、より多くの情報をここで見つけました https://qiita.com/pochman/items/a929a97e555a9b5f0719著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .