Update: da die Bloggingplatform mir nicht mehr die Möglichkeit bietet embedded Javascript zu nutzen, habe ich den Blog auf meinen privaten (kaum gepflegten) Blog gestellt, so dass die Demos dort getestet werden können: http://st-s.info/?p=38.

Hier nun Teil 6 meiner Blogserie zum Troubleshooting des Internet Explorers.

Letzte Woche habe ich über das MakingOff von Cut the Robe berichtet. In dem Bericht erzählen die Entwickler zum Einen von ihrem Resource Loader und zum Anderen von dem Erfolgreichen Einsatz der Developer Tools, insb. des Profilers. Insb. auf diesen möchte ich hier eingehen und das grundsätzliche Vorgehen erklären.

Das Thema Resource Loader habe ich nicht ohne Grund angesprochen, denn Performance Probleme einer Webseite können letztlich aus drei Ursachen entstehen:

  1. Netzwerkprobleme, klingt eindeutig, wird jedoch häufig übersehen und sollte als erstes untersucht werden
  2. Ungeschickte Programmierung, sprich Einsatz eines Algorithmus, der entweder nicht für die Ausführungseinheit/compiler optimiert ist, oder schlicht langsame und/oder überflüssige Schritte
  3. Verklemmungen, bzw. allgemein Warteeinbußen

Heute möchte ich mich insb. um Punkt 2 kümmern und zeigen, wie mittels des Profilers problematische Strukturen/Funktionen erkannt und beseitigt werden können.

Hierfür habe ich ein winziges Demoscript erstellt, welches 4 unterschiedliche Implementierungen mit dem identischen Ergebnis erzeugt:

“Addiere 1 bis der gewünschte Maximalwert erreicht wird und gebe dies aus”. Der Maximalwert hier ist 10000000, wie gesagt, soll ja nur ein Beispiel sein.

Teste es selber:

Fastest (opti)Fast (+=)Slow (++)Slowest
Result:

Time:

Wobei die Addition wie folgt durchgeführt wird:

  • “Fastest” über “result = result +1”
  • “Fast” über “result +=1”
  • “Slow” über “result++”
  • “Slowest” über “result = result + stupidResult()” und stupidResult nichts anderes macht als “return 1”

Btw. sehr interessant zu sehen, welcher Browser am schnellsten Addieren kann! Winking smile

So, aber wie finde ich nun heraus, woran es genau liegt?

Dazu zur gewünschten Seite/Anwendung navigieren und per F12 die Developer Tools öffnen und zum Reiter “Profiler” wechseln:

image

Anschließend nun das Profiling mittels des Buttons starten. Dabei nicht wundern, dass

  1. während des Profilings das UI nicht upgedatet wird
  2. durch das Profiling die Ausführung stark verlangsamt wird
  3. Je nach Profilingaufwand die Berechnung der UI Ausgabe etwas dauern kann!

Vergleichen wir nun aus dem Beispiel die Ergebnisse der Aufzeichnung eines “Fastest” und des “Slowest” Run:

Fastest:
image

Slowest:
image

 

Der erste Blick sollte zu der größten “Inclusive Time” wandern, denn dies ist der Hauptverursache der Ausführungsdauer. Wenn die Funktion(en), die dort gefunden wird/werden “erwartet langsam” ist, dann ist es sinnvoll als nächstes den Fokus auf die Anzahl von Ausführungen zu richten.

Insb. im zweiten Screenshot fällt natürlich die hohe Anzahl Ausführungen der Funktion “stupidResult” auf. Zusammen mit der Zeit (wichtig: generell ist hier die Inclusive Time von Interesse, auch wenn die im Beispiel identisch ist mit der Exclusive Time) ergibt sich, dass hier knapp 43% der Zeit durch diese Funktion “verbraten” wird, auch wenn jede einzelne Ausführung “nur” 0,000608339 ms gebraucht hat.

Hier sieht man schön, dass “Kleinvieh auch Mist macht/en kann” Winking smile

D.h. der nächste Schritt wäre zu überprüfen, ob die Anzahl hier nicht durch Optimierung reduziert werden kann. Ggf. kann hier auch der Blick auf den Call tree zur Vereinfachung beitragen.

Aber auch die eigentliche Funktion “Calculate” kann optimiert werden, wie die 3 unterschiedlichen Buttons zeigen. Um zu demonstrieren, dass durch etwas mehr Optimierung die Zeit noch deutlich weiter reduziert werden kann, hier noch zwei weitere Buttons:

Incredible :PFaster fastest
Result:

Time:

Auch wenn dies natürlich nur ein einfaches Beispiel ist, kann man sehr schön erkennen, dass zwar die Nutzung von objektorientierten Ideen und Verhalten aus “echten” Programmiersprachen nicht immer für die Performance ideal ist. Manchmal ist “unschön” leider auch “schneller”, sprich hier ist die Auslagerung in eine eigene Funktion überhaupt nicht sinnvoll. An vielen anderen Stellen hingegen schon, weil Funktionen i.d.R. auch nicht dermaßen oft aufgerufen werden und damit die Auslagerung nicht der Performance schadet, und dabei auch noch der Übersichtlichkeit/Wartbarkeit dient!