Web Inspector: Add JSContext Script Profiling
https://bugs.webkit.org/show_bug.cgi?id=151899
Reviewed by Brian Burg.
Source/JavaScriptCore:
Extend JSC::Debugger to include a profiling client interface
that the Inspector can implement to be told about script execution
entry and exit points. Add new profiledCall/Evaluate/Construct
methods that are entry points that will notify the profiling
client if it exists.
By putting the profiling client on Debugger it avoids having
special code paths for a JSGlobalObject being JSContext inspected
or a JSGlobalObject in a Page being Web inspected. In either case
the JSGlobalObject can go through its debugger() which always
reaches the correct inspector instance.
- CMakeLists.txt:
- DerivedSources.make:
- JavaScriptCore.xcodeproj/project.pbxproj:
Handle new files.
(JSC::profiledCall):
- runtime/CallData.h:
- runtime/Completion.cpp:
(JSC::profiledEvaluate):
(JSC::profiledEvaluate):
- runtime/ConstructData.cpp:
(JSC::profiledConstruct):
(JSC::profiledConstruct):
Create profiled versions of interpreter entry points. If a profiler client is
available, this will automatically inform it of entry/exit. Include a reason
why this is being profiled. Currently all reasons in JavaScriptCore are enumerated
(API, Microtask) and Other is to be used by WebCore or future clients.
- debugger/ScriptProfilingScope.h: Added.
(JSC::ScriptProfilingScope::ScriptProfilingScope):
(JSC::ScriptProfilingScope::~ScriptProfilingScope):
(JSC::ScriptProfilingScope::shouldStartProfile):
(JSC::ScriptProfilingScope::shouldEndProfile):
At profiled entry points inform the profiling client if needed.
(JSEvaluateScript):
(JSObjectCallAsFunction):
(JSObjectCallAsConstructor):
(JSC::JSJobMicrotask::run):
Use the profiled functions for API and Microtask execution entry points.
- runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::hasProfiler):
- runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::hasProfiler):
Extend hasProfiler to also check the new Debugger script profiler.
(JSC::Debugger::setProfilingClient):
(JSC::Debugger::willEvaluateScript):
(JSC::Debugger::didEvaluateScript):
Pass through to the profiling client.
- inspector/protocol/ScriptProfiler.json: Added.
- inspector/agents/InspectorScriptProfilerAgent.cpp: Added.
(Inspector::InspectorScriptProfilerAgent::InspectorScriptProfilerAgent):
(Inspector::InspectorScriptProfilerAgent::~InspectorScriptProfilerAgent):
(Inspector::InspectorScriptProfilerAgent::didCreateFrontendAndBackend):
(Inspector::InspectorScriptProfilerAgent::willDestroyFrontendAndBackend):
(Inspector::InspectorScriptProfilerAgent::startTracking):
(Inspector::InspectorScriptProfilerAgent::stopTracking):
(Inspector::InspectorScriptProfilerAgent::isAlreadyProfiling):
(Inspector::InspectorScriptProfilerAgent::willEvaluateScript):
(Inspector::InspectorScriptProfilerAgent::didEvaluateScript):
(Inspector::toProtocol):
(Inspector::InspectorScriptProfilerAgent::addEvent):
(Inspector::buildAggregateCallInfoInspectorObject):
(Inspector::buildInspectorObject):
(Inspector::buildProfileInspectorObject):
(Inspector::InspectorScriptProfilerAgent::trackingComplete):
- inspector/agents/InspectorScriptProfilerAgent.h: Added.
New ScriptProfiler domain to just turn on / off script profiling.
It introduces a start/update/complete event model which we want
to include in new domains.
- inspector/InspectorEnvironment.h:
- inspector/InjectedScriptBase.cpp:
(Inspector::InjectedScriptBase::callFunctionWithEvalEnabled):
Simplify this now that we want it to be the same for all clients.
- inspector/JSGlobalObjectInspectorController.h:
- inspector/JSGlobalObjectInspectorController.cpp:
(Inspector::JSGlobalObjectInspectorController::JSGlobalObjectInspectorController):
Create the new agent.
- inspector/InspectorProtocolTypes.h:
(Inspector::Protocol::Array::addItem):
Allow pushing a double onto a Protocol::Array.
Source/WebCore:
Tests: inspector/script-profiler/event-type-API.html
inspector/script-profiler/event-type-Microtask.html
inspector/script-profiler/tracking.html
- ForwardingHeaders/inspector/agents/InspectorScriptProfilerAgent.h: Added.
- inspector/InspectorController.h:
- inspector/InspectorController.cpp:
(WebCore::InspectorController::InspectorController):
Create the new agent, even if we don't use it yet for Page inspection.
(WebCore::InspectorController::willCallInjectedScriptFunction): Deleted.
(WebCore::InspectorController::didCallInjectedScriptFunction): Deleted.
No longer needed, implementation was pushed up into InjectedScriptBase.
- inspector/InspectorCSSAgent.cpp:
(WebCore::InspectorCSSAgent::buildArrayForMatchedRuleList):
- inspector/InspectorReplayAgent.cpp:
(WebCore::buildInspectorObjectForSession):
Disambiguate types.
Source/WebInspectorUI:
Enable the Timeline tab for JSContext inspection. Currently only
JSContext inspection will use the ScriptProfiler domain, it will
be enabled for Page inspection in a follow-up.
First pass at the UI creates basic ScriptTimelineRecords for
ScriptProfiler events. At the end of recording, when profiles
are downloaded, it attaches profiles to the timeline records
and refreshes the Scripts timeline.
- UserInterface/Base/Main.js:
(WebInspector.loaded):
- UserInterface/Controllers/TimelineManager.js:
(WebInspector.TimelineManager):
(WebInspector.TimelineManager.defaultInstruments):
(WebInspector.TimelineManager.prototype.computeElapsedTime):
(WebInspector.TimelineManager.prototype.scriptProfilerIsTracking):
(WebInspector.TimelineManager.prototype._loadNewRecording):
(WebInspector.TimelineManager.prototype._mainResourceDidChange):
(WebInspector.TimelineManager.prototype._resourceWasAdded):
(WebInspector.TimelineManager.prototype._garbageCollected):
(WebInspector.TimelineManager.prototype._addRecord): Deleted.
- UserInterface/Main.html:
- UserInterface/Models/Instrument.js:
(WebInspector.Instrument.startLegacyTimelineAgent):
- UserInterface/Models/ScriptInstrument.js:
(WebInspector.ScriptInstrument.prototype.startInstrumentation):
(WebInspector.ScriptInstrument.prototype.stopInstrumentation):
(WebInspector.ScriptInstrument):
- UserInterface/Models/ScriptTimelineRecord.js:
(WebInspector.ScriptTimelineRecord.prototype.get profilePayload):
(WebInspector.ScriptTimelineRecord.prototype._initializeProfileFromPayload):
(WebInspector.ScriptTimelineRecord):
(WebInspector.ScriptTimelineRecord.EventType.displayName):
- UserInterface/Models/Timeline.js:
(WebInspector.Timeline.prototype.refresh):
- UserInterface/Models/TimelineRecording.js:
(WebInspector.TimelineRecording.sourceCodeTimelinesSupported):
(WebInspector.TimelineRecording.prototype.timelineForRecordType):
(WebInspector.TimelineRecording.prototype.addRecord):
- UserInterface/Protocol/ScriptProfilerObserver.js: Copied from Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js.
(WebInspector.ScriptProfilerObserver.prototype.trackingStart):
(WebInspector.ScriptProfilerObserver.prototype.trackingUpdate):
(WebInspector.ScriptProfilerObserver.prototype.trackingComplete):
(WebInspector.ScriptProfilerObserver):
- UserInterface/Views/ScriptTimelineView.js:
(WebInspector.ScriptTimelineView):
(WebInspector.ScriptTimelineView.prototype._processPendingRecords):
(WebInspector.ScriptTimelineView.prototype._scriptTimelineRecordRefreshed):
- UserInterface/Views/TimelineRecordTreeElement.js:
(WebInspector.TimelineRecordTreeElement):
- UserInterface/Views/TimelineTabContentView.js:
(WebInspector.TimelineTabContentView.isTabAllowed):
LayoutTests:
- inspector/script-profiler/event-type-API-expected.txt: Added.
- inspector/script-profiler/event-type-API.html: Added.
- inspector/script-profiler/event-type-Microtask-expected.txt: Added.
- inspector/script-profiler/event-type-Microtask.html: Added.
- inspector/script-profiler/tracking-expected.txt: Added.
- inspector/script-profiler/tracking.html: Added.
Tests for the new ScriptProfiler domain.