Changeset 202152 in webkit


Ignore:
Timestamp:
Jun 16, 2016 7:26:47 PM (8 years ago)
Author:
commit-queue@webkit.org
Message:

Web Inspector: console.profile should use the new Sampling Profiler
https://bugs.webkit.org/show_bug.cgi?id=153499
<rdar://problem/24352431>

Patch by Joseph Pecoraro <Joseph Pecoraro> on 2016-06-16
Reviewed by Timothy Hatcher.

Source/JavaScriptCore:

Currently console.profile/profileEnd behave slightly differently
between JSContext and Web inspection. Unifying will be part of:
<https://webkit.org/b/158753> Generalize the concept of Instruments on the backend

Both JSContext and Web inspection keep track of active
profiles started and stopped via console.profile/profileEnd.

JSContext inspection sends its programmatic start/stop
via the ScriptProfiler domain.

Web inspection sends its programmatic start/stop
via the Timeline domain, and also will start/stop backend
list of Instruments.

The functional differences between these is that for JSContext
inspection, console.profile only starts/stops the ScriptProfiler
domain, and does not auto-start other instruments. This isn't really
a problem right now given the instruments available for JSContext
inspection; but it will be nice to unify as we add more instruments.
Also, JSContext inspection won't have "Profile (name)" records in
its Events view, since those are currently generated only by the
Web's Timeline domain.

  • inspector/protocol/ScriptProfiler.json:
  • inspector/protocol/Timeline.json:

Events to inform the frontend of programmatic start/stop.

  • debugger/Debugger.h:
  • inspector/agents/InspectorDebuggerAgent.cpp:

(Inspector::InspectorDebuggerAgent::breakpointsActive):
(Inspector::InspectorDebuggerAgent::isPaused):

  • inspector/agents/InspectorDebuggerAgent.h:

Expose breakpoints active state, since programmatic recording
will temporarily disabled breakpoints if needed.

  • inspector/JSGlobalObjectConsoleClient.cpp:

(Inspector::JSGlobalObjectConsoleClient::JSGlobalObjectConsoleClient):
(Inspector::JSGlobalObjectConsoleClient::profile):
(Inspector::JSGlobalObjectConsoleClient::profileEnd):
(Inspector::JSGlobalObjectConsoleClient::startConsoleProfile):
(Inspector::JSGlobalObjectConsoleClient::stopConsoleProfile):

  • inspector/JSGlobalObjectConsoleClient.h:
  • inspector/JSGlobalObjectInspectorController.cpp:

(Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController):

  • inspector/agents/InspectorScriptProfilerAgent.cpp:

(Inspector::InspectorScriptProfilerAgent::programmaticCaptureStarted):
(Inspector::InspectorScriptProfilerAgent::programmaticCaptureStopped):

  • inspector/agents/InspectorScriptProfilerAgent.h:

JSContext implementation of console.profile/profileEnd.

Source/WebCore:

Test: inspector/timeline/setInstruments-programmatic-capture.html

  • inspector/InspectorTimelineAgent.cpp:

(WebCore::InspectorTimelineAgent::startFromConsole):
(WebCore::InspectorTimelineAgent::stopFromConsole):
(WebCore::InspectorTimelineAgent::mainFrameStartedLoading):
(WebCore::InspectorTimelineAgent::startProgrammaticCapture):
(WebCore::InspectorTimelineAgent::stopProgrammaticCapture):
(WebCore::InspectorTimelineAgent::toggleInstruments):
(WebCore::InspectorTimelineAgent::toggleScriptProfilerInstrument):
(WebCore::InspectorTimelineAgent::toggleHeapInstrument):
(WebCore::InspectorTimelineAgent::toggleMemoryInstrument):
(WebCore::InspectorTimelineAgent::toggleTimelineInstrument):

  • inspector/InspectorTimelineAgent.h:

Web implementation of console.profile/profileEnd.
Make helpers for startings / stopping instruments.

Source/WebInspectorUI:

  • UserInterface/Controllers/TimelineManager.js:

(WebInspector.TimelineManager.prototype.programmaticCaptureStarted):
(WebInspector.TimelineManager.prototype.programmaticCaptureStopped):
(WebInspector.TimelineManager.prototype.scriptProfilerProgrammaticCaptureStarted):
(WebInspector.TimelineManager.prototype.scriptProfilerProgrammaticCaptureStopped):
For programmatic captures, automatically show the Script Timeline, since
that is guarenteed to have been started by the backend. Start capturing
without creating a new recording.

  • UserInterface/Models/TimelineRecording.js:

(WebInspector.TimelineRecording.prototype.stop):
(WebInspector.TimelineRecording.prototype.addScriptInstrumentForProgrammaticCapture):
When stopping for programmatic capture we don't need to disable
instruments, the backend would have already done this.

  • UserInterface/Protocol/ScriptProfilerObserver.js:

(WebInspector.ScriptProfilerObserver.prototype.programmaticCaptureStarted):
(WebInspector.ScriptProfilerObserver.prototype.programmaticCaptureStopped):
(WebInspector.ScriptProfilerObserver):

  • UserInterface/Protocol/TimelineObserver.js:

(WebInspector.TimelineObserver.prototype.programmaticCaptureStarted):
(WebInspector.TimelineObserver.prototype.programmaticCaptureStopped):
(WebInspector.TimelineObserver):
Pass through Web and JSContext programmatic capture events.

LayoutTests:

  • inspector/timeline/setInstruments-programmatic-capture-expected.txt: Added.
  • inspector/timeline/setInstruments-programmatic-capture.html: Added.

New test that the backend auto-starts instruments during programmatic capture.

Location:
trunk
Files:
2 added
21 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r202151 r202152  
     12016-06-16  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: console.profile should use the new Sampling Profiler
     4        https://bugs.webkit.org/show_bug.cgi?id=153499
     5        <rdar://problem/24352431>
     6
     7        Reviewed by Timothy Hatcher.
     8
     9        * inspector/timeline/setInstruments-programmatic-capture-expected.txt: Added.
     10        * inspector/timeline/setInstruments-programmatic-capture.html: Added.
     11        New test that the backend auto-starts instruments during programmatic capture.
     12
    1132016-06-16  John Wilander  <wilander@apple.com>
    214
  • trunk/Source/JavaScriptCore/ChangeLog

    r202141 r202152  
     12016-06-16  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: console.profile should use the new Sampling Profiler
     4        https://bugs.webkit.org/show_bug.cgi?id=153499
     5        <rdar://problem/24352431>
     6
     7        Reviewed by Timothy Hatcher.
     8
     9        Currently console.profile/profileEnd behave slightly differently
     10        between JSContext and Web inspection. Unifying will be part of:
     11        <https://webkit.org/b/158753> Generalize the concept of Instruments on the backend
     12
     13        Both JSContext and Web inspection keep track of active
     14        profiles started and stopped via console.profile/profileEnd.
     15
     16        JSContext inspection sends its programmatic start/stop
     17        via the ScriptProfiler domain.
     18
     19        Web inspection sends its programmatic start/stop
     20        via the Timeline domain, and also will start/stop backend
     21        list of Instruments.
     22
     23        The functional differences between these is that for JSContext
     24        inspection, console.profile only starts/stops the ScriptProfiler
     25        domain, and does not auto-start other instruments. This isn't really
     26        a problem right now given the instruments available for JSContext
     27        inspection; but it will be nice to unify as we add more instruments.
     28        Also, JSContext inspection won't have "Profile (name)" records in
     29        its Events view, since those are currently generated only by the
     30        Web's Timeline domain.
     31
     32        * inspector/protocol/ScriptProfiler.json:
     33        * inspector/protocol/Timeline.json:
     34        Events to inform the frontend of programmatic start/stop.
     35
     36        * debugger/Debugger.h:
     37        * inspector/agents/InspectorDebuggerAgent.cpp:
     38        (Inspector::InspectorDebuggerAgent::breakpointsActive):
     39        (Inspector::InspectorDebuggerAgent::isPaused):
     40        * inspector/agents/InspectorDebuggerAgent.h:
     41        Expose breakpoints active state, since programmatic recording
     42        will temporarily disabled breakpoints if needed.
     43
     44        * inspector/JSGlobalObjectConsoleClient.cpp:
     45        (Inspector::JSGlobalObjectConsoleClient::JSGlobalObjectConsoleClient):
     46        (Inspector::JSGlobalObjectConsoleClient::profile):
     47        (Inspector::JSGlobalObjectConsoleClient::profileEnd):
     48        (Inspector::JSGlobalObjectConsoleClient::startConsoleProfile):
     49        (Inspector::JSGlobalObjectConsoleClient::stopConsoleProfile):
     50        * inspector/JSGlobalObjectConsoleClient.h:
     51        * inspector/JSGlobalObjectInspectorController.cpp:
     52        (Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController):
     53        * inspector/agents/InspectorScriptProfilerAgent.cpp:
     54        (Inspector::InspectorScriptProfilerAgent::programmaticCaptureStarted):
     55        (Inspector::InspectorScriptProfilerAgent::programmaticCaptureStopped):
     56        * inspector/agents/InspectorScriptProfilerAgent.h:
     57        JSContext implementation of console.profile/profileEnd.
     58
    1592016-06-16  Filip Pizlo  <fpizlo@apple.com>
    260
  • trunk/Source/JavaScriptCore/debugger/Debugger.h

    r200981 r202152  
    7979    void activateBreakpoints() { setBreakpointsActivated(true); }
    8080    void deactivateBreakpoints() { setBreakpointsActivated(false); }
     81    bool breakpointsActive() const { return m_breakpointsActivated; }
    8182
    8283    enum PauseOnExceptionsState {
  • trunk/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp

    r198786 r202152  
    2929#include "ConsoleMessage.h"
    3030#include "InspectorConsoleAgent.h"
     31#include "InspectorDebuggerAgent.h"
     32#include "InspectorScriptProfilerAgent.h"
    3133#include "ScriptArguments.h"
    3234#include "ScriptCallStack.h"
     
    5355}
    5456
    55 JSGlobalObjectConsoleClient::JSGlobalObjectConsoleClient(InspectorConsoleAgent* consoleAgent)
     57JSGlobalObjectConsoleClient::JSGlobalObjectConsoleClient(InspectorConsoleAgent* consoleAgent, InspectorDebuggerAgent* debuggerAgent, InspectorScriptProfilerAgent* scriptProfilerAgent)
    5658    : ConsoleClient()
    5759    , m_consoleAgent(consoleAgent)
     60    , m_debuggerAgent(debuggerAgent)
     61    , m_scriptProfilerAgent(scriptProfilerAgent)
    5862{
    5963}
     
    7478}
    7579
    76 void JSGlobalObjectConsoleClient::profile(JSC::ExecState*, const String&)
     80void JSGlobalObjectConsoleClient::profile(JSC::ExecState*, const String& title)
    7781{
    78     // FIXME: support |console.profile| for JSContexts. <https://webkit.org/b/136466>
     82    if (!m_consoleAgent->enabled())
     83        return;
     84
     85    // Allow duplicate unnamed profiles. Disallow duplicate named profiles.
     86    if (!title.isEmpty()) {
     87        for (auto& existingTitle : m_profiles) {
     88            if (existingTitle == title) {
     89                // FIXME: Send an enum to the frontend for localization?
     90                String warning = title.isEmpty() ? ASCIILiteral("Unnamed Profile already exists") : makeString("Profile \"", title, "\" already exists");
     91                m_consoleAgent->addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::Profile, MessageLevel::Warning, warning));
     92                return;
     93            }
     94        }
     95    }
     96
     97    m_profiles.append(title);
     98    startConsoleProfile();
    7999}
    80100
    81 void JSGlobalObjectConsoleClient::profileEnd(JSC::ExecState*, const String&)
     101void JSGlobalObjectConsoleClient::profileEnd(JSC::ExecState*, const String& title)
    82102{
    83     // FIXME: support |console.profile| for JSContexts. <https://webkit.org/b/136466>
     103    if (!m_consoleAgent->enabled())
     104        return;
     105
     106    // Stop profiles in reverse order. If the title is empty, then stop the last profile.
     107    // Otherwise, match the title of the profile to stop.
     108    for (ptrdiff_t i = m_profiles.size() - 1; i >= 0; --i) {
     109        if (title.isEmpty() || m_profiles[i] == title) {
     110            m_profiles.remove(i);
     111            if (m_profiles.isEmpty())
     112                stopConsoleProfile();
     113            return;
     114        }
     115    }
     116
     117    // FIXME: Send an enum to the frontend for localization?
     118    String warning = title.isEmpty() ? ASCIILiteral("No profiles exist") : makeString("Profile \"", title, "\" does not exist");
     119    m_consoleAgent->addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::ProfileEnd, MessageLevel::Warning, warning));   
     120}
     121
     122void JSGlobalObjectConsoleClient::startConsoleProfile()
     123{
     124    // FIXME: <https://webkit.org/b/158753> Generalize the concept of Instruments on the backend to work equally for JSContext and Web inspection
     125    m_scriptProfilerAgent->programmaticCaptureStarted();
     126
     127    m_profileRestoreBreakpointActiveValue = m_debuggerAgent->breakpointsActive();
     128
     129    ErrorString unused;
     130    m_debuggerAgent->setBreakpointsActive(unused, false);
     131
     132    const bool includeSamples = true;
     133    m_scriptProfilerAgent->startTracking(unused, &includeSamples);
     134}
     135
     136void JSGlobalObjectConsoleClient::stopConsoleProfile()
     137{
     138    ErrorString unused;
     139    m_scriptProfilerAgent->stopTracking(unused);
     140
     141    m_debuggerAgent->setBreakpointsActive(unused, m_profileRestoreBreakpointActiveValue);
     142
     143    // FIXME: <https://webkit.org/b/158753> Generalize the concept of Instruments on the backend to work equally for JSContext and Web inspection
     144    m_scriptProfilerAgent->programmaticCaptureStopped();
    84145}
    85146
  • trunk/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h

    r198786 r202152  
    2424 */
    2525
    26 #ifndef JSGlobalObjectConsoleClient_h
    27 #define JSGlobalObjectConsoleClient_h
     26#pragma once
    2827
    2928#include "ConsoleClient.h"
     29#include <wtf/Vector.h>
     30#include <wtf/text/WTFString.h>
    3031
    3132namespace Inspector {
    3233
    3334class InspectorConsoleAgent;
     35class InspectorDebuggerAgent;
     36class InspectorScriptProfilerAgent;
    3437
    3538class JSGlobalObjectConsoleClient final : public JSC::ConsoleClient {
    3639    WTF_MAKE_FAST_ALLOCATED;
    3740public:
    38     explicit JSGlobalObjectConsoleClient(InspectorConsoleAgent*);
     41    explicit JSGlobalObjectConsoleClient(InspectorConsoleAgent*, InspectorDebuggerAgent*, InspectorScriptProfilerAgent*);
    3942    virtual ~JSGlobalObjectConsoleClient() { }
    4043
     
    5659    void internalAddMessage(MessageType, MessageLevel, JSC::ExecState*, RefPtr<ScriptArguments>&&);
    5760
     61    void startConsoleProfile();
     62    void stopConsoleProfile();
     63
    5864    InspectorConsoleAgent* m_consoleAgent;
     65    InspectorDebuggerAgent* m_debuggerAgent;
     66    InspectorScriptProfilerAgent* m_scriptProfilerAgent;
     67    Vector<String> m_profiles;
     68    bool m_profileRestoreBreakpointActiveValue { false };
    5969};
    6070
    6171}
    62 
    63 #endif // !defined(JSGlobalObjectConsoleClient_h)
  • trunk/Source/JavaScriptCore/inspector/JSGlobalObjectInspectorController.cpp

    r200893 r202152  
    8989    auto consoleAgent = std::make_unique<JSGlobalObjectConsoleAgent>(context, heapAgent.get());
    9090    auto debuggerAgent = std::make_unique<JSGlobalObjectDebuggerAgent>(context, consoleAgent.get());
     91    auto scriptProfilerAgent = std::make_unique<InspectorScriptProfilerAgent>(context);
    9192
    9293    m_inspectorAgent = inspectorAgent.get();
    9394    m_debuggerAgent = debuggerAgent.get();
    9495    m_consoleAgent = consoleAgent.get();
    95     m_consoleClient = std::make_unique<JSGlobalObjectConsoleClient>(m_consoleAgent);
     96    m_consoleClient = std::make_unique<JSGlobalObjectConsoleClient>(m_consoleAgent, m_debuggerAgent, scriptProfilerAgent.get());
    9697
    9798    m_agents.append(WTFMove(inspectorAgent));
     
    100101    m_agents.append(WTFMove(debuggerAgent));
    101102    m_agents.append(WTFMove(heapAgent));
    102     m_agents.append(std::make_unique<InspectorScriptProfilerAgent>(context));
     103    m_agents.append(WTFMove(scriptProfilerAgent));
    103104
    104105    m_executionStopwatch->start();
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp

    r200467 r202152  
    126126}
    127127
     128bool InspectorDebuggerAgent::breakpointsActive() const
     129{
     130    return m_scriptDebugServer.breakpointsActive();
     131}
     132
    128133void InspectorDebuggerAgent::setBreakpointsActive(ErrorString&, bool active)
    129134{
     
    134139}
    135140
    136 bool InspectorDebuggerAgent::isPaused()
     141bool InspectorDebuggerAgent::isPaused() const
    137142{
    138143    return m_scriptDebugServer.isPaused();
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h

    r199619 r202152  
    8484    void setOverlayMessage(ErrorString&, const String*) override;
    8585
    86     bool isPaused();
     86    bool isPaused() const;
     87    bool breakpointsActive() const;
    8788
    8889    void setSuppressAllPauses(bool);
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.cpp

    r200916 r202152  
    217217}
    218218
     219void InspectorScriptProfilerAgent::programmaticCaptureStarted()
     220{
     221    m_frontendDispatcher->programmaticCaptureStarted();
     222}
     223
     224void InspectorScriptProfilerAgent::programmaticCaptureStopped()
     225{
     226    m_frontendDispatcher->programmaticCaptureStopped();
     227}
     228
    219229} // namespace Inspector
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.h

    r197563 r202152  
    5454    void stopTracking(ErrorString&) override;
    5555
     56    void programmaticCaptureStarted();
     57    void programmaticCaptureStopped();
     58
    5659    // Debugger::ProfilingClient
    5760    bool isAlreadyProfiling() const override;
  • trunk/Source/JavaScriptCore/inspector/protocol/ScriptProfiler.json

    r199201 r202152  
    8787                { "name": "samples", "$ref": "Samples", "optional": true, "description": "Stack traces." }
    8888            ]
     89        },
     90        {
     91            "name": "programmaticCaptureStarted",
     92            "description": "Fired when programmatic capture starts (console.profile). JSContext inspection only."
     93        },
     94        {
     95            "name": "programmaticCaptureStopped",
     96            "description": "Fired when programmatic capture stops (console.profileEnd). JSContext inspection only."
    8997        }
    9098    ]
  • trunk/Source/JavaScriptCore/inspector/protocol/Timeline.json

    r202072 r202152  
    106106            "name": "autoCaptureStarted",
    107107            "description": "Fired when auto capture started."
     108        },
     109        {
     110            "name": "programmaticCaptureStarted",
     111            "description": "Fired when programmatic capture starts (console.profile)."
     112        },
     113        {
     114            "name": "programmaticCaptureStopped",
     115            "description": "Fired when programmatic capture stops (console.profileEnd)."
    108116        }
    109117    ]
  • trunk/Source/WebCore/ChangeLog

    r202151 r202152  
     12016-06-16  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: console.profile should use the new Sampling Profiler
     4        https://bugs.webkit.org/show_bug.cgi?id=153499
     5        <rdar://problem/24352431>
     6
     7        Reviewed by Timothy Hatcher.
     8
     9        Test: inspector/timeline/setInstruments-programmatic-capture.html
     10
     11        * inspector/InspectorTimelineAgent.cpp:
     12        (WebCore::InspectorTimelineAgent::startFromConsole):
     13        (WebCore::InspectorTimelineAgent::stopFromConsole):
     14        (WebCore::InspectorTimelineAgent::mainFrameStartedLoading):
     15        (WebCore::InspectorTimelineAgent::startProgrammaticCapture):
     16        (WebCore::InspectorTimelineAgent::stopProgrammaticCapture):
     17        (WebCore::InspectorTimelineAgent::toggleInstruments):
     18        (WebCore::InspectorTimelineAgent::toggleScriptProfilerInstrument):
     19        (WebCore::InspectorTimelineAgent::toggleHeapInstrument):
     20        (WebCore::InspectorTimelineAgent::toggleMemoryInstrument):
     21        (WebCore::InspectorTimelineAgent::toggleTimelineInstrument):
     22        * inspector/InspectorTimelineAgent.h:
     23        Web implementation of console.profile/profileEnd.
     24        Make helpers for startings / stopping instruments.
     25
    1262016-06-16  John Wilander  <wilander@apple.com>
    227
  • trunk/Source/WebCore/inspector/InspectorTimelineAgent.cpp

    r202072 r202152  
    4444#include "ScriptState.h"
    4545#include "TimelineRecordFactory.h"
     46#include "WebConsoleAgent.h"
     47#include <inspector/ConsoleMessage.h>
    4648#include <inspector/ScriptBreakpoint.h>
    4749#include <inspector/agents/InspectorDebuggerAgent.h>
     
    242244}
    243245
    244 void InspectorTimelineAgent::startFromConsole(JSC::ExecState*, const String&)
    245 {
    246     // FIXME: <https://webkit.org/b/153499> Web Inspector: console.profile should use the new Sampling Profiler
    247 }
    248 
    249 void InspectorTimelineAgent::stopFromConsole(JSC::ExecState*, const String&)
    250 {
    251     // FIXME: <https://webkit.org/b/153499> Web Inspector: console.profile should use the new Sampling Profiler
     246void InspectorTimelineAgent::startFromConsole(JSC::ExecState* exec, const String& title)
     247{
     248    // Allow duplicate unnamed profiles. Disallow duplicate named profiles.
     249    if (!title.isEmpty()) {
     250        for (const TimelineRecordEntry& record : m_pendingConsoleProfileRecords) {
     251            String recordTitle;
     252            record.data->getString(ASCIILiteral("title"), recordTitle);
     253            if (recordTitle == title) {
     254                if (WebConsoleAgent* consoleAgent = m_instrumentingAgents.webConsoleAgent()) {
     255                    // FIXME: Send an enum to the frontend for localization?
     256                    String warning = title.isEmpty() ? ASCIILiteral("Unnamed Profile already exists") : makeString("Profile \"", title, "\" already exists");
     257                    consoleAgent->addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::Profile, MessageLevel::Warning, warning));
     258                }
     259                return;
     260            }
     261        }
     262    }
     263
     264    if (!m_enabled && m_pendingConsoleProfileRecords.isEmpty())
     265        startProgrammaticCapture();
     266
     267    m_pendingConsoleProfileRecords.append(createRecordEntry(TimelineRecordFactory::createConsoleProfileData(title), TimelineRecordType::ConsoleProfile, true, frameFromExecState(exec)));
     268}
     269
     270void InspectorTimelineAgent::stopFromConsole(JSC::ExecState*, const String& title)
     271{
     272    // Stop profiles in reverse order. If the title is empty, then stop the last profile.
     273    // Otherwise, match the title of the profile to stop.
     274    for (int i = m_pendingConsoleProfileRecords.size() - 1; i >= 0; --i) {
     275        const TimelineRecordEntry& record = m_pendingConsoleProfileRecords[i];
     276
     277        String recordTitle;
     278        record.data->getString(ASCIILiteral("title"), recordTitle);
     279        if (title.isEmpty() || recordTitle == title) {
     280            didCompleteRecordEntry(record);
     281            m_pendingConsoleProfileRecords.remove(i);
     282
     283            if (!m_enabledFromFrontend && m_pendingConsoleProfileRecords.isEmpty())
     284                stopProgrammaticCapture();
     285
     286            return;
     287        }
     288    }
     289
     290    if (WebConsoleAgent* consoleAgent = m_instrumentingAgents.webConsoleAgent()) {
     291        // FIXME: Send an enum to the frontend for localization?
     292        String warning = title.isEmpty() ? ASCIILiteral("No profiles exist") : makeString("Profile \"", title, "\" does not exist");
     293        consoleAgent->addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::ConsoleAPI, MessageType::ProfileEnd, MessageLevel::Warning, warning));   
     294    }
    252295}
    253296
     
    406449    m_frontendDispatcher->autoCaptureStarted();
    407450
    408     // Enable instruments.
     451    toggleInstruments(InstrumentState::Start);
     452}
     453
     454void InspectorTimelineAgent::startProgrammaticCapture()
     455{
     456    ASSERT(!m_enabled);
     457
     458    // Disable breakpoints during programmatic capture.
     459    if (InspectorDebuggerAgent* debuggerAgent = m_instrumentingAgents.inspectorDebuggerAgent()) {
     460        m_programmaticCaptureRestoreBreakpointActiveValue = debuggerAgent->breakpointsActive();
     461        if (m_programmaticCaptureRestoreBreakpointActiveValue) {
     462            ErrorString unused;
     463            debuggerAgent->setBreakpointsActive(unused, false);
     464        }
     465    } else
     466        m_programmaticCaptureRestoreBreakpointActiveValue = false;
     467
     468    m_frontendDispatcher->programmaticCaptureStarted();
     469
     470    toggleScriptProfilerInstrument(InstrumentState::Start); // Ensure JavaScript samping data.
     471    toggleTimelineInstrument(InstrumentState::Start); // Ensure Console Profile event records.
     472    toggleInstruments(InstrumentState::Start); // Any other instruments the frontend wants us to record.
     473}
     474
     475void InspectorTimelineAgent::stopProgrammaticCapture()
     476{
     477    ASSERT(m_enabled);
     478    ASSERT(!m_enabledFromFrontend);
     479
     480    toggleInstruments(InstrumentState::Stop);
     481    toggleTimelineInstrument(InstrumentState::Stop);
     482    toggleScriptProfilerInstrument(InstrumentState::Stop);
     483
     484    // Re-enable breakpoints if they were enabled.
     485    if (m_programmaticCaptureRestoreBreakpointActiveValue) {
     486        if (InspectorDebuggerAgent* debuggerAgent = m_instrumentingAgents.inspectorDebuggerAgent()) {
     487            ErrorString unused;
     488            debuggerAgent->setBreakpointsActive(unused, true);
     489        }
     490    }
     491
     492    m_frontendDispatcher->programmaticCaptureStopped();
     493}
     494
     495void InspectorTimelineAgent::toggleInstruments(InstrumentState state)
     496{
    409497    for (auto instrumentType : m_instruments) {
    410498        switch (instrumentType) {
    411499        case Inspector::Protocol::Timeline::Instrument::ScriptProfiler: {
    412             if (m_scriptProfilerAgent) {
    413                 ErrorString unused;
    414                 const bool includeSamples = true;
    415                 m_scriptProfilerAgent->startTracking(unused, &includeSamples);
    416             }
     500            toggleScriptProfilerInstrument(state);
    417501            break;
    418502        }
    419503        case Inspector::Protocol::Timeline::Instrument::Heap: {
    420             if (m_heapAgent) {
    421                 ErrorString unused;
    422                 m_heapAgent->startTracking(unused);
    423             }
     504            toggleHeapInstrument(state);
    424505            break;
    425506        }
    426507        case Inspector::Protocol::Timeline::Instrument::Memory: {
     508            toggleMemoryInstrument(state);
     509            break;
     510        }
     511        case Inspector::Protocol::Timeline::Instrument::Timeline:
     512            toggleTimelineInstrument(state);
     513            break;
     514        }
     515    }
     516}
     517
     518void InspectorTimelineAgent::toggleScriptProfilerInstrument(InstrumentState state)
     519{
     520    if (m_scriptProfilerAgent) {
     521        ErrorString unused;
     522        if (state == InstrumentState::Start) {
     523            const bool includeSamples = true;
     524            m_scriptProfilerAgent->startTracking(unused, &includeSamples);
     525        } else
     526            m_scriptProfilerAgent->stopTracking(unused);
     527    }
     528}
     529
     530void InspectorTimelineAgent::toggleHeapInstrument(InstrumentState state)
     531{
     532    if (m_heapAgent) {
     533        ErrorString unused;
     534        if (state == InstrumentState::Start)
     535            m_heapAgent->startTracking(unused);
     536        else
     537            m_heapAgent->stopTracking(unused);
     538    }
     539}
     540
     541void InspectorTimelineAgent::toggleMemoryInstrument(InstrumentState state)
     542{
    427543#if ENABLE(RESOURCE_USAGE)
    428             if (InspectorMemoryAgent* memoryAgent = m_instrumentingAgents.inspectorMemoryAgent()) {
    429                 ErrorString unused;
    430                 memoryAgent->startTracking(unused);
    431             }
     544    if (InspectorMemoryAgent* memoryAgent = m_instrumentingAgents.inspectorMemoryAgent()) {
     545        ErrorString unused;
     546        if (state == InstrumentState::Start)
     547            memoryAgent->startTracking(unused);
     548        else
     549            memoryAgent->stopTracking(unused);
     550    }
     551#else
     552    UNUSED_PARAM(state);
    432553#endif
    433             break;
    434         }
    435         case Inspector::Protocol::Timeline::Instrument::Timeline:
    436             internalStart();
    437             break;
    438         }
    439     }
     554}
     555
     556void InspectorTimelineAgent::toggleTimelineInstrument(InstrumentState state)
     557{
     558    if (state == InstrumentState::Start)
     559        internalStart();
     560    else
     561        internalStop();
    440562}
    441563
  • trunk/Source/WebCore/inspector/InspectorTimelineAgent.h

    r202072 r202152  
    154154    void breakpointActionProbe(JSC::ExecState&, const Inspector::ScriptBreakpointAction&, unsigned batchId, unsigned sampleId, JSC::JSValue result) final;
    155155
     156    void startProgrammaticCapture();
     157    void stopProgrammaticCapture();
     158
     159    enum class InstrumentState { Start, Stop };
     160    void toggleInstruments(InstrumentState);
     161    void toggleScriptProfilerInstrument(InstrumentState);
     162    void toggleHeapInstrument(InstrumentState);
     163    void toggleMemoryInstrument(InstrumentState);
     164    void toggleTimelineInstrument(InstrumentState);
     165    void disableBreakpoints();
     166    void enableBreakpoints();
     167
    156168    friend class TimelineRecordStack;
    157169
     
    201213
    202214    Vector<TimelineRecordEntry> m_recordStack;
     215    Vector<TimelineRecordEntry> m_pendingConsoleProfileRecords;
    203216
    204217    int m_id { 1 };
     
    207220    bool m_enabled { false };
    208221    bool m_enabledFromFrontend { false };
     222    bool m_programmaticCaptureRestoreBreakpointActiveValue { false };
    209223
    210224    bool m_autoCaptureEnabled { false };
  • trunk/Source/WebInspectorUI/ChangeLog

    r202138 r202152  
     12016-06-16  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: console.profile should use the new Sampling Profiler
     4        https://bugs.webkit.org/show_bug.cgi?id=153499
     5        <rdar://problem/24352431>
     6
     7        Reviewed by Timothy Hatcher.
     8
     9        * UserInterface/Controllers/TimelineManager.js:
     10        (WebInspector.TimelineManager.prototype.programmaticCaptureStarted):
     11        (WebInspector.TimelineManager.prototype.programmaticCaptureStopped):
     12        (WebInspector.TimelineManager.prototype.scriptProfilerProgrammaticCaptureStarted):
     13        (WebInspector.TimelineManager.prototype.scriptProfilerProgrammaticCaptureStopped):
     14        For programmatic captures, automatically show the Script Timeline, since
     15        that is guarenteed to have been started by the backend. Start capturing
     16        without creating a new recording.
     17
     18        * UserInterface/Models/TimelineRecording.js:
     19        (WebInspector.TimelineRecording.prototype.stop):
     20        (WebInspector.TimelineRecording.prototype.addScriptInstrumentForProgrammaticCapture):
     21        When stopping for programmatic capture we don't need to disable
     22        instruments, the backend would have already done this.
     23
     24        * UserInterface/Protocol/ScriptProfilerObserver.js:
     25        (WebInspector.ScriptProfilerObserver.prototype.programmaticCaptureStarted):
     26        (WebInspector.ScriptProfilerObserver.prototype.programmaticCaptureStopped):
     27        (WebInspector.ScriptProfilerObserver):
     28        * UserInterface/Protocol/TimelineObserver.js:
     29        (WebInspector.TimelineObserver.prototype.programmaticCaptureStarted):
     30        (WebInspector.TimelineObserver.prototype.programmaticCaptureStopped):
     31        (WebInspector.TimelineObserver):
     32        Pass through Web and JSContext programmatic capture events.
     33
    1342016-06-16  Joseph Pecoraro  <pecoraro@apple.com>
    235
  • trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js

    r202072 r202152  
    263263    }
    264264
    265     autoCaptureStarted(startTime)
     265    autoCaptureStarted()
    266266    {
    267267        // Called from WebInspector.TimelineObserver.
     
    273273        // between sending the Timeline.start command and receiving Timeline.capturingStarted event.
    274274        // In that case, there is no need to call startCapturing again. Reuse the fresh recording.
    275         if (!this._waitingForCapturingStartedEvent)
    276             this.startCapturing(true);
     275        if (!this._waitingForCapturingStartedEvent) {
     276            const createNewRecording = true;
     277            this.startCapturing(createNewRecording);
     278        }
    277279
    278280        this._shouldSetAutoCapturingMainResource = true;
     281    }
     282
     283    programmaticCaptureStarted()
     284    {
     285        // Called from WebInspector.TimelineObserver.
     286
     287        this._activeRecording.addScriptInstrumentForProgrammaticCapture();
     288
     289        const createNewRecording = false;
     290        this.startCapturing(createNewRecording);
     291    }
     292
     293    programmaticCaptureStopped()
     294    {
     295        // Called from WebInspector.TimelineObserver.
     296
     297        // FIXME: This is purely to avoid a noisy assert. Previously
     298        // it was impossible to stop without stopping from the UI.
     299        console.assert(!this._isCapturing);
     300        this._isCapturing = true;
     301
     302        this.stopCapturing();
    279303    }
    280304
     
    486510        case TimelineAgent.EventType.ConsoleProfile:
    487511            var profileData = recordPayload.data.profile;
    488             console.assert(profileData);
     512            // COMPATIBILITY (iOS 9): With the Sampling Profiler, profiles no longer include legacy profile data.
     513            console.assert(profileData || TimelineAgent.setInstruments);
    489514            return new WebInspector.ScriptTimelineRecord(WebInspector.ScriptTimelineRecord.EventType.ConsoleProfileRecorded, startTime, endTime, callFrames, sourceCodeLocation, recordPayload.data.title, profileData);
    490515
     
    833858            return WebInspector.ScriptTimelineRecord.EventType.ScriptEvaluated;
    834859        }
     860    }
     861
     862    scriptProfilerProgrammaticCaptureStarted()
     863    {
     864        // FIXME: <https://webkit.org/b/158753> Generalize the concept of Instruments on the backend to work equally for JSContext and Web inspection
     865        console.assert(WebInspector.debuggableType === WebInspector.DebuggableType.JavaScript);
     866        console.assert(!this._isCapturing);
     867
     868        this.programmaticCaptureStarted();
     869    }
     870
     871    scriptProfilerProgrammaticCaptureStopped()
     872    {
     873        // FIXME: <https://webkit.org/b/158753> Generalize the concept of Instruments on the backend to work equally for JSContext and Web inspection
     874        console.assert(WebInspector.debuggableType === WebInspector.DebuggableType.JavaScript);
     875        console.assert(this._isCapturing);
     876
     877        this.programmaticCaptureStopped();
    835878    }
    836879
  • trunk/Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js

    r195376 r202152  
    5757        ScriptProfilerAgent.stopTracking();
    5858    }
    59 
    6059};
  • trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js

    r202010 r202152  
    128128    }
    129129
    130     stop()
     130    stop(programmatic)
    131131    {
    132132        console.assert(this._capturing, "Attempted to stop an already stopped session.");
     
    135135        this._capturing = false;
    136136
    137         for (let instrument of this._instruments)
    138             instrument.stopInstrumentation();
     137        if (!programmatic) {
     138            for (let instrument of this._instruments)
     139                instrument.stopInstrumentation();
     140        }
    139141    }
    140142
     
    306308    {
    307309        return this._discontinuities.filter((item) => item.startTime < endTime && item.endTime > startTime);
     310    }
     311
     312    addScriptInstrumentForProgrammaticCapture()
     313    {
     314        for (let instrument of this._instruments) {
     315            if (instrument instanceof WebInspector.ScriptInstrument)
     316                return;
     317        }
     318
     319        this.addInstrument(new WebInspector.ScriptInstrument);
     320
     321        let instrumentTypes = this._instruments.map((instrument) => instrument.timelineRecordType);
     322        WebInspector.timelineManager.enabledTimelineTypes = instrumentTypes;
    308323    }
    309324
  • trunk/Source/WebInspectorUI/UserInterface/Protocol/ScriptProfilerObserver.js

    r195376 r202152  
    4242        WebInspector.timelineManager.scriptProfilerTrackingCompleted(samples);
    4343    }
     44   
     45    programmaticCaptureStarted()
     46    {
     47        WebInspector.timelineManager.scriptProfilerProgrammaticCaptureStarted();
     48    }
     49
     50    programmaticCaptureStopped()
     51    {
     52        WebInspector.timelineManager.scriptProfilerProgrammaticCaptureStopped();
     53    }
    4454};
  • trunk/Source/WebInspectorUI/UserInterface/Protocol/TimelineObserver.js

    r200651 r202152  
    4747        WebInspector.timelineManager.autoCaptureStarted();
    4848    }
     49
     50    programmaticCaptureStarted()
     51    {
     52        WebInspector.timelineManager.programmaticCaptureStarted();
     53    }
     54
     55    programmaticCaptureStopped()
     56    {
     57        WebInspector.timelineManager.programmaticCaptureStopped();
     58    }
    4959};
Note: See TracChangeset for help on using the changeset viewer.