|
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.
Posted Date : 2009-02-09 15:31:09.0
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.
Posted Date : 2009-02-26 10:21:52.0
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
Posted Date : 2009-02-26 10:21:52.0
|