Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

Improving the performance of MuCommander

80 views
Skip to first unread message

marius

unread,
Oct 26, 2008, 4:35:23 PM10/26/08
to mucommander-dev
MuCommander starts up in just a few seconds (3-5 s). It may seem fast,
but I wanted to see if I can reduce the startup time.

First, I configured some settings:
- disabled splash screen
- disabled system notifications
- disabled check for update
- disabled bonjour services

My first step was to measure time before the main window was
initialized. I added System.exit(0) before the line that creates the
main window and commented out the shutdown hook. The shutdown hook is
responsible for saving the configuration when mu closes down so I
commented it out.
See 1. Launcher.patch (all files are located in files section in
startup_time.zip)

To profile the application I was using Eclipse 3.4 with TPTP. I
enabled the Execution Time Analysis.

Profiling adds some overhead so the times shown in the following
report are not the real times (when the profiling is disabled). But I
think these reports show actual time percentage spent in each method.

In the report 1 there are 10 methods with highest base time - that is
time spent in method excluding calls to other methods.

The 15% of time is spent in static initializer (-clinit-()) of
AbstractNotifier. Notice I disabled notifications in the beginning!
From the "call tree" tab (report2) we can see that this is called from
static initializer of MuConfiguration:

public static final boolean DEFAULT_ENABLE_SYSTEM_NOTIFICATIONS =
com.mucommander.ui.notifier.AbstractNotifier.isAvailable()
&& (OsFamilies.MAC_OS_X.isCurrent() ||
OsFamilies.WINDOWS.isCurrent());

isAvailable() method triggers static initialization of the
AbstractNotifier class. This initializer calls several methods, but
their execution time is very low. The answer to the long execution is
in the call to SystemTray.isSupported(). The time of this method is
not shown on call tree because it is a system method and all system
calls are excluded.
The first thing I did was to perform lazy initialization on the
notifier. I moved the code from static initialization to the
getNotifier() method (2. AbstractNotifier.patch). But this code
(getNotifier) was executed as before from the MuConfiguration class,
because AbstractNotifier.isAvailable() called getNotifier. The value
DEFAULT_ENABLE_SYSTEM_NOTIFICATIONS is used in this call from main()
method:

if(MuConfiguration.getVariable(MuConfiguration.ENABLE_SYSTEM_NOTIFICATIONS,
MuConfiguration.DEFAULT_ENABLE_SYSTEM_NOTIFICATIONS))
It is used as a default value when a configuration file doesn't
specify the value for enabling/disabling system notifications. And
this value is set to true if notifier is available (can be
instatiated) and the system is mac os x or windows.
There are two solutions to optimize this:
- get the default value only if a configured one is not given (now the
default value is always calculated, so even when we aren't using the
noftifier, the notifier is created)
- modify the default value to not call isAvailable()
I chose the second solution (3. MuConfiguration.patch)

My new formula for calculating default value for system notifications
was:

public static final boolean DEFAULT_ENABLE_SYSTEM_NOTIFICATIONS =
OsFamilies.MAC_OS_X.isCurrent() ||
(OsFamilies.WINDOWS.isCurrent() &&
JavaVersions.JAVA_1_6.isCurrentOrHigher());

As you can see, there is no more AbstractNotifier in top 10 (report3).
But the InternalOpen() popped up.
If you look into the constructor there are only 2 lines:
if(Desktop.isDesktopSupported())
desktop = Desktop.getDesktop();
The code was very fast with the notifier initialized, but after the
change it got slow. I think this was because there is some
initialization in AWT/Swing that caused that. When I modified the code
to lazy initialization, another methods got into the first place -
InternalBrowse(). And the code for InternalBrowse() was the same as
for InternalOpen(). So I added a lazy initialization to
InternalBrowse() too (4. InternalOpen_Browse).

After applying this patch another method showed:
SwingFileIconProviderImpl.checkInit. This method had been added to fix
a bug in the initialization of icon provider. Swing icon provider used
to be initialized lazily and had been changed to early initialization
because of the bug with a deadlock. So we cannot do much about it.

to be continued...

Maxence Bernard

unread,
Oct 26, 2008, 5:41:43 PM10/26/08
to mucomma...@googlegroups.com
Hey Mariusz,
Thanks for sharing this! Both changes (MuConfiguration and InternalOpen/InternalBrowse) sound good, feel free to commit them whenever you like.

As a sidenote, the Notifier API will eventually be moved into the Desktop API. We'll have to pay attention to startup/init when we get to it.

Cheers,
Maxence
Reply all
Reply to author
Forward
0 new messages