Almost every day we hear of new companies adopting Eclipse as their application development platform of choice. With all these companies' products (not to mention all the Eclipse board member companies' products) potentially converging on the same installation, the risk of memory bloat and performance degradation is high. This article introduces a very helpful but not well-known tool, the Runtime Spy, to aid the plug-in developer. The Runtime Spy perspective is part pf the Core team's group of Spies and Tools (see Resources for a download link).
Note: The Core Tools run on Eclipse version 2.x only. At the time of this article's publication, they did not run on the Eclipse 3.0 drivers; bug 47518 has documented this problem.
Eclipse's architecture is designed to enable the discovery of extensions to its environment at runtime. This architected extension capability allows many tools to integrate seamlessly into Eclipse. The Eclipse architects recognized early in the project that these extensions could not be defined programmatically in client code since the cumulative startup cost would become prohibitive as Eclipse integrated more and more extensions. Instead, these extensions are defined by plug-ins.
To avoid this startup cost while retaining flexibility, a plug-in statically defines its extensions in a manifest file. The plug-in manifest defines enough information to enable the Eclipse platform to postpone loading code while still recognizing the initial contributions of an extension. For example, the user interface extension points require enough information to render the initial user interface element (for example, the icon and tooltip text of a contributed toolbar button) so the platform can defer loading the plug-in code until the user actually chooses a menu option, selects a toolbar button, opens a preferences page, or starts a creation wizard. The initial cost of a plug-in is only the parsing of its manifest. The XML format parses quickly, and the result is saved to disk for the next time, so startup is not significantly affected as new plug-ins and extensions are defined. There are, however, means by which this benefit can be unwittingly defeated, thereby increasing startup time and memory consumption.
Fortunately, Eclipse plug-in developers can use the Runtime Spy perspective to help track down these problems. This article introduces the Core Tools plug-in and its Runtime Spy, plus some tidbits that describe its utility beyond what is already covered in the readme (see Resources). Part 2 of this article series describes the common programming mistakes that may lead to poor startup time. It also demonstrates how we used the Runtime Spy to improve the startup performance of IBM® WebSphere® Studio Application Developer version 5.1.1.
The installation is simple. Just download the Core Tools zip file and unzip it into your <inst_dir>\eclipse\plugins directory. Next decide whether you want to spy on your base Eclipse installation (use the
-debug command line option) or whether you want to spy on your Run-time Workbench (use the Tracing page of its launch configuration. We'll return to this in "Spying on the Run-time Workbench"). For now let's go with the first choice: spying on your base Eclipse installation.
To begin, enable all the available Spy options by copying the sample .options file from the plugins\org.eclipse.core.tools_1.0.2 subdirectory into your <inst_dir>\eclipse directory. This will enable all options except those for class monitoring. To monitor class loading, you must list the packages or plug-ins that contain the classes that interest you in the plugins\org.eclipse.core.boot_1.0.2\trace.properties file. We'll come back to how you specify these in "Seeing what classes of a plug-in were loaded".
Next start Eclipse, and remember to specify the
-debug command line option, which will read the .options file found in the <inst_dir>\eclipse directory. Alternatively, you can identify the location of the .options file as a parameter to the
-debug option (for example,
Let's assume you've installed the Core Tools files and restarted Eclipse. Since the
-debug command line option is specified, you'll see some startup messages that were directed to stdout. When in debug mode, these are displayed in a separate Command Prompt window as shown in Figure 1.
Figure 1. Specifying the -debug option opens a Command Prompt window that shows stdout messages
Now that everything is up and running, let's take a quick tour of the Runtime Spy's views. Keep in mind that the Spy runs in the same Workbench as the "spied" plug-ins, so some plug-in activation may occur through the natural course of using the tool itself. Usually this isn't an issue, since it only uses base functionality that will probably already be loaded or would have been loaded soon enough anyway. In the unlikely case that it does matter, remember that its views are only refreshed on demand, so the first time the Runtime Spy perspective is opened, it will show only those plug-ins that were active before its own activation.
Selecting Window > Open Perspective > Runtime Spy opens four views, as shown in Figure 2.
Figure 2. Runtime Spy perspective is composed of the Activated Plugins, Loaded Classes, Plugin Datasheet, and Stack Trace views
If you forgot to specify the
-debug option, you'll see the message "Plugin monitoring is not enabled" displayed in the Activated Plugins view. The Loaded Classes view will contain the message "Class monitoring is not enabled" since the default is no class monitoring. Capturing class loading information slows Eclipse, so you must list which classes you're interested in by specifying the package(s) or plug-in(s) that contain them. For now we're only interested in what plug-ins are loaded. Figure 3 shows the Runtime Spy's central view, Activated Plugins.
Figure 3. Activated Plugins view shown in the Runtime Spy
If you want memory usage statistics shown in the Runtime Spy views (Alloc, Used, and Rom Used columns), you must use the IBM Java Runtime Environment with J9 technology. This JRE is included with the IBM® version of Eclipse called WebSphere® Studio Workbench, which is available as a free download after you register with IBM PartnerWorld for Developers (see Resources for links). Remember to specify the J9 as an argument to the Java runtime environment (for example,
eclipse -debug -vmargs -Xj9).
Clicking the first column heading, Plugin, changes the sort to ascending, descending, and ascending with grouping. The plug-ins grouped under the "+" symbol are the required plug-ins that were activated during the activation of the parent. When loaded plug-ins are grouped, the row's values are for the plug-in and all its child plug-ins. Use this ordering when you want to see the big consumers as a group.
The plug-in names followed by an asterisk are those that were loaded during startup. Despite what the name may suggest, the set of startup plug-ins marked with an asterisk in the Activated Plugins view will not include those that were loaded as a result of the Workbench processing its org.eclipse.ui.startup extension point. That is, the Workbench processes these extension contributions after the initial startup.
Of particular interest is the Order column. Clicking the column heading sorts the list of plug-ins in load order. If you want to quickly see what plug-ins are activated by a given action, select all the plug-ins beforehand (Ctrl+A), perform the action, return to the Activated Plugins view, and then select the button. The unselected plug-ins are those that were just activated. Alternatively, note the order value of the last plug-in that was activated before your action, and then afterward refresh to see those plug-ins that are ordered higher.
Classes of a plug-in are loaded on demand. You can potentially save memory and startup time by deferring these references or reducing the reference set of classes. The Loaded Classes view will help you see what classes of the selected plug-in have been loaded so far. To update the Loaded Classes view, select one or more plug-ins from the Activated Plugins list, and then select the button. The loaded classes for the org.eclipse.jdt.core plug-in are shown in Figure 4, sorted in load order.
Figure 4. Loaded Classes view shown in the Runtime Spy
In addition to the plug-in activation order, I found this view useful to get a "big picture" of what classes and sequences a given action initiates by sorting in order of reference. The plug-in startup code is included in this list and gives you a good idea of the cost of executing it. The moral of that story is often "too much is done at startup."
To get a better idea of what led to the activation of a plug-in or the loading of a class, you first must have the trace options enabled for the plug-ins or packages of the classes that interest you. In this example, I created a traces.properties file containing the line
packages=org.eclipse.jface.text. Then you need to:
- Select the org.eclipse.jface.text plug-in in the list of Activated Plugins.
- Update the Loaded Classes list by pressing the button.
- Select the
- Select the button to update the Stack Trace view.
This will display what code led to the classloader loading the class, and if it wasn't already done earlier, activating the selected plug-in, as shown in Figure 5.
Figure 5. Stack Trace view shown in the Runtime Spy
The top of the stack generally isn't interesting, since that's tracing the classloader code itself. The useful information is about midway down. In this case, the stack trace shows the
ITextViewer class was ultimately loaded because the Runtime Spy perspective was opened, as shown at the bottom of the highlighted stack trace lines. The perspective opened its initial views, including the Plugin Datasheet view, which uses the JFace Text class
TextViewer to display its data. While verifying the class during
defineClass, the JVM found it needed
ITextViewer as well because
TextViewer implements this interface. As you can see, the JVM's runtime classloading can be nested quite deeply; for performance purposes you'll generally focus on the code leading up to the classloader calls, similar to the highlighted portion of the stack trace shown in Figure 5.
The previous example showed why a specific class was loaded. You can also see why a given plug-in is loaded, but the reason for a plug-in's activation may not seem as obvious because the causes are indirect. Unlike a class that is typically loaded because it is referenced in another class' method (and has a corresponding
import statement you can refer to), plug-ins are loaded as a consequence of some indirect reference. Recall that the goal is to avoid loading plug-ins until they are needed, so references to the plug-ins themselves are by:
- Explicitly stated identifiers such as
<import plugin="org.eclipse.ui">in the plug-in manifest, or
- Implied identifiers such as the exported packages in the runtime JARs for that plug-in
Both of these examples are highlighted in the extract from the "Hello, Eclipse" plug-in manifest, shown in Listing 1.
<?xml version="1.0" encoding="UTF-8"?> <plugin ...> ... lines omitted ... <runtime> <library name="hello.jar"/> <export name="*"/> </library> </runtime> <requires> <import plugin="org.eclipse.core.resources"/> <import plugin="org.eclipse.ui"/> </requires> ... lines omitted ... <extension point="org.eclipse.ui.actionSets"> <actionSet label="Sample Action Set" visible="true" id="hello.actionSet"> <menu label="Sample &Menu" id="sampleMenu"> <separator name="sampleGroup"> </separator> </menu> <action label="&Sample Action" icon="icons/sample.gif" class="hello.actions.SampleAction" tooltip="Hello, Eclipse world" menubarPath="sampleMenu/sampleGroup" toolbarPath="sampleGroup" id="hello.actions.SampleAction"> </action> </actionSet> </extension>
The contribution of an action set to the org.eclipse.ui.actionSets extension point implicitly depends on the defining plug-in, the Workbench UI plug-in (org.eclipse.ui). The Workbench plug-in will read the plug-in registry, which includes this contribution to its org.eclipse.ui.actionSets extension, and create the appropriate action sets. The
SampleAction class will not be loaded at this point and therefore neither will its containing plug-in. Instead the Workbench plug-in defines a delegate action to represent the choice in the user interface that waits until the user actually selects it before creating an instance of
SampleAction to handle the response.
To create an instance of
SampleAction, the action delegate calls the
method of the plug-in registry instance
IConfigurationElement that represents the
<action class="hello.actions.SampleAction" ...> tag specified in our example manifest file. That's all well and good, but sometimes it isn't obvious looking at the resulting stack trace. Let's take a closer look at a more difficult example than the selection of a "Hello, Eclipse" menu choice. Figure 6 shows a typical activation that resulted from the processing of an executable extension. Now let's use the Stack Trace view to determine what caused it, following the same steps as before.
Figure 6. Stack Trace view showing executable extension activation
In this case, we see from the bottom of the highlighted portion of the stack trace that it all began with a double-click in the PDE's Plug-ins view. The default action handler responsible for handling the action requested the Workbench to open the Plug-in Manifest editor, which subsequently activated the org.eclipse.ui.editors plug-in. The highlighted portion of the stack trace shows only the code of the extension point processor because its reference to the Workbench plug-in classes, org.eclipse.ui, is indirect. After working through half-a-dozen similar stack traces, you'll recognize the important parts before and after the calls to
IConfigurationElement.createExecutableExtension and quickly see who started it and what happened as a result. You can refresh the loaded classes by selecting the
button again and resort by load order to get a better idea of what happened after the plug-in's activation.
Finally, the Plugin Datasheet view summarizes some interesting statistics, such as how many resources and extensions the plug-in defines, as shown in Figure 7.
Figure 7. Plugin Datasheet showing used resources
This tracks the Resource bundle data that has been loaded via the
IPluginDescriptor.getResourceString method and its variants. This summary information takes advantage of the fact that the Eclipse Platform Runtime provides its own classloader, and classloaders handle resource bundles in the same fashion as classes, so keeping track of resource data statistics is straightforward. The "not loaded yet" message refers to the fact that the plug-in registry is written to disk, and referenced portions of it are reloaded only as needed.
The previous sections covered spying on the base installation of Eclipse itself. More realistically, you'll want to spy on your test version of the Workbench, known as the Run-time Workbench. You can configure the instance of the Run-time Workbench you wish to launch by selecting Run > Run As... > Run-time Workbench and turning to the Tracing page as shown in Figure 8.
Figure 8. Setting the Runtime Spy options in the Tracing page
The debug options of the org.eclipse.core.boot plug-in are populated with the <inst_dir>\eclipse\plugins\org.eclipse.core.boot_2.1.1\.options file choices we discussed earlier. This defines the defaults that you'll more than likely want (everything on). However, if you want to take reasonably accurate performance measurements of elapsed time, you should minimize the number of active options, especially those that require taking a stack trace (that is, trace/pluginactivation etc.). Setting
monitor/plugins to true and all others to false introduces little performance overhead.
You can find a lot of information on Java performance tuning, but very little specific to Eclipse. This article introduced you to one of best tools for understanding and diagnosing startup performance problems related to plug-in activation. Before closing, it is worth noting some of the other useful diagnostic information that the Core Tools provide you:
- The Plug-in Dependency perspective shows information similar to that shown in the Plug-in Registry view (accessible from Window > Show View > Other... > PDE Runtime > Plug-in Registry), but with an exhaustive listing of the dependent plug-ins of the selected plug-in.
- Ever wonder what the workspace's .metadata directory contains? The Metadata perspective will help you walk its structure. It does, however, presume considerable understanding of the Workspace implementation.
- The Resource Tools category of views presents useful insights into the inner workings of resource change listeners and resource deltas, builders, and more. The Resource, Delta, and Builder/Listener views are especially interesting for those learning the Workspace API. Select Window > Show View > Other... > Resource Tools) to access these views.
You can learn more about these tools in the Core Tools' readme (see Resources).
Part 2 of this article series will show how I used the Runtime Spy to diagnose several startup problems in WebSphere Studio Application Developer version 5.1.1. The subsequent improvements in startup performance varied from 11% to 37% depending on the active views and perspectives, demonstrating that knowing when and why your plug-ins are activated can help deliver on Eclipse's promise of a quick startup.
And just wait until you see version 6.0 of WebSphere Studio, where we'll really improve on startup performance!
- Read Part 2 of this series of two articles by Dan Kehn on tuning Eclipse's startup performance with the Runtime Spy.
- Download the Eclipse Core Spies/Tools, which includes the Runtime Spy perspective. Learn more about the tools in the Core Tools' readme.
- Download the WebSphere Studio Workbench, which includes the IBM JRE with J9 that the Runtime Spy requires to gather memory statistics. The WebSphere Studio Workbench is available as a free download after you register with PartnerWorld for Developers.
- For a comprehensive guide to Eclipse plug-in development, see The Java Developer's Guide to Eclipse, by Sherry Shavor, Jim D'Anjou, Dan Kehn, Scott Fairbrother, John Kellerman, and Pat McCarthy (Addison Wesley Professional, 2003). Below are other developerWorks articles by the same authors:
- " Internationalizing your Eclipse plug-in" (developerWorks, June 2002)
- "Testing your internationalized Eclipse plug-in" (developerWorks, July 2002)
- "Extend Eclipse's Java Development Tools" (developerWorks, July 2003)
- "Put Eclipse features to work for you" (developerWorks, October 2003)
- "How You've Changed! Responding to resource changes in the Eclipse workspace" offers additional insight on resource change listeners.
- "Project Builders and Natures" explains the mechanisms behind incremental project builders and natures.
- "Notes on the Eclipse Plug-in Architecture" further describes plug-ins and how plug-in extensions are defined and processed.
- The eclipse.org is the home of Eclipse. eclipse.org lists over fifty board member companies at present.
- Find more articles for Eclipse users in the Open source projects zone on developerWorks. Also see the latest Eclipse technology downloads on alphaWorks.
- Browse for books on these and other technical topics.
Dan Kehn is a Senior Software Engineer at IBM in Research Triangle Park, North Carolina. His interest in object-oriented programming goes back to 1985, long before it enjoyed the acceptance it has today. He has a broad range of software experience, having worked on development tools like VisualAge for Smalltalk, operating system performance and memory analysis, and user interface design. Dan worked as a consultant for object-oriented development projects throughout the U.S. as well as in Europe. His recent interests include object-oriented analysis/design, application development tools, and Web programming with the WebSphere Application Server. He co-authored The Java Developer's Guide to Eclipse.