OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/frame/PerformanceMonitor.h" | 5 #include "core/frame/PerformanceMonitor.h" |
6 | 6 |
7 #include "bindings/core/v8/ScheduledAction.h" | 7 #include "bindings/core/v8/ScheduledAction.h" |
8 #include "bindings/core/v8/ScriptEventListener.h" | 8 #include "bindings/core/v8/ScriptEventListener.h" |
9 #include "bindings/core/v8/SourceLocation.h" | 9 #include "bindings/core/v8/SourceLocation.h" |
| 10 #include "core/InstrumentingAgents.h" |
10 #include "core/dom/Document.h" | 11 #include "core/dom/Document.h" |
11 #include "core/dom/ExecutionContext.h" | 12 #include "core/dom/ExecutionContext.h" |
12 #include "core/events/EventListener.h" | 13 #include "core/events/EventListener.h" |
13 #include "core/frame/Frame.h" | 14 #include "core/frame/Frame.h" |
14 #include "core/frame/LocalFrame.h" | 15 #include "core/frame/LocalFrame.h" |
15 #include "core/html/parser/HTMLDocumentParser.h" | 16 #include "core/html/parser/HTMLDocumentParser.h" |
16 #include "public/platform/Platform.h" | 17 #include "public/platform/Platform.h" |
17 #include "wtf/CurrentTime.h" | 18 #include "wtf/CurrentTime.h" |
18 | 19 |
19 namespace blink { | 20 namespace blink { |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 return; | 55 return; |
55 --m_performanceMonitor->m_handlerDepth; | 56 --m_performanceMonitor->m_handlerDepth; |
56 if (!m_performanceMonitor->m_handlerDepth) { | 57 if (!m_performanceMonitor->m_handlerDepth) { |
57 m_performanceMonitor->m_handlerType = PerformanceMonitor::kAfterLast; | 58 m_performanceMonitor->m_handlerType = PerformanceMonitor::kAfterLast; |
58 m_performanceMonitor->m_handlerName = nullptr; | 59 m_performanceMonitor->m_handlerName = nullptr; |
59 m_performanceMonitor->m_handlerAtomicName = AtomicString(); | 60 m_performanceMonitor->m_handlerAtomicName = AtomicString(); |
60 } | 61 } |
61 } | 62 } |
62 | 63 |
63 // static | 64 // static |
64 void PerformanceMonitor::willExecuteScript(ExecutionContext* context) { | |
65 PerformanceMonitor* performanceMonitor = PerformanceMonitor::monitor(context); | |
66 if (performanceMonitor) | |
67 performanceMonitor->alwaysWillExecuteScript(context); | |
68 } | |
69 | |
70 // static | |
71 void PerformanceMonitor::didExecuteScript(ExecutionContext* context) { | |
72 PerformanceMonitor* performanceMonitor = PerformanceMonitor::monitor(context); | |
73 if (performanceMonitor) | |
74 performanceMonitor->alwaysDidExecuteScript(); | |
75 } | |
76 | |
77 // static | |
78 void PerformanceMonitor::willCallFunction(ExecutionContext* context) { | |
79 PerformanceMonitor* performanceMonitor = PerformanceMonitor::monitor(context); | |
80 if (performanceMonitor) | |
81 performanceMonitor->alwaysWillCallFunction(context); | |
82 } | |
83 | |
84 // static | |
85 void PerformanceMonitor::didCallFunction(ExecutionContext* context, | |
86 v8::Local<v8::Function> function) { | |
87 PerformanceMonitor* performanceMonitor = PerformanceMonitor::monitor(context); | |
88 if (performanceMonitor) | |
89 performanceMonitor->alwaysDidCallFunction(context, function); | |
90 } | |
91 | |
92 // static | |
93 void PerformanceMonitor::willUpdateLayout(Document* document) { | |
94 PerformanceMonitor* performanceMonitor = | |
95 PerformanceMonitor::instrumentingMonitor(document); | |
96 if (performanceMonitor) | |
97 performanceMonitor->willUpdateLayout(); | |
98 } | |
99 | |
100 // static | |
101 void PerformanceMonitor::didUpdateLayout(Document* document) { | |
102 PerformanceMonitor* performanceMonitor = | |
103 PerformanceMonitor::instrumentingMonitor(document); | |
104 if (performanceMonitor) | |
105 performanceMonitor->didUpdateLayout(); | |
106 } | |
107 | |
108 // static | |
109 void PerformanceMonitor::willRecalculateStyle(Document* document) { | |
110 PerformanceMonitor* performanceMonitor = | |
111 PerformanceMonitor::instrumentingMonitor(document); | |
112 if (performanceMonitor) | |
113 performanceMonitor->willRecalculateStyle(); | |
114 } | |
115 | |
116 // static | |
117 void PerformanceMonitor::didRecalculateStyle(Document* document) { | |
118 PerformanceMonitor* performanceMonitor = | |
119 PerformanceMonitor::instrumentingMonitor(document); | |
120 if (performanceMonitor) | |
121 performanceMonitor->didRecalculateStyle(); | |
122 } | |
123 | |
124 // static | |
125 void PerformanceMonitor::documentWriteFetchScript(Document* document) { | |
126 PerformanceMonitor* performanceMonitor = | |
127 PerformanceMonitor::instrumentingMonitor(document); | |
128 if (!performanceMonitor) | |
129 return; | |
130 String text = "Parser was blocked due to document.write(<script>)"; | |
131 performanceMonitor->innerReportGenericViolation(document, kBlockedParser, | |
132 text, 0, nullptr); | |
133 } | |
134 | |
135 // static | |
136 double PerformanceMonitor::threshold(ExecutionContext* context, | 65 double PerformanceMonitor::threshold(ExecutionContext* context, |
137 Violation violation) { | 66 Violation violation) { |
138 PerformanceMonitor* monitor = | 67 PerformanceMonitor* monitor = |
139 PerformanceMonitor::instrumentingMonitor(context); | 68 PerformanceMonitor::instrumentingMonitor(context); |
140 return monitor ? monitor->m_thresholds[violation] : 0; | 69 return monitor ? monitor->m_thresholds[violation] : 0; |
141 } | 70 } |
142 | 71 |
143 // static | 72 // static |
144 void PerformanceMonitor::reportGenericViolation( | 73 void PerformanceMonitor::reportGenericViolation( |
145 ExecutionContext* context, | 74 ExecutionContext* context, |
(...skipping 24 matching lines...) Expand all Loading... |
170 PerformanceMonitor* PerformanceMonitor::instrumentingMonitor( | 99 PerformanceMonitor* PerformanceMonitor::instrumentingMonitor( |
171 const ExecutionContext* context) { | 100 const ExecutionContext* context) { |
172 PerformanceMonitor* monitor = PerformanceMonitor::monitor(context); | 101 PerformanceMonitor* monitor = PerformanceMonitor::monitor(context); |
173 return monitor && monitor->m_enabled ? monitor : nullptr; | 102 return monitor && monitor->m_enabled ? monitor : nullptr; |
174 } | 103 } |
175 | 104 |
176 PerformanceMonitor::PerformanceMonitor(LocalFrame* localRoot) | 105 PerformanceMonitor::PerformanceMonitor(LocalFrame* localRoot) |
177 : m_localRoot(localRoot) { | 106 : m_localRoot(localRoot) { |
178 std::fill(std::begin(m_thresholds), std::end(m_thresholds), 0); | 107 std::fill(std::begin(m_thresholds), std::end(m_thresholds), 0); |
179 Platform::current()->currentThread()->addTaskTimeObserver(this); | 108 Platform::current()->currentThread()->addTaskTimeObserver(this); |
| 109 m_localRoot->instrumentingAgents()->addPerformanceMonitor(this); |
180 } | 110 } |
181 | 111 |
182 PerformanceMonitor::~PerformanceMonitor() { | 112 PerformanceMonitor::~PerformanceMonitor() { |
183 shutdown(); | 113 DCHECK(!m_localRoot); |
184 } | 114 } |
185 | 115 |
186 void PerformanceMonitor::subscribe(Violation violation, | 116 void PerformanceMonitor::subscribe(Violation violation, |
187 double threshold, | 117 double threshold, |
188 Client* client) { | 118 Client* client) { |
189 DCHECK(violation < kAfterLast); | 119 DCHECK(violation < kAfterLast); |
190 ClientThresholds* clientThresholds = m_subscriptions.at(violation); | 120 ClientThresholds* clientThresholds = m_subscriptions.at(violation); |
191 if (!clientThresholds) { | 121 if (!clientThresholds) { |
192 clientThresholds = new ClientThresholds(); | 122 clientThresholds = new ClientThresholds(); |
193 m_subscriptions.set(violation, clientThresholds); | 123 m_subscriptions.set(violation, clientThresholds); |
194 } | 124 } |
195 clientThresholds->set(client, threshold); | 125 clientThresholds->set(client, threshold); |
196 updateInstrumentation(); | 126 updateInstrumentation(); |
197 } | 127 } |
198 | 128 |
199 void PerformanceMonitor::unsubscribeAll(Client* client) { | 129 void PerformanceMonitor::unsubscribeAll(Client* client) { |
200 for (const auto& it : m_subscriptions) | 130 for (const auto& it : m_subscriptions) |
201 it.value->erase(client); | 131 it.value->erase(client); |
202 updateInstrumentation(); | 132 updateInstrumentation(); |
203 } | 133 } |
204 | 134 |
205 void PerformanceMonitor::shutdown() { | 135 void PerformanceMonitor::shutdown() { |
| 136 if (!m_localRoot) |
| 137 return; |
206 m_subscriptions.clear(); | 138 m_subscriptions.clear(); |
207 updateInstrumentation(); | 139 updateInstrumentation(); |
208 Platform::current()->currentThread()->removeTaskTimeObserver(this); | 140 Platform::current()->currentThread()->removeTaskTimeObserver(this); |
| 141 m_localRoot->instrumentingAgents()->removePerformanceMonitor(this); |
| 142 m_localRoot = nullptr; |
209 } | 143 } |
210 | 144 |
211 void PerformanceMonitor::updateInstrumentation() { | 145 void PerformanceMonitor::updateInstrumentation() { |
212 std::fill(std::begin(m_thresholds), std::end(m_thresholds), 0); | 146 std::fill(std::begin(m_thresholds), std::end(m_thresholds), 0); |
213 | 147 |
214 for (const auto& it : m_subscriptions) { | 148 for (const auto& it : m_subscriptions) { |
215 Violation violation = static_cast<Violation>(it.key); | 149 Violation violation = static_cast<Violation>(it.key); |
216 ClientThresholds* clientThresholds = it.value; | 150 ClientThresholds* clientThresholds = it.value; |
217 for (const auto& clientThreshold : *clientThresholds) { | 151 for (const auto& clientThreshold : *clientThresholds) { |
218 if (!m_thresholds[violation] || | 152 if (!m_thresholds[violation] || |
219 m_thresholds[violation] > clientThreshold.value) | 153 m_thresholds[violation] > clientThreshold.value) |
220 m_thresholds[violation] = clientThreshold.value; | 154 m_thresholds[violation] = clientThreshold.value; |
221 } | 155 } |
222 } | 156 } |
223 | 157 |
224 m_enabled = std::count(std::begin(m_thresholds), std::end(m_thresholds), 0) < | 158 m_enabled = std::count(std::begin(m_thresholds), std::end(m_thresholds), 0) < |
225 static_cast<int>(kAfterLast); | 159 static_cast<int>(kAfterLast); |
226 } | 160 } |
227 | 161 |
228 void PerformanceMonitor::alwaysWillExecuteScript(ExecutionContext* context) { | 162 void PerformanceMonitor::willExecuteScript(ExecutionContext* context) { |
229 // Heuristic for minimal frame context attribution: note the frame context | 163 // Heuristic for minimal frame context attribution: note the frame context |
230 // for each script execution. When a long task is encountered, | 164 // for each script execution. When a long task is encountered, |
231 // if there is only one frame context involved, then report it. | 165 // if there is only one frame context involved, then report it. |
232 // Otherwise don't report frame context. | 166 // Otherwise don't report frame context. |
233 // NOTE: This heuristic is imperfect and will be improved in V2 API. | 167 // NOTE: This heuristic is imperfect and will be improved in V2 API. |
234 // In V2, timing of script execution along with style & layout updates will be | 168 // In V2, timing of script execution along with style & layout updates will be |
235 // accounted for detailed and more accurate attribution. | 169 // accounted for detailed and more accurate attribution. |
236 ++m_scriptDepth; | 170 ++m_scriptDepth; |
237 if (!m_taskExecutionContext) | 171 if (!m_taskExecutionContext) |
238 m_taskExecutionContext = context; | 172 m_taskExecutionContext = context; |
239 else if (m_taskExecutionContext != context) | 173 else if (m_taskExecutionContext != context) |
240 m_taskHasMultipleContexts = true; | 174 m_taskHasMultipleContexts = true; |
241 } | 175 } |
242 | 176 |
243 void PerformanceMonitor::alwaysDidExecuteScript() { | 177 void PerformanceMonitor::didExecuteScript() { |
244 --m_scriptDepth; | 178 --m_scriptDepth; |
245 } | 179 } |
246 | 180 |
247 void PerformanceMonitor::alwaysWillCallFunction(ExecutionContext* context) { | 181 void PerformanceMonitor::willCallFunction(ExecutionContext* context) { |
248 alwaysWillExecuteScript(context); | 182 willExecuteScript(context); |
249 if (!m_enabled) | 183 if (!m_enabled) |
250 return; | 184 return; |
251 if (m_scriptDepth == 1 && m_thresholds[m_handlerType]) | 185 if (m_scriptDepth == 1 && m_thresholds[m_handlerType]) |
252 m_scriptStartTime = WTF::monotonicallyIncreasingTime(); | 186 m_scriptStartTime = WTF::monotonicallyIncreasingTime(); |
253 } | 187 } |
254 | 188 |
255 void PerformanceMonitor::alwaysDidCallFunction( | 189 void PerformanceMonitor::didCallFunction(ExecutionContext* context, |
256 ExecutionContext* context, | 190 v8::Local<v8::Function> function) { |
257 v8::Local<v8::Function> function) { | 191 didExecuteScript(); |
258 alwaysDidExecuteScript(); | |
259 if (!m_enabled) | 192 if (!m_enabled) |
260 return; | 193 return; |
261 if (m_scriptDepth) | 194 if (m_scriptDepth) |
262 return; | 195 return; |
263 if (m_handlerType == kAfterLast) | 196 if (m_handlerType == kAfterLast) |
264 return; | 197 return; |
265 double threshold = m_thresholds[m_handlerType]; | 198 double threshold = m_thresholds[m_handlerType]; |
266 if (!threshold) | 199 if (!threshold) |
267 return; | 200 return; |
268 | 201 |
269 double time = WTF::monotonicallyIncreasingTime() - m_scriptStartTime; | 202 double time = WTF::monotonicallyIncreasingTime() - m_scriptStartTime; |
270 if (time < threshold) | 203 if (time < threshold) |
271 return; | 204 return; |
272 String name = m_handlerName ? m_handlerName : m_handlerAtomicName; | 205 String name = m_handlerName ? m_handlerName : m_handlerAtomicName; |
273 String text = String::format("'%s' handler took %ldms", name.utf8().data(), | 206 String text = String::format("'%s' handler took %ldms", name.utf8().data(), |
274 lround(time * 1000)); | 207 lround(time * 1000)); |
275 innerReportGenericViolation(context, m_handlerType, text, time, | 208 innerReportGenericViolation(context, m_handlerType, text, time, |
276 SourceLocation::fromFunction(function)); | 209 SourceLocation::fromFunction(function)); |
277 } | 210 } |
278 | 211 |
279 void PerformanceMonitor::willUpdateLayout() { | 212 void PerformanceMonitor::willUpdateLayout() { |
| 213 if (!m_enabled) |
| 214 return; |
280 if (m_thresholds[kLongLayout] && m_scriptDepth && !m_layoutDepth) | 215 if (m_thresholds[kLongLayout] && m_scriptDepth && !m_layoutDepth) |
281 m_layoutStartTime = WTF::monotonicallyIncreasingTime(); | 216 m_layoutStartTime = WTF::monotonicallyIncreasingTime(); |
282 ++m_layoutDepth; | 217 ++m_layoutDepth; |
283 } | 218 } |
284 | 219 |
285 void PerformanceMonitor::didUpdateLayout() { | 220 void PerformanceMonitor::didUpdateLayout() { |
| 221 if (!m_enabled) |
| 222 return; |
286 --m_layoutDepth; | 223 --m_layoutDepth; |
287 if (m_thresholds[kLongLayout] && m_scriptDepth && !m_layoutDepth) { | 224 if (m_thresholds[kLongLayout] && m_scriptDepth && !m_layoutDepth) { |
288 m_perTaskStyleAndLayoutTime += | 225 m_perTaskStyleAndLayoutTime += |
289 WTF::monotonicallyIncreasingTime() - m_layoutStartTime; | 226 WTF::monotonicallyIncreasingTime() - m_layoutStartTime; |
290 } | 227 } |
291 } | 228 } |
292 | 229 |
293 void PerformanceMonitor::willRecalculateStyle() { | 230 void PerformanceMonitor::willRecalculateStyle(Document*) { |
| 231 if (!m_enabled) |
| 232 return; |
| 233 |
294 if (m_thresholds[kLongLayout] && m_scriptDepth) | 234 if (m_thresholds[kLongLayout] && m_scriptDepth) |
295 m_styleStartTime = WTF::monotonicallyIncreasingTime(); | 235 m_styleStartTime = WTF::monotonicallyIncreasingTime(); |
296 } | 236 } |
297 | 237 |
298 void PerformanceMonitor::didRecalculateStyle() { | 238 void PerformanceMonitor::didRecalculateStyle() { |
| 239 if (!m_enabled) |
| 240 return; |
299 if (m_thresholds[kLongLayout] && m_scriptDepth) { | 241 if (m_thresholds[kLongLayout] && m_scriptDepth) { |
300 m_perTaskStyleAndLayoutTime += | 242 m_perTaskStyleAndLayoutTime += |
301 WTF::monotonicallyIncreasingTime() - m_styleStartTime; | 243 WTF::monotonicallyIncreasingTime() - m_styleStartTime; |
302 } | 244 } |
303 } | 245 } |
304 | 246 |
| 247 void PerformanceMonitor::documentWriteFetchScript(Document* document) { |
| 248 if (!m_enabled) |
| 249 return; |
| 250 String text = "Parser was blocked due to document.write(<script>)"; |
| 251 innerReportGenericViolation(document, kBlockedParser, text, 0, nullptr); |
| 252 } |
| 253 |
305 void PerformanceMonitor::willProcessTask(scheduler::TaskQueue*, | 254 void PerformanceMonitor::willProcessTask(scheduler::TaskQueue*, |
306 double startTime) { | 255 double startTime) { |
307 // Reset m_taskExecutionContext. We don't clear this in didProcessTask | 256 // Reset m_taskExecutionContext. We don't clear this in didProcessTask |
308 // as it is needed in ReportTaskTime which occurs after didProcessTask. | 257 // as it is needed in ReportTaskTime which occurs after didProcessTask. |
309 m_taskExecutionContext = nullptr; | 258 m_taskExecutionContext = nullptr; |
310 m_taskHasMultipleContexts = false; | 259 m_taskHasMultipleContexts = false; |
311 | 260 |
312 if (!m_enabled) | 261 if (!m_enabled) |
313 return; | 262 return; |
314 m_scriptDepth = 0; | 263 m_scriptDepth = 0; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 } | 319 } |
371 } | 320 } |
372 | 321 |
373 DEFINE_TRACE(PerformanceMonitor) { | 322 DEFINE_TRACE(PerformanceMonitor) { |
374 visitor->trace(m_localRoot); | 323 visitor->trace(m_localRoot); |
375 visitor->trace(m_taskExecutionContext); | 324 visitor->trace(m_taskExecutionContext); |
376 visitor->trace(m_subscriptions); | 325 visitor->trace(m_subscriptions); |
377 } | 326 } |
378 | 327 |
379 } // namespace blink | 328 } // namespace blink |
OLD | NEW |