iText Performance Optimierung mit AppDynamics und YourKit

Keine Kommentare

Wie sinnvoll sich eine Performance Monitoring Lösung mit einem Profiler verbinden lässt, kann man ganz anschaulich an folgendem Beispiel feststellen.
Bei meinem regelmäßigen Rundgang durch das bei uns in der Continuous Integration Umgebung mitlaufende AppDynamics fand ich einen interessanten HotSpot in iText.
Mittels iText, einer früher komplett freien, mittlerweile teilweise kommerziellen Java Bibliothek, kann man sehr leicht PDFs auslesen. Dafür verwendet man einfach einen PDFReader:

PdfReader reader = new PdfReader(filename);

Wirklich problemlos!
Jedenfalls scheinbar. Den von mir gefundenen Hotspot kann man in folgendem Screenshot aus AppDynamics leicht selbst entdecken:

[singlepic id=336 w=560 float=]

In diesem Fall gehen fast 20% der Gesamtzeit durch das Öffnen von 2 PDFs verloren. Meine Neugierde war geweckt. Was passiert dort?

Der Invocation Trace zeigt, dass im Constructor des PdfReader ein PRTokeniser erstellt wird, der ein RandomAccessFileOrArray erstellt. Dort wird dann entweder ein RandomAccessFile oder ein MappedRandomAccessFile erstellt. Letzteres liest über einen FileChannel die Datei direkt in den Arbeitsspeicher. Wenn das als langsam gefunden wurde, ist das vielleicht gar keine so gute Idee, dachte ich mir und begann meine Suche nach einer Alternative.

Also war ein kleines Microbenchmark für unsere Funktion, welche die in dem PDF enthaltenen Felder ausliest, geschrieben.
Nach 3000 warmup Aufrufe folgten 10000 gemessene Aufrufe und ergaben 12,3 Sekunden auf meiner Maschine (Win 7 32bit, Java 1.6.20, -server).
Um besser zu verstehen was passiert, ließ ich YourKit als Profiler mitlaufen. Dieser berichtete mir am Schluss:

Die gesuchte Alternative zum Ausprobieren fand ich in einem Constructor, der ein RandomAccessFileOrArray entgegen nimmt, so dass ich dort eine andere Implementierung zum Dateiauslesen versuchen kann. Mit möglichst kleinen Schritten wollte ich mich dem Thema nähen und tat das was sonst der Code im „filename-Constructor“ tun würde:

PdfReader reader = new PdfReader(new RandomAccessFileOrArray(filename), null);

Doch zu meiner Überraschung stellte ich fest, dass nun die 10k Durchläufe weniger als die Hälfte der Zeit benötigten: 5,8 Sekunden. Und das obwohl ich doch nichts Anderes tat als vorher?
Was war da passiert? Nun die Javadoc dieses Konstruktors des PdfReaders sagt es bereits:

/**
* Reads and parses a pdf document. Contrary to the other constructors only the xref is read
* into memory. The reader is said to be working in "partial" mode as only parts of the pdf
* are read as needed.
**/

Aha, interessant. Könnte für meinen Anwendungszeck des reinen Felderauslesens sogar erheblich performanter sein.

Bestätigt wird dies durch YourKit. Keine Spur mehr von den teuren Konstruktoren:

Ganz offensichtlich ist diese Variante wesentlich schneller. Zwar war dies nicht die Stelle nach der ich gesucht hatte, jedoch sollte man bei Performance auch gerne mal nach den tiefhängenden Früchten greifen. Zumal die Stelle an der die Korrektur erfolgt, oft nicht genau die im Profiler oder Monitor gesehene Stelle ist.
Seit dieser Optimierung haben wir nie wieder eine langsame Codeausführung in unserem PDFServide entdecken können.

Ich denke dieses Beispiel zeigt ganz anschaulich wie man sinnvoll Performanceoptimierungen durchführen kann:

  1. Permanente Messung in Produktion und Test.
  2. Analyse von Ausreißern und Anaomalien.
  3. Evaluierung alternativer Implementierungen im Bereich der Anomalie mit einem Profiler.
  4. Wenige einfache Änderungen mit großer Wirkung durchführen.
  5. Weiter beobachten.

Tags

Fabian Lange ist Lead Agent Engineer bei Instana und bei der codecentric als Performance Geek bekannt. Er baut leidenschaftlich gerne schnelle Software und hilft anderen dabei, das Gleiche zu tun.
Er kennt die Java Virtual Machine bis in die letzte Ecke und beherrscht verschiedenste Tools, die JVM, den JIT oder den GC zu verstehen.
Er ist beliebter Vortragender auf zahlreichen Konferenzen und wurde unter anderem mit dem JavaOne Rockstar Award ausgezeichnet.

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.