sinkEvents optimization (25% gain by manual bubbling)

3 views
Skip to first unread message

Matthew Mastracci

unread,
Sep 23, 2007, 2:33:04 PM9/23/07
to Google Web Toolkit Contributors
I'd like to propose a big performance boost for sinkEvents by
switching the event model to global capture (through the Window
object) and manually bubbling events that aren't latency-sensitive. I
prototyped a very simple implementation of this and I'm seeing 25%+
faster sinkEvents calls (4480ms->2900ms in one test of adding 1000
labels in Firefox).

The theory of this change is:

1. sinkEvents causes a measurable hit when constructing lots of
widgets, so anything we can do to lighten up the function will help.

2. Most events aren't latency-sensitive, ie: key{press,up,down},
mouse{up,down}, [dbl]click, etc. If there's an extra 10-100 ms when
pressing a key, the user won't notice. On the other hand, the ones
that may happen many times per second are very latency-sensitive.
These ones are mousemove, mouseover, mouseout, mousewheel and scroll.

The big win for #1 is that GWT wouldn't need to set up most of the
event listeners in sinkEvents. In fact, it would only need to check
for five bits in the event mask, vs. the larger number it does today.
This would reduce the amount of time needed for Widget construction
and would be a win in some cases.

It's possible that this might be fast enough to handle *all* events
for #2, making sinkEvents a simple integer flag set operation. This
is currently untested.

One other possible problem might be with how onload and onerror events
bubble. This is currently untested.

The only change required in DOMImpl to support this is a single
function to handle the manual bubbling. It's just a prototype and
more performance could be squeezed out of it:

var domimpl = this;
function bubbleEvent(evt) {
var type =
domimpl.@com.google.gwt.user.client.impl.DOMImpl::eventGetTypeInt(Lcom/
google/gwt/user/client/Event;)(evt);
var target = evt.target;

while (target && !target.__listener && (((target.__eventBits ||
0) & type) == 0))
target = target.parentNode;

if (target)
@com.google.gwt.user.client.DOM::dispatchEvent(Lcom/google/
gwt/user/client/Event;Lcom/google/gwt/user/client/Element;Lcom/google/
gwt/user/client/EventListener;)(evt, target, target.__listener);
}

$wnd.addEventListener('click', bubbleEvent, true);
$wnd.addEventListener('mousedown', bubbleEvent, true);
$wnd.addEventListener('mouseup', bubbleEvent, true);

You can check out my prototype here. I've only prototyped this for
Firefox (DOMImplMozilla) for now. Additionally, only the click,
mousedown and mouseup events are correctly implemented.

http://www.box.net/shared/zh1cy9fg74

To try it with and without the changes, comment out the binding
section in .gwt.xml file to use the default or the improved version.

Let me know if you have any comments or concerns. With any luck,
there won't be any serious corner cases that I've missed.

Scott Blum

unread,
Sep 23, 2007, 8:43:39 PM9/23/07
to Google-Web-Tool...@googlegroups.com
There is also a competing proposal, which is to not sink events at all on most widgets, but only the ones that ACTUALLY get event listeners attached to them.  Assuming the majority of widgets don't get listeners attached, this could save big on startup time.

The fastest code is the code you never actually run (to paraphrase Joel Webber).

Matthew Mastracci

unread,
Sep 23, 2007, 10:07:52 PM9/23/07
to Google Web Toolkit Contributors
I'm not sure that these optimizations are competing. I think that
both of these proposals could be implemented at the same time for
bigger wins all around.

If I were adding listeners to a few hundred labels (or any other
control), this could help keep the overhead lower than the other
prototype alone. It helps automatically optimize for the case where a
developer is listening for events at a fine-grained level, even if
this case could be optimized by putting event handlers higher-up. If
I were creating labels without listeners, the other proposal would
certainly help the most, though this one would still eliminate many of
the event handlers that would need to be hooked up.

Would there be a case where using global listeners as an optimization
might interfere with using the listener collections to optimize event
sinking?

In any case, it looks like there's lots of low hanging fruit (the best
kind!) where optimization can take place in the event system.

Fred Sauer

unread,
Sep 24, 2007, 10:20:49 AM9/24/07
to Google-Web-Tool...@googlegroups.com
On 9/23/07, Scott Blum <sco...@google.com> wrote:
There is also a competing proposal, which is to not sink events at all on most widgets, but only the ones that ACTUALLY get event listeners attached to them.  Assuming the majority of widgets don't get listeners attached, this could save big on startup time.

+1   (without trying to detract from any other proposed orthogonal solutions)


--
Fred Sauer
fr...@allen-sauer.com

Matthew Mastracci

unread,
Sep 24, 2007, 10:48:28 AM9/24/07
to Google Web Toolkit Contributors
BTW, for those interested, the issue tracking lazy event
initialization that Scott mentioned is:

http://code.google.com/p/google-web-toolkit/issues/detail?id=1491&can=5

> f...@allen-sauer.com

Reply all
Reply to author
Forward
0 new messages