Pourquoi l'ordre dans lequel les méthodes C# dans .NET 4.0 sont juste-à-temps compilé une incidence sur la rapidité de leur exécution? Par exemple, considérons deux méthodes équivalentes:
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);
}
La seule différence est l'introduction d'une variable locale, ce qui affecte le code assembleur généré et la performance de la boucle. Pourquoi c'est le cas c'est une question dans son propre droit.
Peut-être même étrange, c'est que sur x86 (mais pas x64), l'ordre dans lequel les méthodes sont invoquées a environ 20% de l'impact sur les performances. Appeler les méthodes comme ça...
static void Main()
{
SingleLineTest();
MultiLineTest();
}
...et SingleLineTest
est plus rapide. (Compiler à l'aide de la Version x86 de configuration, assurant que "Optimiser le code", le réglage est activé, et exécutez le test de l'extérieur de VS2010.) Mais inverser l'ordre...
static void Main()
{
MultiLineTest();
SingleLineTest();
}
...et les deux méthodes prennent le même temps (ou presque, mais pas tout à fait, tant que MultiLineTest
avant). (Lors de l'exécution de ce test, il est utile d'ajouter des appels à l' SingleLineTest
et MultiLineTest
pour obtenir des échantillons supplémentaires. Combien et de quel ordre n'a pas d'importance, sauf pour lequel la méthode est appelée en premier.)
Enfin, pour démontrer que JIT l'ordre est important, laissez MultiLineTest
première, mais à force SingleLineTest
à JITed première...
static void Main()
{
RuntimeHelpers.PrepareMethod(typeof(Program).GetMethod("SingleLineTest").MethodHandle);
MultiLineTest();
SingleLineTest();
}
Maintenant, SingleLineTest
est plus rapide encore.
Si vous désactivez "Supprimer JIT sur l'optimisation de charger le module" dans VS2010, vous pouvez placer un point d'arrêt en SingleLineTest
et de voir que l'assemblée de code dans la boucle est la même quel que soit JIT ordre; toutefois, l'assemblée de code au début de la méthode varie. Mais comment c'est important quand la majeure partie du temps est passé dans la boucle est perplexe.
Un exemple de projet en démontrant ce comportement est sur github.
Il n'est pas clair comment ce comportement affecte les applications du monde réel. Une préoccupation est qu'il peut faire le réglage des performances volatiles, selon l'ordre des méthodes d'arriver à être appelée en premier. Des problèmes de ce genre serait difficile à détecter à l'aide d'un profileur. Une fois que vous avez trouvé les points chauds et optimisé leurs algorithmes, il serait difficile de le savoir sans beaucoup de deviner et vérifier si d'autres speedup est possible par JITing méthodes tôt.
Mise à jour: Voir aussi le Microsoft Connect à l'entrée de ce problème.