我可以检查 C# 编译器是否内联了方法调用吗?
-
03-07-2019 - |
题
我正在编写一个 XNA 游戏,在其中进行逐像素碰撞检查。检查这一点的循环通过移位 int 和按位 ORing 来实现,并且通常难以阅读和理解。
我想添加私有方法,例如 private bool IsTransparent(int pixelColorValue)
使循环更具可读性,但我不希望方法调用的开销,因为这是对性能非常敏感的代码。
有没有办法强制编译器内联此调用,或者我只是希望编译器会进行此优化?
如果没有办法强制执行此操作,是否有办法检查该方法是否内联,而不需要阅读反汇编代码?如果该方法是内联的并且不存在其他调用者,该方法是否会在反射中显示?
编辑: 我无法强制它,所以我可以检测到它吗?
解决方案
不,你不能。更重要的是,决定内联的人不是带有代码并将其转换为IL的VS编译器,而是带有IL并将其转换为机器代码的JIT编译器。这是因为只有JIT编译器对处理器体系结构有足够的了解才能确定将内联方法放在适当的位置,因为它是指令流水线和缓存大小之间的权衡。
因此,即使查看.NET Reflector也无济于事。
其他提示
“你可以检查一下 System.Reflection.MethodBase.GetCurrentMethod()。名称。 如果方法是内联的,它会 返回调用者的名字 代替"
有一种新方法可以鼓励在.net 4.5中进行更具侵略性的内联,如下所述: http://blogs.microsoft.co.il/blogs/sasha/archive/2012/01/20/aggressive -inlining-内式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 的工作方式有所不同。
谷歌一下发现了这个:
“内联方法可以减轻方法调用的开销。JIT 形成满足以下条件的内联。
- IL 代码大小为 16 字节或更小。
- 不使用分支命令(如果句子等)。
- 不使用局部变量。
- 尚未执行异常处理(尝试,捕获等)。
- Float不用用作方法的参数或返回值(可能是由Xbox 360,未应用的)。
- 当方法中有两个或多个参数时,它用于轮流声明。
但是,虚拟函数不会形成内联函数。”
http://xnafever.blogspot.com/2008/07/inline-method-by-xna-on-xbox360.html
我不知道他是否正确。任何人?
基本上,你不能在大多数现代C ++编译器中这样做。 inline
只是对编译器的提议。它可以随意使用。
C#编译器不会在IL级别进行任何特殊的内联。 JIT优化器就是这样做的。
为什么不使用不安全的代码(内联c作为已知代码)并使用c / c ++样式指针,这对于GC来说是安全的(即不受集合影响)但是它具有自己的安全隐患(无法用于互联网)区域应用程序)但是对于你试图实现的那种东西,特别是性能,甚至更多的数组和按位操作,它是非常好的?
总结一下,您希望应用程序的一小部分性能如何?使用不安全的代码并使用指针等对我来说似乎是最好的选择
编辑:有点启动? http://msdn.microsoft.com/en-us /library/aa288474(VS.71).aspx检查此问题的唯一方法是获取或编写分析器,并挂钩到JIT事件,还必须确保在分析时默认情况下不会关闭内联。
您可以使用前面提到的GetCurrentMethod调用在运行时检测它。但是,这似乎有点浪费[1]。最简单的方法就是ILDASM MSIL并检查那里。
请注意,这是专门用于内联调用的编译器,并且包含在各种反射文档。
如果调用GetCallingAssembly方法的方法是由编译器内联扩展的(也就是说,如果编译器将函数体插入到发出的Microsoft中间语言(MSIL)中,而不是发出函数调用),那么程序集返回GetCallingAssembly方法是包含内联代码的程序集。这可能与包含原始方法的程序集不同。要确保编译器不会内联调用GetCallingAssembly方法的方法,可以将MethodImplAttribute属性应用于MethodImplOptions.NoInlining。
但是,JITter也可以自由进行内联调用 - 但我认为反汇编程序是唯一可以验证该级别是什么和未完成的方法。
编辑:只是为了清除这个帖子中的一些混淆, csc.exe 将内联MSIL调用 - 尽管JITter(可能)会更加积极主动。
[1]而且,浪费 - 我的意思是(a)因为反射查找而失去了内联的目的(更好的性能)。而且(b),它可能会改变内联行为,因此无论如何都不再内联。而且,在您认为可以使用Assert或其他东西打开Debug版本之前 - 意识到它不会在Debug期间内联,但可能在Release中。
有没有办法强制编译器内联这个调用,或者我会这样做,我只希望编译器会进行这种优化?
如果内联函数更便宜,它会。所以不要担心它,除非你的探查者说它实际上是一个问题。
了解更多信息
- 对于简单的代码,您甚至可以尝试在线获取 asm: https://sharplab.io/
- 对于更复杂的情况,请尝试 https://github.com/szehetner/InlinedAnalyzer (我还没试过)。