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
42namespace WebCore {
43
44namespace {
45
46class TraceEventDispatcher {
47    WTF_MAKE_NONCOPYABLE(TraceEventDispatcher);
48public:
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
78private:
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
104TimelineRecordStack::TimelineRecordStack(WeakPtr<InspectorTimelineAgent> timelineAgent)
105    : m_timelineAgent(timelineAgent)
106{
107}
108
109void TimelineRecordStack::addScopedRecord(PassRefPtr<JSONObject> record)
110{
111    m_stack.append(Entry(record));
112}
113
114void 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
126void 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
135bool 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
142void TimelineRecordStack::send(PassRefPtr<JSONObject> record)
143{
144    InspectorTimelineAgent* timelineAgent = m_timelineAgent.get();
145    if (!timelineAgent)
146        return;
147    timelineAgent->sendEvent(record);
148}
149
150TimelineTraceEventProcessor::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
179TimelineTraceEventProcessor::~TimelineTraceEventProcessor()
180{
181}
182
183void TimelineTraceEventProcessor::registerHandler(const char* name, TraceEventPhase phase, TraceEventHandler handler)
184{
185    m_handlersByType.set(std::make_pair(name, phase), handler);
186}
187
188void TimelineTraceEventProcessor::shutdown()
189{
190    TraceEventDispatcher::instance()->removeProcessor(this, m_inspectorClient);
191}
192
193size_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
202const 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
213void 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
231void TimelineTraceEventProcessor::onBeginFrame(const TraceEvent&)
232{
233    processBackgroundEvents();
234}
235
236void 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
248void TimelineTraceEventProcessor::onUpdateLayerEnd(const TraceEvent& event)
249{
250    m_layerId = 0;
251}
252
253void TimelineTraceEventProcessor::onPaintLayerBegin(const TraceEvent& event)
254{
255    m_layerId = event.asUInt(InstrumentationEventArguments::LayerId);
256    ASSERT(m_layerId);
257    ASSERT(!m_paintSetupStart);
258}
259
260void TimelineTraceEventProcessor::onPaintLayerEnd(const TraceEvent& event)
261{
262    m_layerId = 0;
263    ASSERT(m_paintSetupStart);
264}
265
266void TimelineTraceEventProcessor::onPaintSetupBegin(const TraceEvent& event)
267{
268    ASSERT(!m_paintSetupStart);
269    m_paintSetupStart = m_timeConverter.toProtocolTimestamp(event.timestamp());
270}
271
272void TimelineTraceEventProcessor::onPaintSetupEnd(const TraceEvent& event)
273{
274    ASSERT(m_paintSetupStart);
275    m_paintSetupEnd = m_timeConverter.toProtocolTimestamp(event.timestamp());
276}
277
278void 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
290void 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
300void TimelineTraceEventProcessor::onImageDecodeTaskBegin(const TraceEvent& event)
301{
302    maybeEnterLayerTask(event, threadState(event.threadIdentifier()));
303}
304
305void TimelineTraceEventProcessor::onImageDecodeTaskEnd(const TraceEvent& event)
306{
307    leaveLayerTask(threadState(event.threadIdentifier()));
308}
309
310bool 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
320void TimelineTraceEventProcessor::leaveLayerTask(TimelineThreadState& threadState)
321{
322    threadState.inKnownLayerTask = false;
323}
324
325void 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
333void 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
342void 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
350void 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
371PassRefPtr<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
380void 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