1 | /* |
2 | * Copyright (C) 2016 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
23 | * THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #include "config.h" |
27 | #include "InspectorMemoryAgent.h" |
28 | |
29 | #if ENABLE(RESOURCE_USAGE) |
30 | |
31 | #include "InstrumentingAgents.h" |
32 | #include "ResourceUsageThread.h" |
33 | #include <JavaScriptCore/InspectorEnvironment.h> |
34 | #include <wtf/Stopwatch.h> |
35 | |
36 | |
37 | namespace WebCore { |
38 | |
39 | using namespace Inspector; |
40 | |
41 | InspectorMemoryAgent::InspectorMemoryAgent(PageAgentContext& context) |
42 | : InspectorAgentBase("Memory"_s , context) |
43 | , m_frontendDispatcher(std::make_unique<Inspector::MemoryFrontendDispatcher>(context.frontendRouter)) |
44 | , m_backendDispatcher(Inspector::MemoryBackendDispatcher::create(context.backendDispatcher, this)) |
45 | { |
46 | } |
47 | |
48 | void InspectorMemoryAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*) |
49 | { |
50 | m_instrumentingAgents.setInspectorMemoryAgent(this); |
51 | } |
52 | |
53 | void InspectorMemoryAgent::willDestroyFrontendAndBackend(DisconnectReason) |
54 | { |
55 | m_instrumentingAgents.setInspectorMemoryAgent(nullptr); |
56 | |
57 | ErrorString ignored; |
58 | stopTracking(ignored); |
59 | disable(ignored); |
60 | } |
61 | |
62 | void InspectorMemoryAgent::enable(ErrorString&) |
63 | { |
64 | m_enabled = true; |
65 | } |
66 | |
67 | void InspectorMemoryAgent::disable(ErrorString&) |
68 | { |
69 | m_enabled = false; |
70 | } |
71 | |
72 | void InspectorMemoryAgent::startTracking(ErrorString&) |
73 | { |
74 | if (m_tracking) |
75 | return; |
76 | |
77 | ResourceUsageThread::addObserver(this, Memory, [this] (const ResourceUsageData& data) { |
78 | collectSample(data); |
79 | }); |
80 | |
81 | m_tracking = true; |
82 | |
83 | m_frontendDispatcher->trackingStart(m_environment.executionStopwatch()->elapsedTime().seconds()); |
84 | } |
85 | |
86 | void InspectorMemoryAgent::stopTracking(ErrorString&) |
87 | { |
88 | if (!m_tracking) |
89 | return; |
90 | |
91 | ResourceUsageThread::removeObserver(this); |
92 | |
93 | m_tracking = false; |
94 | |
95 | m_frontendDispatcher->trackingComplete(m_environment.executionStopwatch()->elapsedTime().seconds()); |
96 | } |
97 | |
98 | void InspectorMemoryAgent::didHandleMemoryPressure(Critical critical) |
99 | { |
100 | if (!m_enabled) |
101 | return; |
102 | |
103 | MemoryFrontendDispatcher::Severity severity = critical == Critical::Yes ? MemoryFrontendDispatcher::Severity::Critical : MemoryFrontendDispatcher::Severity::NonCritical; |
104 | m_frontendDispatcher->memoryPressure(m_environment.executionStopwatch()->elapsedTime().seconds(), severity); |
105 | } |
106 | |
107 | void InspectorMemoryAgent::collectSample(const ResourceUsageData& data) |
108 | { |
109 | auto javascriptCategory = Protocol::Memory::CategoryData::create() |
110 | .setType(Protocol::Memory::CategoryData::Type::JavaScript) |
111 | .setSize(data.categories[MemoryCategory::GCHeap].totalSize() + data.categories[MemoryCategory::GCOwned].totalSize()) |
112 | .release(); |
113 | |
114 | auto jitCategory = Protocol::Memory::CategoryData::create() |
115 | .setType(Protocol::Memory::CategoryData::Type::JIT) |
116 | .setSize(data.categories[MemoryCategory::JSJIT].totalSize()) |
117 | .release(); |
118 | |
119 | auto imagesCategory = Protocol::Memory::CategoryData::create() |
120 | .setType(Protocol::Memory::CategoryData::Type::Images) |
121 | .setSize(data.categories[MemoryCategory::Images].totalSize()) |
122 | .release(); |
123 | |
124 | auto layersCategory = Protocol::Memory::CategoryData::create() |
125 | .setType(Protocol::Memory::CategoryData::Type::Layers) |
126 | .setSize(data.categories[MemoryCategory::Layers].totalSize()) |
127 | .release(); |
128 | |
129 | auto pageCategory = Protocol::Memory::CategoryData::create() |
130 | .setType(Protocol::Memory::CategoryData::Type::Page) |
131 | .setSize(data.categories[MemoryCategory::bmalloc].totalSize() + data.categories[MemoryCategory::LibcMalloc].totalSize()) |
132 | .release(); |
133 | |
134 | auto otherCategory = Protocol::Memory::CategoryData::create() |
135 | .setType(Protocol::Memory::CategoryData::Type::Other) |
136 | .setSize(data.categories[MemoryCategory::Other].totalSize()) |
137 | .release(); |
138 | |
139 | auto categories = JSON::ArrayOf<Protocol::Memory::CategoryData>::create(); |
140 | categories->addItem(WTFMove(javascriptCategory)); |
141 | categories->addItem(WTFMove(jitCategory)); |
142 | categories->addItem(WTFMove(imagesCategory)); |
143 | categories->addItem(WTFMove(layersCategory)); |
144 | categories->addItem(WTFMove(pageCategory)); |
145 | categories->addItem(WTFMove(otherCategory)); |
146 | |
147 | auto event = Protocol::Memory::Event::create() |
148 | .setTimestamp(m_environment.executionStopwatch()->elapsedTimeSince(data.timestamp).seconds()) |
149 | .setCategories(WTFMove(categories)) |
150 | .release(); |
151 | |
152 | m_frontendDispatcher->trackingUpdate(WTFMove(event)); |
153 | } |
154 | |
155 | } // namespace WebCore |
156 | |
157 | #endif // ENABLE(RESOURCE_USAGE) |
158 | |