2 * Copyright (C) 2009 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
32 #include "InspectorTimelineAgent.h"
37 #include "IdentifiersFactory.h"
38 #include "InspectorFrontend.h"
39 #include "InspectorState.h"
40 #include "InstrumentingAgents.h"
42 #include "ResourceRequest.h"
43 #include "ResourceResponse.h"
44 #include "TimelineRecordFactory.h"
46 #include <wtf/CurrentTime.h>
50 namespace TimelineAgentState {
51 static const char timelineAgentEnabled[] = "timelineAgentEnabled";
52 static const char timelineMaxCallStackDepth[] = "timelineMaxCallStackDepth";
55 // Must be kept in sync with TimelineAgent.js
56 namespace TimelineRecordType {
57 static const char EventDispatch[] = "EventDispatch";
58 static const char Layout[] = "Layout";
59 static const char RecalculateStyles[] = "RecalculateStyles";
60 static const char Paint[] = "Paint";
61 static const char ParseHTML[] = "ParseHTML";
63 static const char TimerInstall[] = "TimerInstall";
64 static const char TimerRemove[] = "TimerRemove";
65 static const char TimerFire[] = "TimerFire";
67 static const char EvaluateScript[] = "EvaluateScript";
69 static const char MarkLoad[] = "MarkLoad";
70 static const char MarkDOMContent[] = "MarkDOMContent";
72 static const char TimeStamp[] = "TimeStamp";
74 static const char ScheduleResourceRequest[] = "ScheduleResourceRequest";
75 static const char ResourceSendRequest[] = "ResourceSendRequest";
76 static const char ResourceReceiveResponse[] = "ResourceReceiveResponse";
77 static const char ResourceReceivedData[] = "ResourceReceivedData";
78 static const char ResourceFinish[] = "ResourceFinish";
80 static const char XHRReadyStateChange[] = "XHRReadyStateChange";
81 static const char XHRLoad[] = "XHRLoad";
83 static const char FunctionCall[] = "FunctionCall";
84 static const char GCEvent[] = "GCEvent";
86 static const char RegisterAnimationFrameCallback[] = "RegisterAnimationFrameCallback";
87 static const char CancelAnimationFrameCallback[] = "CancelAnimationFrameCallback";
88 static const char FireAnimationFrameEvent[] = "FireAnimationFrameEvent";
91 void InspectorTimelineAgent::pushGCEventRecords()
93 if (!m_gcEvents.size())
96 GCEvents events = m_gcEvents;
98 for (GCEvents::iterator i = events.begin(); i != events.end(); ++i) {
99 RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(i->startTime, m_maxCallStackDepth);
100 record->setObject("data", TimelineRecordFactory::createGCEventData(i->collectedBytes));
101 record->setNumber("endTime", i->endTime);
102 addRecordToTimeline(record.release(), TimelineRecordType::GCEvent);
106 void InspectorTimelineAgent::didGC(double startTime, double endTime, size_t collectedBytesCount)
108 m_gcEvents.append(GCEvent(startTime, endTime, collectedBytesCount));
111 InspectorTimelineAgent::~InspectorTimelineAgent()
116 void InspectorTimelineAgent::setFrontend(InspectorFrontend* frontend)
118 m_frontend = frontend->timeline();
121 void InspectorTimelineAgent::clearFrontend()
128 void InspectorTimelineAgent::restore()
130 if (m_state->getBoolean(TimelineAgentState::timelineAgentEnabled)) {
131 m_maxCallStackDepth = m_state->getLong(TimelineAgentState::timelineMaxCallStackDepth);
133 start(&error, &m_maxCallStackDepth);
137 void InspectorTimelineAgent::start(ErrorString*, int* maxCallStackDepth)
142 if (maxCallStackDepth && *maxCallStackDepth > 0)
143 m_maxCallStackDepth = *maxCallStackDepth;
145 m_maxCallStackDepth = 5;
146 m_state->setLong(TimelineAgentState::timelineMaxCallStackDepth, m_maxCallStackDepth);
148 m_instrumentingAgents->setInspectorTimelineAgent(this);
149 ScriptGCEvent::addEventListener(this);
150 m_frontend->started();
151 m_state->setBoolean(TimelineAgentState::timelineAgentEnabled, true);
154 void InspectorTimelineAgent::stop(ErrorString*)
158 m_instrumentingAgents->setInspectorTimelineAgent(0);
160 m_frontend->stopped();
161 ScriptGCEvent::removeEventListener(this);
166 m_state->setBoolean(TimelineAgentState::timelineAgentEnabled, false);
169 bool InspectorTimelineAgent::started() const
171 return m_state->getBoolean(TimelineAgentState::timelineAgentEnabled);
174 void InspectorTimelineAgent::willCallFunction(const String& scriptName, int scriptLine)
176 pushCurrentRecord(TimelineRecordFactory::createFunctionCallData(scriptName, scriptLine), TimelineRecordType::FunctionCall);
179 void InspectorTimelineAgent::didCallFunction()
181 didCompleteCurrentRecord(TimelineRecordType::FunctionCall);
184 void InspectorTimelineAgent::willDispatchEvent(const Event& event)
186 pushCurrentRecord(TimelineRecordFactory::createEventDispatchData(event),
187 TimelineRecordType::EventDispatch);
190 void InspectorTimelineAgent::didDispatchEvent()
192 didCompleteCurrentRecord(TimelineRecordType::EventDispatch);
195 void InspectorTimelineAgent::willLayout()
197 pushCurrentRecord(InspectorObject::create(), TimelineRecordType::Layout);
200 void InspectorTimelineAgent::didLayout()
202 didCompleteCurrentRecord(TimelineRecordType::Layout);
205 void InspectorTimelineAgent::willRecalculateStyle()
207 pushCurrentRecord(InspectorObject::create(), TimelineRecordType::RecalculateStyles);
210 void InspectorTimelineAgent::didRecalculateStyle()
212 didCompleteCurrentRecord(TimelineRecordType::RecalculateStyles);
215 void InspectorTimelineAgent::willPaint(const LayoutRect& rect)
217 pushCurrentRecord(TimelineRecordFactory::createPaintData(rect), TimelineRecordType::Paint);
220 void InspectorTimelineAgent::didPaint()
222 didCompleteCurrentRecord(TimelineRecordType::Paint);
225 void InspectorTimelineAgent::willWriteHTML(unsigned int length, unsigned int startLine)
227 pushCurrentRecord(TimelineRecordFactory::createParseHTMLData(length, startLine), TimelineRecordType::ParseHTML);
230 void InspectorTimelineAgent::didWriteHTML(unsigned int endLine)
232 if (!m_recordStack.isEmpty()) {
233 TimelineRecordEntry entry = m_recordStack.last();
234 entry.data->setNumber("endLine", endLine);
235 didCompleteCurrentRecord(TimelineRecordType::ParseHTML);
239 void InspectorTimelineAgent::didInstallTimer(int timerId, int timeout, bool singleShot)
241 appendRecord(TimelineRecordFactory::createTimerInstallData(timerId, timeout, singleShot), TimelineRecordType::TimerInstall);
244 void InspectorTimelineAgent::didRemoveTimer(int timerId)
246 appendRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerRemove);
249 void InspectorTimelineAgent::willFireTimer(int timerId)
251 pushCurrentRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerFire);
254 void InspectorTimelineAgent::didFireTimer()
256 didCompleteCurrentRecord(TimelineRecordType::TimerFire);
259 void InspectorTimelineAgent::willChangeXHRReadyState(const String& url, int readyState)
261 pushCurrentRecord(TimelineRecordFactory::createXHRReadyStateChangeData(url, readyState), TimelineRecordType::XHRReadyStateChange);
264 void InspectorTimelineAgent::didChangeXHRReadyState()
266 didCompleteCurrentRecord(TimelineRecordType::XHRReadyStateChange);
269 void InspectorTimelineAgent::willLoadXHR(const String& url)
271 pushCurrentRecord(TimelineRecordFactory::createXHRLoadData(url), TimelineRecordType::XHRLoad);
274 void InspectorTimelineAgent::didLoadXHR()
276 didCompleteCurrentRecord(TimelineRecordType::XHRLoad);
279 void InspectorTimelineAgent::willEvaluateScript(const String& url, int lineNumber)
281 pushCurrentRecord(TimelineRecordFactory::createEvaluateScriptData(url, lineNumber), TimelineRecordType::EvaluateScript);
284 void InspectorTimelineAgent::didEvaluateScript()
286 didCompleteCurrentRecord(TimelineRecordType::EvaluateScript);
289 void InspectorTimelineAgent::didScheduleResourceRequest(const String& url)
291 appendRecord(TimelineRecordFactory::createScheduleResourceRequestData(url), TimelineRecordType::ScheduleResourceRequest);
294 void InspectorTimelineAgent::willSendResourceRequest(unsigned long identifier, const ResourceRequest& request)
296 pushGCEventRecords();
297 RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(WTF::currentTimeMS(), m_maxCallStackDepth);
298 String requestId = IdentifiersFactory::requestId(identifier);
299 record->setObject("data", TimelineRecordFactory::createResourceSendRequestData(requestId, request));
300 record->setString("type", TimelineRecordType::ResourceSendRequest);
301 setHeapSizeStatistic(record.get());
302 m_frontend->eventRecorded(record.release());
305 void InspectorTimelineAgent::willReceiveResourceData(unsigned long identifier)
307 String requestId = IdentifiersFactory::requestId(identifier);
308 pushCurrentRecord(TimelineRecordFactory::createReceiveResourceData(requestId), TimelineRecordType::ResourceReceivedData);
311 void InspectorTimelineAgent::didReceiveResourceData()
313 didCompleteCurrentRecord(TimelineRecordType::ResourceReceivedData);
316 void InspectorTimelineAgent::willReceiveResourceResponse(unsigned long identifier, const ResourceResponse& response)
318 String requestId = IdentifiersFactory::requestId(identifier);
319 pushCurrentRecord(TimelineRecordFactory::createResourceReceiveResponseData(requestId, response), TimelineRecordType::ResourceReceiveResponse);
322 void InspectorTimelineAgent::didReceiveResourceResponse()
324 didCompleteCurrentRecord(TimelineRecordType::ResourceReceiveResponse);
327 void InspectorTimelineAgent::didFinishLoadingResource(unsigned long identifier, bool didFail, double finishTime)
329 appendRecord(TimelineRecordFactory::createResourceFinishData(IdentifiersFactory::requestId(identifier), didFail, finishTime * 1000), TimelineRecordType::ResourceFinish);
332 void InspectorTimelineAgent::didTimeStamp(const String& message)
334 appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeStamp);
337 void InspectorTimelineAgent::didMarkDOMContentEvent()
339 appendRecord(InspectorObject::create(), TimelineRecordType::TimeStamp);
342 void InspectorTimelineAgent::didMarkLoadEvent()
344 appendRecord(InspectorObject::create(), TimelineRecordType::MarkLoad);
347 void InspectorTimelineAgent::didCommitLoad()
352 void InspectorTimelineAgent::didRegisterAnimationFrameCallback(int callbackId)
354 appendRecord(TimelineRecordFactory::createAnimationFrameCallbackData(callbackId), TimelineRecordType::RegisterAnimationFrameCallback);
357 void InspectorTimelineAgent::didCancelAnimationFrameCallback(int callbackId)
359 appendRecord(TimelineRecordFactory::createAnimationFrameCallbackData(callbackId), TimelineRecordType::CancelAnimationFrameCallback);
362 void InspectorTimelineAgent::willFireAnimationFrameEvent(int callbackId)
364 pushCurrentRecord(TimelineRecordFactory::createAnimationFrameCallbackData(callbackId), TimelineRecordType::FireAnimationFrameEvent);
367 void InspectorTimelineAgent::didFireAnimationFrameEvent()
369 didCompleteCurrentRecord(TimelineRecordType::FireAnimationFrameEvent);
372 void InspectorTimelineAgent::addRecordToTimeline(PassRefPtr<InspectorObject> prpRecord, const String& type)
374 RefPtr<InspectorObject> record(prpRecord);
375 record->setString("type", type);
376 setHeapSizeStatistic(record.get());
377 if (m_recordStack.isEmpty())
378 m_frontend->eventRecorded(record.release());
380 TimelineRecordEntry parent = m_recordStack.last();
381 parent.children->pushObject(record.release());
385 void InspectorTimelineAgent::setHeapSizeStatistic(InspectorObject* record)
387 size_t usedHeapSize = 0;
388 size_t totalHeapSize = 0;
389 size_t heapSizeLimit = 0;
390 ScriptGCEvent::getHeapSize(usedHeapSize, totalHeapSize, heapSizeLimit);
391 record->setNumber("usedHeapSize", usedHeapSize);
392 record->setNumber("totalHeapSize", totalHeapSize);
395 void InspectorTimelineAgent::didCompleteCurrentRecord(const String& type)
397 // An empty stack could merely mean that the timeline agent was turned on in the middle of
398 // an event. Don't treat as an error.
399 if (!m_recordStack.isEmpty()) {
400 pushGCEventRecords();
401 TimelineRecordEntry entry = m_recordStack.last();
402 m_recordStack.removeLast();
403 ASSERT(entry.type == type);
404 entry.record->setObject("data", entry.data);
405 entry.record->setArray("children", entry.children);
406 entry.record->setNumber("endTime", WTF::currentTimeMS());
407 addRecordToTimeline(entry.record, type);
411 InspectorTimelineAgent::InspectorTimelineAgent(InstrumentingAgents* instrumentingAgents, InspectorState* state)
412 : m_instrumentingAgents(instrumentingAgents)
416 , m_maxCallStackDepth(5)
420 void InspectorTimelineAgent::appendRecord(PassRefPtr<InspectorObject> data, const String& type)
422 pushGCEventRecords();
423 RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(WTF::currentTimeMS(), m_maxCallStackDepth);
424 record->setObject("data", data);
425 record->setString("type", type);
426 addRecordToTimeline(record.release(), type);
429 void InspectorTimelineAgent::pushCurrentRecord(PassRefPtr<InspectorObject> data, const String& type)
431 pushGCEventRecords();
432 RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(WTF::currentTimeMS(), m_maxCallStackDepth);
433 m_recordStack.append(TimelineRecordEntry(record.release(), data, InspectorArray::create(), type));
436 void InspectorTimelineAgent::clearRecordStack()
438 m_recordStack.clear();
442 } // namespace WebCore
444 #endif // ENABLE(INSPECTOR)