C#コンパイラがメソッド呼び出しをインライン化したかどうかを確認できますか?
-
03-07-2019 - |
質問
ピクセルごとの衝突チェックを行うXNAゲームを書いています。これをチェックするループは、intとビット単位のORをシフトすることでそうしますが、一般的に読みやすく理解しにくいです。
ループを読みやすくするために private bool IsTransparent(int pixelColorValue)
などのプライベートメソッドを追加したいが、これはパフォーマンスに非常に敏感であるため、メソッド呼び出しのオーバーヘッドは望ましくないコード。
コンパイラーにこの呼び出しをインライン化させる方法はありますか、またはコンパイラーがこの最適化を行うことを望みますか?
これを強制する方法がない場合、メソッドがインライン化されたかどうかをチェックする方法はありますか?インライン化され、他の呼び出し元が存在しない場合、メソッドはリフレクションに表示されますか?
編集:強制できません。検出できますか
解決
いいえ、できません。さらに、インライン化を決定するのは、コードを受け取ってILに変換するVSコンパイラではなく、ILを受け取ってマシンコードに変換するJITコンパイラです。これは、命令のパイプライン化とキャッシュサイズのトレードオフであるため、メソッドのインライン化が適切かどうかを判断するのに十分なプロセッサアーキテクチャを知っているのはJITコンパイラーだけだからです。
したがって、.NET Reflectorを調べても役に立ちません。
他のヒント
"確認できます System.Reflection.MethodBase.GetCurrentMethod()。Name。 メソッドがインライン化されている場合、 呼び出し元の名前を返します 代わりに。"
.net 4.5でより積極的なインライン展開を奨励する新しい方法があります。これは、 http://blogs.microsoft.co.il/blogs/sasha/archive/2012/01/20/aggressive -inlining-in-the-clr-4-5-jit.aspx
基本的には、可能であればコンパイラーにインラインを指示するための単なるフラグです。残念ながら、現在のバージョンのXNA(Game Studio 4.0)では使用できませんが、XNAが今年中にVS 2012に追いつくと使用可能になるはずです。何らかの方法でMonoを実行している場合は、すでに利用可能です。
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int LargeMethod(int i, int j)
{
if (i + 14 > j)
{
return i + j;
}
else if (j * 12 < i)
{
return 42 + i - j * 7;
}
else
{
return i % 14 - j;
}
}
XBoxの動作が異なることに注意してください。
Googleがこれを明らかにした:
&quot;メソッドの呼び出しのオーバーヘッドを軽減するインラインメソッド。 JITは、次の条件を満たすインラインを形成します。
- ILコードサイズは16バイト以下です。
- ブランチコマンドは使用されません(if 文など)。
- ローカル変数は使用されません。
- 例外処理はされていません 実行(試行、キャッチなど)。
- floatが引数として使用されていない、または メソッドの戻り値(おそらく Xbox 360、適用されません)。
- 2つ以上の引数が メソッド、それはターンに使用します 宣言されました。
ただし、仮想関数はインラインになりません。&quot;
http://xnafever.blogspot .com / 2008/07 / inline-method-by-xna-on-xbox360.html
彼が正しいかどうかはわかりません。誰ですか?
いいえ、できません。
基本的に、ほとんどの最新のC ++コンパイラでもこれを行うことはできません。 inline
はコンパイラへの単なる提案です。それを取るかどうかは自由です。
C#コンパイラは、ILレベルで特別なインライン化を行いません。 JITオプティマイザーがそれを行います。
安全でないコード(既知のインラインc)を使用せず、c / c ++スタイルのポインターを使用する理由、これはGCから安全です(つまり、コレクションの影響を受けません)が、独自のセキュリティの意味がありますゾーンアプリ)ですが、特にパフォーマンスで達成しようとしているように見えるものには優れていますが、配列やビット演算でさらに達成できますか?
要約すると、アプリのごく一部のパフォーマンスが必要ですか?安全でないコードを使用し、ポインターなどを使用することが私にとって最良の選択肢だと思われます
EDIT:ちょっとしたスターター? http://msdn.microsoft.com/en-us /library/aa288474(VS.71).aspx
これを確認する唯一の方法は、プロファイラーを取得または作成し、JITイベントにフックすることです。また、プロファイリング時にデフォルトでインライン化がオフになっていないことも確認する必要があります。
前述のGetCurrentMethod呼び出しを使用すると、実行時に検出できます。しかし、それは少し無駄に思えます[1]。最も簡単な方法は、MSILをILDASMして、そこで確認することです。
これは、呼び出しをインライン化するコンパイラ専用であり、さまざまな Reflection MSDNのドキュメント。
GetCallingAssemblyメソッドを呼び出すメソッドがコンパイラーによってインライン展開される場合(つまり、コンパイラーが関数呼び出しを発行するのではなく、発行されるMicrosoft中間言語(MSIL)に関数本体を挿入する場合)、アセンブリが返されますGetCallingAssemblyメソッドは、インラインコードを含むアセンブリです。これは、元のメソッドを含むアセンブリとは異なる場合があります。 GetCallingAssemblyメソッドを呼び出すメソッドがコンパイラーによってインライン化されないようにするために、MethodImplOptions.NoInliningでMethodImplAttribute属性を適用できます。
ただし、JITterはインライン呼び出しも無料です。しかし、そのレベルで何が行われ、何が行われないかを検証するには、逆アセンブラが唯一の方法だと思います。
編集:このスレッドの混乱を解消するために、 csc.exeは、インラインMSIL呼び出しを します-JITterは(おそらく)より積極的になります。
[1]そして、無駄に-私は、(a)Reflectionルックアップのためにインライン化の目的を無効にすること(より良いパフォーマンス)を意味します。 (b)インライン化動作をおそらく変更して、インライン化されないようにします。そして、あなたが考える前に、アサートまたは何かを使用してデバッグビルドをオンにすることができます-デバッグ中にインライン化されず、リリースされる可能性があることを認識してください。
コンパイラーにこの呼び出しをインライン化させる方法はありますか、またはコンパイラーがこの最適化を行うことを望みますか?
関数のインライン化の方が安価な場合、インライン化されます。プロファイラーが実際に問題であると言っていない限り、心配する必要はありません。
詳細情報
- 単純なコードの場合、オンラインでもasmを取得できます。 https://sharplab.io/
- より複雑なケースについては、 https://github.com/szehetner/InliningAnalyzer (I 「まだ試していません」。