Home | History | Annotate | Download | only in inspector
      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