Bug 111627

Summary: recalcStyle() with a Detach styleDiff calculates style twice
Product: WebKit Reporter: Eric Seidel (no email) <eric>
Component: Layout and RenderingAssignee: Elliott Sprehn <esprehn>
Status: RESOLVED INVALID    
Severity: Normal CC: allan.jensen, buildbot, cmarcelo, darin, dglazkov, esprehn+autocc, esprehn, hyatt, koivisto, macpherson, menard, ojan.autocc, rniwa, simon.fraser, webkit.review.bot
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Bug Depends on: 113123, 115042    
Bug Blocks:    
Attachments:
Description Flags
Patch webkit.review.bot: commit-queue-

Eric Seidel (no email)
Reported 2013-03-06 14:41:21 PST
recalcStyle() with a Detach styleDiff calculates style twice As noted in: https://bugs.webkit.org/show_bug.cgi?id=111494#c16 This is extra-bad, because I believe using lazyAttach will always go down this code path. Fixing this could be as much as an 8% win on html5-full-render, if it cuts our style-resolves in half. :)
Attachments
Patch (4.41 KB, patch)
2013-03-06 16:51 PST, Elliott Sprehn
webkit.review.bot: commit-queue-
Elliott Sprehn
Comment 1 2013-03-06 16:51:37 PST
Eric Seidel (no email)
Comment 2 2013-03-06 16:53:52 PST
I'm not sure this is the solution we want to go with long-term. :) But it would appear to solve the bug. Do you have any perf data to show this is a win?
Ryosuke Niwa
Comment 3 2013-03-06 16:58:06 PST
There got to be a better way of doing this?
Elliott Sprehn
Comment 4 2013-03-06 16:59:26 PST
(In reply to comment #2) > I'm not sure this is the solution we want to go with long-term. :) But it would appear to solve the bug. > > Do you have any perf data to show this is a win? I'm having issues getting the perf tests to not hang after running them, but I did a few runs and it didn't seem like it was a win at all on html5-full-render.html
Elliott Sprehn
Comment 5 2013-03-06 17:01:38 PST
(In reply to comment #3) > There got to be a better way of doing this? It requires considerable amounts of plumbing since we'd need to pass the style from recalcStyle => reattach => attach => createRendererIfNeeded => NodeRenderingContext::createRendererForElementIfNeeded() which finally calls styleForRenderer(). I guess we could use the same class and use the style in createRendererForElementIfNeeded instead though which means StyleResolver doesn't need this knowledge, and it would work for PseudoElements too.
Antti Koivisto
Comment 6 2013-03-06 17:02:12 PST
Comment on attachment 191867 [details] Patch That's just too ugly. I have a patch somewhere that fixes this properly, by passing the style to attach().
Elliott Sprehn
Comment 7 2013-03-06 17:10:17 PST
Comment on attachment 191867 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=191867&action=review > Source/WebCore/css/StyleResolver.cpp:1388 > + return style; If we did this approach, this code should be inside NodeRenderingContext::createRendererForElementIfNeeded
Elliott Sprehn
Comment 8 2013-03-06 17:36:08 PST
Ran perf tests for html5-full-render: With this caching: 3202.66 ± 0.23% 3205.94 ± 0.17% Without this caching: 3198.89 ± 0.24% 3202.49 ± 0.12% So, surprisingly, it doesn't seem to really matter. I guess there's caching stuff down inside StyleResolver already?
WebKit Review Bot
Comment 9 2013-03-06 17:49:36 PST
Comment on attachment 191867 [details] Patch Attachment 191867 [details] did not pass chromium-ews (chromium-xvfb): Output: http://webkit-commit-queue.appspot.com/results/17062114 New failing tests: fast/css/pseudo-empty-dynamic-empty.html fast/events/drag-display-none-element.html fast/selectors/empty-element-made-non-empty.html
Build Bot
Comment 10 2013-03-06 17:56:05 PST
Comment on attachment 191867 [details] Patch Attachment 191867 [details] did not pass mac-wk2-ews (mac-wk2): Output: http://webkit-commit-queue.appspot.com/results/17062117 New failing tests: fast/css/pseudo-empty-dynamic-empty.html http/tests/misc/acid3.html fast/selectors/empty-element-made-non-empty.html
Allan Sandfeld Jensen
Comment 11 2013-03-07 05:34:57 PST
(In reply to comment #8) > Ran perf tests for html5-full-render: > > With this caching: > 3202.66 ± 0.23% > 3205.94 ± 0.17% > > Without this caching: > 3198.89 ± 0.24% > 3202.49 ± 0.12% > > So, surprisingly, it doesn't seem to really matter. I guess there's caching stuff down inside StyleResolver already? It only caches in the sense that it will reuse the calculated style of a sibling if the elements are similar enough. To get a performance improvement you probably need to trigger a style that is unique.
Antti Koivisto
Comment 12 2013-03-07 11:14:23 PST
> So, surprisingly, it doesn't seem to really matter. I guess there's caching stuff down inside StyleResolver already? StyleResolver has multiple levels of caches. Also the case just doesn't generally get hit that much. When reattach() gets called the whole subtree under the element will get attached outside recalcStyle without hitting the double calculation case. I have yet to see a real case where this is practical problem. It would still be nice to fix it as it is silly.
Eric Seidel (no email)
Comment 13 2013-03-07 13:01:06 PST
(In reply to comment #12) > > So, surprisingly, it doesn't seem to really matter. I guess there's caching stuff down inside StyleResolver already? > > Also the case just doesn't generally get hit that much. When reattach() gets called the whole subtree under the element will get attached outside recalcStyle without hitting the double calculation case. Ah! this is the key bit I was missing. My understanding is lazyAttach() puts us into this state all the time. But it doesn't end up showing up because we only double-style-calc for the root most element of a subtree.
Build Bot
Comment 14 2013-03-07 19:34:00 PST
Comment on attachment 191867 [details] Patch Attachment 191867 [details] did not pass mac-ews (mac): Output: http://webkit-commit-queue.appspot.com/results/17081252 New failing tests: fast/css/pseudo-empty-dynamic-empty.html fast/events/drag-display-none-element.html http/tests/misc/acid3.html fast/selectors/empty-element-made-non-empty.html
Elliott Sprehn
Comment 15 2013-03-21 23:38:41 PDT
(In reply to comment #14) > (From update of attachment 191867 [details]) > Attachment 191867 [details] did not pass mac-ews (mac): > Output: http://webkit-commit-queue.appspot.com/results/17081252 > > New failing tests: > fast/css/pseudo-empty-dynamic-empty.html > fast/events/drag-display-none-element.html > http/tests/misc/acid3.html > fast/selectors/empty-element-made-non-empty.html These failures have me pretty confused. Apparently when calling styleForRenderer() inside Element::recalcStyle we get a different style than we would when later calling it inside NodeRenderingContext. Specifically: style1 = styleForRenderer(); detach(); style2 = styleForRenderer(); These two styles don't have the same properties which breaks the idea of passing the style down through the reattach() call. @antti Do you know what's going on here?
Elliott Sprehn
Comment 16 2013-03-22 01:16:38 PDT
(In reply to comment #15) > (In reply to comment #14) > ... > > These failures have me pretty confused. Apparently when calling styleForRenderer() inside Element::recalcStyle we get a different style than we would when later calling it inside NodeRenderingContext. > > Specifically: > > style1 = styleForRenderer(); > detach(); > style2 = styleForRenderer(); > > These two styles don't have the same properties which breaks the idea of passing the style down through the reattach() call. > > @antti Do you know what's going on here? Hmm, I'm wrong, there's something else weird going on here I'm missing. :/
Elliott Sprehn
Comment 17 2013-03-22 11:55:02 PDT
(In reply to comment #16) > ... > > Hmm, I'm wrong, there's something else weird going on here I'm missing. :/ Figured this out. We used to store the affectedBy bits in the RenderStyle, but now we store them in the ElementRareData and reset them in detach() which means calling styleForRenderer in recalcStyle sets a bunch of bits, but then detach() inside reattach() clears the affectedBy bits so we get a RenderStyle but none of the correct affectedBy bits. So we need to tell detach() not to clear the bits so we get the right values since we're not going to call styleForRenderer() again to set them.
Eric Seidel (no email)
Comment 18 2013-03-22 13:00:43 PDT
These are some of the side effects of style resolve which we'll need to make explicit. Dimitri and I were just musing about this yesterday.
Elliott Sprehn
Comment 19 2013-03-22 16:52:10 PDT
(In reply to comment #18) > These are some of the side effects of style resolve which we'll need to make explicit. Dimitri and I were just musing about this yesterday. Yeah. So not calling resetComputedStyle() inside detach() (from reattach) fixes some of the tests, but I'm still stuck for LayoutTests/fast/events/drag-display-none-element.html This test fails because the paragraph remains hidden. I tried not calling resetDynamicRestyleObservations but that doesn't seem to help. I need to figure out what other shared state change happened inside style recalc.
Elliott Sprehn
Comment 20 2013-03-22 17:58:25 PDT
This would be resolved by passing the context in Bug 113123
Elliott Sprehn
Comment 21 2013-03-22 18:01:23 PDT
(In reply to comment #19) > (In reply to comment #18) > > These are some of the side effects of style resolve which we'll need to make explicit. Dimitri and I were just musing about this yesterday. > > Yeah. So not calling resetComputedStyle() inside detach() (from reattach) fixes some of the tests, but I'm still stuck for LayoutTests/fast/events/drag-display-none-element.html > > This test fails because the paragraph remains hidden. I tried not calling resetDynamicRestyleObservations but that doesn't seem to help. > > I need to figure out what other shared state change happened inside style recalc. I figured this out btw, it's because SelectorChecker looks at the renderer for isDragging to set some state which is different after detach() since we lose the renderer. We should probably break that dependency.
Antti Koivisto
Comment 22 2013-04-23 09:24:20 PDT
http://trac.webkit.org/changeset/148970 fixed the most common instance of this problem.
Note You need to log in before you can comment on or make changes to this bug.