jjb
Mutation listeners cause slowdown in two ways:
1)  Firing the event takes time O(tree depth at which mutation
     happened), with a constant that can easily be comparable to the
     cost of the mutation itself.
2)  Creating the event object includes various operations to grab the
     information mutation event objects carry (e.g. the old and new
     values for attribute changes); generating this can be expensive,
     because generating the string representation of some attributes is
     expensive (thing multi-dozen-kilobyte SVG path attribute, or large
     inline style block), and because conversion from our internal types
     to the ones mutation events want is expensive for nodes.
Some of these issues we could mitigate, of course....
-Boris
Is there a simple way to test the slowdown? I'm thinking with and 
without Firebug open kind of test.
jjb
Sure; just write whatever code you want to test and run it and time, no?
-Boris
Is it still the case that adding a mutation listeners and removing it
again won't bring back original speed?
Yes. There are no plans to change this, fwiw.
-Boris
>> Is it still the case that adding a mutation listeners and removing it
>> again won't bring back original speed?
>
> Yes. There are no plans to change this, fwiw.
I'm curious; what's left behind when removing the mutation listener that 
causes performance impact?
Justin
The reason we don't always pay the cost of firing mutation events is 
that we check whether there's a mutation listener before firing them. 
This check consists of two steps:
1)  Check a bit on the window that indicates that at some point a 
mutation listener for the relevant event type was added to something in 
that window.
2)  If the bit is set, walk up the tree from the target node checking 
whether the listeners are on that path.
If we find a listener as a result, we fire the event.
If you add and remove the listener, the bit remains set, so we have to 
do step 2 above.
-Boris
Can't that bit be replaced by a counter which is incremented when adding
a mutation listener and decremented when removing one, so that we can
only check its value against 0, and skip step 2 if it is?
Ehsan
Yes, at some cost in memory and time to handle a rare case.  In 
practice, mutation listeners, when actually used, are very rarely 
removed.  So the win would be purely theoretical.
Given further that many of the things that make mutation events slow to 
fire are also some of the things that are completely useless with 
mutation events (e.g. the old/new value stuff), we'd really rather focus 
on a mutation event behavior that makes sense and deprecating existing 
mutation events.
-Boris
You can see some basic numbers that I pulled out of the Dromaeo test 
suite with and without simple mutation listeners in place here: 
http://www.oxymoronical.com/blog/2008/10/How-extensions-can-slow-down-Firefox-my-dirty-little-secret
Slightly off topic but is "DOMAttrModified" a DOM mutation listener? On
the scale of listeners how much impact does listening to this event
have? Is there a better alternative?
Phil
-- 
Philip Chee <phi...@aleytys.pc.my>, <phili...@gmail.com>
http://flashblock.mozdev.org/ http://xsidebar.mozdev.org
Guard us from the she-wolf and the wolf, and guard us from the thief,
oh Night, and so be good for us to pass.
Yes.
> On the scale of listeners how much impact does listening to this event
> have?
It slows down all attribute changes; the amount of slowdown depends on 
the exact attribute being set, the styles on the page, etc.  A good 
estimate is probably 2x slower, but I haven't measured recently.
> Is there a better alternative?
From JS, sadly not yet.
-Boris
>Is there a better alternative?
>  
>
I've never tried this, but broadcasters might be. See 
https://developer.mozilla.org/en/XUL_Tutorial/Broadcasters_and_Observers#Broadcast_event
-- 
Warning: May contain traces of nuts.
I could still clarify that mutation events have
large performance impact in all the browsers.
-Olli
I'm curious too. When you say "there are no plans to change this", is 
that purely a lack of plans (perhaps because it just doesn't matter), or 
is there some reason why this is difficult to change? It seems easy 
enough to clear the bit when a listener is removed and the resulting 
list is empty, but perhaps there's a race condition involved? Or some 
other complexity?
Not good. I'm porting some Firefox front end code to SeaMonkey that
makes heavy use of DOMAttrModified.
That was the first thing I thought of, but the menu items in the Firefox
code I'm trying to port are dynamically generated and don't have IDs.
Hmm but there may be a way around this. Let me think about it
If there's a more performant way to do it, I'm sure the Firefox folks 
would be happy about a patch as well ;-)
Robert Kaiser
-- 
Note that any statements of mine - no matter how passionate - are never 
meant to be offensive but very often as food for thought or possible 
arguments that we as a community needs answers to. And most of the time, 
I even appreciate irony and fun! :)
> It seems easy enough to clear the bit when a listener is removed and 
> the resulting list is empty, but perhaps there's a race condition 
> involved? Or some other complexity?
Each element has its own list. However there is only one bit for the 
entire document that says "at least one element has had a mutation event 
handler". It's done this way so that if the bit is clear we don't 
actually have to trawl through looking for the event handler(s).
Per Robert's reply as well - wouldn't it be possible to adapt this code so the 
items have predictable, dynamically generated IDs?
Cheers,
Gijs
Well, in Firebug, we could make the HTML panel have a enable/disable
option like the other panels, if it made a difference to people. But
if hooking things up once, causes the slowdown forever, then I guess
that is why the panel is always active. Is there a bugzilla entry for
fixing this, even if no one wants to do it? At least to track it,
should someone change their mind?
-steve--
The cost of the mutation listener itself is the least of the Firebug 
HTML panel's performance problems.  Most of the cost is in the panel 
code itself (esp. the domplate gunk), last time I profiled.
 > Is there a bugzilla entry for
 > fixing this, even if no one wants to do it? At least to track it,
 > should someone change their mind?
Not at the moment. Feel free to file!
-Boris
One other thing worth filing: a request for a better API for Firebug to 
use.  DOMi doesn't have this problem, for example, since it uses a C++ 
DOM observer...
-Boris
But the domplate only hits when adding info to the panel (first HTML 
look, inspect, user hits a twisty).  The mutation listener cost is 
continuous, independent of Firebug-clicks, and continues after Firebug 
and it's domplate are gone. This is reason I asked originally, because 
it will appear to affect Firefox performance even when a user does not 
get value from Firebug view.
jjb
What code?
This search suggests that we're using it only in bookmarkProperties.xul:
http://mxr.mozilla.org/mozilla-central/search?string=DOMAttrModified&find=%2Fbrowser%2F&findi=&filter=^[^\0]*%24&hitlimit=&tree=mozilla-central
Instead of looking at the actual patch/bug I really should have looked at:
1. the current mozilla-central tabbrowser of the all-tabs popup.
2. the Thunderbird tabmail implementation.
3. the MailNews tabmail implementation.
Firefox solved this by applying a sledgehammer to the problem.
The Thunderbird tabmail implementation appears to be frozen in time and
still uses DOMAttrModified :S
In the SeaMonkey tabmail implementation Mnyromyr[1] found a much more
elegant solution which we should all steal.
I think my brain shorted out trying to reconcile three^Wfour[2]
divergent tabbrowser implementations. Can we please unfork at least some
of the code into a generic toolkit base binding, pretty please?
[1] Damn ingenious these Germans.
[2] Firefox tabbrowser, SeaMonkey tabbrowser, Thunderbird tabmail,
MailNews tabmail.[3]
[3] Gawd knows what sort of evil mutant tabbrowsers Spicebird,
Instantbird, and Postbox are using.
If someone does file a bug regarding that, please mark bug 578218 as 
dependent, or let me know about it.
You know, a really crazy thought occurred to me some months ago, which 
is that someone could write a shim that implements nsITreeBoxObject and 
either rests between inDOMView and its box object, or replaces its box 
object completely.  When the fake box object captures calls to 
RowCountChanged, it means a node was inserted, a node was removed, or a 
twisty was clicked to show its children (or an attribute was added or 
removed, if whatToShow allows them to be shown).
But yeah, don't take this as an encouragement to actually do that.
-- 
Colby Russell
Thanks,
Dan
Having mutation event listeners affects only to the performance of the 
document/window in which they are used.