Aug 30, 2011 11:40 PM
1 Posts

Speeding up Xpages

  • Category: Performance
  • Platform: Windows
  • Release: 8.5.2
  • Role: End user,Developer,Administrator
  • Tags: speed up,performance,data,loading
  • Replies: 8
Hello! I'm a newbie here and also in XPages development. My question is how do I speed up XPages? I mean besides the best practices that applies to web development in general, what practices and conventions do i need to follow to speed up the loading page, activities, and AJAX requests of Xpages. Or are there server-side settings that I can change to optimize the speed and interaction between the user and the application. The application that I'm doing will reside on a dedicated server, so if there are ways to optimize XPages in the server-side, for sure I can do it. Please help me. Thanks a lot! :D
Aug 31, 2011 1:31 AM
41 Posts
Re: Speeding up Xpages
 If you're going for raw speed, the easiest way to boost performance is to throw hardware at it. Specifically, RAM. The XPages runtime has been highly optimized by IBM, but as of 8.5.2 the default settings are optimized for scalability rather than speed. So if, instead of maxing out the total number of concurrent users the application can support, you want to maximize the performance for each individual user, here's what I recommend in terms of server configuration:
 
  • Add as much physical RAM to the box as you can talk the admins into installing. Obviously, a fast processor helps as well, but RAM is comparatively cheap, and unless your app is extremely complex (or heavily used), 8 GB is going to be plenty... but if you can get 16 GB, even better.
     
  • The default Java heap size is ridiculously low. Whatever amount of RAM you end up with, set the HTTPJVMMaxHeapSize parameter in the server's notes.ini to a fourth of that. If the server has 8 GB, for example, HTTPJVMMaxHeapSize=2048M. Be sure not to remove the corresponding setting, HTTPJVMMaxHeapSizeSet=1, or Domino will reset the heap size the next time it loads.
     
  • If you can swing it, run the program files on an SSD. I don't actually recommend going solid state for the data, but if Domino itself is installed on an SSD, you'll be amazed how fast the whole HTTP stack runs.
But beyond hardware, there are several development techniques that will maximize speed.
  • First and foremost, become intimately familiar with the so-called "scope variables". The nature and use of these are documented in detail elsewhere, so I won't belabor that here. But the better you understand what information is appropriate to store in each scope - and that you can store complex object structures, not just "string-to-string" mapping - and the more you take advantage of this, the faster the application's response will be. This is because you're limiting disk I/O as much as possible... the more frequently the application can just pull whatever data the user is requesting from RAM, instead of querying the database every time, the faster the application will be. This is why you want lots and lots of RAM. :) Of course, you don't want to be gratuitous with your memory storage, which is why it's crucial to understand which scope is appropriate for which type of data... when you get the hang of this, Domino will clean up these memory caches for you automatically.
     
  • If you find that you're running out of memory, but you're confident your scope storage is reasonably optimized, tweak the application properties to clear the application scope periodically. The higher the frequency you set, the more you can cache in all the scopes without bursting the heap... but if you find you're needing to set this to a frequency of less than an hour, revisit what you're actually storing, because it's probably out of control.
     
  • Change the server page persistence setting to keep the current page in memory. Strictly speaking, keeping all pages in memory provides the best performance, but it tends to be downright wasteful of memory. When only the current page is kept in memory, as a user navigates from page to page (as opposed to firing events against the page they're already on... even if it's a full refresh event), it serializes the state of the previous page to disk. If a subsequent event is fired against that previous page, then that page's state is retrieved from disk and loaded back into memory. But this scenario only occurs if the application loads a new page in a new window or tab, and the user later switches back to the original window and interacts with it again. In typical navigation scenarios, once the user has opened a new page, the previous page instance no longer exists... even if they navigate back to the same page again, it's a new instance  of that page. Hence, keeping all pages in memory essentially guarantees at least a temporary memory leak. All of that storage is eventually released, of course, but in the meantime the server is consuming memory it will never need again that would be better served storing whatever you're explicitly caching in scope variables.
     
  • Minimize the use of SSJS (server-side JavaScript). Every time any SSJS expression is evaluated, Domino parses the expression in realtime into an abstract syntax tree, then runs Java code that is a rough approximation of how the JavaScript specification states that code matching the detected syntax should run. The more you move your logic directly into true Java classes, the less expensive it is to execute, so it runs faster. Each time, this differential is minuscule, but aggregated over the entirety of a complex application, it adds up enough to be perceptible to end users. Even without moving your code to Java, however, you can reduce SSJS usage simply by making the most of EL (expression language). For instance, rather than binding an image's src attribute to: 

    "#{javascript:return '/' + database.getFilePath() + '/images/' + currentDocument.getUniversalID() + '/$FILE/' currentDocument.getItemValueString('thumbnail');}"

    ...you can intersperse standard EL expressions throughout an otherwise hardcoded string:

    "/#{database.filePath}/images/#{currentDocument.universalID}/$FILE/#{currentDocument.thumbnail}"

    Not only does this reduce (and, often, eliminate) the amount of quote escaping required, making the code easier to maintain, it's more efficient for the server to evaluate each expression. In the above example, it's actually slightly faster to evaluate those three separate EL expressions than to evaluate the single SSJS expression they replaced.
     
  • Wherever possible, change your expressions from dynamic bindings to page load bindings. This is just a fancy way of saying that ${database.title} is always better than #{database.title}. The $ means that the expression is only calculated once per page instance... # means it's recalculated as often as needed - sometimes several times within the same request, depending upon what value is bound to the expression. So obviously you can't just change all your expressions to $... input controls bound to form items, for instance, should remain #. But if you have computed text displaying the application's title (as in the above example), that value is obviously unlikely to change during any given page instance, so change it to a $ expression, and then the server only has to evaluate it once. Combine this optimization with thorough scope caching, and it's easy to see how this can really speed up page load times and event execution response. This gets particularly noticeable when dealing with repeat controls: each time a user navigates to the next page of a repeat, if that repeat's value is a # binding, it has to recalculate that value... change it to a $, and it only loads the collection once. Even if the event the user triggered has nothing to do with the repeat, the server has to recalculate all # bindings, so if the repeat's value is a #, it still has to pull the collection again even though the user wasn't explicitly interacting with the repeat.
     
  • If you have the luxury of using the Extension Library, check out the Remote Service control. This allows you to easily define a JSON-RPC API for the page, which lets you call server-side code from client-side JavaScript. Because this skips posting the entire form (as all standard events do), it's incredibly efficient. There are many situations where this allows you to perform the desired operation faster than you could with a standard event... just keep in mind that, because it's not posting the form, the server is unaware of anything that may have occurred since the last event - most notably, any field values that have changed - so limit use of this to situations where you can manually send only the information the server needs in order to execute the necessary code and send back the desired response.
I'm sure there are other ways to optimize performance that I'm forgetting at the moment, but hopefully that's enough to get you started. :) 
Aug 31, 2011 10:02 AM
199 Posts
*Great ideas Tim, thanks for taking the time to post this
Sep 1, 2011 7:43 AM
21 Posts
Re: Speeding up Xpages
These tips don't help much for the issue when a user tries to load your page for the first time. Could someone post the code / information on how to keep the xsp servlet in memory ?
Sep 6, 2011 4:35 PM
6 Posts
Re: Speeding up Xpages
In addition to the hints provided by Tim, you should take a look at the ViewNavigator performance improvements that were introduced in 8.5.2, in case you are processing a lot of view entries in your application:
 
 
Using the new entry cache is MUCH FASTER than e.g. using a ViewEntryCollection.
Oct 1, 2011 8:32 AM
1 Posts
Re: Speeding up Xpages
In 8.5.3, there will be a Notes.ini parameter which allow you load xpage server classes once Domino start. Thus, the first time access XPage application will be improved.
Feb 23, 2012 10:36 AM
3 Posts
Re: Speeding up Xpages
There are two notes.ini parameters. XPagesPreload & XPagesPreloadDB. You can find more info about them here.
Mar 6, 2012 5:26 PM
1 Posts
Re: Speeding up Xpages
Tim
 
Why don't you recommend storing data on an SSD?  Why only programs?