Bug 255534 - Optimize startup performance by replacing EventListenerList implementation
Summary: Optimize startup performance by replacing EventListenerList implementation
Status: NEW
Alias: None
Product: GEF
Classification: Tools
Component: GEF-Legacy Draw2d (show other bugs)
Version: 3.4   Edit
Hardware: PC Windows XP
: P3 normal with 1 vote (vote)
Target Milestone: ---   Edit
Assignee: Anthony Hunter CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-11-17 11:28 EST by Iwan Birrer CLA
Modified: 2013-10-17 09:45 EDT (History)
4 users (show)

See Also:


Attachments
Replacement for the draw2d EventListenerList (2.05 KB, text/x-java)
2008-11-17 11:28 EST, Iwan Birrer CLA
no flags Details
Executable gef snippet to profile initialization times (8.86 KB, text/x-java)
2008-11-17 11:29 EST, Iwan Birrer CLA
no flags Details
add profiling screenshot (8.64 KB, image/png)
2010-02-18 05:13 EST, Igor Burilo CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Iwan Birrer CLA 2008-11-17 11:28:09 EST
Created attachment 118060 [details]
Replacement for the draw2d EventListenerList

Build ID: M20080911-1700

Steps To Reproduce:

1. Create a new Pluin project, add the dependencies listed below to the Manifest and copy the attached EventListenerPerformance.java to the src folder.

- org.eclipse.jface 3.4.0
- org.eclipse.gef 3.4.1
- org.eclipse.core.runtime 3.4.0
- com.ibm.icu 3.8.1 

2. Run the EventListenerPerformance.java. Initialization times are printed to the console.

3. Import the org.eclipse.draw2d plug-in as a source project and replace the org.eclipse.draw2d.EventListenerList with the one in the attachenent.

4. Re-run the EventListenerPerformance.java. Initialization times are printed to the console.


More information:
With a growing number of edit parts (> 5000) the initialization time of a gef editor can increase to several seconds.

After some profiling we found that a great deal of the time is taken by the org.eclipse.draw2d.EventListenerList.addListener() class due to a System.arraycopy() for each listener added to the list.

The attached snippets demonstrates the slow down caused by the EventListenerList class for a growing number of edit parts by measuring the time for EditorViewer.setContents().

2000 edit parts:   141 ms
10000 edit parts:  1828 ms
20000 edit parts:  7109 ms
40000 edit parts: 31235 ms

By removing the array copy in the EventListenerList (see attached EventListenerList.java) and replacing the internal array with a map, we got the following numbers:

2000 edit parts:  110 ms
10000 edit parts:  375 ms
20000 edit parts:  594 ms
40000 edit parts: 1297 ms

The performance gain is quite obvious.
It boils down to a different approach on the array copy strategy: The attached EventListenerList implementation does the copy of the array when iterating over the list while the draw2d/GEF version performs the copy operation when adding a listener to the list. However the attached version may slow down updating the edit parts/figures. Our tests with and editable editor hasn't shown a perceivable slow down though.

We hope somebody can look at this issue and let us know if there's a chance that the EventListenerList implementation is changed for the next release.


Test environment: 
- Intel Core 2, T7200 @ 2 GHz, 2 GB Ram
- JavaSE-1.6
Comment 1 Iwan Birrer CLA 2008-11-17 11:29:36 EST
Created attachment 118061 [details]
Executable gef snippet to profile initialization times
Comment 2 Anthony Hunter CLA 2009-01-23 16:27:12 EST
We need to look into this for 3.5 if a performance gain is to be had.
Comment 3 Randy Hudson CLA 2009-01-26 09:32:56 EST
The implementation of EventListenerList is similar in performance to the implementation of EventTable in SWT, or ListenerList in org.eclipse.core.runtime.  Insertion performance is O(n^2).

With the patch, it is still O(n^2), but the performance for each type of listener interface is isolated from the others.

A better approach would be to grow Object array's size geometrically, as is done in ArrayList#ensureCapacity().  That way the number of calls to arrayCopy is Log(n) instead of N.
Comment 4 Igor Burilo CLA 2010-02-18 05:12:14 EST
I have the same problem too.
For 87000 edit parts it takes about 80 seconds. Also the problem isn't only in EventListenerList but in Figure.addPropertyChangeListener, I'll add an attachment of my profiling.

Target milestone for this bug is set to 3.5, but 3.5 is already completed, is there any plans for this bug for 3.6?
I'm using GEF 3.4.1.
Comment 5 Igor Burilo CLA 2010-02-18 05:13:01 EST
Created attachment 159408 [details]
add profiling screenshot
Comment 6 Alexander Nyßen CLA 2013-10-17 09:45:17 EDT
Unset target milestone as the specified one is already passed.