Closed Bug 35294 Opened 25 years ago Closed 23 years ago

PERF: nsIDOMNode::InsertBefore() performance.

Categories

(Core :: DOM: Core & HTML, defect, P3)

defect

Tracking

()

RESOLVED FIXED
mozilla0.9.6

People

(Reporter: mozeditor, Assigned: jst)

References

Details

(Keywords: dom1, perf, Whiteboard: [HAVE FIX])

Attachments

(8 files)

I've broken out editor Paste performace into 5 bugs.  This one is about the 
InsertBefore() bottleneck.  There are two issues here:
 
1) We have to call InsertBefore() twice for each line of text we paste.  This is 
because we have to replace newlines with <br> nodes.  This is done because 
otherwise we cant draw a caret on blank lines.  If we had a frame for blank lines 
caused by newlines, then we wouldn't need to call InsertBefore() so much, so 
that's one possible way to address this performance problem.
2) InsertBefore() is taking 18+ milliseconds on my 300mHz G3 Portable.  The time 
taken slowly creeps upward as later lines are pasted in.  I assume that scannig 
through the lengthening child list as hundreds of nodes are inserted is what 
causes the creep upwards.  Any speed improvement to InsertBefore() is a big win 
for us in Editorland.
Blocks: 28783
ignore the 18+ milliseconds figure.  I meant 1.8 ms.  Your milage may vary.  What 
is true though is that the loop for chucking the text and breaks into the dom is 
bound by InsertBefore() performance, and that loop is a big piece of the time for 
paste (and once we've fixed some editor and caret perf problems, it should make 
up most of the paste time).
Block/inline problem so reassigning to Buster
Assignee: troy → buster
M18.  I know I won't get to this for beta 2.  Don't know where it falls in
priority order for FCS.
Status: NEW → ASSIGNED
Target Milestone: --- → M18
redistributing bugs across future milestones, sorry for the spam
Target Milestone: M18 → M19
Keywords: perf
marking FUTURE.  Unless this shows up as a major performance issue for a common 
task, it won't be looked at any time soon.  Joe, can you provide any hard data 
to change my mind?  "nsIDOMNode::InsertBefore() degrades exponentially with the 
number of lines" or "nsIDOMNode::InsertBefore() takes up 75% of the time to do 
any paste operation" or something like that?
Target Milestone: M19 → Future
i have a nice graphic of where time is spent in paste that i'll bring to you.
Joe - 

If I'm understanding this correctly, you're looking at a performance problem 
when pasting multiple lines of text at once.  My understanding (from the text 
above) of what you're currently doing is that you are doing insertBefore() for 
each line, and for the BR after it.

A possible solution (which *should* be faster, and I would think could be made 
faster if it is not) to this on your end could be to append all of the stuff 
into a DocumentFragment object, and then call insertBefore on the 
DocumentFragment.  See the DOM spec at 
http://www.w3.org/TR/DOM-Level-2/core.html#ID-952280727 (insertBefore)
http://www.w3.org/TR/DOM-Level-2/core.html#ID-B63ED1A3 (documentFragment)

It's worth looking at the code that would do this and making sure that it is 
fast or can be made fast before plunging ahead with this (although actually I 
wouldn't think it would be all that hard...).  If you have any questions, I 
might be able to help, although my knowledge in this area is mainly about the 
DOM itself rather than our implementation of it.
Component: Layout → DOM Level 1
insertBefore's implementation is O(n) with respect to the number of lines in the 
target:

1. due to the call to nsVoidArray::IndexOf(), which must scan the void array to 
find the element.

http://lxr.mozilla.org/mozilla/source/layout/base/src/nsGenericElement.cpp#1903

2. due to the call to nsVoidArray::InsertChildAt(), which requires O(n/2) to 
shift elements and create space for the new element.

http://lxr.mozilla.org/mozilla/source/layout/base/src/nsGenericElement.cpp#1985

I think dbaron is right on the money with respect to how to improve performance 
for this. Assigning back to jfrancis for investigation.
Assignee: buster → jfrancis
Status: ASSIGNED → NEW
sounds like a plan.  I had considered something like this before but didn't know 
about document fragments, so I didn't have a way to use Append().
Status: NEW → ASSIGNED
However, looking at the current implementation of insertBefore, it may not be 
optimized for inserting documentFragments, something that probably could be 
done.  In particular, it calls insertChildAt for every child inserted.  That 
implementation *is* a peformance bug that could be improved (although it might 
be a little messy).  Probably the two 
issues of:
 * speeding up documentFragment insertion
 * making editor paste use documentFragments
should be separate bugs.
Depends on: 43863
ooof.  Ok, it makes no sense to spend time on making the editor use docfrags 
until they are a performance improvement.  Given their current implementation, it 
would actually degrade performance to use them.  

I've opened a new bug 43863 for that issue and marked it as a blocker for this 
bug.
No longer depends on: 43863
adding the blocker info
Depends on: 43863
Blocks: 53252
No longer blocks: 28783
Keywords: mailtrack
I'd like to nominate this for nsbeta1.  I think this is one of the bugs that
affects message reply performance due to inserting text (if it's not one of the
bugs then ignore the nsbeta1 nomination and let me know).  reply performance is
one of our key areas and it looks like Jean-Francois data shows that we'd get a
big win if we could speed up inserting text.
Keywords: nsbeta1
Keywords: dom1
Component: DOM Level 1 → DOM Core
nom catfood:  with the mail perf landing, this is about to become the biggest
remaining mail perf problem.

(Is this the active bug or is there another somewhere?)
Keywords: nsCatFood
Assignee: jfrancis → jst
Status: ASSIGNED → NEW
QA Contact: petersen → desale
not sure why waterson assigned this back to me long ago.  The issue described 
here is a layout problem.  While I know there are editor performance issues as 
well, we really need a faster way to beat on the dom tree without firing off so 
many duplicate content notifications, etc.  

cc'ing me and assigning to layout
Keywords: nsbeta1nsbeta1+
Target Milestone: Future → mozilla0.9.1
*** Bug 43863 has been marked as a duplicate of this bug. ***
*** Bug 74907 has been marked as a duplicate of this bug. ***
Blocks: 22486
Blocks: 74912
moving to TM of 0.9.2 per PDT triage (you can check it into 0.9.1 until Friday,
18/May/01 or into 0.9.2 after the tree opens)
Target Milestone: mozilla0.9.1 → mozilla0.9.2
Johnny, will this help with the AppendChild() case as well?  That ends up being 
the one usually hit in mail reply.  InsertBefore() work is not wasted though and 
will help us elsewhere.
Joe, AppendChild() calls InsertBefore() so yes, this will benefit both thoese cases.
This improves my 4000 line mail reply testcase.  The AppendChild() call the 
editor makes is 15% faster with this patch.  Thanks!
Updating QA contact to Shivakiran Tummala.
QA Contact: desale → stummala
Joe, can you run the same tests with the new patch I attached? The new patch
only contains the changes to nsGenericElement.cpp, you also need the other
changes in the first patch in this bug.

The new patch should cut down the notifications we make to the document to 1
single call to nsIDocument::ContentAppended() when *appending* a document
fragment (in stead of calling nsIDocument::ContentInserted() for every node in
the document fragment). This is about as far as we can optimize appending of
document fragments in the DOM code (we could still get rid of some reallocing of
child pointer arrays, but that's hardly where we spend most of the time), any
further optimizations need to happen in layout land (i.e. frame construction)...
CC Putterman, someone on the mail team needs to be helping with this issue.  If
this proves out, then we should push to get all the existing reply speed fixes
incorporated.
Johnny, please merge these patches.  They conflict.
C:\moz_src\mozilla\content\base\src>patch <jstpatch4.txt
patching file `nsGenericElement.cpp'
Hunk #1 succeeded at 2400 (offset 207 lines).
Hunk #2 FAILED at 2419.
1 out of 2 hunks FAILED -- saving rejects to nsGenericElement.cpp.rej

Yeah, I couldn't patch the last patch
(http://bugzilla.mozilla.org/showattachment.cgi?attach_id=37337)

But I am building with the other patches and will export this opt build down to
the lab and run my perf tests against msgreply.
Can we have new patches that work. Thanks
Attached patch Above patches merged (deleted) — Splinter Review
latest patch gets AppendChild down to 2.62 seconds in my test scenario, down
from over 16 seconds.  Cool beans.
Moving to mozilla0.9.3
Target Milestone: mozilla0.9.2 → mozilla0.9.3
Moving to mozilla1.0
Target Milestone: mozilla0.9.3 → mozilla1.0
Back to mozilla0.9.3 per high demand for this fix, this still needs some more
work to handle errors more gracefully before this is checked in...
Status: NEW → ASSIGNED
Target Milestone: mozilla1.0 → mozilla0.9.3
Target Milestone: mozilla0.9.3 → mozilla0.9.4
a question about content, editor and nsVoidArray (used heavily): does it make
sense to add some type of way to insert multiple entries instead of doing them
one at a time?  Perhaps RemoveElementsAt(index,count) and
InsertElementsAt(index, ????)?

Or perhaps adding a call to the new nsVoidArray::ExpandTo method would allow us
to do all the growing at once; the overhead for adding the elements would only
be in shifting elements after the insertion point.  Currently the overhead
includes the expense of (possibly several) reallocations and copies.  All we
need is a count of the (likely) number of nodes we'll add.  Certainly when
adding DocumentFragments that's possible.

I'm not certain how much we gain here since I haven't seen a jprof/quantify
output for this case, but it's a pretty straightforward and general optimization.
I've added (in the 90545 patch) support for Inserting and removing multiple
elements at once.  Also, nsSupportsArray now supports SizeTo().  After these
patches are merged, we may want to try using these new calls.
Moving to mozilla0.9.5
Target Milestone: mozilla0.9.4 → mozilla0.9.5
Blocks: 28783
What is the status of this work?  Though it was decided not to take the sum
total of the mail-reply perf branch work, some of the pieces will help out with
editor performance in general,  This patch is one.  Can we have this in 095?
Target Milestone: mozilla0.9.5 → mozilla0.9.6
Blocks: 63759
To repeat:
------- Additional Comments From jfrancis@netscape.com 2001-09-23 23:54 -------

What is the status of this work?  Though it was decided not to take the sum
total of the mail-reply perf branch work, some of the pieces will help out with
editor performance in general,  This patch is one.  Can we have this in 095?

-------
Perhaps for 0.9.6?
Attached patch This should be "The One" (deleted) — Splinter Review
Whiteboard: [HAVE FIX]
Being pretty up on array references, that all looks pretty good to me.  I agree
that the IndexOf case is not a performance issue, since it shouldn't be hit
often/ever.  r=rjesup@wgate.com
Comment on attachment 55867 [details] [diff] [review]
This should be "The One"

This looks like a neat performace win, especially for the case when a fragment is appended
r=sicking
Ahem, hmm, I forgot that I already had a review for this patch, sorry to request
one more Sicking. Well, the more the merryer, right? :-)
Fix checked in.
Status: ASSIGNED → RESOLVED
Closed: 23 years ago
Resolution: --- → FIXED
Component: DOM: Core → DOM: Core & HTML
QA Contact: stummala → general
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: