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/TimelineTraceEventProcessor.h" 33 34 #include "core/inspector/InspectorClient.h" 35 #include "core/inspector/InspectorInstrumentation.h" 36 #include "core/inspector/TimelineRecordFactory.h" 37 38 #include "wtf/CurrentTime.h" 39 #include "wtf/MainThread.h" 40 #include "wtf/Vector.h" 41 42 namespace WebCore { 43 44 namespace { 45 46 class TraceEventDispatcher { 47 WTF_MAKE_NONCOPYABLE(TraceEventDispatcher); 48 public: 49 static TraceEventDispatcher* instance() 50 { 51 DEFINE_STATIC_LOCAL(TraceEventDispatcher, instance, ()); 52 return &instance; 53 } 54 55 void addProcessor(TimelineTraceEventProcessor* processor, InspectorClient* client) 56 { 57 MutexLocker locker(m_mutex); 58 59 m_processors.append(processor); 60 if (m_processors.size() == 1) 61 client->setTraceEventCallback(dispatchEventOnAnyThread); 62 } 63 64 void removeProcessor(TimelineTraceEventProcessor* processor, InspectorClient* client) 65 { 66 MutexLocker locker(m_mutex); 67 68 size_t index = m_processors.find(processor); 69 if (index == notFound) { 70 ASSERT_NOT_REACHED(); 71 return; 72 } 73 m_processors.remove(index); 74 if (m_processors.isEmpty()) 75 client->setTraceEventCallback(0); 76 } 77 78 private: 79 TraceEventDispatcher() { } 80 81 static void dispatchEventOnAnyThread(char phase, const unsigned char*, const char* name, unsigned long long id, 82 int numArgs, const char* const* argNames, const unsigned char* argTypes, const unsigned long long* argValues, 83 unsigned char flags) 84 { 85 TraceEventDispatcher* self = instance(); 86 Vector<RefPtr<TimelineTraceEventProcessor> > processors; 87 { 88 MutexLocker locker(self->m_mutex); 89 processors = self->m_processors; 90 } 91 for (int i = 0, size = processors.size(); i < size; ++i) { 92 processors[i]->processEventOnAnyThread(static_cast<TimelineTraceEventProcessor::TraceEventPhase>(phase), 93 name, id, numArgs, argNames, argTypes, argValues, flags); 94 } 95 } 96 97 Mutex m_mutex; 98 Vector<RefPtr<TimelineTraceEventProcessor> > m_processors; 99 }; 100 101 } // namespce 102 103 104 TimelineRecordStack::TimelineRecordStack(WeakPtr<InspectorTimelineAgent> timelineAgent) 105 : m_timelineAgent(timelineAgent) 106 { 107 } 108 109 void TimelineRecordStack::addScopedRecord(PassRefPtr<JSONObject> record) 110 { 111 m_stack.append(Entry(record)); 112 } 113 114 void TimelineRecordStack::closeScopedRecord(double endTime) 115 { 116 if (m_stack.isEmpty()) 117 return; 118 Entry last = m_stack.last(); 119 m_stack.removeLast(); 120 last.record->setNumber("endTime", endTime); 121 if (last.children->length()) 122 last.record->setArray("children", last.children); 123 addInstantRecord(last.record); 124 } 125 126 void TimelineRecordStack::addInstantRecord(PassRefPtr<JSONObject> record) 127 { 128 if (m_stack.isEmpty()) 129 send(record); 130 else 131 m_stack.last().children->pushObject(record); 132 } 133 134 #ifndef NDEBUG 135 bool TimelineRecordStack::isOpenRecordOfType(const String& type) 136 { 137 String lastRecordType; 138 return m_stack.isEmpty() || (m_stack.last().record->getString("type", &lastRecordType) && type == lastRecordType); 139 } 140 #endif 141 142 void TimelineRecordStack::send(PassRefPtr<JSONObject> record) 143 { 144 InspectorTimelineAgent* timelineAgent = m_timelineAgent.get(); 145 if (!timelineAgent) 146 return; 147 timelineAgent->sendEvent(record); 148 } 149 150 TimelineTraceEventProcessor::TimelineTraceEventProcessor(WeakPtr<InspectorTimelineAgent> timelineAgent, InspectorClient *client) 151 : m_timelineAgent(timelineAgent) 152 , m_timeConverter(timelineAgent.get()->timeConverter()) 153 , m_inspectorClient(client) 154 , m_pageId(reinterpret_cast<unsigned long long>(m_timelineAgent.get()->page())) 155 , m_layerTreeId(m_timelineAgent.get()->layerTreeId()) 156 , m_layerId(0) 157 , m_paintSetupStart(0) 158 , m_paintSetupEnd(0) 159 { 160 registerHandler(InstrumentationEvents::BeginFrame, TracePhaseInstant, &TimelineTraceEventProcessor::onBeginFrame); 161 registerHandler(InstrumentationEvents::UpdateLayer, TracePhaseBegin, &TimelineTraceEventProcessor::onUpdateLayerBegin); 162 registerHandler(InstrumentationEvents::UpdateLayer, TracePhaseEnd, &TimelineTraceEventProcessor::onUpdateLayerEnd); 163 registerHandler(InstrumentationEvents::PaintLayer, TracePhaseBegin, &TimelineTraceEventProcessor::onPaintLayerBegin); 164 registerHandler(InstrumentationEvents::PaintLayer, TracePhaseEnd, &TimelineTraceEventProcessor::onPaintLayerEnd); 165 registerHandler(InstrumentationEvents::PaintSetup, TracePhaseBegin, &TimelineTraceEventProcessor::onPaintSetupBegin); 166 registerHandler(InstrumentationEvents::PaintSetup, TracePhaseEnd, &TimelineTraceEventProcessor::onPaintSetupEnd); 167 registerHandler(InstrumentationEvents::RasterTask, TracePhaseBegin, &TimelineTraceEventProcessor::onRasterTaskBegin); 168 registerHandler(InstrumentationEvents::RasterTask, TracePhaseEnd, &TimelineTraceEventProcessor::onRasterTaskEnd); 169 registerHandler(InstrumentationEvents::ImageDecodeTask, TracePhaseBegin, &TimelineTraceEventProcessor::onImageDecodeTaskBegin); 170 registerHandler(InstrumentationEvents::ImageDecodeTask, TracePhaseEnd, &TimelineTraceEventProcessor::onImageDecodeTaskEnd); 171 registerHandler(InstrumentationEvents::Layer, TracePhaseDeleteObject, &TimelineTraceEventProcessor::onLayerDeleted); 172 registerHandler(InstrumentationEvents::Paint, TracePhaseInstant, &TimelineTraceEventProcessor::onPaint); 173 registerHandler(PlatformInstrumentation::ImageDecodeEvent, TracePhaseBegin, &TimelineTraceEventProcessor::onImageDecodeBegin); 174 registerHandler(PlatformInstrumentation::ImageDecodeEvent, TracePhaseEnd, &TimelineTraceEventProcessor::onImageDecodeEnd); 175 176 TraceEventDispatcher::instance()->addProcessor(this, m_inspectorClient); 177 } 178 179 TimelineTraceEventProcessor::~TimelineTraceEventProcessor() 180 { 181 } 182 183 void TimelineTraceEventProcessor::registerHandler(const char* name, TraceEventPhase phase, TraceEventHandler handler) 184 { 185 m_handlersByType.set(std::make_pair(name, phase), handler); 186 } 187 188 void TimelineTraceEventProcessor::shutdown() 189 { 190 TraceEventDispatcher::instance()->removeProcessor(this, m_inspectorClient); 191 } 192 193 size_t TimelineTraceEventProcessor::TraceEvent::findParameter(const char* name) const 194 { 195 for (int i = 0; i < m_argumentCount; ++i) { 196 if (!strcmp(name, m_argumentNames[i])) 197 return i; 198 } 199 return notFound; 200 } 201 202 const TimelineTraceEventProcessor::TraceValueUnion& TimelineTraceEventProcessor::TraceEvent::parameter(const char* name, TraceValueTypes expectedType) const 203 { 204 static TraceValueUnion missingValue; 205 size_t index = findParameter(name); 206 if (index == notFound || m_argumentTypes[index] != expectedType) { 207 ASSERT_NOT_REACHED(); 208 return missingValue; 209 } 210 return *reinterpret_cast<const TraceValueUnion*>(m_argumentValues + index); 211 } 212 213 void TimelineTraceEventProcessor::processEventOnAnyThread(TraceEventPhase phase, const char* name, unsigned long long id, 214 int numArgs, const char* const* argNames, const unsigned char* argTypes, const unsigned long long* argValues, 215 unsigned char) 216 { 217 HandlersMap::iterator it = m_handlersByType.find(std::make_pair(name, phase)); 218 if (it == m_handlersByType.end()) 219 return; 220 221 TraceEvent event(WTF::monotonicallyIncreasingTime(), phase, name, id, currentThread(), numArgs, argNames, argTypes, argValues); 222 223 if (!isMainThread()) { 224 MutexLocker locker(m_backgroundEventsMutex); 225 m_backgroundEvents.append(event); 226 return; 227 } 228 (this->*(it->value))(event); 229 } 230 231 void TimelineTraceEventProcessor::onBeginFrame(const TraceEvent&) 232 { 233 processBackgroundEvents(); 234 } 235 236 void TimelineTraceEventProcessor::onUpdateLayerBegin(const TraceEvent& event) 237 { 238 unsigned long long layerTreeId = event.asUInt(InstrumentationEventArguments::LayerTreeId); 239 if (layerTreeId != m_layerTreeId) 240 return; 241 m_layerId = event.asUInt(InstrumentationEventArguments::LayerId); 242 // We don't know the node yet. For content layers, the node will be updated 243 // by paint. For others, let it remain 0 -- we just need the fact that 244 // the layer belongs to the page (see cookie check). 245 m_layerToNodeMap.add(m_layerId, 0); 246 } 247 248 void TimelineTraceEventProcessor::onUpdateLayerEnd(const TraceEvent& event) 249 { 250 m_layerId = 0; 251 } 252 253 void TimelineTraceEventProcessor::onPaintLayerBegin(const TraceEvent& event) 254 { 255 m_layerId = event.asUInt(InstrumentationEventArguments::LayerId); 256 ASSERT(m_layerId); 257 ASSERT(!m_paintSetupStart); 258 } 259 260 void TimelineTraceEventProcessor::onPaintLayerEnd(const TraceEvent& event) 261 { 262 m_layerId = 0; 263 ASSERT(m_paintSetupStart); 264 } 265 266 void TimelineTraceEventProcessor::onPaintSetupBegin(const TraceEvent& event) 267 { 268 ASSERT(!m_paintSetupStart); 269 m_paintSetupStart = m_timeConverter.toProtocolTimestamp(event.timestamp()); 270 } 271 272 void TimelineTraceEventProcessor::onPaintSetupEnd(const TraceEvent& event) 273 { 274 ASSERT(m_paintSetupStart); 275 m_paintSetupEnd = m_timeConverter.toProtocolTimestamp(event.timestamp()); 276 } 277 278 void TimelineTraceEventProcessor::onRasterTaskBegin(const TraceEvent& event) 279 { 280 TimelineThreadState& state = threadState(event.threadIdentifier()); 281 if (!maybeEnterLayerTask(event, state)) 282 return; 283 unsigned long long layerId = event.asUInt(InstrumentationEventArguments::LayerId); 284 ASSERT(layerId); 285 RefPtr<JSONObject> record = createRecord(event, TimelineRecordType::Rasterize); 286 record->setObject("data", TimelineRecordFactory::createLayerData(m_layerToNodeMap.get(layerId))); 287 state.recordStack.addScopedRecord(record.release()); 288 } 289 290 void TimelineTraceEventProcessor::onRasterTaskEnd(const TraceEvent& event) 291 { 292 TimelineThreadState& state = threadState(event.threadIdentifier()); 293 if (!state.inKnownLayerTask) 294 return; 295 ASSERT(state.recordStack.isOpenRecordOfType(TimelineRecordType::Rasterize)); 296 state.recordStack.closeScopedRecord(m_timeConverter.toProtocolTimestamp(event.timestamp())); 297 leaveLayerTask(state); 298 } 299 300 void TimelineTraceEventProcessor::onImageDecodeTaskBegin(const TraceEvent& event) 301 { 302 maybeEnterLayerTask(event, threadState(event.threadIdentifier())); 303 } 304 305 void TimelineTraceEventProcessor::onImageDecodeTaskEnd(const TraceEvent& event) 306 { 307 leaveLayerTask(threadState(event.threadIdentifier())); 308 } 309 310 bool TimelineTraceEventProcessor::maybeEnterLayerTask(const TraceEvent& event, TimelineThreadState& threadState) 311 { 312 unsigned long long layerId = event.asUInt(InstrumentationEventArguments::LayerId); 313 if (!m_layerToNodeMap.contains(layerId)) 314 return false; 315 ASSERT(!threadState.inKnownLayerTask); 316 threadState.inKnownLayerTask = true; 317 return true; 318 } 319 320 void TimelineTraceEventProcessor::leaveLayerTask(TimelineThreadState& threadState) 321 { 322 threadState.inKnownLayerTask = false; 323 } 324 325 void TimelineTraceEventProcessor::onImageDecodeBegin(const TraceEvent& event) 326 { 327 TimelineThreadState& state = threadState(event.threadIdentifier()); 328 if (!state.inKnownLayerTask) 329 return; 330 state.recordStack.addScopedRecord(createRecord(event, TimelineRecordType::DecodeImage)); 331 } 332 333 void TimelineTraceEventProcessor::onImageDecodeEnd(const TraceEvent& event) 334 { 335 TimelineThreadState& state = threadState(event.threadIdentifier()); 336 if (!state.inKnownLayerTask) 337 return; 338 ASSERT(state.recordStack.isOpenRecordOfType(TimelineRecordType::DecodeImage)); 339 state.recordStack.closeScopedRecord(m_timeConverter.toProtocolTimestamp(event.timestamp())); 340 } 341 342 void TimelineTraceEventProcessor::onLayerDeleted(const TraceEvent& event) 343 { 344 unsigned long long id = event.id(); 345 ASSERT(id); 346 processBackgroundEvents(); 347 m_layerToNodeMap.remove(id); 348 } 349 350 void TimelineTraceEventProcessor::onPaint(const TraceEvent& event) 351 { 352 double paintSetupStart = m_paintSetupStart; 353 m_paintSetupStart = 0; 354 if (!m_layerId) 355 return; 356 unsigned long long pageId = event.asUInt(InstrumentationEventArguments::PageId); 357 if (pageId != m_pageId) 358 return; 359 long long nodeId = event.asInt(InstrumentationEventArguments::NodeId); 360 ASSERT(nodeId); 361 m_layerToNodeMap.set(m_layerId, nodeId); 362 InspectorTimelineAgent* timelineAgent = m_timelineAgent.get(); 363 if (timelineAgent && paintSetupStart) { 364 RefPtr<JSONObject> paintSetupRecord = TimelineRecordFactory::createGenericRecord(paintSetupStart, 0, TimelineRecordType::PaintSetup); 365 paintSetupRecord->setNumber("endTime", m_paintSetupEnd); 366 paintSetupRecord->setObject("data", TimelineRecordFactory::createLayerData(nodeId)); 367 timelineAgent->addRecordToTimeline(paintSetupRecord); 368 } 369 } 370 371 PassRefPtr<JSONObject> TimelineTraceEventProcessor::createRecord(const TraceEvent& event, const String& recordType, PassRefPtr<JSONObject> data) 372 { 373 double startTime = m_timeConverter.toProtocolTimestamp(event.timestamp()); 374 RefPtr<JSONObject> record = TimelineRecordFactory::createBackgroundRecord(startTime, String::number(event.threadIdentifier())); 375 record->setString("type", recordType); 376 record->setObject("data", data ? data : JSONObject::create()); 377 return record.release(); 378 } 379 380 void TimelineTraceEventProcessor::processBackgroundEvents() 381 { 382 ASSERT(isMainThread()); 383 Vector<TraceEvent> events; 384 { 385 MutexLocker locker(m_backgroundEventsMutex); 386 events.reserveCapacity(m_backgroundEvents.capacity()); 387 m_backgroundEvents.swap(events); 388 } 389 for (size_t i = 0, size = events.size(); i < size; ++i) { 390 const TraceEvent& event = events[i]; 391 HandlersMap::iterator it = m_handlersByType.find(std::make_pair(event.name(), event.phase())); 392 ASSERT(it != m_handlersByType.end() && it->value); 393 (this->*(it->value))(event); 394 } 395 } 396 397 } // namespace WebCore 398 399