Dlaczego zamówienie JIT wpływa na wydajność?

Dlaczego kolejność, w jakiej metody C # w .NET 4.0 są kompilowane na czas, wpływa na szybkość ich wykonywania? Na przykład rozważ dwie równoważne metody:

<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>

Jedyną różnicą jest wprowadzenie zmiennej lokalnej, która wpływa na wygenerowany kod zespołu i wydajność pętli. Dlaczego tak jestpytanie samo w sobie.

Być może nawet dziwniejsze jest to, że na x86 (ale nie na x64) kolejność wywoływania metod ma około 20% wpływ na wydajność. Wywołaj takie metody ...

<code>static void Main()
{
    SingleLineTest();
    MultiLineTest();
}
</code>

...iSingleLineTest jest szybszy. (Skompiluj za pomocą konfiguracji wydania x86, upewniając się, że ustawienie „Optymalizuj kod” jest włączone i uruchom test z zewnątrz VS2010.) Ale odwróć kolejność ...

<code>static void Main()
{
    MultiLineTest();
    SingleLineTest();
}
</code>

... i obie metody zajmują ten sam czas (prawie, ale nie całkiem, tak długo jakMultiLineTest przed). (Podczas uruchamiania tego testu warto dodać dodatkowe połączenia doSingleLineTest iMultiLineTest uzyskać dodatkowe próbki. Ile i jaka kolejność nie ma znaczenia, z wyjątkiem tego, która metoda nazywa się najpierw.)

Wreszcie, aby pokazać, że kolejność JIT jest ważna, odejdźMultiLineTest po pierwsze, ale siłaSingleLineTest być najpierw JITem ...

<code>static void Main()
{
    RuntimeHelpers.PrepareMethod(typeof(Program).GetMethod("SingleLineTest").MethodHandle);
    MultiLineTest();
    SingleLineTest();
}
</code>

Teraz,SingleLineTest jest jeszcze szybszy.

Jeśli wyłączysz „Pomiń optymalizację JIT na obciążeniu modułu” w VS2010, możesz umieścić punkt przerwania wSingleLineTest i zobacz, że kod zespołu w pętli jest taki sam bez względu na kolejność JIT; jednakże kod zespołu na początku metody jest różny. Ale to, jak to ma znaczenie, gdy większość czasu spędza w pętli, jest kłopotliwe.

A przykładowy projekt demonstrujący to zachowanie jest na githubie.

Nie jest jasne, jak to zachowanie wpływa na rzeczywiste aplikacje. Jedną z obaw jest to, że może sprawić, że dostrajanie wydajności stanie się niestabilne, w zależności od tego, jakie metody kolejności zostaną wywołane. Problemy tego rodzaju byłyby trudne do wykrycia za pomocą profilera. Po znalezieniu hotspotów i zoptymalizowaniu ich algorytmów, trudno byłoby się domyślić bez większego zgadywania i sprawdzić, czy wczesne przyspieszenie jest możliwe dzięki metodom JIT.

Aktualizacja: Zobacz takżeWpis Microsoft Connect dla tego problemu.

questionAnswers(3)

yourAnswerToTheQuestion