31513d15e2b58d146abd5b98d4e8fcc479d0c729
[WebKit-https.git] / WebCore / inspector / InspectorTimelineAgent.cpp
1 /*
2 * Copyright (C) 2009 Google 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 are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "InspectorTimelineAgent.h"
33
34 #if ENABLE(INSPECTOR)
35
36 #include "Event.h"
37 #include "IntRect.h"
38 #include "RemoteInspectorFrontend2.h"
39 #include "ResourceRequest.h"
40 #include "ResourceResponse.h"
41 #include "TimelineRecordFactory.h"
42
43 #include <wtf/CurrentTime.h>
44
45 namespace WebCore {
46
47 int InspectorTimelineAgent::s_instanceCount = 0;
48
49 InspectorTimelineAgent::InspectorTimelineAgent(InspectorFrontend2* frontend)
50     : m_frontend(frontend)
51 {
52     ++s_instanceCount;
53     ScriptGCEvent::addEventListener(this);
54     ASSERT(m_frontend);
55 }
56
57 void InspectorTimelineAgent::pushGCEventRecords()
58 {
59     if (!m_gcEvents.size())
60         return;
61
62     GCEvents events = m_gcEvents;
63     m_gcEvents.clear();
64     for (GCEvents::iterator i = events.begin(); i != events.end(); ++i) {
65         RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(i->startTime);
66         record->set("data", TimelineRecordFactory::createGCEventData(i->collectedBytes));
67         record->setNumber("endTime", i->endTime);
68         addRecordToTimeline(record.release(), GCEventTimelineRecordType);
69     }
70 }
71
72 void InspectorTimelineAgent::didGC(double startTime, double endTime, size_t collectedBytesCount)
73 {
74     m_gcEvents.append(GCEvent(startTime, endTime, collectedBytesCount));
75 }
76
77 InspectorTimelineAgent::~InspectorTimelineAgent()
78 {
79     ASSERT(s_instanceCount);
80     --s_instanceCount;
81     ScriptGCEvent::removeEventListener(this);
82 }
83
84 void InspectorTimelineAgent::willCallFunction(const String& scriptName, int scriptLine)
85 {
86     pushCurrentRecord(TimelineRecordFactory::createFunctionCallData(scriptName, scriptLine), FunctionCallTimelineRecordType);
87 }
88
89 void InspectorTimelineAgent::didCallFunction()
90 {
91     didCompleteCurrentRecord(FunctionCallTimelineRecordType);
92 }
93
94 void InspectorTimelineAgent::willDispatchEvent(const Event& event)
95 {
96     pushCurrentRecord(TimelineRecordFactory::createEventDispatchData(event),
97         EventDispatchTimelineRecordType);
98 }
99
100 void InspectorTimelineAgent::didDispatchEvent()
101 {
102     didCompleteCurrentRecord(EventDispatchTimelineRecordType);
103 }
104
105 void InspectorTimelineAgent::willLayout()
106 {
107     pushCurrentRecord(InspectorObject::create(), LayoutTimelineRecordType);
108 }
109
110 void InspectorTimelineAgent::didLayout()
111 {
112     didCompleteCurrentRecord(LayoutTimelineRecordType);
113 }
114
115 void InspectorTimelineAgent::willRecalculateStyle()
116 {
117     pushCurrentRecord(InspectorObject::create(), RecalculateStylesTimelineRecordType);
118 }
119
120 void InspectorTimelineAgent::didRecalculateStyle()
121 {
122     didCompleteCurrentRecord(RecalculateStylesTimelineRecordType);
123 }
124
125 void InspectorTimelineAgent::willPaint(const IntRect& rect)
126 {
127     pushCurrentRecord(TimelineRecordFactory::createPaintData(rect), PaintTimelineRecordType);
128 }
129
130 void InspectorTimelineAgent::didPaint()
131 {
132     didCompleteCurrentRecord(PaintTimelineRecordType);
133 }
134
135 void InspectorTimelineAgent::willWriteHTML(unsigned int length, unsigned int startLine)
136 {
137     pushCurrentRecord(TimelineRecordFactory::createParseHTMLData(length, startLine), ParseHTMLTimelineRecordType);
138 }
139
140 void InspectorTimelineAgent::didWriteHTML(unsigned int endLine)
141 {
142     if (!m_recordStack.isEmpty()) {
143         TimelineRecordEntry entry = m_recordStack.last();
144         entry.data->setNumber("endLine", endLine);
145         didCompleteCurrentRecord(ParseHTMLTimelineRecordType);
146     }
147 }
148
149 void InspectorTimelineAgent::didInstallTimer(int timerId, int timeout, bool singleShot)
150 {
151     pushGCEventRecords();
152     RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(WTF::currentTimeMS());
153     record->set("data", TimelineRecordFactory::createTimerInstallData(timerId, timeout, singleShot));
154     addRecordToTimeline(record.release(), TimerInstallTimelineRecordType);
155 }
156
157 void InspectorTimelineAgent::didRemoveTimer(int timerId)
158 {
159     pushGCEventRecords();
160     RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(WTF::currentTimeMS());
161     record->set("data", TimelineRecordFactory::createGenericTimerData(timerId));
162     addRecordToTimeline(record.release(), TimerRemoveTimelineRecordType);
163 }
164
165 void InspectorTimelineAgent::willFireTimer(int timerId)
166 {
167     pushCurrentRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimerFireTimelineRecordType);
168 }
169
170 void InspectorTimelineAgent::didFireTimer()
171 {
172     didCompleteCurrentRecord(TimerFireTimelineRecordType);
173 }
174
175 void InspectorTimelineAgent::willChangeXHRReadyState(const String& url, int readyState)
176 {
177     pushCurrentRecord(TimelineRecordFactory::createXHRReadyStateChangeData(url, readyState), XHRReadyStateChangeRecordType);
178 }
179
180 void InspectorTimelineAgent::didChangeXHRReadyState()
181 {
182     didCompleteCurrentRecord(XHRReadyStateChangeRecordType);
183 }
184
185 void InspectorTimelineAgent::willLoadXHR(const String& url) 
186 {
187     pushCurrentRecord(TimelineRecordFactory::createXHRLoadData(url), XHRLoadRecordType);
188 }
189
190 void InspectorTimelineAgent::didLoadXHR()
191 {
192     didCompleteCurrentRecord(XHRLoadRecordType);
193 }
194
195 void InspectorTimelineAgent::willEvaluateScript(const String& url, int lineNumber)
196 {
197     pushCurrentRecord(TimelineRecordFactory::createEvaluateScriptData(url, lineNumber), EvaluateScriptTimelineRecordType);
198 }
199     
200 void InspectorTimelineAgent::didEvaluateScript()
201 {
202     didCompleteCurrentRecord(EvaluateScriptTimelineRecordType);
203 }
204
205 void InspectorTimelineAgent::didScheduleResourceRequest(const String& url)
206 {
207     pushGCEventRecords();
208     RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(WTF::currentTimeMS());
209     record->set("data", TimelineRecordFactory::createScheduleResourceRequestData(url));
210     record->setNumber("type", ScheduleResourceRequestTimelineRecordType);
211     addRecordToTimeline(record.release(), ScheduleResourceRequestTimelineRecordType);
212 }
213
214 void InspectorTimelineAgent::willSendResourceRequest(unsigned long identifier, bool isMainResource,
215     const ResourceRequest& request)
216 {
217     pushGCEventRecords();
218     RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(WTF::currentTimeMS());
219     record->set("data", TimelineRecordFactory::createResourceSendRequestData(identifier, isMainResource, request));
220     record->setNumber("type", ResourceSendRequestTimelineRecordType);
221     setHeapSizeStatistic(record.get());
222     m_frontend->addRecordToTimeline(record.release());
223 }
224
225 void InspectorTimelineAgent::willReceiveResourceData(unsigned long identifier)
226 {
227     pushCurrentRecord(TimelineRecordFactory::createReceiveResourceData(identifier), ReceiveResourceDataTimelineRecordType);
228 }
229
230 void InspectorTimelineAgent::didReceiveResourceData()
231 {
232     didCompleteCurrentRecord(ReceiveResourceDataTimelineRecordType);
233 }
234     
235 void InspectorTimelineAgent::willReceiveResourceResponse(unsigned long identifier, const ResourceResponse& response)
236 {
237     pushCurrentRecord(TimelineRecordFactory::createResourceReceiveResponseData(identifier, response), ResourceReceiveResponseTimelineRecordType);
238 }
239
240 void InspectorTimelineAgent::didReceiveResourceResponse()
241 {
242     didCompleteCurrentRecord(ResourceReceiveResponseTimelineRecordType);
243 }
244
245 void InspectorTimelineAgent::didFinishLoadingResource(unsigned long identifier, bool didFail)
246 {
247     pushGCEventRecords();
248     RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(WTF::currentTimeMS());
249     record->set("data", TimelineRecordFactory::createResourceFinishData(identifier, didFail));
250     record->setNumber("type", ResourceFinishTimelineRecordType);
251     setHeapSizeStatistic(record.get());
252     m_frontend->addRecordToTimeline(record.release());
253 }
254
255 void InspectorTimelineAgent::didMarkTimeline(const String& message)
256 {
257     pushGCEventRecords();
258     RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(WTF::currentTimeMS());
259     record->set("data", TimelineRecordFactory::createMarkTimelineData(message));
260     addRecordToTimeline(record.release(), MarkTimelineRecordType);
261 }
262
263 void InspectorTimelineAgent::didMarkDOMContentEvent()
264 {
265     pushGCEventRecords();
266     RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(WTF::currentTimeMS());
267     addRecordToTimeline(record.release(), MarkDOMContentEventType);
268 }
269
270 void InspectorTimelineAgent::didMarkLoadEvent()
271 {
272     pushGCEventRecords();
273     RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(WTF::currentTimeMS());
274     addRecordToTimeline(record.release(), MarkLoadEventType);
275 }
276
277 void InspectorTimelineAgent::reset()
278 {
279     m_recordStack.clear();
280 }
281
282 void InspectorTimelineAgent::resetFrontendProxyObject(InspectorFrontend2* frontend)
283 {
284     ASSERT(frontend);
285     reset();
286     m_frontend = frontend;
287 }
288
289 void InspectorTimelineAgent::addRecordToTimeline(PassRefPtr<InspectorObject> prpRecord, TimelineRecordType type)
290 {
291     RefPtr<InspectorObject> record(prpRecord);
292     record->setNumber("type", type);
293     setHeapSizeStatistic(record.get());
294     if (m_recordStack.isEmpty())
295         m_frontend->addRecordToTimeline(record.release());
296     else {
297         TimelineRecordEntry parent = m_recordStack.last();
298         parent.children->push(record.release());
299     }
300 }
301
302 void InspectorTimelineAgent::setHeapSizeStatistic(InspectorObject* record)
303 {
304     size_t usedHeapSize = 0;
305     size_t totalHeapSize = 0;
306     ScriptGCEvent::getHeapSize(usedHeapSize, totalHeapSize);
307     record->setNumber("usedHeapSize", usedHeapSize);
308     record->setNumber("totalHeapSize", totalHeapSize);
309 }
310
311 void InspectorTimelineAgent::didCompleteCurrentRecord(TimelineRecordType type)
312 {
313     // An empty stack could merely mean that the timeline agent was turned on in the middle of
314     // an event.  Don't treat as an error.
315     if (!m_recordStack.isEmpty()) {
316         pushGCEventRecords();
317         TimelineRecordEntry entry = m_recordStack.last();
318         m_recordStack.removeLast();
319         ASSERT(entry.type == type);
320         entry.record->set("data", entry.data);
321         entry.record->set("children", entry.children);
322         entry.record->setNumber("endTime", WTF::currentTimeMS());
323         addRecordToTimeline(entry.record, type);
324     }
325 }
326
327 void InspectorTimelineAgent::pushCurrentRecord(PassRefPtr<InspectorObject> data, TimelineRecordType type)
328 {
329     pushGCEventRecords();
330     RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(WTF::currentTimeMS());
331     m_recordStack.append(TimelineRecordEntry(record.release(), data, InspectorArray::create(), type));
332 }
333 } // namespace WebCore
334
335 #endif // ENABLE(INSPECTOR)