1/* 2* Copyright (C) 2013 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 33#if ENABLE(INSPECTOR) 34 35#include "InspectorTimelineAgent.h" 36 37#include "Event.h" 38#include "Frame.h" 39#include "FrameView.h" 40#include "IdentifiersFactory.h" 41#include "InspectorClient.h" 42#include "InspectorCounters.h" 43#include "InspectorFrontend.h" 44#include "InspectorInstrumentation.h" 45#include "InspectorMemoryAgent.h" 46#include "InspectorPageAgent.h" 47#include "InspectorState.h" 48#include "InstrumentingAgents.h" 49#include "IntRect.h" 50#include "RenderObject.h" 51#include "RenderView.h" 52#include "ResourceRequest.h" 53#include "ResourceResponse.h" 54#include "TimelineRecordFactory.h" 55#include "TimelineTraceEventProcessor.h" 56 57#include <wtf/CurrentTime.h> 58 59namespace WebCore { 60 61namespace TimelineAgentState { 62static const char timelineAgentEnabled[] = "timelineAgentEnabled"; 63static const char timelineMaxCallStackDepth[] = "timelineMaxCallStackDepth"; 64static const char includeDomCounters[] = "includeDomCounters"; 65static const char includeNativeMemoryStatistics[] = "includeNativeMemoryStatistics"; 66} 67 68// Must be kept in sync with WebInspector.TimelineModel.RecordType in TimelineModel.js 69namespace TimelineRecordType { 70static const char Program[] = "Program"; 71 72static const char EventDispatch[] = "EventDispatch"; 73static const char BeginFrame[] = "BeginFrame"; 74static const char ScheduleStyleRecalculation[] = "ScheduleStyleRecalculation"; 75static const char RecalculateStyles[] = "RecalculateStyles"; 76static const char InvalidateLayout[] = "InvalidateLayout"; 77static const char Layout[] = "Layout"; 78static const char Paint[] = "Paint"; 79static const char ScrollLayer[] = "ScrollLayer"; 80static const char ResizeImage[] = "ResizeImage"; 81static const char CompositeLayers[] = "CompositeLayers"; 82 83static const char ParseHTML[] = "ParseHTML"; 84 85static const char TimerInstall[] = "TimerInstall"; 86static const char TimerRemove[] = "TimerRemove"; 87static const char TimerFire[] = "TimerFire"; 88 89static const char EvaluateScript[] = "EvaluateScript"; 90 91static const char MarkLoad[] = "MarkLoad"; 92static const char MarkDOMContent[] = "MarkDOMContent"; 93 94static const char TimeStamp[] = "TimeStamp"; 95static const char Time[] = "Time"; 96static const char TimeEnd[] = "TimeEnd"; 97 98static const char ScheduleResourceRequest[] = "ScheduleResourceRequest"; 99static const char ResourceSendRequest[] = "ResourceSendRequest"; 100static const char ResourceReceiveResponse[] = "ResourceReceiveResponse"; 101static const char ResourceReceivedData[] = "ResourceReceivedData"; 102static const char ResourceFinish[] = "ResourceFinish"; 103 104static const char XHRReadyStateChange[] = "XHRReadyStateChange"; 105static const char XHRLoad[] = "XHRLoad"; 106 107static const char FunctionCall[] = "FunctionCall"; 108static const char GCEvent[] = "GCEvent"; 109 110static const char RequestAnimationFrame[] = "RequestAnimationFrame"; 111static const char CancelAnimationFrame[] = "CancelAnimationFrame"; 112static const char FireAnimationFrame[] = "FireAnimationFrame"; 113 114static const char WebSocketCreate[] = "WebSocketCreate"; 115static const char WebSocketSendHandshakeRequest[] = "WebSocketSendHandshakeRequest"; 116static const char WebSocketReceiveHandshakeResponse[] = "WebSocketReceiveHandshakeResponse"; 117static const char WebSocketDestroy[] = "WebSocketDestroy"; 118 119// Event names visible to other modules. 120const char DecodeImage[] = "DecodeImage"; 121const char Rasterize[] = "Rasterize"; 122} 123 124void TimelineTimeConverter::reset() 125{ 126 m_startOffset = monotonicallyIncreasingTime() - currentTime(); 127} 128 129void InspectorTimelineAgent::pushGCEventRecords() 130{ 131 if (!m_gcEvents.size()) 132 return; 133 134 GCEvents events = m_gcEvents; 135 m_gcEvents.clear(); 136 for (GCEvents::iterator i = events.begin(); i != events.end(); ++i) { 137 RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(m_timeConverter.fromMonotonicallyIncreasingTime(i->startTime), m_maxCallStackDepth); 138 record->setObject("data", TimelineRecordFactory::createGCEventData(i->collectedBytes)); 139 record->setNumber("endTime", m_timeConverter.fromMonotonicallyIncreasingTime(i->endTime)); 140 addRecordToTimeline(record.release(), TimelineRecordType::GCEvent); 141 } 142} 143 144void InspectorTimelineAgent::didGC(double startTime, double endTime, size_t collectedBytesCount) 145{ 146 m_gcEvents.append(GCEvent(startTime, endTime, collectedBytesCount)); 147} 148 149InspectorTimelineAgent::~InspectorTimelineAgent() 150{ 151 clearFrontend(); 152} 153 154void InspectorTimelineAgent::setFrontend(InspectorFrontend* frontend) 155{ 156 m_frontend = frontend->timeline(); 157} 158 159void InspectorTimelineAgent::clearFrontend() 160{ 161 ErrorString error; 162 stop(&error); 163 m_frontend = 0; 164} 165 166void InspectorTimelineAgent::restore() 167{ 168 if (m_state->getBoolean(TimelineAgentState::timelineAgentEnabled)) { 169 m_maxCallStackDepth = m_state->getLong(TimelineAgentState::timelineMaxCallStackDepth); 170 ErrorString error; 171 bool includeDomCounters = m_state->getBoolean(TimelineAgentState::includeDomCounters); 172 bool includeNativeMemoryStatistics = m_state->getBoolean(TimelineAgentState::includeNativeMemoryStatistics); 173 start(&error, &m_maxCallStackDepth, &includeDomCounters, &includeNativeMemoryStatistics); 174 } 175} 176 177void InspectorTimelineAgent::start(ErrorString*, const int* maxCallStackDepth, const bool* includeDomCounters, const bool* includeNativeMemoryStatistics) 178{ 179 if (!m_frontend) 180 return; 181 182 if (maxCallStackDepth && *maxCallStackDepth > 0) 183 m_maxCallStackDepth = *maxCallStackDepth; 184 else 185 m_maxCallStackDepth = 5; 186 m_state->setLong(TimelineAgentState::timelineMaxCallStackDepth, m_maxCallStackDepth); 187 m_state->setBoolean(TimelineAgentState::includeDomCounters, includeDomCounters && *includeDomCounters); 188 m_state->setBoolean(TimelineAgentState::includeNativeMemoryStatistics, includeNativeMemoryStatistics && *includeNativeMemoryStatistics); 189 m_timeConverter.reset(); 190 191 m_instrumentingAgents->setInspectorTimelineAgent(this); 192 ScriptGCEvent::addEventListener(this); 193 m_state->setBoolean(TimelineAgentState::timelineAgentEnabled, true); 194 if (m_client && m_pageAgent) 195 m_traceEventProcessor = adoptRef(new TimelineTraceEventProcessor(m_weakFactory.createWeakPtr(), m_client)); 196} 197 198void InspectorTimelineAgent::stop(ErrorString*) 199{ 200 if (!m_state->getBoolean(TimelineAgentState::timelineAgentEnabled)) 201 return; 202 203 m_traceEventProcessor->shutdown(); 204 m_traceEventProcessor.clear(); 205 m_weakFactory.revokeAll(); 206 m_instrumentingAgents->setInspectorTimelineAgent(0); 207 ScriptGCEvent::removeEventListener(this); 208 209 clearRecordStack(); 210 m_gcEvents.clear(); 211 212 m_state->setBoolean(TimelineAgentState::timelineAgentEnabled, false); 213} 214 215void InspectorTimelineAgent::canMonitorMainThread(ErrorString*, bool* result) 216{ 217 *result = m_client && m_client->canMonitorMainThread(); 218} 219 220void InspectorTimelineAgent::supportsFrameInstrumentation(ErrorString*, bool* result) 221{ 222 *result = m_client && m_client->supportsFrameInstrumentation(); 223} 224 225void InspectorTimelineAgent::didBeginFrame() 226{ 227 m_pendingFrameRecord = TimelineRecordFactory::createGenericRecord(timestamp(), 0); 228} 229 230void InspectorTimelineAgent::didCancelFrame() 231{ 232 m_pendingFrameRecord.clear(); 233} 234 235void InspectorTimelineAgent::willCallFunction(const String& scriptName, int scriptLine, Frame* frame) 236{ 237 pushCurrentRecord(TimelineRecordFactory::createFunctionCallData(scriptName, scriptLine), TimelineRecordType::FunctionCall, true, frame); 238} 239 240void InspectorTimelineAgent::didCallFunction() 241{ 242 didCompleteCurrentRecord(TimelineRecordType::FunctionCall); 243} 244 245void InspectorTimelineAgent::willDispatchEvent(const Event& event, Frame* frame) 246{ 247 pushCurrentRecord(TimelineRecordFactory::createEventDispatchData(event), TimelineRecordType::EventDispatch, false, frame); 248} 249 250void InspectorTimelineAgent::didDispatchEvent() 251{ 252 didCompleteCurrentRecord(TimelineRecordType::EventDispatch); 253} 254 255void InspectorTimelineAgent::didInvalidateLayout(Frame* frame) 256{ 257 appendRecord(InspectorObject::create(), TimelineRecordType::InvalidateLayout, true, frame); 258} 259 260void InspectorTimelineAgent::willLayout(Frame* frame) 261{ 262 RenderObject* root = frame->view()->layoutRoot(); 263 bool partialLayout = !!root; 264 265 if (!partialLayout) 266 root = frame->contentRenderer(); 267 268 unsigned dirtyObjects = 0; 269 unsigned totalObjects = 0; 270 for (RenderObject* o = root; o; o = o->nextInPreOrder(root)) { 271 ++totalObjects; 272 if (o->needsLayout()) 273 ++dirtyObjects; 274 } 275 pushCurrentRecord(TimelineRecordFactory::createLayoutData(dirtyObjects, totalObjects, partialLayout), TimelineRecordType::Layout, true, frame); 276} 277 278void InspectorTimelineAgent::didLayout(RenderObject* root) 279{ 280 if (m_recordStack.isEmpty()) 281 return; 282 TimelineRecordEntry& entry = m_recordStack.last(); 283 ASSERT(entry.type == TimelineRecordType::Layout); 284 Vector<FloatQuad> quads; 285 root->absoluteQuads(quads); 286 if (quads.size() >= 1) 287 TimelineRecordFactory::appendLayoutRoot(entry.data.get(), quads[0]); 288 else 289 ASSERT_NOT_REACHED(); 290 didCompleteCurrentRecord(TimelineRecordType::Layout); 291} 292 293void InspectorTimelineAgent::didScheduleStyleRecalculation(Frame* frame) 294{ 295 appendRecord(InspectorObject::create(), TimelineRecordType::ScheduleStyleRecalculation, true, frame); 296} 297 298void InspectorTimelineAgent::willRecalculateStyle(Frame* frame) 299{ 300 pushCurrentRecord(InspectorObject::create(), TimelineRecordType::RecalculateStyles, true, frame); 301} 302 303void InspectorTimelineAgent::didRecalculateStyle() 304{ 305 didCompleteCurrentRecord(TimelineRecordType::RecalculateStyles); 306} 307 308void InspectorTimelineAgent::willPaint(Frame* frame) 309{ 310 pushCurrentRecord(InspectorObject::create(), TimelineRecordType::Paint, true, frame, true); 311} 312 313void InspectorTimelineAgent::didPaint(RenderObject* renderer, const LayoutRect& clipRect) 314{ 315 TimelineRecordEntry& entry = m_recordStack.last(); 316 ASSERT(entry.type == TimelineRecordType::Paint); 317 FloatQuad quad; 318 localToPageQuad(*renderer, clipRect, &quad); 319 entry.data = TimelineRecordFactory::createPaintData(quad); 320 didCompleteCurrentRecord(TimelineRecordType::Paint); 321} 322 323void InspectorTimelineAgent::willScroll(Frame* frame) 324{ 325 pushCurrentRecord(InspectorObject::create(), TimelineRecordType::ScrollLayer, false, frame); 326} 327 328void InspectorTimelineAgent::didScroll() 329{ 330 didCompleteCurrentRecord(TimelineRecordType::ScrollLayer); 331} 332 333void InspectorTimelineAgent::willDecodeImage(const String& imageType) 334{ 335 pushCurrentRecord(TimelineRecordFactory::createDecodeImageData(imageType), TimelineRecordType::DecodeImage, true, 0); 336} 337 338void InspectorTimelineAgent::didDecodeImage() 339{ 340 didCompleteCurrentRecord(TimelineRecordType::DecodeImage); 341} 342 343void InspectorTimelineAgent::willResizeImage(bool shouldCache) 344{ 345 pushCurrentRecord(TimelineRecordFactory::createResizeImageData(shouldCache), TimelineRecordType::ResizeImage, true, 0); 346} 347 348void InspectorTimelineAgent::didResizeImage() 349{ 350 didCompleteCurrentRecord(TimelineRecordType::ResizeImage); 351} 352 353void InspectorTimelineAgent::willComposite() 354{ 355 pushCurrentRecord(InspectorObject::create(), TimelineRecordType::CompositeLayers, false, 0); 356} 357 358void InspectorTimelineAgent::didComposite() 359{ 360 didCompleteCurrentRecord(TimelineRecordType::CompositeLayers); 361} 362 363void InspectorTimelineAgent::willWriteHTML(unsigned startLine, Frame* frame) 364{ 365 pushCurrentRecord(TimelineRecordFactory::createParseHTMLData(startLine), TimelineRecordType::ParseHTML, true, frame); 366} 367 368void InspectorTimelineAgent::didWriteHTML(unsigned endLine) 369{ 370 if (!m_recordStack.isEmpty()) { 371 TimelineRecordEntry entry = m_recordStack.last(); 372 entry.data->setNumber("endLine", endLine); 373 didCompleteCurrentRecord(TimelineRecordType::ParseHTML); 374 } 375} 376 377void InspectorTimelineAgent::didInstallTimer(int timerId, int timeout, bool singleShot, Frame* frame) 378{ 379 appendRecord(TimelineRecordFactory::createTimerInstallData(timerId, timeout, singleShot), TimelineRecordType::TimerInstall, true, frame); 380} 381 382void InspectorTimelineAgent::didRemoveTimer(int timerId, Frame* frame) 383{ 384 appendRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerRemove, true, frame); 385} 386 387void InspectorTimelineAgent::willFireTimer(int timerId, Frame* frame) 388{ 389 pushCurrentRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerFire, false, frame); 390} 391 392void InspectorTimelineAgent::didFireTimer() 393{ 394 didCompleteCurrentRecord(TimelineRecordType::TimerFire); 395} 396 397void InspectorTimelineAgent::willDispatchXHRReadyStateChangeEvent(const String& url, int readyState, Frame* frame) 398{ 399 pushCurrentRecord(TimelineRecordFactory::createXHRReadyStateChangeData(url, readyState), TimelineRecordType::XHRReadyStateChange, false, frame); 400} 401 402void InspectorTimelineAgent::didDispatchXHRReadyStateChangeEvent() 403{ 404 didCompleteCurrentRecord(TimelineRecordType::XHRReadyStateChange); 405} 406 407void InspectorTimelineAgent::willDispatchXHRLoadEvent(const String& url, Frame* frame) 408{ 409 pushCurrentRecord(TimelineRecordFactory::createXHRLoadData(url), TimelineRecordType::XHRLoad, true, frame); 410} 411 412void InspectorTimelineAgent::didDispatchXHRLoadEvent() 413{ 414 didCompleteCurrentRecord(TimelineRecordType::XHRLoad); 415} 416 417void InspectorTimelineAgent::willEvaluateScript(const String& url, int lineNumber, Frame* frame) 418{ 419 pushCurrentRecord(TimelineRecordFactory::createEvaluateScriptData(url, lineNumber), TimelineRecordType::EvaluateScript, true, frame); 420} 421 422void InspectorTimelineAgent::didEvaluateScript() 423{ 424 didCompleteCurrentRecord(TimelineRecordType::EvaluateScript); 425} 426 427void InspectorTimelineAgent::didScheduleResourceRequest(const String& url, Frame* frame) 428{ 429 appendRecord(TimelineRecordFactory::createScheduleResourceRequestData(url), TimelineRecordType::ScheduleResourceRequest, true, frame); 430} 431 432void InspectorTimelineAgent::willSendResourceRequest(unsigned long identifier, const ResourceRequest& request, Frame* frame) 433{ 434 String requestId = IdentifiersFactory::requestId(identifier); 435 appendRecord(TimelineRecordFactory::createResourceSendRequestData(requestId, request), TimelineRecordType::ResourceSendRequest, true, frame); 436} 437 438void InspectorTimelineAgent::willReceiveResourceData(unsigned long identifier, Frame* frame, int length) 439{ 440 String requestId = IdentifiersFactory::requestId(identifier); 441 pushCurrentRecord(TimelineRecordFactory::createReceiveResourceData(requestId, length), TimelineRecordType::ResourceReceivedData, false, frame); 442} 443 444void InspectorTimelineAgent::didReceiveResourceData() 445{ 446 didCompleteCurrentRecord(TimelineRecordType::ResourceReceivedData); 447} 448 449void InspectorTimelineAgent::willReceiveResourceResponse(unsigned long identifier, const ResourceResponse& response, Frame* frame) 450{ 451 String requestId = IdentifiersFactory::requestId(identifier); 452 pushCurrentRecord(TimelineRecordFactory::createResourceReceiveResponseData(requestId, response), TimelineRecordType::ResourceReceiveResponse, false, frame); 453} 454 455void InspectorTimelineAgent::didReceiveResourceResponse() 456{ 457 didCompleteCurrentRecord(TimelineRecordType::ResourceReceiveResponse); 458} 459 460void InspectorTimelineAgent::didFinishLoadingResource(unsigned long identifier, bool didFail, double finishTime, Frame* frame) 461{ 462 appendRecord(TimelineRecordFactory::createResourceFinishData(IdentifiersFactory::requestId(identifier), didFail, finishTime * 1000), TimelineRecordType::ResourceFinish, false, frame); 463} 464 465void InspectorTimelineAgent::didTimeStamp(Frame* frame, const String& message) 466{ 467 appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeStamp, true, frame); 468} 469 470void InspectorTimelineAgent::time(Frame* frame, const String& message) 471{ 472 appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::Time, true, frame); 473} 474 475void InspectorTimelineAgent::timeEnd(Frame* frame, const String& message) 476{ 477 appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeEnd, true, frame); 478} 479 480void InspectorTimelineAgent::didMarkDOMContentEvent(Frame* frame) 481{ 482 bool isMainFrame = frame && m_pageAgent && (frame == m_pageAgent->mainFrame()); 483 appendRecord(TimelineRecordFactory::createMarkData(isMainFrame), TimelineRecordType::MarkDOMContent, false, frame); 484} 485 486void InspectorTimelineAgent::didMarkLoadEvent(Frame* frame) 487{ 488 bool isMainFrame = frame && m_pageAgent && (frame == m_pageAgent->mainFrame()); 489 appendRecord(TimelineRecordFactory::createMarkData(isMainFrame), TimelineRecordType::MarkLoad, false, frame); 490} 491 492void InspectorTimelineAgent::didCommitLoad() 493{ 494 clearRecordStack(); 495} 496 497void InspectorTimelineAgent::didRequestAnimationFrame(int callbackId, Frame* frame) 498{ 499 appendRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::RequestAnimationFrame, true, frame); 500} 501 502void InspectorTimelineAgent::didCancelAnimationFrame(int callbackId, Frame* frame) 503{ 504 appendRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::CancelAnimationFrame, true, frame); 505} 506 507void InspectorTimelineAgent::willFireAnimationFrame(int callbackId, Frame* frame) 508{ 509 pushCurrentRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::FireAnimationFrame, false, frame); 510} 511 512void InspectorTimelineAgent::didFireAnimationFrame() 513{ 514 didCompleteCurrentRecord(TimelineRecordType::FireAnimationFrame); 515} 516 517void InspectorTimelineAgent::willProcessTask() 518{ 519 pushCurrentRecord(InspectorObject::create(), TimelineRecordType::Program, false, 0); 520} 521 522void InspectorTimelineAgent::didProcessTask() 523{ 524 didCompleteCurrentRecord(TimelineRecordType::Program); 525} 526 527#if ENABLE(WEB_SOCKETS) 528void InspectorTimelineAgent::didCreateWebSocket(unsigned long identifier, const KURL& url, const String& protocol, Frame* frame) 529{ 530 appendRecord(TimelineRecordFactory::createWebSocketCreateData(identifier, url, protocol), TimelineRecordType::WebSocketCreate, true, frame); 531} 532 533void InspectorTimelineAgent::willSendWebSocketHandshakeRequest(unsigned long identifier, Frame* frame) 534{ 535 appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketSendHandshakeRequest, true, frame); 536} 537 538void InspectorTimelineAgent::didReceiveWebSocketHandshakeResponse(unsigned long identifier, Frame* frame) 539{ 540 appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketReceiveHandshakeResponse, false, frame); 541} 542 543void InspectorTimelineAgent::didDestroyWebSocket(unsigned long identifier, Frame* frame) 544{ 545 appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketDestroy, true, frame); 546} 547#endif // ENABLE(WEB_SOCKETS) 548 549void InspectorTimelineAgent::addRecordToTimeline(PassRefPtr<InspectorObject> record, const String& type) 550{ 551 commitFrameRecord(); 552 innerAddRecordToTimeline(record, type); 553} 554 555void InspectorTimelineAgent::innerAddRecordToTimeline(PassRefPtr<InspectorObject> prpRecord, const String& type) 556{ 557 prpRecord->setString("type", type); 558 RefPtr<TypeBuilder::Timeline::TimelineEvent> record = TypeBuilder::Timeline::TimelineEvent::runtimeCast(prpRecord); 559 if (type == TimelineRecordType::Program) 560 setNativeHeapStatistics(record.get()); 561 else 562 setDOMCounters(record.get()); 563 564 if (m_recordStack.isEmpty()) 565 sendEvent(record.release()); 566 else { 567 TimelineRecordEntry parent = m_recordStack.last(); 568 parent.children->pushObject(record.release()); 569 } 570} 571 572static size_t getUsedHeapSize() 573{ 574 HeapInfo info; 575 ScriptGCEvent::getHeapSize(info); 576 return info.usedJSHeapSize; 577} 578 579void InspectorTimelineAgent::setDOMCounters(TypeBuilder::Timeline::TimelineEvent* record) 580{ 581 record->setUsedHeapSize(getUsedHeapSize()); 582 583 if (m_state->getBoolean(TimelineAgentState::includeDomCounters)) { 584 int documentCount = 0; 585 int nodeCount = 0; 586 if (m_inspectorType == PageInspector) { 587 documentCount = InspectorCounters::counterValue(InspectorCounters::DocumentCounter); 588 nodeCount = InspectorCounters::counterValue(InspectorCounters::NodeCounter); 589 } 590 int listenerCount = ThreadLocalInspectorCounters::current().counterValue(ThreadLocalInspectorCounters::JSEventListenerCounter); 591 RefPtr<TypeBuilder::Timeline::DOMCounters> counters = TypeBuilder::Timeline::DOMCounters::create() 592 .setDocuments(documentCount) 593 .setNodes(nodeCount) 594 .setJsEventListeners(listenerCount); 595 record->setCounters(counters.release()); 596 } 597} 598 599// FIXME: This entire function can probably be removed, since it's a no-op. 600void InspectorTimelineAgent::setNativeHeapStatistics(TypeBuilder::Timeline::TimelineEvent* record) 601{ 602 if (!m_memoryAgent) 603 return; 604 if (!m_state->getBoolean(TimelineAgentState::includeNativeMemoryStatistics)) 605 return; 606 RefPtr<InspectorObject> stats = InspectorObject::create(); 607 stats->setNumber("PrivateBytes", 0); 608 record->setNativeHeapStatistics(stats.release()); 609} 610 611void InspectorTimelineAgent::setFrameIdentifier(InspectorObject* record, Frame* frame) 612{ 613 if (!frame || !m_pageAgent) 614 return; 615 String frameId; 616 if (frame && m_pageAgent) 617 frameId = m_pageAgent->frameId(frame); 618 record->setString("frameId", frameId); 619} 620 621void InspectorTimelineAgent::didCompleteCurrentRecord(const String& type) 622{ 623 // An empty stack could merely mean that the timeline agent was turned on in the middle of 624 // an event. Don't treat as an error. 625 if (!m_recordStack.isEmpty()) { 626 if (m_platformInstrumentationClientInstalledAtStackDepth == m_recordStack.size()) { 627 m_platformInstrumentationClientInstalledAtStackDepth = 0; 628 PlatformInstrumentation::setClient(0); 629 } 630 631 pushGCEventRecords(); 632 TimelineRecordEntry entry = m_recordStack.last(); 633 m_recordStack.removeLast(); 634 ASSERT(entry.type == type); 635 entry.record->setObject("data", entry.data); 636 entry.record->setArray("children", entry.children); 637 entry.record->setNumber("endTime", timestamp()); 638 size_t usedHeapSizeDelta = getUsedHeapSize() - entry.usedHeapSizeAtStart; 639 if (usedHeapSizeDelta) 640 entry.record->setNumber("usedHeapSizeDelta", usedHeapSizeDelta); 641 addRecordToTimeline(entry.record, type); 642 } 643} 644 645InspectorTimelineAgent::InspectorTimelineAgent(InstrumentingAgents* instrumentingAgents, InspectorPageAgent* pageAgent, InspectorMemoryAgent* memoryAgent, InspectorCompositeState* state, InspectorType type, InspectorClient* client) 646 : InspectorBaseAgent<InspectorTimelineAgent>("Timeline", instrumentingAgents, state) 647 , m_pageAgent(pageAgent) 648 , m_memoryAgent(memoryAgent) 649 , m_frontend(0) 650 , m_id(1) 651 , m_maxCallStackDepth(5) 652 , m_platformInstrumentationClientInstalledAtStackDepth(0) 653 , m_inspectorType(type) 654 , m_client(client) 655 , m_weakFactory(this) 656{ 657} 658 659void InspectorTimelineAgent::appendRecord(PassRefPtr<InspectorObject> data, const String& type, bool captureCallStack, Frame* frame) 660{ 661 pushGCEventRecords(); 662 RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(timestamp(), captureCallStack ? m_maxCallStackDepth : 0); 663 record->setObject("data", data); 664 setFrameIdentifier(record.get(), frame); 665 addRecordToTimeline(record.release(), type); 666} 667 668void InspectorTimelineAgent::sendEvent(PassRefPtr<InspectorObject> event) 669{ 670 // FIXME: runtimeCast is a hack. We do it because we can't build TimelineEvent directly now. 671 RefPtr<TypeBuilder::Timeline::TimelineEvent> recordChecked = TypeBuilder::Timeline::TimelineEvent::runtimeCast(event); 672 m_frontend->eventRecorded(recordChecked.release()); 673} 674 675void InspectorTimelineAgent::pushCurrentRecord(PassRefPtr<InspectorObject> data, const String& type, bool captureCallStack, Frame* frame, bool hasLowLevelDetails) 676{ 677 pushGCEventRecords(); 678 commitFrameRecord(); 679 RefPtr<InspectorObject> record = TimelineRecordFactory::createGenericRecord(timestamp(), captureCallStack ? m_maxCallStackDepth : 0); 680 setFrameIdentifier(record.get(), frame); 681 m_recordStack.append(TimelineRecordEntry(record.release(), data, InspectorArray::create(), type, getUsedHeapSize())); 682 if (hasLowLevelDetails && !m_platformInstrumentationClientInstalledAtStackDepth && !PlatformInstrumentation::hasClient()) { 683 m_platformInstrumentationClientInstalledAtStackDepth = m_recordStack.size(); 684 PlatformInstrumentation::setClient(this); 685 } 686} 687 688void InspectorTimelineAgent::commitFrameRecord() 689{ 690 if (!m_pendingFrameRecord) 691 return; 692 693 m_pendingFrameRecord->setObject("data", InspectorObject::create()); 694 innerAddRecordToTimeline(m_pendingFrameRecord.release(), TimelineRecordType::BeginFrame); 695} 696 697void InspectorTimelineAgent::clearRecordStack() 698{ 699 if (m_platformInstrumentationClientInstalledAtStackDepth) { 700 m_platformInstrumentationClientInstalledAtStackDepth = 0; 701 PlatformInstrumentation::setClient(0); 702 } 703 m_pendingFrameRecord.clear(); 704 m_recordStack.clear(); 705 m_id++; 706} 707 708void InspectorTimelineAgent::localToPageQuad(const RenderObject& renderer, const LayoutRect& rect, FloatQuad* quad) 709{ 710 Frame* frame = renderer.frame(); 711 FrameView* view = frame->view(); 712 FloatQuad absolute = renderer.localToAbsoluteQuad(FloatQuad(rect)); 713 quad->setP1(view->contentsToRootView(roundedIntPoint(absolute.p1()))); 714 quad->setP2(view->contentsToRootView(roundedIntPoint(absolute.p2()))); 715 quad->setP3(view->contentsToRootView(roundedIntPoint(absolute.p3()))); 716 quad->setP4(view->contentsToRootView(roundedIntPoint(absolute.p4()))); 717} 718 719double InspectorTimelineAgent::timestamp() 720{ 721 return m_timeConverter.fromMonotonicallyIncreasingTime(WTF::monotonicallyIncreasingTime()); 722} 723 724Page* InspectorTimelineAgent::page() 725{ 726 return m_pageAgent ? m_pageAgent->page() : 0; 727} 728 729} // namespace WebCore 730 731#endif // ENABLE(INSPECTOR) 732