Closed
Bug 1050773
Opened 11 years ago
Closed 10 years ago
Reflows, restyle and paints are only recorded within refreshdriver::tick
Categories
(DevTools :: Performance Tools (Profiler/Timeline), defect)
DevTools
Performance Tools (Profiler/Timeline)
Tracking
(Not tracked)
RESOLVED
WORKSFORME
People
(Reporter: paul, Assigned: pbro)
References
Details
Attachments
(6 files, 4 obsolete files)
3.75 KB,
patch
|
Details | Diff | Splinter Review | |
753 bytes,
text/html
|
Details | |
154 bytes,
text/html
|
Details | |
27.10 KB,
patch
|
pbro
:
review+
pbro
:
checkin+
|
Details | Diff | Splinter Review |
4.69 KB,
patch
|
pbro
:
review+
|
Details | Diff | Splinter Review |
4.35 KB,
patch
|
Details | Diff | Splinter Review |
They also happen in other places. We need to cover these too.
Reporter | ||
Updated•11 years ago
|
Blocks: timeline-v1
Reporter | ||
Comment 1•11 years ago
|
||
Sync reflows are not recorded for example.
And if the docshell is an iframe inside a tab, nothing is recorded.
Reporter | ||
Comment 2•11 years ago
|
||
First run this:
> ./mach mochitest-chrome --keep-open docshell/test/chrome/test_timelineMarkers.html
You'll see failures. Open the console. You'll there never was any markers found.
Now only load: chrome://mochitests/content/chrome/docshell/test/chrome/test_timelineMarkers.html
Test is green.
The difference being the iframe.
Reporter | ||
Updated•11 years ago
|
Component: Developer Tools → Developer Tools: Timeline
Assignee | ||
Comment 4•11 years ago
|
||
So, sync reflows are already recorded since they aren't instrumented in refreshdriver::tick but instead in nsPresShell::DoReflow, which is called whether the reflow is interruptible or not.
The test html page attached should demonstrate that (open the timeline panel, and alternatively click on the sync and async buttons, you should see reflow markers in both cases).
Assignee | ||
Comment 5•11 years ago
|
||
However, only Paint markers are recorded in iframes, not Reflow nor Styles.
Open this HTML test page and click on the sync/async buttons with the timeline panel opened. You should only see paint events.
Since paint is always handled at top docshell level, we put in place since the start a mechanism that records by recursing through docshells. But that is not the case for reflows and restyles.
Assignee | ||
Updated•11 years ago
|
Assignee: nobody → pbrosset
Reporter | ||
Comment 6•11 years ago
|
||
What about this configuration (non-e10s): browser.xul docshell > tab docshell > iframe docshell
You connect the devtools to the iframe. What do we miss?
Assignee | ||
Comment 7•11 years ago
|
||
Olli, this patch helps with recording profile timeline markers at ancestor docshell level. The use case is the following:
Open a page that has an iframe, open the new devtools timeline panel, make sure there are reflows/styles in the child iframe ==> The timeline right now doesn't show those.
We do want child frame operations to be recorded too, so for this, what I did in this patch is: whenever a new marker is add, if the docshell it is added on isn't actually recording right now, we walk up its parents until we find one that is, and we store the marker there.
I also added a new test for this.
Let me know if this is a correct way to address the use case.
Attachment #8489346 -
Flags: review?(bugs)
Comment on attachment 8489346 [details] [diff] [review]
bug1050773-timeline-iframe v1.patch
> nsDocShell::AddProfileTimelineMarker(const char* aName,
> TracingMetadata aMetaData)
> {
> #ifdef MOZ_ENABLE_PROFILER_SPS
> if (!mProfileTimelineStartTime.IsNull()) {
> float delta = GetProfileTimelineDelta();
> ProfilerMarkerTracing* payload = new ProfilerMarkerTracing("Timeline",
> aMetaData);
> mProfileTimelineMarkers.AppendElement(
> new InternalProfileTimelineMarker(aName, payload, delta));
>+ } else {
>+ // If the docShell isn't recording, check if it has an ancestor that does
>+ // and add the marker on that docShell instead.
>+ nsRefPtr<nsDocShell> parentDocShell = GetProfileTimelineRecordingAncestor();
>+ if (parentDocShell) {
>+ parentDocShell->AddProfileTimelineMarker(aName, aMetaData);
>+ }
This makes no sense to me.
Say you have some ad in the page and it is doing plenty of reflows or so, but we're recording only the main page, the
ad related stuff gets recorded as being part of the main page.
Perhaps we should record all the child iframes, but data for their behavior shouldn't be part of the parent's.
Shouldn't devtools handle this case, and just start recording/profiling on child docshells if needed?
>+ } else {
>+ // If the docShell isn't recording, check if it has an ancestor that does
>+ // and add the marker on that docShell instead.
>+ nsRefPtr<nsDocShell> parentDocShell = GetProfileTimelineRecordingAncestor();
>+ if (parentDocShell) {
>+ parentDocShell->AddProfileTimelineMarker(aName, aCause, aMetaData);
>+ }
ditto
So, I don't understand why we want this behavior.
Attachment #8489346 -
Flags: review?(bugs) → review-
Reporter | ||
Comment 9•11 years ago
|
||
We can do what we do for the layout actor (record per docshell, up to the actor to go down the tree).
Patrick, I'm not sure exactly what your patch does, but the issue here is to not being to track docshells that are inside a content docshell. See comment 6.
Assignee | ||
Comment 10•11 years ago
|
||
(In reply to Paul Rouget [:paul] (slow to respond. Ping me on IRC) from comment #9)
> We can do what we do for the layout actor (record per docshell, up to the
> actor to go down the tree).
Yes that's another option for sure, this would be pretty easy too. And, as discussed with Olli over IRC, the advantage of doing this is that we would be able to know which frame do operations come from (so potentially, we would be able to show that in the UI somehow).
> Patrick, I'm not sure exactly what your patch does, but the issue here is to
> not being to track docshells that are inside a content docshell. See comment
> 6.
If devtools is inspecting the tab's docShell and the tab contains an iframe: in this situation my patch would save at tab docShell's level all reflow/style operations that happen at child iframe level. So that's what we need.
I'll provide a new patch soon with the new solution.
Reporter | ||
Comment 11•11 years ago
|
||
STR:
- load http://jsbin.com/comuquneluxo
- open the toolbox
- select the iframe "http://jsbin.com/banefohoyeko"
- start the timeline
- move mouse over the iframe
Only reflow and restyle are recorded, not the paint.
Assignee | ||
Comment 12•11 years ago
|
||
Thanks Paul for the STR.
So we have 2 problems to solve:
1 - the timeline devtools actor isn't recording markers from all frames.
2 - paint operations for sub-iframes are actually reported at parent frame level.
1 is relatively easy to solve by making the actor iterate over |this.tabActor.windows| and reacting to |window-ready| events.
2 is a bit more complex, I'll need to investigate.
Right now the mechanism is that we record paint START and STOP markers at top level (which is where we know paint is happening) and we store these in all child docshells. And we only turn them into a real Paint marker for the docShell(s) that actually had layers drawn (in FrameLayerBuilder::DrawThebesLayer) in between start and stop.
Thing is, I just realized that the docShell we get via |presContext->GetDocShell()| in this method is the one for the parent frame when paint occurs in the child frame.
Assignee | ||
Comment 13•11 years ago
|
||
I'm trying to find a place where we know when a docShell is being painted.
My use case is the following: http://bgrins.github.io/devtools-demos/inspector/iframe.html
This page contains a few iframes, but we're only interested in the first, the one that has a markup mutation every second.
Now, I'm logging the document.title (using something like |docShell->GetWindow()->GetDoc()->GetTitle()|) in the following methods:
- nsLayoutUtils::PaintFrame (docShell in this method being |aFrame->PresContext()->GetDocShell()|)
- FrameLayerBuilder::PaintItems (docShell being |aPresContext->GetDocShell()| here)
- FrameLayerBuilder::DrawThebesLayer (same)
And every second, when the child iframe content changes and gets painted, my logs tell me that it was the parent page that built the layer (or painted the frame).
Is there a place where I can safely get the child iframe's docShell whenever the mutation occurs?
Flags: needinfo?(matt.woodrow)
Flags: needinfo?(bgirard)
Comment 14•11 years ago
|
||
The painting that happens is pretty intertwined. We paint for the window at once. I don't think we can really get a breakdown of how much time was spent painting what without adding a lot more instrumentation.
Basically we will go through our layer tree and update them all at once. Assuming we don't have a layer that mixes content from more then one docshell together (feels like a bad assumption) then we would have to keep track of which docshell a layer belongs to and as we start painting we would have to track.
Even with all that there's still times where it's not clear which layer you're working on like when we're working on our display list.
Matt can you confirm?
Flags: needinfo?(bgirard)
Assignee | ||
Comment 15•11 years ago
|
||
So that's the patch for part 1, it makes the timeline actor pull markers from all current docshell in the tabactor.
I've added a new test for it and cleaned up some of the tests in the same directory at the same time.
Attachment #8489346 -
Attachment is obsolete: true
Attachment #8490690 -
Flags: review?(paul)
Reporter | ||
Updated•11 years ago
|
Attachment #8490690 -
Flags: review?(paul) → review+
Assignee | ||
Comment 16•11 years ago
|
||
Thanks for the review Paul.
I had some try failures because of the test cleanup, so here's a new patch that fixes those.
Pending try build: https://tbpl.mozilla.org/?tree=Try&rev=10783e523a48
Attachment #8490690 -
Attachment is obsolete: true
Attachment #8490810 -
Flags: review+
Assignee | ||
Comment 17•11 years ago
|
||
Rebased, and landed in fx-team: https://hg.mozilla.org/integration/fx-team/rev/a48989ed6aa6
Attachment #8490810 -
Attachment is obsolete: true
Attachment #8491344 -
Flags: review+
Assignee | ||
Updated•11 years ago
|
Keywords: leave-open
Assignee | ||
Comment 19•11 years ago
|
||
Discussed with Paul: at least for now, we can make sure the timeline actor always listens to all frames, so that we are sure to get paint markers. This means that even if the user switches to a sub frame using the iframe switcher drop-down menu, we should still listen to the parent frame.
Assignee | ||
Comment 20•11 years ago
|
||
There's another bug related to iframe that actually depends on bug 1070089 being fixed: Say you record timeline markers on a page that has an iframe, and you then, later, refresh the iframe.
In that case, attachment 8491344 [details] [diff] [review] (which already landed) will make sure the refreshed iframe is recorded too, but its record start time is going to restart from 0 while the parent page has been recording for some time already, so markers from the child frame aren't going to be visible.
Depends on: 1070089
Assignee | ||
Comment 21•11 years ago
|
||
This makes sure we always record markers from the top level window, so that we don't miss paint markers.
It would be more ideal to be able to track paint markers per window, but since we can't, it seems fine enough in v1 to at least do that.
Attachment #8493130 -
Flags: review?(paul)
Assignee | ||
Updated•11 years ago
|
Attachment #8491344 -
Flags: checkin+
Reporter | ||
Updated•11 years ago
|
Attachment #8493130 -
Flags: review?(paul) → review+
Assignee | ||
Comment 22•11 years ago
|
||
Minor last minute change as I had some test failures on try.
There isn't always a tabActor.originalWindow available, so when this is the case, just default to using tabActor.window.
Attachment #8493130 -
Attachment is obsolete: true
Attachment #8493740 -
Flags: review+
Assignee | ||
Comment 23•11 years ago
|
||
Pending try build: https://tbpl.mozilla.org/?tree=Try&rev=171eec8557d4
Assignee | ||
Comment 24•11 years ago
|
||
Try is green, so pushed this part 2 patch to fx-team: https://hg.mozilla.org/integration/fx-team/rev/11ba7e5e8834
Leaving the bug open as Matt may have feedback about how to track paint markers at the right docshell level.
Also, Paul was investigating earlier how to force refresh drivers in nested iframes, which could help with this too.
Reporter | ||
Comment 25•11 years ago
|
||
(In reply to Patrick Brosset [:pbrosset] [:patrick] from comment #24)
> Also, Paul was investigating earlier how to force refresh drivers in nested
> iframes, which could help with this too.
This is what I tried:
- added a new flag to the docshell "forceOwnRefreshDriver"
- layout/base/nsPresContext.cpp: force ownRefreshDriver if docshell.forceOwnRefreshDriver
- to re-init the contentViewer:
- mark iframe's docshell non-sticky
- hide contentViewer
- showContenViewer
> let d = frame.QueryInterface(Ci.nsIInterfaceRequestor)
> .getInterface(Ci.nsIWebNavigation)
> .QueryInterface(Ci.nsIDocShell);
>
> d.forceOwnRefreshDriver = true;
> d.contentViewer.sticky = false;
> d.contentViewer.hide();
> d.contentViewer.show();
The logs tell me that the iframe is indeed using its own refreshDriver.
But apparently, we still miss the paints :(
Comment 26•11 years ago
|
||
What BenWa said was correct.
What do you mean by having an iframe use its own RefreshDriver? Every PresShell (document/iframe etc) always has a refresh driver for driving style/layout flushes, requestAnimationFrame callbacks etc. However, only the refresh driver for the root document for a given window ever drives painting.
Content within an iframe isn't separated from content from the parent document from a displaylist/layers perspective, so its going to be very hard to measure these separately. One option would be to change layerization heuristics when the timeline is enabled to force content from an iframe into a separate layer sub-tree (we do this for the root content document to separate it from the chrome). Another options would be to split up the paint measurement and measure each individual item we paint (background, border, image etc), and then attribute that time to the appropriate document.
Flags: needinfo?(matt.woodrow)
Comment 27•11 years ago
|
||
Reporter | ||
Comment 28•11 years ago
|
||
(In reply to Matt Woodrow (:mattwoodrow) from comment #26)
> What BenWa said was correct.
>
> What do you mean by having an iframe use its own RefreshDriver? Every
> PresShell (document/iframe etc) always has a refresh driver for driving
> style/layout flushes, requestAnimationFrame callbacks etc. However, only the
> refresh driver for the root document for a given window ever drives painting.
There's obviously something wrong with my understanding of refresh drivers :)
For example, look at nsPresContext.cpp, I see that we use the refreshDriver
from the parent docshell:
http://mxr.mozilla.org/mozilla-central/source/layout/base/nsPresContext.cpp#1006
> Content within an iframe isn't separated from content from the parent
> document from a displaylist/layers perspective, so its going to be very hard
> to measure these separately.
I thought that what "forceOwnRefreshDriver" was doing:
http://mxr.mozilla.org/mozilla-central/source/layout/base/nsPresContext.cpp#1002
> One option would be to change layerization
> heuristics when the timeline is enabled to force content from an iframe into
> a separate layer sub-tree (we do this for the root content document to
> separate it from the chrome). Another options would be to split up the paint
> measurement and measure each individual item we paint (background, border,
> image etc), and then attribute that time to the appropriate document.
Assignee | ||
Comment 29•11 years ago
|
||
(In reply to Matt Woodrow (:mattwoodrow) from comment #26)
> One option would be to change layerization
> heuristics when the timeline is enabled to force content from an iframe into
> a separate layer sub-tree (we do this for the root content document to
> separate it from the chrome).
That sounds like a good idea to me! Is this going to degrade performance in a noticeable way?
Flags: needinfo?(matt.woodrow)
Comment 30•11 years ago
|
||
(In reply to Paul Rouget [:paul] (slow to respond. Ping me on IRC) from comment #28)
> There's obviously something wrong with my understanding of refresh drivers :)
>
> For example, look at nsPresContext.cpp, I see that we use the refreshDriver
> from the parent docshell:
>
> http://mxr.mozilla.org/mozilla-central/source/layout/base/nsPresContext.
> cpp#1006
>
Hrm, maybe there's something wrong with my understanding of refresh drivers too, hadn't seen that code before.
Anyway, this shoudn't affect that painting is always driven by the 'root' refresh driver.
(In reply to Patrick Brosset [:pbrosset] [:patrick] from comment #29)
> That sounds like a good idea to me! Is this going to degrade performance in
> a noticeable way?
It shouldn't do! It'll increase memory usage for iframes since we'll have pixels for the iframe as well as the content behind it, but that's unlikely to matter for a debugging option.
The decision is made in nsSubDocumentFrame [1], which currently makes sure we have a layer wrapping the root content document and subdocuments that are currently being scrolled. If we make that true for iframes that we are trying to track from devtools, then we can guaranteee that all layers for the iframe are within a single subtree of the layer tree.
[1] http://mxr.mozilla.org/mozilla-central/source/layout/generic/nsSubDocumentFrame.cpp#448
Flags: needinfo?(matt.woodrow)
Comment 31•10 years ago
|
||
Moving into the Profiler component. Filter on GUTHRIE'S WAVY CAKES.
Component: Developer Tools: Timeline → Developer Tools: Profiler
Updated•10 years ago
|
Summary: [timeline] reflows, restyle and paints are only recorded within refreshdriver::tick → Reflows, restyle and paints are only recorded within refreshdriver::tick
Updated•10 years ago
|
Hardware: x86_64 → All
Comment 32•10 years ago
|
||
Read through this, and I don't quite understand -- is this about recording markers for iframes? Is this still an issue?
Flags: needinfo?(paul)
Reporter | ||
Comment 33•10 years ago
|
||
All of the initial concerns I had are now covered.
Status: NEW → RESOLVED
Closed: 10 years ago
Resolution: --- → WORKSFORME
Reporter | ||
Updated•10 years ago
|
Flags: needinfo?(paul)
Comment 34•7 years ago
|
||
Removing leave-open keyword from resolved bugs, per :sylvestre.
Keywords: leave-open
Updated•7 years ago
|
Product: Firefox → DevTools
You need to log in
before you can comment on or make changes to this bug.
Description
•