The JVM is designed with a means to get information on running processes (JVMPI, and the newer JVMTI). Using these mechanisms many Java tools can report on exactly what is going on when a Java application is executing. This information includes number of objects in use, memory, threads, garbage collection and so on. Profiling can be invaluable in tuning and troubleshooting an application. The end goal of profiling is to determine exactly what is happening with an application at runtime, in great detail, and identify performance metrics and bottlenecks.
The Limitations of Hosted Mode Profiling
Web Mode Profiling
How do I profile a running GWT application in web mode?
In order to profile GWT code in web mode you first need to make sure to use the -style command line parameter with the GWT compiler and set the format to PRETTY or DETAILED. PRETTY is the recommended setting for normal profiling. If you need extra troubleshooting help, or for any other reason want extra verbosity, you can use DETAILED. If you are using the “Compile/Browse” button from the GWTShell, you can also pass the -style parameter to the shell, which will in turn hand it off to the compiler. If you leave things in the default style setting of OBF (obfuscated), you do not stand much of a chance of following the output. Ultimately after you have profiled your code, before you deploy it to a production environment, you will want to switch back and compile with the OBF style.
Installation of Firebug is the same as that for any Firefox plug-in, select the .xpi file from the Firebug website (http://www.getfirebug.com/), and allow it to install. Once installed, the Firefox “Tools” element on the top menu will include a new Firebug sub-menu. To see Firebug in action, after it is installed, you simply invoke Tools->Firebug->Open Firebug. Figure 1 is a screen shot of the Firebug Console window open, on the lower half of a browser screen.
Figure 1 Firebug running in the lower half of the Firefox browser, Console section open
To use Firebug with a GWT application you simply direct your browser to the GWT application and open Firebug. The simplest way to do this, assuming Firefox is your default browser, is to invoke web mode from the GWTShell via the Compile/Browse button. Using a GWT app in the shell, and invoking web mode, will invoke the GWT compiler and open a browser window directed at the compiled code (and still run any service servlets in the hosted mode shell). Then you can start Firebug (recall, Tools->Firebug) and learn a great deal of useful information about your application.
Figure 2 Firebug screen shot showing XHR POST operations, including full HTTP headers, in the Console
From the Firebug Console, as seen in Figure 2, we see several important GWT details. First, the “Headers” section shows the XHR response and request headers. These indicate that a POST response was returned from a local “Apache-Coyote” server, at the path http://localhost:8888/%5BMODULE_NAME%5D/%5BSERVICE_NAME%5D. This shows us exactly where our GWT RPC is ending up, if we were using -noserver we would expect to see our external server instance being invoked here. Also the POST request includes the “referer,” which denotes exactly which of the hash named “cache.html” files was used (which specific compiled version of the application). Finally, in the “Post” and “Response” sections we see the GWT IsSerializable/Serializable objects that are passed across the wire. These are not specifically profiling tasks, but are handy related features of Firebug that can be extremely useful when working on GWT applications.
By clicking on Profile a first time, you tell the profiler to begin paying attention. At that point you can then click around your application and perform some tasks. Then when you click Profile again, you instruct the profiler to stop and display the collected data in the Console. It is this data that can help you understand how your GWT application is working. Figure 3 is a screen shot showing the results of the Firebug profiler, which includes such concepts such as the number of calls each function received, percentage, time, and what file each is in. (Note that “own time” means time inside the function specified without recursive calls to other functions, while “time” means total time including recursive calls.)
Figure 3 Firebug Profiler screen shot showing sortable profiling data collection results
Once you have collected profiling data with Firebug you can then inspect the results to understand exactly how your application is operating. You need to keep in mind though, that what you are seeing is your code as optimized by the GWT compiler (unless you are using JSNI). This is key because you have to remember that the GWT compiler is fairly smart. The “optimizations” it performs should mean that you will not ever have much to “fix” as a result of your profiling, if you are using standard GWT code and allowing the compiler to do its job.
The hosted mode browser is a running Java process, as is the GWT shell. There is a harness between these components that propagates browser based events to GWT projects running in the shell. Using this approach, you can run your GWT project and use a standard Java debugger in a variety of ways. The most common means to debug a Java project are either to run the project in process inside of an IDE, or to connect an IDE to a remotely running Java process with the Java Platform Debugger Architecture (JPDA) interface enabled and listening for connections.
These same methods can be used with GWT, to connect to, and debug your programs, through the GWT shell.
Many modern IDEs have all sorts of support for running applications, even servers, in process with the IDE; and then debugging from there. It’s good to also be aware, however, that you can debug external processes pretty easily as well. This is made possible by the Java Platform Debugger Architecture (JPDA – http://java.sun.com/j2se/1.5.0/docs/guide/jpda/architecture.html).
Basically, modern JVMs have a set of profiling interfaces (one for the front end, and one for the back end), and a protocol, that work together to enable external debugging. JVMs include a native interface implementation, based on JVMTI, on the back end, and a Java interface based on JDI is used for front end debugging. The protocol that enables communication between the two layers is JDWP. Using this setup debuggers can easily connect to remote Java processes, and perform their typical beloved duties.
How do I configure the JVM to allow a remote process to be debugged.
Use the JPDA support built into the JVM to pass the appropriate options to the Java process on the command line, and then connect to that process with a debugger.
To demonstrate the concepts, let’s step through an example using GWT-Maven to launch a GWT project, and then debug that project from Eclipse. To begin, an external Java process needs to be running, and that process must have been configured to pass the -Xdebug and -Xrunjdwp options to the JVM at startup (optionally the newer -agentlib:jdwp option is preferable on Java 5.0 and above VMs).
The exact options used for this example, which are passed automatically via Maven and the GWT-Maven plugin using the gwt:debug goal, are as follows:
-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,address=3408,suspend=y
More detail about all of the options is available in the JPDA documentation ( http://java.sun.com/j2se/1.5.0/docs/guide/jpda/conninv.html#Invocation).
Basically, in this case, we are telling whatever Java process we run with these options to start and wait for a debugger to connect before continuing. Because we will be using GWT-Maven here the Java process we are controlling will ultimately be the GWTShell. On the command line this looks like what is shown in figure 4 (notice the process stopped, and is waiting for a connection on port 3408):
Figure 4 Shell session showing JVM waiting for debugger connection.
Once the process is waiting for a debugger to connect, the stage is set. The next thing to do is simply to connect with a debugger to the port shown – this is where Eclipse comes in. To connect with Eclipse you must use the “Run dialog,” and select new “Remote Java Application.” From there simply specify a name for the project, and the port as shown in figure 5.
Figure 5 Configuration dialog for Eclipse that demonstrates connecting to a remote process for debugging.
(Note* this screen shot shows port 1941 from a previous run, in this case it would need to be changed to 3408 to connect to the process started above.)
With that, all the pieces are in place, the JVM is running as the back end, and the IDE has connected as the front end. In this example the GWTShell continues along and launches the application, and from there you can click around to exercise the Java code. As with any typical debugging you can use breakpoints and step into and out of the code, and inspect the state as you go. Though the screen shot in figure 6 is small, you get the idea with the blue breakpoint dot and green highlighted code line:
Figure 6 Typical Eclipse debugger in use showing breakpoints.
In total the technique is very easy once you understand the roles of the components. Though this example used GWT, and GWT-Maven (something where external debugging comes in very handy), keep in mind that these concepts can be applied to any external Java process (a Tomcat server, a JBoss server, a Swing app, even an Applet – with a few caveats).
Other Debugging Tools