我可以检查C#编译器内联方法调用吗?

时间:2009-03-05 21:49:40

标签: c# optimization inline compilation

我正在编写一个XNA游戏,我会进行逐像素碰撞检查。通过移位int和按位ORing来检查这种情况的循环通常难以阅读和理解。

我想添加private bool IsTransparent(int pixelColorValue)之类的私有方法来使循环更具可读性,但我不希望方法调用的开销,因为这是对性能非常敏感的代码。

有没有办法强制编译器内联这个调用,或者我会这样做,我只希望编译器会进行这种优化?

如果无法强制执行此操作,是否有办法检查方法是否内联,而不是阅读反汇编?如果内联并且没有其他调用者存在,该方法是否会显示在反射中?

编辑:我无法强迫它,所以我可以检测到它吗?

10 个答案:

答案 0 :(得分:24)

不,你不能。更重要的是,决定内联的人不是带有代码并将其转换为IL的VS编译器,而是带有IL并将其转换为机器代码的JIT编译器。这是因为只有JIT编译器对处理器体系结构有足够的了解才能确定将内联方法放在适当位置,因为它是指令流水线和缓存大小之间的权衡。

因此,即使查看.NET Reflector也无济于事。

答案 1 :(得分:16)

  

“你可以检查一下   System.Reflection.MethodBase.GetCurrentMethod()。名称。   如果方法是内联的,它会   返回调用者的名字   代替“。

- Joel Coehoorn

答案 2 :(得分:14)

有一种新的方法可以鼓励在此处描述的.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; 
    } 
}

答案 3 :(得分:4)

请注意XBox的工作方式不同。

谷歌出现了这个:

“内联方法,可减轻方法调用的开销。 JIT形成内联符合以下条件的内容。

  • IL代码大小不超过16个字节。
  • 不使用分支命令(如果 句子等。)。
  • 未使用局部变量。
  • 异常处理尚未完成 进行(尝试,捕捉等)。
  • float不用作参数或 方法的返回值(可能是 Xbox 360,未应用)。
  • 当两个或多个参数出现在 方法,它用于转弯 声明。

但是,虚函数不会形成内联。“

http://xnafever.blogspot.com/2008/07/inline-method-by-xna-on-xbox360.html

我不知道他是否正确。任何人吗?

答案 4 :(得分:1)

不,你不能。

基本上,你不能在大多数现代C ++编译器中这样做。 inline只是对编译器的提议。它可以随意使用。

C#编译器不会在IL级别进行任何特殊的内联。 JIT优化器就是这样做的。

答案 5 :(得分:1)

为什么不使用不安全的代码(内联c作为已知代码)并使用c / c ++样式指针,这对于GC来说是安全的(即不受集合影响)但是它具有自己的安全隐患(无法用于互联网)区域应用程序)但是对于你试图实现的那种东西,特别是性能,甚至更多的数组和按位操作,它是非常好的?

总结一下,您希望应用程序的一小部分性能如何?使用不安全的代码并使用指针等对我来说似乎是最好的选择

编辑:有点启动? http://msdn.microsoft.com/en-us/library/aa288474(VS.71).aspx

答案 6 :(得分:1)

检查此问题的唯一方法是获取或编写分析器,并挂钩到JIT事件,还必须确保在分析时默认情况下不会关闭内联。

答案 7 :(得分:0)

您可以使用前面提到的GetCurrentMethod调用在运行时检测它。但是,这似乎有点浪费[1]。最简单的方法就是ILDASM MSIL并检查那里。

请注意,这是专门针对编译器内联调用的,并且在MSDN上的各种Reflection文档中都有介绍。

  

如果调用GetCallingAssembly方法的方法是由编译器内联扩展的(也就是说,如果编译器将函数体插入到发出的Microsoft中间语言(MSIL)中,而不是发出函数调用),那么程序集返回GetCallingAssembly方法是包含内联代码的程序集。这可能与包含原始方法的程序集不同。要确保编译器不会内联调用GetCallingAssembly方法的方法,可以将MethodImplAttribute属性应用于MethodImplOptions.NoInlining。

但是,JITter也可以自由进行内联调用 - 但我认为反汇编程序是唯一可以验证该级别是什么和未完成的方法。

编辑:只是为了澄清这个帖子中的一些混淆,csc.exe will inline MSIL calls - 虽然JITter(可能)会更积极。

[1]而且,浪费 - 我的意思是(a)因为反射查找而失去了内联的目的(更好的性能)。而且(b),它可能会改变内联行为,因此无论如何都不再内联。而且,在您认为可以使用Assert或其他东西打开Debug版本之前 - 意识到它不会在Debug期间内联,但可能在Release中。

答案 8 :(得分:0)

  

有没有办法强制编译器内联这个调用,或者我会这样做,我只希望编译器会进行这种优化?

如果内联函数更便宜,它会。所以不要担心它,除非你的探查者说它实际上是一个问题。

了解更多信息

JIT Enhancements in .NET 3.5 SP1

答案 9 :(得分:0)