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