2009-03-05 11 views
23

Escribo un juego XNA donde realizo verificaciones de colisión por píxel. El bucle que comprueba esto lo hace desplazando un ORing interno y bit a bit y, por lo general, es difícil de leer y entender.¿Puedo verificar si el compilador de C# indicó una llamada a un método?

Me gustaría agregar métodos privados como private bool IsTransparent(int pixelColorValue) para hacer que el ciclo sea más legible, pero no quiero la sobrecarga de las llamadas a métodos ya que este es un código muy sensible al rendimiento.

¿Hay alguna manera de forzar al compilador a alinear esta llamada o lo haré solo espero que el compilador haga esta optimización?

Si no hay una manera de forzar esto, ¿hay alguna manera de verificar si el método estaba en línea, salvo por la lectura del desmontaje? ¿Aparecerá el método reflejado si estaba en línea y no existen otras personas que llaman?

Edit: No puedo forzarlo, ¿así que puedo detectarlo?

+1

Puede (en .Net 4.5). usando: '[MethodImpl (MethodImplOptions.AggressiveInlining)] ' – Mahmoodvcs

Respuesta

23

No, no puede. Aún más, el que decide en línea no es un compilador VS que toma el código y lo convierte en IL, sino un compilador JIT que toma IL y lo convierte en código máquina. Esto se debe a que solo el compilador JIT sabe lo suficiente sobre la arquitectura del procesador para decidir si es apropiado poner un método en línea, ya que es una compensación entre el encadenamiento de la instrucción y el tamaño de la caché.

Por lo tanto, mirar en .NET Reflector no lo ayudará.

+0

Otros piden diferir sobre la reflexión ya que usa la pila de llamadas. http://stackoverflow.com/questions/44153/can-you-use-reflection-to-find-the-name-of-the-currently-executing-method/44171#44171 –

+1

No dije el reflejo, yo dicho reflector, como en Red Gates .NET Reflector. –

+0

Malo, lo he entendido mal. –

1

No, no se puede.

Básicamente, tampoco puedes hacer eso en la mayoría de los compiladores modernos de C++. inline es solo una oferta para el compilador. Es gratis tomarlo o no.

El compilador C# no realiza ninguna alineación especial en el nivel IL. JIT optimizer es el que lo hará.

+0

" Si no hay una manera de forzar esto, ¿hay alguna manera de verificar si el método estaba en línea, sin leer el desmontaje? ¿Aparecerá el método en la reflexión? si estaba en línea y no existen otras personas que llaman? " –

+0

No, dudo que el compilador de C# haga ninguna alineación en absoluto. El compilador JIT es responsable de eso. –

+0

Puede marcar System.Reflection.MethodBase.GetCurrentMethod(). Name. Si el método está en línea, devolverá el nombre de la persona que llama. –

14

"Puede comprobar System.Reflection.MethodBase.GetCurrentMethod().. Nombre Si se colocarán en línea del método, se devolver el nombre de la persona que llama en su lugar."

- Joel Coehoorn

+0

Solo funcionará en tiempo de ejecución. –

+19

Por supuesto, solo funcionará en tiempo de ejecución, es decir, cuando se produce la internación. –

+10

¿No llama este método en su código para cambiar el IL real, lo que teóricamente cambiaría el "razonamiento" del compilador JIT si estuviera en línea o no? –

0

Puede detectarlo en tiempo de ejecución con la llamada GetCurrentMethod antes mencionada. Pero, eso parece ser un desperdicio [1]. Lo más fácil sería simplemente ILDASM el MSIL y verificar allí.

Tenga en cuenta que esto es específicamente para el compilador que engloba la llamada, y está cubierto en los diversos documentos Reflection en MSDN.

Si el método que llama al método GetCallingAssembly se expande en línea por el compilador (es decir, si el compilador inserta el cuerpo de la función en el lenguaje intermedio de Microsoft emitida (MSIL), en lugar de emitir una llamada de función), entonces el conjunto devuelto por el método GetCallingAssembly es el conjunto que contiene el código en línea. Esto podría ser diferente del ensamblaje que contiene el método original. Para asegurarse de que un método que llama al método GetCallingAssembly no esté en línea por el compilador, puede aplicar el atributo MethodImplAttribute con MethodImplOptions.NoInlining.

Sin embargo, el JITter también es gratuito para llamadas en línea, pero creo que un desensamblador sería la única forma de verificar lo que se hace y lo que no se hace en ese nivel.

Editar: Sólo para aclarar un poco de confusión en este hilo, csc.exe will inline MSIL calls - aunque el JITter (probablemente) sea más agresivo.

[1] Y, por desperdicio - me refiero a que (a) derrota el propósito de la alineación (mejor rendimiento) debido a la búsqueda de Reflexión. Y (b), probablemente cambiaría el comportamiento de alineación de modo que ya no esté en línea. Y, antes de que crea que puede activar las compilaciones de depuración con un Assert o algo así, tenga en cuenta que no se incluirá durante Debug, pero puede estar en Release.

+0

Sí, definitivamente es un desperdicio probar esto en tiempo de ejecución. Si estaba JIT en línea, probablemente había una buena razón para ello, y este control solo empeorará las cosas. Pero tomé esto como un ejercicio más de aprendizaje: él quiere 'experimentar' para sí mismo. –

1

por qué no utilizar el código inseguro (en línea c como se conoce) y utilizar punteros de estilo c/C++, esto está a salvo del GC (es decir, no se ve afectado por la colección) pero tiene sus propias implicaciones de seguridad (no se puede usar aplicaciones de la zona de Internet) pero es excelente para el tipo de cosas que parece que está tratando de lograr especialmente con el rendimiento y aún más con las matrices y las operaciones de bit a bit.

para resumir, ¿desea rendimiento para una pequeña parte de su aplicación? usar código inseguro y hacer uso de punteros, etc. me parece la mejor opción

EDITAR: ¿un poco de arranque? http://msdn.microsoft.com/en-us/library/aa288474(VS.71).aspx

+4

código no seguro es a menudo más lento que el código administrado, porque el JIT no puede hacer tantas garantías sobre su código por lo que no puede hacer ciertas optimizaciones. Entonces, si haces esto, como siempre, ** ¡perfil! ** –

0

¿Hay una manera de forzar al compilador que esta llamada inline o voy a hacer yo solo espero que el compilador va a hacer esta optimización?

Si es más barato alinear la función, lo hará. Así que no te preocupes, a menos que tu perfilador diga que realmente es un problema.

Para obtener más información

JIT Enhancements in .NET 3.5 SP1

4

Tenga en cuenta que la XBox funciona diferente.

un Google apareció esto:

"El método en línea que mitiga la sobrecarga de una llamada de un método formas JIT en una línea lo que cumple las siguientes condiciones

  • El código IL.. el tamaño es de 16 bytes o menos.
  • no se utiliza el comando branch (si frase, etc.).
  • La variable local no se utiliza.
  • El manejo de excepciones no se ha llevado a cabo (intente, atrape, etc.).
  • flotante no se utiliza como argumento valor de retorno de un método (probablemente por Xbox 360, no aplicado).
  • Cuando dos o más argumentos están en un método , se utiliza para el turno declarado.

Sin embargo, una función virtual no se forma en línea."

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

no tengo ni idea de si es correcta. Cualquier persona?

+0

Gracias por señalar esto. En realidad es bastante relevante para mí. Aunque sería bueno verlo en un documento oficial. –

1

La única manera de comprobar esto es para obtener o escribir un generador de perfiles, y enganchar en los eventos JIT, también debe hacer seguro inlining no se apaga, ya que es por defecto al perfilar

14

Hay una nueva manera de fomentar una mayor expansión en línea agresiva en .net 4.5 que se describe aquí:. http://blogs.microsoft.co.il/blogs/sasha/archive/2012/01/20/aggressive-inlining-in-the-clr-4-5-jit.aspx

Básicamente es sólo una bandera a te ll el compilador para en línea si es posible. Desafortunadamente, no está disponible en la versión actual de XNA (Game Studio 4.0) pero debe estar disponible cuando XNA alcance VS 2012 este año en algún momento. Ya está disponible si de alguna manera se ejecuta en 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; 
    } 
} 
Cuestiones relacionadas