Introduction to optimizing custom GWT widgets in Vaadin

So you've just created your custom GWT widget in Vaadin and feel that your application is running a bit sluggish? Figuring out what to optimize in a custom Widget can be hard. This article will discuss some of the common pitfalls that can be the source of this and give a short introductory presentation about a few developer tools that can be used to find resource heavy sections in widgets.

For detailed tutorials of the tools introduced here, please refer to their respective tutorials.

What is Firebug
Safari WebKit (Apple)
Chrome Webkit

1. Common pitfalls #

1.1 GWT compiler options #

One of the sure ways of making a application slow when compiling widget sets is to compile them using the pretty or the detailed modes in the GWT compiler.
Options in the GWT compiler
When profiling the JavaScript code (which we will do in section 2) it is useful to use these different options in order to make it easier to follow the flow of the program, but when compiling a widget for production, the compiler should always be set to obfuscated. The GWT compiler is very good in optimizing the code that is given to it, however these optimizations are done only when the widget set is compiled with the obfuscated flag.

1.2 Minimizing client-server communication #

By far, the most time-consuming operation in most custom widgets is the communication between client and server. When rendering a component the time consumed is usually below 100 ms (which is considered as a threshold when a user starts to notice sluggishness in an application). A roundtrip between the client and server can easily exceed this threshold. This doesn't necessarily mean that a application becomes sluggish as the framework does not freeze the UI while waiting for a response. But if the user is waiting for something to happen while the application is waiting for a response from the server, it might seem like like the application is unresponsive to the user.

There are a few ways to combat this problem. The first and foremost way is to keep this in mind when creating a custom component so that the client-server communication can be minimized. If you have created a component that requires a lot of client-server communication you should try to group them together. The API of the Vaadin client-server communications protocol (ApplicationConnection) supports queuing of server calls so that several calls can be sent to the server at the same time. This can be done by setting the last parameter, immediate, in the call to updateVariable to false for all but the last of the calls to updateVariable. When the immediate parameter is false it will tell the Vaadin application connection that this update does not need to be sent immediately. If the immediate parameter is true, ApplicationConnection will send the request (along will all other queued requests) immediately to the server. Let's look at a example:

#!java
public void updateToServer(){
	/* Method declaration for the updateVariable() used here 
	 * 
	 * public void updateVariable(String paintableId, String variableName, 
	 * 						 String newValue, boolean immediate)
	 */
	
	client.updateVariable(paintableId, EVENT_E1_IDENTIFIER, "property1", true);
	doSomething(); 
	client.updateVariable(paintableId, EVENT_E2_IDENTIFIER, "property2", true);
	String property3 = doSomethingElse();
	client.updateVariable(paintableId, EVENT_E3_IDENTIFIER, property3, true);
}
Here three string parameters are updated and sent to the server from the client side. Note the value of the last parameter in the updateVariable-method. Setting up the calls like this will cause three requests to the server that will produce three times the overhead as sending one update.

#!java
public void updateToServer(){
	client.updateVariable(paintableId, EVENT_E1_IDENTIFIER, "property1", false);
	doSomething(); 
	client.updateVariable(paintableId, EVENT_E2_IDENTIFIER, "property2", false);
	String property3 = doSomethingElse();
	client.updateVariable(paintableId, EVENT_E3_IDENTIFIER, "property3", true);
}
In the second example the first two updates are queued while the third one is set as immediate. When the call to updateVariable with immediate as true is made, all of the queued requests are sent along with the new request to the server. Hence all of the updates will be sent to the server in a single request.

1.3 Compiling only needed widgets #

This is a neat trick that can some times speed up the initial load of a application if the application is comprised of only a few specific Widgets. When using the Vaadin template for creating custom widgets, the widget set that is compiled includes all of the widgets that are used in Vaadin. Usually this is desired behavior, but if you have created a specific application that only uses a subset of those standard widgets you can exclude the unused widgets from the widget set. By compiling only the needed widgets to the widget set you will reduce the overhead that is sent to the client side upon application initialization.

NOTE: The widget set is compiled for the entire application, so when excluding a widget you must ensure that that widget is never used in any part of any other component that you use in the application!

To see what widgets are included in the current widget set that is compiled you can enable the "Verbose mode" for the widget set compiler. This will output information about the widget set compilation to the console.

Enable widget set compiler verbose mode

In order to create a custom reduced widget set we must create a new class that extends WidgetMapGenerator that will be used during the widget set compilation to tell the widget set compiler what classes should be included in the widget set. The WidgetMapGenerator will normally generate a widget set that includes all the default widgets in Vaadin. We can override the getUsedPaintables method to either explicitly specify the classes with widgets that are used application or we can remove some not needed widgets from the default set of widgets.

#!java
public class CustomWidgetMapGenerator extends WidgetMapGenerator {

    @Override
    protected Collection<Class<? extends Paintable>> getUsedPaintables() {
        Collection<Class<? extends Paintable>> paintablesHavingWidgetAnnotation = 
        new HashSet<Class<? extends Paintable>>();

        paintablesHavingWidgetAnnotation.add(Label.class);
        paintablesHavingWidgetAnnotation.add(Window.class);
        paintablesHavingWidgetAnnotation.add(VerticalLayout.class);
        paintablesHavingWidgetAnnotation.add(MyCustomComponent.class);
       
 		return paintablesHavingWidgetAnnotation;
    }

}

In this first example, we define the UI components that our application uses. The WidgetSetGenerator will search the given classes for the @..ClientWidget -annotation and compile the client side widget for that component. (Only the server side classes for the widgets should be added here).

#!java
public class CustomWidgetMapGenerator extends WidgetMapGenerator {
	@Override
	protected Collection<Class<? extends Paintable>> getUsedPaintables() {
       
    	Collection<Class<? extends Paintable>> usedPaintables = super
                .getUsedPaintables();

				usedPaintables.remove(Table.class);
				usedPaintables.remove(GridLayout.class);
				usedPaintables.remove(TabSheet.class);

				return usedPaintables;
				}

}
In this second example we start off by using the default widget set that we can get from super.getUsedPaintables(). The returned collection will have the references to all of the server side classes that have widgets in the used Vaadin framework as well as the current project. We can now remove the unused components "Table", "GridLayout" and "TabSheet" from that collection to remove them from our custom widget set.

Now that we have created the CustomWidgetMapGenerator we must still tell compiler to use it. This is done in the yourprojectWidgetset.xml file that should be under the server side package.

#!xml
<module>
	...
	<inherits name="com.vaadin.terminal.gwt.DefaultWidgetSet" />
	
	<generate-with class="com.example.exampleproject.CustomWidgetMapGenerator">
		<when-type-is class="com.vaadin.terminal.gwt.client.WidgetMap"/>
	</generate-with>
	...
	<!-- <set-property name="user.agent" value="safari"/> -->
</module>
Here we tell the compiler to use the CustomWidgetMapGenarator that we just created to compile the widget set.

Here are some of the largest widgets in Vaadin (in no particular order)

  • GridLayout
  • Table
  • TabSheet

A good thing to remember is that the size of data transferred during initialization for a clean Vaadin application is about 600 KB and consists mainly of the widget set and the theme data (CSS and images). The "large widgets" when optimized and compressed with the GWT compiler are about 10-30KB each, so removing only one or two widgets will probably not provide a huge performance gain. At the same time a heavy theme might produce more overhead then the all of the widgets put together. Realistically in Vaadin 6.2 you can save up to about 200 KB in the initial transfer by compiling only the required widgets. In most applications this will not even be an issue but for example in mobile applications it might be significant.

2 Using developer tools for finding hotspots #

Ok, so the compiler settings are correct, we have checked the required widgets and we have minimized the number of client-server calls but the custom component is still not performing like it should. It's time to take a look at what is actually taking so much time and if we can find a way to reduce it. Below is a short presentation of how to use JavaScript profiling in Firebug with Mozilla Firefox and the WebKit development tools that can be found in Safari and Google Chrome browsers. Finally we'll take a peak at new tool called SpeedTracer that is still (at the time of writing) under development but can be installed as a plugin to Google Chrome.

A few notes about optimizing GWT widgets #

  • Generally optimizing GWT widgets can be a very tedious process because of the highly advanced GWT compiler. The compiler is very good in finding common paradigms that can cause poor performance and is designed to eliminate them. This means that traditional simple optimization techniques might give only a small performance gain or in worst cases no performance gain at all as these will already be optimized by the compiler.

  • Profiling a GWT Widget is unlike Java profiling. You can not profile a class or method, you'll have to profile the entire application. This can be hard if you have a lot of irrelevant components throwing off your profile data. I recommend that you start profiling your widget in a clean Vaadin application with minimum number of other components.

  • Most importantly, the profiles can only point you towards the right direction in your efforts to optimize your application. They are not a quick fix that show you exactly what line of code you should optimize. When you have identified the probable cause for the poor performance in your application, you still have to go back to your Java code and figure out how to reduce the number of calculations, server requests or repaints that caused the problem in the first place. Then you'll have to fix it, recompile the widget set with all optimizations on and see if it fixed the problem or not.

2.1 Setting up the compiler for profiling #

First thing we must do in order to profile our widget is to compile it in a way so that the generated JavaScript is human readable. When using the GWT compiler in the obfuscated mode, the compiler tries to optimize the code as much as possible both for performance and size. This creates JavaScript code that is gibberish for us mere humans. In order to keep the method names and the code the way we have programmed it, we have to give the compiler the Pretty or Detailed flag.

Compiler flags:

  • Obfuscated: Highly compressed and optimized, non human readable, JavaScript.
  • Pretty: Will compile the Java code to JavaScript without optimizations and preserve the method names and structure of the original code.
  • Detailed: Same as pretty but will preserve the full name for the methods so that you can see the hierarchy for the method (i.e. what package/class it belongs to).

So what does this mean? Let's take a look at an example.

#!java
public long fibonacci(int thFibValue){
		long nMinus2; 		//The n-2 term
		long nMinus1;			//The n-1 term
		long result; 			//The n:th term
		result = nMinus2 = nMinus1 = 1;  
		
		//Compute the fibonacci value for the input
		for(int i=3; i<= thFibValue; i++){
			result = nMinus1+nMinus2;
			nMinus2=nMinus1; 
			nMinus1=result;
		}
	   	 
		//Return the result
	   	 return result;
	}
Here is a simple method that computes the n:th fibonacci value for a input value.

#!javaScript
2264 function Bfb(d){var a=new Array;var b=d;for(var c in b){a.push(c)}return a}
2265 function RA(a,b,c){var d=0,e;for(var f in a){if(e=a[f]){b[d]=f;c[d]=e;++d}} }
2266 function Y2(a,b){var c;for(c=0;c<a.d;++c){if(a.b[c]==b){return c}}return -1}
2267 function lqb(a){var b,c;for(c=eUb(a,0);c.c!=c.e.b;){b=$A(pUb(c),38);Rqb(b)}}
2268 function Qj(a){var b,c,d,e;e=b=c=1;for(d=3;d<=a;++d){e=c+b;b=c;c=e}return e}
2269 function ivb(a){var b,c;for(b=this.c.Ac();b.qc();){c=$A(b.rc(),76);c.Fc(a)} }
2270 function peb(a){var b;if(this.d){b=$A(this.c,33).nb;fj(b,v6b,NQ(this.b).b)} }
Here is a snapshot of the JavaScript of a Vaadin Widget compiled with obfuscated flag. Can you find the fibonacci function?

#!javaScript
...
2268 function Qj(a){
	var b,c,d,e;
	e=b=c=1;
	for(d=3;d<=a;++d){
		e=c+b;
		b=c;
		c=e
	}
	return e
} 
...
Yes, it's now called "Qj(a)" and it can conveniently be found on line 2268 in the generated script file.

#!javaScript
function $fibonacci(thFibValue){
	var i, nMinus1, nMinus2, result;
	result = nMinus2 = nMinus1 = 1;
	for (i = 3; i < thFibValue; ++i) {
		result = nMinus1 + nMinus2;
		nMinus2 = nMinus1;
		nMinus1 = result;
	}
	return result;
}
When compiled with the Pretty flag the code is more readable.

#!javaScript
function com_example_cleanwithwidgets_client_ui_VMyComponent_$
        fibonacci__Lcom_example_cleanwithwidgets_client_ui_VMyComponent_2ID(thFibValue){
	var i, nMinus1, nMinus2, result;
	result = nMinus2 = nMinus1 = 1;
	for (i = 3; i < thFibValue; ++i) {
	result = nMinus1 + nMinus2;
	nMinus2 = nMinus1;
	nMinus1 = result;
	}
	return result;
}
And finally with the Detailed flag you can see the full hierarchy for the method.

2.2 Firebug (Mozilla Firefox) #

Firebug is a plugin that can be installed to Mozilla Firefox that can help you in finding bugs and profile your custom widget. You can get Firebug from getFirebug.com. It will install as a plugin to Firefox and show up as a little "Bug" in the lower right corner of your browser. When you click on the bug icon it will open Firebug and show you the current console output. You can also open Firebug by right-clicking on any component on the webpage and selecting "Inspect Element". When opened through "Inspect Element", Firebug opens to the HTML-source view by default. Firebug can also be used for debugging CSS or generated HTML but this will not be covered here, for a tutorial on these please refer to Firebug tutorials

CPU profiling with Firebug #

Now that we have firebug installed we can start to profile the generated JavaScript. Make sure you are in the "Console" tab and click on the "Profile" button. This will tell firebug to start profiling the method calls that are made in the application. Now, do something with your application that seems to cause sluggish behavior. Remember the fewer things you do, the easier it will be go through the profiling data. Finally click on the "Profile" button again to se the data that the profiler has gathered.
Profile

You will probably notice that a lot more happened during your test then you expected. Let's take a look at what the table of profile data can tell us.

The table consists of several columns:

  • Function: The function that was called
  • Percent: The relative time of this function with respect to total profiling time
  • Calls: The total number of calls to this function during this profiling session
  • Own Time: The amount of time that it took to process the methods own code (excluding internal method calls)
  • Time: The total processing time for this method (including internal method calls)
  • Avg: The average processing time for this method
  • Min: The minimum processing time for this method
  • Max: The maximum processing time for this method

The table can be sorted ascending or descending for any of these columns and if you hover your mouse on top of any of the method names you'll see the code for that method.

In the example screenshot we can see that the "heavyComputation"-method has a high relative time (Percentage) and that the time spent in the function is quite high. Hence our optimization efforts should probably start here. However finding hotspots might not always be so easy. As we can see, there are a lot of other methods that were triggered and most of these are not part of our widget in the sense that we haven't coded them. Some times you'll have to go through the list many times and narrow down the profiling to "a single click of a button" or "content update" to find which function that you have implemented causes the slowdown.

Network resources #

Another important part of the application performance is the network traffic. You can click the "Net" tab in Firebug to get an overview of the network traffic between the client and the server. This is a great way to find server calls that could be queued and other resource hogs like oversized images.
Example of Firebug network view

2.3 WebKit development tools (Safari and Google Chrome) #

Safari #

Safari and Chrome use a different layout engine than Firefox and have different developer tools. Safari can be downloaded from Apple here. Safari includes the developer tools in the standard install but hides them from the regular user. To enable the developer tools in Safari, go to Safari preferences (menubar: Safari -> Preferences), click on the "Advanced" tab and select "Show developer tools".
Enable safari developer tools
You've now gained access to a new menu in the menu bar "Develop" where You can find "Show Web Inspector" and if you right click on any element in a document you'll find a new option "Inspect Element"

Google Chrome #

Google Chrome is still under heavy development on most platforms but stable enough to use with caution. You can get Chrome for your OS from Google, how ever if you are planning on trying out the "Speed Trace" feature, you must download the "Developer Channel" version which you can find here.

Just like Safari, Chrome includes the WebKit developer tools out of the box, in the Beta version of Chrome the developer tools are enabled by default. If you right click on a element you'll find the "Inspect Element" option, and you can manually open the development tools by navigating through the menus in the menubar: View -> Developer -> Developer Tools. To enable quick access to the tools, you can check the "Show Page and Tools menus" under the "General" tab in the Chrome settings. This will show the developer tools to the right of the URL input field

Chrome quick access

Using CPU profiling with WebKit #

To use CPU profiling with WebKit development tools, select the "Profiles" tab and click on the "start profiling" button.
start profiling button
This will start the profiler that monitors all the method calls that are made. To stop profiling click on the start profiling button again. The profiler will now show you the statistics for that profiling session. The table has the columns:
  • Self: The amount of time that it took to process the methods own code (excluding internal method calls)
  • Total: The total processing time for this method (including internal method calls)
  • Function: The name of the function that was executed
The profiler can display the metrics as absolute values for the method calls, or as a percentage relative to the total time. You can switch between these two with the %-icon at the bottom of the window. The table can also be viewed in two different ways:
  • Heavy(Bottom Up): Places the function with the greatest performance impact at the top
  • Tree(Top Down): Gives you a picture of the call structure of the program
You can also focus on a specific function to see the values for only that function, this is about the closest to single method profiling as you can get with these browser based tools. You can also exclude specific functions if you like to minimize the clutter in the profile view.
Focus/Exclude method

Network resources #

In the WebKit developer tools you can find the network resources overview under the "Resources" tab. The resources view can give you a overview of what exactly is sent between the client and the server. The resources view can show you the time that was required for each part of a request latency (the time from request to receive) and the download (Time view), or the size of the components sent (Size view). The "Time view" is great for getting a overview of what is making the request slow and what exactly is sent between the client and server. The "Size view" on the other hand can be useful when trying to identify potential problems with clients behind a limited network.
WebKit resources ”Time view”
WebKit resources ”Size view”

Note: When compiling the widget set with the Pretty or the Detailed flags, the document size becomes quite large. This is due to all of the extra overhead that is not optimized away. To get a realistic figure on the actual data that is sent you should use the resources view only when the widget set is compiled with the obfuscated flag.

Google Speed Tracer (Chrome only) #

Google Speed Tracer is a profiling tool for finding hotspots in a web application that cause slowdowns and sluggishness. Speed tracer is currently only available for Chrome and can be downloaded from here. Speed tracer can give you a overview of what is causing slowdowns in your application, for example if it's the paint operation, the script evaluation or the style recalculation that is the root cause of the slowdown. Speed Tracer provides you with two views, the "Sluggishness view" and the "Network view". The sluggishness view indicates how blocked the UI of your application is during the processing of a request while the network view shows the network traffic during that time. If the sluggishness reaches 100% the UI will be completely blocked and seem unresponsive to the user. If you find a hotspot in your application, you can click on that event and see how the workload is divided between different parts of the request.
Example
In the example we can see that the sluggishness graph (purple) is close to 100% during the 2.29s to 2.37s interval. We can open up the event to see the distribution of actions during that event to find out what is causing the slowdown. Quickly we see that the root cause of the slow down is the script evaluation process. This indicates that we should review our JavaScripts (in Vaadin: the client side Java code for widgets).

2.4 Timing blocks of code on the client side #

When you have identified the method that is your performance hog you need to go back to your code and find what part of it is causing the problem. If you have written nice and clean code this should be relatively simple but this might not always be the case. If you feel that it's hard to find the actual lines of code that causes the greatest performance hit you can use the GWT counterpart to the classic call to System.out.println() with the difference in start and stop times.
#!java
long startTime = System.currentTimeMillis();
...
Block of code
...
long stopTime = System.currentTimeMillis();

ApplicationConnection.getConsole().log("Exec time: " + (stopTime-startTime));

Google has included the sources for the call to currentTimeMillis() so you can call it directly from the client side code. However, nanoTime() is not part of the GWT code so these calls will fail, as will the calls to System.out.println(). To print something to a console on the client side you have to use ApplicationConnection.getConsole() and then use one of the logging methods there, for example ApplicationConnection.getConsole().log(myString) or ApplicationConnection.getConsole().error(myString). These calls will log messages to the browser console on the client side that can be accessed through the developer tools presented earlier.

In order to enable logging to the browser console you'll have to append "?debug" to the URL of the webpage. For example if your application is called "MyApp" and you're running the server on your own system, the URL should be something like: [http://localhost:8080/MyApp?debug] or if you have several parameters: [http://localhost:8080/MyApp?restartApplication&debug]

Summary #

In this article we've looked at the common pitfalls that can cause even a well written widget to perform badly. We also took a look at a special case where we could exclude some unused widgets and create a reduced widget set. We also introduced some development tools that can be helpful when we are trying to find the computationally heavy sections of our widget and possible resource hogs in the terms of network traffic.

To summarize the most important things you should take with you from this article:

When creating custom GWT widgets for Vaadin you should:

  • always check that the compiler flags is obfuscated when you build your widget set for production
  • strive to minimize client-server communication
  • use profiling tools to find resource heavy sections and then go back and review your code
14 Attachments
12193 Views
Average (3 Votes)
Comments