November 2007 Performance Day @ JUGS Schneller mit AspectJ Oliver.Boehm@agentes.de
Wir über uns Gründung 01.04.2004 Vorstand Olaf Ahl & Wolfgang Clauss Standorte Stuttgart (Firmensitz), Kassel, München und Hamburg Aktionäre PIRONET NDH AG, Köln (börsennotiert) agentes Management Kassel Hamburg Mitarbeiter 110 Ergebnis Stuttgart 2004: 2005: 2006: Umsatz Umsatz Umsatz 8,6 Mio. EUR 8,7 Mio. EUR 10,7 Mio. EUR EBIT EBIT EBIT 0,834 Mio. 0,850 Mio. 2,2 Mio. München 2
Inhalt Profiling mit Java Bordmittel Instrumentierung über AspectJ Poor Man's Profiler (JaMon) Rich Man's Profiler (kommerzielle Profiler) Optimierungs-Strategien mit AspectJ 3
Profiling mit Java Bordmittel 4
Beispiel: einfache Zeitmessung long t = System.currentTimeMillis(); // hier kommt jetzt der zu messende Code... t = System.currentTimeMillis() t; log.info(" Vorgang dauerte " + t + " ms")); s. WebRobot1/src/web/Robot.java 5
Beispiel: Speicherverbrauch long mem = getfreememory(); // hier kommt jetzt der zu messende Code... mem = mem getfreememory(); log.info(" Speicherverbrauch: " + mem + " Bytes");... private static long getfreememory() { System.gc(); return Runtime.getRuntime().freeMemory(); } 6
Probleme Garbage Collector große Unbekannte kann Zeitmessung verfälschen expliziter Aufruf möglich, aber keine Garantie nur grobe Speichermessung Zeitmessung hängt von der internen Timer-Auflösung ab meist nur als Richtwert zu sehen aber: für einfache (Vergleichs-) Messungen ausreichend 7
Tipps Warmup Startup-Time ausfiltern Caches befüllen Messung sollte nicht zu kurz sein auf andere Prozesse achten (Verfälschung) mind. 10-fache Timer-Auflösung (Ungenauigkeit: 10%) nicht unter Windows messen geringe Timer-Auflösung (ca. 16 ms) damit nur geeignet für ältere (langsamere) Rechner Linux System.currentTimeMillis() im ms-bereich System.nanoTime() (seit Java 5) MacOS-X (noch) nicht ausprobiert 8
Instrumentierung mit AspectJ 9
Schritt 1: Logik herausziehen void around() : Messpunkte() { long t = System.currentTimeMillis(); try { proceed(); // eigentlicher Aufruf } finally { t = System.currentTimeMillis() t; log.info(thisjoinpoint + ": " + t + " ms"); } } s. WebRobot2/src/web/ProfilerAspect.aj 10
Schritt 2: Messpunkte definieren // alle Robot.ping() Methoden pointcut Messpunkte() : execution(public void Robot.ping(..)); // oder: alle Robot Methoden pointcut Messpunkte() : execution(public void Robot.*(..)); s. WebRobot2/src/web/ProfilerAspect.aj 11
JaMon (poor man's profiler) 12
Was ist JaMon? Framework für Zeitmessungen JDBC/SQL-Monitoring HTTP- und EJB-Monitoring 13
Einbindung Object around() : Messpunkte() { Monitor mon = MonitorFactory.start(thisJoinPoint.toString()); try { return proceed(); } finally { mon.stop(); log.info(mon); } } s. WebRobot3/src/web/ProfilerAspect.aj 14
Auswertung MonitorComposite rootmonitor = MonitorFactory.getRootMonitor(); Monitor[] monitors = rootmonitor.getmonitors(); for (int i = 0; i < monitors.length; i++) { System.out.println(monitors[i]); } s. WebRobot3/src/web/ProfilerStatistics.java 15
jamonadmin.jsp 16
Optimierungsstrategien mit AspectJ 17
Was kostet Zeit? teure Resourcen anfordern und (zu früh) freigeben Abhilfe: Pooling unnötige Zerstörung teurer Objekte Problem: teure Kreierung Abhilfe: Caching Problem muss von Anfang an in der Architektur vorgesehen werden nachträglicher Einbau möglich, aber schwierig Lösung Einbau durch AspectJ 18
Beispiel: Verbindungsaufbau Socket aufbauen (teuer): Socket socket = new Socket(hostname, 80); Socket lesen / schreiben Socket freigeben socket.close(); Problem Freigabe: Hmm, vielleicht brauche ich den Socket noch andererseits: nicht benötigte Resourcen sollten freigegeben werden Abhilfe Socket-Pooling lohnt sich aber nur, wenn ich viele Verbindungen habe!!! nächstes Problem: aber da muss ich ja alle Socket-Kreierungen abändern :-( 19
Lösung: SocketPoolingAspect /** * Pointcut fuer das Oeffnen bzw. Anlegen eines Sockets */ pointcut socketcreation(string host, int port) : call(public Socket.new(String, int)) && args(host, port) &&!within(socketpool); /** * Pointcut fuer das Schliessen eines Sockets */ pointcut socketclose(socket socket) : call(public void Socket.close()) && target(socket) &&!within(socketpool); s. WebRobot4/src/web/SocketPoolingAspect.java 20
Lösung: SocketPoolingAspect (2) /** * Das Oeffnen eines Sockets erfolgt nun ueber den socketpool. * Falls dies fehlschlaegt, wird der Original Pointcut aufgerufen. */ Socket around(string host, int port) throws UnknownHostException, IOException : socketcreation(host, port) { Socket socket = socketpool.getsocket(host, port); if (socket == null) { return proceed(host, port); } else { return socket; } } s. WebRobot4/src/web/SocketPoolingAspect.java 21
Zusammenfassung (einfaches) Profiling bereits mit Java- Bordmittel möglich etwas komfortabler geht es mit JaMon AOP/AspectJ kann bei der Instrumentierung helfen Performance-Probleme sind oft Architektur-Probleme! AOP/AspectJ kann bei Architektur- Problemen helfen nachträgliches Einfügen von Caching- /Pooling-Strategien allg.: nachträgliches Einfügen von Zwischen-Schichten immer noch zu langsam? Warten auf neue Hardware,... wie wär's mit Assembler? Was man nicht in Assembler machen kann, muss man löten! 22
neugierig auf AOP? Oliver Böhm Aspektorientierte Programmierung mit AspectJ 5 http://www.dpunkt.de/buch/3-89864-330-1.html die Seite zum Buch / AOP-Ecke http://www.aosd.de http://www.agentes.de/aop/ SIG-AspectJ s. http://www.jugs.org/forum.html Ramnivas Laddad AspectJ in Action Manning Publications Co., 2003, ISBN 1-930110-93-6 PatternTesting http://patterntesting.sf.net 23
Vielen Dank Oliver Böhm ob@jugs.org oliver.boehm@agentes.de http://oli.blogger.de Telefon 0711/2012-2734 24