From 0924ee5efb3b829fd2f09eb2028b060404d83b68 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 23 May 2016 16:34:32 +0200 Subject: [PATCH] QmlProfiler: Move type resolution logic into trace client This way we will be able to use server-provided type IDs for more efficient lookup of event types. Change-Id: I37cd592a7829e5f36c6cfc04e400013d1dc37155 Reviewed-by: Joerg Bornemann --- .../qmlprofiler/qmlprofilerdatamodel.cpp | 111 ++---------------- .../qmlprofiler/qmlprofilerdatamodel.h | 2 +- .../qmlprofiler/qmlprofilertraceclient.cpp | 98 +++++++++++++++- 3 files changed, 106 insertions(+), 105 deletions(-) diff --git a/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp b/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp index 3794b6ce151..e9ab29d169f 100644 --- a/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp @@ -43,13 +43,9 @@ class QmlProfilerDataModel::QmlProfilerDataModelPrivate { public: void rewriteType(int typeIndex); - int resolveType(const QmlEventType &type); int resolveStackTop(); QVector eventTypes; - QHash eventTypeIds; - - QStack rangesInProgress; QmlProfilerModelManager *modelManager; int modelId; @@ -141,8 +137,15 @@ void QmlProfilerDataModel::setEventTypes(const QVector &types) { Q_D(QmlProfilerDataModel); d->eventTypes = types; - for (int id = 0; id < types.count(); ++id) - d->eventTypeIds[types[id]] = id; +} + +int QmlProfilerDataModel::addEventType(const QmlEventType &type) +{ + Q_D(QmlProfilerDataModel); + int typeIndex = d->eventTypes.length(); + d->eventTypes.append(type); + d->rewriteType(typeIndex); + return typeIndex; } void QmlProfilerDataModel::addEvent(const QmlEvent &event) @@ -159,8 +162,6 @@ void QmlProfilerDataModel::clear() d->file.open(); d->eventStream.setDevice(&d->file); d->eventTypes.clear(); - d->eventTypeIds.clear(); - d->rangesInProgress.clear(); d->detailsRewriter->clearRequests(); } @@ -170,26 +171,6 @@ bool QmlProfilerDataModel::isEmpty() const return d->file.pos() == 0; } -inline static uint qHash(const QmlEventType &type) -{ - return qHash(type.location.filename) ^ - ((type.location.line & 0xfff) | // 12 bits of line number - ((type.message << 12) & 0xf000) | // 4 bits of message - ((type.location.column << 16) & 0xff0000) | // 8 bits of column - ((type.rangeType << 24) & 0xf000000) | // 4 bits of rangeType - ((type.detailType << 28) & 0xf0000000)); // 4 bits of detailType -} - -inline static bool operator==(const QmlEventType &type1, - const QmlEventType &type2) -{ - return type1.message == type2.message && type1.rangeType == type2.rangeType && - type1.detailType == type2.detailType && type1.location.line == type2.location.line && - type1.location.column == type2.location.column && - // compare filename last as it's expensive. - type1.location.filename == type2.location.filename; -} - void QmlProfilerDataModel::QmlProfilerDataModelPrivate::rewriteType(int typeIndex) { QmlEventType &type = eventTypes[typeIndex]; @@ -207,80 +188,6 @@ void QmlProfilerDataModel::QmlProfilerDataModelPrivate::rewriteType(int typeInde detailsRewriter->requestDetailsForLocation(typeIndex, type.location); } -int QmlProfilerDataModel::QmlProfilerDataModelPrivate::resolveType(const QmlEventType &type) -{ - QHash::ConstIterator it = eventTypeIds.constFind(type); - - int typeIndex = -1; - if (it != eventTypeIds.constEnd()) { - typeIndex = it.value(); - } else { - typeIndex = eventTypes.size(); - eventTypeIds[type] = typeIndex; - eventTypes.append(type); - rewriteType(typeIndex); - } - return typeIndex; -} - -int QmlProfilerDataModel::QmlProfilerDataModelPrivate::resolveStackTop() -{ - if (rangesInProgress.isEmpty()) - return -1; - - QmlTypedEvent &typedEvent = rangesInProgress.top(); - int typeIndex = typedEvent.event.typeIndex(); - if (typeIndex >= 0) - return typeIndex; - - typeIndex = resolveType(typedEvent.type); - typedEvent.event.setTypeIndex(typeIndex); - eventStream << typedEvent.event; - modelManager->dispatch(typedEvent.event, eventTypes[typeIndex]); - return typeIndex; -} - -void QmlProfilerDataModel::addTypedEvent(const QmlEvent &event, const QmlEventType &type) -{ - Q_D(QmlProfilerDataModel); - - // RangeData and RangeLocation always apply to the range on the top of the stack. Furthermore, - // all ranges are perfectly nested. This is why we can defer the type resolution until either - // the range ends or a child range starts. With only the information in RangeStart we wouldn't - // be able to uniquely identify the event type. - Message rangeStage = type.rangeType == MaximumRangeType ? type.message : event.rangeStage(); - switch (rangeStage) { - case RangeStart: - d->resolveStackTop(); - d->rangesInProgress.push(QmlTypedEvent({event, type})); - break; - case RangeEnd: { - int typeIndex = d->resolveStackTop(); - QTC_ASSERT(typeIndex != -1, break); - QmlEvent appended = event; - appended.setTypeIndex(typeIndex); - d->eventStream << appended; - d->modelManager->dispatch(appended, d->eventTypes[typeIndex]); - d->rangesInProgress.pop(); - break; - } - case RangeData: - d->rangesInProgress.top().type.data = type.data; - break; - case RangeLocation: - d->rangesInProgress.top().type.location = type.location; - break; - default: { - QmlEvent appended = event; - int typeIndex = d->resolveType(type); - appended.setTypeIndex(typeIndex); - d->eventStream << appended; - d->modelManager->dispatch(appended, d->eventTypes[typeIndex]); - break; - } - } -} - void QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd, QmlProfilerModelManager::EventLoader loader) const { diff --git a/src/plugins/qmlprofiler/qmlprofilerdatamodel.h b/src/plugins/qmlprofiler/qmlprofilerdatamodel.h index 88fec553a0c..5bb97abea4f 100644 --- a/src/plugins/qmlprofiler/qmlprofilerdatamodel.h +++ b/src/plugins/qmlprofiler/qmlprofilerdatamodel.h @@ -47,11 +47,11 @@ public: const QVector &eventTypes() const; void setEventTypes(const QVector &types); + int addEventType(const QmlEventType &type); void clear(); bool isEmpty() const; void addEvent(const QmlEvent &event); - void addTypedEvent(const QmlEvent &event, const QmlEventType &type); void replayEvents(qint64 startTime, qint64 endTime, QmlProfilerModelManager::EventLoader loader) const; void finalize(); diff --git a/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp b/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp index c848edbeb16..84a3fffa3c7 100644 --- a/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp @@ -30,9 +30,30 @@ #include #include #include +#include namespace QmlProfiler { +inline static uint qHash(const QmlEventType &type) +{ + return qHash(type.location.filename) ^ + ((type.location.line & 0xfff) | // 12 bits of line number + ((type.message << 12) & 0xf000) | // 4 bits of message + ((type.location.column << 16) & 0xff0000) | // 8 bits of column + ((type.rangeType << 24) & 0xf000000) | // 4 bits of rangeType + ((type.detailType << 28) & 0xf0000000)); // 4 bits of detailType +} + +inline static bool operator==(const QmlEventType &type1, + const QmlEventType &type2) +{ + return type1.message == type2.message && type1.rangeType == type2.rangeType && + type1.detailType == type2.detailType && type1.location.line == type2.location.line && + type1.location.column == type2.location.column && + // compare filename last as it's expensive. + type1.location.filename == type2.location.filename; +} + class QmlProfilerTraceClientPrivate { public: QmlProfilerTraceClientPrivate(QmlProfilerTraceClient *_q, QmlDebug::QmlDebugConnection *client, @@ -50,6 +71,9 @@ public: void sendRecordingStatus(int engineId); bool updateFeatures(ProfileFeature feature); + int resolveType(const QmlEventType &type); + int resolveStackTop(); + void processCurrentEvent(); QmlProfilerTraceClient *q; QmlProfilerDataModel *model; @@ -63,8 +87,76 @@ public: // Reuse the same event, so that we don't have to constantly reallocate all the data. QmlTypedEvent currentEvent; + QHash eventTypeIds; + QStack rangesInProgress; }; +int QmlProfilerTraceClientPrivate::resolveType(const QmlEventType &type) +{ + QHash::ConstIterator it = eventTypeIds.constFind(type); + + int typeIndex = -1; + if (it != eventTypeIds.constEnd()) { + typeIndex = it.value(); + } else { + typeIndex = model->addEventType(type); + eventTypeIds[type] = typeIndex; + } + return typeIndex; +} + +int QmlProfilerTraceClientPrivate::resolveStackTop() +{ + if (rangesInProgress.isEmpty()) + return -1; + + QmlTypedEvent &typedEvent = rangesInProgress.top(); + int typeIndex = typedEvent.event.typeIndex(); + if (typeIndex >= 0) + return typeIndex; + + typeIndex = resolveType(typedEvent.type); + typedEvent.event.setTypeIndex(typeIndex); + model->addEvent(typedEvent.event); + return typeIndex; +} + +void QmlProfilerTraceClientPrivate::processCurrentEvent() +{ + // RangeData and RangeLocation always apply to the range on the top of the stack. Furthermore, + // all ranges are perfectly nested. This is why we can defer the type resolution until either + // the range ends or a child range starts. With only the information in RangeStart we wouldn't + // be able to uniquely identify the event type. + Message rangeStage = currentEvent.type.rangeType == MaximumRangeType ? + currentEvent.type.message : currentEvent.event.rangeStage(); + switch (rangeStage) { + case RangeStart: + resolveStackTop(); + rangesInProgress.push(currentEvent); + break; + case RangeEnd: { + int typeIndex = resolveStackTop(); + QTC_ASSERT(typeIndex != -1, break); + currentEvent.event.setTypeIndex(typeIndex); + model->addEvent(currentEvent.event); + rangesInProgress.pop(); + break; + } + case RangeData: + rangesInProgress.top().type.data = currentEvent.type.data; + break; + case RangeLocation: + rangesInProgress.top().type.location = currentEvent.type.location; + break; + default: { + int typeIndex = resolveType(currentEvent.type); + currentEvent.event.setTypeIndex(typeIndex); + model->addEvent(currentEvent.event); + break; + } + } +} + void QmlProfilerTraceClientPrivate::sendRecordingStatus(int engineId) { QmlDebug::QPacket stream(q->connection()->currentDataStreamVersion()); @@ -96,6 +188,8 @@ QmlProfilerTraceClient::~QmlProfilerTraceClient() void QmlProfilerTraceClient::clearData() { + d->eventTypeIds.clear(); + d->rangesInProgress.clear(); if (d->recordedFeatures != 0) { d->recordedFeatures = 0; emit recordedFeaturesChanged(0); @@ -152,7 +246,7 @@ void QmlProfilerTraceClient::setRequestedFeatures(quint64 features) d->currentEvent.type.message = DebugMessage; d->currentEvent.type.rangeType = MaximumRangeType; d->currentEvent.type.detailType = type; - d->model->addTypedEvent(d->currentEvent.event, d->currentEvent.type); + d->processCurrentEvent(); }); } else { d->messageClient.reset(); @@ -211,7 +305,7 @@ void QmlProfilerTraceClient::messageReceived(const QByteArray &data) emit traceFinished(d->currentEvent.event.timestamp(), d->currentEvent.event.numbers, qint32>()); } else if (d->updateFeatures(d->currentEvent.type.feature())) { - d->model->addTypedEvent(d->currentEvent.event, d->currentEvent.type); + d->processCurrentEvent(); } }