Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

layout: Dramatically improve performance of layout queries and `requestAnimationFrame()`. #14442

Closed
wants to merge 6 commits into from

Conversation

@pcwalton
Copy link
Contributor

pcwalton commented Dec 2, 2016

See individual commits for details. This improves nytimes.com CPU usage and gets it within the ballpark of Firefox.

r? @emilio


This change is Reviewable

pcwalton added 6 commits Dec 2, 2016
`ConstructionResult::get()`.

It only actually swaps out in nonincremental mode (which isn't suitable
for real world use), so the name is confusing.
non-animation purposes and back off to a timer if so.

After this patch, when the page calls `requestAnimationFrame()` too many
times in the row without actually mutating the DOM, further calls to
`rAF` will actually perform the moral equivalent of `setTimeout(16)`.
This saves a lot of CPU time compared to actually waiting for the
vertical blanking interval, because waiting for that requires us to draw
the page.

Reduces CPU usage drastically on nytimes.com, which has a perpetual
`requestAnimationFrame()` loop that checks whether ads are in view.
queries.

Instead of searching the entire tree to find the applicable fragment, we
use the flow construction result of the nearest DOM node to find the
flow we're looking for directly. We then recursively do this with
ancestor DOM nodes in order to find the entire flow tree path,
performing breadth first search to deal with anonymous flows in between.

To fully eliminate the search, we will probably want some combination of
(a) parent pointers in the flow tree and (b) rewritten script-to-layout
queries that don't depend on visiting all ancestor flows of the query
node. But this is a quick and dirty solution that dramatically improves
the performance of layout queries.

This is a large responsiveness increase on nytimes.com.
changed and no flows were reconstructed.

This saves a tree traversal. It also has the side effect of making
incremental reflow bugs of the form "a dirty bit is never cleared" less
likely to ruin the performance of layout queries.
@highfive
Copy link

highfive commented Dec 2, 2016

Heads up! This PR modifies the following files:

  • @KiChjang: components/script/dom/document.rs, components/script/timers.rs, components/script_layout_interface/wrapper_traits.rs
  • @fitzgen: components/script/dom/document.rs, components/script/timers.rs, components/script_layout_interface/wrapper_traits.rs
  • @emilio: components/layout/construct.rs, components/layout/sequential.rs, components/layout/query.rs, components/layout/flow.rs
@highfive
Copy link

highfive commented Dec 2, 2016

warning Warning warning

  • These commits modify layout and script code, but no tests are modified. Please consider adding a test!
@fitzgen
Copy link
Member

fitzgen commented Dec 2, 2016

Regarding ba274c9: Is an RAF that performs canvas draws but no dom mutations considered "spurious"? Is that desirable?

@pcwalton
Copy link
Contributor Author

pcwalton commented Dec 2, 2016

@fitzgen No, it shouldn't be considered spurious. Does it dirty the canvas? If not, I'm not sure what the best way to detect this is.

@pcwalton
Copy link
Contributor Author

pcwalton commented Dec 2, 2016

The canvas element is dirtied when you draw to it, so there should be no problems here.

Copy link
Member

emilio left a comment

r=me on the layout changes, they're great :)

I'm not sure we can fake animation frame callbacks using a timer per spec. IIRC we should run them at a very specific timing per the processing model, and we're already awful at it unfortunately.

I'd love to see this, and it may be the case that results are black-box identical in this case (though I think not because at least the last fake callback that modifies something and makes us go back to real animation frames runs out of sync).

I'd probably defer to @jdm or @Ms2ger to approve that bit, or request more proof of that being the case.

///
/// A rAF request is considered spurious if nothing was actually reflowed.
spurious_animation_frames: Cell<u8>,

This comment has been minimized.

@emilio

emilio Dec 3, 2016

Member

nit: Extra newline.

// Find the path from the root to the node.
//
// FIXME(pcwalton): This would be unnecessary if we had parent pointers in the flow tree. I
// think they're going to be inevitable.

This comment has been minimized.

@emilio

emilio Dec 3, 2016

Member

Yeah, this is relatively expensive, though better that a full traversal I guess...

}

// Find the next child in the path.
let target_child = *path.last().expect("Path ended prematurely!");

This comment has been minimized.

@emilio

emilio Dec 3, 2016

Member

I think here it's acceptable to just unwrap given the check above.

@emilio
Copy link
Member

emilio commented Dec 3, 2016

@bors-servo
Copy link
Contributor

bors-servo commented Dec 3, 2016

Trying commit 89895e3 with merge 6d97221...

bors-servo added a commit that referenced this pull request Dec 3, 2016
layout: Dramatically improve performance of layout queries and `requestAnimationFrame()`.

See individual commits for details. This improves nytimes.com CPU usage and gets it within the ballpark of Firefox.

r? @emilio

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/14442)
<!-- Reviewable:end -->
@bors-servo
Copy link
Contributor

bors-servo commented Dec 3, 2016

💔 Test failed - mac-rel-wpt2

@pcwalton
Copy link
Contributor Author

pcwalton commented Dec 3, 2016

@emilio I don't see anything in that list that mandates when animation frame callbacks run, only that they run at specific times relative to other events. We already don't try to do that, I don't think. Indeed it'd be impossible for the spec to mandate a specific time other than describing what a VBLANK is (and if it did, then every other browser on non-Windows platforms would fail it because they don't sync to VBLANK properly).

(On a side note, it's irritating that the spec technically forbids off main thread CSS animations, but I'm going to just break the spec because that's dumb.)

@emilio
Copy link
Member

emilio commented Dec 3, 2016

@bors-servo
Copy link
Contributor

bors-servo commented Dec 7, 2016

The latest upstream changes (presumably #14473) made this pull request unmergeable. Please resolve the merge conflicts.

@jdm jdm assigned jdm and unassigned emilio Jan 27, 2017
Copy link
Member

jdm left a comment

This looks fine to me. Sorry that it was overlooked for so long!

}

impl FakeRequestAnimationFrameCallback {
#[allow(unrooted_must_root)]

This comment has been minimized.

@jdm

jdm Feb 2, 2017

Member

This shouldn't be necessary.

@jdm jdm removed the S-awaiting-review label Feb 2, 2017
@nox
Copy link
Member

nox commented Mar 3, 2017

@jdm Want me to carry this? @pcwalton is busy with his Pathfinder adventures AFAIK.

@nox nox assigned nox and unassigned jdm Mar 3, 2017
@jdm
Copy link
Member

jdm commented Mar 3, 2017

That would be great!

bors-servo added a commit that referenced this pull request Mar 3, 2017
Improve performance of layout queries and requestAnimationFrame

Supersedes #14442.
bors-servo added a commit that referenced this pull request Mar 4, 2017
Improve performance of layout queries and requestAnimationFrame

Supersedes #14442.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15816)
<!-- Reviewable:end -->
bors-servo added a commit that referenced this pull request Mar 5, 2017
Improve performance of layout queries and requestAnimationFrame

Part of #14442.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15816)
<!-- Reviewable:end -->
@nox
Copy link
Member

nox commented Mar 5, 2017

I carried the first 2 commits in #15816. 👶👣

@nox
Copy link
Member

nox commented Mar 12, 2017

@pcwalton Are you sure the commit "query: Stop searching the entire flow tree to resolve script-to-layout" works as intended?

@nox
Copy link
Member

nox commented Mar 15, 2017

Lack of response, I'm closing this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

7 participants
You can’t perform that action at this time.