After reading Part 1 of this series, you should have a general idea of how the Runtime Spy can help you locate startup trouble spots. Let's turn to some specific examples of how to use it to reduce your plug-in's startup time. To make it more interesting, we'll look at some problems that were corrected with the help of the Runtime Spy as part of the performance improvements of IBM WebSphere Studio Application Developer.
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.
The two general goals for improving the startup performance of an Eclipse-based application are:
- Defer plug-in activation until as late as possible
- Minimize the amount of work involved in activating your plug-in
A common tenet of both goals is defer code execution where possible. Here are some ways you can do this:
- Don't load your plug-in
How? First and foremost, follow the lead of Eclipse's own plug-in extensions. Recall that many of the Eclipse extension point definitions require the contributor to statically declare enough information so that loading code can be deferred until the requested action is needed. This idea is fundamental to the Eclipse architecture and embodied in the plug-in manifest file declarations. Your own extension point definitions should embrace this approach. - Reduce class loading during plug-in initialization
The most common culprits are references within thePlugin.startupmethod. Many plug-ins override this method to perform their initialization. The ideal solution is often for your plug-in to defer its initialization until the user requests a specific action of your product. Otherwise, minimizing the number of referenced classes and plug-ins is the next best choice. In either case, the Runtime Spy can point to those that might be taking too much time or triggering the activation of too many other plug-ins. - Reduce CPU usage during plug-in initialization
Again, the most common cause points to code within the plug-in'sstartupmethod or code called by it. Lazy initialization of memory structures will save CPU time and may defer the activation of other plug-ins. Another possibility is to fork a separate low-priority thread during startup to perform initialization when the system is idle, although this choice requires more care to handle synchronization.
By deferring the activation of a plug-in, the user is given the impression of a zippier product. It may well be that the cumulative CPU usage is the same, but having it spreading it out in small chunks over a long period is less noticeable than paying the brute cost upfront. A delay is especially objectionable if it occurs at the first invocation (that is, starting your product, or opening the first perspective, editor, or view), as this is the very moment the user is focused on getting work done and not feeling especially patient.
The Runtime Spy gives you the basic statistics for tracking each of the three ways of speeding up startup, as shown in Figure 1.
Figure 1. Runtime Spy perspective is composed of the Activated Plugins, Loaded Classes, Plugin Datasheet, and Stack Trace views
Minimizing the number of items in the Activated Plugins view is your number-one goal.
Of those that do appear in this list, make it your number-two goal
to minimize the number of items in the Loaded Classes view. The Startup time column
in the Activated Plugins view
will point you to the big hitters. Selecting
the
button from the Activated Plugins view will
update the Stack Trace view to show you why a plug-in was loaded, and selecting the
button from the Loaded Classes view will show you why a
class was loaded.
Let's begin with examples of how to use the Runtime Spy to diagnose and correct a startup coding error. As you'll see, the corrections will not "improve" performance in an absolute sense but rather defer startup costs, giving the user the perception of an overall faster product. This is something that the base Eclipse product does very well, staging its startup costs in little chunks as you use it. This is the cornerstone of Eclipse's deferred plug-in load strategy.
To first survey the situation, let's start Studio with only the Runtime Spy perspective open. This should give a near-minimum load of plug-ins and the fastest startup, as shown in Figure 2.
Figure 2. Minimal activated plug-ins at startup
Notice the trailing asterisks in the plug-in names.
These are plug-ins that were loaded during the activation of the plug-in that
is responsible for launching Eclipse, the plug-in known as the application plug-in. This plug-in contributes
a class that implements the IPlatformRunnable interface
to the org.eclipse.core.runtime.applications extension point.
By default, the Workbench UI plug-in contributes an implementation of this interface that
creates the workbench window, collects action contributions to the main menu bar, toolbar, and so on, and generally prepares
the Eclipse workbench user interface for business.
The actual elapsed clock time will be greater than the sum of the Startup time column shown in the Activated Plugins view. This is because the latter doesn't include JVM activity prior to the loading of the Platform Runtime or CPU activity outside of plug-in startup. In the case shown in Figure 2, the start time was actually around 13 seconds from the time the launch configuration started the instance of the Run-time Workbench. It also includes some overhead that the development-time launch configuration itself introduces for tasks like building the plug-in list.
Even with this overhead, the startup time looks pretty good, right?
Consequences of the Workbench's startup extension point
Let's update the list of active plug-ins by pressing the
button.
Voilà! Our first surprise is shown in Figure 3.
Figure 3. Plug-ins activated by the org.eclipse.ui.startup extension point
The selected plug-ins are those that were initially activated. What are these additional 11 plug-ins? Perhaps some were loaded because of the Runtime Spy perspective. More interestingly, there are several Studio plug-ins that look suspicious in Figure 3. Shown at the top of the list are "cheatsheet" and "internet". What are they and why are they loaded now? Going back to the user interface, we find choices related to the first plug-in under the Help pull-down menu, as shown in Figure 4.
Figure 4. Plug-in activated by org.eclipse.ui.startup that could be avoided?
It is likely that only new users would choose the Cheat Sheets menu options, so why are we paying the cost of loading their associated plug-in at startup? The Workbench > Startup preference page reveals the answer, as shown in Figure 5.
Figure 5. Plug-ins contributing to the org.eclipse.ui.startup extension point
The org.eclipse.ui.startup extension point was perhaps one of the more contentiously debated
APIs for version 2.0. It is a carte blanche request to the Workbench UI to activate a plug-in
once the workbench window is opened,
bypassing the deferred load strategy. If a plug-in's manifest defines this extension point,
then its plug-in class must implement the IStartup.earlyStartup method.
There are legitimate uses of this API. The length of this article doesn't allow for treatment of every item in this list. So let's consider the validity of a couple of the extenders shown above in Figure 5:
- Cheat Sheets. The cheat sheet menu choices are built dynamically based on the installed features and reordered after each selection. There is no Workbench UI means to implement this behavior via extensions. It looks like this plug-in has no other choice but continue to "cheat."
- Internet Preferences. This startup code initializes the Window > Preferences > Internet settings based
on the system properties of the
URLclass. Since there is no way to know when this class will be referenced and since it has no explicit initialization methods, this appears legitimate. It may be prudent, however, to consider using a library extension. We'll return to why in a moment.
You may be wondering why the Workbench defines a Startup preference page in the first place.
Deselecting one of the listed plug-ins gives the user the choice of having a faster startup with reduced functionality. For example, experienced developers with no need of the hints provided by the Cheat Sheets cascade menu could choose
to disable its contribution to the org.eclipse.ui.startup extension point,
thus removing the Help > Cheat Sheets menu option.
Keep this in mind if your own plug-in contributes to this extension point. That is, code your plug-in defensively under the assumption
that the plug-in class' IStartup.earlyStartup method may not have been called.
Returning to our example in Figure 3, consider the non-asterisk plug-in com.ibm.etools.internet
in the list. Its stack trace in Figure 6 confirms why this plug-in was activated after the workbench window opened.
Figure 6. Workbench startup processing
The Workbench's run method is highlighted, where
the contributions to the org.eclipse.ui.startup extension point are processed.
Subsequent plug-in activations at this point are all attributed to either
the startup extension point or references thereof.
Sorting through potential WebSphere Studio hotspots
To see something Studio specific, let's open the J2EE perspective. (If you want to diagnose an easier scenario, open a single view,
for example, Window > Show View > DB Servers, not its corresponding perspective;
the list of activated plug-ins should be much shorter.)
After opening the J2EE perspective, return to the Runtime Spy and select
the Activated Plugin's
button.
Wow! The list jumps from 22 to 73 plug-ins, adding 20 seconds in plug-in activation
(the prior total was just over three seconds). Figure 7 shows them sorted in plug-in activation order,
with the most recently activated plug-in shown at the top.
Figure 7. Activated plug-ins after opening the J2EE perspective
In all fairness, the Runtime Spy adds overhead, especially if stack traces are captured, so true uninstrumented elapsed time is closer to 37 seconds overall from a warm start. But let's see if anything beyond the startup plug-ins jumps out as potentially unnecessary. To save space, the list below isn't exhaustive, since we accept that base components like EMF, JDT, and J2EE UI are required. But what about these?
- com.ibm.etools.validation.* (could be deferred or made optional?)
- com.ibm.etools.rsc.core.ui (db)
- com.ibm.etools.rdblib (db)
- com.ibm.etools.sqlmodel.* (db)
- com.ibm.sed.preferences (could be deferred?)
- com.ibm.etools.rsc (db)
- com.ibm.etools.sqlparse (db)
- com.ibm.etools.rdbschemagen.ui (db)
- com.ibm.etools.rdbexport.ui (db)
- com.ibm.etools.sqlbuilder (db)
- com.ibm.etools.subuilder (db and takes 1828ms to load!)
- com.ibm.etools.sqlj (db)
No views or editors specifically related to databases have been opened yet. So why were the relational database schema center (6) and so many other database-related plug-ins activated? The parenthetical comment "could be deferred" denotes those capabilities for which Eclipse has architected solutions to avoid activation until needed, as is especially evident in the case of preferences. Nonetheless, even when considered collectively, most of these are small potatoes. There are, however, some plug-ins that consume a lot of startup time and, as we'll see, their costs are tied to plug-in activation during the processing of extension points. The next section explains this cost more fully as it explores how startup costs are initially incurred. Then we'll return to our analysis of the J2EE perspective startup.
Understanding the relationship between plug-in activation and extension point processing
Saving some startup time by avoiding the activation of the subuilder plug-in
(Stored Procedure and UDF Builder, according to its plug-in manifest) looks
promising since it required almost 10% of the total time.
Moreover, it is near the end of the activation sequence (72 of 73), so it may be easier to "trim off"
than avoiding the activation of an earlier plug-in. The stack trace of this plug-in's activation is shown in Figure 8.
Figure 8. Plug-in activation stack trace for com.ibm.etools.subuilder
There is no need for Studio's source code to understand what's happening; the stack trace alone points to the cause.
The Eclipse class PartPane manages tabbed views like those you see containing
the J2EE Hierarchy, Package Explorer, and Navigator views. As shown
in Figure 8 beneath the text selection, the tabbed view PartPane
is attempting to create an instance of the
view associated with the J2EE Hierarchy tab, a class named J2EEView.
Looking further up the stack, we see this class is in turn calling a helper that then calls
the createExecutableExtension method.
The IConfigurationElement.createExecutableExtension method merits special attention.
As you'll discover when debugging your own
performance problems, this method instigates many of the plug-in activation cases that the Runtime Spy uncovers.
To better understand what it does and how it affects plug-in activation,
consider the simple extension point contribution shown in Listing 1.
You may recognize this as the same listing, the canonical "Hello Eclipse" sample,
from Part 1.
Listing 1. Sample extension point from "Hello, Eclipse"
<?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>
|
Note
the processing of the class attribute of the <action> tag.
This specifies the name of the class that will handle the menu choice selection, a class that must
implement the IWorkbenchWindowActionDelegate interface. This class isn't located
in the same plug-in as the one that processes the org.eclipse.ui.actionSets extension point,
the Workbench UI plug-in, or any of its prerequisite plug-ins. So how does the Workbench UI plug-in create an instance of this
class when it doesn't appear to lie on the plug-in's classpath?
It is the responsibility of a plug-in's classloader to resolve references to classes within its libraries.
The classloader maps plug-in references to their corresponding
JAR files containing the plug-in's classes, as in our example, SampleAction. Therefore, the Workbench
UI plug-in doesn't have to "know" about the classes referenced by attributes
like class of the <action> tag.
Rather, it is the "Hello Eclipse" plug-in defining a dependency on the
Workbench UI plug-in that allows it to access the plug-in class of the target plug-in
and thereby have access to Hello Eclipse's classes via the target plug-in's classloader.
To restate it more concisely, when Eclipse is unable to find a class, it asks the target plug-in's class loader to load the class;
that's what the createExecutableExtension method does.
Avoiding premature plug-in activation linked to extension point processing
Returning to the stack trace shown in Figure 8, we recognize that the code near the middle of the text selection
is processing extension contributions by calling createExecutableExtension -- and bingo! -- plug-ins
start loading. Our quest turns to answering the burning questions:
Was it necessary at this point? Can it be deferred until later?
Practically all classes that provoke the activation of another plug-in can ultimately be traced
back to an invocation of the createExecutableExtension method.
The invocation parameters specified on these calls denote the name of the attribute
(often "class") and its value, the fully-qualified name of the class to be loaded.
This leads back to the plug-in extension contribution responsible for
the activation, in our case, the subuilder plug-in. An extract of its manifest is shown in Listing 2.
Listing 2. Subuilder plugin.xml extract
<extension point = "com.ibm.etools.rsc.sp">
<sp
id = "com.ibm.etools.subuilder.sp.NewSQLSPAction"
name="%STR_NEWWIZARD_SQLSP"
group ="SPFolderAction.New"
view = "datadef"
class="com.ibm.etools.subuilder.actions.create.NewSQLSPAction"/>
</extension>
|
It terms of parameters, this extension contribution looks similar to the org.eclipse.ui.popupmenu
extension point for defining menu choice contributions; that is, it defines a label (attribute "name"), placement (attribute "group"),
target (attribute "view"), and most notably, a handler (attribute "class"). What differentiates the Eclipse
extension and this particular implementation is that Eclipse's extension creates a delegate class to act as a proxy
for the menu choice. It isn't until the menu choice is actually selected that the corresponding handler
class is created, thereby deferring the activation of the plug-in containing the handler class.
This same proxy strategy was applied to Studio's case above and the J2EE perspective opened almost seven seconds faster.
The cost of creating the NewSQLSPAction instance and activating
the plug-ins containing its referenced classes
wasn't eliminated but rather changed to
pay-as-you-go.
Now you see why this article is subtitled "Winning the shell game." It's all about managing the user's expectations and keeping their eyes away from what you hope they won't notice. In this particular case study example, the startup is now faster but the user will pay the same CPU costs later if they activate the database tools. That's acceptable since it is in small chunks, and more importantly, it moves the delay closer to the associated action where the user expects to pay.
Recall that the goal is defer code execution where possible, not only because it may result in a perceived improvement in performance, but also because the easiest code to optimize for speed is code that never executes. Eclipse's plug-in architecture makes it easier for you to create extensions that accomplish this, and the Runtime Spy helps you find those cases where your implementation could be improved.
- Read Part 1 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)
- "Notes on the Eclipse Plug-in Architecture" further describes plug-ins and how plug-in extensions are defined and processed.
- See Platform Extension Points to learn more about Eclipse's extension points like
org.eclipse.ui.startup. - The eclipse.org is the home of Eclipse.
- 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.




