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 #include "core/inspector/InspectorTimelineAgent.h" 33 34 #include "core/events/Event.h" 35 #include "core/frame/LocalDOMWindow.h" 36 #include "core/frame/FrameConsole.h" 37 #include "core/frame/FrameHost.h" 38 #include "core/frame/FrameView.h" 39 #include "core/frame/LocalFrame.h" 40 #include "core/inspector/ConsoleMessage.h" 41 #include "core/inspector/IdentifiersFactory.h" 42 #include "core/inspector/InspectorClient.h" 43 #include "core/inspector/InspectorCounters.h" 44 #include "core/inspector/InspectorInstrumentation.h" 45 #include "core/inspector/InspectorLayerTreeAgent.h" 46 #include "core/inspector/InspectorNodeIds.h" 47 #include "core/inspector/InspectorOverlay.h" 48 #include "core/inspector/InspectorPageAgent.h" 49 #include "core/inspector/InspectorState.h" 50 #include "core/inspector/InstrumentingAgents.h" 51 #include "core/inspector/ScriptCallStack.h" 52 #include "core/inspector/TimelineRecordFactory.h" 53 #include "core/inspector/TraceEventDispatcher.h" 54 #include "core/loader/DocumentLoader.h" 55 #include "core/page/Page.h" 56 #include "core/rendering/RenderObject.h" 57 #include "core/rendering/RenderView.h" 58 #include "core/xml/XMLHttpRequest.h" 59 #include "platform/TraceEvent.h" 60 #include "platform/graphics/DeferredImageDecoder.h" 61 #include "platform/graphics/GraphicsLayer.h" 62 #include "platform/network/ResourceRequest.h" 63 #include "wtf/CurrentTime.h" 64 #include "wtf/DateMath.h" 65 66 namespace blink { 67 68 namespace TimelineAgentState { 69 static const char enabled[] = "enabled"; 70 static const char started[] = "started"; 71 static const char startedFromProtocol[] = "startedFromProtocol"; 72 static const char timelineMaxCallStackDepth[] = "timelineMaxCallStackDepth"; 73 static const char includeCounters[] = "includeCounters"; 74 static const char includeGPUEvents[] = "includeGPUEvents"; 75 static const char bufferEvents[] = "bufferEvents"; 76 static const char liveEvents[] = "liveEvents"; 77 } 78 79 // Must be kept in sync with WebInspector.TimelineModel.RecordType in TimelineModel.js 80 namespace TimelineRecordType { 81 static const char Program[] = "Program"; 82 83 static const char EventDispatch[] = "EventDispatch"; 84 static const char ScheduleStyleRecalculation[] = "ScheduleStyleRecalculation"; 85 static const char RecalculateStyles[] = "RecalculateStyles"; 86 static const char InvalidateLayout[] = "InvalidateLayout"; 87 static const char Layout[] = "Layout"; 88 static const char UpdateLayerTree[] = "UpdateLayerTree"; 89 static const char Paint[] = "Paint"; 90 static const char ScrollLayer[] = "ScrollLayer"; 91 static const char ResizeImage[] = "ResizeImage"; 92 static const char CompositeLayers[] = "CompositeLayers"; 93 94 static const char ParseHTML[] = "ParseHTML"; 95 96 static const char TimerInstall[] = "TimerInstall"; 97 static const char TimerRemove[] = "TimerRemove"; 98 static const char TimerFire[] = "TimerFire"; 99 100 static const char EvaluateScript[] = "EvaluateScript"; 101 102 static const char MarkLoad[] = "MarkLoad"; 103 static const char MarkDOMContent[] = "MarkDOMContent"; 104 static const char MarkFirstPaint[] = "MarkFirstPaint"; 105 106 static const char TimeStamp[] = "TimeStamp"; 107 static const char ConsoleTime[] = "ConsoleTime"; 108 109 static const char ResourceSendRequest[] = "ResourceSendRequest"; 110 static const char ResourceReceiveResponse[] = "ResourceReceiveResponse"; 111 static const char ResourceReceivedData[] = "ResourceReceivedData"; 112 static const char ResourceFinish[] = "ResourceFinish"; 113 114 static const char XHRReadyStateChange[] = "XHRReadyStateChange"; 115 static const char XHRLoad[] = "XHRLoad"; 116 117 static const char FunctionCall[] = "FunctionCall"; 118 static const char GCEvent[] = "GCEvent"; 119 120 static const char UpdateCounters[] = "UpdateCounters"; 121 122 static const char RequestAnimationFrame[] = "RequestAnimationFrame"; 123 static const char CancelAnimationFrame[] = "CancelAnimationFrame"; 124 static const char FireAnimationFrame[] = "FireAnimationFrame"; 125 126 static const char WebSocketCreate[] = "WebSocketCreate"; 127 static const char WebSocketSendHandshakeRequest[] = "WebSocketSendHandshakeRequest"; 128 static const char WebSocketReceiveHandshakeResponse[] = "WebSocketReceiveHandshakeResponse"; 129 static const char WebSocketDestroy[] = "WebSocketDestroy"; 130 131 static const char RequestMainThreadFrame[] = "RequestMainThreadFrame"; 132 static const char ActivateLayerTree[] = "ActivateLayerTree"; 133 static const char DrawFrame[] = "DrawFrame"; 134 static const char BeginFrame[] = "BeginFrame"; 135 static const char DecodeImage[] = "DecodeImage"; 136 static const char GPUTask[] = "GPUTask"; 137 static const char Rasterize[] = "Rasterize"; 138 static const char PaintSetup[] = "PaintSetup"; 139 140 static const char EmbedderCallback[] = "EmbedderCallback"; 141 } 142 143 using TypeBuilder::Timeline::TimelineEvent; 144 145 class InspectorTimelineAgentTraceEventListener : public TraceEventDispatcher::TraceEventListener { 146 public: 147 typedef void (InspectorTimelineAgent::*TraceEventHandlerMethod)(const TraceEventDispatcher::TraceEvent&); 148 static PassOwnPtrWillBeRawPtr<InspectorTimelineAgentTraceEventListener> create(InspectorTimelineAgent* instance, TraceEventHandlerMethod method) 149 { 150 return adoptPtrWillBeNoop(new InspectorTimelineAgentTraceEventListener(instance, method)); 151 } 152 virtual void call(const TraceEventDispatcher::TraceEvent& event) OVERRIDE 153 { 154 (m_instance->*m_method)(event); 155 } 156 virtual void* target() OVERRIDE 157 { 158 return m_instance; 159 } 160 virtual void trace(Visitor* visitor) OVERRIDE 161 { 162 visitor->trace(m_instance); 163 TraceEventDispatcher::TraceEventListener::trace(visitor); 164 } 165 166 private: 167 InspectorTimelineAgentTraceEventListener(InspectorTimelineAgent* instance, TraceEventHandlerMethod method) 168 : m_instance(instance) 169 , m_method(method) 170 { 171 } 172 RawPtrWillBeMember<InspectorTimelineAgent> m_instance; 173 TraceEventHandlerMethod m_method; 174 }; 175 176 struct TimelineRecordEntry { 177 TimelineRecordEntry(PassRefPtr<TimelineEvent> record, PassRefPtr<JSONObject> data, PassRefPtr<TypeBuilder::Array<TimelineEvent> > children, const String& type) 178 : record(record) 179 , data(data) 180 , children(children) 181 , type(type) 182 , skipWhenUnbalanced(false) 183 { 184 } 185 RefPtr<TimelineEvent> record; 186 RefPtr<JSONObject> data; 187 RefPtr<TypeBuilder::Array<TimelineEvent> > children; 188 String type; 189 bool skipWhenUnbalanced; 190 }; 191 192 class TimelineRecordStack { 193 DISALLOW_ALLOCATION(); 194 private: 195 struct Entry { 196 Entry(PassRefPtr<TimelineEvent> record, const String& type) 197 : record(record) 198 , children(TypeBuilder::Array<TimelineEvent>::create()) 199 #if ENABLE(ASSERT) 200 , type(type) 201 #endif 202 { 203 } 204 205 RefPtr<TimelineEvent> record; 206 RefPtr<TypeBuilder::Array<TimelineEvent> > children; 207 #if ENABLE(ASSERT) 208 String type; 209 #endif 210 }; 211 212 public: 213 TimelineRecordStack() : m_timelineAgent(nullptr) { } 214 explicit TimelineRecordStack(InspectorTimelineAgent*); 215 216 void addScopedRecord(PassRefPtr<TimelineEvent> record, const String& type); 217 void closeScopedRecord(double endTime); 218 void addInstantRecord(PassRefPtr<TimelineEvent> record); 219 220 #if ENABLE(ASSERT) 221 bool isOpenRecordOfType(const String& type); 222 #endif 223 224 void trace(Visitor*); 225 226 private: 227 void send(PassRefPtr<JSONObject>); 228 229 RawPtrWillBeMember<InspectorTimelineAgent> m_timelineAgent; 230 Vector<Entry> m_stack; 231 }; 232 233 struct TimelineThreadState { 234 ALLOW_ONLY_INLINE_ALLOCATION(); 235 public: 236 TimelineThreadState() { } 237 238 TimelineThreadState(InspectorTimelineAgent* timelineAgent) 239 : recordStack(timelineAgent) 240 , inKnownLayerTask(false) 241 , decodedPixelRefId(0) 242 { 243 } 244 245 void trace(Visitor*); 246 247 TimelineRecordStack recordStack; 248 bool inKnownLayerTask; 249 unsigned long long decodedPixelRefId; 250 }; 251 252 struct TimelineImageInfo { 253 int backendNodeId; 254 String url; 255 256 TimelineImageInfo() : backendNodeId(0) { } 257 TimelineImageInfo(int backendNodeId, String url) : backendNodeId(backendNodeId), url(url) { } 258 }; 259 260 static LocalFrame* frameForExecutionContext(ExecutionContext* context) 261 { 262 LocalFrame* frame = 0; 263 if (context->isDocument()) 264 frame = toDocument(context)->frame(); 265 return frame; 266 } 267 268 static bool eventHasListeners(const AtomicString& eventType, LocalDOMWindow* window, Node* node, const EventPath& eventPath) 269 { 270 if (window && window->hasEventListeners(eventType)) 271 return true; 272 273 if (node->hasEventListeners(eventType)) 274 return true; 275 276 for (size_t i = 0; i < eventPath.size(); i++) { 277 if (eventPath[i].node()->hasEventListeners(eventType)) 278 return true; 279 } 280 281 return false; 282 } 283 284 void InspectorTimelineAgent::didGC(double startTime, double endTime, size_t collectedBytesCount) 285 { 286 RefPtr<TimelineEvent> record = TimelineRecordFactory::createGenericRecord( 287 startTime * msPerSecond, 288 0, 289 TimelineRecordType::GCEvent, 290 TimelineRecordFactory::createGCEventData(collectedBytesCount)); 291 record->setEndTime(endTime * msPerSecond); 292 double time = timestamp(); 293 addRecordToTimeline(record.release(), time); 294 if (m_state->getBoolean(TimelineAgentState::includeCounters)) { 295 addRecordToTimeline(createCountersUpdate(), time); 296 } 297 } 298 299 InspectorTimelineAgent::~InspectorTimelineAgent() 300 { 301 } 302 303 void InspectorTimelineAgent::trace(Visitor* visitor) 304 { 305 visitor->trace(m_pageAgent); 306 visitor->trace(m_layerTreeAgent); 307 #if ENABLE(OILPAN) 308 visitor->trace(m_threadStates); 309 #endif 310 InspectorBaseAgent::trace(visitor); 311 } 312 313 void InspectorTimelineAgent::setFrontend(InspectorFrontend* frontend) 314 { 315 m_frontend = frontend->timeline(); 316 } 317 318 void InspectorTimelineAgent::clearFrontend() 319 { 320 ErrorString error; 321 stop(&error); 322 disable(&error); 323 m_frontend = 0; 324 } 325 326 void InspectorTimelineAgent::restore() 327 { 328 if (m_state->getBoolean(TimelineAgentState::startedFromProtocol)) { 329 if (m_state->getBoolean(TimelineAgentState::bufferEvents)) 330 m_bufferedEvents = TypeBuilder::Array<TimelineEvent>::create(); 331 332 setLiveEvents(m_state->getString(TimelineAgentState::liveEvents)); 333 innerStart(); 334 } else if (isStarted()) { 335 // Timeline was started from console.timeline, it is not restored. 336 // Tell front-end timline is no longer collecting. 337 m_state->setBoolean(TimelineAgentState::started, false); 338 bool fromConsole = true; 339 m_frontend->stopped(&fromConsole, nullptr); 340 } 341 } 342 343 void InspectorTimelineAgent::enable(ErrorString*) 344 { 345 m_state->setBoolean(TimelineAgentState::enabled, true); 346 } 347 348 void InspectorTimelineAgent::disable(ErrorString*) 349 { 350 m_state->setBoolean(TimelineAgentState::enabled, false); 351 } 352 353 void InspectorTimelineAgent::start(ErrorString* errorString, const int* maxCallStackDepth, const bool* bufferEvents, const String* liveEvents, const bool* includeCounters, const bool* includeGPUEvents) 354 { 355 if (!m_frontend) 356 return; 357 m_state->setBoolean(TimelineAgentState::startedFromProtocol, true); 358 359 if (isStarted()) { 360 *errorString = "Timeline is already started"; 361 return; 362 } 363 364 if (maxCallStackDepth && *maxCallStackDepth >= 0) 365 m_maxCallStackDepth = *maxCallStackDepth; 366 else 367 m_maxCallStackDepth = 5; 368 369 if (asBool(bufferEvents)) { 370 m_bufferedEvents = TypeBuilder::Array<TimelineEvent>::create(); 371 m_lastProgressTimestamp = timestamp(); 372 } 373 374 if (liveEvents) 375 setLiveEvents(*liveEvents); 376 377 m_state->setLong(TimelineAgentState::timelineMaxCallStackDepth, m_maxCallStackDepth); 378 m_state->setBoolean(TimelineAgentState::includeCounters, asBool(includeCounters)); 379 m_state->setBoolean(TimelineAgentState::includeGPUEvents, asBool(includeGPUEvents)); 380 m_state->setBoolean(TimelineAgentState::bufferEvents, asBool(bufferEvents)); 381 m_state->setString(TimelineAgentState::liveEvents, liveEvents ? *liveEvents : ""); 382 383 innerStart(); 384 bool fromConsole = false; 385 m_frontend->started(&fromConsole); 386 } 387 388 bool InspectorTimelineAgent::isStarted() 389 { 390 return m_state->getBoolean(TimelineAgentState::started); 391 } 392 393 void InspectorTimelineAgent::innerStart() 394 { 395 if (m_overlay) 396 m_overlay->startedRecordingProfile(); 397 m_state->setBoolean(TimelineAgentState::started, true); 398 m_instrumentingAgents->setInspectorTimelineAgent(this); 399 ScriptGCEvent::addEventListener(this); 400 if (m_client) { 401 TraceEventDispatcher* dispatcher = TraceEventDispatcher::instance(); 402 dispatcher->addListener(InstrumentationEvents::BeginFrame, TRACE_EVENT_PHASE_INSTANT, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onBeginImplSideFrame), m_client); 403 dispatcher->addListener(InstrumentationEvents::PaintSetup, TRACE_EVENT_PHASE_BEGIN, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onPaintSetupBegin), m_client); 404 dispatcher->addListener(InstrumentationEvents::PaintSetup, TRACE_EVENT_PHASE_END, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onPaintSetupEnd), m_client); 405 dispatcher->addListener(InstrumentationEvents::RasterTask, TRACE_EVENT_PHASE_BEGIN, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onRasterTaskBegin), m_client); 406 dispatcher->addListener(InstrumentationEvents::RasterTask, TRACE_EVENT_PHASE_END, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onRasterTaskEnd), m_client); 407 dispatcher->addListener(InstrumentationEvents::Layer, TRACE_EVENT_PHASE_DELETE_OBJECT, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onLayerDeleted), m_client); 408 dispatcher->addListener(InstrumentationEvents::RequestMainThreadFrame, TRACE_EVENT_PHASE_INSTANT, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onRequestMainThreadFrame), m_client); 409 dispatcher->addListener(InstrumentationEvents::ActivateLayerTree, TRACE_EVENT_PHASE_INSTANT, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onActivateLayerTree), m_client); 410 dispatcher->addListener(InstrumentationEvents::DrawFrame, TRACE_EVENT_PHASE_INSTANT, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onDrawFrame), m_client); 411 dispatcher->addListener(PlatformInstrumentation::ImageDecodeEvent, TRACE_EVENT_PHASE_BEGIN, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onImageDecodeBegin), m_client); 412 dispatcher->addListener(PlatformInstrumentation::ImageDecodeEvent, TRACE_EVENT_PHASE_END, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onImageDecodeEnd), m_client); 413 dispatcher->addListener(PlatformInstrumentation::DrawLazyPixelRefEvent, TRACE_EVENT_PHASE_INSTANT, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onDrawLazyPixelRef), m_client); 414 dispatcher->addListener(PlatformInstrumentation::DecodeLazyPixelRefEvent, TRACE_EVENT_PHASE_BEGIN, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onDecodeLazyPixelRefBegin), m_client); 415 dispatcher->addListener(PlatformInstrumentation::DecodeLazyPixelRefEvent, TRACE_EVENT_PHASE_END, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onDecodeLazyPixelRefEnd), m_client); 416 dispatcher->addListener(PlatformInstrumentation::LazyPixelRef, TRACE_EVENT_PHASE_DELETE_OBJECT, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onLazyPixelRefDeleted), m_client); 417 dispatcher->addListener(InstrumentationEvents::EmbedderCallback, TRACE_EVENT_PHASE_BEGIN, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onEmbedderCallbackBegin), m_client); 418 dispatcher->addListener(InstrumentationEvents::EmbedderCallback, TRACE_EVENT_PHASE_END, InspectorTimelineAgentTraceEventListener::create(this, &InspectorTimelineAgent::onEmbedderCallbackEnd), m_client); 419 420 if (m_state->getBoolean(TimelineAgentState::includeGPUEvents)) { 421 m_pendingGPURecord.clear(); 422 m_client->startGPUEventsRecording(); 423 } 424 } 425 } 426 427 void InspectorTimelineAgent::stop(ErrorString* errorString) 428 { 429 m_state->setBoolean(TimelineAgentState::startedFromProtocol, false); 430 m_state->setBoolean(TimelineAgentState::bufferEvents, false); 431 m_state->setString(TimelineAgentState::liveEvents, ""); 432 433 if (!isStarted()) { 434 *errorString = "Timeline was not started"; 435 return; 436 } 437 innerStop(false); 438 m_liveEvents.clear(); 439 } 440 441 void InspectorTimelineAgent::innerStop(bool fromConsole) 442 { 443 m_state->setBoolean(TimelineAgentState::started, false); 444 445 if (m_client) { 446 TraceEventDispatcher::instance()->removeAllListeners(this, m_client); 447 if (m_state->getBoolean(TimelineAgentState::includeGPUEvents)) 448 m_client->stopGPUEventsRecording(); 449 } 450 m_instrumentingAgents->setInspectorTimelineAgent(0); 451 ScriptGCEvent::removeEventListener(this); 452 453 clearRecordStack(); 454 m_threadStates.clear(); 455 m_gpuTask.clear(); 456 m_layerToNodeMap.clear(); 457 m_pixelRefToImageInfo.clear(); 458 m_imageBeingPainted = 0; 459 m_paintSetupStart = 0; 460 m_mayEmitFirstPaint = false; 461 462 for (size_t i = 0; i < m_consoleTimelines.size(); ++i) { 463 String message = String::format("Timeline '%s' terminated.", m_consoleTimelines[i].utf8().data()); 464 mainFrame()->console().addMessage(ConsoleMessage::create(JSMessageSource, DebugMessageLevel, message)); 465 } 466 m_consoleTimelines.clear(); 467 468 m_frontend->stopped(&fromConsole, m_bufferedEvents.release()); 469 if (m_overlay) 470 m_overlay->finishedRecordingProfile(); 471 } 472 473 void InspectorTimelineAgent::didBeginFrame(int frameId) 474 { 475 TraceEventDispatcher::instance()->processBackgroundEvents(); 476 m_pendingFrameRecord = TimelineRecordFactory::createGenericRecord(timestamp(), 0, TimelineRecordType::BeginFrame, TimelineRecordFactory::createFrameData(frameId)); 477 } 478 479 void InspectorTimelineAgent::didCancelFrame() 480 { 481 m_pendingFrameRecord.clear(); 482 } 483 484 bool InspectorTimelineAgent::willCallFunction(ExecutionContext* context, int scriptId, const String& scriptName, int scriptLine) 485 { 486 pushCurrentRecord(TimelineRecordFactory::createFunctionCallData(scriptId, scriptName, scriptLine), TimelineRecordType::FunctionCall, true, frameForExecutionContext(context)); 487 return true; 488 } 489 490 void InspectorTimelineAgent::didCallFunction() 491 { 492 didCompleteCurrentRecord(TimelineRecordType::FunctionCall); 493 } 494 495 bool InspectorTimelineAgent::willDispatchEvent(Document* document, const Event& event, LocalDOMWindow* window, Node* node, const EventPath& eventPath) 496 { 497 if (!eventHasListeners(event.type(), window, node, eventPath)) 498 return false; 499 500 pushCurrentRecord(TimelineRecordFactory::createEventDispatchData(event), TimelineRecordType::EventDispatch, false, document->frame()); 501 return true; 502 } 503 504 bool InspectorTimelineAgent::willDispatchEventOnWindow(const Event& event, LocalDOMWindow* window) 505 { 506 if (!window->hasEventListeners(event.type())) 507 return false; 508 pushCurrentRecord(TimelineRecordFactory::createEventDispatchData(event), TimelineRecordType::EventDispatch, false, window->frame()); 509 return true; 510 } 511 512 void InspectorTimelineAgent::didDispatchEvent() 513 { 514 didCompleteCurrentRecord(TimelineRecordType::EventDispatch); 515 } 516 517 void InspectorTimelineAgent::didDispatchEventOnWindow() 518 { 519 didDispatchEvent(); 520 } 521 522 void InspectorTimelineAgent::didInvalidateLayout(LocalFrame* frame) 523 { 524 appendRecord(JSONObject::create(), TimelineRecordType::InvalidateLayout, true, frame); 525 } 526 527 bool InspectorTimelineAgent::willLayout(LocalFrame* frame) 528 { 529 bool isPartial; 530 unsigned needsLayoutObjects; 531 unsigned totalObjects; 532 frame->countObjectsNeedingLayout(needsLayoutObjects, totalObjects, isPartial); 533 534 pushCurrentRecord(TimelineRecordFactory::createLayoutData(needsLayoutObjects, totalObjects, isPartial), TimelineRecordType::Layout, true, frame); 535 return true; 536 } 537 538 void InspectorTimelineAgent::didLayout(RenderObject* root) 539 { 540 if (m_recordStack.isEmpty()) 541 return; 542 TimelineRecordEntry& entry = m_recordStack.last(); 543 ASSERT(entry.type == TimelineRecordType::Layout); 544 Vector<FloatQuad> quads; 545 root->absoluteQuads(quads); 546 if (quads.size() >= 1) 547 TimelineRecordFactory::setLayoutRoot(entry.data.get(), quads[0], nodeId(root)); 548 else 549 ASSERT_NOT_REACHED(); 550 didCompleteCurrentRecord(TimelineRecordType::Layout); 551 } 552 553 void InspectorTimelineAgent::layerTreeDidChange() 554 { 555 ASSERT(!m_pendingLayerTreeData); 556 m_pendingLayerTreeData = m_layerTreeAgent->buildLayerTree(); 557 } 558 559 void InspectorTimelineAgent::willUpdateLayerTree() 560 { 561 pushCurrentRecord(JSONObject::create(), TimelineRecordType::UpdateLayerTree, false, 0); 562 } 563 564 void InspectorTimelineAgent::didUpdateLayerTree() 565 { 566 if (m_recordStack.isEmpty()) 567 return; 568 TimelineRecordEntry& entry = m_recordStack.last(); 569 ASSERT(entry.type == TimelineRecordType::UpdateLayerTree); 570 if (m_pendingLayerTreeData) 571 TimelineRecordFactory::setLayerTreeData(entry.data.get(), m_pendingLayerTreeData.release()); 572 didCompleteCurrentRecord(TimelineRecordType::UpdateLayerTree); 573 } 574 575 void InspectorTimelineAgent::didScheduleStyleRecalculation(Document* document) 576 { 577 appendRecord(JSONObject::create(), TimelineRecordType::ScheduleStyleRecalculation, true, document->frame()); 578 } 579 580 bool InspectorTimelineAgent::willRecalculateStyle(Document* document) 581 { 582 pushCurrentRecord(JSONObject::create(), TimelineRecordType::RecalculateStyles, true, document->frame()); 583 return true; 584 } 585 586 void InspectorTimelineAgent::didRecalculateStyle(int elementCount) 587 { 588 if (m_recordStack.isEmpty()) 589 return; 590 TimelineRecordEntry& entry = m_recordStack.last(); 591 ASSERT(entry.type == TimelineRecordType::RecalculateStyles); 592 TimelineRecordFactory::setStyleRecalcDetails(entry.data.get(), elementCount); 593 didCompleteCurrentRecord(TimelineRecordType::RecalculateStyles); 594 } 595 596 void InspectorTimelineAgent::willPaint(RenderObject* renderer, const GraphicsLayer* graphicsLayer) 597 { 598 LocalFrame* frame = renderer->frame(); 599 600 TraceEventDispatcher::instance()->processBackgroundEvents(); 601 double paintSetupStart = m_paintSetupStart; 602 m_paintSetupStart = 0; 603 if (graphicsLayer) { 604 int layerIdentifier = graphicsLayer->platformLayer()->id(); 605 int nodeIdentifier = nodeId(renderer); 606 ASSERT(layerIdentifier && nodeIdentifier); 607 m_layerToNodeMap.set(layerIdentifier, nodeIdentifier); 608 if (paintSetupStart) { 609 RefPtr<TimelineEvent> paintSetupRecord = TimelineRecordFactory::createGenericRecord(paintSetupStart, 0, TimelineRecordType::PaintSetup, TimelineRecordFactory::createLayerData(nodeIdentifier)); 610 paintSetupRecord->setEndTime(m_paintSetupEnd); 611 addRecordToTimeline(paintSetupRecord, paintSetupStart); 612 } 613 } 614 pushCurrentRecord(JSONObject::create(), TimelineRecordType::Paint, true, frame, true); 615 } 616 617 void InspectorTimelineAgent::didPaint(RenderObject* renderer, const GraphicsLayer* graphicsLayer, GraphicsContext*, const LayoutRect& clipRect) 618 { 619 TimelineRecordEntry& entry = m_recordStack.last(); 620 ASSERT(entry.type == TimelineRecordType::Paint); 621 FloatQuad quad; 622 localToPageQuad(*renderer, clipRect, &quad); 623 int graphicsLayerId = graphicsLayer ? graphicsLayer->platformLayer()->id() : 0; 624 TimelineRecordFactory::setPaintData(entry.data.get(), quad, nodeId(renderer), graphicsLayerId); 625 didCompleteCurrentRecord(TimelineRecordType::Paint); 626 if (m_mayEmitFirstPaint && !graphicsLayer) { 627 m_mayEmitFirstPaint = false; 628 appendRecord(JSONObject::create(), TimelineRecordType::MarkFirstPaint, false, 0); 629 } 630 } 631 632 void InspectorTimelineAgent::willPaintImage(RenderImage* renderImage) 633 { 634 ASSERT(!m_imageBeingPainted); 635 m_imageBeingPainted = renderImage; 636 } 637 638 void InspectorTimelineAgent::didPaintImage() 639 { 640 m_imageBeingPainted = 0; 641 } 642 643 void InspectorTimelineAgent::willScrollLayer(RenderObject* renderer) 644 { 645 pushCurrentRecord(TimelineRecordFactory::createLayerData(nodeId(renderer)), TimelineRecordType::ScrollLayer, false, renderer->frame()); 646 } 647 648 void InspectorTimelineAgent::didScrollLayer() 649 { 650 didCompleteCurrentRecord(TimelineRecordType::ScrollLayer); 651 } 652 653 void InspectorTimelineAgent::willDecodeImage(const String& imageType) 654 { 655 RefPtr<JSONObject> data = TimelineRecordFactory::createDecodeImageData(imageType); 656 if (m_imageBeingPainted) 657 populateImageDetails(data.get(), *m_imageBeingPainted); 658 pushCurrentRecord(data, TimelineRecordType::DecodeImage, true, 0); 659 } 660 661 void InspectorTimelineAgent::didDecodeImage() 662 { 663 didCompleteCurrentRecord(TimelineRecordType::DecodeImage); 664 } 665 666 void InspectorTimelineAgent::willResizeImage(bool shouldCache) 667 { 668 RefPtr<JSONObject> data = TimelineRecordFactory::createResizeImageData(shouldCache); 669 if (m_imageBeingPainted) 670 populateImageDetails(data.get(), *m_imageBeingPainted); 671 pushCurrentRecord(data, TimelineRecordType::ResizeImage, true, 0); 672 } 673 674 void InspectorTimelineAgent::didResizeImage() 675 { 676 didCompleteCurrentRecord(TimelineRecordType::ResizeImage); 677 } 678 679 void InspectorTimelineAgent::willComposite() 680 { 681 pushCurrentRecord(JSONObject::create(), TimelineRecordType::CompositeLayers, false, 0); 682 } 683 684 void InspectorTimelineAgent::didComposite() 685 { 686 didCompleteCurrentRecord(TimelineRecordType::CompositeLayers); 687 if (m_mayEmitFirstPaint) { 688 m_mayEmitFirstPaint = false; 689 appendRecord(JSONObject::create(), TimelineRecordType::MarkFirstPaint, false, 0); 690 } 691 } 692 693 bool InspectorTimelineAgent::willWriteHTML(Document* document, unsigned startLine) 694 { 695 pushCurrentRecord(TimelineRecordFactory::createParseHTMLData(startLine), TimelineRecordType::ParseHTML, true, document->frame()); 696 return true; 697 } 698 699 void InspectorTimelineAgent::didWriteHTML(unsigned endLine) 700 { 701 if (!m_recordStack.isEmpty()) { 702 TimelineRecordEntry& entry = m_recordStack.last(); 703 entry.data->setNumber("endLine", endLine); 704 didCompleteCurrentRecord(TimelineRecordType::ParseHTML); 705 } 706 } 707 708 void InspectorTimelineAgent::didInstallTimer(ExecutionContext* context, int timerId, int timeout, bool singleShot) 709 { 710 appendRecord(TimelineRecordFactory::createTimerInstallData(timerId, timeout, singleShot), TimelineRecordType::TimerInstall, true, frameForExecutionContext(context)); 711 } 712 713 void InspectorTimelineAgent::didRemoveTimer(ExecutionContext* context, int timerId) 714 { 715 appendRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerRemove, true, frameForExecutionContext(context)); 716 } 717 718 bool InspectorTimelineAgent::willFireTimer(ExecutionContext* context, int timerId) 719 { 720 pushCurrentRecord(TimelineRecordFactory::createGenericTimerData(timerId), TimelineRecordType::TimerFire, false, frameForExecutionContext(context)); 721 return true; 722 } 723 724 void InspectorTimelineAgent::didFireTimer() 725 { 726 didCompleteCurrentRecord(TimelineRecordType::TimerFire); 727 } 728 729 bool InspectorTimelineAgent::willDispatchXHRReadyStateChangeEvent(ExecutionContext* context, XMLHttpRequest* request) 730 { 731 if (!request->hasEventListeners(EventTypeNames::readystatechange)) 732 return false; 733 pushCurrentRecord(TimelineRecordFactory::createXHRReadyStateChangeData(request->url().string(), request->readyState()), TimelineRecordType::XHRReadyStateChange, false, frameForExecutionContext(context)); 734 return true; 735 } 736 737 void InspectorTimelineAgent::didDispatchXHRReadyStateChangeEvent() 738 { 739 didCompleteCurrentRecord(TimelineRecordType::XHRReadyStateChange); 740 } 741 742 bool InspectorTimelineAgent::willDispatchXHRLoadEvent(ExecutionContext* context, XMLHttpRequest* request) 743 { 744 if (!request->hasEventListeners(EventTypeNames::load)) 745 return false; 746 pushCurrentRecord(TimelineRecordFactory::createXHRLoadData(request->url().string()), TimelineRecordType::XHRLoad, true, frameForExecutionContext(context)); 747 return true; 748 } 749 750 void InspectorTimelineAgent::didDispatchXHRLoadEvent() 751 { 752 didCompleteCurrentRecord(TimelineRecordType::XHRLoad); 753 } 754 755 bool InspectorTimelineAgent::willEvaluateScript(LocalFrame* frame, const String& url, int lineNumber) 756 { 757 pushCurrentRecord(TimelineRecordFactory::createEvaluateScriptData(url, lineNumber), TimelineRecordType::EvaluateScript, true, frame); 758 return true; 759 } 760 761 void InspectorTimelineAgent::didEvaluateScript() 762 { 763 didCompleteCurrentRecord(TimelineRecordType::EvaluateScript); 764 } 765 766 void InspectorTimelineAgent::willSendRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request, const ResourceResponse&, const FetchInitiatorInfo&) 767 { 768 String requestId = IdentifiersFactory::requestId(identifier); 769 appendRecord(TimelineRecordFactory::createResourceSendRequestData(requestId, request), TimelineRecordType::ResourceSendRequest, true, loader->frame()); 770 } 771 772 void InspectorTimelineAgent::didReceiveData(LocalFrame* frame, unsigned long identifier, const char*, int, int encodedDataLength) 773 { 774 String requestId = IdentifiersFactory::requestId(identifier); 775 appendRecord(TimelineRecordFactory::createReceiveResourceData(requestId, encodedDataLength), TimelineRecordType::ResourceReceivedData, false, frame); 776 } 777 778 void InspectorTimelineAgent::didReceiveResourceResponse(LocalFrame* frame, unsigned long identifier, DocumentLoader* loader, const ResourceResponse& response, ResourceLoader* resourceLoader) 779 { 780 String requestId = IdentifiersFactory::requestId(identifier); 781 appendRecord(TimelineRecordFactory::createResourceReceiveResponseData(requestId, response), TimelineRecordType::ResourceReceiveResponse, false, 0); 782 } 783 784 void InspectorTimelineAgent::didFinishLoadingResource(unsigned long identifier, bool didFail, double finishTime) 785 { 786 appendRecord(TimelineRecordFactory::createResourceFinishData(IdentifiersFactory::requestId(identifier), didFail, finishTime), TimelineRecordType::ResourceFinish, false, 0); 787 } 788 789 void InspectorTimelineAgent::didFinishLoading(unsigned long identifier, DocumentLoader* loader, double monotonicFinishTime, int64_t) 790 { 791 didFinishLoadingResource(identifier, false, monotonicFinishTime * msPerSecond); 792 } 793 794 void InspectorTimelineAgent::didFailLoading(unsigned long identifier, const ResourceError& error) 795 { 796 didFinishLoadingResource(identifier, true, 0); 797 } 798 799 void InspectorTimelineAgent::consoleTimeStamp(ExecutionContext* context, const String& title) 800 { 801 appendRecord(TimelineRecordFactory::createTimeStampData(title), TimelineRecordType::TimeStamp, true, frameForExecutionContext(context)); 802 } 803 804 void InspectorTimelineAgent::consoleTime(ExecutionContext* context, const String& message) 805 { 806 pushCurrentRecord(TimelineRecordFactory::createConsoleTimeData(message), TimelineRecordType::ConsoleTime, false, frameForExecutionContext(context)); 807 m_recordStack.last().skipWhenUnbalanced = true; 808 } 809 810 void InspectorTimelineAgent::consoleTimeEnd(ExecutionContext* context, const String& message, ScriptState*) 811 { 812 if (m_recordStack.last().type != TimelineRecordType::ConsoleTime) 813 return; 814 String originalMessage; 815 if (m_recordStack.last().data->getString("message", &originalMessage) && message != originalMessage) 816 return; 817 // Only complete console.time that is balanced. 818 didCompleteCurrentRecord(TimelineRecordType::ConsoleTime); 819 } 820 821 void InspectorTimelineAgent::consoleTimeline(ExecutionContext* context, const String& title, ScriptState* scriptState) 822 { 823 if (!m_state->getBoolean(TimelineAgentState::enabled)) 824 return; 825 826 String message = String::format("Timeline '%s' started.", title.utf8().data()); 827 828 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(JSMessageSource, DebugMessageLevel, message); 829 consoleMessage->setScriptState(scriptState); 830 mainFrame()->console().addMessage(consoleMessage.release()); 831 m_consoleTimelines.append(title); 832 if (!isStarted()) { 833 m_state->setBoolean(TimelineAgentState::bufferEvents, true); 834 m_bufferedEvents = TypeBuilder::Array<TimelineEvent>::create(); 835 836 innerStart(); 837 bool fromConsole = true; 838 m_frontend->started(&fromConsole); 839 } 840 appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeStamp, true, frameForExecutionContext(context)); 841 } 842 843 void InspectorTimelineAgent::consoleTimelineEnd(ExecutionContext* context, const String& title, ScriptState* scriptState) 844 { 845 if (!m_state->getBoolean(TimelineAgentState::enabled)) 846 return; 847 848 size_t index = m_consoleTimelines.find(title); 849 if (index == kNotFound) { 850 String message = String::format("Timeline '%s' was not started.", title.utf8().data()); 851 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(JSMessageSource, DebugMessageLevel, message); 852 consoleMessage->setScriptState(scriptState); 853 mainFrame()->console().addMessage(consoleMessage.release()); 854 return; 855 } 856 857 String message = String::format("Timeline '%s' finished.", title.utf8().data()); 858 appendRecord(TimelineRecordFactory::createTimeStampData(message), TimelineRecordType::TimeStamp, true, frameForExecutionContext(context)); 859 m_consoleTimelines.remove(index); 860 if (!m_consoleTimelines.size() && isStarted() && !m_state->getBoolean(TimelineAgentState::startedFromProtocol)) { 861 unwindRecordStack(); 862 innerStop(true); 863 } 864 RefPtrWillBeRawPtr<ConsoleMessage> consoleMessage = ConsoleMessage::create(JSMessageSource, DebugMessageLevel, message); 865 consoleMessage->setScriptState(scriptState); 866 mainFrame()->console().addMessage(consoleMessage.release()); 867 } 868 869 void InspectorTimelineAgent::domContentLoadedEventFired(LocalFrame* frame) 870 { 871 bool isMainFrame = frame && m_pageAgent && (frame == m_pageAgent->mainFrame()); 872 appendRecord(TimelineRecordFactory::createMarkData(isMainFrame), TimelineRecordType::MarkDOMContent, false, frame); 873 if (isMainFrame) 874 m_mayEmitFirstPaint = true; 875 } 876 877 void InspectorTimelineAgent::loadEventFired(LocalFrame* frame) 878 { 879 bool isMainFrame = frame && m_pageAgent && (frame == m_pageAgent->mainFrame()); 880 appendRecord(TimelineRecordFactory::createMarkData(isMainFrame), TimelineRecordType::MarkLoad, false, frame); 881 } 882 883 void InspectorTimelineAgent::didCommitLoad() 884 { 885 clearRecordStack(); 886 } 887 888 void InspectorTimelineAgent::didRequestAnimationFrame(Document* document, int callbackId) 889 { 890 appendRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::RequestAnimationFrame, true, document->frame()); 891 } 892 893 void InspectorTimelineAgent::didCancelAnimationFrame(Document* document, int callbackId) 894 { 895 appendRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::CancelAnimationFrame, true, document->frame()); 896 } 897 898 bool InspectorTimelineAgent::willFireAnimationFrame(Document* document, int callbackId) 899 { 900 pushCurrentRecord(TimelineRecordFactory::createAnimationFrameData(callbackId), TimelineRecordType::FireAnimationFrame, false, document->frame()); 901 return true; 902 } 903 904 void InspectorTimelineAgent::didFireAnimationFrame() 905 { 906 didCompleteCurrentRecord(TimelineRecordType::FireAnimationFrame); 907 } 908 909 void InspectorTimelineAgent::willProcessTask() 910 { 911 pushCurrentRecord(JSONObject::create(), TimelineRecordType::Program, false, 0); 912 } 913 914 void InspectorTimelineAgent::didProcessTask() 915 { 916 didCompleteCurrentRecord(TimelineRecordType::Program); 917 } 918 919 void InspectorTimelineAgent::didCreateWebSocket(Document* document, unsigned long identifier, const KURL& url, const String& protocol) 920 { 921 appendRecord(TimelineRecordFactory::createWebSocketCreateData(identifier, url, protocol), TimelineRecordType::WebSocketCreate, true, document->frame()); 922 } 923 924 void InspectorTimelineAgent::willSendWebSocketHandshakeRequest(Document* document, unsigned long identifier, const WebSocketHandshakeRequest*) 925 { 926 appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketSendHandshakeRequest, true, document->frame()); 927 } 928 929 void InspectorTimelineAgent::didReceiveWebSocketHandshakeResponse(Document* document, unsigned long identifier, const WebSocketHandshakeRequest*, const WebSocketHandshakeResponse*) 930 { 931 appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketReceiveHandshakeResponse, false, document->frame()); 932 } 933 934 void InspectorTimelineAgent::didCloseWebSocket(Document* document, unsigned long identifier) 935 { 936 appendRecord(TimelineRecordFactory::createGenericWebSocketData(identifier), TimelineRecordType::WebSocketDestroy, true, document->frame()); 937 } 938 939 void InspectorTimelineAgent::onBeginImplSideFrame(const TraceEventDispatcher::TraceEvent& event) 940 { 941 unsigned long long layerTreeId = event.asUInt(InstrumentationEventArguments::LayerTreeId); 942 if (layerTreeId != m_layerTreeId) 943 return; 944 TimelineThreadState& state = threadState(event.threadIdentifier()); 945 state.recordStack.addInstantRecord(createRecordForEvent(event, TimelineRecordType::BeginFrame, JSONObject::create())); 946 } 947 948 void InspectorTimelineAgent::onPaintSetupBegin(const TraceEventDispatcher::TraceEvent& event) 949 { 950 ASSERT(!m_paintSetupStart); 951 m_paintSetupStart = event.timestamp() * msPerSecond; 952 } 953 954 void InspectorTimelineAgent::onPaintSetupEnd(const TraceEventDispatcher::TraceEvent& event) 955 { 956 ASSERT(m_paintSetupStart); 957 m_paintSetupEnd = event.timestamp() * msPerSecond; 958 } 959 960 void InspectorTimelineAgent::onRasterTaskBegin(const TraceEventDispatcher::TraceEvent& event) 961 { 962 TimelineThreadState& state = threadState(event.threadIdentifier()); 963 unsigned long long layerId = event.asUInt(InstrumentationEventArguments::LayerId); 964 ASSERT(layerId); 965 if (!m_layerToNodeMap.contains(layerId)) 966 return; 967 ASSERT(!state.inKnownLayerTask); 968 state.inKnownLayerTask = true; 969 double timestamp = event.timestamp() * msPerSecond; 970 RefPtr<JSONObject> data = TimelineRecordFactory::createLayerData(m_layerToNodeMap.get(layerId)); 971 RefPtr<TimelineEvent> record = TimelineRecordFactory::createBackgroundRecord(timestamp, String::number(event.threadIdentifier()), TimelineRecordType::Rasterize, data); 972 state.recordStack.addScopedRecord(record, TimelineRecordType::Rasterize); 973 } 974 975 void InspectorTimelineAgent::onRasterTaskEnd(const TraceEventDispatcher::TraceEvent& event) 976 { 977 TimelineThreadState& state = threadState(event.threadIdentifier()); 978 if (!state.inKnownLayerTask) 979 return; 980 ASSERT(state.recordStack.isOpenRecordOfType(TimelineRecordType::Rasterize)); 981 state.recordStack.closeScopedRecord(event.timestamp() * msPerSecond); 982 state.inKnownLayerTask = false; 983 } 984 985 void InspectorTimelineAgent::onImageDecodeBegin(const TraceEventDispatcher::TraceEvent& event) 986 { 987 TimelineThreadState& state = threadState(event.threadIdentifier()); 988 if (!state.decodedPixelRefId && !state.inKnownLayerTask) 989 return; 990 TimelineImageInfo imageInfo; 991 if (state.decodedPixelRefId) { 992 PixelRefToImageInfoMap::const_iterator it = m_pixelRefToImageInfo.find(state.decodedPixelRefId); 993 if (it != m_pixelRefToImageInfo.end()) 994 imageInfo = it->value; 995 else 996 ASSERT_NOT_REACHED(); 997 } 998 RefPtr<JSONObject> data = JSONObject::create(); 999 TimelineRecordFactory::setImageDetails(data.get(), imageInfo.backendNodeId, imageInfo.url); 1000 double timeestamp = event.timestamp() * msPerSecond; 1001 state.recordStack.addScopedRecord(TimelineRecordFactory::createBackgroundRecord(timeestamp, String::number(event.threadIdentifier()), TimelineRecordType::DecodeImage, data), TimelineRecordType::DecodeImage); 1002 } 1003 1004 void InspectorTimelineAgent::onImageDecodeEnd(const TraceEventDispatcher::TraceEvent& event) 1005 { 1006 TimelineThreadState& state = threadState(event.threadIdentifier()); 1007 if (!state.decodedPixelRefId) 1008 return; 1009 ASSERT(state.recordStack.isOpenRecordOfType(TimelineRecordType::DecodeImage)); 1010 state.recordStack.closeScopedRecord(event.timestamp() * msPerSecond); 1011 } 1012 1013 void InspectorTimelineAgent::onRequestMainThreadFrame(const TraceEventDispatcher::TraceEvent& event) 1014 { 1015 unsigned long long layerTreeId = event.asUInt(InstrumentationEventArguments::LayerTreeId); 1016 if (layerTreeId != m_layerTreeId) 1017 return; 1018 TimelineThreadState& state = threadState(event.threadIdentifier()); 1019 state.recordStack.addInstantRecord(createRecordForEvent(event, TimelineRecordType::RequestMainThreadFrame, JSONObject::create())); 1020 } 1021 1022 void InspectorTimelineAgent::onActivateLayerTree(const TraceEventDispatcher::TraceEvent& event) 1023 { 1024 unsigned long long layerTreeId = event.asUInt(InstrumentationEventArguments::LayerTreeId); 1025 if (layerTreeId != m_layerTreeId) 1026 return; 1027 unsigned long long frameId = event.asUInt(InstrumentationEventArguments::FrameId); 1028 TimelineThreadState& state = threadState(event.threadIdentifier()); 1029 state.recordStack.addInstantRecord(createRecordForEvent(event, TimelineRecordType::ActivateLayerTree, TimelineRecordFactory::createFrameData(frameId))); 1030 } 1031 1032 void InspectorTimelineAgent::onDrawFrame(const TraceEventDispatcher::TraceEvent& event) 1033 { 1034 unsigned long long layerTreeId = event.asUInt(InstrumentationEventArguments::LayerTreeId); 1035 if (layerTreeId != m_layerTreeId) 1036 return; 1037 TimelineThreadState& state = threadState(event.threadIdentifier()); 1038 state.recordStack.addInstantRecord(createRecordForEvent(event, TimelineRecordType::DrawFrame, JSONObject::create())); 1039 } 1040 1041 void InspectorTimelineAgent::onLayerDeleted(const TraceEventDispatcher::TraceEvent& event) 1042 { 1043 unsigned long long id = event.id(); 1044 ASSERT(id); 1045 m_layerToNodeMap.remove(id); 1046 } 1047 1048 void InspectorTimelineAgent::onDecodeLazyPixelRefBegin(const TraceEventDispatcher::TraceEvent& event) 1049 { 1050 TimelineThreadState& state = threadState(event.threadIdentifier()); 1051 ASSERT(!state.decodedPixelRefId); 1052 unsigned long long pixelRefId = event.asUInt(PlatformInstrumentation::LazyPixelRef); 1053 ASSERT(pixelRefId); 1054 if (m_pixelRefToImageInfo.contains(pixelRefId)) 1055 state.decodedPixelRefId = pixelRefId; 1056 } 1057 1058 void InspectorTimelineAgent::onDecodeLazyPixelRefEnd(const TraceEventDispatcher::TraceEvent& event) 1059 { 1060 threadState(event.threadIdentifier()).decodedPixelRefId = 0; 1061 } 1062 1063 void InspectorTimelineAgent::onDrawLazyPixelRef(const TraceEventDispatcher::TraceEvent& event) 1064 { 1065 unsigned long long pixelRefId = event.asUInt(PlatformInstrumentation::LazyPixelRef); 1066 ASSERT(pixelRefId); 1067 if (!m_imageBeingPainted) 1068 return; 1069 String url; 1070 if (const ImageResource* resource = m_imageBeingPainted->cachedImage()) 1071 url = resource->url().string(); 1072 m_pixelRefToImageInfo.set(pixelRefId, TimelineImageInfo(nodeId(m_imageBeingPainted->generatingNode()), url)); 1073 } 1074 1075 void InspectorTimelineAgent::onLazyPixelRefDeleted(const TraceEventDispatcher::TraceEvent& event) 1076 { 1077 m_pixelRefToImageInfo.remove(event.id()); 1078 } 1079 1080 void InspectorTimelineAgent::processGPUEvent(const GPUEvent& event) 1081 { 1082 double timelineTimestamp = event.timestamp * msPerSecond; 1083 if (event.phase == GPUEvent::PhaseBegin) { 1084 m_pendingGPURecord = TimelineRecordFactory::createBackgroundRecord(timelineTimestamp, "gpu", TimelineRecordType::GPUTask, TimelineRecordFactory::createGPUTaskData(event.foreign)); 1085 } else if (m_pendingGPURecord) { 1086 m_pendingGPURecord->setEndTime(timelineTimestamp); 1087 sendEvent(m_pendingGPURecord.release()); 1088 if (!event.foreign && m_state->getBoolean(TimelineAgentState::includeCounters)) { 1089 RefPtr<TypeBuilder::Timeline::Counters> counters = TypeBuilder::Timeline::Counters::create(); 1090 counters->setGpuMemoryUsedKB(static_cast<double>(event.usedGPUMemoryBytes / 1024)); 1091 counters->setGpuMemoryLimitKB(static_cast<double>(event.limitGPUMemoryBytes / 1024)); 1092 sendEvent(TimelineRecordFactory::createBackgroundRecord(timelineTimestamp, "gpu", TimelineRecordType::UpdateCounters, counters.release()->asObject())); 1093 } 1094 } 1095 } 1096 1097 void InspectorTimelineAgent::onEmbedderCallbackBegin(const TraceEventDispatcher::TraceEvent& event) 1098 { 1099 TimelineThreadState& state = threadState(event.threadIdentifier()); 1100 double timestamp = event.timestamp() * msPerSecond; 1101 RefPtr<JSONObject> data = TimelineRecordFactory::createEmbedderCallbackData(event.asString(InstrumentationEventArguments::CallbackName)); 1102 RefPtr<TimelineEvent> record = TimelineRecordFactory::createGenericRecord(timestamp, 0, TimelineRecordType::EmbedderCallback, data); 1103 state.recordStack.addScopedRecord(record, TimelineRecordType::EmbedderCallback); 1104 } 1105 1106 void InspectorTimelineAgent::onEmbedderCallbackEnd(const TraceEventDispatcher::TraceEvent& event) 1107 { 1108 TimelineThreadState& state = threadState(event.threadIdentifier()); 1109 state.recordStack.closeScopedRecord(event.timestamp() * msPerSecond); 1110 } 1111 1112 void InspectorTimelineAgent::addRecordToTimeline(PassRefPtr<TimelineEvent> record, double ts) 1113 { 1114 commitFrameRecord(); 1115 innerAddRecordToTimeline(record); 1116 if (m_bufferedEvents && ts - m_lastProgressTimestamp > 300) { 1117 m_lastProgressTimestamp = ts; 1118 m_frontend->progress(m_bufferedEvents->length()); 1119 } 1120 } 1121 1122 void InspectorTimelineAgent::innerAddRecordToTimeline(PassRefPtr<TimelineEvent> record) 1123 { 1124 if (m_recordStack.isEmpty()) { 1125 TraceEventDispatcher::instance()->processBackgroundEvents(); 1126 sendEvent(record); 1127 } else { 1128 TimelineRecordEntry& parent = m_recordStack.last(); 1129 parent.children->addItem(record); 1130 if (m_state->getBoolean(TimelineAgentState::includeCounters)) 1131 parent.children->addItem(createCountersUpdate()); 1132 } 1133 } 1134 1135 static size_t getUsedHeapSize() 1136 { 1137 HeapInfo info; 1138 ScriptGCEvent::getHeapSize(info); 1139 return info.usedJSHeapSize; 1140 } 1141 1142 PassRefPtr<TypeBuilder::Timeline::TimelineEvent> InspectorTimelineAgent::createCountersUpdate() 1143 { 1144 RefPtr<TypeBuilder::Timeline::Counters> counters = TypeBuilder::Timeline::Counters::create(); 1145 if (m_inspectorType == PageInspector) { 1146 counters->setDocuments(InspectorCounters::counterValue(InspectorCounters::DocumentCounter)); 1147 counters->setNodes(InspectorCounters::counterValue(InspectorCounters::NodeCounter)); 1148 counters->setJsEventListeners(InspectorCounters::counterValue(InspectorCounters::JSEventListenerCounter)); 1149 } 1150 counters->setJsHeapSizeUsed(static_cast<double>(getUsedHeapSize())); 1151 return TimelineRecordFactory::createGenericRecord(timestamp(), 0, TimelineRecordType::UpdateCounters, counters.release()->asObject()); 1152 } 1153 1154 void InspectorTimelineAgent::setFrameIdentifier(TimelineEvent* record, LocalFrame* frame) 1155 { 1156 if (!frame || !m_pageAgent) 1157 return; 1158 String frameId; 1159 if (frame && m_pageAgent) 1160 frameId = m_pageAgent->frameId(frame); 1161 record->setFrameId(frameId); 1162 } 1163 1164 void InspectorTimelineAgent::populateImageDetails(JSONObject* data, const RenderImage& renderImage) 1165 { 1166 const ImageResource* resource = renderImage.cachedImage(); 1167 TimelineRecordFactory::setImageDetails(data, nodeId(renderImage.generatingNode()), resource ? resource->url().string() : ""); 1168 } 1169 1170 void InspectorTimelineAgent::didCompleteCurrentRecord(const String& type) 1171 { 1172 // An empty stack could merely mean that the timeline agent was turned on in the middle of 1173 // an event. Don't treat as an error. 1174 if (!m_recordStack.isEmpty()) { 1175 if (m_platformInstrumentationClientInstalledAtStackDepth == m_recordStack.size()) { 1176 m_platformInstrumentationClientInstalledAtStackDepth = 0; 1177 PlatformInstrumentation::setClient(0); 1178 } 1179 1180 TimelineRecordEntry entry = m_recordStack.last(); 1181 m_recordStack.removeLast(); 1182 while (entry.type != type && entry.skipWhenUnbalanced && !m_recordStack.isEmpty()) { 1183 // Discard pending skippable entry, paste its children inplace. 1184 if (entry.children) 1185 m_recordStack.last().children->concat(entry.children); 1186 entry = m_recordStack.last(); 1187 m_recordStack.removeLast(); 1188 } 1189 ASSERT(entry.type == type); 1190 entry.record->setChildren(entry.children); 1191 double ts = timestamp(); 1192 entry.record->setEndTime(ts); 1193 addRecordToTimeline(entry.record, ts); 1194 } 1195 } 1196 1197 void InspectorTimelineAgent::unwindRecordStack() 1198 { 1199 while (!m_recordStack.isEmpty()) { 1200 TimelineRecordEntry& entry = m_recordStack.last(); 1201 didCompleteCurrentRecord(entry.type); 1202 } 1203 } 1204 1205 InspectorTimelineAgent::InspectorTimelineAgent(InspectorPageAgent* pageAgent, InspectorLayerTreeAgent* layerTreeAgent, 1206 InspectorOverlay* overlay, InspectorType type, InspectorClient* client) 1207 : InspectorBaseAgent<InspectorTimelineAgent>("Timeline") 1208 , m_pageAgent(pageAgent) 1209 , m_layerTreeAgent(layerTreeAgent) 1210 , m_frontend(0) 1211 , m_client(client) 1212 , m_overlay(overlay) 1213 , m_inspectorType(type) 1214 , m_id(1) 1215 , m_layerTreeId(0) 1216 , m_maxCallStackDepth(5) 1217 , m_platformInstrumentationClientInstalledAtStackDepth(0) 1218 , m_imageBeingPainted(0) 1219 , m_paintSetupStart(0) 1220 , m_mayEmitFirstPaint(false) 1221 , m_lastProgressTimestamp(0) 1222 { 1223 } 1224 1225 void InspectorTimelineAgent::appendRecord(PassRefPtr<JSONObject> data, const String& type, bool captureCallStack, LocalFrame* frame) 1226 { 1227 double ts = timestamp(); 1228 RefPtr<TimelineEvent> record = TimelineRecordFactory::createGenericRecord(ts, captureCallStack ? m_maxCallStackDepth : 0, type, data); 1229 setFrameIdentifier(record.get(), frame); 1230 addRecordToTimeline(record.release(), ts); 1231 } 1232 1233 void InspectorTimelineAgent::sendEvent(PassRefPtr<TimelineEvent> record) 1234 { 1235 RefPtr<TimelineEvent> retain = record; 1236 if (m_bufferedEvents) { 1237 m_bufferedEvents->addItem(retain); 1238 if (!m_liveEvents.contains(TimelineRecordFactory::type(retain.get()))) 1239 return; 1240 } 1241 m_frontend->eventRecorded(retain.release()); 1242 } 1243 1244 void InspectorTimelineAgent::pushCurrentRecord(PassRefPtr<JSONObject> data, const String& type, bool captureCallStack, LocalFrame* frame, bool hasLowLevelDetails) 1245 { 1246 commitFrameRecord(); 1247 RefPtr<TimelineEvent> record = TimelineRecordFactory::createGenericRecord(timestamp(), captureCallStack ? m_maxCallStackDepth : 0, type, data.get()); 1248 setFrameIdentifier(record.get(), frame); 1249 m_recordStack.append(TimelineRecordEntry(record.release(), data, TypeBuilder::Array<TimelineEvent>::create(), type)); 1250 if (hasLowLevelDetails && !m_platformInstrumentationClientInstalledAtStackDepth && !PlatformInstrumentation::hasClient()) { 1251 m_platformInstrumentationClientInstalledAtStackDepth = m_recordStack.size(); 1252 PlatformInstrumentation::setClient(this); 1253 } 1254 } 1255 1256 TimelineThreadState& InspectorTimelineAgent::threadState(ThreadIdentifier thread) 1257 { 1258 ThreadStateMap::iterator it = m_threadStates.find(thread); 1259 if (it != m_threadStates.end()) 1260 return it->value; 1261 return m_threadStates.add(thread, TimelineThreadState(this)).storedValue->value; 1262 } 1263 1264 void InspectorTimelineAgent::commitFrameRecord() 1265 { 1266 if (!m_pendingFrameRecord) 1267 return; 1268 innerAddRecordToTimeline(m_pendingFrameRecord.release()); 1269 } 1270 1271 void InspectorTimelineAgent::clearRecordStack() 1272 { 1273 if (m_platformInstrumentationClientInstalledAtStackDepth) { 1274 m_platformInstrumentationClientInstalledAtStackDepth = 0; 1275 PlatformInstrumentation::setClient(0); 1276 } 1277 m_pendingFrameRecord.clear(); 1278 m_recordStack.clear(); 1279 m_id++; 1280 } 1281 1282 void InspectorTimelineAgent::localToPageQuad(const RenderObject& renderer, const LayoutRect& rect, FloatQuad* quad) 1283 { 1284 LocalFrame* frame = renderer.frame(); 1285 FrameView* view = frame->view(); 1286 FloatQuad absolute = renderer.localToAbsoluteQuad(FloatQuad(rect)); 1287 quad->setP1(view->contentsToRootView(roundedIntPoint(absolute.p1()))); 1288 quad->setP2(view->contentsToRootView(roundedIntPoint(absolute.p2()))); 1289 quad->setP3(view->contentsToRootView(roundedIntPoint(absolute.p3()))); 1290 quad->setP4(view->contentsToRootView(roundedIntPoint(absolute.p4()))); 1291 } 1292 1293 long long InspectorTimelineAgent::nodeId(Node* node) 1294 { 1295 return node ? InspectorNodeIds::idForNode(node) : 0; 1296 } 1297 1298 long long InspectorTimelineAgent::nodeId(RenderObject* renderer) 1299 { 1300 return InspectorNodeIds::idForNode(renderer->generatingNode()); 1301 } 1302 1303 double InspectorTimelineAgent::timestamp() 1304 { 1305 return WTF::monotonicallyIncreasingTime() * msPerSecond; 1306 } 1307 1308 LocalFrame* InspectorTimelineAgent::mainFrame() const 1309 { 1310 if (!m_pageAgent) 1311 return 0; 1312 return m_pageAgent->mainFrame(); 1313 } 1314 1315 PassRefPtr<TimelineEvent> InspectorTimelineAgent::createRecordForEvent(const TraceEventDispatcher::TraceEvent& event, const String& type, PassRefPtr<JSONObject> data) 1316 { 1317 double timeestamp = event.timestamp() * msPerSecond; 1318 return TimelineRecordFactory::createBackgroundRecord(timeestamp, String::number(event.threadIdentifier()), type, data); 1319 } 1320 1321 void InspectorTimelineAgent::setLiveEvents(const String& liveEvents) 1322 { 1323 m_liveEvents.clear(); 1324 if (liveEvents.isNull() || liveEvents.isEmpty()) 1325 return; 1326 Vector<String> eventList; 1327 liveEvents.split(',', eventList); 1328 for (Vector<String>::iterator it = eventList.begin(); it != eventList.end(); ++it) 1329 m_liveEvents.add(*it); 1330 } 1331 1332 TimelineRecordStack::TimelineRecordStack(InspectorTimelineAgent* timelineAgent) 1333 : m_timelineAgent(timelineAgent) 1334 { 1335 } 1336 1337 void TimelineRecordStack::addScopedRecord(PassRefPtr<TimelineEvent> record, const String& type) 1338 { 1339 m_stack.append(Entry(record, type)); 1340 } 1341 1342 void TimelineRecordStack::closeScopedRecord(double endTime) 1343 { 1344 if (m_stack.isEmpty()) 1345 return; 1346 Entry last = m_stack.last(); 1347 m_stack.removeLast(); 1348 last.record->setEndTime(endTime); 1349 if (last.children->length()) 1350 last.record->setChildren(last.children); 1351 addInstantRecord(last.record); 1352 } 1353 1354 void TimelineRecordStack::addInstantRecord(PassRefPtr<TimelineEvent> record) 1355 { 1356 if (m_stack.isEmpty()) 1357 m_timelineAgent->sendEvent(record); 1358 else 1359 m_stack.last().children->addItem(record); 1360 } 1361 1362 #if ENABLE(ASSERT) 1363 bool TimelineRecordStack::isOpenRecordOfType(const String& type) 1364 { 1365 return !m_stack.isEmpty() && m_stack.last().type == type; 1366 } 1367 #endif 1368 1369 void TimelineRecordStack::trace(Visitor* visitor) 1370 { 1371 visitor->trace(m_timelineAgent); 1372 } 1373 1374 void TimelineThreadState::trace(Visitor* visitor) 1375 { 1376 visitor->trace(recordStack); 1377 } 1378 1379 } // namespace blink 1380