United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6802944 Nimbus initialization is too slow
JDK-6802944 : Nimbus initialization is too slow

Details
Type:
Bug
Submit Date:
2009-02-09
Status:
Closed
Updated Date:
2011-01-25
Project Name:
JDK
Resolved Date:
2009-05-18
Component:
client-libs
OS:
generic
Sub-Component:
javax.swing
CPU:
generic
Priority:
P1
Resolution:
Fixed
Affected Versions:
6u14
Fixed Versions:
6u14 (b03)

Related Reports
Backport:
Backport:
Relates:
Relates:

Sub Tasks

Description
It was shown that avoiding Nimbus initialization saves about 10% of startup of simple FX apps.
E.g. here are data from Dmitry's experiment:

> In the meantime, the difference between initializing Nimbus L&F and not during startup is about 11% on my system for FXFramer: 2.24s vs 2.0s . 

This is significant chunk of time. Expecially because many FX applications barely need Nibmus as they do not use standard Swing components. 

There are some efforts to delay nimbus initialization on FX side. But these are workarounds and it will be always possible to defeat them. Nimbus startup has to be optimized.

                                    

Comments
EVALUATION

I've tried to profile following minimal example and found that there are number of things that can be improved:

==========
import javax.swing.JFrame;
import javax.swing.UIManager;

public class NimbusTest {
    public static void main(String[] args) throws Exception {
        UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
        JFrame f = new JFrame("Test");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        System.err.println("Done");
    }
}
===========

1) Nimbus does "compile" resources to hasmap different from UIDefaults. 
   Comment says it is done for performance reasons to avoid impact on miss lookups.
   I do not exactly understand this but the way NimbusStyle.compileDefaults() is implemented is wrong
   as it causes loading of ALL lazy values. 

   Rewriting this along following lines cuts time significantly (note that it is not ideal fix yet 
    as dereferencing lazy value will cause its replacement in the UIDefaults but not its update 
    in this compiled representation).

    private void compileDefaults(
            Map<String, TreeMap<String,Object>> compiledDefaults,
            UIDefaults d) {
        for (Map.Entry obj : d.entrySet()) {
            Object k = obj.getKey();
            if (k instanceof String) {
                String key = (String) k;
                String kp = parsePrefix(key);
                if (kp == null) continue;
                TreeMap<String,Object> map = compiledDefaults.get(kp);
                if (map == null) {
                    map = new TreeMap<String,Object>();
                    compiledDefaults.put(kp, map);
                }
                map.put(key, obj.getValue());
            }
        }
    }

2) derivedColor and derivedColorKey may cache hashcode in the transient variable.
   It is also helpful to check for equivalence of hashcodes in the equals(). 
   There are lots of hashmap lookups related to derivedkey object and it saves some time.

   For DerivedColorKey it has sense to save int representations of the fields instead of floats 
   as it will save subsequent hashcode() and equals() and noone actually needs their float versions.

3) NimbusDefaults.DefaultsListener.propertyChange() is not optimal as it triggers a lot of not needed events
   Keeping list of colors ordered (the only requirement is that "parent" color 
   has to be in front of any of its childs) will help to ensure that all changes could be done 
   by single iteration over array. (Note that you have to be careful with events here -
   e.g. you may want avoid posting events to same default listener).
   
   Also, when color is created if LAF was not set yet then there is no need to fire events or even 
  rederiveColor(). When LAF will be set all of them will be rederived again.

According to profiler these changes help to cut cost of Nimbus initialization to 20% of initial.
Perhaps something more can be done if NibusDefaults will be improved.
                                     
2009-02-09
SUGGESTED FIX

compileDefaults() can be rewritten using entrySet() instead of keySet(). It creates a set of TreeMaps which cannot resolve lazy values, so extra care should be taken when getting values from this map.

Ideally UIDefaults should compile these by-prefix maps on the fly, then there would be no need to scan the whole table each time a property is added. I have some ideas to try, but they're for jdk7.

DerivedColors could be updated more effectively if organized into a tree. It is that tree, and not individual colors, that should listen to color changes. It would then just rederive the updated color and all its children. So i introduce a new class, ColorTree, to NimbusDefaults with methods to add/traverse/update colors. This tree listens to changes to UIDefaults properly.

Some changes to generator files are needed, too.
                                     
2009-02-18
EVALUATION

compileDefaults() can be rewritten using entrySet() instead of keySet(). It creates a set of TreeMaps which cannot resolve lazy values, so extra care should be taken when getting values from this map.

Ideally UIDefaults should compile these by-prefix maps on the fly, then there would be no need to scan the whole table each time a property is added. I have some ideas to try, but they're for jdk7.

DerivedColors could be updated more effectively if organized into a tree. It is that tree, and not individual colors, that should listen to color changes. It would then just rederive the updated color and all its children. So i introduce a new class, ColorTree, to NimbusDefaults with methods to add/traverse/update colors. This tree listens to changes to UIDefaults properly.

Some changes to generator files are needed, too.
                                     
2009-02-26
EVALUATION

These changes improved performance of a simple test (set Nimbus, show a frame) by 14%.
Figures as measured by refworkload:
  Stock Nimbus:		1.07 sec
  Optimized Nimbus:	0.92 sec
  Metal:		0.73 sec
                                     
2009-02-26



Hardware and Software, Engineered to Work Together