際際滷

際際滷Share a Scribd company logo
BP 206
Let's Give Your LotusScript a Tune-Up




   Craig Schumann  Senior Developer, Teamstudio

   Jens-B. Augustiny, CEO, LIGONET GmbH
Who is who?

    Craig Schumann, Senior Developer at Teamstudio

    Teamstudio is a producer of Development and Administration tools
    for IBM Lotus Notes and Domino



    Jens-B. Augustiny, CEO at LIGONET GmbH

    Ligonet is a small but active Busines Partner located in Switzerland




          2
Agenda
   What do you mean it's slow?

                      Where do performance problems show up


   Where the heck is that coming from?

                      Tips and tools to weed out the slow bits


   Don't want to go through that again!

                      Tips for avoiding slowness in the first place




         3
What do you mean it's slow?




       4
Bad performance... what exactly do we
mean?

     The application is bad ....

     Delivery time vs response time ....

     Impossible to work with this application

     This workflow has to be improved in any case!



Who has never heard these comments?

First and foremost - Make sure you are addressing the right problem.




           5
6
Performance of WHAT?
    Perceived Performance
    The user is feeling that the application is not giving the expected
     output
    Rather difficult to define, hence rather difficult to analyze
    Possible fixes:
                  Better user training - Explain the functionality to the
                     users
                  Enhance the experience - More information on
                     screen during processing or data entry
                  Streamline the experience - Change the process
                     flow

User experience can greatly influence how fast an application seems to
     work. If it is frustrating or takes a long time to enter data, users may
     report this as bad performance.
            7
Real performance ....
..... or rather the lack of it ....


 Bottlenecks, that can be verified by timing
 Almost impossible to anticipate
 Differences between testing and production environment
 Any conclusion without actual timing data is pure speculation
 Timing may influence the result




 It is important to have empirical data before you start changing anything.
  Just like with end users, developers have preconceived notions about
  what the source of the problem might be


               8
Example

    Running the same functionality four times: list all the views of
    names.nsf

    2 parameters are changed: The loop logic and the way that we
    access the DB properties



    Which of the four variants is the fastest?

    Why is your choice the fastest?




          9
Core code for the examples




       10
Timing results
First run




Second run (caching)




            11
Conclusion

    Results may surprise you

    Metering should be done in a realistic environment

    The amount of data and its structure has to be realistic; most testing
    environments are insufficient

    Approach of analysis has to be very, very systematic e.g. by
    narrowing down the points of problem




          12
Where the heck is that coming from?




            So you need actual numbers to justify the work to
            speed something up..... where are those supposed
            to come from?




       13
Timing with Now

        Example:
BaseTime = Now
    [.... your code goes here ... ]
Print Time used:  & Now  BaseTime


             Advantages                           Disadvantages

                                      Requires changing of code
                                      Bad placement falsifies the result
Simple and cheap                      Insufficient timing resolution




               14
High Resolution Timing - GetThreadInfo()

     Bruce Perry once published an undocumented way to use a high
     resolution timer

     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
              15
High Resolution Timing - GetThreadInfo()

                  Advantages                        Disadvantages
                                         Requires changing of code
                                         Bad placement falsifies the result
    Relatively Simple to implement       Makes use of undocumented functions
    Better resolution than using 'Now'





          A bit more tricky to use

          GetThreadInfo() is not guaranteed to work on all versions of Lotus
          Notes




                    16
How to communicate the results

    PRINT to the status bar (client) or the log.nsf (server)

    Better:
                        
                            Output to a document
                        
                            Output to a profile document
                        
                            Output into an analysis database ..... sorry ....
                            application




          17
Example - Make it reusable
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 & " took " & Now-Start & " seconds to complete."
  End Sub
End Class


                  18
Example - Make it reusable
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




              19
Built in profiling
 
     Introduced in Lotus Notes / Domino 7
                        速       速         速



 
     Only for agents and Web Services
 
     Java and LotusScript
 
     Activation in the properties of the Agent or Service
 
     Access to the results by right-clicking on the Agent or Service
 
     There are only results for pure Notes-Objects, no information for
     your own code




           20
Built in profiling - Example
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




        21
Built in profiling - Example


                 Run your
                 agent




        22
Built in profiling - Example




        23
Teamstudio Profiler

    Timing of functions

    Timing of code line-by-line

    Plethora of additional analysis information available

    Server and Client

    LotusScript only

    Application is slowed down a lot

    You have to pay for it




          24
Teamstudio Profiler - Example




       25
Don't want to go through that again!




       26
Common problems

     Tooling is a must for existing applications and performance
     problems, but even better would be not to create the problem to
     being with!



     Some of these are just rookie mistakes, others are just careless.




So first up.....


GetNthDocument!



           27
GetNthDocument()

        Running through a Doc-Collection with GetNThDocument(n) is a lot
        slower than getting the first doc with GetFirstDocument and then
        going through the collection by GetNextDocument (doc)



        Much has been said about this ... mostly all can be read online


        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


    Be familiar with the limitations of the API you are using. There are no
    bad functions, but not every function is appropriate for all situations.



               28
Check your loop logic

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

              29
and fix your bugs....
found=False

Do Until (selected_doc Is Nothing)
     If (selected_doc.Form(0)="fa_Term") Then
           found=True
           ' loop should short circuit here!!
     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

               30
Fix your bugs - Code Rot

     Fact - Code changes over time. Requirements change, better ways
     of doing things are discovered.

     Make sure your code changes are complete before moving on other
     wise performance suffers
    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

    The variable 'view' is never used anywhere on the form.
     NotesDatabase.GetView() is an expensive call to make on a QueryOpen.
     Especially if it is never used.


            31
Careful with nested IFs
  
        Unlike languages like C and Java LotusScript always evaluates all
        conditions in an if statement.


      x = 1
      If x = 0 And checkresult( res ) = 0 Then
        'do some stuff
      End If

Checkresult() will always be called. Performance problems can easily be
  masked in seemingly simple statements like this.




              32
Careful with nested IFs  The Fix
  
        The correct statement is the following:



      x = 1
      If x = 0 Then
          If checkresult( res ) Then
               'do some stuff
          End If
      End If
Checkresult() will only be called when the first statement is true.




              33
Variables  Variant is slower

                Besides being breeding grounds for bugs the
                 Variant data type is inherently slower than typed
                 variables.


                LotusScript will have to figure out the type at
                 some point and provide a conversion to the
                 correct type.


                Don't be lazy! Use Option Declare




        34
Loops  Some are faster than others
Forall through arrays much faster than For ..... Next
For ... Next is faster than Do ..... Loop or While ..... Wend




                 35
Left overs....
 
     Access to selected documents is faster by accessing them through a
     view instead of a document collection
 
     Access to Notes object through a temporary variable is faster than
     accessing them every time through the property of another Notes
     object




           36
Summary
   There are technical and non-technical reasons for performance
    issues
   If the issue is technical, any statement without metering is pure
    speculation
   There are no two identical cases
   Systematic top down analysis is very, very important
   Sometimes the redesign of the application is the best way to remove
    the issues
   There are some best practices




          37
Thank you!

Questions?
Maybe there are even answers ..... :-)


Craig Schumann - Teamstudio
craig_schuman@teamstudio.com
www.teamstudio.com


Jens-B. Augustiny - LIGONET GmbH
augustiny.j@ligonet.ch
www.ligonet.ch


                 38
Legal Disclaimer
息 IBM Corporation 2009. All Rights Reserved.

The information contained in this publication is provided for informational purposes only. While efforts were made to verify the completeness and accuracy of the information contained in this publication, it is provided AS IS
without warranty of any kind, express or implied. In addition, this information is based on IBMs current product plans and strategy, which are subject to change by IBM without notice. IBM shall not be responsible for any
damages arising out of the use of, or otherwise related to, this publication or any other materials. Nothing contained in this publication is intended to, nor shall have the effect of, creating any warranties or representations
from IBM or its suppliers or licensors, or altering the terms and conditions of the applicable license agreement governing the use of IBM software.

References in this presentation to IBM products, programs, or services do not imply that they will be available in all countries in which IBM operates. Product release dates and/or capabilities referenced in this presentation
may change at any time at IBMs sole discretion based on market opportunities or other factors, and are not intended to be a commitment to future product or feature availability in any way. Nothing contained in these
materials is intended to, nor shall have the effect of, stating or implying that any activities undertaken by you will result in any specific sales, revenue growth or other results.



Performance is based on measurements and projections using standard IBM benchmarks in a controlled environment. The actual throughput or performance that any user will experience will vary depending upon many
factors, including considerations such as the amount of multiprogramming in the user's job stream, the I/O configuration, the storage configuration, and the workload processed. Therefore, no assurance can be given that
an individual user will achieve results similar to those stated here.



IBM, the IBM logo, Lotus, Lotus Notes, Notes, Domino, Quickr, Sametime, WebSphere, UC2, PartnerWorld and Lotusphere are trademarks of International Business Machines Corporation in the United States, other
countries, or both. Unyte is a trademark of WebDialogs, Inc., in the United States, other countries, or both.


Java and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both.


Microsoft and Windows are trademarks of Microsoft Corporation in the United States, other countries, or both.


Intel, Intel Centrino, Celeron, Intel Xeon, Intel SpeedStep, Itanium, and Pentium are trademarks or registered trademarks of Intel Corporation or its subsidiaries in the United States and other countries.


UNIX is a registered trademark of The Open Group in the United States and other countries.
Linux is a registered trademark of Linus Torvalds in the United States, other countries, or both.
Other company, product, or service names may be trademarks or service marks of others.




                                         39

More Related Content

BP206 - Let's Give Your LotusScript a Tune-Up

  • 1. BP 206 Let's Give Your LotusScript a Tune-Up Craig Schumann Senior Developer, Teamstudio Jens-B. Augustiny, CEO, LIGONET GmbH
  • 2. Who is who? Craig Schumann, Senior Developer at Teamstudio Teamstudio is a producer of Development and Administration tools for IBM Lotus Notes and Domino Jens-B. Augustiny, CEO at LIGONET GmbH Ligonet is a small but active Busines Partner located in Switzerland 2
  • 3. Agenda What do you mean it's slow? Where do performance problems show up Where the heck is that coming from? Tips and tools to weed out the slow bits Don't want to go through that again! Tips for avoiding slowness in the first place 3
  • 4. What do you mean it's slow? 4
  • 5. Bad performance... what exactly do we mean? The application is bad .... Delivery time vs response time .... Impossible to work with this application This workflow has to be improved in any case! Who has never heard these comments? First and foremost - Make sure you are addressing the right problem. 5
  • 6. 6
  • 7. Performance of WHAT? Perceived Performance The user is feeling that the application is not giving the expected output Rather difficult to define, hence rather difficult to analyze Possible fixes: Better user training - Explain the functionality to the users Enhance the experience - More information on screen during processing or data entry Streamline the experience - Change the process flow User experience can greatly influence how fast an application seems to work. If it is frustrating or takes a long time to enter data, users may report this as bad performance. 7
  • 8. Real performance .... ..... or rather the lack of it .... Bottlenecks, that can be verified by timing Almost impossible to anticipate Differences between testing and production environment Any conclusion without actual timing data is pure speculation Timing may influence the result It is important to have empirical data before you start changing anything. Just like with end users, developers have preconceived notions about what the source of the problem might be 8
  • 9. Example Running the same functionality four times: list all the views of names.nsf 2 parameters are changed: The loop logic and the way that we access the DB properties Which of the four variants is the fastest? Why is your choice the fastest? 9
  • 10. Core code for the examples 10
  • 12. Conclusion Results may surprise you Metering should be done in a realistic environment The amount of data and its structure has to be realistic; most testing environments are insufficient Approach of analysis has to be very, very systematic e.g. by narrowing down the points of problem 12
  • 13. Where the heck is that coming from? So you need actual numbers to justify the work to speed something up..... where are those supposed to come from? 13
  • 14. Timing with Now Example: BaseTime = Now [.... your code goes here ... ] Print Time used: & Now BaseTime Advantages Disadvantages Requires changing of code Bad placement falsifies the result Simple and cheap Insufficient timing resolution 14
  • 15. High Resolution Timing - GetThreadInfo() Bruce Perry once published an undocumented way to use a high resolution timer 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 15
  • 16. High Resolution Timing - GetThreadInfo() Advantages Disadvantages Requires changing of code Bad placement falsifies the result Relatively Simple to implement Makes use of undocumented functions Better resolution than using 'Now' A bit more tricky to use GetThreadInfo() is not guaranteed to work on all versions of Lotus Notes 16
  • 17. How to communicate the results PRINT to the status bar (client) or the log.nsf (server) Better: Output to a document Output to a profile document Output into an analysis database ..... sorry .... application 17
  • 18. Example - Make it reusable 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 & " took " & Now-Start & " seconds to complete." End Sub End Class 18
  • 19. Example - Make it reusable 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 19
  • 20. Built in profiling Introduced in Lotus Notes / Domino 7 速 速 速 Only for agents and Web Services Java and LotusScript Activation in the properties of the Agent or Service Access to the results by right-clicking on the Agent or Service There are only results for pure Notes-Objects, no information for your own code 20
  • 21. Built in profiling - Example 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 21
  • 22. Built in profiling - Example Run your agent 22
  • 23. Built in profiling - Example 23
  • 24. Teamstudio Profiler Timing of functions Timing of code line-by-line Plethora of additional analysis information available Server and Client LotusScript only Application is slowed down a lot You have to pay for it 24
  • 25. Teamstudio Profiler - Example 25
  • 26. Don't want to go through that again! 26
  • 27. Common problems Tooling is a must for existing applications and performance problems, but even better would be not to create the problem to being with! Some of these are just rookie mistakes, others are just careless. So first up..... GetNthDocument! 27
  • 28. GetNthDocument() Running through a Doc-Collection with GetNThDocument(n) is a lot slower than getting the first doc with GetFirstDocument and then going through the collection by GetNextDocument (doc) Much has been said about this ... mostly all can be read online 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 Be familiar with the limitations of the API you are using. There are no bad functions, but not every function is appropriate for all situations. 28
  • 29. Check your loop logic 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 29
  • 30. and fix your bugs.... found=False Do Until (selected_doc Is Nothing) If (selected_doc.Form(0)="fa_Term") Then found=True ' loop should short circuit here!! 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 30
  • 31. Fix your bugs - Code Rot Fact - Code changes over time. Requirements change, better ways of doing things are discovered. Make sure your code changes are complete before moving on other wise performance suffers 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 The variable 'view' is never used anywhere on the form. NotesDatabase.GetView() is an expensive call to make on a QueryOpen. Especially if it is never used. 31
  • 32. Careful with nested IFs Unlike languages like C and Java LotusScript always evaluates all conditions in an if statement. x = 1 If x = 0 And checkresult( res ) = 0 Then 'do some stuff End If Checkresult() will always be called. Performance problems can easily be masked in seemingly simple statements like this. 32
  • 33. Careful with nested IFs The Fix The correct statement is the following: x = 1 If x = 0 Then If checkresult( res ) Then 'do some stuff End If End If Checkresult() will only be called when the first statement is true. 33
  • 34. Variables Variant is slower Besides being breeding grounds for bugs the Variant data type is inherently slower than typed variables. LotusScript will have to figure out the type at some point and provide a conversion to the correct type. Don't be lazy! Use Option Declare 34
  • 35. Loops Some are faster than others Forall through arrays much faster than For ..... Next For ... Next is faster than Do ..... Loop or While ..... Wend 35
  • 36. Left overs.... Access to selected documents is faster by accessing them through a view instead of a document collection Access to Notes object through a temporary variable is faster than accessing them every time through the property of another Notes object 36
  • 37. Summary There are technical and non-technical reasons for performance issues If the issue is technical, any statement without metering is pure speculation There are no two identical cases Systematic top down analysis is very, very important Sometimes the redesign of the application is the best way to remove the issues There are some best practices 37
  • 38. Thank you! Questions? Maybe there are even answers ..... :-) Craig Schumann - Teamstudio craig_schuman@teamstudio.com www.teamstudio.com Jens-B. Augustiny - LIGONET GmbH augustiny.j@ligonet.ch www.ligonet.ch 38
  • 39. Legal Disclaimer 息 IBM Corporation 2009. All Rights Reserved. The information contained in this publication is provided for informational purposes only. While efforts were made to verify the completeness and accuracy of the information contained in this publication, it is provided AS IS without warranty of any kind, express or implied. In addition, this information is based on IBMs current product plans and strategy, which are subject to change by IBM without notice. IBM shall not be responsible for any damages arising out of the use of, or otherwise related to, this publication or any other materials. Nothing contained in this publication is intended to, nor shall have the effect of, creating any warranties or representations from IBM or its suppliers or licensors, or altering the terms and conditions of the applicable license agreement governing the use of IBM software. References in this presentation to IBM products, programs, or services do not imply that they will be available in all countries in which IBM operates. Product release dates and/or capabilities referenced in this presentation may change at any time at IBMs sole discretion based on market opportunities or other factors, and are not intended to be a commitment to future product or feature availability in any way. Nothing contained in these materials is intended to, nor shall have the effect of, stating or implying that any activities undertaken by you will result in any specific sales, revenue growth or other results. Performance is based on measurements and projections using standard IBM benchmarks in a controlled environment. The actual throughput or performance that any user will experience will vary depending upon many factors, including considerations such as the amount of multiprogramming in the user's job stream, the I/O configuration, the storage configuration, and the workload processed. Therefore, no assurance can be given that an individual user will achieve results similar to those stated here. IBM, the IBM logo, Lotus, Lotus Notes, Notes, Domino, Quickr, Sametime, WebSphere, UC2, PartnerWorld and Lotusphere are trademarks of International Business Machines Corporation in the United States, other countries, or both. Unyte is a trademark of WebDialogs, Inc., in the United States, other countries, or both. Java and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both. Microsoft and Windows are trademarks of Microsoft Corporation in the United States, other countries, or both. Intel, Intel Centrino, Celeron, Intel Xeon, Intel SpeedStep, Itanium, and Pentium are trademarks or registered trademarks of Intel Corporation or its subsidiaries in the United States and other countries. UNIX is a registered trademark of The Open Group in the United States and other countries. Linux is a registered trademark of Linus Torvalds in the United States, other countries, or both. Other company, product, or service names may be trademarks or service marks of others. 39

Editor's Notes

  • #6: Collection of user comments about bad performing applications