From 8d15633a22d5fb72db3342626e001bfbcf0e0d7b Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 28 Apr 2016 15:57:12 +0200 Subject: [PATCH] QmlProfiler: Add a QmlTypedEvent and extend QmlEvent The QmlTypedEvent is mainly useful to read a generic QmlEvent and QmlEventType from a QPacket. QmlEventType has a stream operator to do exactly that. QmlEvent also gets further options to store 32-bit data in addition to 64- and 8-bit data. Also, with the more generic storage layout we can reduce the memory consumption of range events by 50%. This comes at the cost of additional memory allocations for non-range events, but as non-range events are significantly less frequent than range events, this is a good tradeoff. Finally the new storage layout lends itself to efficient serialization, which will help when developing new storage and transfer formats for QML traces. Change-Id: I420de68b0142f23c8fb2ca8b329d7ffe69c83fe0 Reviewed-by: Joerg Bornemann --- .../qmlprofiler/debugmessagesmodel.cpp | 2 +- src/plugins/qmlprofiler/inputeventsmodel.cpp | 4 +- src/plugins/qmlprofiler/memoryusagemodel.cpp | 8 +- src/plugins/qmlprofiler/pixmapcachemodel.cpp | 10 +- src/plugins/qmlprofiler/qmlevent.h | 261 +++++++++++++----- src/plugins/qmlprofiler/qmlprofiler.pro | 2 + src/plugins/qmlprofiler/qmlprofiler.qbs | 1 + .../qmlprofileranimationsmodel.cpp | 8 +- .../qmlprofiler/qmlprofilerdatamodel.cpp | 2 +- .../qmlprofiler/qmlprofilertracefile.cpp | 74 +++-- src/plugins/qmlprofiler/qmltypedevent.cpp | 203 ++++++++++++++ src/plugins/qmlprofiler/qmltypedevent.h | 42 +++ .../qmlprofiler/scenegraphtimelinemodel.cpp | 84 +++--- 13 files changed, 541 insertions(+), 160 deletions(-) create mode 100644 src/plugins/qmlprofiler/qmltypedevent.cpp create mode 100644 src/plugins/qmlprofiler/qmltypedevent.h diff --git a/src/plugins/qmlprofiler/debugmessagesmodel.cpp b/src/plugins/qmlprofiler/debugmessagesmodel.cpp index ae0dfd07448..f34ad5b1b3a 100644 --- a/src/plugins/qmlprofiler/debugmessagesmodel.cpp +++ b/src/plugins/qmlprofiler/debugmessagesmodel.cpp @@ -113,7 +113,7 @@ void DebugMessagesModel::loadData() continue; m_data.insert(insert(event.timestamp(), 0, type.detailType), - MessageData(event.stringData(), event.typeIndex())); + MessageData(event.string(), event.typeIndex())); if (type.detailType > m_maximumMsgType) m_maximumMsgType = event.typeIndex(); updateProgress(count(), simpleModel->events().count()); diff --git a/src/plugins/qmlprofiler/inputeventsmodel.cpp b/src/plugins/qmlprofiler/inputeventsmodel.cpp index e7438282169..455f78b6a86 100644 --- a/src/plugins/qmlprofiler/inputeventsmodel.cpp +++ b/src/plugins/qmlprofiler/inputeventsmodel.cpp @@ -153,8 +153,8 @@ void InputEventsModel::loadData() continue; m_data.insert(insert(event.timestamp(), 0, type.detailType), - InputEvent(static_cast(event.numericData(0)), - event.numericData(1), event.numericData(2))); + InputEvent(static_cast(event.number(0)), + event.number(1), event.number(2))); if (type.detailType == Mouse) { if (m_mouseTypeId == -1) diff --git a/src/plugins/qmlprofiler/memoryusagemodel.cpp b/src/plugins/qmlprofiler/memoryusagemodel.cpp index 013a4ff6890..178a07400f0 100644 --- a/src/plugins/qmlprofiler/memoryusagemodel.cpp +++ b/src/plugins/qmlprofiler/memoryusagemodel.cpp @@ -177,12 +177,12 @@ void MemoryUsageModel::loadData() type.detailType == selectionId(currentUsageIndex) && m_data[currentUsageIndex].originTypeIndex == rangeStack.top().originTypeIndex && rangeStack.top().startTime < startTime(currentUsageIndex)) { - m_data[currentUsageIndex].update(event.numericData(0)); + m_data[currentUsageIndex].update(event.number(0)); currentUsage = m_data[currentUsageIndex].size; } else { MemoryAllocationItem allocation(event.typeIndex(), currentUsage, rangeStack.empty() ? -1 : rangeStack.top().originTypeIndex); - allocation.update(event.numericData(0)); + allocation.update(event.number(0)); currentUsage = allocation.size; if (currentUsageIndex != -1) { @@ -200,12 +200,12 @@ void MemoryUsageModel::loadData() m_data[currentJSHeapIndex].originTypeIndex == rangeStack.top().originTypeIndex && rangeStack.top().startTime < startTime(currentJSHeapIndex)) { - m_data[currentJSHeapIndex].update(event.numericData(0)); + m_data[currentJSHeapIndex].update(event.number(0)); currentSize = m_data[currentJSHeapIndex].size; } else { MemoryAllocationItem allocation(event.typeIndex(), currentSize, rangeStack.empty() ? -1 : rangeStack.top().originTypeIndex); - allocation.update(event.numericData(0)); + allocation.update(event.number(0)); currentSize = allocation.size; if (currentSize > m_maxSize) diff --git a/src/plugins/qmlprofiler/pixmapcachemodel.cpp b/src/plugins/qmlprofiler/pixmapcachemodel.cpp index 3adace69c70..37392181d14 100644 --- a/src/plugins/qmlprofiler/pixmapcachemodel.cpp +++ b/src/plugins/qmlprofiler/pixmapcachemodel.cpp @@ -211,15 +211,15 @@ void PixmapCacheModel::loadData() // We can't have cached it before we knew the size Q_ASSERT(i->cacheState != Cached); - i->size.setWidth(event.numericData(0)); - i->size.setHeight(event.numericData(1)); + i->size.setWidth(event.number(0)); + i->size.setHeight(event.number(1)); newEvent.sizeIndex = i - pixmap.sizes.begin(); break; } if (newEvent.sizeIndex == -1) { newEvent.sizeIndex = pixmap.sizes.length(); - pixmap.sizes << PixmapState(event.numericData(0), event.numericData(1)); + pixmap.sizes << PixmapState(event.number(0), event.number(1)); } PixmapState &state = pixmap.sizes[newEvent.sizeIndex]; @@ -234,8 +234,8 @@ void PixmapCacheModel::loadData() case PixmapCacheCountChanged: {// Cache Size Changed Event pixmapStartTime = event.timestamp() + 1; // delay 1 ns for proper sorting - bool uncache = cumulatedCount > event.numericData(2); - cumulatedCount = event.numericData(2); + bool uncache = cumulatedCount > event.number(2); + cumulatedCount = event.number(2); qint64 pixSize = 0; // First try to find a preferred pixmap, which either is Corrupt and will be uncached diff --git a/src/plugins/qmlprofiler/qmlevent.h b/src/plugins/qmlprofiler/qmlevent.h index 6d81c2b70fc..c050455d9ce 100644 --- a/src/plugins/qmlprofiler/qmlevent.h +++ b/src/plugins/qmlprofiler/qmlevent.h @@ -24,33 +24,45 @@ ****************************************************************************/ #pragma once +#include "qmlprofilereventtypes.h" + #include +#include +#include + +#include +#include namespace QmlProfiler { struct QmlEvent { - QmlEvent(qint64 timestamp = -1, qint64 duration = -1, int typeIndex = -1, - qint64 num0 = 0, qint64 num1 = 0, qint64 num2 = 0, qint64 num3 = 0, - qint64 num4 = 0) : - m_timestamp(timestamp), m_duration(duration), m_dataType(NumericData), - m_typeIndex(typeIndex) + QmlEvent() : m_timestamp(-1), m_duration(0), m_typeIndex(-1), m_dataType(Inline8Bit), + m_dataLength(0) {} + + template + QmlEvent(qint64 timestamp, qint64 duration, int typeIndex, std::initializer_list list) + : m_timestamp(timestamp), m_duration(duration), m_typeIndex(typeIndex) { - m_numericData[0] = num0; - m_numericData[1] = num1; - m_numericData[2] = num2; - m_numericData[3] = num3; - m_numericData[4] = num4; + assignNumbers, Number>(list); } QmlEvent(qint64 timestamp, qint64 duration, int typeIndex, const QString &data) : m_timestamp(timestamp), m_duration(duration), m_typeIndex(typeIndex) { - assignStringData(data); + assignNumbers(data.toUtf8()); } - QmlEvent(const QmlEvent &other) : - m_timestamp(other.m_timestamp), m_duration(other.m_duration), - m_dataType(other.m_dataType), m_typeIndex(other.m_typeIndex) + template + QmlEvent(qint64 timestamp, qint64 duration, int typeIndex, const QVector &data) + : m_timestamp(timestamp), m_duration(duration), m_typeIndex(typeIndex) + { + assignNumbers, Number>(data); + } + + QmlEvent(const QmlEvent &other) + : m_timestamp(other.m_timestamp), m_duration(other.m_duration), + m_typeIndex(other.m_typeIndex), m_dataType(other.m_dataType), + m_dataLength(other.m_dataLength) { assignData(other); } @@ -58,13 +70,12 @@ struct QmlEvent { QmlEvent &operator=(const QmlEvent &other) { if (this != &other) { - if (m_dataType == StringData) - delete m_stringData; - + clearPointer(); m_timestamp = other.m_timestamp; m_duration = other.m_duration; m_typeIndex = other.m_typeIndex; m_dataType = other.m_dataType; + m_dataLength = other.m_dataLength; assignData(other); } return *this; @@ -72,8 +83,7 @@ struct QmlEvent { ~QmlEvent() { - if (m_dataType == StringData) - delete m_stringData; + clearPointer(); } qint64 timestamp() const { return m_timestamp; } @@ -85,31 +95,102 @@ struct QmlEvent { int typeIndex() const { return m_typeIndex; } void setTypeIndex(int typeIndex) { m_typeIndex = typeIndex; } - qint64 numericData(int i) const { return m_dataType == NumericData ? m_numericData[i] : 0; } - void setNumericData(int i, qint64 data) - { - if (m_dataType == StringData) - delete m_stringData; - - m_dataType = NumericData; - m_numericData[i] = data; - } - - QString stringData() const + template + Number number(int i) const { + // Trailing zeroes can be omitted, for example for SceneGraph events + if (i >= m_dataLength) + return 0; switch (m_dataType) { - case NumericData: return QString(); - case StringData: return *m_stringData; - default: return QString::fromUtf8(m_characterData, m_characterDataLength); + case Inline8Bit: + return m_data.internal8bit[i]; + case Inline16Bit: + return m_data.internal16bit[i]; + case Inline32Bit: + return m_data.internal32bit[i]; + case Inline64Bit: + return m_data.internal64bit[i]; + case External8Bit: + return static_cast(m_data.external)[i]; + case External16Bit: + return static_cast(m_data.external)[i]; + case External32Bit: + return static_cast(m_data.external)[i]; + case External64Bit: + return static_cast(m_data.external)[i]; + default: + return 0; } } - void setStringData(const QString &data) + template + void setNumber(int i, Number number) { - if (m_dataType == StringData) - delete m_stringData; + QVarLengthArray nums = numbers, Number>(); + int prevSize = nums.size(); + if (i >= prevSize) { + nums.resize(i + 1); + // Fill with zeroes. We don't want to accidentally prevent squeezing. + while (prevSize < i) + nums[prevSize++] = 0; + } + nums[i] = number; + setNumbers, Number>(nums); + } - assignStringData(data); + template + void setNumbers(const Container &numbers) + { + clearPointer(); + assignNumbers(numbers); + } + + template + void setNumbers(std::initializer_list numbers) + { + setNumbers, Number>(numbers); + } + + template + Container numbers() const + { + Container container; + for (int i = 0; i < m_dataLength; ++i) + container.append(number(i)); + return container; + } + + QString string() const + { + switch (m_dataType) { + case External8Bit: + return QString::fromUtf8(static_cast(m_data.external)); + case Inline8Bit: + return QString::fromUtf8(m_data.internalChar); + default: + Q_UNREACHABLE(); + return QString(); + } + } + + void setString(const QString &data) + { + clearPointer(); + assignNumbers(data.toUtf8()); + } + + Message rangeStage() const + { + Q_ASSERT(m_dataType == Inline8Bit); + return static_cast(m_data.internal8bit[0]); + } + + void setRangeStage(Message stage) + { + clearPointer(); + m_dataType = Inline8Bit; + m_dataLength = 1; + m_data.internal8bit[0] = stage; } bool isValid() const @@ -118,50 +199,96 @@ struct QmlEvent { } private: - - static const quint8 StringData = 254; - static const quint8 NumericData = 255; + enum Type: quint16 { + External = 1, + Inline8Bit = 8, + External8Bit = Inline8Bit | External, + Inline16Bit = 16, + External16Bit = Inline16Bit | External, + Inline32Bit = 32, + External32Bit = Inline32Bit | External, + Inline64Bit = 64, + External64Bit = Inline64Bit | External + }; qint64 m_timestamp; qint64 m_duration; - union { - qint64 m_numericData[5]; - QString *m_stringData; - char m_characterData[5 * sizeof(qint64) + 3]; - }; union { - quint8 m_dataType; - quint8 m_characterDataLength; - }; + void *external; + char internalChar [sizeof(external)]; + qint8 internal8bit [sizeof(external)]; + qint16 internal16bit[sizeof(external) / 2]; + qint32 internal32bit[sizeof(external) / 4]; + qint64 internal64bit[sizeof(external) / 8]; + } m_data; + qint32 m_typeIndex; + Type m_dataType; + quint16 m_dataLength; void assignData(const QmlEvent &other) { - switch (m_dataType) { - case StringData: - m_stringData = new QString(*other.m_stringData); - break; - case NumericData: - for (int i = 0; i < 5; ++i) - m_numericData[i] = other.m_numericData[i]; - break; - default: - memcpy(m_characterData, other.m_characterData, m_characterDataLength); - break; + if (m_dataType & External) { + int length = m_dataLength * (other.m_dataType / 8); + m_data.external = malloc(length); + memcpy(m_data.external, other.m_data.external, length); + } else { + memcpy(&m_data, &other.m_data, sizeof(m_data)); } } - void assignStringData(const QString &data) + template + bool squeezable(Big source) { - QByteArray cdata = data.toUtf8(); - if (cdata.length() <= (int)sizeof(m_characterData)) { - m_characterDataLength = cdata.length(); - memcpy(m_characterData, cdata.constData(), m_characterDataLength); - } else { - m_dataType = StringData; - m_stringData = new QString(data); + return static_cast(source) == source; + } + + template + typename std::enable_if<(sizeof(Number) > 1), bool>::type + squeeze(const Container &numbers) + { + typedef typename QIntegerForSize::Signed Small; + foreach (Number item, numbers) { + if (!squeezable(item)) + return false; } + assignNumbers(numbers); + return true; + } + + template + typename std::enable_if<(sizeof(Number) <= 1), bool>::type + squeeze(const Container &) + { + return false; + } + + template + void assignNumbers(const Container &numbers) + { + Number *data; + m_dataLength = squeezable(numbers.size()) ? + numbers.size() : std::numeric_limits::max(); + if (m_dataLength > sizeof(m_data) / sizeof(Number)) { + if (squeeze(numbers)) + return; + m_dataType = static_cast((sizeof(Number) * 8) | External); + m_data.external = malloc(m_dataLength * sizeof(Number)); + data = static_cast(m_data.external); + } else { + m_dataType = static_cast(sizeof(Number) * 8); + data = static_cast(m_dataType & External ? m_data.external : &m_data); + } + quint16 i = 0; // If you really have more than 64k items, this will wrap. Too bad. + foreach (Number item, numbers) + data[i++] = item; + } + + void clearPointer() + { + if (m_dataType & External) + free(m_data.external); } }; diff --git a/src/plugins/qmlprofiler/qmlprofiler.pro b/src/plugins/qmlprofiler/qmlprofiler.pro index 8fe65c66ffb..2757110c611 100644 --- a/src/plugins/qmlprofiler/qmlprofiler.pro +++ b/src/plugins/qmlprofiler/qmlprofiler.pro @@ -39,6 +39,7 @@ SOURCES += \ qmlprofilertracefile.cpp \ qmlprofilertraceview.cpp \ qmlprofilerviewmanager.cpp \ + qmltypedevent.cpp \ scenegraphtimelinemodel.cpp HEADERS += \ @@ -84,6 +85,7 @@ HEADERS += \ qmlprofilertracefile.h \ qmlprofilertraceview.h \ qmlprofilerviewmanager.h \ + qmltypedevent.h \ scenegraphtimelinemodel.h RESOURCES += \ diff --git a/src/plugins/qmlprofiler/qmlprofiler.qbs b/src/plugins/qmlprofiler/qmlprofiler.qbs index 8dac527a66f..4852c363b58 100644 --- a/src/plugins/qmlprofiler/qmlprofiler.qbs +++ b/src/plugins/qmlprofiler/qmlprofiler.qbs @@ -59,6 +59,7 @@ QtcPlugin { "qmlprofilertracefile.cpp", "qmlprofilertracefile.h", "qmlprofilertraceview.cpp", "qmlprofilertraceview.h", "qmlprofilerviewmanager.cpp", "qmlprofilerviewmanager.h", + "qmltypedevent.cpp", "qmltypedevent.h", "scenegraphtimelinemodel.cpp", "scenegraphtimelinemodel.h", ] } diff --git a/src/plugins/qmlprofiler/qmlprofileranimationsmodel.cpp b/src/plugins/qmlprofiler/qmlprofileranimationsmodel.cpp index 36b956a1458..a9cece7fddc 100644 --- a/src/plugins/qmlprofiler/qmlprofileranimationsmodel.cpp +++ b/src/plugins/qmlprofiler/qmlprofileranimationsmodel.cpp @@ -78,10 +78,10 @@ void QmlProfilerAnimationsModel::loadData() if (!accepted(type)) continue; - lastThread = (AnimationThread)event.numericData(2); + lastThread = (AnimationThread)event.number(2); // initial estimation of the event duration: 1/framerate - qint64 estimatedDuration = event.numericData(0) > 0 ? 1e9/event.numericData(0) : 1; + qint64 estimatedDuration = event.number(0) > 0 ? 1e9 / event.number(0) : 1; // the profiler registers the animation events at the end of them qint64 realEndTime = event.timestamp(); @@ -97,8 +97,8 @@ void QmlProfilerAnimationsModel::loadData() // Don't "fix" the framerate even if we've fixed the duration. // The server should know better after all and if it doesn't we want to see that. lastEvent.typeId = event.typeIndex(); - lastEvent.framerate = (int)event.numericData(0); - lastEvent.animationcount = (int)event.numericData(1); + lastEvent.framerate = event.number(0); + lastEvent.animationcount = event.number(1); QTC_ASSERT(lastEvent.animationcount > 0, continue); m_data.insert(insert(realStartTime, realEndTime - realStartTime, lastThread), lastEvent); diff --git a/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp b/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp index 19852475c7b..1f64834392c 100644 --- a/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp @@ -248,7 +248,7 @@ void QmlProfilerDataModel::addEvent(Message message, RangeType rangeType, int de message == DebugMessage ? QString() : data); QmlEvent eventData = (message == DebugMessage) ? QmlEvent(startTime, duration, -1, data) : - QmlEvent(startTime, duration, -1, ndata1, ndata2, ndata3, ndata4, ndata5); + QmlEvent(startTime, duration, -1, {ndata1, ndata2, ndata3, ndata4, ndata5}); QHash::Iterator it = d->eventTypeIds.find(typeData); if (it != d->eventTypeIds.end()) { diff --git a/src/plugins/qmlprofiler/qmlprofilertracefile.cpp b/src/plugins/qmlprofiler/qmlprofilertracefile.cpp index 5e93f0b04a8..ca15d28eb66 100644 --- a/src/plugins/qmlprofiler/qmlprofilertracefile.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertracefile.cpp @@ -360,7 +360,7 @@ void QmlProfilerFileReader::loadEvents(QXmlStreamReader &stream) case QXmlStreamReader::StartElement: { if (elementName == _("range")) { progress(stream.device()); - QmlEvent event(0, 0, -1, 0, 0, 0, 0, 0); + QmlEvent event; const QXmlStreamAttributes attributes = stream.attributes(); if (!attributes.hasAttribute(_("startTime")) @@ -375,37 +375,37 @@ void QmlProfilerFileReader::loadEvents(QXmlStreamReader &stream) // attributes for special events if (attributes.hasAttribute(_("framerate"))) - event.setNumericData(0, attributes.value(_("framerate")).toLongLong()); + event.setNumber(0, attributes.value(_("framerate")).toInt()); if (attributes.hasAttribute(_("animationcount"))) - event.setNumericData(1, attributes.value(_("animationcount")).toLongLong()); + event.setNumber(1, attributes.value(_("animationcount")).toInt()); if (attributes.hasAttribute(_("thread"))) - event.setNumericData(2, attributes.value(_("thread")).toLongLong()); + event.setNumber(2, attributes.value(_("thread")).toInt()); if (attributes.hasAttribute(_("width"))) - event.setNumericData(0, attributes.value(_("width")).toLongLong()); + event.setNumber(0, attributes.value(_("width")).toInt()); if (attributes.hasAttribute(_("height"))) - event.setNumericData(1, attributes.value(_("height")).toLongLong()); + event.setNumber(1, attributes.value(_("height")).toInt()); if (attributes.hasAttribute(_("refCount"))) - event.setNumericData(2, attributes.value(_("refCount")).toLongLong()); + event.setNumber(2, attributes.value(_("refCount")).toInt()); if (attributes.hasAttribute(_("amount"))) - event.setNumericData(0, attributes.value(_("amount")).toLongLong()); + event.setNumber(0, attributes.value(_("amount")).toLongLong()); if (attributes.hasAttribute(_("timing1"))) - event.setNumericData(0, attributes.value(_("timing1")).toLongLong()); + event.setNumber(0, attributes.value(_("timing1")).toLongLong()); if (attributes.hasAttribute(_("timing2"))) - event.setNumericData(1, attributes.value(_("timing2")).toLongLong()); + event.setNumber(1, attributes.value(_("timing2")).toLongLong()); if (attributes.hasAttribute(_("timing3"))) - event.setNumericData(2, attributes.value(_("timing3")).toLongLong()); + event.setNumber(2, attributes.value(_("timing3")).toLongLong()); if (attributes.hasAttribute(_("timing4"))) - event.setNumericData(3, attributes.value(_("timing4")).toLongLong()); + event.setNumber(3, attributes.value(_("timing4")).toLongLong()); if (attributes.hasAttribute(_("timing5"))) - event.setNumericData(4, attributes.value(_("timing5")).toLongLong()); + event.setNumber(4, attributes.value(_("timing5")).toLongLong()); if (attributes.hasAttribute(_("type"))) - event.setNumericData(0, attributes.value(_("type")).toLongLong()); + event.setNumber(0, attributes.value(_("type")).toInt()); if (attributes.hasAttribute(_("data1"))) - event.setNumericData(1, attributes.value(_("data1")).toLongLong()); + event.setNumber(1, attributes.value(_("data1")).toInt()); if (attributes.hasAttribute(_("data2"))) - event.setNumericData(2, attributes.value(_("data2")).toLongLong()); + event.setNumber(2, attributes.value(_("data2")).toInt()); if (attributes.hasAttribute(_("text"))) - event.setStringData(attributes.value(_("text")).toString()); + event.setString(attributes.value(_("text")).toString()); event.setTypeIndex(attributes.value(_("eventIndex")).toInt()); @@ -601,49 +601,47 @@ void QmlProfilerFileWriter::save(QIODevice *device) if (type.message == Event) { if (type.detailType == AnimationFrame) { // special: animation event - stream.writeAttribute(_("framerate"), QString::number(event.numericData(0))); - stream.writeAttribute(_("animationcount"), QString::number(event.numericData(1))); - stream.writeAttribute(_("thread"), QString::number(event.numericData(2))); + stream.writeAttribute(_("framerate"), QString::number(event.number(0))); + stream.writeAttribute(_("animationcount"), + QString::number(event.number(1))); + stream.writeAttribute(_("thread"), QString::number(event.number(2))); } else if (type.detailType == Key || type.detailType == Mouse) { // special: input event - stream.writeAttribute(_("type"), QString::number(event.numericData(0))); - stream.writeAttribute(_("data1"), QString::number(event.numericData(1))); - stream.writeAttribute(_("data2"), QString::number(event.numericData(2))); + stream.writeAttribute(_("type"), QString::number(event.number(0))); + stream.writeAttribute(_("data1"), QString::number(event.number(1))); + stream.writeAttribute(_("data2"), QString::number(event.number(2))); } } // special: pixmap cache event if (type.message == PixmapCacheEvent) { if (type.detailType == PixmapSizeKnown) { - stream.writeAttribute(_("width"), QString::number(event.numericData(0))); - stream.writeAttribute(_("height"), QString::number(event.numericData(1))); + stream.writeAttribute(_("width"), QString::number(event.number(0))); + stream.writeAttribute(_("height"), QString::number(event.number(1))); } if (type.detailType == PixmapReferenceCountChanged || type.detailType == PixmapCacheCountChanged) - stream.writeAttribute(_("refCount"), QString::number(event.numericData(2))); + stream.writeAttribute(_("refCount"), QString::number(event.number(2))); } if (type.message == SceneGraphFrame) { // special: scenegraph frame events - if (event.numericData(0) > 0) - stream.writeAttribute(_("timing1"), QString::number(event.numericData(0))); - if (event.numericData(1) > 0) - stream.writeAttribute(_("timing2"), QString::number(event.numericData(1))); - if (event.numericData(2) > 0) - stream.writeAttribute(_("timing3"), QString::number(event.numericData(2))); - if (event.numericData(3) > 0) - stream.writeAttribute(_("timing4"), QString::number(event.numericData(3))); - if (event.numericData(4) > 0) - stream.writeAttribute(_("timing5"), QString::number(event.numericData(4))); + for (int i = 0; i < 5; ++i) { + qint64 number = event.number(i); + if (number <= 0) + continue; + stream.writeAttribute(QString::fromLatin1("timing%1").arg(i + 1), + QString::number(number)); + } } // special: memory allocation event if (type.message == MemoryAllocation) - stream.writeAttribute(_("amount"), QString::number(event.numericData(0))); + stream.writeAttribute(_("amount"), QString::number(event.number(0))); if (type.message == DebugMessage) - stream.writeAttribute(_("text"), event.stringData()); + stream.writeAttribute(_("text"), event.string()); stream.writeEndElement(); incrementProgress(); diff --git a/src/plugins/qmlprofiler/qmltypedevent.cpp b/src/plugins/qmlprofiler/qmltypedevent.cpp new file mode 100644 index 00000000000..235c4c177c1 --- /dev/null +++ b/src/plugins/qmlprofiler/qmltypedevent.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "qmltypedevent.h" +#include + +namespace QmlProfiler { + +QDataStream &operator>>(QDataStream &stream, QmlTypedEvent &event) +{ + qint64 time; + qint32 messageType; + qint32 subtype; + + stream >> time >> messageType; + + RangeType rangeType = MaximumRangeType; + if (!stream.atEnd()) { + stream >> subtype; + rangeType = static_cast(subtype); + } else { + subtype = -1; + } + + event.event.setTimestamp(time); + event.event.setTypeIndex(-1); + event.type.displayName.clear(); + event.type.data.clear(); + event.type.location.filename.clear(); + event.type.location.line = event.type.location.column = -1; + + switch (messageType) { + case Event: { + event.type.detailType = subtype; + event.type.rangeType = MaximumRangeType; + event.type.message = static_cast(messageType); + switch (subtype) { + case StartTrace: + case EndTrace: { + QVarLengthArray engineIds; + while (!stream.atEnd()) { + qint32 id; + stream >> id; + engineIds << id; + } + event.event.setNumbers, qint32>(engineIds); + break; + } + case AnimationFrame: { + qint32 frameRate, animationCount; + qint32 threadId; + stream >> frameRate >> animationCount; + if (!stream.atEnd()) + stream >> threadId; + else + threadId = 0; + + event.event.setNumbers({frameRate, animationCount, threadId}); + break; + } + case Mouse: + case Key: + int inputType = (subtype == Key ? InputKeyUnknown : InputMouseUnknown); + if (!stream.atEnd()) + stream >> inputType; + qint32 a = -1; + if (!stream.atEnd()) + stream >> a; + qint32 b = -1; + if (!stream.atEnd()) + stream >> b; + + event.event.setNumbers({inputType, a, b}); + break; + } + + break; + } + case Complete: { + event.type.message = static_cast(messageType); + event.type.rangeType = MaximumRangeType; + event.type.detailType = subtype; + break; + } + case SceneGraphFrame: { + QVarLengthArray params; + qint64 param; + + while (!stream.atEnd()) { + stream >> param; + params.push_back(param); + } + + event.type.message = static_cast(messageType); + event.type.rangeType = MaximumRangeType; + event.type.detailType = subtype; + event.event.setNumbers, qint64>(params); + break; + } + case PixmapCacheEvent: { + qint32 width = 0, height = 0, refcount = 0; + stream >> event.type.location.filename; + if (subtype == PixmapReferenceCountChanged || subtype == PixmapCacheCountChanged) { + stream >> refcount; + } else if (subtype == PixmapSizeKnown) { + stream >> width >> height; + refcount = 1; + } + + event.type.message = static_cast(messageType); + event.type.rangeType = MaximumRangeType; + event.type.location.line = event.type.location.column = 0; + event.type.detailType = subtype; + event.event.setNumbers({width, height, refcount}); + break; + } + case MemoryAllocation: { + qint64 delta; + stream >> delta; + + event.type.message = static_cast(messageType); + event.type.rangeType = MaximumRangeType; + event.type.detailType = subtype; + event.event.setNumbers({delta}); + break; + } + case RangeStart: { + // read and ignore binding type + if (rangeType == Binding && !stream.atEnd()) { + qint32 bindingType; + stream >> bindingType; + } + + event.type.message = MaximumMessage; + event.type.rangeType = rangeType; + event.event.setRangeStage(RangeStart); + event.type.detailType = -1; + break; + } + case RangeData: { + stream >> event.type.data; + + event.type.message = MaximumMessage; + event.type.rangeType = rangeType; + event.event.setRangeStage(RangeData); + event.type.detailType = -1; + break; + } + case RangeLocation: { + stream >> event.type.location.filename + >> static_cast(event.type.location.line); + + if (!stream.atEnd()) + stream >> static_cast(event.type.location.column); + else + event.type.location.column = -1; + + event.type.message = MaximumMessage; + event.type.rangeType = rangeType; + event.event.setRangeStage(RangeLocation); + event.type.detailType = -1; + break; + } + case RangeEnd: { + event.type.message = MaximumMessage; + event.type.rangeType = rangeType; + event.event.setRangeStage(RangeEnd); + event.type.detailType = -1; + break; + } + default: + event.type.message = static_cast(messageType); + event.type.rangeType = MaximumRangeType; + event.type.detailType = subtype; + break; + } + + return stream; +} + +} // namespace QmlProfiler diff --git a/src/plugins/qmlprofiler/qmltypedevent.h b/src/plugins/qmlprofiler/qmltypedevent.h new file mode 100644 index 00000000000..9a3375f792c --- /dev/null +++ b/src/plugins/qmlprofiler/qmltypedevent.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#pragma once + +#include "qmlevent.h" +#include "qmleventtype.h" + +#include + +namespace QmlProfiler { + +struct QmlTypedEvent +{ + QmlEvent event; + QmlEventType type; +}; + +QDataStream &operator>>(QDataStream &stream, QmlTypedEvent &event); + +} // namespace QmlProfiler diff --git a/src/plugins/qmlprofiler/scenegraphtimelinemodel.cpp b/src/plugins/qmlprofiler/scenegraphtimelinemodel.cpp index ba3b7410aca..d537c200fcd 100644 --- a/src/plugins/qmlprofiler/scenegraphtimelinemodel.cpp +++ b/src/plugins/qmlprofiler/scenegraphtimelinemodel.cpp @@ -150,71 +150,79 @@ void SceneGraphTimelineModel::loadData() // look incomplete if that was left out as the printf profiler lists it, too, and people // are apparently comparing that. Unfortunately it is somewhat redundant as the other // parts of the breakdown are usually very short. - qint64 startTime = event.timestamp() - event.numericData(0) - event.numericData(1) - - event.numericData(2) - event.numericData(3); - startTime += insert(startTime, event.numericData(0), event.typeIndex(), RenderPreprocess); - startTime += insert(startTime, event.numericData(1), event.typeIndex(), RenderUpdate); - startTime += insert(startTime, event.numericData(2), event.typeIndex(), RenderBind); - insert(startTime, event.numericData(3), event.typeIndex(), RenderRender); + qint64 startTime = event.timestamp() - event.number(0) - event.number(1) + - event.number(2) - event.number(3); + startTime += insert(startTime, event.number(0), event.typeIndex(), + RenderPreprocess); + startTime += insert(startTime, event.number(1), event.typeIndex(), + RenderUpdate); + startTime += insert(startTime, event.number(2), event.typeIndex(), RenderBind); + insert(startTime, event.number(3), event.typeIndex(), RenderRender); break; } case SceneGraphAdaptationLayerFrame: { - qint64 startTime = event.timestamp() - event.numericData(1) - event.numericData(2); - startTime += insert(startTime, event.numericData(1), event.typeIndex(), GlyphRender, - event.numericData(0)); - insert(startTime, event.numericData(2), event.typeIndex(), GlyphStore, event.numericData(0)); + qint64 startTime = event.timestamp() - event.number(1) + - event.number(2); + startTime += insert(startTime, event.number(1), event.typeIndex(), GlyphRender, + event.number(0)); + insert(startTime, event.number(2), event.typeIndex(), GlyphStore, + event.number(0)); break; } case SceneGraphContextFrame: { - insert(event.timestamp() - event.numericData(0), event.numericData(0), event.typeIndex(), - Material); + insert(event.timestamp() - event.number(0), event.number(0), + event.typeIndex(), Material); break; } case SceneGraphRenderLoopFrame: { - qint64 startTime = event.timestamp() - event.numericData(0) - event.numericData(1) - - event.numericData(2); - startTime += insert(startTime, event.numericData(0), event.typeIndex(), - RenderThreadSync); - startTime += insert(startTime, event.numericData(1), event.typeIndex(), - Render); - insert(startTime, event.numericData(2), event.typeIndex(), Swap); + qint64 startTime = event.timestamp() - event.number(0) - event.number(1) + - event.number(2); + startTime += insert(startTime, event.number(0), event.typeIndex(), + RenderThreadSync); + startTime += insert(startTime, event.number(1), event.typeIndex(), + Render); + insert(startTime, event.number(2), event.typeIndex(), Swap); break; } case SceneGraphTexturePrepare: { - qint64 startTime = event.timestamp() - event.numericData(0) - event.numericData(1) - - event.numericData(2) - event.numericData(3) - event.numericData(4); - startTime += insert(startTime, event.numericData(0), event.typeIndex(), TextureBind); - startTime += insert(startTime, event.numericData(1), event.typeIndex(), TextureConvert); - startTime += insert(startTime, event.numericData(2), event.typeIndex(), TextureSwizzle); - startTime += insert(startTime, event.numericData(3), event.typeIndex(), TextureUpload); - insert(startTime, event.numericData(4), event.typeIndex(), TextureMipmap); + qint64 startTime = event.timestamp() - event.number(0) - event.number(1) + - event.number(2) - event.number(3) - event.number(4); + startTime += insert(startTime, event.number(0), event.typeIndex(), TextureBind); + startTime += insert(startTime, event.number(1), event.typeIndex(), + TextureConvert); + startTime += insert(startTime, event.number(2), event.typeIndex(), + TextureSwizzle); + startTime += insert(startTime, event.number(3), event.typeIndex(), + TextureUpload); + insert(startTime, event.number(4), event.typeIndex(), TextureMipmap); break; } case SceneGraphTextureDeletion: { - insert(event.timestamp() - event.numericData(0), event.numericData(0), event.typeIndex(), - TextureDeletion); + insert(event.timestamp() - event.number(0), event.number(0), + event.typeIndex(), TextureDeletion); break; } case SceneGraphPolishAndSync: { - qint64 startTime = event.timestamp() - event.numericData(0) - event.numericData(1) - - event.numericData(2) - event.numericData(3); + qint64 startTime = event.timestamp() - event.number(0) - event.number(1) + - event.number(2) - event.number(3); - startTime += insert(startTime, event.numericData(0), event.typeIndex(), Polish); - startTime += insert(startTime, event.numericData(1), event.typeIndex(), Wait); - startTime += insert(startTime, event.numericData(2), event.typeIndex(), GUIThreadSync); - insert(startTime, event.numericData(3), event.typeIndex(), Animations); + startTime += insert(startTime, event.number(0), event.typeIndex(), Polish); + startTime += insert(startTime, event.number(1), event.typeIndex(), Wait); + startTime += insert(startTime, event.number(2), event.typeIndex(), + GUIThreadSync); + insert(startTime, event.number(3), event.typeIndex(), Animations); break; } case SceneGraphWindowsAnimations: { // GUI thread, separate animations stage - insert(event.timestamp() - event.numericData(0), event.numericData(0), event.typeIndex(), - Animations); + insert(event.timestamp() - event.number(0), event.number(0), + event.typeIndex(), Animations); break; } case SceneGraphPolishFrame: { // GUI thread, separate polish stage - insert(event.timestamp() - event.numericData(0), event.numericData(0), event.typeIndex(), - Polish); + insert(event.timestamp() - event.number(0), event.number(0), + event.typeIndex(), Polish); break; } default: break;