OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2010 Google Inc. All rights reserved. | 2 * Copyright (C) 2010 Google Inc. All rights reserved. |
3 * Copyright (C) 2012 Intel Inc. All rights reserved. | 3 * Copyright (C) 2012 Intel Inc. All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are | 6 * modification, are permitted provided that the following conditions are |
7 * met: | 7 * met: |
8 * | 8 * |
9 * * Redistributions of source code must retain the above copyright | 9 * * Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
(...skipping 17 matching lines...) Expand all Loading... | |
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 */ | 30 */ |
31 | 31 |
32 #include "config.h" | 32 #include "config.h" |
33 #include "core/timing/PerformanceBase.h" | 33 #include "core/timing/PerformanceBase.h" |
34 | 34 |
35 #include "core/dom/Document.h" | 35 #include "core/dom/Document.h" |
36 #include "core/events/Event.h" | 36 #include "core/events/Event.h" |
37 #include "core/timing/PerformanceCompositeTiming.h" | 37 #include "core/timing/PerformanceCompositeTiming.h" |
38 #include "core/timing/PerformanceObserver.h" | |
38 #include "core/timing/PerformanceRenderTiming.h" | 39 #include "core/timing/PerformanceRenderTiming.h" |
39 #include "core/timing/PerformanceResourceTiming.h" | 40 #include "core/timing/PerformanceResourceTiming.h" |
40 #include "core/timing/PerformanceUserTiming.h" | 41 #include "core/timing/PerformanceUserTiming.h" |
41 #include "platform/network/ResourceTimingInfo.h" | 42 #include "platform/network/ResourceTimingInfo.h" |
42 #include "platform/weborigin/SecurityOrigin.h" | 43 #include "platform/weborigin/SecurityOrigin.h" |
43 #include "wtf/CurrentTime.h" | 44 #include "wtf/CurrentTime.h" |
44 | 45 |
45 namespace blink { | 46 namespace blink { |
46 | 47 |
48 using PerformanceObserverVector = HeapVector<Member<PerformanceObserver>>; | |
49 | |
47 static const size_t defaultResourceTimingBufferSize = 150; | 50 static const size_t defaultResourceTimingBufferSize = 150; |
48 static const size_t defaultFrameTimingBufferSize = 150; | 51 static const size_t defaultFrameTimingBufferSize = 150; |
49 | 52 |
50 PerformanceBase::PerformanceBase(double timeOrigin) | 53 PerformanceBase::PerformanceBase(double timeOrigin) |
51 : m_frameTimingBufferSize(defaultFrameTimingBufferSize) | 54 : m_frameTimingBufferSize(defaultFrameTimingBufferSize) |
52 , m_resourceTimingBufferSize(defaultResourceTimingBufferSize) | 55 , m_resourceTimingBufferSize(defaultResourceTimingBufferSize) |
53 , m_timeOrigin(timeOrigin) | 56 , m_timeOrigin(timeOrigin) |
54 , m_userTiming(nullptr) | 57 , m_userTiming(nullptr) |
58 , m_observerFilterOptions(PerformanceEntry::Invalid) | |
59 , m_deliverObservationsTimer(this, &PerformanceBase::deliverObservationsTime rFired) | |
55 { | 60 { |
56 } | 61 } |
57 | 62 |
58 PerformanceBase::~PerformanceBase() | 63 PerformanceBase::~PerformanceBase() |
59 { | 64 { |
60 } | 65 } |
61 | 66 |
62 const AtomicString& PerformanceBase::interfaceName() const | 67 const AtomicString& PerformanceBase::interfaceName() const |
63 { | 68 { |
64 return EventTargetNames::Performance; | 69 return EventTargetNames::Performance; |
(...skipping 16 matching lines...) Expand all Loading... | |
81 entries.appendVector(m_userTiming->getMeasures()); | 86 entries.appendVector(m_userTiming->getMeasures()); |
82 } | 87 } |
83 | 88 |
84 std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompare LessThan); | 89 std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompare LessThan); |
85 return entries; | 90 return entries; |
86 } | 91 } |
87 | 92 |
88 PerformanceEntryVector PerformanceBase::getEntriesByType(const String& entryType ) | 93 PerformanceEntryVector PerformanceBase::getEntriesByType(const String& entryType ) |
89 { | 94 { |
90 PerformanceEntryVector entries; | 95 PerformanceEntryVector entries; |
96 PerformanceEntry::EntryType type = PerformanceEntry::toEntryTypeEnum(entryTy pe); | |
91 | 97 |
92 if (equalIgnoringCase(entryType, "resource")) { | 98 if (type == PerformanceEntry::Invalid) |
esprehn
2015/09/09 22:41:40
This should be a switch() over the type.
MikeB
2015/09/10 19:53:01
Done.
| |
99 return entries; | |
100 | |
101 if (type == PerformanceEntry::Resource) { | |
93 for (const auto& resource : m_resourceTimingBuffer) | 102 for (const auto& resource : m_resourceTimingBuffer) |
94 entries.append(resource); | 103 entries.append(resource); |
95 } | 104 } |
96 | 105 |
97 if (equalIgnoringCase(entryType, "composite") | 106 if (type == PerformanceEntry::Composite || type == PerformanceEntry::Render) { |
98 || equalIgnoringCase(entryType, "render")) { | |
99 for (const auto& frame : m_frameTimingBuffer) { | 107 for (const auto& frame : m_frameTimingBuffer) { |
100 if (equalIgnoringCase(entryType, frame->entryType())) { | 108 if (type == frame->entryTypeEnum()) { |
101 entries.append(frame); | 109 entries.append(frame); |
102 } | 110 } |
103 } | 111 } |
104 } | 112 } |
105 | 113 |
106 if (m_userTiming) { | 114 if (m_userTiming) { |
107 if (equalIgnoringCase(entryType, "mark")) | 115 if (type == PerformanceEntry::Mark) |
108 entries.appendVector(m_userTiming->getMarks()); | 116 entries.appendVector(m_userTiming->getMarks()); |
109 else if (equalIgnoringCase(entryType, "measure")) | 117 else if (type == PerformanceEntry::Measure) |
110 entries.appendVector(m_userTiming->getMeasures()); | 118 entries.appendVector(m_userTiming->getMeasures()); |
111 } | 119 } |
112 | 120 |
113 std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompare LessThan); | 121 std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompare LessThan); |
114 return entries; | 122 return entries; |
115 } | 123 } |
116 | 124 |
117 PerformanceEntryVector PerformanceBase::getEntriesByName(const String& name, con st String& entryType) | 125 PerformanceEntryVector PerformanceBase::getEntriesByName(const String& name, con st String& entryType) |
118 { | 126 { |
119 PerformanceEntryVector entries; | 127 PerformanceEntryVector entries; |
128 PerformanceEntry::EntryType type = PerformanceEntry::toEntryTypeEnum(entryTy pe); | |
120 | 129 |
121 if (entryType.isNull() || equalIgnoringCase(entryType, "resource")) { | 130 if (!entryType.isNull() && type == PerformanceEntry::Invalid) |
131 return entries; | |
132 | |
133 if (entryType.isNull() || type == PerformanceEntry::Resource) { | |
122 for (const auto& resource : m_resourceTimingBuffer) { | 134 for (const auto& resource : m_resourceTimingBuffer) { |
123 if (resource->name() == name) | 135 if (resource->name() == name) |
124 entries.append(resource); | 136 entries.append(resource); |
125 } | 137 } |
126 } | 138 } |
127 | 139 |
128 if (entryType.isNull() || equalIgnoringCase(entryType, "composite") | 140 if (entryType.isNull() || type == PerformanceEntry::Composite || type == Per formanceEntry::Render) { |
129 || equalIgnoringCase(entryType, "render")) { | |
130 for (const auto& frame : m_frameTimingBuffer) { | 141 for (const auto& frame : m_frameTimingBuffer) { |
131 if (frame->name() == name && (entryType.isNull() | 142 if (frame->name() == name && (entryType.isNull() |
132 || equalIgnoringCase(entryType, frame->entryType()))) { | 143 || equalIgnoringCase(entryType, frame->entryType()))) { |
133 entries.append(frame); | 144 entries.append(frame); |
134 } | 145 } |
135 } | 146 } |
136 } | 147 } |
137 | 148 |
138 if (m_userTiming) { | 149 if (m_userTiming) { |
139 if (entryType.isNull() || equalIgnoringCase(entryType, "mark")) | 150 if (entryType.isNull() || type == PerformanceEntry::Mark) |
140 entries.appendVector(m_userTiming->getMarks(name)); | 151 entries.appendVector(m_userTiming->getMarks(name)); |
141 if (entryType.isNull() || equalIgnoringCase(entryType, "measure")) | 152 if (entryType.isNull() || type == PerformanceEntry::Measure) |
142 entries.appendVector(m_userTiming->getMeasures(name)); | 153 entries.appendVector(m_userTiming->getMeasures(name)); |
143 } | 154 } |
144 | 155 |
145 std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompare LessThan); | 156 std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompare LessThan); |
146 return entries; | 157 return entries; |
147 } | 158 } |
148 | 159 |
149 void PerformanceBase::clearResourceTimings() | 160 void PerformanceBase::clearResourceTimings() |
150 { | 161 { |
151 m_resourceTimingBuffer.clear(); | 162 m_resourceTimingBuffer.clear(); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
206 for (const ResourceResponse& response : redirectChain) { | 217 for (const ResourceResponse& response : redirectChain) { |
207 if (!passesTimingAllowCheck(response, initiatorSecurityOrigin, emptyAtom )) | 218 if (!passesTimingAllowCheck(response, initiatorSecurityOrigin, emptyAtom )) |
208 return false; | 219 return false; |
209 } | 220 } |
210 | 221 |
211 return true; | 222 return true; |
212 } | 223 } |
213 | 224 |
214 void PerformanceBase::addResourceTiming(const ResourceTimingInfo& info) | 225 void PerformanceBase::addResourceTiming(const ResourceTimingInfo& info) |
215 { | 226 { |
216 if (isResourceTimingBufferFull()) | 227 if (isResourceTimingBufferFull() && !hasObserverFor(PerformanceEntry::Resour ce)) |
217 return; | 228 return; |
218 SecurityOrigin* securityOrigin = nullptr; | 229 SecurityOrigin* securityOrigin = nullptr; |
219 if (ExecutionContext* context = executionContext()) | 230 if (ExecutionContext* context = executionContext()) |
220 securityOrigin = context->securityOrigin(); | 231 securityOrigin = context->securityOrigin(); |
221 if (!securityOrigin) | 232 if (!securityOrigin) |
222 return; | 233 return; |
223 | 234 |
224 const ResourceResponse& finalResponse = info.finalResponse(); | 235 const ResourceResponse& finalResponse = info.finalResponse(); |
225 bool allowTimingDetails = passesTimingAllowCheck(finalResponse, *securityOri gin, info.originalTimingAllowOrigin()); | 236 bool allowTimingDetails = passesTimingAllowCheck(finalResponse, *securityOri gin, info.originalTimingAllowOrigin()); |
226 double startTime = info.initialTime(); | 237 double startTime = info.initialTime(); |
227 | 238 |
228 if (info.redirectChain().isEmpty()) { | 239 if (info.redirectChain().isEmpty()) { |
229 PerformanceEntry* entry = PerformanceResourceTiming::create(info, timeOr igin(), startTime, allowTimingDetails); | 240 PerformanceEntry* entry = PerformanceResourceTiming::create(info, timeOr igin(), startTime, allowTimingDetails); |
230 addResourceTimingBuffer(entry); | 241 addResourceTimingBuffer(*entry); |
231 return; | 242 return; |
232 } | 243 } |
233 | 244 |
234 const Vector<ResourceResponse>& redirectChain = info.redirectChain(); | 245 const Vector<ResourceResponse>& redirectChain = info.redirectChain(); |
235 bool allowRedirectDetails = allowsTimingRedirect(redirectChain, finalRespons e, *securityOrigin); | 246 bool allowRedirectDetails = allowsTimingRedirect(redirectChain, finalRespons e, *securityOrigin); |
236 | 247 |
237 if (!allowRedirectDetails) { | 248 if (!allowRedirectDetails) { |
238 ResourceLoadTiming* finalTiming = finalResponse.resourceLoadTiming(); | 249 ResourceLoadTiming* finalTiming = finalResponse.resourceLoadTiming(); |
239 ASSERT(finalTiming); | 250 ASSERT(finalTiming); |
240 if (finalTiming) | 251 if (finalTiming) |
241 startTime = finalTiming->requestTime(); | 252 startTime = finalTiming->requestTime(); |
242 } | 253 } |
243 | 254 |
244 ResourceLoadTiming* lastRedirectTiming = redirectChain.last().resourceLoadTi ming(); | 255 ResourceLoadTiming* lastRedirectTiming = redirectChain.last().resourceLoadTi ming(); |
245 ASSERT(lastRedirectTiming); | 256 ASSERT(lastRedirectTiming); |
246 double lastRedirectEndTime = lastRedirectTiming->receiveHeadersEnd(); | 257 double lastRedirectEndTime = lastRedirectTiming->receiveHeadersEnd(); |
247 | 258 |
248 PerformanceEntry* entry = PerformanceResourceTiming::create(info, timeOrigin (), startTime, lastRedirectEndTime, allowTimingDetails, allowRedirectDetails); | 259 PerformanceEntry* entry = PerformanceResourceTiming::create(info, timeOrigin (), startTime, lastRedirectEndTime, allowTimingDetails, allowRedirectDetails); |
249 addResourceTimingBuffer(entry); | 260 notifyObserversOfEntry(*entry); |
261 if (!isResourceTimingBufferFull()) | |
262 addResourceTimingBuffer(*entry); | |
250 } | 263 } |
251 | 264 |
252 void PerformanceBase::addResourceTimingBuffer(PerformanceEntry* entry) | 265 void PerformanceBase::addResourceTimingBuffer(PerformanceEntry& entry) |
253 { | 266 { |
254 m_resourceTimingBuffer.append(entry); | 267 m_resourceTimingBuffer.append(&entry); |
255 | 268 |
256 if (isResourceTimingBufferFull()) { | 269 if (isResourceTimingBufferFull()) { |
257 dispatchEvent(Event::create(EventTypeNames::resourcetimingbufferfull)); | 270 dispatchEvent(Event::create(EventTypeNames::resourcetimingbufferfull)); |
258 dispatchEvent(Event::create(EventTypeNames::webkitresourcetimingbufferfu ll)); | 271 dispatchEvent(Event::create(EventTypeNames::webkitresourcetimingbufferfu ll)); |
259 } | 272 } |
260 } | 273 } |
261 | 274 |
262 bool PerformanceBase::isResourceTimingBufferFull() | 275 bool PerformanceBase::isResourceTimingBufferFull() |
263 { | 276 { |
264 return m_resourceTimingBuffer.size() >= m_resourceTimingBufferSize; | 277 return m_resourceTimingBuffer.size() >= m_resourceTimingBufferSize; |
265 } | 278 } |
266 | 279 |
267 void PerformanceBase::addRenderTiming(Document* initiatorDocument, unsigned sour ceFrame, double startTime, double finishTime) | 280 void PerformanceBase::addRenderTiming(Document* initiatorDocument, unsigned sour ceFrame, double startTime, double finishTime) |
268 { | 281 { |
269 if (isFrameTimingBufferFull()) | 282 if (isFrameTimingBufferFull() && !hasObserverFor(PerformanceEntry::Render)) |
270 return; | 283 return; |
271 | 284 |
272 PerformanceEntry* entry = PerformanceRenderTiming::create(initiatorDocument, sourceFrame, startTime, finishTime); | 285 PerformanceEntry* entry = PerformanceRenderTiming::create(initiatorDocument, sourceFrame, startTime, finishTime); |
273 addFrameTimingBuffer(entry); | 286 notifyObserversOfEntry(*entry); |
287 if (!isFrameTimingBufferFull()) | |
288 addFrameTimingBuffer(*entry); | |
274 } | 289 } |
275 | 290 |
276 void PerformanceBase::addCompositeTiming(Document* initiatorDocument, unsigned s ourceFrame, double startTime) | 291 void PerformanceBase::addCompositeTiming(Document* initiatorDocument, unsigned s ourceFrame, double startTime) |
277 { | 292 { |
278 if (isFrameTimingBufferFull()) | 293 if (isFrameTimingBufferFull() && !hasObserverFor(PerformanceEntry::Composite )) |
279 return; | 294 return; |
280 | 295 |
281 PerformanceEntry* entry = PerformanceCompositeTiming::create(initiatorDocume nt, sourceFrame, startTime); | 296 PerformanceEntry* entry = PerformanceCompositeTiming::create(initiatorDocume nt, sourceFrame, startTime); |
282 addFrameTimingBuffer(entry); | 297 notifyObserversOfEntry(*entry); |
298 if (!isFrameTimingBufferFull()) | |
299 addFrameTimingBuffer(*entry); | |
283 } | 300 } |
284 | 301 |
285 void PerformanceBase::addFrameTimingBuffer(PerformanceEntry* entry) | 302 void PerformanceBase::addFrameTimingBuffer(PerformanceEntry& entry) |
286 { | 303 { |
287 m_frameTimingBuffer.append(entry); | 304 m_frameTimingBuffer.append(&entry); |
288 | 305 |
289 if (isFrameTimingBufferFull()) | 306 if (isFrameTimingBufferFull()) |
290 dispatchEvent(Event::create(EventTypeNames::frametimingbufferfull)); | 307 dispatchEvent(Event::create(EventTypeNames::frametimingbufferfull)); |
291 } | 308 } |
292 | 309 |
293 bool PerformanceBase::isFrameTimingBufferFull() | 310 bool PerformanceBase::isFrameTimingBufferFull() |
294 { | 311 { |
295 return m_frameTimingBuffer.size() >= m_frameTimingBufferSize; | 312 return m_frameTimingBuffer.size() >= m_frameTimingBufferSize; |
296 } | 313 } |
297 | 314 |
298 void PerformanceBase::mark(const String& markName, ExceptionState& exceptionStat e) | 315 void PerformanceBase::mark(const String& markName, ExceptionState& exceptionStat e) |
299 { | 316 { |
300 if (!m_userTiming) | 317 if (!m_userTiming) |
301 m_userTiming = UserTiming::create(this); | 318 m_userTiming = UserTiming::create(*this); |
302 m_userTiming->mark(markName, exceptionState); | 319 if (PerformanceEntry* entry = m_userTiming->mark(markName, exceptionState)) |
320 notifyObserversOfEntry(*entry); | |
303 } | 321 } |
304 | 322 |
305 void PerformanceBase::clearMarks(const String& markName) | 323 void PerformanceBase::clearMarks(const String& markName) |
306 { | 324 { |
307 if (!m_userTiming) | 325 if (!m_userTiming) |
308 m_userTiming = UserTiming::create(this); | 326 m_userTiming = UserTiming::create(*this); |
309 m_userTiming->clearMarks(markName); | 327 m_userTiming->clearMarks(markName); |
310 } | 328 } |
311 | 329 |
312 void PerformanceBase::measure(const String& measureName, const String& startMark , const String& endMark, ExceptionState& exceptionState) | 330 void PerformanceBase::measure(const String& measureName, const String& startMark , const String& endMark, ExceptionState& exceptionState) |
313 { | 331 { |
314 if (!m_userTiming) | 332 if (!m_userTiming) |
315 m_userTiming = UserTiming::create(this); | 333 m_userTiming = UserTiming::create(*this); |
316 m_userTiming->measure(measureName, startMark, endMark, exceptionState); | 334 if (PerformanceEntry* entry = m_userTiming->measure(measureName, startMark, endMark, exceptionState)) |
335 notifyObserversOfEntry(*entry); | |
317 } | 336 } |
318 | 337 |
319 void PerformanceBase::clearMeasures(const String& measureName) | 338 void PerformanceBase::clearMeasures(const String& measureName) |
320 { | 339 { |
321 if (!m_userTiming) | 340 if (!m_userTiming) |
322 m_userTiming = UserTiming::create(this); | 341 m_userTiming = UserTiming::create(*this); |
323 m_userTiming->clearMeasures(measureName); | 342 m_userTiming->clearMeasures(measureName); |
324 } | 343 } |
325 | 344 |
345 void PerformanceBase::registerPerformanceObserver(PerformanceObserver& observer) | |
346 { | |
347 m_observerFilterOptions |= observer.filterOptions(); | |
348 m_observers.add(&observer); | |
349 } | |
350 | |
351 void PerformanceBase::unregisterPerformanceObserver(PerformanceObserver& oldObse rver) | |
352 { | |
353 m_observers.remove(&oldObserver); | |
354 updatePerformanceObserverFilterOptions(); | |
355 } | |
356 | |
357 void PerformanceBase::updatePerformanceObserverFilterOptions() | |
358 { | |
359 m_observerFilterOptions = PerformanceEntry::Invalid; | |
360 for (const auto& observer : m_observers) { | |
361 m_observerFilterOptions |= observer->filterOptions(); | |
362 } | |
363 } | |
364 | |
365 void PerformanceBase::notifyObserversOfEntry(PerformanceEntry& entry) | |
366 { | |
367 for (auto& observer : m_observers) { | |
368 if (observer->filterOptions() & entry.entryTypeEnum()) | |
369 observer->enqueuePerformanceEntry(entry); | |
370 } | |
371 } | |
372 | |
373 bool PerformanceBase::hasObserverFor(PerformanceEntry::EntryType filterType) | |
374 { | |
375 return m_observerFilterOptions & filterType; | |
376 } | |
377 | |
378 void PerformanceBase::activateObserver(PerformanceObserver& observer) | |
379 { | |
380 if (m_activeObservers.isEmpty()) | |
381 m_deliverObservationsTimer.startOneShot(0, FROM_HERE); | |
382 | |
383 m_activeObservers.add(&observer); | |
384 } | |
385 | |
386 void PerformanceBase::resumeSuspendedObservers() | |
387 { | |
388 ASSERT(isMainThread()); | |
389 if (m_suspendedObservers.isEmpty()) | |
390 return; | |
391 | |
392 PerformanceObserverVector suspended; | |
393 copyToVector(m_suspendedObservers, suspended); | |
394 for (size_t i = 0; i < suspended.size(); ++i) { | |
395 if (!suspended[i]->shouldBeSuspended()) { | |
396 m_suspendedObservers.remove(suspended[i]); | |
397 activateObserver(*suspended[i]); | |
398 } | |
399 } | |
400 } | |
401 | |
402 void PerformanceBase::deliverObservationsTimerFired(Timer<PerformanceBase>*) | |
403 { | |
404 ASSERT(isMainThread()); | |
405 PerformanceObserverVector observers; | |
406 copyToVector(m_activeObservers, observers); | |
407 m_activeObservers.clear(); | |
408 for (size_t i = 0; i < observers.size(); ++i) { | |
409 if (observers[i]->shouldBeSuspended()) | |
410 m_suspendedObservers.add(observers[i]); | |
411 else | |
412 observers[i]->deliver(); | |
413 } | |
414 } | |
415 | |
326 double PerformanceBase::now() const | 416 double PerformanceBase::now() const |
327 { | 417 { |
328 double nowSeconds = monotonicallyIncreasingTime() - m_timeOrigin; | 418 double nowSeconds = monotonicallyIncreasingTime() - m_timeOrigin; |
329 const double resolutionSeconds = 0.000005; | 419 const double resolutionSeconds = 0.000005; |
330 return 1000.0 * floor(nowSeconds / resolutionSeconds) * resolutionSeconds; | 420 return 1000.0 * floor(nowSeconds / resolutionSeconds) * resolutionSeconds; |
331 } | 421 } |
332 | 422 |
333 DEFINE_TRACE(PerformanceBase) | 423 DEFINE_TRACE(PerformanceBase) |
334 { | 424 { |
335 visitor->trace(m_frameTimingBuffer); | 425 visitor->trace(m_frameTimingBuffer); |
336 visitor->trace(m_resourceTimingBuffer); | 426 visitor->trace(m_resourceTimingBuffer); |
337 visitor->trace(m_userTiming); | 427 visitor->trace(m_userTiming); |
428 visitor->trace(m_observers); | |
429 visitor->trace(m_activeObservers); | |
430 visitor->trace(m_suspendedObservers); | |
338 RefCountedGarbageCollectedEventTargetWithInlineData<PerformanceBase>::trace( visitor); | 431 RefCountedGarbageCollectedEventTargetWithInlineData<PerformanceBase>::trace( visitor); |
339 } | 432 } |
340 | 433 |
341 } // namespace blink | 434 } // namespace blink |
OLD | NEW |