Summary: | REGRESSION(r74593): removing nodes is 200+ times slower when selection is inside a shadow DOM | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Product: | WebKit | Reporter: | Igor Minar <iiminar> | ||||||||||||||||
Component: | DOM | Assignee: | Ryosuke Niwa <rniwa> | ||||||||||||||||
Status: | RESOLVED FIXED | ||||||||||||||||||
Severity: | Major | CC: | abarth, ap, dglazkov, eae, eric, hyatt, mitz, rniwa, rolandsteiner, simon.fraser, webkit-ews, webkit.review.bot | ||||||||||||||||
Priority: | P1 | Keywords: | HasReduction | ||||||||||||||||
Version: | 528+ (Nightly build) | ||||||||||||||||||
Hardware: | Mac (Intel) | ||||||||||||||||||
OS: | OS X 10.5 | ||||||||||||||||||
Attachments: |
|
Description
Igor Minar
2011-03-24 15:42:34 PDT
Thank you for the report! Do you know if there are any public sites affected by this? At google we have a for now internal-only app that is affected. The testcase I attached is minuscule reduction of the affected part of our code base. The functionality that is affected is a client side search. User types something into a input box and we update the DOM by removing all table rows that represent the records that were not matched by the user query. I would say that removing table rows or list elements that were styled with nth-child(odd) (or nth-child(even)) because of user input is quite common scenario and affects more than us. Created attachment 87238 [details]
timeline without focus
Chrome Timeline graph showing how quick removal of 289 table row nodes (styled with nth-child(even)) is when our input field doesn't have the focus.
Created attachment 87239 [details]
timeline with focus
Chrome Timeline graph showing how slow removal of 289 table row nodes (styled with nth-child(even)) is when our input field does have the focus.
We are still struggling with this one. I attached screenshots showing that removing nodes styled with nth-child pseudo selector while an input field on the page has focus, results in "Recalculate Style" operation after removal of each of our 289 nodes. This doesn't happen when I execute the very same code path, without previously calling focus() on the input field. I also noticed that while my reduction exhibits the issue only when nodes are removed top-to-bottom, in our production app, the order of removal doesn't matter. The removal is slow in both directions. That makes me think that there is one more element in this puzzle that I haven't discovered yet. Any hints would be very welcome. Looks like the regression was caused by r74593. In SelectionController::respondToNodeModification if (!ec && (compareResult == Range::NODE_BEFORE_AND_AFTER || compareResult == Range::NODE_INSIDE)) { is true when the input field has focus and thus a reflow is triggered for each call to removeChild in the test. Ryosuke, would you mind taking a look at this? I don't quite understand what you fixed in r74593 and how this is supposed to work. The bug is coming from Range::compareNode. It returns NODE_INSIDE when a range is inside a shadow DOM and a node is outside of the shadow DOM. We need to fix this. I think we need to throw WRONG_DOCUMENT_ERR in compareBoundaryPoints when two nodes have no common ancestors. Created attachment 89901 [details]
work in progress
Will finish this patch next week.
(In reply to comment #9) > I think we need to throw WRONG_DOCUMENT_ERR in compareBoundaryPoints when two nodes have no common ancestors. Yes, ShadowRoot being comparable to DocumentFragment makes throwing WRONG_DOCUMENT_ERR probably a good choice w.r.t. the DOMRange spec. Great, let me know if there is anything I can do to help! Created attachment 89953 [details]
reduction
Here's reduced test case
nth-child is nothing to do with this regression. It's just that nth-child slows rendering down and makes it more obvious. Slow re-layout of nth-child should be addressed by another bug if necessary. Created attachment 90134 [details]
fixes the bug
Attachment 90134 [details] did not build on qt: Build output: http://queues.webkit.org/results/8471166 Attachment 90134 [details] did not build on chromium: Build output: http://queues.webkit.org/results/8474124 Created attachment 90141 [details]
fixed qt/chromium-linux build
Comment on attachment 90141 [details] fixed qt/chromium-linux build View in context: https://bugs.webkit.org/attachment.cgi?id=90141&action=review > Source/WebCore/ChangeLog:18 > + No new tests because this is a performance improvement and the fix in Range cannot be tested since shadow DOM > + isn't exposed to JavaScript. I am not sure I follow -- the original reduction showed there was a performance issue. Perhaps a perf test would be at least useful here? (In reply to comment #19) > (From update of attachment 90141 [details]) > View in context: https://bugs.webkit.org/attachment.cgi?id=90141&action=review > > > Source/WebCore/ChangeLog:18 > > + No new tests because this is a performance improvement and the fix in Range cannot be tested since shadow DOM > > + isn't exposed to JavaScript. > > I am not sure I follow -- the original reduction showed there was a performance issue. Perhaps a perf test would be at least useful here? No, perf test only checks asymptotic behavior and this performance regression doesn't change the asymptotic behavior so I don't think it works. I can check in a reduced test case with a really large number of nodes but that'll be very unreliable and I'm afraid that it's going to fail too. I also considered verifying the fix I added to Range's method but that's not possible now because shadow DOM isn't accessible from JavaScript. (In reply to comment #20) > (In reply to comment #19) > > (From update of attachment 90141 [details] [details]) > > View in context: https://bugs.webkit.org/attachment.cgi?id=90141&action=review > > > > > Source/WebCore/ChangeLog:18 > > > + No new tests because this is a performance improvement and the fix in Range cannot be tested since shadow DOM > > > + isn't exposed to JavaScript. > > > > I am not sure I follow -- the original reduction showed there was a performance issue. Perhaps a perf test would be at least useful here? > > No, perf test only checks asymptotic behavior and this performance regression doesn't change the asymptotic behavior so I don't think it works. I can check in a reduced test case with a really large number of nodes but that'll be very unreliable and I'm afraid that it's going to fail too. I also considered verifying the fix I added to Range's method but that's not possible now because shadow DOM isn't accessible from JavaScript. Ah I see. Well, hopefully when Kent-san converts text inputs (https://bugs.webkit.org/show_bug.cgi?id=54179) to the new shadow DOM, we'll be able to write a test, since we do expose layoutTestController.shadowRoot(node) for it. Thanks guys for looking into this issue. Does the original test case work fast in all cases? I'll be happy to test the fix when it lands in nightly builds. Comment on attachment 90141 [details] fixed qt/chromium-linux build View in context: https://bugs.webkit.org/attachment.cgi?id=90141&action=review >>>> Source/WebCore/ChangeLog:18 >>>> + isn't exposed to JavaScript. >>> >>> I am not sure I follow -- the original reduction showed there was a performance issue. Perhaps a perf test would be at least useful here? >> >> No, perf test only checks asymptotic behavior and this performance regression doesn't change the asymptotic behavior so I don't think it works. I can check in a reduced test case with a really large number of nodes but that'll be very unreliable and I'm afraid that it's going to fail too. I also considered verifying the fix I added to Range's method but that's not possible now because shadow DOM isn't accessible from JavaScript. > > Ah I see. Well, hopefully when Kent-san converts text inputs (https://bugs.webkit.org/show_bug.cgi?id=54179) to the new shadow DOM, we'll be able to write a test, since we do expose layoutTestController.shadowRoot(node) for it. Yeah, it's unfortunate that the bug 54179 hasn't been fixed yet. Committed r84265: <http://trac.webkit.org/changeset/84265> http://trac.webkit.org/changeset/84265 might have broken Windows 7 Release (Tests) Just a quick note that I tested build r84295 and the issue is gone. Thanks! |