Closed Bug 349113 Opened 18 years ago Closed 18 years ago

[FIX]Speed up nsSpaceManager::ClearFloats

Categories

(Core :: Layout: Floats, defect, P1)

x86
Linux
defect

Tracking

()

RESOLVED FIXED
mozilla1.9alpha1

People

(Reporter: bzbarsky, Assigned: bzbarsky)

References

(Blocks 1 open bug, )

Details

(Keywords: perf)

Attachments

(1 file, 5 obsolete files)

On the testcases for bug 64858, nsSpaceManager::ClearFloats is about 10% of the total pageload time.  I'll post a patch that significantly speeds it up on this testcase for me by avoiding almost all calls to ShouldClearFrame().  I _think_ this is the right patch in general, but I'm not sure.

With that patch, ClearFloats is only about 2-3% of total time; still a fair amount.  Would it be possible to keep track of the two values we really need here (the maximal YMost() of the left floats and the same for the right ones) as we go?  That would make calling ClearFloats O(1) in the number of floats, instead of the current O(N)....
Attached patch Simple patch (obsolete) — Splinter Review
Again, it would be nice if we could avoid having to do a loop here at all.  roc, do you think we can do that?  We'd just need to update a value every time we FlowAndPlaceFloat(), right?
Attached patch More extensive patch (obsolete) — Splinter Review
With this patch, on that testcase, I have ClearFloats at about than 0.05%.  The time spent in nsSpaceManager::CreateFrameInfo went up by about 0.03% of total profile time.  DestroyFrameInfo doesn't appear in the profile at all.  Overall times are about 10% faster than without this patch, as expected.
Assignee: nobody → bzbarsky
Attachment #234374 - Attachment is obsolete: true
Status: NEW → ASSIGNED
Attachment #234377 - Flags: superreview?(roc)
Attachment #234377 - Flags: review?(roc)
I should note that the GetFrameInfoFor call that we expect to return nothing is generally _expensive_.  Could we remove it?  Or make it debug-only?  Or something?
Priority: -- → P1
Summary: Speed up nsSpaceManager::ClearFloats → [FIX]Speed up nsSpaceManager::ClearFloats
Target Milestone: --- → mozilla1.9alpha
I checked, and the only reasonable effect of the GetFrameInfoFor check in nsSpaceManager::AddRectRegion is an assert on the caller side (other than the early return itself, of course).  I think it makes more sense to just make the check debug-only to start with.
Attachment #234377 - Attachment is obsolete: true
Attachment #234471 - Flags: superreview?(roc)
Attachment #234471 - Flags: review?(roc)
Attachment #234377 - Flags: superreview?(roc)
Attachment #234377 - Flags: review?(roc)
+  // Optimize for the case when the frame being removed is not likely to be
+  // near the bottom.  Is this reasonable?

Generally if frames are removed we remove the bottom frames :-) so this optimization doesn't really help.

I think PushState and PopState should save and restore your cached values.

+    // Optimize for the case when the frame being added is likely to be near
+    // the bottom.  Is this reasonable?

Yes.

+    mHaveCachedLeftYMost(PR_FALSE),
+    mHaveCachedRightYMost(PR_FALSE),
+    mMaximalLeftYMost(0),
+    mMaximalRightYMost(0)

Why not set the have-cache values to PR_TRUE here?
Attached patch Updated to comments (obsolete) — Splinter Review
Attachment #234471 - Attachment is obsolete: true
Attachment #235659 - Flags: superreview?(roc)
Attachment #235659 - Flags: review?(roc)
Attachment #234471 - Flags: superreview?(roc)
Attachment #234471 - Flags: review?(roc)
+  // Optimize for the case when the frame being removed is likely to be near
+  // the bottom, but do nothing if we have neither cached value -- that case is
+  // likely to be hit from PopState().
+  if (mHaveCachedLeftYMost || mHaveCachedRightYMost) {
+    nscoord ymost = aFrameInfo->mRect.YMost();
+    PRUint8 floatType = aFrameInfo->mFrame->GetStyleDisplay()->mFloats;
+    if (mHaveCachedLeftYMost && ymost >= mMaximalLeftYMost &&
+        floatType == NS_STYLE_FLOAT_LEFT) {
+      mHaveCachedLeftYMost = PR_FALSE;
+    }
+    else if (mHaveCachedRightYMost && ymost >= mMaximalRightYMost &&
+             floatType == NS_STYLE_FLOAT_RIGHT) {
+      mHaveCachedRightYMost = PR_FALSE;
+    }
+  }

Like I said, this is not very useful. I would just flush the cache on the side that the float belongs to.

+        NS_ASSERTION(!mHaveCachedLeftYMost, "Shouldn't happen");

Why can't this happen?

I think this loop would be slightly better if you test the float style before checking ymost. Also, I would just accumulate the left and right ymost values in local variables and only change the spacemanager state at the end of the loop.
> I would just flush the cache on the side that the float belongs to.

As in, skip the ymost check?  I'd like to keep the checks mHaveCachedLeftYMost and mHaveCachedRightYMost because we're generally removing several floats, and GetStyleDisplay() is a little expensive; I'd like to avoid doing it several thousand times (in edge cases) when it's not needed at all.

> Why can't this happen?

Hmm..  I probably need to push the assert down into the side check.

> If you test the float style before checking ymost

Hmm.  So if my left ymost needs updating and I have a whole slew of right-floats, most of them above a single left float, I'd like to avoid doing the expensive GetStyleDisplay() on them...  Or will said right floats come before the left float anyway in mFrameInfoMap?  I'm not sure what invariants I can assume that way, if any.

> I would just accumulate the left and right ymost values in local variables

Sure.  I can do that.
(In reply to comment #8)
> > I would just flush the cache on the side that the float belongs to.
> 
> As in, skip the ymost check?  I'd like to keep the checks
> mHaveCachedLeftYMost and mHaveCachedRightYMost because we're generally
> removing several floats, and
> GetStyleDisplay() is a little expensive; I'd like to avoid doing it several
> thousand times (in edge cases) when it's not needed at all.

OK, just

  if (mHaveCachedLeftYMost || mHaveCachedRightYMost) {
    PRUint8 floatType = aFrameInfo->mFrame->GetStyleDisplay()->mFloats;
    if (floatType == NS_STYLE_FLOAT_LEFT) {
      mHaveCachedLeftYMost = PR_FALSE;
    }
    else {
      mHaveCachedRightYMost = PR_FALSE;
    }
  }

> > If you test the float style before checking ymost
> 
> Hmm.  So if my left ymost needs updating and I have a whole slew of
> right-floats, most of them above a single left float, I'd like to avoid doing
> the expensive GetStyleDisplay() on them...  Or will said right floats come
> before the left float anyway in mFrameInfoMap?  I'm not sure what invariants I
> can assume that way, if any.

Ok, I guess what you have is best then. Bottom floats will tend to be first in the list here so you will avoid almost all the calls to GetStyleDisplay().
Attached patch Updated to comments again (obsolete) — Splinter Review
Attachment #235659 - Attachment is obsolete: true
Attachment #235852 - Flags: superreview?(roc)
Attachment #235852 - Flags: review?(roc)
Attachment #235659 - Flags: superreview?(roc)
Attachment #235659 - Flags: review?(roc)
Comment on attachment 235852 [details] [diff] [review]
Updated to comments again

great!
Attachment #235852 - Flags: superreview?(roc)
Attachment #235852 - Flags: superreview+
Attachment #235852 - Flags: review?(roc)
Attachment #235852 - Flags: review+
Attached patch Merged to tipSplinter Review
Attachment #235852 - Attachment is obsolete: true
Fixed.
Status: ASSIGNED → RESOLVED
Closed: 18 years ago
Resolution: --- → FIXED
Depends on: 351202
Depends on: 384762
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: