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