Open Bug 1535134 Opened 5 years ago Updated 1 year ago

nsLayoutUtils::DisplayRootHasRetainedDisplayListBuilder is slow

Categories

(Core :: Web Painting, enhancement, P3)

enhancement

Tracking

()

Performance Impact low
Tracking Status
firefox67 --- affected

People

(Reporter: dholbert, Unassigned)

References

(Blocks 1 open bug, )

Details

(Keywords: perf:responsiveness)

Attachments

(1 file)

When rendering the single-page HTML spec, we spent 53.4ms inside the boolean function nsLayoutUtils::DisplayRootHasRetainedDisplayListBuilder. That seems high and like something we perhaps can optimize.

Here's a profile, filtered for this function: https://perfht.ml/2SZRxMV

This function is only 2 lines long (ignoring the debug-only MOZ_ASSERT statement):

bool nsLayoutUtils::DisplayRootHasRetainedDisplayListBuilder(nsIFrame* aFrame) {
  const nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame);
  MOZ_ASSERT(displayRoot);
  return displayRoot->HasProperty(RetainedDisplayListBuilder::Cached());
}

I don't know offhand which line is the more-expensive one, or if they're both expensive. But notably, the profiler does show that this function spends some of its time (5.6ms) in mozilla::ViewportFrame::GetViewInternal, which I think is somewhere inside of the call to GetDisplayRootFrame. (It seems that intervening stack levels have been inlined so I don't know the exact callpath.)

It's conceivable that HasProperty() might be slow, if the root frame has lots of frame properties set (because the property table is a linked list which must be traversed to answer the "HasProperty" question).

If we had a spare generic frame state bit, we could optimize that call away by using a frame state bit as a proxy for whether the property is set or not.

(Or I guess we could just a bool mFoo : 1; bitfield member-var on the frame. I'm giving that a shot to see if it helps here.)

I tried a patch to use a bool : 1 instead of the HasProperty() check, but it didn't help much.

Methodology: I tested a local build (--enable-optimize --enable-debug-symbols), with this patch applied, and I compared the the "optimized" bool-check (the version in this patch) vs. the same build after restoring the original HasProperty(...) check in nsLayoutUtils.cpp, and I got these measurements:

Using bool member-var:
30.6ms https://perfht.ml/2XWu5DS
29.8ms https://perfht.ml/2XULz3w
26.4ms https://perfht.ml/2T15j1z
28.6ms https://perfht.ml/2T4GbqG

Using HasProperty:
42.8ms https://perfht.ml/2XY5FJZ
30.4ms https://perfht.ml/2Y4LF8S
27.8ms https://perfht.ml/2XWujLl
31.4ms https://perfht.ml/2XSA1xP

Aside from the first 42.8ms measurement with HasProperty (which may've been a fluke/outlier), the measurements are all pretty equivalent, so this strawman patch doesn't seem to help much.

That leads me to believe that DisplayRootHasRetainedDisplayListBuilder's other line (nsLayoutUtils::GetDisplayRootFrame) is the slow thing here.

Assignee: nobody → dholbert

[er, didn't intend to take bug necessarily; i forgot to untick the 'assign-to-me' checkbox that activates when posting a patch]

Assignee: dholbert → nobody
Whiteboard: [qf] → [qf:p3:responsiveness]

Matt, are we close to having retained display lists everywhere? Would that allow us to eliminate the check entirely?

Flags: needinfo?(matt.woodrow)

I think the main problem here is that we mark all reflowed frames modified. I think that this is not necessary, and only marking reflow root modified should be enough. Then we could add a check here1, and skip all the frames that are in reflow.

(In reply to Miko Mynttinen [:miko] from comment #7)

I think the main problem here is that we mark all reflowed frames modified. I think that this is not necessary, and only marking reflow root modified should be enough. Then we could add a check here1, and skip all the frames that are in reflow.

This is true for the initial reflow when loading, but not for normal reflows. Usually when we reflow for a small change, most frames aren't modified, and we don't want to mark the whole frame tree under the reflow root as modified.

(In reply to Markus Stange [:mstange] from comment #6)

Matt, are we close to having retained display lists everywhere? Would that allow us to eliminate the check entirely?

Timothy is working on it!

I'm also not sure why we need to check the root frame for the presence of a retained DL builder, when we could just check the pref value. Seems like there could be a lower overhead way to determine this.

Flags: needinfo?(matt.woodrow)

(In reply to Matt Woodrow (:mattwoodrow) from comment #8)

I'm also not sure why we need to check the root frame for the presence of a retained DL builder, when we could just check the pref value. Seems like there could be a lower overhead way to determine this.

I looked into this a bit more. We have a couple of cases where just checking the pref is not enough:

  1. Hit testing
  2. nsLayoutUtils::PaintFrame() called for non-root frame
  3. Most calls to nsLayoutUtils::PaintFrame() through PresShell::RenderDocument()
Blocks: 1204549
Priority: -- → P3
Performance Impact: --- → P3
Whiteboard: [qf:p3:responsiveness]
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: