© Excellent backgrounds/Shutterstock.com
Kolumne: Java-Trickkiste

Microbenchmarking


von Arno Haase

Performancemessungen sind notorisch schwierig. Je kürzer ein Stück Code läuft, desto schwieriger wird es, sinnvolle Werte zu ermitteln. Und wenn es um einige wenige Statements geht, überdecken die Effekte des Messens leicht das Verhalten des zu messenden Codes.

Naive Messungen

Listing 1 zeigt einen naiven Ansatz dazu, wie lange das Ermitteln einer Zufallszahl dauert. Der Code ruft vor und nach dem zu messenden Aufruf jeweils System.nanoTime() auf und gibt die Differenz der beiden Zeitstempel aus. Dieser Ansatz ist leicht zu verstehen. Er liefert aber keine nützlichen Ergebnisse, weil er eine Reihe von Faktoren außer Acht lässt:

  • Die JVM übersetzt den Bytecode zur Laufzeit („Just in Time“) in Maschinensprache. HotSpot tut das z. B. per Default erst, wenn ein Stück Code 1 000 Mal aufgerufen wurde. Bis dahin wird der Bytecode interpretiert, was erheblich langsamer ist. Meistens interessiert man sich für die Performance des übersetzten Codes; Listing 1 gibt der JVM keine Zeit zum Aufwärmen.

  • Ein einziger Aufruf von random.nextInt() braucht – wenn HotSpot ihn optimiert hat – nur wenige Nanosekunden. Wenn das Betriebssystem in dieser Zeit aktiv wird – Interrupts, Thread Scheduling etc. – dann sind diese Effekte sehr viel größer als der eigentliche Messwert. Man sollte für die Messung den Aufruf häufig wiederholen, dann fallen solche Effekte weniger ins Gewicht.

  • Schließlich sollte man die gesamte Messung mehrmals wiederholen, um zu sehen, wie groß die statistischen Schwankungen sind. Wenn bei drei aufeinanderfolgenden Messungen praktisch die gleichen Werte herauskommen, sind diese Werte wahrscheinlich genauer, als wenn sie um einen Faktor zwei auseinanderliegen.

Listing 1

final Random random = new Random(); final long start = System.nanoTime (); random.nextInt (); final long end = System.nanoTime (); System.out.println (end - start);

Etwas weniger naive Messungen

Ein Lösungsansatz besteht darin, die Messung in eine Methode auszulagern und den zu messenden Code in einer Schleife auszuführen (Listing 2). Man muss diese Methode dann mehrmals nacheinander aufrufen – der erste Aufruf dient dem Aufwärmen von HotSpot, und die darauffolgenden Aufrufe liefern dann mehrere Messwerte. Dieser Code liefert sicherlich weniger schlechte Zahlen als der erste naive Ansatz. Er hat aber immer noch einige Probleme.

Listing 2

static void doMeasure() { final long start = System.nanoTime (); for (int i=0; i<1_000_000; i++) { random.nextInt (); } final long end = Syst...

Neugierig geworden?

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang