5b4330988c4f8476de4aa1950a1f79cc133982a4
[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 "ScriptExecutionContext.h"
50 #include <wtf/CurrentTime.h>
51
52 namespace WebCore {
53
54 Performance::Performance(ScriptExecutionContext& context, double timeOrigin)
55     : ContextDestructionObserver(&context)
56     , m_timeOrigin(timeOrigin)
57 {
58     ASSERT(m_timeOrigin);
59 }
60
61 Performance::~Performance()
62 {
63 }
64
65 double Performance::now() const
66 {
67     double nowSeconds = monotonicallyIncreasingTime() - m_timeOrigin;
68     return 1000.0 * reduceTimeResolution(nowSeconds);
69 }
70
71 double Performance::reduceTimeResolution(double seconds)
72 {
73     const double resolutionSeconds = 0.0001;
74     return std::floor(seconds / resolutionSeconds) * resolutionSeconds;
75 }
76
77 PerformanceNavigation* Performance::navigation()
78 {
79     if (!is<Document>(scriptExecutionContext()))
80         return nullptr;
81
82     ASSERT(isMainThread());
83     if (!m_navigation)
84         m_navigation = PerformanceNavigation::create(downcast<Document>(*scriptExecutionContext()).frame());
85     return m_navigation.get();
86 }
87
88 PerformanceTiming* Performance::timing()
89 {
90     if (!is<Document>(scriptExecutionContext()))
91         return nullptr;
92
93     ASSERT(isMainThread());
94     if (!m_timing)
95         m_timing = PerformanceTiming::create(downcast<Document>(*scriptExecutionContext()).frame());
96     return m_timing.get();
97 }
98
99 Vector<RefPtr<PerformanceEntry>> Performance::getEntries() const
100 {
101     Vector<RefPtr<PerformanceEntry>> entries;
102
103     entries.appendVector(m_resourceTimingBuffer);
104
105     if (m_userTiming) {
106         entries.appendVector(m_userTiming->getMarks());
107         entries.appendVector(m_userTiming->getMeasures());
108     }
109
110     std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompareLessThan);
111     return entries;
112 }
113
114 Vector<RefPtr<PerformanceEntry>> Performance::getEntriesByType(const String& entryType) const
115 {
116     Vector<RefPtr<PerformanceEntry>> entries;
117
118     if (equalLettersIgnoringASCIICase(entryType, "resource"))
119         entries.appendVector(m_resourceTimingBuffer);
120
121     if (m_userTiming) {
122         if (equalLettersIgnoringASCIICase(entryType, "mark"))
123             entries.appendVector(m_userTiming->getMarks());
124         else if (equalLettersIgnoringASCIICase(entryType, "measure"))
125             entries.appendVector(m_userTiming->getMeasures());
126     }
127
128     std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompareLessThan);
129     return entries;
130 }
131
132 Vector<RefPtr<PerformanceEntry>> Performance::getEntriesByName(const String& name, const String& entryType) const
133 {
134     Vector<RefPtr<PerformanceEntry>> entries;
135
136     if (entryType.isNull() || equalLettersIgnoringASCIICase(entryType, "resource")) {
137         for (auto& resource : m_resourceTimingBuffer) {
138             if (resource->name() == name)
139                 entries.append(resource);
140         }
141     }
142
143     if (m_userTiming) {
144         if (entryType.isNull() || equalLettersIgnoringASCIICase(entryType, "mark"))
145             entries.appendVector(m_userTiming->getMarks(name));
146         if (entryType.isNull() || equalLettersIgnoringASCIICase(entryType, "measure"))
147             entries.appendVector(m_userTiming->getMeasures(name));
148     }
149
150     std::sort(entries.begin(), entries.end(), PerformanceEntry::startTimeCompareLessThan);
151     return entries;
152 }
153
154 void Performance::clearResourceTimings()
155 {
156     m_resourceTimingBuffer.clear();
157 }
158
159 void Performance::setResourceTimingBufferSize(unsigned size)
160 {
161     m_resourceTimingBufferSize = size;
162
163     if (isResourceTimingBufferFull())
164         dispatchEvent(Event::create(eventNames().resourcetimingbufferfullEvent, false, false));
165 }
166
167 void Performance::addResourceTiming(const String& initiatorName, const URL& originalURL, const ResourceResponse& response, const LoadTiming& loadTiming)
168 {
169     if (isResourceTimingBufferFull())
170         return;
171
172     SecurityOrigin* securityOrigin = scriptExecutionContext()->securityOrigin();
173     if (!securityOrigin)
174         return;
175
176     RefPtr<PerformanceEntry> entry = PerformanceResourceTiming::create(initiatorName, originalURL, response, *securityOrigin, m_timeOrigin, loadTiming);
177
178     m_resourceTimingBuffer.append(entry);
179
180     if (isResourceTimingBufferFull())
181         dispatchEvent(Event::create(eventNames().resourcetimingbufferfullEvent, false, false));
182 }
183
184 bool Performance::isResourceTimingBufferFull() const
185 {
186     return m_resourceTimingBuffer.size() >= m_resourceTimingBufferSize;
187 }
188
189 ExceptionOr<void> Performance::mark(const String& markName)
190 {
191     if (!m_userTiming)
192         m_userTiming = std::make_unique<UserTiming>(*this);
193
194     auto result = m_userTiming->mark(markName);
195     if (result.hasException())
196         return result.releaseException();
197
198     queueEntry(result.releaseReturnValue());
199
200     return { };
201 }
202
203 void Performance::clearMarks(const String& markName)
204 {
205     if (!m_userTiming)
206         m_userTiming = std::make_unique<UserTiming>(*this);
207     m_userTiming->clearMarks(markName);
208 }
209
210 ExceptionOr<void> Performance::measure(const String& measureName, const String& startMark, const String& endMark)
211 {
212     if (!m_userTiming)
213         m_userTiming = std::make_unique<UserTiming>(*this);
214
215     auto result = m_userTiming->measure(measureName, startMark, endMark);
216     if (result.hasException())
217         return result.releaseException();
218
219     queueEntry(result.releaseReturnValue());
220
221     return { };
222 }
223
224 void Performance::clearMeasures(const String& measureName)
225 {
226     if (!m_userTiming)
227         m_userTiming = std::make_unique<UserTiming>(*this);
228     m_userTiming->clearMeasures(measureName);
229 }
230
231 void Performance::registerPerformanceObserver(PerformanceObserver& observer)
232 {
233     m_observers.add(&observer);
234 }
235
236 void Performance::unregisterPerformanceObserver(PerformanceObserver& observer)
237 {
238     m_observers.remove(&observer);
239 }
240
241 void Performance::queueEntry(PerformanceEntry& entry)
242 {
243     bool shouldScheduleTask = false;
244     for (auto& observer : m_observers) {
245         if (observer->typeFilter().contains(entry.type())) {
246             observer->queueEntry(entry);
247             shouldScheduleTask = true;
248         }
249     }
250
251     if (!shouldScheduleTask)
252         return;
253
254     if (m_performanceTimelineTaskQueue.hasPendingTasks())
255         return;
256
257     m_performanceTimelineTaskQueue.enqueueTask([this] () {
258         Vector<RefPtr<PerformanceObserver>> observers;
259         copyToVector(m_observers, observers);
260         for (auto& observer : observers)
261             observer->deliver();
262     });
263 }
264
265 } // namespace WebCore
266
267 #endif // ENABLE(WEB_TIMING)