WebKit Bugzilla
Attachment 360044 Details for
Bug 193730
: Web Inspector: CPU Usage Timeline
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
[PATCH] For Landing
for-landing-10.patch (text/plain), 119.81 KB, created by
Joseph Pecoraro
on 2019-01-24 16:09:56 PST
(
hide
)
Description:
[PATCH] For Landing
Filename:
MIME Type:
Creator:
Joseph Pecoraro
Created:
2019-01-24 16:09:56 PST
Size:
119.81 KB
patch
obsolete
>diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 0181576f8c1..41e0fa2057c 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,26 @@ >+2019-01-24 Joseph Pecoraro <pecoraro@apple.com> >+ >+ Web Inspector: CPU Usage Timeline >+ https://bugs.webkit.org/show_bug.cgi?id=193730 >+ <rdar://problem/46797201> >+ >+ Reviewed by Devin Rousso. >+ >+ * inspector/cpu-profiler/tracking-expected.txt: Added. >+ * inspector/cpu-profiler/tracking.html: Added. >+ Test the CPUProfiler domain emits events. >+ >+ * inspector/heap/tracking-expected.txt: >+ * inspector/heap/tracking.html: >+ * inspector/memory/tracking-expected.txt: >+ * inspector/memory/tracking.html: >+ * inspector/script-profiler/tracking-expected.txt: >+ * inspector/script-profiler/tracking.html: >+ Update test naming. >+ >+ * platform/win/TestExpectations: >+ Skip on platforms without RESOURCE_USAGE. >+ > 2019-01-23 Eric Liang <ericliang@apple.com> > > AX: [GTK] Layout test accessibility/set-selected-editable.html is failing >diff --git a/LayoutTests/inspector/cpu-profiler/tracking-expected.txt b/LayoutTests/inspector/cpu-profiler/tracking-expected.txt >new file mode 100644 >index 00000000000..5b9cfc08ace >--- /dev/null >+++ b/LayoutTests/inspector/cpu-profiler/tracking-expected.txt >@@ -0,0 +1,14 @@ >+Tests that CPUProfiler.startTracking and CPUProfiler.stopTracking trigger trackingStart, trackingUpdate, and trackingComplete events with expected data. >+ >+ >+== Running test suite: CPUProfiler.Tracking >+-- Running test case: CPUProfiler.Tracking.StartAndStopTrackingWithEvent >+CPUProfiler.trackingStart >+PASS: Should have a timestamp when starting. >+CPUProfiler.trackingUpdate >+PASS: Should have an event object. >+PASS: Event should have a timestamp. >+PASS: Event should have a usage. >+PASS: usage should be greater than or equal to zero. >+CPUProfiler.trackingComplete >+ >diff --git a/LayoutTests/inspector/cpu-profiler/tracking.html b/LayoutTests/inspector/cpu-profiler/tracking.html >new file mode 100644 >index 00000000000..4500faf4e03 >--- /dev/null >+++ b/LayoutTests/inspector/cpu-profiler/tracking.html >@@ -0,0 +1,44 @@ >+<!DOCTYPE html> >+<html> >+<head> >+<script src="../../http/tests/inspector/resources/protocol-test.js"></script> >+<script> >+function test() >+{ >+ let suite = ProtocolTest.createAsyncSuite("CPUProfiler.Tracking"); >+ >+ suite.addTestCase({ >+ name: "CPUProfiler.Tracking.StartAndStopTrackingWithEvent", >+ test(resolve, reject) { >+ InspectorProtocol.awaitEvent({event: "CPUProfiler.trackingStart"}).then((messageObject) => { >+ ProtocolTest.log("CPUProfiler.trackingStart"); >+ ProtocolTest.expectThat(typeof messageObject.params.timestamp === "number", "Should have a timestamp when starting."); >+ }); >+ >+ InspectorProtocol.awaitEvent({event: "CPUProfiler.trackingUpdate"}).then((messageObject) => { >+ ProtocolTest.log("CPUProfiler.trackingUpdate"); >+ ProtocolTest.expectThat(typeof messageObject.params.event === "object", "Should have an event object."); >+ ProtocolTest.expectThat(typeof messageObject.params.event.timestamp === "number", "Event should have a timestamp."); >+ ProtocolTest.expectThat(typeof messageObject.params.event.usage === "number", "Event should have a usage."); >+ ProtocolTest.expectThat(messageObject.params.event.usage >= 0, "usage should be greater than or equal to zero."); >+ >+ InspectorProtocol.sendCommand("CPUProfiler.stopTracking", {}); >+ }); >+ >+ InspectorProtocol.awaitEvent({event: "CPUProfiler.trackingComplete"}).then((messageObject) => { >+ ProtocolTest.log("CPUProfiler.trackingComplete"); >+ resolve(); >+ }); >+ >+ InspectorProtocol.sendCommand("CPUProfiler.startTracking", {}); >+ } >+ }); >+ >+ suite.runTestCasesAndFinish(); >+} >+</script> >+</head> >+<body onload="runTest()"> >+<p>Tests that CPUProfiler.startTracking and CPUProfiler.stopTracking trigger trackingStart, trackingUpdate, and trackingComplete events with expected data.</p> >+</body> >+</html> >diff --git a/LayoutTests/inspector/heap/tracking-expected.txt b/LayoutTests/inspector/heap/tracking-expected.txt >index 27d049f817c..847900e039d 100644 >--- a/LayoutTests/inspector/heap/tracking-expected.txt >+++ b/LayoutTests/inspector/heap/tracking-expected.txt >@@ -1,8 +1,8 @@ > Tests that Heap.startTracking and Heap.stopTracking trigger trackingStart and trackingComplete events with expected data. > > >-== Running test suite: Heap.startTracking and Heap.stopTracking >--- Running test case: StartAndStopTrackingIncludeSnapshots >+== Running test suite: Heap.Tracking >+-- Running test case: Heap.Tracking.StartAndStopTrackingIncludeSnapshots > Heap.trackingStart > PASS: Should have a timestamp when starting. > PASS: Should have snapshotData when starting. >diff --git a/LayoutTests/inspector/heap/tracking.html b/LayoutTests/inspector/heap/tracking.html >index 2bb83d001b4..a5699c6174f 100644 >--- a/LayoutTests/inspector/heap/tracking.html >+++ b/LayoutTests/inspector/heap/tracking.html >@@ -5,10 +5,10 @@ > <script> > function test() > { >- let suite = ProtocolTest.createAsyncSuite("Heap.startTracking and Heap.stopTracking"); >+ let suite = ProtocolTest.createAsyncSuite("Heap.Tracking"); > > suite.addTestCase({ >- name: "StartAndStopTrackingIncludeSnapshots", >+ name: "Heap.Tracking.StartAndStopTrackingIncludeSnapshots", > test(resolve, reject) { > InspectorProtocol.awaitEvent({event: "Heap.trackingStart"}).then((messageObject) => { > ProtocolTest.log("Heap.trackingStart"); >diff --git a/LayoutTests/inspector/memory/tracking-expected.txt b/LayoutTests/inspector/memory/tracking-expected.txt >index 7687ae562fd..8cc3aafd403 100644 >--- a/LayoutTests/inspector/memory/tracking-expected.txt >+++ b/LayoutTests/inspector/memory/tracking-expected.txt >@@ -1,8 +1,8 @@ > Tests that Memory.startTracking and Memory.stopTracking trigger trackingStart, trackingUpdate, and trackingComplete events with expected data. > > >-== Running test suite: Memory.startTracking and Memory.stopTracking >--- Running test case: StartAndStopTrackingWithEvent >+== Running test suite: Memory.Tracking >+-- Running test case: Memory.Tracking.StartAndStopTrackingWithEvent > Memory.trackingStart > PASS: Should have a timestamp when starting. > Memory.trackingUpdate >diff --git a/LayoutTests/inspector/memory/tracking.html b/LayoutTests/inspector/memory/tracking.html >index bee202aba1d..11d7e7a866b 100644 >--- a/LayoutTests/inspector/memory/tracking.html >+++ b/LayoutTests/inspector/memory/tracking.html >@@ -5,10 +5,10 @@ > <script> > function test() > { >- let suite = ProtocolTest.createAsyncSuite("Memory.startTracking and Memory.stopTracking"); >+ let suite = ProtocolTest.createAsyncSuite("Memory.Tracking"); > > suite.addTestCase({ >- name: "StartAndStopTrackingWithEvent", >+ name: "Memory.Tracking.StartAndStopTrackingWithEvent", > test(resolve, reject) { > InspectorProtocol.awaitEvent({event: "Memory.trackingStart"}).then((messageObject) => { > ProtocolTest.log("Memory.trackingStart"); >diff --git a/LayoutTests/inspector/script-profiler/tracking-expected.txt b/LayoutTests/inspector/script-profiler/tracking-expected.txt >index 3634ea8efc3..ae0a6e4a2ad 100644 >--- a/LayoutTests/inspector/script-profiler/tracking-expected.txt >+++ b/LayoutTests/inspector/script-profiler/tracking-expected.txt >@@ -1,8 +1,8 @@ > Tests that ScriptProfiler.startTracking and ScriptProfiler.stopTracking trigger trackingStart and trackingComplete events. > > >-== Running test suite: ScriptProfiler.startTracking and ScriptProfiler.stopTracking >--- Running test case: StartAndStopTracking >+== Running test suite: ScriptProfiler.Tracking >+-- Running test case: ScriptProfiler.Tracking.StartAndStopTracking > ScriptProfiler.trackingStart > PASS: Should have a timestamp when starting. > ScriptProfiler.trackingComplete >diff --git a/LayoutTests/inspector/script-profiler/tracking.html b/LayoutTests/inspector/script-profiler/tracking.html >index dfa097f9330..c23af040398 100644 >--- a/LayoutTests/inspector/script-profiler/tracking.html >+++ b/LayoutTests/inspector/script-profiler/tracking.html >@@ -5,10 +5,10 @@ > <script> > function test() > { >- let suite = ProtocolTest.createAsyncSuite("ScriptProfiler.startTracking and ScriptProfiler.stopTracking"); >+ let suite = ProtocolTest.createAsyncSuite("ScriptProfiler.Tracking"); > > suite.addTestCase({ >- name: "StartAndStopTracking", >+ name: "ScriptProfiler.Tracking.StartAndStopTracking", > description: "Start and stop the ScriptProfiler should cause trackingStart and trackingComplete events.", > test(resolve, reject) { > InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingStart"}).then((messageObject) => { >diff --git a/LayoutTests/platform/win/TestExpectations b/LayoutTests/platform/win/TestExpectations >index 080fbeaf3f3..9e2d83f942c 100644 >--- a/LayoutTests/platform/win/TestExpectations >+++ b/LayoutTests/platform/win/TestExpectations >@@ -2397,6 +2397,7 @@ webkit.org/b/137157 http/tests/inspector [ Skip ] > > # Requires ENABLE(RESOURCE_USAGE). > inspector/memory [ Skip ] >+inspector/cpu-profiler [ Skip ] > > # webkit.org/b/143548 inspector/console [ Skip ] > # webkit.org/b/137157 inspector/css [ Skip ] >diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt >index 878efe7503a..de0530059d9 100644 >--- a/Source/JavaScriptCore/CMakeLists.txt >+++ b/Source/JavaScriptCore/CMakeLists.txt >@@ -1096,6 +1096,7 @@ endif () > > if (ENABLE_RESOURCE_USAGE) > list(APPEND JavaScriptCore_INSPECTOR_DOMAINS >+ ${JAVASCRIPTCORE_DIR}/inspector/protocol/CPUProfiler.json > ${JAVASCRIPTCORE_DIR}/inspector/protocol/Memory.json > ) > endif () >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index a514c8fddd3..bc8e855a5c8 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,22 @@ >+2019-01-24 Joseph Pecoraro <pecoraro@apple.com> >+ >+ Web Inspector: CPU Usage Timeline >+ https://bugs.webkit.org/show_bug.cgi?id=193730 >+ <rdar://problem/46797201> >+ >+ Reviewed by Devin Rousso. >+ >+ * CMakeLists.txt: >+ * DerivedSources-input.xcfilelist: >+ * DerivedSources.make: >+ New files. >+ >+ * inspector/protocol/CPUProfiler.json: Added. >+ New domain that follows the pattern of Memory/ScriptProfiler. >+ >+ * inspector/protocol/Timeline.json: >+ New enum to auto-start a CPU instrument in the backend. >+ > 2019-01-23 David Kilzer <ddkilzer@apple.com> > > [JSC] Duplicate global variables: JSC::opcodeLengths >diff --git a/Source/JavaScriptCore/DerivedSources-input.xcfilelist b/Source/JavaScriptCore/DerivedSources-input.xcfilelist >index 20e86fdf508..b5f47a631f7 100644 >--- a/Source/JavaScriptCore/DerivedSources-input.xcfilelist >+++ b/Source/JavaScriptCore/DerivedSources-input.xcfilelist >@@ -77,6 +77,7 @@ $(PROJECT_DIR)/generator/main.rb > $(PROJECT_DIR)/inspector/InjectedScriptSource.js > $(PROJECT_DIR)/inspector/protocol/ApplicationCache.json > $(PROJECT_DIR)/inspector/protocol/Audit.json >+$(PROJECT_DIR)/inspector/protocol/CPUProfiler.json > $(PROJECT_DIR)/inspector/protocol/CSS.json > $(PROJECT_DIR)/inspector/protocol/Canvas.json > $(PROJECT_DIR)/inspector/protocol/Console.json >diff --git a/Source/JavaScriptCore/DerivedSources.make b/Source/JavaScriptCore/DerivedSources.make >index 011a2201493..d9e2c8bc553 100644 >--- a/Source/JavaScriptCore/DerivedSources.make >+++ b/Source/JavaScriptCore/DerivedSources.make >@@ -258,6 +258,7 @@ ifeq ($(findstring ENABLE_INDEXED_DATABASE,$(FEATURE_DEFINES)), ENABLE_INDEXED_D > endif > > ifeq ($(findstring ENABLE_RESOURCE_USAGE,$(FEATURE_DEFINES)), ENABLE_RESOURCE_USAGE) >+ INSPECTOR_DOMAINS := $(INSPECTOR_DOMAINS) $(JavaScriptCore)/inspector/protocol/CPUProfiler.json > INSPECTOR_DOMAINS := $(INSPECTOR_DOMAINS) $(JavaScriptCore)/inspector/protocol/Memory.json > endif > >diff --git a/Source/JavaScriptCore/inspector/protocol/CPUProfiler.json b/Source/JavaScriptCore/inspector/protocol/CPUProfiler.json >new file mode 100644 >index 00000000000..2db2b501610 >--- /dev/null >+++ b/Source/JavaScriptCore/inspector/protocol/CPUProfiler.json >@@ -0,0 +1,46 @@ >+{ >+ "domain": "CPUProfiler", >+ "description": "CPUProfiler domain exposes cpu usage tracking.", >+ "featureGuard": "ENABLE(RESOURCE_USAGE)", >+ "availability": ["web"], >+ "types": [ >+ { >+ "id": "Event", >+ "type": "object", >+ "properties": [ >+ { "name": "timestamp", "type": "number" }, >+ { "name": "usage", "type": "number", "description": "Percent of total cpu usage. If there are multiple cores the usage may be greater than 100%." } >+ ] >+ } >+ ], >+ "commands": [ >+ { >+ "name": "startTracking", >+ "description": "Start tracking cpu usage." >+ }, >+ { >+ "name": "stopTracking", >+ "description": "Stop tracking cpu usage. This will produce a `trackingComplete` event." >+ } >+ ], >+ "events": [ >+ { >+ "name": "trackingStart", >+ "description": "Tracking started.", >+ "parameters": [ >+ { "name": "timestamp", "type": "number" } >+ ] >+ }, >+ { >+ "name": "trackingUpdate", >+ "description": "Periodic tracking updates with event data.", >+ "parameters": [ >+ { "name": "event", "$ref": "Event" } >+ ] >+ }, >+ { >+ "name": "trackingComplete", >+ "description": "Tracking stopped. Includes any buffered data during tracking, such as profiling information." >+ } >+ ] >+} >diff --git a/Source/JavaScriptCore/inspector/protocol/Timeline.json b/Source/JavaScriptCore/inspector/protocol/Timeline.json >index 6b55c299ed9..b9c4f846110 100644 >--- a/Source/JavaScriptCore/inspector/protocol/Timeline.json >+++ b/Source/JavaScriptCore/inspector/protocol/Timeline.json >@@ -39,6 +39,7 @@ > "enum": [ > "ScriptProfiler", > "Timeline", >+ "CPU", > "Memory", > "Heap" > ] >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index c06d2b5f6df..4d3b801236a 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,73 @@ >+2019-01-24 Joseph Pecoraro <pecoraro@apple.com> >+ >+ Web Inspector: CPU Usage Timeline >+ https://bugs.webkit.org/show_bug.cgi?id=193730 >+ <rdar://problem/46797201> >+ >+ Reviewed by Devin Rousso. >+ >+ Test: inspector/cpu-profiler/tracking.html >+ >+ * Sources.txt: >+ * UnifiedSources-input.xcfilelist: >+ * WebCore.xcodeproj/project.pbxproj: >+ New files. >+ >+ * inspector/InspectorController.cpp: >+ (WebCore::InspectorController::createLazyAgents): >+ * inspector/InstrumentingAgents.cpp: >+ (WebCore::InstrumentingAgents::reset): >+ * inspector/InstrumentingAgents.h: >+ (WebCore::InstrumentingAgents::inspectorCPUProfilerAgent const): >+ (WebCore::InstrumentingAgents::setInspectorCPUProfilerAgent): >+ Create and track the CPUProfilerAgent. >+ >+ * inspector/agents/InspectorTimelineAgent.cpp: >+ (WebCore::InspectorTimelineAgent::toggleInstruments): >+ (WebCore::InspectorTimelineAgent::toggleCPUInstrument): >+ Handle backend auto-start of the CPU instrument / timeline. >+ >+ * inspector/agents/InspectorCPUProfilerAgent.h: >+ * inspector/agents/InspectorCPUProfilerAgent.cpp: Added. >+ (WebCore::InspectorCPUProfilerAgent::InspectorCPUProfilerAgent): >+ (WebCore::InspectorCPUProfilerAgent::didCreateFrontendAndBackend): >+ (WebCore::InspectorCPUProfilerAgent::willDestroyFrontendAndBackend): >+ (WebCore::InspectorCPUProfilerAgent::startTracking): >+ (WebCore::InspectorCPUProfilerAgent::stopTracking): >+ (WebCore::InspectorCPUProfilerAgent::collectSample): >+ CPUProfilerAgent uses the ResourceUsageThread to get CPU data. >+ >+ * inspector/agents/InspectorTimelineAgent.h: >+ * inspector/agents/InspectorMemoryAgent.cpp: >+ (WebCore::InspectorMemoryAgent::startTracking): >+ (WebCore::InspectorMemoryAgent::collectSample): >+ Update the MemoryAgent to collect only Memory data and use a more accurate sample timestamp. >+ >+ * page/ResourceUsageData.h: >+ * page/ResourceUsageThread.cpp: >+ (WebCore::ResourceUsageThread::addObserver): >+ (WebCore::ResourceUsageThread::removeObserver): >+ (WebCore::ResourceUsageThread::notifyObservers): >+ (WebCore::ResourceUsageThread::recomputeCollectionMode): >+ (WebCore::ResourceUsageThread::threadBody): >+ * page/ResourceUsageThread.h: >+ * page/cocoa/ResourceUsageOverlayCocoa.mm: >+ (WebCore::ResourceUsageOverlay::platformInitialize): >+ * page/cocoa/ResourceUsageThreadCocoa.mm: >+ (WebCore::ResourceUsageThread::platformCollectCPUData): >+ (WebCore::ResourceUsageThread::platformCollectMemoryData): >+ (WebCore::ResourceUsageThread::platformThreadBody): Deleted. >+ * page/linux/ResourceUsageOverlayLinux.cpp: >+ (WebCore::ResourceUsageOverlay::platformInitialize): >+ * page/linux/ResourceUsageThreadLinux.cpp: >+ (WebCore::ResourceUsageThread::platformCollectCPUData): >+ (WebCore::ResourceUsageThread::platformCollectMemoryData): >+ (WebCore::ResourceUsageThread::platformThreadBody): >+ Give each observer their own collection mode. The ResourceUsageThread >+ will then collect data that is the union of all of the active observers. >+ This allows collecting CPU and Memory data separately, reducing the cost >+ of each when gathered individually. >+ > 2019-01-23 David Kilzer <ddkilzer@apple.com> > > REGRESSION (r240292): Attempt to fix WinCairo build >diff --git a/Source/WebCore/Sources.txt b/Source/WebCore/Sources.txt >index d2adb0e5409..c073d3f39c7 100644 >--- a/Source/WebCore/Sources.txt >+++ b/Source/WebCore/Sources.txt >@@ -1286,6 +1286,7 @@ inspector/WorkerInspectorController.cpp > inspector/WorkerScriptDebugServer.cpp > > inspector/agents/InspectorApplicationCacheAgent.cpp >+inspector/agents/InspectorCPUProfilerAgent.cpp > inspector/agents/InspectorCSSAgent.cpp > inspector/agents/InspectorCanvasAgent.cpp > inspector/agents/InspectorDOMAgent.cpp >diff --git a/Source/WebCore/UnifiedSources-input.xcfilelist b/Source/WebCore/UnifiedSources-input.xcfilelist >index 476411cd5c0..9f248b7a786 100644 >--- a/Source/WebCore/UnifiedSources-input.xcfilelist >+++ b/Source/WebCore/UnifiedSources-input.xcfilelist >@@ -2201,6 +2201,7 @@ $(SRCROOT)/inspector/WebInjectedScriptManager.cpp > $(SRCROOT)/inspector/WorkerInspectorController.cpp > $(SRCROOT)/inspector/WorkerScriptDebugServer.cpp > $(SRCROOT)/inspector/agents/InspectorApplicationCacheAgent.cpp >+$(SRCROOT)/inspector/agents/InspectorCPUProfilerAgent.cpp > $(SRCROOT)/inspector/agents/InspectorCSSAgent.cpp > $(SRCROOT)/inspector/agents/InspectorCanvasAgent.cpp > $(SRCROOT)/inspector/agents/InspectorDOMAgent.cpp >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index dab4df504e2..ea90d5ad680 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -3116,6 +3116,7 @@ > A58C59D11E382EAE0047859C /* JSPerformanceMark.h in Headers */ = {isa = PBXBuildFile; fileRef = A58C59CD1E382EA90047859C /* JSPerformanceMark.h */; }; > A58C59D31E382EB20047859C /* JSPerformanceMeasure.h in Headers */ = {isa = PBXBuildFile; fileRef = A58C59CF1E382EA90047859C /* JSPerformanceMeasure.h */; }; > A593CF8B1840535200BFCE27 /* InspectorWebAgentBase.h in Headers */ = {isa = PBXBuildFile; fileRef = A593CF8A1840535200BFCE27 /* InspectorWebAgentBase.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ A59C230A21F29206004EC939 /* InspectorCPUProfilerAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = A59C230821F29206004EC939 /* InspectorCPUProfilerAgent.h */; }; > A5A2AF0C1829734300DE1729 /* PageDebuggable.h in Headers */ = {isa = PBXBuildFile; fileRef = A5A2AF0A1829734300DE1729 /* PageDebuggable.h */; }; > A5A7AA43132F0ECC00D3A3C2 /* AutocapitalizeTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = A5A7AA42132F0ECC00D3A3C2 /* AutocapitalizeTypes.h */; settings = {ATTRIBUTES = (Private, ); }; }; > A5A9933D1E37FB19005B5E4D /* PerformanceObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = A5A993361E37FAFD005B5E4D /* PerformanceObserver.h */; }; >@@ -11453,6 +11454,8 @@ > A58C59CE1E382EA90047859C /* JSPerformanceMeasure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPerformanceMeasure.cpp; sourceTree = "<group>"; }; > A58C59CF1E382EA90047859C /* JSPerformanceMeasure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPerformanceMeasure.h; sourceTree = "<group>"; }; > A593CF8A1840535200BFCE27 /* InspectorWebAgentBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorWebAgentBase.h; sourceTree = "<group>"; }; >+ A59C230621F29205004EC939 /* InspectorCPUProfilerAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorCPUProfilerAgent.cpp; sourceTree = "<group>"; }; >+ A59C230821F29206004EC939 /* InspectorCPUProfilerAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorCPUProfilerAgent.h; sourceTree = "<group>"; }; > A5A2AF091829734300DE1729 /* PageDebuggable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PageDebuggable.cpp; sourceTree = "<group>"; }; > A5A2AF0A1829734300DE1729 /* PageDebuggable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PageDebuggable.h; sourceTree = "<group>"; }; > A5A7AA42132F0ECC00D3A3C2 /* AutocapitalizeTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutocapitalizeTypes.h; sourceTree = "<group>"; }; >@@ -22475,6 +22478,8 @@ > A5B81C971FAA44260037D1E6 /* InspectorApplicationCacheAgent.h */, > A5B81C961FAA44260037D1E6 /* InspectorCanvasAgent.cpp */, > A5B81C911FAA44260037D1E6 /* InspectorCanvasAgent.h */, >+ A59C230621F29205004EC939 /* InspectorCPUProfilerAgent.cpp */, >+ A59C230821F29206004EC939 /* InspectorCPUProfilerAgent.h */, > A5B81C921FAA44260037D1E6 /* InspectorCSSAgent.cpp */, > A5B81CA11FAA44270037D1E6 /* InspectorCSSAgent.h */, > A5B81CA51FAA44270037D1E6 /* InspectorDatabaseAgent.cpp */, >@@ -29552,6 +29557,7 @@ > F55B3DC21251F12D003EF269 /* ImageInputType.h in Headers */, > 089582560E857A7E00F82C83 /* ImageLoader.h in Headers */, > BC7F44A80B9E324E00A9D081 /* ImageObserver.h in Headers */, >+ A59C230A21F29206004EC939 /* InspectorCPUProfilerAgent.h in Headers */, > 2D5A5931152525D00036EE51 /* ImageOrientation.h in Headers */, > B51A2F3F17D7D3AE0072517A /* ImageQualityController.h in Headers */, > 49291E4B134172C800E753DE /* ImageRenderingMode.h in Headers */, >diff --git a/Source/WebCore/inspector/InspectorController.cpp b/Source/WebCore/inspector/InspectorController.cpp >index 866210cdb13..be94652efd3 100644 >--- a/Source/WebCore/inspector/InspectorController.cpp >+++ b/Source/WebCore/inspector/InspectorController.cpp >@@ -39,6 +39,7 @@ > #include "Frame.h" > #include "GraphicsContext.h" > #include "InspectorApplicationCacheAgent.h" >+#include "InspectorCPUProfilerAgent.h" > #include "InspectorCSSAgent.h" > #include "InspectorCanvasAgent.h" > #include "InspectorClient.h" >@@ -205,6 +206,7 @@ void InspectorController::createLazyAgents() > m_agents.append(std::make_unique<InspectorIndexedDBAgent>(pageContext, m_pageAgent)); > #endif > #if ENABLE(RESOURCE_USAGE) >+ m_agents.append(std::make_unique<InspectorCPUProfilerAgent>(pageContext)); > m_agents.append(std::make_unique<InspectorMemoryAgent>(pageContext)); > #endif > m_agents.append(std::make_unique<PageAuditAgent>(pageContext)); >diff --git a/Source/WebCore/inspector/InstrumentingAgents.cpp b/Source/WebCore/inspector/InstrumentingAgents.cpp >index c5970a258eb..b5886c4f870 100644 >--- a/Source/WebCore/inspector/InstrumentingAgents.cpp >+++ b/Source/WebCore/inspector/InstrumentingAgents.cpp >@@ -57,6 +57,7 @@ void InstrumentingAgents::reset() > m_persistentInspectorTimelineAgent = nullptr; > m_inspectorDOMStorageAgent = nullptr; > #if ENABLE(RESOURCE_USAGE) >+ m_inspectorCPUProfilerAgent = nullptr; > m_inspectorMemoryAgent = nullptr; > #endif > m_inspectorDatabaseAgent = nullptr; >diff --git a/Source/WebCore/inspector/InstrumentingAgents.h b/Source/WebCore/inspector/InstrumentingAgents.h >index c58dd5e016e..5477732a5e5 100644 >--- a/Source/WebCore/inspector/InstrumentingAgents.h >+++ b/Source/WebCore/inspector/InstrumentingAgents.h >@@ -44,18 +44,19 @@ class InspectorDebuggerAgent; > namespace WebCore { > > class InspectorApplicationCacheAgent; >-class InspectorCanvasAgent; >+class InspectorCPUProfilerAgent; > class InspectorCSSAgent; >+class InspectorCanvasAgent; > class InspectorDOMAgent; > class InspectorDOMDebuggerAgent; > class InspectorDOMStorageAgent; > class InspectorDatabaseAgent; > class InspectorLayerTreeAgent; >-class InspectorWorkerAgent; > class InspectorMemoryAgent; > class InspectorNetworkAgent; > class InspectorPageAgent; > class InspectorTimelineAgent; >+class InspectorWorkerAgent; > class Page; > class PageDebuggerAgent; > class PageHeapAgent; >@@ -111,6 +112,9 @@ public: > void setInspectorDOMStorageAgent(InspectorDOMStorageAgent* agent) { m_inspectorDOMStorageAgent = agent; } > > #if ENABLE(RESOURCE_USAGE) >+ InspectorCPUProfilerAgent* inspectorCPUProfilerAgent() const { return m_inspectorCPUProfilerAgent; } >+ void setInspectorCPUProfilerAgent(InspectorCPUProfilerAgent* agent) { m_inspectorCPUProfilerAgent = agent; } >+ > InspectorMemoryAgent* inspectorMemoryAgent() const { return m_inspectorMemoryAgent; } > void setInspectorMemoryAgent(InspectorMemoryAgent* agent) { m_inspectorMemoryAgent = agent; } > #endif >@@ -157,6 +161,7 @@ private: > InspectorTimelineAgent* m_persistentInspectorTimelineAgent { nullptr }; > InspectorDOMStorageAgent* m_inspectorDOMStorageAgent { nullptr }; > #if ENABLE(RESOURCE_USAGE) >+ InspectorCPUProfilerAgent* m_inspectorCPUProfilerAgent { nullptr }; > InspectorMemoryAgent* m_inspectorMemoryAgent { nullptr }; > #endif > InspectorDatabaseAgent* m_inspectorDatabaseAgent { nullptr }; >diff --git a/Source/WebCore/inspector/agents/InspectorCPUProfilerAgent.cpp b/Source/WebCore/inspector/agents/InspectorCPUProfilerAgent.cpp >new file mode 100644 >index 00000000000..66248b982f2 >--- /dev/null >+++ b/Source/WebCore/inspector/agents/InspectorCPUProfilerAgent.cpp >@@ -0,0 +1,95 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "InspectorCPUProfilerAgent.h" >+ >+#if ENABLE(RESOURCE_USAGE) >+ >+#include "InstrumentingAgents.h" >+#include "ResourceUsageThread.h" >+#include <JavaScriptCore/InspectorEnvironment.h> >+#include <wtf/Stopwatch.h> >+ >+namespace WebCore { >+ >+using namespace Inspector; >+ >+InspectorCPUProfilerAgent::InspectorCPUProfilerAgent(PageAgentContext& context) >+ : InspectorAgentBase("CPUProfiler"_s, context) >+ , m_frontendDispatcher(std::make_unique<Inspector::CPUProfilerFrontendDispatcher>(context.frontendRouter)) >+ , m_backendDispatcher(Inspector::CPUProfilerBackendDispatcher::create(context.backendDispatcher, this)) >+{ >+} >+ >+void InspectorCPUProfilerAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*) >+{ >+ m_instrumentingAgents.setInspectorCPUProfilerAgent(this); >+} >+ >+void InspectorCPUProfilerAgent::willDestroyFrontendAndBackend(DisconnectReason) >+{ >+ m_instrumentingAgents.setInspectorCPUProfilerAgent(nullptr); >+} >+ >+void InspectorCPUProfilerAgent::startTracking(ErrorString&) >+{ >+ if (m_tracking) >+ return; >+ >+ ResourceUsageThread::addObserver(this, CPU, [this] (const ResourceUsageData& data) { >+ collectSample(data); >+ }); >+ >+ m_tracking = true; >+ >+ m_frontendDispatcher->trackingStart(m_environment.executionStopwatch()->elapsedTime().seconds()); >+} >+ >+void InspectorCPUProfilerAgent::stopTracking(ErrorString&) >+{ >+ if (!m_tracking) >+ return; >+ >+ ResourceUsageThread::removeObserver(this); >+ >+ m_tracking = false; >+ >+ m_frontendDispatcher->trackingComplete(); >+} >+ >+void InspectorCPUProfilerAgent::collectSample(const ResourceUsageData& data) >+{ >+ auto event = Protocol::CPUProfiler::Event::create() >+ .setTimestamp(m_environment.executionStopwatch()->elapsedTimeSince(data.timestamp).seconds()) >+ .setUsage(data.cpu) >+ .release(); >+ >+ m_frontendDispatcher->trackingUpdate(WTFMove(event)); >+} >+ >+} // namespace WebCore >+ >+#endif // ENABLE(RESOURCE_USAGE) >diff --git a/Source/WebCore/inspector/agents/InspectorCPUProfilerAgent.h b/Source/WebCore/inspector/agents/InspectorCPUProfilerAgent.h >new file mode 100644 >index 00000000000..a542abf15f9 >--- /dev/null >+++ b/Source/WebCore/inspector/agents/InspectorCPUProfilerAgent.h >@@ -0,0 +1,63 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#if ENABLE(RESOURCE_USAGE) >+ >+#include "InspectorWebAgentBase.h" >+#include "ResourceUsageData.h" >+#include <JavaScriptCore/InspectorBackendDispatchers.h> >+#include <JavaScriptCore/InspectorFrontendDispatchers.h> >+ >+namespace WebCore { >+ >+typedef String ErrorString; >+ >+class InspectorCPUProfilerAgent final : public InspectorAgentBase, public Inspector::CPUProfilerBackendDispatcherHandler { >+ WTF_MAKE_NONCOPYABLE(InspectorCPUProfilerAgent); >+ WTF_MAKE_FAST_ALLOCATED; >+public: >+ InspectorCPUProfilerAgent(PageAgentContext&); >+ virtual ~InspectorCPUProfilerAgent() = default; >+ >+ void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override; >+ void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; >+ >+ // CPUProfilerBackendDispatcherHandler >+ void startTracking(ErrorString&) override; >+ void stopTracking(ErrorString&) override; >+ >+private: >+ void collectSample(const ResourceUsageData&); >+ >+ std::unique_ptr<Inspector::CPUProfilerFrontendDispatcher> m_frontendDispatcher; >+ RefPtr<Inspector::CPUProfilerBackendDispatcher> m_backendDispatcher; >+ bool m_tracking { false }; >+}; >+ >+} // namespace WebCore >+ >+#endif // ENABLE(RESOURCE_USAGE) >diff --git a/Source/WebCore/inspector/agents/InspectorMemoryAgent.cpp b/Source/WebCore/inspector/agents/InspectorMemoryAgent.cpp >index 768a6da918b..5bc56eab689 100644 >--- a/Source/WebCore/inspector/agents/InspectorMemoryAgent.cpp >+++ b/Source/WebCore/inspector/agents/InspectorMemoryAgent.cpp >@@ -74,7 +74,7 @@ void InspectorMemoryAgent::startTracking(ErrorString&) > if (m_tracking) > return; > >- ResourceUsageThread::addObserver(this, [this] (const ResourceUsageData& data) { >+ ResourceUsageThread::addObserver(this, Memory, [this] (const ResourceUsageData& data) { > collectSample(data); > }); > >@@ -145,13 +145,13 @@ void InspectorMemoryAgent::collectSample(const ResourceUsageData& data) > categories->addItem(WTFMove(otherCategory)); > > auto event = Protocol::Memory::Event::create() >- .setTimestamp(m_environment.executionStopwatch()->elapsedTime().seconds()) >+ .setTimestamp(m_environment.executionStopwatch()->elapsedTimeSince(data.timestamp).seconds()) > .setCategories(WTFMove(categories)) > .release(); > > m_frontendDispatcher->trackingUpdate(WTFMove(event)); > } > >-} // namespace Inspector >+} // namespace WebCore > > #endif // ENABLE(RESOURCE_USAGE) >diff --git a/Source/WebCore/inspector/agents/InspectorTimelineAgent.cpp b/Source/WebCore/inspector/agents/InspectorTimelineAgent.cpp >index 2e270d46a82..0505bd3e6e8 100644 >--- a/Source/WebCore/inspector/agents/InspectorTimelineAgent.cpp >+++ b/Source/WebCore/inspector/agents/InspectorTimelineAgent.cpp >@@ -36,6 +36,7 @@ > #include "DOMWindow.h" > #include "Event.h" > #include "Frame.h" >+#include "InspectorCPUProfilerAgent.h" > #include "InspectorMemoryAgent.h" > #include "InspectorPageAgent.h" > #include "InstrumentingAgents.h" >@@ -514,6 +515,10 @@ void InspectorTimelineAgent::toggleInstruments(InstrumentState state) > toggleHeapInstrument(state); > break; > } >+ case Inspector::Protocol::Timeline::Instrument::CPU: { >+ toggleCPUInstrument(state); >+ break; >+ } > case Inspector::Protocol::Timeline::Instrument::Memory: { > toggleMemoryInstrument(state); > break; >@@ -549,6 +554,21 @@ void InspectorTimelineAgent::toggleHeapInstrument(InstrumentState state) > } > } > >+void InspectorTimelineAgent::toggleCPUInstrument(InstrumentState state) >+{ >+#if ENABLE(RESOURCE_USAGE) >+ if (InspectorCPUProfilerAgent* cpuProfilerAgent = m_instrumentingAgents.inspectorCPUProfilerAgent()) { >+ ErrorString unused; >+ if (state == InstrumentState::Start) >+ cpuProfilerAgent->startTracking(unused); >+ else >+ cpuProfilerAgent->stopTracking(unused); >+ } >+#else >+ UNUSED_PARAM(state); >+#endif >+} >+ > void InspectorTimelineAgent::toggleMemoryInstrument(InstrumentState state) > { > #if ENABLE(RESOURCE_USAGE) >diff --git a/Source/WebCore/inspector/agents/InspectorTimelineAgent.h b/Source/WebCore/inspector/agents/InspectorTimelineAgent.h >index 4033cdfe171..82847c6788b 100644 >--- a/Source/WebCore/inspector/agents/InspectorTimelineAgent.h >+++ b/Source/WebCore/inspector/agents/InspectorTimelineAgent.h >@@ -164,6 +164,7 @@ private: > void toggleInstruments(InstrumentState); > void toggleScriptProfilerInstrument(InstrumentState); > void toggleHeapInstrument(InstrumentState); >+ void toggleCPUInstrument(InstrumentState); > void toggleMemoryInstrument(InstrumentState); > void toggleTimelineInstrument(InstrumentState); > void disableBreakpoints(); >diff --git a/Source/WebCore/page/ResourceUsageData.h b/Source/WebCore/page/ResourceUsageData.h >index c620a218c82..ab977b5e443 100644 >--- a/Source/WebCore/page/ResourceUsageData.h >+++ b/Source/WebCore/page/ResourceUsageData.h >@@ -82,6 +82,7 @@ struct ResourceUsageData { > WEBCORE_EACH_MEMORY_CATEGORIES(WEBCORE_DEFINE_MEMORY_CATEGORY) > #undef WEBCORE_DEFINE_MEMORY_CATEGORY > } }; >+ MonotonicTime timestamp { MonotonicTime::now() }; > MonotonicTime timeOfNextEdenCollection { MonotonicTime::nan() }; > MonotonicTime timeOfNextFullCollection { MonotonicTime::nan() }; > }; >diff --git a/Source/WebCore/page/ResourceUsageThread.cpp b/Source/WebCore/page/ResourceUsageThread.cpp >index 28b7e6602cb..d9dd3e769ed 100644 >--- a/Source/WebCore/page/ResourceUsageThread.cpp >+++ b/Source/WebCore/page/ResourceUsageThread.cpp >@@ -46,7 +46,7 @@ ResourceUsageThread& ResourceUsageThread::singleton() > return resourceUsageThread; > } > >-void ResourceUsageThread::addObserver(void* key, std::function<void (const ResourceUsageData&)> function) >+void ResourceUsageThread::addObserver(void* key, ResourceUsageCollectionMode mode, std::function<void (const ResourceUsageData&)> function) > { > auto& resourceUsageThread = ResourceUsageThread::singleton(); > resourceUsageThread.createThreadIfNeeded(); >@@ -54,7 +54,9 @@ void ResourceUsageThread::addObserver(void* key, std::function<void (const Resou > { > LockHolder locker(resourceUsageThread.m_lock); > bool wasEmpty = resourceUsageThread.m_observers.isEmpty(); >- resourceUsageThread.m_observers.set(key, function); >+ resourceUsageThread.m_observers.set(key, std::make_pair(mode, function)); >+ >+ resourceUsageThread.recomputeCollectionMode(); > > if (wasEmpty) > resourceUsageThread.m_condition.notifyAll(); >@@ -68,6 +70,8 @@ void ResourceUsageThread::removeObserver(void* key) > { > LockHolder locker(resourceUsageThread.m_lock); > resourceUsageThread.m_observers.remove(key); >+ >+ resourceUsageThread.recomputeCollectionMode(); > } > } > >@@ -81,19 +85,27 @@ void ResourceUsageThread::waitUntilObservers() > void ResourceUsageThread::notifyObservers(ResourceUsageData&& data) > { > callOnMainThread([data = WTFMove(data)]() mutable { >- Vector<std::function<void (const ResourceUsageData&)>> functions; >- >+ Vector<std::pair<ResourceUsageCollectionMode, std::function<void (const ResourceUsageData&)>>> pairs; >+ > { > auto& resourceUsageThread = ResourceUsageThread::singleton(); > LockHolder locker(resourceUsageThread.m_lock); >- functions = copyToVector(resourceUsageThread.m_observers.values()); >+ pairs = copyToVector(resourceUsageThread.m_observers.values()); > } > >- for (auto& function : functions) >- function(data); >+ for (auto& pair : pairs) >+ pair.second(data); > }); > } > >+void ResourceUsageThread::recomputeCollectionMode() >+{ >+ m_collectionMode = None; >+ >+ for (auto& pair : m_observers.values()) >+ m_collectionMode = static_cast<ResourceUsageCollectionMode>(m_collectionMode | pair.first); >+} >+ > void ResourceUsageThread::createThreadIfNeeded() > { > if (m_thread) >@@ -114,9 +126,16 @@ NO_RETURN void ResourceUsageThread::threadBody() > auto start = WallTime::now(); > > ResourceUsageData data; >- platformThreadBody(m_vm, data); >+ ResourceUsageCollectionMode mode = m_collectionMode; >+ if (mode & CPU) >+ platformCollectCPUData(m_vm, data); >+ if (mode & Memory) >+ platformCollectMemoryData(m_vm, data); >+ > notifyObservers(WTFMove(data)); > >+ // NOTE: Web Inspector expects this interval to be 500ms (CPU / Memory timelines), >+ // so if this interval changes Web Inspector may need to change. > auto duration = WallTime::now() - start; > auto difference = 500_ms - duration; > WTF::sleep(difference); >diff --git a/Source/WebCore/page/ResourceUsageThread.h b/Source/WebCore/page/ResourceUsageThread.h >index 9416c76b6a0..7dfb4a7bc13 100644 >--- a/Source/WebCore/page/ResourceUsageThread.h >+++ b/Source/WebCore/page/ResourceUsageThread.h >@@ -43,11 +43,18 @@ class VM; > > namespace WebCore { > >+enum ResourceUsageCollectionMode { >+ None = 0, >+ CPU = 1 << 0, >+ Memory = 1 << 1, >+ All = CPU | Memory, >+}; >+ > class ResourceUsageThread { > WTF_MAKE_NONCOPYABLE(ResourceUsageThread); > > public: >- static void addObserver(void* key, std::function<void (const ResourceUsageData&)>); >+ static void addObserver(void* key, ResourceUsageCollectionMode, std::function<void (const ResourceUsageData&)>); > static void removeObserver(void* key); > > private: >@@ -58,14 +65,19 @@ private: > void waitUntilObservers(); > void notifyObservers(ResourceUsageData&&); > >+ void recomputeCollectionMode(); >+ > void createThreadIfNeeded(); > void threadBody(); >- void platformThreadBody(JSC::VM*, ResourceUsageData&); >+ >+ void platformCollectCPUData(JSC::VM*, ResourceUsageData&); >+ void platformCollectMemoryData(JSC::VM*, ResourceUsageData&); > > RefPtr<Thread> m_thread; > Lock m_lock; > Condition m_condition; >- HashMap<void*, std::function<void (const ResourceUsageData&)>> m_observers; >+ HashMap<void*, std::pair<ResourceUsageCollectionMode, std::function<void (const ResourceUsageData&)>>> m_observers; >+ ResourceUsageCollectionMode m_collectionMode { None }; > > // Platforms may need to access some data from the common VM. > // They should ensure their use of the VM is thread safe. >diff --git a/Source/WebCore/page/cocoa/ResourceUsageOverlayCocoa.mm b/Source/WebCore/page/cocoa/ResourceUsageOverlayCocoa.mm >index e03e06f51b6..4b5c6310963 100644 >--- a/Source/WebCore/page/cocoa/ResourceUsageOverlayCocoa.mm >+++ b/Source/WebCore/page/cocoa/ResourceUsageOverlayCocoa.mm >@@ -229,7 +229,7 @@ void ResourceUsageOverlay::platformInitialize() > > overlay().layer().setContentsToPlatformLayer(m_layer.get(), GraphicsLayer::ContentsLayerPurpose::None); > >- ResourceUsageThread::addObserver(this, [this] (const ResourceUsageData& data) { >+ ResourceUsageThread::addObserver(this, All, [this] (const ResourceUsageData& data) { > appendDataToHistory(data); > > // FIXME: It shouldn't be necessary to update the bounds on every single thread loop iteration, >diff --git a/Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm b/Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm >index 698fb8de64d..e644abef126 100644 >--- a/Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm >+++ b/Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm >@@ -205,10 +205,13 @@ static unsigned categoryForVMTag(unsigned tag) > } > } > >-void ResourceUsageThread::platformThreadBody(JSC::VM* vm, ResourceUsageData& data) >+void ResourceUsageThread::platformCollectCPUData(JSC::VM*, ResourceUsageData& data) > { > data.cpu = cpuUsage(); >+} > >+void ResourceUsageThread::platformCollectMemoryData(JSC::VM* vm, ResourceUsageData& data) >+{ > auto tags = pagesPerVMTag(); > std::array<TagInfo, MemoryCategory::NumberOfCategories> pagesPerCategory; > size_t totalDirtyPages = 0; >@@ -248,9 +251,8 @@ void ResourceUsageThread::platformThreadBody(JSC::VM* vm, ResourceUsageData& dat > > data.totalExternalSize = currentGCOwnedExternal; > >- auto now = MonotonicTime::now(); >- data.timeOfNextEdenCollection = now + vm->heap.edenActivityCallback()->timeUntilFire().valueOr(Seconds(std::numeric_limits<double>::infinity())); >- data.timeOfNextFullCollection = now + vm->heap.fullActivityCallback()->timeUntilFire().valueOr(Seconds(std::numeric_limits<double>::infinity())); >+ data.timeOfNextEdenCollection = data.timestamp + vm->heap.edenActivityCallback()->timeUntilFire().valueOr(Seconds(std::numeric_limits<double>::infinity())); >+ data.timeOfNextFullCollection = data.timestamp + vm->heap.fullActivityCallback()->timeUntilFire().valueOr(Seconds(std::numeric_limits<double>::infinity())); > } > > } >diff --git a/Source/WebCore/page/linux/ResourceUsageOverlayLinux.cpp b/Source/WebCore/page/linux/ResourceUsageOverlayLinux.cpp >index c3c87fd6641..e8a4bc070c0 100644 >--- a/Source/WebCore/page/linux/ResourceUsageOverlayLinux.cpp >+++ b/Source/WebCore/page/linux/ResourceUsageOverlayLinux.cpp >@@ -139,7 +139,7 @@ void ResourceUsageOverlay::platformInitialize() > m_paintLayer->setDrawsContent(true); > overlay().layer().addChild(*m_paintLayer); > >- ResourceUsageThread::addObserver(this, [this] (const ResourceUsageData& data) { >+ ResourceUsageThread::addObserver(this, All, [this] (const ResourceUsageData& data) { > gData = data; > m_paintLayer->setNeedsDisplay(); > }); >diff --git a/Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp b/Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp >index 1562a08c579..f76f15aa572 100644 >--- a/Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp >+++ b/Source/WebCore/page/linux/ResourceUsageThreadLinux.cpp >@@ -150,10 +150,13 @@ static float cpuUsage() > return clampTo<float>(usage, 0, 100); > } > >-void ResourceUsageThread::platformThreadBody(JSC::VM* vm, ResourceUsageData& data) >+void ResourceUsageThread::platformCollectCPUData(JSC::VM*, ResourceUsageData& data) > { > data.cpu = cpuUsage(); >+} > >+void ResourceUsageThread::platformCollectMemoryData(JSC::VM* vm, ResourceUsageData& data) >+{ > ProcessMemoryStatus memoryStatus; > currentProcessMemoryStatus(memoryStatus); > data.totalDirtySize = memoryStatus.resident - memoryStatus.shared; >@@ -169,9 +172,8 @@ void ResourceUsageThread::platformThreadBody(JSC::VM* vm, ResourceUsageData& dat > > data.totalExternalSize = currentGCOwnedExternal; > >- auto now = MonotonicTime::now(); >- data.timeOfNextEdenCollection = now + vm->heap.edenActivityCallback()->timeUntilFire().valueOr(Seconds(std::numeric_limits<double>::infinity())); >- data.timeOfNextFullCollection = now + vm->heap.fullActivityCallback()->timeUntilFire().valueOr(Seconds(std::numeric_limits<double>::infinity())); >+ data.timeOfNextEdenCollection = data.timestamp + vm->heap.edenActivityCallback()->timeUntilFire().valueOr(Seconds(std::numeric_limits<double>::infinity())); >+ data.timeOfNextFullCollection = data.timestamp + vm->heap.fullActivityCallback()->timeUntilFire().valueOr(Seconds(std::numeric_limits<double>::infinity())); > } > > } // namespace WebCore >diff --git a/Source/WebInspectorUI/ChangeLog b/Source/WebInspectorUI/ChangeLog >index 2c0371f0c1b..e8d3a048e70 100644 >--- a/Source/WebInspectorUI/ChangeLog >+++ b/Source/WebInspectorUI/ChangeLog >@@ -1,3 +1,165 @@ >+2019-01-24 Joseph Pecoraro <pecoraro@apple.com> >+ >+ Web Inspector: CPU Usage Timeline >+ https://bugs.webkit.org/show_bug.cgi?id=193730 >+ <rdar://problem/46797201> >+ >+ Reviewed by Devin Rousso. >+ >+ CPU Usage is gathered in the backend twice a second, the frequency of the >+ ResourceUsageThread in WebCore. The frontend displays cpu usage in a few >+ ways in the Timeline. >+ >+ We use a column chart in the timeline overview to display the frequency and >+ relative distance of samples. This helps show if the samples were close >+ together or far apart, which indicates how meaningful they will be at a >+ particular scale. >+ >+ We use a line chart in the timeline detail view which will be easier to see >+ the changes over a particular time range selection. >+ >+ * Localizations/en.lproj/localizedStrings.js: >+ New strings. >+ >+ * UserInterface/Main.html: >+ * UserInterface/Base/Main.js: >+ (WI.loaded): >+ * UserInterface/Test.html: >+ * UserInterface/Test/Test.js: >+ (WI.loaded): >+ * UserInterface/Protocol/CPUProfilerObserver.js: >+ (WI.CPUProfilerObserver.prototype.trackingStart): >+ (WI.CPUProfilerObserver.prototype.trackingUpdate): >+ (WI.CPUProfilerObserver.prototype.trackingComplete): >+ (WI.CPUProfilerObserver): >+ New files and default registration. >+ >+ * UserInterface/Protocol/Target.js: >+ (WI.Target.prototype.get CPUProfilerAgent): >+ New Agent. >+ >+ * UserInterface/Controllers/TimelineManager.js: >+ (WI.TimelineManager.availableTimelineTypes): >+ (WI.TimelineManager.prototype.cpuProfilerTrackingStarted): >+ (WI.TimelineManager.prototype.cpuProfilerTrackingUpdated): >+ (WI.TimelineManager.prototype.cpuProfilerTrackingCompleted): >+ (WI.TimelineManager.prototype._updateAutoCaptureInstruments): >+ (WI.TimelineManager.prototype.memoryTrackingStart): Renamed. >+ (WI.TimelineManager.prototype.memoryTrackingUpdate): Renamed. >+ (WI.TimelineManager.prototype.memoryTrackingComplete): Renamed. >+ * UserInterface/Models/CPUInstrument.js: >+ (WI.CPUInstrument): >+ (WI.CPUInstrument.supported): >+ (WI.CPUInstrument.prototype.get timelineRecordType): >+ (WI.CPUInstrument.prototype.startInstrumentation): >+ (WI.CPUInstrument.prototype.stopInstrumentation): >+ * UserInterface/Models/CPUTimelineRecord.js: >+ (WI.CPUTimelineRecord): >+ (WI.CPUTimelineRecord.prototype.get timestamp): >+ (WI.CPUTimelineRecord.prototype.get usage): >+ * UserInterface/Models/Instrument.js: >+ (WI.Instrument.createForTimelineType): >+ * UserInterface/Models/TimelineRecord.js: >+ * UserInterface/Models/TimelineRecording.js: >+ (WI.TimelineRecording.prototype.addRecord): >+ Expose a new CPU instrument and timeline. >+ >+ * UserInterface/Views/ColumnChart.js: Added. >+ (WI.ColumnChart): >+ (WI.ColumnChart.prototype.get element): >+ (WI.ColumnChart.prototype.get bars): >+ (WI.ColumnChart.prototype.get size): >+ (WI.ColumnChart.prototype.set size): >+ (WI.ColumnChart.prototype.addBar): >+ (WI.ColumnChart.prototype.clear): >+ (WI.ColumnChart.prototype.needsLayout): >+ (WI.ColumnChart.prototype.updateLayout): >+ View that will draw vertical bars with independent widths. >+ This is meant to be used similiar to WI.LineChart. >+ >+ * UserInterface/Images/CPUInstrument.svg: Added. >+ * UserInterface/Views/Variables.css: >+ (:root): >+ CPU timeline colors and icon. >+ >+ * UserInterface/Views/CPUTimelineOverviewGraph.css: >+ (body .sidebar > .panel.navigation.timeline > .timelines-content li.item.cpu,): >+ (.timeline-overview-graph.cpu): >+ (.timeline-overview-graph.cpu > .legend): >+ (body[dir=ltr] .timeline-overview-graph.cpu > .legend): >+ (body[dir=rtl] .timeline-overview-graph.cpu > .legend): >+ (.timeline-overview-graph:nth-child(even) > .legend): >+ (body[dir=rtl] .timeline-overview-graph.cpu > .bar-chart): >+ (.timeline-overview-graph.cpu > .bar-chart > svg > g > rect): >+ * UserInterface/Views/CPUTimelineOverviewGraph.js: Added. >+ (WI.CPUTimelineOverviewGraph): >+ (WI.CPUTimelineOverviewGraph.prototype.get height): >+ (WI.CPUTimelineOverviewGraph.prototype.reset): >+ (WI.CPUTimelineOverviewGraph.prototype.layout.xScale): >+ (WI.CPUTimelineOverviewGraph.prototype.layout.yScale): >+ (WI.CPUTimelineOverviewGraph.prototype.layout.yScaleForRecord): >+ (WI.CPUTimelineOverviewGraph.prototype.layout): >+ (WI.CPUTimelineOverviewGraph.prototype._updateLegend): >+ (WI.CPUTimelineOverviewGraph.prototype._cpuTimelineRecordAdded): >+ * UserInterface/Views/CPUTimelineView.css: >+ (.timeline-view.cpu): >+ (.timeline-view.cpu > .content): >+ (.timeline-view.cpu > .content .subtitle): >+ (.timeline-view.cpu > .content > .details): >+ (.timeline-view.cpu > .content > .details > .timeline-ruler): >+ (body[dir=ltr] .timeline-view.cpu > .content > .details > .timeline-ruler): >+ (body[dir=rtl] .timeline-view.cpu > .content > .details > .timeline-ruler): >+ (.timeline-view.cpu > .content > .details > .subtitle): >+ (.cpu-usage-view .line-chart > svg > path): >+ (.timeline-view.cpu .legend > .row > .swatch.current): >+ * UserInterface/Views/CPUTimelineView.js: Added. >+ (WI.CPUTimelineView): >+ (WI.CPUTimelineView.prototype.shown): >+ (WI.CPUTimelineView.prototype.hidden): >+ (WI.CPUTimelineView.prototype.closed): >+ (WI.CPUTimelineView.prototype.reset): >+ (WI.CPUTimelineView.prototype.get scrollableElements): >+ (WI.CPUTimelineView.prototype.get showsFilterBar): >+ (WI.CPUTimelineView.prototype.layout.layoutView): >+ (WI.CPUTimelineView.prototype.layout.xScale): >+ (WI.CPUTimelineView.prototype.layout.yScale): >+ (WI.CPUTimelineView.prototype.layout): >+ (WI.CPUTimelineView.prototype._cpuTimelineRecordAdded): >+ * UserInterface/Views/CPUUsageView.css: >+ (.cpu-usage-view): >+ (.cpu-usage-view > .details): >+ (body[dir=ltr] .cpu-usage-view > .details): >+ (body[dir=rtl] .cpu-usage-view > .details): >+ (.cpu-usage-view > .graph): >+ (body[dir=rtl] .cpu-usage-view > .graph): >+ * UserInterface/Views/CPUUsageView.js: >+ (WI.CPUUsageView): >+ (WI.CPUUsageView.prototype.get element): >+ (WI.CPUUsageView.prototype.clear): >+ (WI.CPUUsageView.prototype.layoutWithDataPoints): >+ (WI.CPUUsageView.prototype._updateDetails): >+ * UserInterface/Views/ContentView.js: >+ (WI.ContentView.createFromRepresentedObject): >+ * UserInterface/Views/TimelineIcons.css: >+ (.cpu-icon .icon): >+ * UserInterface/Views/TimelineOverviewGraph.js: >+ (WI.TimelineOverviewGraph.createForTimeline): >+ * UserInterface/Views/TimelineTabContentView.js: >+ (WI.TimelineTabContentView.displayNameForTimelineType): >+ (WI.TimelineTabContentView.iconClassNameForTimelineType): >+ (WI.TimelineTabContentView.genericClassNameForTimelineType): >+ (WI.TimelineTabContentView.iconClassNameForRecord): >+ (WI.TimelineTabContentView.displayNameForRecord): >+ Timeline views for CPU usage. >+ >+ * UserInterface/Views/MemoryCategoryView.js: >+ (WI.MemoryCategoryView): >+ * UserInterface/Views/MemoryTimelineView.js: >+ (WI.MemoryTimelineView.createChartContainer): >+ (WI.MemoryTimelineView): >+ (WI.MemoryTimelineView.prototype._clearMaxComparisonLegend): >+ Minor updates to style and comments. >+ > 2019-01-23 Devin Rousso <drousso@apple.com> > > WebInspector: Confusingly nested events in the timeline for Mutation Observers >diff --git a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >index a6ac3b2ca2d..a2f3c6df126 100644 >--- a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >+++ b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >@@ -139,6 +139,7 @@ localizedStrings["Auto Increment"] = "Auto Increment"; > localizedStrings["Automatically continue after evaluating"] = "Automatically continue after evaluating"; > localizedStrings["Available Style Sheets"] = "Available Style Sheets"; > localizedStrings["Average Time"] = "Average Time"; >+localizedStrings["Average: %s"] = "Average: %s"; > localizedStrings["Back (%s)"] = "Back (%s)"; > localizedStrings["Backtrace"] = "Backtrace"; > localizedStrings["Basic"] = "Basic"; >@@ -162,6 +163,8 @@ localizedStrings["Busy"] = "Busy"; > localizedStrings["Byte Range %s\u2013%s"] = "Byte Range %s\u2013%s"; > localizedStrings["Bytes Received"] = "Bytes Received"; > localizedStrings["Bytes Sent"] = "Bytes Sent"; >+localizedStrings["CPU"] = "CPU"; >+localizedStrings["CPU Usage"] = "CPU Usage"; > localizedStrings["CSP Hash"] = "CSP Hash"; > localizedStrings["CSS"] = "CSS"; > localizedStrings["CSS Canvas"] = "CSS Canvas"; >@@ -578,6 +581,7 @@ localizedStrings["Mass"] = "Mass"; > localizedStrings["Matching"] = "Matching"; > localizedStrings["Max Comparison"] = "Max Comparison"; > localizedStrings["Maximum"] = "Maximum"; >+localizedStrings["Maximum CPU Usage: %s"] = "Maximum CPU Usage: %s"; > localizedStrings["Maximum Size: %s"] = "Maximum Size: %s"; > localizedStrings["Maximum maximum memory size in this recording"] = "Maximum maximum memory size in this recording"; > localizedStrings["Media"] = "Media"; >diff --git a/Source/WebInspectorUI/UserInterface/Base/Main.js b/Source/WebInspectorUI/UserInterface/Base/Main.js >index 81b06dd502e..71cb8ed6bf1 100644 >--- a/Source/WebInspectorUI/UserInterface/Base/Main.js >+++ b/Source/WebInspectorUI/UserInterface/Base/Main.js >@@ -75,6 +75,8 @@ WI.loaded = function() > InspectorBackend.registerDOMStorageDispatcher(new WI.DOMStorageObserver); > if (InspectorBackend.registerApplicationCacheDispatcher) > InspectorBackend.registerApplicationCacheDispatcher(new WI.ApplicationCacheObserver); >+ if (InspectorBackend.registerCPUProfilerDispatcher) >+ InspectorBackend.registerCPUProfilerDispatcher(new WI.CPUProfilerObserver); > if (InspectorBackend.registerScriptProfilerDispatcher) > InspectorBackend.registerScriptProfilerDispatcher(new WI.ScriptProfilerObserver); > if (InspectorBackend.registerTimelineDispatcher) >diff --git a/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js b/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js >index 61b745d9d23..259205ee394 100644 >--- a/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js >+++ b/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js >@@ -117,6 +117,9 @@ WI.TimelineManager = class TimelineManager extends WI.Object > if (WI.sharedApp.debuggableType === WI.DebuggableType.JavaScript || WI.sharedApp.debuggableType === WI.DebuggableType.ServiceWorker) > return types; > >+ if (WI.CPUInstrument.supported()) >+ types.push(WI.TimelineRecord.Type.CPU); >+ > if (WI.MemoryInstrument.supported()) > types.push(WI.TimelineRecord.Type.Memory); > >@@ -449,14 +452,36 @@ WI.TimelineManager = class TimelineManager extends WI.Object > this._stopAutoRecordingSoon(); > } > >- memoryTrackingStart(timestamp) >+ cpuProfilerTrackingStarted(timestamp) >+ { >+ // Called from WI.CPUProfilerObserver. >+ >+ this.capturingStarted(timestamp); >+ } >+ >+ cpuProfilerTrackingUpdated(event) >+ { >+ // Called from WI.CPUProfilerObserver. >+ >+ if (!this._isCapturing) >+ return; >+ >+ this._addRecord(new WI.CPUTimelineRecord(event.timestamp, event.usage)); >+ } >+ >+ cpuProfilerTrackingCompleted() >+ { >+ // Called from WI.CPUProfilerObserver. >+ } >+ >+ memoryTrackingStarted(timestamp) > { > // Called from WI.MemoryObserver. > > this.capturingStarted(timestamp); > } > >- memoryTrackingUpdate(event) >+ memoryTrackingUpdated(event) > { > // Called from WI.MemoryObserver. > >@@ -466,7 +491,7 @@ WI.TimelineManager = class TimelineManager extends WI.Object > this._addRecord(new WI.MemoryTimelineRecord(event.timestamp, event.categories)); > } > >- memoryTrackingComplete() >+ memoryTrackingCompleted() > { > // Called from WI.MemoryObserver. > } >@@ -1141,6 +1166,9 @@ WI.TimelineManager = class TimelineManager extends WI.Object > case WI.TimelineRecord.Type.Media: > instrumentSet.add(target.TimelineAgent.Instrument.Timeline); > break; >+ case WI.TimelineRecord.Type.CPU: >+ instrumentSet.add(target.TimelineAgent.Instrument.CPU); >+ break; > case WI.TimelineRecord.Type.Memory: > instrumentSet.add(target.TimelineAgent.Instrument.Memory); > break; >diff --git a/Source/WebInspectorUI/UserInterface/Debug/UncaughtExceptionReporter.css b/Source/WebInspectorUI/UserInterface/Debug/UncaughtExceptionReporter.css >index 4c826eb9659..7ae37160076 100644 >--- a/Source/WebInspectorUI/UserInterface/Debug/UncaughtExceptionReporter.css >+++ b/Source/WebInspectorUI/UserInterface/Debug/UncaughtExceptionReporter.css >@@ -37,7 +37,7 @@ > .uncaught-exception-sheet { > min-width: 400px; > padding: 50px 0; >- font-family: '-webkit-system-font'; >+ font-family: -webkit-system-font, sans-serif; > font-size: 11pt; > color: hsl(0, 0%, 40%); > >diff --git a/Source/WebInspectorUI/UserInterface/Images/CPUInstrument.svg b/Source/WebInspectorUI/UserInterface/Images/CPUInstrument.svg >new file mode 100644 >index 00000000000..319ec924709 >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Images/CPUInstrument.svg >@@ -0,0 +1,13 @@ >+<?xml version="1.0" encoding="utf-8"?> >+<!-- Copyright © 2019 Apple Inc. All rights reserved. --> >+<svg xmlns="http://www.w3.org/2000/svg" id="root" version="1.1" viewBox="0 0 16 16"> >+ <circle stroke="hsl(118, 33%, 42%)" fill="hsl(118, 43%, 55%)" cx="8" cy="8" r="7.5"/> >+ <rect stroke="hsl(118, 33%, 42%)" stroke-width="2" x="4" y="4" width="2" height="8" rx="0.25"/> >+ <rect stroke="hsl(118, 33%, 42%)" stroke-width="2" x="7" y="4" width="2" height="8" rx="0.25"/> >+ <rect stroke="hsl(118, 33%, 42%)" stroke-width="2" x="10" y="4" width="2" height="8" rx="0.25"/> >+ <rect fill="white" x="4" y="4" width="2" height="8" rx="0.25"/> >+ <rect fill="white" x="7" y="4" width="2" height="8" rx="0.25"/> >+ <rect fill="white" x="10" y="4" width="2" height="8" rx="0.25"/> >+ <rect stroke="hsl(118, 33%, 42%)" stroke-width="2" x="3" y="6" width="10" height="4" rx="0.25"/> >+ <rect fill="white" x="3" y="6" width="10" height="4" rx="0.25"/> >+</svg> >diff --git a/Source/WebInspectorUI/UserInterface/Main.html b/Source/WebInspectorUI/UserInterface/Main.html >index c55125bc184..33c5cbe2aae 100644 >--- a/Source/WebInspectorUI/UserInterface/Main.html >+++ b/Source/WebInspectorUI/UserInterface/Main.html >@@ -43,6 +43,9 @@ > <link rel="stylesheet" href="Views/BreakpointTreeElement.css"> > <link rel="stylesheet" href="Views/ButtonNavigationItem.css"> > <link rel="stylesheet" href="Views/ButtonToolbarItem.css"> >+ <link rel="stylesheet" href="Views/CPUTimelineOverviewGraph.css"> >+ <link rel="stylesheet" href="Views/CPUTimelineView.css"> >+ <link rel="stylesheet" href="Views/CPUUsageView.css"> > <link rel="stylesheet" href="Views/CallFrameIcons.css"> > <link rel="stylesheet" href="Views/CallFrameTreeElement.css"> > <link rel="stylesheet" href="Views/CallFrameView.css"> >@@ -90,10 +93,10 @@ > <link rel="stylesheet" href="Views/DetailsSection.css"> > <link rel="stylesheet" href="Views/DividerNavigationItem.css"> > <link rel="stylesheet" href="Views/Editing.css"> >+ <link rel="stylesheet" href="Views/ErrorObjectView.css"> > <link rel="stylesheet" href="Views/EventBreakpointPopover.css"> > <link rel="stylesheet" href="Views/EventBreakpointTreeElement.css"> > <link rel="stylesheet" href="Views/EventListenerSectionGroup.css"> >- <link rel="stylesheet" href="Views/ErrorObjectView.css"> > <link rel="stylesheet" href="Views/FilterBar.css"> > <link rel="stylesheet" href="Views/FindBanner.css"> > <link rel="stylesheet" href="Views/FlexibleSpaceNavigationItem.css"> >@@ -307,6 +310,7 @@ > <script src="Protocol/WorkerTarget.js"></script> > > <script src="Protocol/ApplicationCacheObserver.js"></script> >+ <script src="Protocol/CPUProfilerObserver.js"></script> > <script src="Protocol/CSSObserver.js"></script> > <script src="Protocol/CanvasObserver.js"></script> > <script src="Protocol/ConsoleObserver.js"></script> >@@ -344,8 +348,8 @@ > <script src="Models/BackForwardEntry.js"></script> > <script src="Models/Branch.js"></script> > <script src="Models/Breakpoint.js"></script> >- <script src="Models/CallingContextTree.js"></script> >- <script src="Models/CallingContextTreeNode.js"></script> >+ <script src="Models/CPUInstrument.js"></script> >+ <script src="Models/CPUTimelineRecord.js"></script> > <script src="Models/CSSCompletions.js"></script> > <script src="Models/CSSKeywordCompletions.js"></script> > <script src="Models/CSSMedia.js"></script> >@@ -355,6 +359,8 @@ > <script src="Models/CSSStyleDeclaration.js"></script> > <script src="Models/CSSStyleSheet.js"></script> > <script src="Models/CallFrame.js"></script> >+ <script src="Models/CallingContextTree.js"></script> >+ <script src="Models/CallingContextTreeNode.js"></script> > <script src="Models/Canvas.js"></script> > <script src="Models/Collection.js"></script> > <script src="Models/CollectionEntry.js"></script> >@@ -560,6 +566,7 @@ > <script src="Views/SettingsGroup.js"></script> > <script src="Views/SettingsView.js"></script> > >+ <script src="Views/AuditTestContentView.js"></script> > <script src="Views/CollectionContentView.js"></script> > > <script src="Views/ActivateButtonNavigationItem.js"></script> >@@ -569,7 +576,6 @@ > <script src="Views/ApplicationCacheFrameTreeElement.js"></script> > <script src="Views/ApplicationCacheManifestTreeElement.js"></script> > <script src="Views/AuditNavigationSidebarPanel.js"></script> >- <script src="Views/AuditTestContentView.js"></script> > <script src="Views/AuditTestCaseContentView.js"></script> > <script src="Views/AuditTestGroupContentView.js"></script> > <script src="Views/AuditTreeElement.js"></script> >@@ -578,6 +584,9 @@ > <script src="Views/BreakpointActionView.js"></script> > <script src="Views/BreakpointTreeElement.js"></script> > <script src="Views/ButtonToolbarItem.js"></script> >+ <script src="Views/CPUTimelineOverviewGraph.js"></script> >+ <script src="Views/CPUTimelineView.js"></script> >+ <script src="Views/CPUUsageView.js"></script> > <script src="Views/CSSStyleSheetTreeElement.js"></script> > <script src="Views/CallFrameTreeElement.js"></script> > <script src="Views/CallFrameView.js"></script> >@@ -597,6 +606,7 @@ > <script src="Views/CodeMirrorTextMarkers.js"></script> > <script src="Views/ColorPicker.js"></script> > <script src="Views/ColorWheel.js"></script> >+ <script src="Views/ColumnChart.js"></script> > <script src="Views/CompletionSuggestionsView.js"></script> > <script src="Views/ComputedStyleDetailsPanel.js"></script> > <script src="Views/ComputedStyleSection.js"></script> >diff --git a/Source/WebInspectorUI/UserInterface/Models/CPUInstrument.js b/Source/WebInspectorUI/UserInterface/Models/CPUInstrument.js >new file mode 100644 >index 00000000000..dfcc6e7b6d6 >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Models/CPUInstrument.js >@@ -0,0 +1,61 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+WI.CPUInstrument = class CPUInstrument extends WI.Instrument >+{ >+ constructor() >+ { >+ super(); >+ >+ console.assert(WI.CPUInstrument.supported()); >+ } >+ >+ // Static >+ >+ static supported() >+ { >+ // COMPATIBILITY (iOS 12): CPUProfiler domain did not exist. >+ return InspectorBackend.domains.CPUProfiler; >+ } >+ >+ // Protected >+ >+ get timelineRecordType() >+ { >+ return WI.TimelineRecord.Type.CPU; >+ } >+ >+ startInstrumentation(initiatedByBackend) >+ { >+ if (!initiatedByBackend) >+ CPUProfilerAgent.startTracking(); >+ } >+ >+ stopInstrumentation(initiatedByBackend) >+ { >+ if (!initiatedByBackend) >+ CPUProfilerAgent.stopTracking(); >+ } >+}; >diff --git a/Source/WebInspectorUI/UserInterface/Models/CPUTimelineRecord.js b/Source/WebInspectorUI/UserInterface/Models/CPUTimelineRecord.js >new file mode 100644 >index 00000000000..f0002844120 >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Models/CPUTimelineRecord.js >@@ -0,0 +1,44 @@ >+/* >+ * Copyright (C) 2016 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+WI.CPUTimelineRecord = class CPUTimelineRecord extends WI.TimelineRecord >+{ >+ constructor(timestamp, usage) >+ { >+ super(WI.TimelineRecord.Type.CPU, timestamp, timestamp); >+ >+ console.assert(typeof timestamp === "number"); >+ console.assert(typeof usage === "number"); >+ console.assert(usage >= 0); >+ >+ this._timestamp = timestamp; >+ this._usage = usage; >+ } >+ >+ // Public >+ >+ get timestamp() { return this._timestamp; } >+ get usage() { return this._usage; } >+}; >diff --git a/Source/WebInspectorUI/UserInterface/Models/Instrument.js b/Source/WebInspectorUI/UserInterface/Models/Instrument.js >index f12c3af6ffe..4c12d3601db 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/Instrument.js >+++ b/Source/WebInspectorUI/UserInterface/Models/Instrument.js >@@ -38,6 +38,8 @@ WI.Instrument = class Instrument > return new WI.ScriptInstrument; > case WI.TimelineRecord.Type.RenderingFrame: > return new WI.FPSInstrument; >+ case WI.TimelineRecord.Type.CPU: >+ return new WI.CPUInstrument; > case WI.TimelineRecord.Type.Memory: > return new WI.MemoryInstrument; > case WI.TimelineRecord.Type.HeapAllocations: >diff --git a/Source/WebInspectorUI/UserInterface/Models/TimelineRecord.js b/Source/WebInspectorUI/UserInterface/Models/TimelineRecord.js >index 5c5e78b11bc..bd4a995c98c 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/TimelineRecord.js >+++ b/Source/WebInspectorUI/UserInterface/Models/TimelineRecord.js >@@ -158,6 +158,7 @@ WI.TimelineRecord.Type = { > Layout: "timeline-record-type-layout", > Script: "timeline-record-type-script", > RenderingFrame: "timeline-record-type-rendering-frame", >+ CPU: "timeline-record-type-cpu", > Memory: "timeline-record-type-memory", > HeapAllocations: "timeline-record-type-heap-allocations", > Media: "timeline-record-type-media", >diff --git a/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js b/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js >index fc7587e8214..9ae7638438b 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js >+++ b/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js >@@ -211,6 +211,7 @@ WI.TimelineRecording = class TimelineRecording extends WI.Object > // Some records don't have source code timelines. > if (record.type === WI.TimelineRecord.Type.Network > || record.type === WI.TimelineRecord.Type.RenderingFrame >+ || record.type === WI.TimelineRecord.Type.CPU > || record.type === WI.TimelineRecord.Type.Memory > || record.type === WI.TimelineRecord.Type.HeapAllocations > || record.type === WI.TimelineRecord.Type.Media) >diff --git a/Source/WebInspectorUI/UserInterface/Protocol/CPUProfilerObserver.js b/Source/WebInspectorUI/UserInterface/Protocol/CPUProfilerObserver.js >new file mode 100644 >index 00000000000..49a2345bda4 >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Protocol/CPUProfilerObserver.js >@@ -0,0 +1,44 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+WI.CPUProfilerObserver = class CPUProfilerObserver >+{ >+ // Events defined by the "CPUProfiler" domain. >+ >+ trackingStart(timestamp) >+ { >+ WI.timelineManager.cpuProfilerTrackingStarted(timestamp); >+ } >+ >+ trackingUpdate(event) >+ { >+ WI.timelineManager.cpuProfilerTrackingUpdated(event); >+ } >+ >+ trackingComplete(samples) >+ { >+ WI.timelineManager.cpuProfilerTrackingCompleted(samples); >+ } >+}; >diff --git a/Source/WebInspectorUI/UserInterface/Protocol/MemoryObserver.js b/Source/WebInspectorUI/UserInterface/Protocol/MemoryObserver.js >index 7e1d3268923..7224de277c6 100644 >--- a/Source/WebInspectorUI/UserInterface/Protocol/MemoryObserver.js >+++ b/Source/WebInspectorUI/UserInterface/Protocol/MemoryObserver.js >@@ -34,16 +34,16 @@ WI.MemoryObserver = class MemoryObserver > > trackingStart(timestamp) > { >- WI.timelineManager.memoryTrackingStart(timestamp); >+ WI.timelineManager.memoryTrackingStarted(timestamp); > } > > trackingUpdate(event) > { >- WI.timelineManager.memoryTrackingUpdate(event); >+ WI.timelineManager.memoryTrackingUpdated(event); > } > > trackingComplete() > { >- WI.timelineManager.memoryTrackingComplete(); >+ WI.timelineManager.memoryTrackingCompleted(); > } > }; >diff --git a/Source/WebInspectorUI/UserInterface/Protocol/Target.js b/Source/WebInspectorUI/UserInterface/Protocol/Target.js >index b0ea5eae2ef..d1687e2e109 100644 >--- a/Source/WebInspectorUI/UserInterface/Protocol/Target.js >+++ b/Source/WebInspectorUI/UserInterface/Protocol/Target.js >@@ -111,6 +111,7 @@ WI.Target = class Target extends WI.Object > > get AuditAgent() { return this._agents.Audit; } > get ApplicationCacheAgent() { return this._agents.ApplicationCache; } >+ get CPUProfilerAgent() { return this._agents.CPUProfiler; } > get CSSAgent() { return this._agents.CSS; } > get CanvasAgent() { return this._agents.Canvas; } > get ConsoleAgent() { return this._agents.Console; } >diff --git a/Source/WebInspectorUI/UserInterface/Test.html b/Source/WebInspectorUI/UserInterface/Test.html >index ee4282b6713..06a0d84a8a3 100644 >--- a/Source/WebInspectorUI/UserInterface/Test.html >+++ b/Source/WebInspectorUI/UserInterface/Test.html >@@ -80,6 +80,7 @@ > <script src="Protocol/WorkerTarget.js"></script> > > <script src="Protocol/InspectorObserver.js"></script> >+ <script src="Protocol/CPUProfilerObserver.js"></script> > <script src="Protocol/CSSObserver.js"></script> > <script src="Protocol/CanvasObserver.js"></script> > <script src="Protocol/ConsoleObserver.js"></script> >@@ -113,6 +114,8 @@ > <script src="Models/LocalScript.js"></script> > > <script src="Models/Breakpoint.js"></script> >+ <script src="Models/CPUInstrument.js"></script> >+ <script src="Models/CPUTimelineRecord.js"></script> > <script src="Models/CSSCompletions.js"></script> > <script src="Models/CSSKeywordCompletions.js"></script> > <script src="Models/CSSMedia.js"></script> >diff --git a/Source/WebInspectorUI/UserInterface/Test/Test.js b/Source/WebInspectorUI/UserInterface/Test/Test.js >index 195fbc21222..bdcca1b9d1d 100644 >--- a/Source/WebInspectorUI/UserInterface/Test/Test.js >+++ b/Source/WebInspectorUI/UserInterface/Test/Test.js >@@ -38,6 +38,7 @@ WI.loaded = function() > InspectorBackend.registerMemoryDispatcher(new WI.MemoryObserver); > InspectorBackend.registerDOMStorageDispatcher(new WI.DOMStorageObserver); > InspectorBackend.registerScriptProfilerDispatcher(new WI.ScriptProfilerObserver); >+ InspectorBackend.registerCPUProfilerDispatcher(new WI.CPUProfilerObserver); > InspectorBackend.registerTimelineDispatcher(new WI.TimelineObserver); > InspectorBackend.registerCSSDispatcher(new WI.CSSObserver); > InspectorBackend.registerLayerTreeDispatcher(new WI.LayerTreeObserver); >diff --git a/Source/WebInspectorUI/UserInterface/Views/CPUTimelineOverviewGraph.css b/Source/WebInspectorUI/UserInterface/Views/CPUTimelineOverviewGraph.css >new file mode 100644 >index 00000000000..aaeb296d2aa >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Views/CPUTimelineOverviewGraph.css >@@ -0,0 +1,66 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+body .sidebar > .panel.navigation.timeline > .timelines-content li.item.cpu, >+body .timeline-overview > .graphs-container > .timeline-overview-graph.cpu { >+ height: 72px; >+} >+ >+.timeline-overview-graph.cpu { >+ position: relative; >+} >+ >+.timeline-overview-graph.cpu > .legend { >+ position: absolute; >+ top: 0; >+ padding: 2px; >+ font-size: 8px; >+ color: hsl(0, 0%, 50%); >+ background-color: white; >+ pointer-events: none; >+ >+ --cpu-timeline-overview-graph-legend-offset-end: 0; >+} >+ >+body[dir=ltr] .timeline-overview-graph.cpu > .legend { >+ right: var(--cpu-timeline-overview-graph-legend-offset-end); >+} >+ >+body[dir=rtl] .timeline-overview-graph.cpu > .legend { >+ left: var(--cpu-timeline-overview-graph-legend-offset-end); >+} >+ >+.timeline-overview-graph:nth-child(even) > .legend { >+ background-color: hsl(0, 0%, 96%); >+} >+ >+body[dir=rtl] .timeline-overview-graph.cpu > .bar-chart { >+ transform: scaleX(-1); >+} >+ >+.timeline-overview-graph.cpu > .bar-chart > svg > rect { >+ stroke: var(--cpu-stroke-color); >+ fill: var(--cpu-fill-color); >+} >diff --git a/Source/WebInspectorUI/UserInterface/Views/CPUTimelineOverviewGraph.js b/Source/WebInspectorUI/UserInterface/Views/CPUTimelineOverviewGraph.js >new file mode 100644 >index 00000000000..3065710f9e4 >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Views/CPUTimelineOverviewGraph.js >@@ -0,0 +1,151 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+WI.CPUTimelineOverviewGraph = class CPUTimelineOverviewGraph extends WI.TimelineOverviewGraph >+{ >+ constructor(timeline, timelineOverview) >+ { >+ console.assert(timeline instanceof WI.Timeline); >+ console.assert(timeline.type === WI.TimelineRecord.Type.CPU, timeline); >+ >+ super(timelineOverview); >+ >+ this.element.classList.add("cpu"); >+ >+ this._cpuTimeline = timeline; >+ this._cpuTimeline.addEventListener(WI.Timeline.Event.RecordAdded, this._cpuTimelineRecordAdded, this); >+ >+ let size = new WI.Size(0, this.height); >+ this._chart = new WI.ColumnChart(size); >+ this.element.appendChild(this._chart.element); >+ >+ this._legendElement = this.element.appendChild(document.createElement("div")); >+ this._legendElement.classList.add("legend"); >+ >+ this.reset(); >+ } >+ >+ // Protected >+ >+ get height() >+ { >+ return 72; >+ } >+ >+ reset() >+ { >+ super.reset(); >+ >+ this._maxUsage = 0; >+ this._cachedMaxUsage = undefined; >+ >+ this._updateLegend(); >+ this._chart.clear(); >+ this._chart.needsLayout(); >+ } >+ >+ layout() >+ { >+ if (!this.visible) >+ return; >+ >+ this._updateLegend(); >+ this._chart.clear(); >+ >+ let graphWidth = this.timelineOverview.scrollContainerWidth; >+ if (isNaN(graphWidth)) >+ return; >+ >+ if (this._chart.size.width !== graphWidth || this._chart.size.height !== this.height) >+ this._chart.size = new WI.Size(graphWidth, this.height); >+ >+ let graphStartTime = this.startTime; >+ let visibleEndTime = Math.min(this.endTime, this.currentTime); >+ let secondsPerPixel = this.timelineOverview.secondsPerPixel; >+ let maxCapacity = Math.max(20, this._maxUsage * 1.05); // Add 5% for padding. >+ >+ // 500ms. This matches the ResourceUsageThread sampling frequency in the backend. >+ const samplingRatePerSecond = 0.5; >+ >+ function xScale(time) { >+ return (time - graphStartTime) / secondsPerPixel; >+ } >+ >+ let height = this.height; >+ function yScale(size) { >+ return (size / maxCapacity) * height; >+ } >+ >+ const includeRecordBeforeStart = true; >+ let visibleRecords = this._cpuTimeline.recordsInTimeRange(graphStartTime, visibleEndTime + (samplingRatePerSecond / 2), includeRecordBeforeStart); >+ if (!visibleRecords.length) >+ return; >+ >+ function yScaleForRecord(record) { >+ return yScale(record.usage); >+ } >+ >+ let intervalWidth = (samplingRatePerSecond / secondsPerPixel); >+ const minimumDisplayHeight = 2; >+ >+ // Bars for each record. >+ for (let record of visibleRecords) { >+ let w = intervalWidth; >+ let h = Math.max(minimumDisplayHeight, yScale(record.usage)); >+ let x = xScale(record.startTime - (samplingRatePerSecond / 2)); >+ let y = height - h; >+ this._chart.addBar(x, y, w, h); >+ } >+ >+ this._chart.updateLayout(); >+ } >+ >+ // Private >+ >+ _updateLegend() >+ { >+ if (this._cachedMaxUsage === this._maxUsage) >+ return; >+ >+ this._cachedMaxUsage = this._maxUsage; >+ >+ if (!this._maxUsage) { >+ this._legendElement.hidden = true; >+ this._legendElement.textContent = ""; >+ } else { >+ this._legendElement.hidden = false; >+ this._legendElement.textContent = WI.UIString("Maximum CPU Usage: %s").format(Number.percentageString(this._maxUsage / 100)); >+ } >+ } >+ >+ _cpuTimelineRecordAdded(event) >+ { >+ let cpuTimelineRecord = event.data.record; >+ >+ this._maxUsage = Math.max(this._maxUsage, cpuTimelineRecord.usage); >+ >+ this.needsLayout(); >+ } >+}; >diff --git a/Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.css b/Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.css >new file mode 100644 >index 00000000000..c5ab00d7699 >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.css >@@ -0,0 +1,75 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+.timeline-view.cpu { >+ overflow: scroll; >+} >+ >+.timeline-view.cpu > .content { >+ width: 970px; >+ margin: 10px auto; >+} >+ >+.timeline-view.cpu > .content .subtitle { >+ font-family: -webkit-system-font, sans-serif; >+ font-size: 14px; >+} >+ >+.timeline-view.cpu > .content > .details { >+ position: relative; >+} >+ >+.timeline-view.cpu > .content > .details > .timeline-ruler { >+ position: absolute; >+ top: 5px; >+ bottom: 0; >+ right: 0; >+ left: 0; >+ >+ --cpu-timeline-view-details-timeline-ruler-offset-start: 150px; >+} >+ >+body[dir=ltr] .timeline-view.cpu > .content > .details > .timeline-ruler { >+ left: var(--cpu-timeline-view-details-timeline-ruler-offset-start); >+} >+ >+body[dir=rtl] .timeline-view.cpu > .content > .details > .timeline-ruler { >+ right: var(--cpu-timeline-view-details-timeline-ruler-offset-start); >+} >+ >+.timeline-view.cpu > .content > .details > .subtitle { >+ padding: 0 10px 10px; >+ border-bottom: 1px solid var(--border-color); >+} >+ >+.cpu-usage-view .line-chart > svg > path { >+ stroke: var(--cpu-stroke-color); >+ fill: var(--cpu-fill-color); >+} >+ >+.timeline-view.cpu .legend > .row > .swatch.current { >+ border: 1px solid var(--cpu-max-comparison-stroke-color); >+ background: var(--cpu-max-comparison-fill-color); >+} >diff --git a/Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.js b/Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.js >new file mode 100644 >index 00000000000..ce48b38b880 >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Views/CPUTimelineView.js >@@ -0,0 +1,189 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+WI.CPUTimelineView = class CPUTimelineView extends WI.TimelineView >+{ >+ constructor(timeline, extraArguments) >+ { >+ console.assert(timeline.type === WI.TimelineRecord.Type.CPU, timeline); >+ >+ super(timeline, extraArguments); >+ >+ this._recording = extraArguments.recording; >+ this._maxUsage = -Infinity; >+ >+ this.element.classList.add("cpu"); >+ >+ let contentElement = this.element.appendChild(document.createElement("div")); >+ contentElement.classList.add("content"); >+ >+ // FIXME: Overview with charts. >+ >+ let detailsContainerElement = this._detailsContainerElement = contentElement.appendChild(document.createElement("div")); >+ detailsContainerElement.classList.add("details"); >+ >+ this._timelineRuler = new WI.TimelineRuler; >+ this.addSubview(this._timelineRuler); >+ detailsContainerElement.appendChild(this._timelineRuler.element); >+ >+ let detailsSubtitleElement = detailsContainerElement.appendChild(document.createElement("div")); >+ detailsSubtitleElement.classList.add("subtitle"); >+ detailsSubtitleElement.textContent = WI.UIString("CPU Usage"); >+ >+ this._cpuUsageView = new WI.CPUUsageView; >+ this._detailsContainerElement.appendChild(this._cpuUsageView.element); >+ >+ timeline.addEventListener(WI.Timeline.Event.RecordAdded, this._cpuTimelineRecordAdded, this); >+ } >+ >+ // Public >+ >+ shown() >+ { >+ super.shown(); >+ >+ this._timelineRuler.updateLayout(WI.View.LayoutReason.Resize); >+ } >+ >+ closed() >+ { >+ console.assert(this.representedObject instanceof WI.Timeline); >+ this.representedObject.removeEventListener(null, null, this); >+ } >+ >+ reset() >+ { >+ super.reset(); >+ >+ this._maxUsage = -Infinity; >+ >+ this._cpuUsageView.clear(); >+ } >+ >+ get scrollableElements() >+ { >+ return [this.element]; >+ } >+ >+ // Protected >+ >+ get showsFilterBar() { return false; } >+ >+ layout() >+ { >+ // Always update timeline ruler. >+ this._timelineRuler.zeroTime = this.zeroTime; >+ this._timelineRuler.startTime = this.startTime; >+ this._timelineRuler.endTime = this.endTime; >+ >+ let graphStartTime = this.startTime; >+ let graphEndTime = this.endTime; >+ let visibleEndTime = Math.min(this.endTime, this.currentTime); >+ >+ let discontinuities = this._recording.discontinuitiesInTimeRange(graphStartTime, visibleEndTime); >+ >+ // Don't include the record before the graph start if the graph start is within a gap. >+ let includeRecordBeforeStart = !discontinuities.length || discontinuities[0].startTime > graphStartTime; >+ let visibleRecords = this.representedObject.recordsInTimeRange(graphStartTime, visibleEndTime, includeRecordBeforeStart); >+ if (!visibleRecords.length) >+ return; >+ >+ // Update total usage chart with the last record's data. >+ let lastRecord = visibleRecords.lastValue; >+ >+ // FIXME: Left chart. >+ // FIXME: Right chart. >+ >+ // FIXME: <https://webkit.org/b/153758> Web Inspector: Memory / CPU Timeline Views should be responsive / resizable >+ const cpuUsageViewWidth = 800; >+ const cpuUsageViewHeight = 150; >+ >+ let secondsPerPixel = (graphEndTime - graphStartTime) / cpuUsageViewWidth; >+ >+ let dataPoints = []; >+ let max = -Infinity; >+ let min = Infinity; >+ let average = 0; >+ >+ for (let record of visibleRecords) { >+ let time = record.startTime; >+ let usage = record.usage; >+ >+ if (discontinuities.length && discontinuities[0].endTime < time) { >+ let discontinuity = discontinuities.shift(); >+ dataPoints.push({time: discontinuity.startTime, size: 0}); >+ dataPoints.push({time: discontinuity.endTime, size: 0}); >+ dataPoints.push({time: discontinuity.endTime, size: usage}); >+ } >+ >+ dataPoints.push({time, size: usage}); >+ max = Math.max(max, usage); >+ min = Math.min(min, usage); >+ average += usage; >+ } >+ >+ average /= visibleRecords.length; >+ >+ // If the graph end time is inside a gap, the last data point should >+ // only be extended to the start of the discontinuity. >+ if (discontinuities.length) >+ visibleEndTime = discontinuities[0].startTime; >+ >+ function layoutView(view, {dataPoints, min, max, average}) { >+ if (min === Infinity) >+ min = 0; >+ if (max === -Infinity) >+ max = 0; >+ >+ // Zoom in to the top of each graph to accentuate small changes. >+ let graphMin = min * 0.95; >+ let graphMax = (max * 1.05) - graphMin; >+ >+ function xScale(time) { >+ return (time - graphStartTime) / secondsPerPixel; >+ } >+ function yScale(size) { >+ return cpuUsageViewHeight - (((size - graphMin) / graphMax) * cpuUsageViewHeight); >+ } >+ >+ view.layoutWithDataPoints(dataPoints, visibleEndTime, min, max, average, xScale, yScale); >+ } >+ >+ layoutView(this._cpuUsageView, {dataPoints, min, max, average}); >+ } >+ >+ // Private >+ >+ _cpuTimelineRecordAdded(event) >+ { >+ let cpuTimelineRecord = event.data.record; >+ console.assert(cpuTimelineRecord instanceof WI.CPUTimelineRecord); >+ >+ this._maxUsage = Math.max(this._maxUsage, cpuTimelineRecord.usage); >+ >+ if (cpuTimelineRecord.startTime >= this.startTime && cpuTimelineRecord.endTime <= this.endTime) >+ this.needsLayout(); >+ } >+}; >diff --git a/Source/WebInspectorUI/UserInterface/Views/CPUUsageView.css b/Source/WebInspectorUI/UserInterface/Views/CPUUsageView.css >new file mode 100644 >index 00000000000..1b137bc0659 >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Views/CPUUsageView.css >@@ -0,0 +1,57 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+.cpu-usage-view { >+ display: flex; >+ border-bottom: 1px solid var(--border-color); >+} >+ >+.cpu-usage-view > .details { >+ width: 150px; >+ padding-top: 10px; >+ font-family: -webkit-system-font, sans-serif; >+ font-size: 12px; >+ color: hsl(0, 0%, 70%); >+ -webkit-padding-start: 15px; >+ >+ --cpu-usage-view-details-border-end: 1px solid var(--border-color); >+} >+ >+body[dir=ltr] .cpu-usage-view > .details { >+ border-right: var(--cpu-usage-view-details-border-end); >+} >+ >+body[dir=rtl] .cpu-usage-view > .details { >+ border-left: var(--cpu-usage-view-details-border-end); >+} >+ >+.cpu-usage-view > .graph { >+ position: relative; >+ bottom: -3px; >+} >+ >+body[dir=rtl] .cpu-usage-view > .graph { >+ transform: scaleX(-1); >+} >diff --git a/Source/WebInspectorUI/UserInterface/Views/CPUUsageView.js b/Source/WebInspectorUI/UserInterface/Views/CPUUsageView.js >new file mode 100644 >index 00000000000..0360afcdd77 >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Views/CPUUsageView.js >@@ -0,0 +1,119 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+WI.CPUUsageView = class CPUUsageView >+{ >+ constructor() >+ { >+ this._element = document.createElement("div"); >+ this._element.classList.add("cpu-usage-view"); >+ >+ this._detailsElement = this._element.appendChild(document.createElement("div")); >+ this._detailsElement.classList.add("details"); >+ >+ this._detailsAverageElement = this._detailsElement.appendChild(document.createElement("span")); >+ this._detailsElement.appendChild(document.createElement("br")); >+ this._detailsMaxElement = this._detailsElement.appendChild(document.createElement("span")); >+ this._detailsElement.appendChild(document.createElement("br")); >+ this._detailsMinElement = this._detailsElement.appendChild(document.createElement("span")); >+ this._updateDetails(NaN, NaN); >+ >+ this._graphElement = this._element.appendChild(document.createElement("div")); >+ this._graphElement.classList.add("graph"); >+ >+ // FIXME: <https://webkit.org/b/153758> Web Inspector: Memory / CPU Timeline Views should be responsive / resizable >+ let size = new WI.Size(800, 150); >+ this._chart = new WI.LineChart(size); >+ this._graphElement.appendChild(this._chart.element); >+ } >+ >+ // Public >+ >+ get element() { return this._element; } >+ >+ clear() >+ { >+ this._cachedAverageSize = undefined; >+ this._cachedMinSize = undefined; >+ this._cachedMaxSize = undefined; >+ this._updateDetails(NaN, NaN); >+ >+ this._chart.clear(); >+ this._chart.needsLayout(); >+ } >+ >+ layoutWithDataPoints(dataPoints, lastTime, minSize, maxSize, averageSize, xScale, yScale) >+ { >+ console.assert(minSize >= 0); >+ console.assert(maxSize >= 0); >+ console.assert(minSize <= maxSize); >+ >+ this._updateDetails(minSize, maxSize, averageSize); >+ this._chart.clear(); >+ >+ if (!dataPoints.length) >+ return; >+ >+ // Ensure an empty graph is empty. >+ if (!maxSize) >+ return; >+ >+ // Extend the first data point to the start so it doesn't look like we originate at zero size. >+ let firstX = 0; >+ let firstY = yScale(dataPoints[0].size); >+ this._chart.addPoint(firstX, firstY); >+ >+ // Points for data points. >+ for (let dataPoint of dataPoints) { >+ let x = xScale(dataPoint.time); >+ let y = yScale(dataPoint.size); >+ this._chart.addPoint(x, y); >+ } >+ >+ // Extend the last data point to the end time. >+ let lastDataPoint = dataPoints.lastValue; >+ let lastX = Math.floor(xScale(lastTime)); >+ let lastY = yScale(lastDataPoint.size); >+ this._chart.addPoint(lastX, lastY); >+ >+ this._chart.updateLayout(); >+ } >+ >+ // Private >+ >+ _updateDetails(minSize, maxSize, averageSize) >+ { >+ if (this._cachedMinSize === minSize && this._cachedMaxSize === maxSize && this._cachedAverageSize === averageSize) >+ return; >+ >+ this._cachedAverageSize = averageSize; >+ this._cachedMinSize = minSize; >+ this._cachedMaxSize = maxSize; >+ >+ this._detailsAverageElement.textContent = WI.UIString("Average: %s").format(Number.isFinite(maxSize) ? Number.percentageString(averageSize / 100) : emDash); >+ this._detailsMaxElement.textContent = WI.UIString("Highest: %s").format(Number.isFinite(maxSize) ? Number.percentageString(maxSize / 100) : emDash); >+ this._detailsMinElement.textContent = WI.UIString("Lowest: %s").format(Number.isFinite(minSize) ? Number.percentageString(minSize / 100) : emDash); >+ } >+}; >diff --git a/Source/WebInspectorUI/UserInterface/Views/ColumnChart.js b/Source/WebInspectorUI/UserInterface/Views/ColumnChart.js >new file mode 100644 >index 00000000000..13d3755a9f6 >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Views/ColumnChart.js >@@ -0,0 +1,108 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+// ColumnChart creates a single filled line chart. >+// >+// Initialize the chart with a size. You can then include a new bar >+// in the bar chart by providing an (x, y, w, h) via `addBar`. >+// >+// SVG: >+// >+// - There is a single rect for each bar. >+// >+// <div class="line-chart"> >+// <svg width="800" height="75" viewbox="0 0 800 75"> >+// <rect width="<w>" height="<h>" transform="translate(<x>, <y>)" /> >+// <rect width="<w>" height="<h>" transform="translate(<x>, <y>)" /> >+// </svg> >+// </div> >+ >+WI.ColumnChart = class ColumnChart >+{ >+ constructor(size) >+ { >+ this._element = document.createElement("div"); >+ this._element.classList.add("bar-chart"); >+ >+ this._svgElement = this._element.appendChild(createSVGElement("svg")); >+ >+ this._bars = []; >+ this.size = size; >+ } >+ >+ // Public >+ >+ get element() { return this._element; } >+ get bars() { return this._bars; } >+ >+ get size() >+ { >+ return this._size; >+ } >+ >+ set size(size) >+ { >+ this._size = size; >+ >+ this._svgElement.setAttribute("width", size.width); >+ this._svgElement.setAttribute("height", size.height); >+ this._svgElement.setAttribute("viewbox", `0 0 ${size.width} ${size.height}`); >+ } >+ >+ addBar(x, y, width, height) >+ { >+ this._bars.push({x, y, width, height}); >+ } >+ >+ clear() >+ { >+ this._bars = []; >+ } >+ >+ needsLayout() >+ { >+ if (this._scheduledLayoutUpdateIdentifier) >+ return; >+ >+ this._scheduledLayoutUpdateIdentifier = requestAnimationFrame(this.updateLayout.bind(this)); >+ } >+ >+ updateLayout() >+ { >+ if (this._scheduledLayoutUpdateIdentifier) { >+ cancelAnimationFrame(this._scheduledLayoutUpdateIdentifier); >+ this._scheduledLayoutUpdateIdentifier = undefined; >+ } >+ >+ this._svgElement.removeChildren(); >+ >+ for (let {x, y, width, height} of this._bars) { >+ let rect = this._svgElement.appendChild(createSVGElement("rect")); >+ rect.setAttribute("width", width); >+ rect.setAttribute("height", height); >+ rect.setAttribute("transform", `translate(${x}, ${y})`); >+ } >+ } >+}; >diff --git a/Source/WebInspectorUI/UserInterface/Views/ContentView.js b/Source/WebInspectorUI/UserInterface/Views/ContentView.js >index b151033f1d0..558e45e0246 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/ContentView.js >+++ b/Source/WebInspectorUI/UserInterface/Views/ContentView.js >@@ -83,6 +83,9 @@ WI.ContentView = class ContentView extends WI.View > if (timelineType === WI.TimelineRecord.Type.RenderingFrame) > return new WI.RenderingFrameTimelineView(representedObject, extraArguments); > >+ if (timelineType === WI.TimelineRecord.Type.CPU) >+ return new WI.CPUTimelineView(representedObject, extraArguments); >+ > if (timelineType === WI.TimelineRecord.Type.Memory) > return new WI.MemoryTimelineView(representedObject, extraArguments); > >diff --git a/Source/WebInspectorUI/UserInterface/Views/MemoryCategoryView.css b/Source/WebInspectorUI/UserInterface/Views/MemoryCategoryView.css >index e9446a1970a..739f3f1a1f6 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/MemoryCategoryView.css >+++ b/Source/WebInspectorUI/UserInterface/Views/MemoryCategoryView.css >@@ -31,21 +31,19 @@ > .memory-category-view > .details { > width: 150px; > padding-top: 10px; >- font-family: '-webkit-system-font'; >+ font-family: -webkit-system-font, sans-serif; > font-size: 12px; > color: hsl(0, 0%, 70%); >+ -webkit-padding-start: 15px; > >- --memory-category-view-details-padding-start: 15px; > --memory-category-view-details-border-end: 1px solid var(--border-color); > } > > body[dir=ltr] .memory-category-view > .details { >- padding-left: var(--memory-category-view-details-padding-start); > border-right: var(--memory-category-view-details-border-end); > } > > body[dir=rtl] .memory-category-view > .details { >- padding-right: var(--memory-category-view-details-padding-start); > border-left: var(--memory-category-view-details-border-end); > } > >diff --git a/Source/WebInspectorUI/UserInterface/Views/MemoryCategoryView.js b/Source/WebInspectorUI/UserInterface/Views/MemoryCategoryView.js >index 22d013780e5..89f6274d1d8 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/MemoryCategoryView.js >+++ b/Source/WebInspectorUI/UserInterface/Views/MemoryCategoryView.js >@@ -23,12 +23,10 @@ > * THE POSSIBILITY OF SUCH DAMAGE. > */ > >-WI.MemoryCategoryView = class MemoryCategoryView extends WI.Object >+WI.MemoryCategoryView = class MemoryCategoryView > { > constructor(category, displayName) > { >- super(); >- > console.assert(typeof category === "string"); > > this._category = category; >@@ -51,7 +49,7 @@ WI.MemoryCategoryView = class MemoryCategoryView extends WI.Object > this._graphElement = this._element.appendChild(document.createElement("div")); > this._graphElement.classList.add("graph"); > >- // FIXME: <https://webkit.org/b/153758> Web Inspector: Memory Timeline View should be responsive / resizable >+ // FIXME: <https://webkit.org/b/153758> Web Inspector: Memory / CPU Timeline Views should be responsive / resizable > let size = new WI.Size(800, 75); > this._chart = new WI.LineChart(size); > this._graphElement.appendChild(this._chart.element); >@@ -66,6 +64,7 @@ WI.MemoryCategoryView = class MemoryCategoryView extends WI.Object > { > this._cachedMinSize = undefined; > this._cachedMaxSize = undefined; >+ this._updateDetails(NaN, NaN); > > this._chart.clear(); > this._chart.needsLayout(); >diff --git a/Source/WebInspectorUI/UserInterface/Views/MemoryTimelineOverviewGraph.js b/Source/WebInspectorUI/UserInterface/Views/MemoryTimelineOverviewGraph.js >index 77f8b1d0678..1fa6401b5c0 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/MemoryTimelineOverviewGraph.js >+++ b/Source/WebInspectorUI/UserInterface/Views/MemoryTimelineOverviewGraph.js >@@ -27,12 +27,12 @@ WI.MemoryTimelineOverviewGraph = class MemoryTimelineOverviewGraph extends WI.Ti > { > constructor(timeline, timelineOverview) > { >+ console.assert(timeline instanceof WI.MemoryTimeline); >+ > super(timelineOverview); > > this.element.classList.add("memory"); > >- console.assert(timeline instanceof WI.MemoryTimeline); >- > this._memoryTimeline = timeline; > this._memoryTimeline.addEventListener(WI.Timeline.Event.RecordAdded, this._memoryTimelineRecordAdded, this); > this._memoryTimeline.addEventListener(WI.MemoryTimeline.Event.MemoryPressureEventAdded, this._memoryTimelineMemoryPressureEventAdded, this); >diff --git a/Source/WebInspectorUI/UserInterface/Views/MemoryTimelineView.css b/Source/WebInspectorUI/UserInterface/Views/MemoryTimelineView.css >index 6e642b3ec22..10e26b10256 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/MemoryTimelineView.css >+++ b/Source/WebInspectorUI/UserInterface/Views/MemoryTimelineView.css >@@ -39,7 +39,7 @@ > } > > .timeline-view.memory > .content .subtitle { >- font-family: '-webkit-system-font'; >+ font-family: -webkit-system-font, sans-serif; > font-size: 14px; > } > >diff --git a/Source/WebInspectorUI/UserInterface/Views/MemoryTimelineView.js b/Source/WebInspectorUI/UserInterface/Views/MemoryTimelineView.js >index f35a38b5dab..577e9051070 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/MemoryTimelineView.js >+++ b/Source/WebInspectorUI/UserInterface/Views/MemoryTimelineView.js >@@ -41,8 +41,7 @@ WI.MemoryTimelineView = class MemoryTimelineView extends WI.TimelineView > let overviewElement = contentElement.appendChild(document.createElement("div")); > overviewElement.classList.add("overview"); > >- function createChartContainer(parentElement, subtitle, tooltip) >- { >+ function createChartContainer(parentElement, subtitle, tooltip) { > let chartElement = parentElement.appendChild(document.createElement("div")); > chartElement.classList.add("chart"); > >@@ -120,11 +119,6 @@ WI.MemoryTimelineView = class MemoryTimelineView extends WI.TimelineView > this._timelineRuler.updateLayout(WI.View.LayoutReason.Resize); > } > >- hidden() >- { >- super.hidden(); >- } >- > closed() > { > console.assert(this.representedObject instanceof WI.Timeline); >@@ -200,7 +194,7 @@ WI.MemoryTimelineView = class MemoryTimelineView extends WI.TimelineView > this._maxComparisonCircleChart.updateLayout(); > this._updateMaxComparisonLegend(lastRecord.totalSize); > >- // FIXME: <https://webkit.org/b/153758> Web Inspector: Memory Timeline View should be responsive / resizable >+ // FIXME: <https://webkit.org/b/153758> Web Inspector: Memory / CPU Timeline Views should be responsive / resizable > const categoryViewWidth = 800; > const categoryViewHeight = 75; > >@@ -310,8 +304,10 @@ WI.MemoryTimelineView = class MemoryTimelineView extends WI.TimelineView > > _clearMaxComparisonLegend() > { >- this._maxComparisonMaximumSizeElement.textContent = emDash; >- this._maxComparisonCurrentSizeElement.textContent = emDash; >+ if (this._maxComparisonMaximumSizeElement) >+ this._maxComparisonMaximumSizeElement.textContent = emDash; >+ if (this._maxComparisonCurrentSizeElement) >+ this._maxComparisonCurrentSizeElement.textContent = emDash; > > let totalElement = this._maxComparisonCircleChart.centerElement.firstChild; > if (totalElement) >diff --git a/Source/WebInspectorUI/UserInterface/Views/ResourceSizesContentView.css b/Source/WebInspectorUI/UserInterface/Views/ResourceSizesContentView.css >index d7d3a40fc04..ce05f3e847c 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/ResourceSizesContentView.css >+++ b/Source/WebInspectorUI/UserInterface/Views/ResourceSizesContentView.css >@@ -24,7 +24,7 @@ > */ > > .resource-sizes { >- font-family: '-webkit-system-font'; >+ font-family: -webkit-system-font, sans-serif; > } > > .resource-sizes > .content { >diff --git a/Source/WebInspectorUI/UserInterface/Views/TimelineIcons.css b/Source/WebInspectorUI/UserInterface/Views/TimelineIcons.css >index 9ef65e0a7b3..ca8e893393f 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/TimelineIcons.css >+++ b/Source/WebInspectorUI/UserInterface/Views/TimelineIcons.css >@@ -31,6 +31,10 @@ > content: url(../Images/ScriptsInstrument.svg); > } > >+.cpu-icon .icon { >+ content: url(../Images/CPUInstrument.svg); >+} >+ > .memory-icon .icon { > content: url(../Images/MemoryInstrument.svg); > } >diff --git a/Source/WebInspectorUI/UserInterface/Views/TimelineOverviewGraph.js b/Source/WebInspectorUI/UserInterface/Views/TimelineOverviewGraph.js >index a0e12d696ae..1e9f2f1a7e6 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/TimelineOverviewGraph.js >+++ b/Source/WebInspectorUI/UserInterface/Views/TimelineOverviewGraph.js >@@ -63,6 +63,9 @@ WI.TimelineOverviewGraph = class TimelineOverviewGraph extends WI.View > if (timelineType === WI.TimelineRecord.Type.RenderingFrame) > return new WI.RenderingFrameTimelineOverviewGraph(timeline, timelineOverview); > >+ if (timelineType === WI.TimelineRecord.Type.CPU) >+ return new WI.CPUTimelineOverviewGraph(timeline, timelineOverview); >+ > if (timelineType === WI.TimelineRecord.Type.Memory) > return new WI.MemoryTimelineOverviewGraph(timeline, timelineOverview); > >diff --git a/Source/WebInspectorUI/UserInterface/Views/TimelineTabContentView.js b/Source/WebInspectorUI/UserInterface/Views/TimelineTabContentView.js >index c0adfb6efa1..1e91a77ffaa 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/TimelineTabContentView.js >+++ b/Source/WebInspectorUI/UserInterface/Views/TimelineTabContentView.js >@@ -116,6 +116,8 @@ WI.TimelineTabContentView = class TimelineTabContentView extends WI.ContentBrows > return WI.UIString("JavaScript & Events"); > case WI.TimelineRecord.Type.RenderingFrame: > return WI.UIString("Rendering Frames"); >+ case WI.TimelineRecord.Type.CPU: >+ return WI.UIString("CPU"); > case WI.TimelineRecord.Type.Memory: > return WI.UIString("Memory"); > case WI.TimelineRecord.Type.HeapAllocations: >@@ -136,6 +138,8 @@ WI.TimelineTabContentView = class TimelineTabContentView extends WI.ContentBrows > return "network-icon"; > case WI.TimelineRecord.Type.Layout: > return "layout-icon"; >+ case WI.TimelineRecord.Type.CPU: >+ return "cpu-icon"; > case WI.TimelineRecord.Type.Memory: > return "memory-icon"; > case WI.TimelineRecord.Type.HeapAllocations: >@@ -160,6 +164,8 @@ WI.TimelineTabContentView = class TimelineTabContentView extends WI.ContentBrows > return "network"; > case WI.TimelineRecord.Type.Layout: > return "colors"; >+ case WI.TimelineRecord.Type.CPU: >+ return "cpu"; > case WI.TimelineRecord.Type.Memory: > return "memory"; > case WI.TimelineRecord.Type.HeapAllocations: >@@ -248,6 +254,7 @@ WI.TimelineTabContentView = class TimelineTabContentView extends WI.ContentBrows > > break; > >+ case WI.TimelineRecord.Type.CPU: > case WI.TimelineRecord.Type.Memory: > // Not used. Fall through to error just in case. > >@@ -275,6 +282,7 @@ WI.TimelineTabContentView = class TimelineTabContentView extends WI.ContentBrows > return WI.UIString("Snapshot %d").format(timelineRecord.heapSnapshot.identifier); > case WI.TimelineRecord.Type.Media: > return timelineRecord.displayName; >+ case WI.TimelineRecord.Type.CPU: > case WI.TimelineRecord.Type.Memory: > // Not used. Fall through to error just in case. > default: >diff --git a/Source/WebInspectorUI/UserInterface/Views/Variables.css b/Source/WebInspectorUI/UserInterface/Views/Variables.css >index ea103b6b292..ef4c5542493 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/Variables.css >+++ b/Source/WebInspectorUI/UserInterface/Views/Variables.css >@@ -116,6 +116,9 @@ > --memory-max-comparison-fill-color: hsl(220, 10%, 75%); > --memory-max-comparison-stroke-color: hsl(220, 10%, 55%); > >+ --cpu-stroke-color: hsl(118, 33%, 42%); >+ --cpu-fill-color: hsl(118, 43%, 55%); >+ > --network-header-color: hsl(204, 52%, 55%); > --network-system-color: hsl(79, 32%, 50%); > --network-pseudo-header-color: hsl(312, 35%, 51%);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 193730
:
359925
|
359926
|
359927
|
359928
|
359929
|
359949
| 360044