Cuando es un método elegible para ser insertados por el CLR?


He observado una gran cantidad de código "introspectivo de pila" en las aplicaciones, que a menudo se basan implícitamente en sus métodos de contenido no que están en línea para su corrección. Tales métodos comúnmente implican llamadas a:

  • MethodBase.GetCurrentMethod
  • Assembly.GetCallingAssembly
  • Assembly.GetExecutingAssembly

Ahora, encuentro que la información que rodea a estos métodos es muy confusa. He oído que el tiempo de ejecución no insertará un método que llame a GetCurrentMethod, pero no puedo encontrar ninguna documentación para ese efecto. He visto publicaciones en StackOverflow en varias ocasiones, como this one , lo que indica que el CLR no hace llamadas de ensamblado cruzado en línea, sino que GetCallingAssembly la documentación indica claramente lo contrario.

También está el muy difamado [MethodImpl(MethodImplOptions.NoInlining)], pero no estoy seguro de si el CLR considera que esto es una "solicitud" o un "comando."

Tenga en cuenta que estoy preguntando acerca de la inclusión elegibilidad desde el punto de vista del contrato, no acerca de cuándo es actual las implementaciones del JITter declinan considerar los métodos debido a dificultades de implementación, o cuando el JITter finalmente termina eligiendo para alinear un método elegible después de evaluar las compensaciones. He leído este y este, pero parecen estar más centrados en los dos últimos puntos (hay menciones pasajeras de MethodImpOptions.NoInlining y "exotic IL instructions", pero estos parecen presentarse como heurísticas en lugar de como obligaciones).

¿Cuándo se permite que el CLR entre en línea?

Author: Community, 2011-01-11

4 answers

Es un detalle de implementación de jitter, los jitters x86 y x64 tienen reglas sutilmente diferentes. Esto se documenta casualmente en las publicaciones de blog de los miembros del equipo que trabajaron en el jitter, pero los equipos ciertamente se reservan el derecho de alterar las reglas. Parece que ya los encontraste.

Los métodos de incrustación de otros ensamblados ciertamente están soportados, muchas de las clases.NET funcionarían bastante miserablemente si ese no fuera el caso. Se puede ver en el trabajo cuando se mira el código de la máquina generado para Consola.WriteLine(), a menudo se entre líneas cuando se pasa una cadena simple. Para ver esto por ti mismo, necesitas cambiar a la versión de compilación y cambiar una opción de depurador. Herramientas + Opciones, Depuración, General, desmarcar "Suprimir optimización JIT en la carga del módulo".

De lo contrario, no hay una buena razón para considerar MethodImpOptions.No en la línea difamada, es más o menos por eso que existe en primer lugar. De hecho, se utiliza intencionalmente en el. NET framework en muchos pequeños métodos públicos que llaman a un método auxiliar interno. Hace que los rastros de pila de excepciones sean más fáciles de diagnosticar.

 23
Author: Hans Passant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-11 18:06:38

A pesar de la respuesta de Hans Passant, aquí primero un par de pistas a partir de 2004, y más abajo algo de información más actualizada. Están sujetas a cambios, pero te dan una idea de qué buscar si quieres hacer que un método sea elegible para la inclusión:

El JIT no se insertará:

  • Métodos marcados con MethodImplOptions.NoInlining
  • Métodos mayores de 32 bytes de IL
  • Métodos virtuales
  • Métodos que toman una tipo de valor grande como parámetro
  • Métodos sobre las clases MarshalByRef
  • Métodos con diagramas de flujo complicados
  • Métodos que cumplen otros criterios más exóticos

En particular, hay MethodImplOptions.AggressiveInlining, que se supone que eleva el límite de 32 bytes (o lo que sea que suceda en estos días y para su plataforma).

. NET 3.5 agregó heurísticas que le ayudan a determinar si En Línea o no en Línea, lo cual es probablemente una buena cosa, aunque hace que sea más difícil para el desarrollador predecir la decisión del jitter:

Una cita del artículo:

  1. Si la inserción hace que el código sea más pequeño que la llamada que reemplaza, siempre es bueno. Tenga en cuenta que estamos hablando del tamaño del código NATIVO, no el tamaño del código IL (que puede ser muy diferente).

  2. Cuanto más se ejecute un sitio de llamada en particular, más se beneficiará de inlning. Así código en bucles merece ser incluido más que el código que no está en bucles.

  3. Si la inserción expone optimizaciones importantes, entonces la inserción es más deseable. En particular métodos con argumentos de tipos de valor beneficiarse más de lo normal debido a optimizaciones como esta y por lo tanto tener un sesgo para alinear estos métodos es bueno.

Así, la heurística que usa el compilador JIT X86 es, dada una candidato.

  1. Estimar el tamaño del sitio de la llamada si el método no estaban alineadas.

  2. Estimar el tamaño del sitio de la llamada si estuviera inlineado (esta es una estimación basada en el IL, empleamos una máquina de estado simple (Markov Modelo), creado usando muchos datos reales para formar esta lógica de estimador)

  3. Calcula un multiplicador. Por defecto es 1

  4. Aumentar el multiplicador si el código está en un bucle (la actual heurística golpes a 5 en un bucle)

  5. Aumentar el multiplicador si se ve como struct optimizaciones se desataran.

  6. If InlineSize

 6
Author: Eugene Beresovsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-21 22:32:28

Mientras que la respuesta de Hans es correcta, hay una omisión, no necesariamente acerca de cuándo un método es elegible para la inserción, pero cuando un método es no.

Los métodos abstractos y virtuales no son elegibles para la inserción en el CLR.

Es importante tener en cuenta que reduce las condiciones bajo las cuales un método puede ser inlineado.

 3
Author: casperOne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:04

Hay más información sobre la inserción de MethodBase.GetCurrentMethod en este hilo http://prdlxvm0001.codify.net/pipermail/ozdotnet/2011-March/009085.html

Parafraseando fuertemente, indica que el RefCrawlMark NO impide que el método de llamada esté inlineado. Sin embargo, RequireSecObject tiene el efecto secundario de detener la llamada que está en línea.

Además, la Asamblea.GetCallingAssembly y Montaje.Los métodos GetExecutingAssembly NO tienen esto atributo.

 1
Author: stew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-09 00:03:30