問題タブ [inlining]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - C++ 関数のインライン化について
グローバル関数を強制的にインライン化するために MS 固有のキーワードを使用していますが、明示的な単純なデストラクタを持つオブジェクトを使用すると、関数がインライン化に失敗することに気付きました。
MSDNからの引用
を使用しても
__forceinline
、コンパイラはすべての状況でコードをインライン化できるわけではありません。次の場合、コンパイラは関数をインライン化できません。
関数またはその呼び出し元は
/Ob0
(デバッグ ビルドの既定のオプション) でコンパイルされます。関数と呼び出し元は、異なるタイプの例外処理を使用します (一方は C++ 例外処理、もう一方は構造化例外処理)。
関数には可変引数リストがあります。
/Og
関数は、 、/Ox
、/O1
、またはでコンパイルされていない限り、インライン アセンブリを使用します/O2
。この関数は再帰的で、 を伴いません
#pragma inline_recursion(on)
。プラグマを使用すると、再帰関数はデフォルトの深さ 16 呼び出しにインライン化されます。インライン化の深さを減らすには、inline_depth
pragma を使用します。関数は仮想であり、仮想的に呼び出されます。仮想関数への直接呼び出しはインライン化できます。
プログラムは関数のアドレスを取得し、呼び出しは関数へのポインターを介して行われます。アドレスが取得された関数への直接呼び出しは、インライン化できます。
この関数は、naked
__declspec
修飾子でもマークされています。
動作をテストするために、次の自己完結型プログラムを試しています
自明なデストラクタINLINE ~Spam() {}
を配置すると、次の分解が行われます
デストラクタINLINE ~Spam() {}
がない場合、次の逆アセンブリがあります
デストラクタが存在する場合、コンパイラが関数のインライン化に失敗する理由を理解できていませんT movz(T& t)
- 注: 動作は 2008 年から 2013 年まで一貫しています。
- 注意cygwin-gcc で確認しましたが、コンパイラはコードをインライン化します。現時点では他のコンパイラを確認できませんが、必要に応じて 12 時間以内に更新します
java - 可視性と javac / JVM インライン化
メソッド/フィールドの可視性は、Java でのメソッドのインライン化にどのように影響しますか?
私が念頭に置いているケースは、フィールドのpublic
ゲッターのようなものです:private
ここでいくつかの問題が発生します。
1 つは、Java コンパイラ自体がインライン展開を行うかどうかです。この質問には、イエスと言う人もいればノーと言う人もいて、さまざまな答えがあるようです。以前はインライン化を行わなかったが、現在はインライン化を行っているためなのか、それとも正しい人もいれば間違っている人もいるというだけなのかはわかりません...
getBlah()
さて、インライン化を行う場合、呼び出しをインライン化できない可能性があると考えるのは正しいでしょうか? メソッドは非常に単純であり、メソッドを呼び出すオーバーヘッドはメソッド自体のコードと同じくらい大きいため、これらはインライン化が有用な場所であることは明らかです。private
しかし、コンパイラによってインライン化された場合、フィールドに直接アクセスするバイトコードになってしまいます。そして確かにJVMは文句を言うでしょうか?(これは、このメソッドが であっても適用されstatic final
ます。)
第二に、JIT コンパイラーはどうですか? 私が見る限り、そのレベルでのインライン化に関しては、この問題は当てはまりません。ネイティブ コードが生成されると、JVM はすでにチェックを行っており、メソッドを呼び出すことができることを確認しています (これは であるためpublic
)。そのため、可視性の問題なしに、呼び出しをインライン化するネイティブ コードを生成できます...はい?
haskell - 繰り返し呼び出しのインライン化 (GHC)
GHCは複数回使用される関数をインライン化しますか? 例えば:
を呼び出すg innerLoop
と、関数innerLoop
は 3 回複製されますか? それともただになるのg stuff...
でしょうか?
どうすればinnerLoop
複数回インライン化するように強制したり、複数回インライン化されないようにすることができますか?
c++ - 関数の定義に先行する呼び出しはインライン化できませんか?
gcc のドキュメントには、次の内容が含まれています。
関数がインラインと静的の両方である場合、関数へのすべての呼び出しが呼び出し元に統合され、関数のアドレスが使用されない場合、関数自体のアセンブラー コードが参照されることはありません。この場合、オプション -fkeep-inline-functions を指定しない限り、GCC は実際には関数のアセンブラー コードを出力しません。一部の呼び出しは、さまざまな理由で統合できません (特に、関数の定義に先行する呼び出しは統合できず、定義内の再帰呼び出しも統合できません)。
それは私にはいつもばかげているように思えました -- なぜ現代のコンパイラはそれほど馬鹿げているのでしょうか? 簡単なテストの後、それは真実ではないようです。
テストコード:
Linux での gcc-4.9.2 の結果には、 のコードが含まれていますが、 のコードは含まれてbar()
いませんfoo()
。foo()
統合されていることがわかります。
C++ としてコンパイルすると、名前マングリングを除いて、結果は同じです。
ドキュメントに反して、foo()
の呼び出し後に定義されているにもかかわらずbar()
、foo()
は完全に に統合されていbar()
ます。
ドキュメントを誤解していますか、それとも間違っていますか? おそらく、より複雑なケースでは正しいでしょうか?
「統合」と「インライン」の間に技術的な違いがあるかどうかはわかりませんが、「統合」はキーワードinline
と区別するために使用されており、関数のインライン化を指しているだけだと思います(したがって、タイトル)。
この質問は C および C++ としてタグ付けされています。これは、gcc ドキュメントのこの部分が「C 言語ファミリー」に関連しており、回答が 2 つの言語で同じであると予想されるためです。
c++ - オブジェクトの実際の型をテンプレート パラメーターとして指定できる場合の仮想関数のインライン化
仮想クラスCalculator
とそのクラスの実装例MyCalculator
があります。
次の関数で示されているように使用すると、コンパイラは仮想であるためop1()
、もちろんインライン化できません。op1()
ただし、場合によっては、calc
AND の実際の型を知っていて、パフォーマンス上の理由からインライン化したいことがあります。そこで、次の案を考えます。
この関数を次のように呼び出します。
最初の例では、インライン化はできませんが、2 番目の例では、 op1()
ofMyCalculator
は 内にインライン化する必要があると思いますcalculate()
。
私の仮定は本当ですか?
c - gcc でパフォーマンスが大幅に低下します。インラインに関連している可能性があります
gcc
現在、 (テスト済みバージョン:4.8.4)で奇妙な効果が発生しています。
かなり高速に実行されるパフォーマンス指向のコードがあります。その速度は、多くの小さな関数をインライン化することに大きく依存します。
複数の.c
ファイルにまたがるインライン化は難しいため (-flto
まだ広く利用できるようにはなっていません)、多くの小さな関数 (通常はそれぞれ 1 行から 5 行のコード) を共通の C ファイルに保存し、そこにコーデックを開発しています。関連するデコーダー。私の標準では「比較的」大きいですが (約 2000 行ですが、多くはコメントと空白行だけです)、小さな部分に分割すると新しい問題が発生するため、可能であればそれを避けたいと思います。
Encoder と Decoder は逆の操作であるため、関連しています。しかし、プログラミングの観点から見ると、これらは完全に分離されており、いくつかの typedef と非常に低レベルの関数 (整列されていないメモリ位置からの読み取りなど) を除いて、共通点はありません。
奇妙な効果はこれです:
fnew
最近、エンコーダ側に新しい機能を追加しました。新しい「入り口」です。ファイル内のどこからも使用されず、呼び出されません.c
。
それが存在するという単純な事実は、デコーダー機能のパフォーマンスをfdec
大幅に低下させ、20% 以上低下させます。これは、無視するには多すぎます。
ここで、エンコード操作とデコード操作は完全に分離されており、ほとんど何も共有されておらず、いくつかのマイナーな操作typedef
(u32
などu16
) と関連する操作 (読み取り/書き込み) を除いて覚えておいてください。
新しいエンコーディング関数fnew
を として定義するstatic
と、デコーダのパフォーマンスがfdec
向上し、通常の状態に戻ります。fnew
から呼び出されないので.c
、存在しないのと同じだと思います (デッド コードの削除)。
static fnew
がエンコーダ側から呼び出されるようになった場合、 のパフォーマンスはfdec
引き続き強力です。
しかし、fnew
変更されるとすぐに、fdec
パフォーマンスが大幅に低下します。
変更がしきい値を超えたと仮定して、次のパラメーターfnew
を増やしました: (デフォルトでは、その値は 40 であると想定されています) 。gcc
--param max-inline-insns-auto=60
fdec
fnew
そして、このゲームは、小さな変更やその他の類似のもののたびに永遠に続くと思います。さらに微調整が必要です.
これは単純に奇妙です。fnew
function の小さな変更が、まったく関係のない function に影響を与えるという論理的な理由はありませんfdec
。これは、関係だけが同じファイルにあるはずです。
これまでのところ、私が考案できる唯一の暫定的な説明は、単に存在するだけで、に影響を与えるfnew
何らかの種類の を越えるのに十分であるということです。1. 存在しない、2.しかしどこからも呼び出されない、3 . インライン化できるほど小さい。しかし、それは問題を隠しているだけです。新しい機能を追加できないということですか?global file threshold
fdec
fnew
static
static
本当に、ネットのどこにも満足のいく説明が見つかりませんでした。
誰かがすでに同等の副作用を経験しており、その解決策を見つけているかどうか知りたいと思っていました.
[編集]
もっとクレイジーなテストに行きましょう。今、私はただ遊ぶためだけに、まったく役に立たない別の関数を追加しています。内容は厳密には のコピペですfnew
が、明らかに関数名が違うので としましょうwtf
。
がwtf
存在する場合、fnew
が静的であるかどうかも、 の値が何であるかも問題ではありませんmax-inline-insns-auto
。 のパフォーマンスはfdec
正常に戻ります。どこからもwtf
使用も呼び出しもされていませんが... :'(
【編集2】inline
指示
がありません。すべての機能は通常またはstatic
. インライン化の決定は、これまでのところ問題なく機能しているコンパイラの領域内でのみ行われます。
[編集 3]
Peter Cordes が示唆したように、この問題はインラインではなく、命令の配置に関係しています。新しい Intel CPU (Sandy Bridge 以降) では、ホット ループは 32 バイト境界に揃えることでメリットがあります。問題は、デフォルトでは、gcc
それらを 16 バイト境界に揃えることです。これにより、前のコードの長さに応じて、50% の確率で適切な位置合わせが行われます。したがって、「ランダムに見える」問題を理解するのは困難です。
すべてのループがセンシティブなわけではありません。これはクリティカル ループでのみ重要であり、アライメントが理想的ではない場合に、ループの長さが 32 バイトの命令セグメントをさらに 1 つ超える場合にのみ重要です。
postgresql - PostgreSQL は、OFFSET 0 を使用してサブクエリのインライン化を防止します
評価されるたびにテーブル全体をスキャンする where 句にサブクエリがあります。
サブクエリの最後に OFFSET 0 を追加しても、クエリ プランに変更はありません。
この投稿を参照してください。この場合、where 句で最適化フェンス「OFFSET 0」は機能しませんか?