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

时间:2022-04-17 16:09:55

I'm writing an XNA game where I do per-pixel collision checks. The loop which checks this does so by shifting an int and bitwise ORing and is generally difficult to read and understand.

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

I would like to add private methods such as private bool IsTransparent(int pixelColorValue) to make the loop more readable, but I don't want the overhead of method calls since this is very performance sensitive code.

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

Is there a way to force the compiler to inline this call or will I do I just hope that the compiler will do this optimization?

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

If there isn't a way to force this, is there a way to check if the method was inlined, short of reading the disassembly? Will the method show up in reflection if it was inlined and no other callers exist?

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

Edit: I can't force it, so can I detect it?

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

9 个解决方案

#1


No you can't. Even more, the one who decides on inlining isn't VS compiler that takes you code and converts it into IL, but JIT compiler that takes IL and converts it to machine code. This is because only the JIT compiler knows enough about the processor architecture to decide if putting a method inline is appropriate as it’s a tradeoff between instruction pipelining and cache size.

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

So even looking in .NET Reflector will not help you.

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

#2


"You can check System.Reflection.MethodBase.GetCurrentMethod().Name. If the method is inlined, it will return the name of the caller instead."

“你可以检查System.Reflection.MethodBase.GetCurrentMethod()。Name。如果方法是内联的,它将返回调用者的名字。”

--Joel Coehoorn

#3


There is a new way to encourage more agressive inlining in .net 4.5 that is described here: http://blogs.microsoft.co.il/blogs/sasha/archive/2012/01/20/aggressive-inlining-in-the-clr-4-5-jit.aspx

有一种新方法可以鼓励在这里描述的.net 4.5中更具侵略性的内联:http://blogs.microsoft.co.il/blogs/sasha/archive/2012/01/20/aggressive-inlining-in-the -clr-4-5-jit.aspx

Basically it is just a flag to tell the compiler to inline if possible. Unfortunatly, it's not available in the current version of XNA (Game Studio 4.0) but should be available when XNA catches up to VS 2012 this year some time. It is already available if you are somehow running on Mono.

基本上它只是一个标志,告诉编译器如果可能的话内联。不幸的是,它在当前版本的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; 
    } 
}

#4


Be aware that the XBox works different.

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

A google turned up this:

一个谷歌出现了这个:

"The inline method which mitigates the overhead of a call of a method. JIT forms into an inline what fulfills the following conditions.

“内联方法减轻了方法调用的开销.JIT形成内联,满足以下条件。

  • The IL code size is 16 bytes or less.
  • IL代码大小为16字节或更少。

  • The branch command is not used (if sentence etc.).
  • 不使用分支命令(如果句子等)。

  • The local variable is not used.
  • 不使用局部变量。

  • Exception handling has not been carried out (try, catch, etc.).
  • 尚未执行异常处理(尝试,捕获等)。

  • float is not used as the argument or return value of a method (probably by the Xbox 360, not applied).
  • float不用作方法的参数或返回值(可能是由Xbox 360,未应用)。

  • When two or more arguments are in a method, it uses for the turn declared.
  • 当一个方法中有两个或多个参数时,它用于声明的转弯。

However, a virtual function is not formed into an inline."

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

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

I have no idea if he is correct. Anyone?

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

#5


Nope, you can't.

不,你不能。

Basically, you can't do that in most modern C++ compilers either. inline is just an offer to the compiler. It's free to take it or not.

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

The C# compiler does not do any special inlining at the IL level. JIT optimizer is the one that will do it.

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

#6


why not use unsafe code (inline c as its known) and make use of c/c++ style pointers, this is safe from the GC (ie not affected by collection) but comes with its own security implications (cant use for internet zone apps) but is excellent for the kind of thing it appears you are trying to achieve especially with performance and even more so with arrays and bitwise operations?

为什么不使用不安全的代码(内联c作为其已知的)并使用c / c ++样式指针,这对GC是安全的(即不受集合影响)但具有其自身的安全隐患(不能用于互联网区域应用程序)但是对于你想要实现的那种东西,尤其是性能,以及阵列和按位运算更是如此,它是非常好的吗?

to summarise, you want performance for a small part of your app? use unsafe code and make use of pointers etc seems the best option to me

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

EDIT: a bit of a starter ? http://msdn.microsoft.com/en-us/library/aa288474(VS.71).aspx

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

#7


The only way to check this is to get or write a profiler, and hook into the JIT events, you must also make sure Inlining is not turned off as it is by default when profiling.

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

#8


You can detect it at runtime with the aforementioned GetCurrentMethod call. But, that'd seem to be a bit of a waste[1]. The easiest thing to do would to just ILDASM the MSIL and check there.

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

Note that this is specifically for the compiler inlining the call, and is covered in the various Reflection docs on MSDN.

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

If the method that calls the GetCallingAssembly method is expanded inline by the compiler (that is, if the compiler inserts the function body into the emitted Microsoft intermediate language (MSIL), rather than emitting a function call), then the assembly returned by the GetCallingAssembly method is the assembly containing the inline code. This might be different from the assembly that contains the original method. To ensure that a method that calls the GetCallingAssembly method is not inlined by the compiler, you can apply the MethodImplAttribute attribute with MethodImplOptions.NoInlining.

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

However, the JITter is also free to inline calls - but I think a disassembler would be the only way to verify what is and isn't done at that level.

但是,JITter也可以*进行内联调用 - 但我认为反汇编程序将是验证该级别的内容和未执行内容的唯一方法。

Edit: Just to clear up some confusion in this thread, csc.exe will inline MSIL calls - though the JITter will (probably) be more aggressive in it.

编辑:只是为了清除这个线程中的一些混乱,csc.exe将内联MSIL调用 - 虽然JITter(可能)会更积极。

[1] And, by waste - I mean that (a) that it defeats the purpose of the inlining (better performance) because of the Reflection lookup. And (b), it'd probably change the inlining behavior so that it's no longer inlined anyway. And, before you think you can just turn it on Debug builds with an Assert or something - realize that it will not be inlined during Debug, but may be in Release.

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

#9


Is there a way to force the compiler to inline this call or will I do I just hope that the compiler will do this optimization?

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

If it is cheaper to inline the function, it will. So don't worry about it unless your profiler says that it actually is a problem.

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

For more information

欲获得更多信息

JIT Enhancements in .NET 3.5 SP1

.NET 3.5 SP1中的JIT增强功能

#1


No you can't. Even more, the one who decides on inlining isn't VS compiler that takes you code and converts it into IL, but JIT compiler that takes IL and converts it to machine code. This is because only the JIT compiler knows enough about the processor architecture to decide if putting a method inline is appropriate as it’s a tradeoff between instruction pipelining and cache size.

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

So even looking in .NET Reflector will not help you.

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

#2


"You can check System.Reflection.MethodBase.GetCurrentMethod().Name. If the method is inlined, it will return the name of the caller instead."

“你可以检查System.Reflection.MethodBase.GetCurrentMethod()。Name。如果方法是内联的,它将返回调用者的名字。”

--Joel Coehoorn

#3


There is a new way to encourage more agressive inlining in .net 4.5 that is described here: http://blogs.microsoft.co.il/blogs/sasha/archive/2012/01/20/aggressive-inlining-in-the-clr-4-5-jit.aspx

有一种新方法可以鼓励在这里描述的.net 4.5中更具侵略性的内联:http://blogs.microsoft.co.il/blogs/sasha/archive/2012/01/20/aggressive-inlining-in-the -clr-4-5-jit.aspx

Basically it is just a flag to tell the compiler to inline if possible. Unfortunatly, it's not available in the current version of XNA (Game Studio 4.0) but should be available when XNA catches up to VS 2012 this year some time. It is already available if you are somehow running on Mono.

基本上它只是一个标志,告诉编译器如果可能的话内联。不幸的是,它在当前版本的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; 
    } 
}

#4


Be aware that the XBox works different.

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

A google turned up this:

一个谷歌出现了这个:

"The inline method which mitigates the overhead of a call of a method. JIT forms into an inline what fulfills the following conditions.

“内联方法减轻了方法调用的开销.JIT形成内联,满足以下条件。

  • The IL code size is 16 bytes or less.
  • IL代码大小为16字节或更少。

  • The branch command is not used (if sentence etc.).
  • 不使用分支命令(如果句子等)。

  • The local variable is not used.
  • 不使用局部变量。

  • Exception handling has not been carried out (try, catch, etc.).
  • 尚未执行异常处理(尝试,捕获等)。

  • float is not used as the argument or return value of a method (probably by the Xbox 360, not applied).
  • float不用作方法的参数或返回值(可能是由Xbox 360,未应用)。

  • When two or more arguments are in a method, it uses for the turn declared.
  • 当一个方法中有两个或多个参数时,它用于声明的转弯。

However, a virtual function is not formed into an inline."

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

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

I have no idea if he is correct. Anyone?

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

#5


Nope, you can't.

不,你不能。

Basically, you can't do that in most modern C++ compilers either. inline is just an offer to the compiler. It's free to take it or not.

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

The C# compiler does not do any special inlining at the IL level. JIT optimizer is the one that will do it.

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

#6


why not use unsafe code (inline c as its known) and make use of c/c++ style pointers, this is safe from the GC (ie not affected by collection) but comes with its own security implications (cant use for internet zone apps) but is excellent for the kind of thing it appears you are trying to achieve especially with performance and even more so with arrays and bitwise operations?

为什么不使用不安全的代码(内联c作为其已知的)并使用c / c ++样式指针,这对GC是安全的(即不受集合影响)但具有其自身的安全隐患(不能用于互联网区域应用程序)但是对于你想要实现的那种东西,尤其是性能,以及阵列和按位运算更是如此,它是非常好的吗?

to summarise, you want performance for a small part of your app? use unsafe code and make use of pointers etc seems the best option to me

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

EDIT: a bit of a starter ? http://msdn.microsoft.com/en-us/library/aa288474(VS.71).aspx

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

#7


The only way to check this is to get or write a profiler, and hook into the JIT events, you must also make sure Inlining is not turned off as it is by default when profiling.

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

#8


You can detect it at runtime with the aforementioned GetCurrentMethod call. But, that'd seem to be a bit of a waste[1]. The easiest thing to do would to just ILDASM the MSIL and check there.

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

Note that this is specifically for the compiler inlining the call, and is covered in the various Reflection docs on MSDN.

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

If the method that calls the GetCallingAssembly method is expanded inline by the compiler (that is, if the compiler inserts the function body into the emitted Microsoft intermediate language (MSIL), rather than emitting a function call), then the assembly returned by the GetCallingAssembly method is the assembly containing the inline code. This might be different from the assembly that contains the original method. To ensure that a method that calls the GetCallingAssembly method is not inlined by the compiler, you can apply the MethodImplAttribute attribute with MethodImplOptions.NoInlining.

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

However, the JITter is also free to inline calls - but I think a disassembler would be the only way to verify what is and isn't done at that level.

但是,JITter也可以*进行内联调用 - 但我认为反汇编程序将是验证该级别的内容和未执行内容的唯一方法。

Edit: Just to clear up some confusion in this thread, csc.exe will inline MSIL calls - though the JITter will (probably) be more aggressive in it.

编辑:只是为了清除这个线程中的一些混乱,csc.exe将内联MSIL调用 - 虽然JITter(可能)会更积极。

[1] And, by waste - I mean that (a) that it defeats the purpose of the inlining (better performance) because of the Reflection lookup. And (b), it'd probably change the inlining behavior so that it's no longer inlined anyway. And, before you think you can just turn it on Debug builds with an Assert or something - realize that it will not be inlined during Debug, but may be in Release.

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

#9


Is there a way to force the compiler to inline this call or will I do I just hope that the compiler will do this optimization?

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

If it is cheaper to inline the function, it will. So don't worry about it unless your profiler says that it actually is a problem.

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

For more information

欲获得更多信息

JIT Enhancements in .NET 3.5 SP1

.NET 3.5 SP1中的JIT增强功能