3283c9aa35b058784be6630bc40553645d493a02
[WebKit-https.git] / Source / WebCore / page / Performance.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  * Copyright (C) 2012 Intel Inc. All rights reserved.
4  * Copyright (C) 2016 Apple Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above
13  * copyright notice, this list of conditions and the following disclaimer
14  * in the documentation and/or other materials provided with the
15  * distribution.
16  *     * Neither the name of Google Inc. nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "config.h"
34 #include "Performance.h"
35
36 #if ENABLE(WEB_TIMING)
37
38 #include "Document.h"
39 #include "DocumentLoader.h"
40 #include "EventNames.h"
41 #include "Frame.h"
42 #include "PerformanceEntry.h"
43 #include "PerformanceNavigation.h"
44 #include "PerformanceObserver.h"
45 #include "PerformanceResourceTiming.h"
46 #include "PerformanceTiming.h"
47 #include "PerformanceUserTiming.h"
48 #include "ResourceResponse.h"
49 #include <wtf/CurrentTime.h>
50
51 namespace WebCore {
52
53 Performance::Performance(Frame& frame)
54     : DOMWindowProperty(&frame)
55     , m_referenceTime(frame.document()->loader() ? frame.document()->loader()->timing().referenceMonotonicTime() : monotonicallyIncreasingTime())
56 {
57     ASSERT(m_referenceTime);
58 }
59
60 Performance::~Performance()
61 {
62 }
63
64 ScriptExecutionContext* Performance::scriptExecutionContext() const
65 {
66     if (!frame())
67         return nullptr;
68     return frame()->document();
69 }
70
71 PerformanceNavigation& Performance::navigation()
72 {
73     if (!m_navigation)
74         m_navigation = PerformanceNavigation::create(m_frame);
75     return *m_navigation;
76 }
77
78 PerformanceTiming& Performance::timing()
79 {
80     if (!m_timing)
81         m_timing = PerformanceTiming::create(m_frame);
82     return *m_timing;
83 }
84
85 Vector<RefPtr<PerformanceEntry>> Performance::getEntries() const
86 {
87     Vector<RefPtr<PerformanceEntry>> entries;
88
89     entries.appendVector(m_resourceTimingBuffer);
90
91     if (m_userTiming) {
92         entries.appendVector(m_userTiming->getMarks());
93         entries.appendVector(m_userTiming->getMeasures());
94     }
95
96     std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompareLessThan);
97     return entries;
98 }
99
100 Vector<RefPtr<PerformanceEntry>> Performance::getEntriesByType(const String& entryType) const
101 {
102     Vector<RefPtr<PerformanceEntry>> entries;
103
104     if (equalLettersIgnoringASCIICase(entryType, "resource"))
105         entries.appendVector(m_resourceTimingBuffer);
106
107     if (m_userTiming) {
108         if (equalLettersIgnoringASCIICase(entryType, "mark"))
109             entries.appendVector(m_userTiming->getMarks());
110         else if (equalLettersIgnoringASCIICase(entryType, "measure"))
111             entries.appendVector(m_userTiming->getMeasures());
112     }
113
114     std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompareLessThan);
115     return entries;
116 }
117
118 Vector<RefPtr<PerformanceEntry>> Performance::getEntriesByName(const String& name, const String& entryType) const
119 {
120     Vector<RefPtr<PerformanceEntry>> entries;
121
122     if (entryType.isNull() || equalLettersIgnoringASCIICase(entryType, "resource")) {
123         for (auto& resource : m_resourceTimingBuffer) {
124             if (resource->name() == name)
125                 entries.append(resource);
126         }
127     }
128
129     if (m_userTiming) {
130         if (entryType.isNull() || equalLettersIgnoringASCIICase(entryType, "mark"))
131             entries.appendVector(m_userTiming->getMarks(name));
132         if (entryType.isNull() || equalLettersIgnoringASCIICase(entryType, "measure"))
133             entries.appendVector(m_userTiming->getMeasures(name));
134     }
135
136     std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompareLessThan);
137     return entries;
138 }
139
140 void Performance::clearResourceTimings()
141 {
142     m_resourceTimingBuffer.clear();
143 }
144
145 void Performance::setResourceTimingBufferSize(unsigned size)
146 {
147     m_resourceTimingBufferSize = size;
148
149     if (isResourceTimingBufferFull())
150         dispatchEvent(Event::create(eventNames().resourcetimingbufferfullEvent, false, false));
151 }
152
153 void Performance::addResourceTiming(const String& initiatorName, Document* initiatorDocument, const URL& originalURL, const ResourceResponse& response, const LoadTiming& loadTiming)
154 {
155     if (isResourceTimingBufferFull())
156         return;
157
158     RefPtr<PerformanceEntry> entry = PerformanceResourceTiming::create(initiatorName, originalURL, response, loadTiming, initiatorDocument);
159
160     m_resourceTimingBuffer.append(entry);
161
162     if (isResourceTimingBufferFull())
163         dispatchEvent(Event::create(eventNames().resourcetimingbufferfullEvent, false, false));
164 }
165
166 bool Performance::isResourceTimingBufferFull() const
167 {
168     return m_resourceTimingBuffer.size() >= m_resourceTimingBufferSize;
169 }
170
171 ExceptionOr<void> Performance::mark(const String& markName)
172 {
173     if (!m_userTiming)
174         m_userTiming = std::make_unique<UserTiming>(*this);
175
176     auto result = m_userTiming->mark(markName);
177     if (result.hasException())
178         return result.releaseException();
179
180     queueEntry(result.releaseReturnValue());
181
182     return { };
183 }
184
185 void Performance::clearMarks(const String& markName)
186 {
187     if (!m_userTiming)
188         m_userTiming = std::make_unique<UserTiming>(*this);
189     m_userTiming->clearMarks(markName);
190 }
191
192 ExceptionOr<void> Performance::measure(const String& measureName, const String& startMark, const String& endMark)
193 {
194     if (!m_userTiming)
195         m_userTiming = std::make_unique<UserTiming>(*this);
196
197     auto result = m_userTiming->measure(measureName, startMark, endMark);
198     if (result.hasException())
199         return result.releaseException();
200
201     queueEntry(result.releaseReturnValue());
202
203     return { };
204 }
205
206 void Performance::clearMeasures(const String& measureName)
207 {
208     if (!m_userTiming)
209         m_userTiming = std::make_unique<UserTiming>(*this);
210     m_userTiming->clearMeasures(measureName);
211 }
212
213 void Performance::registerPerformanceObserver(PerformanceObserver& observer)
214 {
215     m_observers.add(&observer);
216 }
217
218 void Performance::unregisterPerformanceObserver(PerformanceObserver& observer)
219 {
220     m_observers.remove(&observer);
221 }
222
223 double Performance::now() const
224 {
225     double nowSeconds = monotonicallyIncreasingTime() - m_referenceTime;
226     return 1000.0 * reduceTimeResolution(nowSeconds);
227 }
228
229 double Performance::reduceTimeResolution(double seconds)
230 {
231     const double resolutionSeconds = 0.0001;
232     return std::floor(seconds / resolutionSeconds) * resolutionSeconds;
233 }
234
235 void Performance::queueEntry(PerformanceEntry& entry)
236 {
237     bool shouldScheduleTask = false;
238     for (auto& observer : m_observers) {
239         if (observer->typeFilter().contains(entry.type())) {
240             observer->queueEntry(entry);
241             shouldScheduleTask = true;
242         }
243     }
244
245     if (!shouldScheduleTask)
246         return;
247
248     if (m_performanceTimelineTaskQueue.hasPendingTasks())
249         return;
250
251     m_performanceTimelineTaskQueue.enqueueTask([this] () {
252         Vector<RefPtr<PerformanceObserver>> observers;
253         copyToVector(m_observers, observers);
254         for (auto& observer : observers)
255             observer->deliver();
256     });
257 }
258
259 } // namespace WebCore
260
261 #endif // ENABLE(WEB_TIMING)