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