2013-09-06 12 views
5

Ten Java method przyzwyczaja się odniesienia do symulowania powolnego obliczeń:Dlaczego ta metoda nie jest zoptymalizowana?

static int slowItDown() { 
    int result = 0; 
    for (int i = 1; i <= 1000; i++) { 
     result += i; 
    } 
    return result; 
} 

To IMHO bardzo zły pomysł, ponieważ jego organizm może się wyrazami return 500500. To wydaje się nigdy nie zdarzyć; prawdopodobnie dlatego, że taka optymalizacja jest nieistotna dla prawdziwego kodu, jak stwierdził Jon Skeet.

Co ciekawe, nieco prostsza metoda z result += 1; zostaje całkowicie zoptymalizowana (raport z suwakiem 0,460543).

Ale nawet jeśli zgodzimy się, że optymalizacja dala metod powracających stałą wynik jest bezużyteczny dla prawdziwego kodu, jest jeszcze rozwijanie pętli, które mogłyby prowadzić do czegoś jak

static int slowItDown() { 
    int result = 0; 
    for (int i = 1; i <= 1000; i += 2) { 
     result += 2 * i + 1; 
    } 
    return result; 
} 

Więc moje pytanie pozostaje: dlaczego ma optymalizacja występował tutaj?

Wbrew temu, co napisałem pierwotnie; Musiałem zobaczyć coś, czego nie było.

+1

Jak to sprawdzić? Jeśli korzystasz z JIT, prawdopodobnie zauważysz podobne rzeczy, nieznacznie zmieniając kod, ponieważ w grę wchodzi wiele heurystyk. Nie masz gwarancji, że JIT zastosuje nawet najprostsze optymalizacje, takie jak inline, ponieważ robi to tylko raz, gdy uzna to za konieczne. –

+0

Czy to jest prawdziwy kod? Jeśli wiesz, co ma powrócić, dlaczego nie napisać kodu w ten sposób? Cieszę się, że kompilatory JIT zostały zoptymalizowane pod kątem * prawdziwego * kodu, zamiast optymalizacji kodu, który nie pojawiłby się w rzeczywistości. (Optymalizatory statyczne mają nieco większą swobodę niż to, ale pamiętaj, że każda optymalizacja, którą próbuje znaleźć kompilator JIT, wiąże się z kosztem w czasie wykonywania *.) –

+0

@ JonSkeet: Zauważam, zawstydzająco, że link kieruje do kodu testu porównawczego Guava, który Normalnie mam nadzieję zaufać ... –

Odpowiedz

3

Cóż, JVM ma zoptymalizować taki kod. Pytanie brzmi, ile razy musi zostać wykryte jako prawdziwy hotspot (testy porównawcze robią zwykle więcej niż ta pojedyncza metoda), zanim zostanie to przeanalizowane w ten sposób. W mojej konfiguracji wymagało 16830 wywołań, zanim czas wykonania osiągnął (prawie) zero.

To prawda, że ​​taki kod nie pojawia się w prawdziwym kodzie. Jednak może pozostać po kilku operacjach wstawiania innych hotspotów zajmujących się wartościami nie będącymi stałymi w czasie kompilacji, ale stałymi w czasie wykonywania lub stałymi de facto (wartości, które mogą ulec zmianie w teorii, ale praktycznie nie występują). Gdy taki kod pozostaje, wielką korzyścią jest jego optymalizacja w całości, ale nie oczekuje się, że nastąpi to niedługo, to jest przy wołaniu bezpośrednio z głównej metody.

Aktualizacja: Uprościliśmy kod, a optymalizacja pojawiła się jeszcze wcześniej.

public static void main(String[] args) { 
    final int inner=10; 
    final float innerFrac=1f/inner; 
    int count=0; 
    for(int j=0; j<Integer.MAX_VALUE; j++) { 
    long t0=System.nanoTime(); 
    for(int i=0; i<inner; i++) slowItDown(); 
    long t1=System.nanoTime(); 
    count+=inner; 
    final float dt = (t1-t0)*innerFrac; 
    System.out.printf("execution time: %.0f ns%n", dt); 
    if(dt<10) break; 
    } 
    System.out.println("after "+count+" invocations"); 
    System.out.println(System.getProperty("java.version")); 
    System.out.println(System.getProperty("java.vm.version")); 
} 
static int slowItDown() { 
    int result = 0; 
    for (int i = 1; i <= 1000; i++) { 
     result += i; 
    } 
    return result; 
} 

...

execution time: 0 ns 
after 15300 invocations 
1.7.0_13 
23.7-b01 

(64Bit Server VM)

+0

Czy możesz napisać kod? Ciekaw jestem, jak to się stało, że wszystko zostało zoptymalizowane - napisałem, że myślałem, że to też mi się przydarzyło, ale teraz myślę, że widziałem coś, czego tam nie było. – maaartinus

+0

Wygląda na to, że metoda zostanie zoptymalizowana * z dala *, a nie zoptymalizowana (czyli złożona do stałej). Próbowałem czegoś takiego jak 'x + = slowItDown()' i wypisałem 'x' na końcu, a czas nie sięgał poniżej 300 ns. Odpowiada to temu, co napisałeś; po prostu byłem bardziej ciekawy składania (ponieważ to zniszczyłoby benchmark, z którego wybrałem metodę). – maaartinus