¿Por qué el orden JIT afecta el rendimiento?
¿Por qué el orden en que los métodos de C # en .NET 4.0 se compilan justo a tiempo afecta la rapidez con la que se ejecutan? Por ejemplo, considere dos métodos equivalentes:
<code>public static void SingleLineTest() { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); int count = 0; for (uint i = 0; i < 1000000000; ++i) { count += i % 16 == 0 ? 1 : 0; } stopwatch.Stop(); Console.WriteLine("Single-line test --> Count: {0}, Time: {1}", count, stopwatch.ElapsedMilliseconds); } public static void MultiLineTest() { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); int count = 0; for (uint i = 0; i < 1000000000; ++i) { var isMultipleOf16 = i % 16 == 0; count += isMultipleOf16 ? 1 : 0; } stopwatch.Stop(); Console.WriteLine("Multi-line test --> Count: {0}, Time: {1}", count, stopwatch.ElapsedMilliseconds); } </code>
La única diferencia es la introducción de una variable local, que afecta el código de ensamblaje generado y el rendimiento del bucle. Porque ese es el caso es unpregunta por derecho propio.
Posiblemente, incluso más extraño es que en x86 (pero no en x64), el orden en que se invocan los métodos tiene un impacto de alrededor del 20% en el rendimiento. Invoca los métodos como este ...
<code>static void Main() { SingleLineTest(); MultiLineTest(); } </code>
...ySingleLineTest
es más rápido. (Compile utilizando la configuración de la versión x86, asegúrese de que la configuración "Optimizar código" esté habilitada y ejecute la prueba desde fuera de VS2010). Pero invierta el orden ...
<code>static void Main() { MultiLineTest(); SingleLineTest(); } </code>
... y ambos métodos toman el mismo tiempo (casi, pero no del todo, siempre queMultiLineTest
antes de). (Al ejecutar esta prueba, es útil agregar algunas llamadas adicionales aSingleLineTest
yMultiLineTest
para obtener muestras adicionales. Cuántos y qué orden no importa, excepto por qué método se llama primero.)
Finalmente, para demostrar que el orden JIT es importante, dejarMultiLineTest
primero, pero fuerzaSingleLineTest
ser JITed primero ...
<code>static void Main() { RuntimeHelpers.PrepareMethod(typeof(Program).GetMethod("SingleLineTest").MethodHandle); MultiLineTest(); SingleLineTest(); } </code>
Ahora,SingleLineTest
es más rápido de nuevo.
Si desactiva "Suprimir optimización JIT en la carga del módulo" en VS2010, puede poner un punto de interrupción enSingleLineTest
y ver que el código de ensamblaje en el bucle es el mismo independientemente del orden JIT; sin embargo, el código de ensamblaje al principio del método varía. Pero cómo esto importa cuando la mayor parte del tiempo que se pasa en el bucle es desconcertante.
A proyecto de muestra que demuestra este comportamiento está en github.
No está claro cómo este comportamiento afecta a las aplicaciones del mundo real. Una de las preocupaciones es que puede hacer que el ajuste del rendimiento sea volátil, dependiendo de los métodos de orden que se llamen primero. Los problemas de este tipo serían difíciles de detectar con un perfilador. Una vez que haya encontrado los puntos de acceso y haya optimizado sus algoritmos, sería difícil saberlo sin mucha conjetura y verificar si es posible acelerar más rápidamente con los métodos de JITing.
Actualizar: Ver también laEntrada de Microsoft Connect para este problema