Closed Bug 270257 Opened 21 years ago Closed 21 years ago

nsSVGElement::SetParent is expensive

Categories

(Core :: SVG, defect)

x86
Linux
defect
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: bzbarsky, Assigned: jwatt)

References

Details

(Keywords: perf)

Attachments

(2 files, 5 obsolete files)

This seems to send various notifications to some sorts of listeners on the nsSVGLength attributes (from nsSVGRectElement::ParentChainChanged()). Can those be lazy, somehow? Esp. in light of bug 270255... All that's happening here is creating an SVG node, setting 5 attrs, and inserting into the document; it looks like we do a fair amount of duplicated work during that process.
one thing that is expensive is that we end up with a callchain like this: SetContext->DidModify->NotifyObservers->DidModifySVGObservable->NotifyObserves-> nsSVGElement::DidModifySVGObservale->nsSVGElement::SetAttrAndNotify In other words, we end up setting as reall attributes all 'mapped attributes' that we call SetContext on. This is both expensive and wrong since those attributes shouldn't show up in the DOM unless explicitly set.
Actually I don't think we should call Will/DidModify in nsSVGLength::SetContext at all. To expand the call chain Jonas mentioned, the stack that results in SetAttrAndNotify being called when inserting an nsSVGRect element into a document is as follows. Object Method ------ ------ nsSVGRect nsSVGElement::SetAttrAndNotify() nsSVGRect nsSVGElement::DidModifySVGObservable() nsSVGAnimatedLength nsSVGValue::NotifyObservers() nsSVGAnimatedLength nsSVGValue::DidModify() nsSVGAnimatedLength nsSVGAnimatedLength::DidModifySVGObservable() nsSVGLength nsSVGValue::NotifyObservers() nsSVGLength nsSVGValue::DidModify() nsSVGLength nsSVGLength::SetContext() nsSVGRect nsSVGRectElement::ParentChainChanged() nsSVGRect nsSVGElement::SetParent() I don't think we should call Will/DidModify for changes further *up* a parent chain - only for changes further *down* it. When one object watches another, it should only expect to be notified if that object or one of its decendents changes. I don't think nsSVGLength::SetContext should be an exception to this rule. The nsSVGLength object itself doesn't actually change as a result of one of its ancestors being inserted into a new coordinate "context". Whenever SetContext is called, it's because the nsSVGLength or one of it's ancestors is being inserted into an SVG document fragment, or because it is being inserted/removed from an nsSVGLengthList object. The function that carries out the insertion should make sure any necessary notifications are sent out.
Assignee: general → jonathan.watt
Comment on attachment 168073 [details] [diff] [review] don't Will/DidModify in SetContext Alex, can you review please.
Attachment #168073 - Flags: review?(alex)
Blocks: 111993
Blocks: 272885
Comment on attachment 168073 [details] [diff] [review] don't Will/DidModify in SetContext As discussed on irc, this won't work. For percentage lengths, the 'real' user-unit value is determined by looking at the context, and most observers expect to be informed of a change in the 'real' value of a length. The quick and dirty workaround would be to add a 'we-are-changing-the-context-not-the-actual-specified-value'-flag to WillModify/DidModify.
Attachment #168073 - Flags: review?(alex) → review-
Do we really need to notify the frame about parentchanges? It seems like whenever the parent is changed we will move the node out of the old position in the tree and into the new. During the moving out isn't the frame get destroyed, and then recreated once the element is in the new position?
(In reply to comment #6) > Do we really need to notify the frame about parentchanges? It seems like > whenever the parent is changed we will move the node out of the old position in > the tree and into the new. During the moving out isn't the frame get destroyed, > and then recreated once the element is in the new position? Good point. Maybe the patch is ok after all.
Attachment #168073 - Flags: review- → review+
Checking in nsSVGLength.cpp; /cvsroot/mozilla/content/svg/content/src/nsSVGLength.cpp,v <-- nsSVGLength.cpp new revision: 1.14; previous revision: 1.13 done
Backed out per irc conversation.
I've opened bug 274886 to address the issue of the SetAttrAndNotify call separately since it no longer looks as if it will be fixed by removing the WillModify/DidModify calls. One thing we should do is check if mSpecifiedUnitType == SVG_LENGTHTYPE_PERCENTAGE before calling WillModify and DidModify in SetContext. That doesn't make the notifications lazy, but it will eliminate a lot of unnecessary notifications.
No longer blocks: 111993, 272885
Tim, can you check this doesn't crash you and review please?
Attachment #168073 - Attachment is obsolete: true
Attachment #168863 - Flags: review?(tor)
Attachment #168863 - Flags: review?(tor)
Attached patch patch (obsolete) — Splinter Review
of course all lengths that aren't already in user units need a context to determine what their user unit value is - thanks alex!
Attachment #168863 - Attachment is obsolete: true
Attached patch patch (obsolete) — Splinter Review
wrong file, sorry for the spam :-(
Attachment #169220 - Attachment is obsolete: true
Attached patch patch (obsolete) — Splinter Review
:-/ Win98 seems to have a stupid "feature" where it opens text files under their DOS name. Again, sorry for the spam, here's the patch with the changes.
Attachment #169221 - Attachment is obsolete: true
I'm not sure about making things lazy, but how about we only notify our observers when necessary? bz: I would be interested to know if the checkin to fix the problem whereby SetAttrAndNotify was always being called has helped performance any.
Attachment #169224 - Attachment is obsolete: true
Attachment #171842 - Flags: review?(tor)
Comment on attachment 171842 [details] [diff] [review] only notify when necessary r=afri
Attachment #171842 - Flags: review?(tor) → review+
Comment on attachment 171842 [details] [diff] [review] only notify when necessary Thanks Alex! Before this patch get's checked in I'd like to make sure that Tim doesn't crash with it applied. Tim?
My testcases seem to work fine with the patch now.
Checked in.
Boris, can I close this bug? If you can think of anything specific we could do to make nsSVGElement::SetParent more efficient then I'll have a go at it here. If you have any general problems with the notification system I think we should open a separate bug.
Feel free to close it, yes. I'll profile the testcase in bug 261974 with this patch and file new bugs as needed....
Status: NEW → RESOLVED
Closed: 21 years ago
Resolution: --- → FIXED
OK. With a build from MOZ_CO_DATE="Thu Jan 20 22:08:11 CST 2005" the time spent in SetParent is less than 0.6% of the total time spent on the testcase in bug 261974. So looks like this helped, at least for those attributes!
bz, what do you get if you change all dimensions into millimeters: el.setAttribute("x", Math.random()*100 + "mm"); el.setAttribute("y", Math.random()*100 + "mm"); el.setAttribute("width", "1mm"); el.setAttribute("height", "1mm"); That will give you poorer results. What I'd be interested to know though, is how the results from that compair to your original results.
Using "mm" makes the time in SetParent about double. I don't recall how this compares to what I used to see... I suppose I could back this patch out (just the last one, right?) and retest without it.
No, testing using "mm" should give you virtually the same results as with the patch backed out. The patch only made things faster for unitless and "px" lengths. What I was interested to know was how much the patch for bug 274886 has helped. It essentially stopped us from calling SetAttrAndNotify, and I was interested to know how much time had been spent in that function. Unfortunately, the patch to that bug was rather more wide reaching (it touched 51 files) so if you don't remember what you were getting before then I guess we'll never know. :-)
Well... Given that I filed this bug, the number before was at least in the 5% ballpark, and I seem to recall it being more like 10-15%. I wasn't going to say it because this patch didn't seem to help that much, but yes, the patch for bug 274886 would have helped a good bit.
Great, that's what I wanted to know. BTW, when you said the time *in*, did you mean the time *under* (by which I mean the time spent from when SetParent starts, to when it ends).
Yes, all times are under. Time in the function itself is pretty negligible. ;)
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: