1. Feinabstimmung für Ihr Lotusscript
Jens-B. Augustiny, LIGONET GmbH
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 1
2. Who is who?
● Jens-B. Augustiny, LIGONET GmbH
Biel, Schweiz / Sindelfingen
● Seit über 15 Jahren im Notes-Umfeld tätig
● Entwicklung und Administration
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 2
3. Agenda
● Was denken Sie, ist langsam?
– Wo tauchen Leistungsprobleme auf?
● Woher nur kommt das?
– Tips und Werkzeuge, die Schwachstellen zu
erkennen
● Nie mehr da durch!
– Tips zur Vermeidung von Leistungsschwächen
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 3
4. Was glauben Sie ist langsam?
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 4
5. Schlechte Leistung – was genau
meinen wir eigentlich?
● Schlechtes Programm ....
● Lieferzeiten statt Antwortzeiten
● Unmöglich damit zu arbeiten!
● Dieser Ablauf muss unbedingt
verbessert werden
● Wer hat diese Argumente nicht schon gehört?
● Stellen Sie sicher, dass Sie das richtige Problem
angehen!
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 5
6. 9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 6
7. Leistung – wovon eigentlich?
● Empfundene Leistung
● Der Benutzer empfindet, dass die Applikation nicht das
gewünschte Resultat liefert.
● Sehr schwer zu analysieren
● Mögliche Lösungen:
● Bessere Ausbildung der Benutzer: Funktionalität erklären
● Verbesserung der Wahrnehmung: Mehr Informationen während der
Verarbeitung oder der Dateneingabe
● Den Workflow überarbeiten und verbessern
● Das Empfinden der Benutzer kann stark beeinflussen, wie die
Leistung eingeschätzt wird: Frustrierende oder langwierige
Eingaben können als schlechte Leistung angekreidet werden
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 7
8. Reale Leistung
..... oder eher das Fehlen derselben ....
● Flaschenhälse, die durch Messung erkannt werden
● Fast unmöglich, diese vorauszusagen
● Unterschiede zwischen Test- und Produktionsumgebung
● Jede Aussage ohne Messung ist Spekulation
● Die Messung selbst kann das Resultat beeinflussen
● Enorm wichtig, Messdaten zu haben, bevor man etwas
ändert. Genau wie bei den Endusern haben auch
Entwickler ihre eigenen Ideen, welches die Ursache
von Problemen sein könnte ...
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 8
9. Beispiel
● Viermal derselbe Code
● 2 Variablen werden verändert: Die Loop-Logik und
die Art, wie auf die Datenbank-Eigenschaften
zugegriffen wird.
● Fragen:
– Welche der 4 Varianten ist die Schnellste?
– Warum ist die von Ihnen gewählte Variante schnell?
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 9
10. Der Beispielcode
Forall v In db.views u = Ubound(db.views)
A s = v.name
Print s
For i = 0 To u
s =db.Views(i).name
C
End Forall Print s
Next
tmpView = db.Views tmpView = db.Views
Forall v In tmpView u = Ubound(tmpView)
B s = v.name
Print s
For i = 0 To u
s =tmpView(i).name
D
End Forall Print s
Next
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 10
11. Resultate
Erster Lauf: B – D – A – C
Zweiter Lauf (caching): D – B – A – C
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 11
12. Folgerungen
● Ergebnisse können Ueberraschen
● Messungen sollten in realistischer Umgebung
durchgeführt werden
● Datenmenge und Datenstruktur sollte der Realität
entsprechen, die meisten Testumgebungen sind
ungenüngend
● Die Analyse muss extrem systematisch
durchgeführt werden, zB. systematische
Eingrenzung
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 12
13. Woher kommt das den alles?
●Sie benötigen aktuelle Werte, um
die Arbeit etwas aufzubessern zu
begründen. Woher sollen die
kommen?
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 13
14. Now für die Zeitmessung
● Beispiel:
BaseTime = Now
[.... Code hier ... ]
Print “Time used: “ & Now – BaseTime
● Vorteil:
– Einfach und billig
● Nachteile:
– Veränderung des Codes
– Platzierung ist kritisch
– Ungenügende Auflösung
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 14
15. High Resolution Timing -
GetThreadInfo()
● Von Brude Perry einst publizierter nicht dokumentierter
Funktionsaufruf, mittlerweile gilt das Verfahren als legal:
● http://searchdomino.techtarget.com/tip/1,289483,sid4_gci895240,00.html?FromTaxonomy=%2Fpr%2F283841
stc = GetThreadInfo(LSI_THREAD_TICKS) ' get the
starting tick count
'[....the code you want To Time...]
'get the final tick count
ftc = GetThreadInfo(LSI_THREAD_TICKS)
'get the ticks per second
tps = GetThreadInfo(LSI_THREAD_TICKS_PER_SEC)
'final tick count minus starting tick count divided by
ticks per second yields duration.
t = (ftc - stc) / tps
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 15
16. GetThreadInfo
● Vorteile:
– Einfache Implementierung
– Bessere Auflösung als Now
● Nachteile:
– Veränderung des Codes
– Falsche Platzierung ergibt falsche Resultate
– GetThreadInfo ist nicht garantiert vorhanden
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 16
17. Wie bekommt man die Resultate?
● PRINT: Resultat in der Statusleiste (Client) oder in
log.nsf (Server)
● Besser:
– Ausgabe in ein Dokument
– Ausgabe in ein Profile-Dokument
– Ausgabe in eine Analyse-Datenbank .... ähhh … Anwendung
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 17
18. Beispiel: Man mache es
wiederverwendbar
Class debugTimer
Private Start As Variant
Private fnName As String
Sub New( fn As String )
Set Start = Now
fnName = fn
End Sub
Sub Delete
Print fnName & " benötigte " & Now-Start & " Sekunden."
End Sub
End Class
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 18
19. Beispiel: Man mache es
wiederverwendbar
Sub Initialize()
Dim fnTime As New debugTimer( GetThreadInfo(LSI_THREAD_PROC) )
Dim i As Integer
While i < 1000
Print i
i = i + 1
Wend
End Sub
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 19
20. Systemeigenes Profiling
● Eingeführt mit Lotus Notes / Domino 7
® ® ®
● Nur für Agenten und Web Services
● Java und LotusScript
● Aktivierung in den Eigenschaften des Agenten/WS
● Resultate durch Rechtsklick auf Agent oder WS
● Es gibt nur Werte für reine Notes/Domino Objekte
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 20
21. Systemeigenes Profiling: Beispiel
Sub Initialize
Dim db As New NotesDatabase( "", "names.nsf" )
i = 0
Dim s As String
For i = 0 To UBound(db.views)
s =db.Views(i).name
Print s
Next
End Sub
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 21
24. Teamstudio Profiler
● Messung eigener Funktionen und Routinen
● Zeitangaben pro Zeile
● Eine Menge an zusätzlichen Analysewerten
● Server und Client
● LotusScript only
● Anwendung wird sehr stark verlangsamt
● Kostenpflichtig
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 24
26. Nein, ich will da nicht wieder durch
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 26
27. Häufige Probleme
● Hilfsmittel sind zwingend bei bestehenden
Programmen und Leistungsproblemen. Besser
ist jedoch, die Probleme von Anfang an zu
vermeiden.
● Manche Probleme sind reale Fehler, andere
häufig nur Sorglosigkeit
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 27
28. GetNthDocument()
● Durchlaufen einer Doc-Collection mit
GetNThDocument(n) ist bedeutend langsamer
als mit GetFirstDocument und
GetNextDocument (doc)
● Viel wurde darüber schon gesagt, einiges ist
online nachlesbar
● http://bobzblog.com/tuxedoguy.nsf/dx/getnth-revisited-helpful-function-or-spawn-of-the-devil
● http://www.lotusgeek.com/LotusGeek/LotusGeekBlog.nsf/d6plinks/ROLR-7HHPER
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 28
29. Ueberprüfen Sie Ihre Loops
found=False
Do Until (selected_doc Is Nothing)
If (selected_doc.Form(0)="fa_Term") Then
found=True
End If
Set selected_doc=term_collection.GetNextDocument(selected_doc)
Loop
Set selected_doc=term_collection.GetFirstDocument()
If Not(found=True) Then
MessageBox NO_TERM_DOCUMENTS_SELECTED_TO_DELETE, 16, DELETE_ERROR
Exit Sub
End If
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 29
30. … und korrigieren Sie die Fehler
found=False
Do Until (selected_doc Is Nothing)
If (selected_doc.Form(0)="fa_Term") Then
found=True
' loop sollte hier abgebrochen werden!!
End If
Set selected_doc=term_collection.GetNextDocument(selected_doc)
Loop
Set selected_doc=term_collection.GetFirstDocument()
If Not(found=True) Then
MessageBox NO_TERM_DOCUMENTS_SELECTED_TO_DELETE, 16, DELETE_ERROR
Exit Sub
End If
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 30
31. Fehler beheben: Verrotteter Code
● Tatsache ist, dass Code sich verändert:
man entdeckt bessere Wege
● Stellen Sie sicher, dass Codeänderungen zu Ende geführt werden, sonst kann
die Leistung leiden.
Sub Queryopen(...)
Dim session As New NotesSession
Set db = session.currentdatabase
Set view = db.getview("People")
Set ProfileDoc = db.getprofiledocument("PickerView")
' ProfileDoc.Pview = "People"
End Sub
● Die Variable “view” wird nirgends im Code verwendet. Db.Getview ist ein teurer
Funktionsaufruf, speziell dann, wenn das Resultat nie verwendet wird.
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 31
32. Achtung mit verschachtelten IF
● Anders als Sprachen wie C und Java wird
bei LotusScript immer die gesamte
Bedingung ausgewertet
x = 1
If x = 0 And checkresult( res ) = 0 Then
'do some stuff
End If
● Checkresult() wird in jedem Fall ausgeführt, auch wenn x nicht 0 ist.
Leistungsprobleme können sich in solch einfachen Anweisungen
verstecken.
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 32
33. Achtung mit verschachtelten IF:
die Lösung
x = 1
If x = 0 Then
If checkresult( res ) Then
'do some stuff
End If
End If
● Durch die Auflösung der Bedingung in zwei Aufrufe wirde Checkresult()
nur noch aufgerufen, wenn die erste Bedingung True ergibt.
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 33
34. Variablen – Variant ist langsamer
● Abgesehen davon, dass Variants
allgemein häufig zu Fehlern führen,
sind sie ausserdem sehr langsam.
● LotusScript muss bei jedem Zugriff den
Typ bestimmen und eine
Datenkonversion durchführen.
● Keine falsche Müdigkeit!
Option Declare gehört in jedes
LotusScript Programm
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 34
35. Loops – Es gibt schnellere und
langsamere
●Forall ist viel schneller beim Durchlauf von Arrays
●For ... Next ist schneller als Do ..... Loop oder While ..... Wend
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 35
36. Und was noch ....
● Zugriff auf ausgewählte Documente ist schneller
mit Hilfe einer Ansicht als einer Document
Collection
● Zugriff auf Notes Objecte ist schneller durch eine
temporäre Variable als durch einen Direktzugriff
– wenn man den Wert mehr als einmal benötigt.
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 36
37. Zusammenfassung
● Es gibt technische und nicht technische Gründe für
fehlende Performance
● Wenn es technische Gründe sind, ist jede Aussage ohne
Messung reine Spekulation
● Es gibt keine zwei gleiche Fälle
● Systematische Top down Analyse ist extrem wichtig
● Manchmal ist ein Redesign die beste Lösung
● Es gibt ein paar “best practices”
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 37
38. Danke!
Fragen?
●
Vielleicht gibt es sogar Antworten ..... :-)
Jens-B. Augustiny - LIGONET GmbH
augustiny.j@ligonet.ch
www.ligonet.ch
9. März 2010 Entwicklercamp 2010 / LIGONET GmbH 38