Title: [202384] trunk/Source
Revision
202384
Author
[email protected]
Date
2016-06-23 11:52:59 -0700 (Thu, 23 Jun 2016)

Log Message

Web Inspector: first heap snapshot taken when a page is reloaded happens before the reload navigation
https://bugs.webkit.org/show_bug.cgi?id=158995
<rdar://problem/26923778>

Reviewed by Brian Burg.

Source/WebCore:

When the "Heap" instrument is included in the Timeline list
of instruments, defer starting it in an auto-capture scenario
until after the page does its first navigation.

AutoCapture on the backend happens when it is enabled at
the main resource starts loading. In that case it proceeds
through the following phases:

    No Auto Capture:
        None

    Auto Capture:
        BeforeLoad -> FirstNavigation -> AfterFirstNavigation

When toggling instruments for backend initiated capture
most instruments do not care and will just start/stop.

* inspector/InspectorInstrumentation.cpp:
(WebCore::InspectorInstrumentation::didCommitLoadImpl):
Inform the TimelineAgent that the main frame navigated.
Do this after informing the HeapAgent (so any potential
snapshot does not get cleared) and PageAgent (so the
frontend knows the page navigated before the agent starts).

* inspector/InspectorTimelineAgent.h:
* inspector/InspectorTimelineAgent.cpp:
(WebCore::InspectorTimelineAgent::internalStop):
(WebCore::InspectorTimelineAgent::mainFrameStartedLoading):
(WebCore::InspectorTimelineAgent::mainFrameNavigated):
Update the auto capture phase transitions.

(WebCore::InspectorTimelineAgent::toggleHeapInstrument):
Only start the heap agent during the None phase (console.profile)
or with the first navigation (auto capture page navigation).

Source/WebInspectorUI:

Let instruments decide to do work or not based on programmatic
(backend initiated) starts and stop.

Programmatic start can happen due to Auto Capture or console.profile.
Programmatic stop can happen due to console.profileEnd.

For example, this allows the frontend to avoid sending agents start/stop
messages when the backend would have already started/stopped the agents.

* UserInterface/Controllers/TimelineManager.js:
(WebInspector.TimelineManager):
(WebInspector.TimelineManager.prototype.startCapturing):
(WebInspector.TimelineManager.prototype.capturingStopped):
(WebInspector.TimelineManager.prototype.autoCaptureStarted):
(WebInspector.TimelineManager.prototype.programmaticCaptureStarted):
Call Recording.start/stop with a programmatic flag so the frontend
instruments can perform a more informed start/stop.

* UserInterface/Models/TimelineRecording.js:
(WebInspector.TimelineRecording.prototype.start):
(WebInspector.TimelineRecording.prototype.stop):
Let the instruments decide to do work based on the start/stop
being initiated by the backend or not.

* UserInterface/Models/HeapAllocationsInstrument.js:
(WebInspector.HeapAllocationsInstrument.prototype.startInstrumentation):
(WebInspector.HeapAllocationsInstrument.prototype.stopInstrumentation):
* UserInterface/Models/Instrument.js:
(WebInspector.Instrument.startLegacyTimelineAgent):
(WebInspector.Instrument.prototype.startInstrumentation):
(WebInspector.Instrument.prototype.stopInstrumentation):
(WebInspector.Instrument):
* UserInterface/Models/MemoryInstrument.js:
(WebInspector.MemoryInstrument.prototype.startInstrumentation):
(WebInspector.MemoryInstrument.prototype.stopInstrumentation):
(WebInspector.MemoryInstrument):
* UserInterface/Models/NetworkInstrument.js:
* UserInterface/Models/ScriptInstrument.js:
(WebInspector.ScriptInstrument.prototype.startInstrumentation):
(WebInspector.ScriptInstrument.prototype.stopInstrumentation):
(WebInspector.ScriptInstrument):
Avoid sending start/stop tracking messages when programmatic.
This still allows the instruments to do their own frontend tracking,
such as the Heap agent triggering periodic snapshots.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (202383 => 202384)


--- trunk/Source/WebCore/ChangeLog	2016-06-23 18:52:54 UTC (rev 202383)
+++ trunk/Source/WebCore/ChangeLog	2016-06-23 18:52:59 UTC (rev 202384)
@@ -1,5 +1,48 @@
 2016-06-23  Joseph Pecoraro  <[email protected]>
 
+        Web Inspector: first heap snapshot taken when a page is reloaded happens before the reload navigation
+        https://bugs.webkit.org/show_bug.cgi?id=158995
+        <rdar://problem/26923778>
+
+        Reviewed by Brian Burg.
+
+        When the "Heap" instrument is included in the Timeline list
+        of instruments, defer starting it in an auto-capture scenario
+        until after the page does its first navigation.
+
+        AutoCapture on the backend happens when it is enabled at
+        the main resource starts loading. In that case it proceeds
+        through the following phases:
+
+            No Auto Capture:
+                None
+
+            Auto Capture:
+                BeforeLoad -> FirstNavigation -> AfterFirstNavigation
+
+        When toggling instruments for backend initiated capture
+        most instruments do not care and will just start/stop.
+
+        * inspector/InspectorInstrumentation.cpp:
+        (WebCore::InspectorInstrumentation::didCommitLoadImpl):
+        Inform the TimelineAgent that the main frame navigated.
+        Do this after informing the HeapAgent (so any potential
+        snapshot does not get cleared) and PageAgent (so the
+        frontend knows the page navigated before the agent starts).
+
+        * inspector/InspectorTimelineAgent.h:
+        * inspector/InspectorTimelineAgent.cpp:
+        (WebCore::InspectorTimelineAgent::internalStop):
+        (WebCore::InspectorTimelineAgent::mainFrameStartedLoading):
+        (WebCore::InspectorTimelineAgent::mainFrameNavigated):
+        Update the auto capture phase transitions.
+
+        (WebCore::InspectorTimelineAgent::toggleHeapInstrument):
+        Only start the heap agent during the None phase (console.profile)
+        or with the first navigation (auto capture page navigation).
+
+2016-06-23  Joseph Pecoraro  <[email protected]>
+
         Web Inspector: Snapshots should be cleared at some point
         https://bugs.webkit.org/show_bug.cgi?id=157907
         <rdar://problem/26373610>

Modified: trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp (202383 => 202384)


--- trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp	2016-06-23 18:52:54 UTC (rev 202383)
+++ trunk/Source/WebCore/inspector/InspectorInstrumentation.cpp	2016-06-23 18:52:59 UTC (rev 202384)
@@ -754,6 +754,11 @@
     if (InspectorPageAgent* pageAgent = instrumentingAgents.inspectorPageAgent())
         pageAgent->frameNavigated(loader);
 
+    if (loader->frame()->isMainFrame()) {
+        if (InspectorTimelineAgent* timelineAgent = instrumentingAgents.inspectorTimelineAgent())
+            timelineAgent->mainFrameNavigated();
+    }
+
 #if ENABLE(WEB_REPLAY)
     if (InspectorReplayAgent* replayAgent = instrumentingAgents.inspectorReplayAgent())
         replayAgent->frameNavigated(loader);

Modified: trunk/Source/WebCore/inspector/InspectorTimelineAgent.cpp (202383 => 202384)


--- trunk/Source/WebCore/inspector/InspectorTimelineAgent.cpp	2016-06-23 18:52:54 UTC (rev 202383)
+++ trunk/Source/WebCore/inspector/InspectorTimelineAgent.cpp	2016-06-23 18:52:59 UTC (rev 202384)
@@ -234,6 +234,7 @@
 
     m_enabled = false;
     m_startedComposite = false;
+    m_autoCapturePhase = AutoCapturePhase::None;
 
     m_frontendDispatcher->recordingStopped(timestamp());
 }
@@ -439,6 +440,8 @@
     if (m_instruments.isEmpty())
         return;
 
+    m_autoCapturePhase = AutoCapturePhase::BeforeLoad;
+
     // Pre-emptively disable breakpoints. The frontend must re-enable them.
     if (InspectorDebuggerAgent* debuggerAgent = m_instrumentingAgents.inspectorDebuggerAgent()) {
         ErrorString unused;
@@ -451,6 +454,15 @@
     toggleInstruments(InstrumentState::Start);
 }
 
+void InspectorTimelineAgent::mainFrameNavigated()
+{
+    if (m_autoCapturePhase == AutoCapturePhase::BeforeLoad) {
+        m_autoCapturePhase = AutoCapturePhase::FirstNavigation;
+        toggleInstruments(InstrumentState::Start);
+        m_autoCapturePhase = AutoCapturePhase::AfterFirstNavigation;
+    }
+}
+
 void InspectorTimelineAgent::startProgrammaticCapture()
 {
     ASSERT(!m_enabled);
@@ -531,9 +543,10 @@
 {
     if (m_heapAgent) {
         ErrorString unused;
-        if (state == InstrumentState::Start)
-            m_heapAgent->startTracking(unused);
-        else
+        if (state == InstrumentState::Start) {
+            if (m_autoCapturePhase == AutoCapturePhase::None || m_autoCapturePhase == AutoCapturePhase::FirstNavigation)
+                m_heapAgent->startTracking(unused);
+        } else
             m_heapAgent->stopTracking(unused);
     }
 }

Modified: trunk/Source/WebCore/inspector/InspectorTimelineAgent.h (202383 => 202384)


--- trunk/Source/WebCore/inspector/InspectorTimelineAgent.h	2016-06-23 18:52:54 UTC (rev 202383)
+++ trunk/Source/WebCore/inspector/InspectorTimelineAgent.h	2016-06-23 18:52:59 UTC (rev 202384)
@@ -141,6 +141,7 @@
     void time(Frame&, const String&);
     void timeEnd(Frame&, const String&);
     void mainFrameStartedLoading();
+    void mainFrameNavigated();
 
 private:
     // ScriptDebugListener
@@ -222,6 +223,8 @@
     bool m_programmaticCaptureRestoreBreakpointActiveValue { false };
 
     bool m_autoCaptureEnabled { false };
+    enum class AutoCapturePhase { None, BeforeLoad, FirstNavigation, AfterFirstNavigation };
+    AutoCapturePhase m_autoCapturePhase { AutoCapturePhase::None };
     Vector<Inspector::Protocol::Timeline::Instrument> m_instruments;
 
 #if PLATFORM(COCOA)

Modified: trunk/Source/WebInspectorUI/ChangeLog (202383 => 202384)


--- trunk/Source/WebInspectorUI/ChangeLog	2016-06-23 18:52:54 UTC (rev 202383)
+++ trunk/Source/WebInspectorUI/ChangeLog	2016-06-23 18:52:59 UTC (rev 202384)
@@ -1,5 +1,58 @@
 2016-06-23  Joseph Pecoraro  <[email protected]>
 
+        Web Inspector: first heap snapshot taken when a page is reloaded happens before the reload navigation
+        https://bugs.webkit.org/show_bug.cgi?id=158995
+        <rdar://problem/26923778>
+
+        Reviewed by Brian Burg.
+
+        Let instruments decide to do work or not based on programmatic
+        (backend initiated) starts and stop.
+
+        Programmatic start can happen due to Auto Capture or console.profile.
+        Programmatic stop can happen due to console.profileEnd.
+
+        For example, this allows the frontend to avoid sending agents start/stop
+        messages when the backend would have already started/stopped the agents.
+
+        * UserInterface/Controllers/TimelineManager.js:
+        (WebInspector.TimelineManager):
+        (WebInspector.TimelineManager.prototype.startCapturing):
+        (WebInspector.TimelineManager.prototype.capturingStopped):
+        (WebInspector.TimelineManager.prototype.autoCaptureStarted):
+        (WebInspector.TimelineManager.prototype.programmaticCaptureStarted):
+        Call Recording.start/stop with a programmatic flag so the frontend
+        instruments can perform a more informed start/stop.
+
+        * UserInterface/Models/TimelineRecording.js:
+        (WebInspector.TimelineRecording.prototype.start):
+        (WebInspector.TimelineRecording.prototype.stop):
+        Let the instruments decide to do work based on the start/stop
+        being initiated by the backend or not.
+
+        * UserInterface/Models/HeapAllocationsInstrument.js:
+        (WebInspector.HeapAllocationsInstrument.prototype.startInstrumentation):
+        (WebInspector.HeapAllocationsInstrument.prototype.stopInstrumentation):
+        * UserInterface/Models/Instrument.js:
+        (WebInspector.Instrument.startLegacyTimelineAgent):
+        (WebInspector.Instrument.prototype.startInstrumentation):
+        (WebInspector.Instrument.prototype.stopInstrumentation):
+        (WebInspector.Instrument):
+        * UserInterface/Models/MemoryInstrument.js:
+        (WebInspector.MemoryInstrument.prototype.startInstrumentation):
+        (WebInspector.MemoryInstrument.prototype.stopInstrumentation):
+        (WebInspector.MemoryInstrument):
+        * UserInterface/Models/NetworkInstrument.js:
+        * UserInterface/Models/ScriptInstrument.js:
+        (WebInspector.ScriptInstrument.prototype.startInstrumentation):
+        (WebInspector.ScriptInstrument.prototype.stopInstrumentation):
+        (WebInspector.ScriptInstrument):
+        Avoid sending start/stop tracking messages when programmatic.
+        This still allows the instruments to do their own frontend tracking,
+        such as the Heap agent triggering periodic snapshots.
+
+2016-06-23  Joseph Pecoraro  <[email protected]>
+
         Web Inspector: Snapshots should be cleared at some point
         https://bugs.webkit.org/show_bug.cgi?id=157907
         <rdar://problem/26373610>

Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js (202383 => 202384)


--- trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js	2016-06-23 18:52:54 UTC (rev 202383)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js	2016-06-23 18:52:59 UTC (rev 202384)
@@ -42,6 +42,8 @@
         this._persistentNetworkTimeline = new WebInspector.NetworkTimeline;
 
         this._isCapturing = false;
+        this._initiatedByBackendStart = false;
+        this._initiatedByBackendStop = false;
         this._waitingForCapturingStartedEvent = false;
         this._isCapturingPageReload = false;
         this._autoCaptureOnPageLoad = false;
@@ -180,7 +182,7 @@
 
         this.dispatchEventToListeners(WebInspector.TimelineManager.Event.CapturingWillStart);
 
-        this._activeRecording.start();
+        this._activeRecording.start(this._initiatedByBackendStart);
     }
 
     stopCapturing()
@@ -187,7 +189,7 @@
     {
         console.assert(this._isCapturing, "TimelineManager is not capturing.");
 
-        this._activeRecording.stop();
+        this._activeRecording.stop(this._initiatedByBackendStop);
 
         // NOTE: Always stop immediately instead of waiting for a Timeline.recordingStopped event.
         // This way the UI feels as responsive to a stop as possible.
@@ -263,6 +265,8 @@
         this._isCapturingPageReload = false;
         this._shouldSetAutoCapturingMainResource = false;
         this._mainResourceForAutoCapturing = null;
+        this._initiatedByBackendStart = false;
+        this._initiatedByBackendStop = false;
 
         this.dispatchEventToListeners(WebInspector.TimelineManager.Event.CapturingStopped, {endTime});
     }
@@ -274,6 +278,8 @@
         if (this._isCapturing)
             this.stopCapturing();
 
+        this._initiatedByBackendStart = true;
+
         // We may already have an fresh TimelineRecording created if autoCaptureStarted is received
         // between sending the Timeline.start command and receiving Timeline.capturingStarted event.
         // In that case, there is no need to call startCapturing again. Reuse the fresh recording.
@@ -289,6 +295,8 @@
     {
         // Called from WebInspector.TimelineObserver.
 
+        this._initiatedByBackendStart = true;
+
         this._activeRecording.addScriptInstrumentForProgrammaticCapture();
 
         const createNewRecording = false;
@@ -299,6 +307,8 @@
     {
         // Called from WebInspector.TimelineObserver.
 
+        this._initiatedByBackendStop = true;
+
         // FIXME: This is purely to avoid a noisy assert. Previously
         // it was impossible to stop without stopping from the UI.
         console.assert(!this._isCapturing);

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/HeapAllocationsInstrument.js (202383 => 202384)


--- trunk/Source/WebInspectorUI/UserInterface/Models/HeapAllocationsInstrument.js	2016-06-23 18:52:54 UTC (rev 202383)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/HeapAllocationsInstrument.js	2016-06-23 18:52:59 UTC (rev 202384)
@@ -49,12 +49,13 @@
         return WebInspector.TimelineRecord.Type.HeapAllocations;
     }
 
-    startInstrumentation()
+    startInstrumentation(initiatedByBackend)
     {
         // FIXME: Include a "track allocations" option for this instrument.
         // FIXME: Include a periodic snapshot interval option for this instrument.
 
-        HeapAgent.startTracking();
+        if (!initiatedByBackend)
+            HeapAgent.startTracking();
 
         // Periodic snapshots.
         const snapshotInterval = 10000;
@@ -61,9 +62,10 @@
         this._snapshotIntervalIdentifier = setInterval(this._takeHeapSnapshot.bind(this), snapshotInterval);
     }
 
-    stopInstrumentation()
+    stopInstrumentation(initiatedByBackend)
     {
-        HeapAgent.stopTracking();
+        if (!initiatedByBackend)
+            HeapAgent.stopTracking();
 
         window.clearInterval(this._snapshotIntervalIdentifier);
         this._snapshotIntervalIdentifier = undefined;

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Instrument.js (202383 => 202384)


--- trunk/Source/WebInspectorUI/UserInterface/Models/Instrument.js	2016-06-23 18:52:54 UTC (rev 202383)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Instrument.js	2016-06-23 18:52:59 UTC (rev 202384)
@@ -48,7 +48,7 @@
         }
     }
 
-    static startLegacyTimelineAgent()
+    static startLegacyTimelineAgent(initiatedByBackend)
     {
         console.assert(window.TimelineAgent, "Attempted to start legacy timeline agent without TimelineAgent.");
 
@@ -57,6 +57,9 @@
 
         WebInspector.Instrument._legacyTimelineAgentStarted = true;
 
+        if (initiatedByBackend)
+            return;
+
         let result = TimelineAgent.start();
 
         // COMPATIBILITY (iOS 7): recordingStarted event did not exist yet. Start explicitly.
@@ -67,7 +70,7 @@
         }
     }
 
-    static stopLegacyTimelineAgent()
+    static stopLegacyTimelineAgent(initiatedByBackend)
     {
         if (!WebInspector.Instrument._legacyTimelineAgentStarted)
             return;
@@ -74,6 +77,9 @@
 
         WebInspector.Instrument._legacyTimelineAgentStarted = false;
 
+        if (initiatedByBackend)
+            return;
+
         TimelineAgent.stop();
     }
 
@@ -84,14 +90,14 @@
         return null; // Implemented by subclasses.
     }
 
-    startInstrumentation()
+    startInstrumentation(initiatedByBackend)
     {
-        WebInspector.Instrument.startLegacyTimelineAgent();
+        WebInspector.Instrument.startLegacyTimelineAgent(initiatedByBackend);
     }
 
-    stopInstrumentation()
+    stopInstrumentation(initiatedByBackend)
     {
-        WebInspector.Instrument.stopLegacyTimelineAgent();
+        WebInspector.Instrument.stopLegacyTimelineAgent(initiatedByBackend);
     }
 };
 

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/MemoryInstrument.js (202383 => 202384)


--- trunk/Source/WebInspectorUI/UserInterface/Models/MemoryInstrument.js	2016-06-23 18:52:54 UTC (rev 202383)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/MemoryInstrument.js	2016-06-23 18:52:59 UTC (rev 202384)
@@ -47,13 +47,15 @@
         return WebInspector.TimelineRecord.Type.Memory;
     }
 
-    startInstrumentation()
+    startInstrumentation(initiatedByBackend)
     {
-        MemoryAgent.startTracking();
+        if (!initiatedByBackend)
+            MemoryAgent.startTracking();
     }
 
-    stopInstrumentation()
+    stopInstrumentation(initiatedByBackend)
     {
-        MemoryAgent.stopTracking();
+        if (!initiatedByBackend)
+            MemoryAgent.stopTracking();
     }
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/NetworkInstrument.js (202383 => 202384)


--- trunk/Source/WebInspectorUI/UserInterface/Models/NetworkInstrument.js	2016-06-23 18:52:54 UTC (rev 202383)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/NetworkInstrument.js	2016-06-23 18:52:59 UTC (rev 202384)
@@ -32,12 +32,12 @@
         return WebInspector.TimelineRecord.Type.Network;
     }
 
-    startInstrumentation()
+    startInstrumentation(initiatedByBackend)
     {
         // Nothing to do, network instrumentation is always happening.
     }
 
-    stopInstrumentation()
+    stopInstrumentation(initiatedByBackend)
     {
         // Nothing to do, network instrumentation is always happening.
     }

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js (202383 => 202384)


--- trunk/Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js	2016-06-23 18:52:54 UTC (rev 202383)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js	2016-06-23 18:52:59 UTC (rev 202384)
@@ -32,7 +32,7 @@
         return WebInspector.TimelineRecord.Type.Script;
     }
 
-    startInstrumentation()
+    startInstrumentation(initiatedByBackend)
     {
         // COMPATIBILITY (iOS 9): Legacy backends did not have ScriptProfilerAgent. They use TimelineAgent.
         if (!window.ScriptProfilerAgent) {
@@ -43,10 +43,11 @@
         // FIXME: Make this some UI visible option.
         const includeSamples = true;
 
-        ScriptProfilerAgent.startTracking(includeSamples);
+        if (!initiatedByBackend)
+            ScriptProfilerAgent.startTracking(includeSamples);
     }
 
-    stopInstrumentation()
+    stopInstrumentation(initiatedByBackend)
     {
         // COMPATIBILITY (iOS 9): Legacy backends did not have ScriptProfilerAgent. They use TimelineAgent.
         if (!window.ScriptProfilerAgent) {
@@ -54,6 +55,7 @@
             return;
         }
 
-        ScriptProfilerAgent.stopTracking();
+        if (!initiatedByBackend)
+            ScriptProfilerAgent.stopTracking();
     }
 };

Modified: trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js (202383 => 202384)


--- trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js	2016-06-23 18:52:54 UTC (rev 202383)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js	2016-06-23 18:52:59 UTC (rev 202384)
@@ -116,7 +116,7 @@
         return this._topFunctionsBottomUpCallingContextTree;
     }
 
-    start()
+    start(initiatedByBackend)
     {
         console.assert(!this._capturing, "Attempted to start an already started session.");
         console.assert(!this._readonly, "Attempted to start a readonly session.");
@@ -124,10 +124,10 @@
         this._capturing = true;
 
         for (let instrument of this._instruments)
-            instrument.startInstrumentation();
+            instrument.startInstrumentation(initiatedByBackend);
     }
 
-    stop(programmatic)
+    stop(initiatedByBackend)
     {
         console.assert(this._capturing, "Attempted to stop an already stopped session.");
         console.assert(!this._readonly, "Attempted to stop a readonly session.");
@@ -134,10 +134,8 @@
 
         this._capturing = false;
 
-        if (!programmatic) {
-            for (let instrument of this._instruments)
-                instrument.stopInstrumentation();
-        }
+        for (let instrument of this._instruments)
+            instrument.stopInstrumentation(initiatedByBackend);
     }
 
     saveIdentityToCookie()
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to