diff options
Diffstat (limited to 'src')
24 files changed, 462 insertions, 626 deletions
diff --git a/src/plugins/qmlprofiler/flamegraphmodel.cpp b/src/plugins/qmlprofiler/flamegraphmodel.cpp index 2a2055a0df..f5664dc5df 100644 --- a/src/plugins/qmlprofiler/flamegraphmodel.cpp +++ b/src/plugins/qmlprofiler/flamegraphmodel.cpp @@ -63,7 +63,7 @@ FlameGraphModel::FlameGraphModel(QmlProfilerModelManager *modelManager, void FlameGraphModel::clear() { beginResetModel(); - m_stackBottom = FlameGraphData(); + m_stackBottom = FlameGraphData(0, -1, 1); m_callStack.clear(); m_callStack.append(QmlEvent()); m_stackTop = &m_stackBottom; @@ -102,15 +102,16 @@ void FlameGraphModel::loadEvent(const QmlEvent &event, const QmlEventType &type) beginResetModel(); const QmlEvent *potentialParent = &(m_callStack.top()); - while (potentialParent->isValid() && - potentialParent->timestamp() + potentialParent->duration() <= event.timestamp()) { + if (event.rangeStage() == RangeEnd) { + m_stackTop->duration += event.timestamp() - potentialParent->timestamp(); m_callStack.pop(); m_stackTop = m_stackTop->parent; potentialParent = &(m_callStack.top()); + } else { + QTC_ASSERT(event.rangeStage() == RangeStart, return); + m_callStack.push(event); + m_stackTop = pushChild(m_stackTop, event); } - - m_callStack.push(event); - m_stackTop = pushChild(m_stackTop, event); } void FlameGraphModel::finalize() @@ -126,31 +127,6 @@ void FlameGraphModel::onModelManagerStateChanged() { if (m_modelManager->state() == QmlProfilerModelManager::ClearingData) clear(); - else if (m_modelManager->state() == QmlProfilerModelManager::ProcessingData) - loadData(); -} - -void FlameGraphModel::loadData(qint64 rangeStart, qint64 rangeEnd) -{ - clear(); - const bool checkRanges = (rangeStart != -1) && (rangeEnd != -1); - - const QVector<QmlEvent> &eventList = m_modelManager->qmlModel()->events(); - const QVector<QmlEventType> &typesList = m_modelManager->qmlModel()->eventTypes(); - - for (int i = 0; i < eventList.size(); ++i) { - const QmlEvent &event = eventList[i]; - - if (checkRanges) { - if ((event.timestamp() + event.duration() < rangeStart) - || (event.timestamp() > rangeEnd)) - continue; - } - - loadEvent(event, typesList[event.typeIndex()]); - } - - finalize(); } static QString nameForType(RangeType typeNumber) @@ -223,12 +199,11 @@ FlameGraphData *FlameGraphModel::pushChild(FlameGraphData *parent, const QmlEven foreach (FlameGraphData *child, parent->children) { if (child->typeIndex == data.typeIndex()) { ++child->calls; - child->duration += data.duration(); return child; } } - FlameGraphData *child = new FlameGraphData(parent, data.typeIndex(), data.duration()); + FlameGraphData *child = new FlameGraphData(parent, data.typeIndex()); parent->children.append(child); return child; } @@ -293,5 +268,10 @@ QHash<int, QByteArray> FlameGraphModel::roleNames() const return names; } +QmlProfilerModelManager *FlameGraphModel::modelManager() const +{ + return m_modelManager; +} + } // namespace Internal } // namespace QmlProfiler diff --git a/src/plugins/qmlprofiler/flamegraphmodel.h b/src/plugins/qmlprofiler/flamegraphmodel.h index 547d3bc890..0b42aa3946 100644 --- a/src/plugins/qmlprofiler/flamegraphmodel.h +++ b/src/plugins/qmlprofiler/flamegraphmodel.h @@ -80,12 +80,12 @@ public: int columnCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; QHash<int, QByteArray> roleNames() const override; + QmlProfilerModelManager *modelManager() const; public slots: void loadEvent(const QmlEvent &event, const QmlEventType &type); void finalize(); void onModelManagerStateChanged(); - void loadData(qint64 rangeStart = -1, qint64 rangeEnd = -1); void loadNotes(int typeId, bool emitSignal); void clear(); diff --git a/src/plugins/qmlprofiler/flamegraphview.cpp b/src/plugins/qmlprofiler/flamegraphview.cpp index cf5846a258..f461b4332d 100644 --- a/src/plugins/qmlprofiler/flamegraphview.cpp +++ b/src/plugins/qmlprofiler/flamegraphview.cpp @@ -37,7 +37,7 @@ namespace Internal { FlameGraphView::FlameGraphView(QWidget *parent, QmlProfilerModelManager *manager) : QmlProfilerEventsView(parent), m_content(new QQuickWidget(this)), - m_model(new FlameGraphModel(manager, this)), m_isRestrictedToRange(false) + m_model(new FlameGraphModel(manager, this)) { setWindowTitle(QStringLiteral("Flamegraph")); setObjectName(QStringLiteral("QmlProfilerFlamegraph")); @@ -66,22 +66,6 @@ FlameGraphView::FlameGraphView(QWidget *parent, QmlProfilerModelManager *manager this, SIGNAL(gotoSourceLocation(QString,int,int))); } -void FlameGraphView::clear() -{ - m_isRestrictedToRange = false; -} - -void FlameGraphView::restrictToRange(qint64 rangeStart, qint64 rangeEnd) -{ - m_isRestrictedToRange = (rangeStart != -1 || rangeEnd != -1); - m_model->loadData(rangeStart, rangeEnd); -} - -bool FlameGraphView::isRestrictedToRange() const -{ - return m_isRestrictedToRange; -} - void FlameGraphView::selectByTypeId(int typeIndex) { m_content->rootObject()->setProperty("selectedTypeId", typeIndex); @@ -107,7 +91,7 @@ void FlameGraphView::contextMenuEvent(QContextMenuEvent *ev) menu.addActions(QmlProfilerTool::profilerContextMenuActions()); menu.addSeparator(); getGlobalStatsAction = menu.addAction(tr("Show Full Range")); - if (!isRestrictedToRange()) + if (!m_model->modelManager()->isRestrictedToRange()) getGlobalStatsAction->setEnabled(false); if (menu.exec(position) == getGlobalStatsAction) diff --git a/src/plugins/qmlprofiler/flamegraphview.h b/src/plugins/qmlprofiler/flamegraphview.h index 4acb1ac690..02b92723ed 100644 --- a/src/plugins/qmlprofiler/flamegraphview.h +++ b/src/plugins/qmlprofiler/flamegraphview.h @@ -40,10 +40,6 @@ class FlameGraphView : public QmlProfilerEventsView public: FlameGraphView(QWidget *parent, QmlProfilerModelManager *manager); - void clear() override; - void restrictToRange(qint64 rangeStart, qint64 rangeEnd) override; - bool isRestrictedToRange() const override; - public slots: void selectByTypeId(int typeIndex) override; void onVisibleFeaturesChanged(quint64 features) override; @@ -54,7 +50,6 @@ protected: private: QQuickWidget *m_content; FlameGraphModel *m_model; - bool m_isRestrictedToRange; }; } // namespace Internal diff --git a/src/plugins/qmlprofiler/memoryusagemodel.cpp b/src/plugins/qmlprofiler/memoryusagemodel.cpp index 9ec47b694b..88bfbcb6ce 100644 --- a/src/plugins/qmlprofiler/memoryusagemodel.cpp +++ b/src/plugins/qmlprofiler/memoryusagemodel.cpp @@ -142,12 +142,12 @@ bool MemoryUsageModel::accepted(const QmlEventType &type) const void MemoryUsageModel::loadEvent(const QmlEvent &event, const QmlEventType &type) { - while (!m_rangeStack.empty() && m_rangeStack.top().endTime < event.timestamp()) - m_rangeStack.pop(); if (type.message != MemoryAllocation) { if (type.rangeType != MaximumRangeType) { - m_rangeStack.push(RangeStackFrame(event.typeIndex(), event.timestamp(), - event.timestamp() + event.duration())); + if (event.rangeStage() == RangeStart) + m_rangeStack.push(RangeStackFrame(event.typeIndex(), event.timestamp())); + else if (event.rangeStage() == RangeEnd) + m_rangeStack.pop(); } return; } diff --git a/src/plugins/qmlprofiler/memoryusagemodel.h b/src/plugins/qmlprofiler/memoryusagemodel.h index 9cc1116823..1fb280323f 100644 --- a/src/plugins/qmlprofiler/memoryusagemodel.h +++ b/src/plugins/qmlprofiler/memoryusagemodel.h @@ -76,12 +76,11 @@ protected: private: struct RangeStackFrame { - RangeStackFrame() : originTypeIndex(-1), startTime(-1), endTime(-1) {} - RangeStackFrame(int originTypeIndex, qint64 startTime, qint64 endTime) : - originTypeIndex(originTypeIndex), startTime(startTime), endTime(endTime) {} + RangeStackFrame() : originTypeIndex(-1), startTime(-1) {} + RangeStackFrame(int originTypeIndex, qint64 startTime) : + originTypeIndex(originTypeIndex), startTime(startTime) {} int originTypeIndex; qint64 startTime; - qint64 endTime; }; static QString memoryTypeName(int type); diff --git a/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp b/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp index ddd96da4f0..5263928da9 100644 --- a/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp @@ -198,10 +198,6 @@ void QmlProfilerClientManager::connectClientSignals() this, &QmlProfilerClientManager::qmlComplete); connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::newEngine, this, &QmlProfilerClientManager::qmlNewEngine); - connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::rangedEvent, - d->modelManager, &QmlProfilerModelManager::addQmlEvent); - connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::debugMessage, - d->modelManager, &QmlProfilerModelManager::addDebugMessage); connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::traceFinished, d->modelManager->traceTime(), &QmlProfilerTraceTime::increaseEndTime); connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::traceStarted, @@ -212,6 +208,8 @@ void QmlProfilerClientManager::connectClientSignals() d->qmlclientplugin.data(), &QmlProfilerTraceClient::setRequestedFeatures); connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::recordedFeaturesChanged, d->profilerState, &QmlProfilerStateManager::setRecordedFeatures); + connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::qmlEvent, + d->modelManager, &QmlProfilerModelManager::addQmlEvent); } } @@ -222,10 +220,6 @@ void QmlProfilerClientManager::disconnectClientSignals() this, &QmlProfilerClientManager::qmlComplete); disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::newEngine, this, &QmlProfilerClientManager::qmlNewEngine); - disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::rangedEvent, - d->modelManager, &QmlProfilerModelManager::addQmlEvent); - disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::debugMessage, - d->modelManager, &QmlProfilerModelManager::addDebugMessage); disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::traceFinished, d->modelManager->traceTime(), &QmlProfilerTraceTime::increaseEndTime); disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::traceStarted, @@ -236,6 +230,8 @@ void QmlProfilerClientManager::disconnectClientSignals() d->qmlclientplugin.data(), &QmlProfilerTraceClient::setRequestedFeatures); disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::recordedFeaturesChanged, d->profilerState, &QmlProfilerStateManager::setRecordedFeatures); + disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::qmlEvent, + d->modelManager, &QmlProfilerModelManager::addQmlEvent); } } diff --git a/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp b/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp index 870fcd7f4a..a54658ecf6 100644 --- a/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp @@ -28,10 +28,12 @@ #include "qmlprofilernotesmodel.h" #include "qmlprofilerdetailsrewriter.h" #include "qmlprofilereventtypes.h" +#include "qmltypedevent.h" #include <utils/qtcassert.h> #include <QUrl> #include <QDebug> +#include <QStack> #include <algorithm> namespace QmlProfiler { @@ -39,10 +41,16 @@ namespace QmlProfiler { class QmlProfilerDataModel::QmlProfilerDataModelPrivate { public: + void rewriteType(int typeIndex); + int resolveType(const QmlEventType &type); + int resolveStackTop(); + QVector<QmlEventType> eventTypes; QVector<QmlEvent> eventList; QHash<QmlEventType, int> eventTypeIds; + QStack<QmlTypedEvent> rangesInProgress; + QmlProfilerModelManager *modelManager; int modelId; Internal::QmlProfilerDetailsRewriter *detailsRewriter; @@ -108,9 +116,7 @@ QmlProfilerDataModel::QmlProfilerDataModel(Utils::FileInProjectFinder *fileFinde connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::rewriteDetailsString, this, &QmlProfilerDataModel::detailsChanged); connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::eventDetailsChanged, - this, &QmlProfilerDataModel::detailsDone); - connect(this, &QmlProfilerDataModel::requestReload, - d->detailsRewriter, &QmlProfilerDetailsRewriter::reloadDocuments); + this, &QmlProfilerDataModel::allTypesLoaded); } QmlProfilerDataModel::~QmlProfilerDataModel() @@ -142,6 +148,9 @@ void QmlProfilerDataModel::setData(qint64 traceStart, qint64 traceEnd, d->eventTypes = types; for (int id = 0; id < types.count(); ++id) d->eventTypeIds[types[id]] = id; + + foreach (const QmlEvent &event, d->eventList) + d->modelManager->dispatch(event, d->eventTypes[event.typeIndex()]); } int QmlProfilerDataModel::count() const @@ -156,6 +165,7 @@ void QmlProfilerDataModel::clear() d->eventList.clear(); d->eventTypes.clear(); d->eventTypeIds.clear(); + d->rangesInProgress.clear(); d->detailsRewriter->clearRequests(); } @@ -165,11 +175,6 @@ bool QmlProfilerDataModel::isEmpty() const return d->eventList.isEmpty(); } -inline static bool operator<(const QmlEvent &t1, const QmlEvent &t2) -{ - return t1.timestamp() < t2.timestamp(); -} - inline static uint qHash(const QmlEventType &type) { return qHash(type.location.filename) ^ @@ -190,66 +195,139 @@ inline static bool operator==(const QmlEventType &type1, type1.location.filename == type2.location.filename; } -void QmlProfilerDataModel::processData() +void QmlProfilerDataModel::QmlProfilerDataModelPrivate::rewriteType(int typeIndex) { - Q_D(QmlProfilerDataModel); - // post-processing - - // sort events by start time, using above operator< - std::sort(d->eventList.begin(), d->eventList.end()); + QmlEventType &type = eventTypes[typeIndex]; + type.displayName = getDisplayName(type); + type.data = getInitialDetails(type); - // rewrite strings - int n = d->eventTypes.count(); - for (int i = 0; i < n; i++) { - QmlEventType *event = &d->eventTypes[i]; - event->displayName = getDisplayName(*event); - event->data = getInitialDetails(*event); + // Only bindings and signal handlers need rewriting + if (type.rangeType != Binding && type.rangeType != HandlingSignal) + return; - // - // request further details from files - // + // There is no point in looking for invalid locations + if (type.location.filename.isEmpty() || type.location.line < 0 || type.location.column < 0) + return; - if (event->rangeType != Binding && event->rangeType != HandlingSignal) - continue; - - // This skips anonymous bindings in Qt4.8 (we don't have valid location data for them) - if (event->location.filename.isEmpty()) - continue; + detailsRewriter->requestDetailsForLocation(typeIndex, type.location); +} - // Skip non-anonymous bindings from Qt4.8 (we already have correct details for them) - if (event->location.column == -1) - continue; +int QmlProfilerDataModel::QmlProfilerDataModelPrivate::resolveType(const QmlEventType &type) +{ + QHash<QmlEventType, int>::ConstIterator it = eventTypeIds.constFind(type); - d->detailsRewriter->requestDetailsForLocation(i, event->location); + int typeIndex = -1; + if (it != eventTypeIds.constEnd()) { + typeIndex = it.value(); + } else { + typeIndex = eventTypes.size(); + eventTypeIds[type] = typeIndex; + eventTypes.append(type); + rewriteType(typeIndex); } + return typeIndex; +} - emit requestReload(); +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); + eventList.append(typedEvent.event); + modelManager->dispatch(eventList.last(), eventTypes[typeIndex]); + return typeIndex; } -void QmlProfilerDataModel::addEvent(Message message, RangeType rangeType, int detailType, - qint64 startTime, qint64 duration, const QString &data, - const QmlEventLocation &location, qint64 ndata1, qint64 ndata2, - qint64 ndata3, qint64 ndata4, qint64 ndata5) +void QmlProfilerDataModel::addEvent(const QmlEvent &event, const QmlEventType &type) { Q_D(QmlProfilerDataModel); - QString displayName; - - QmlEventType typeData(displayName, location, message, rangeType, detailType, - message == DebugMessage ? QString() : data); - QmlEvent eventData = (message == DebugMessage) ? - QmlEvent(startTime, duration, -1, data) : - QmlEvent(startTime, duration, -1, {ndata1, ndata2, ndata3, ndata4, ndata5}); - QHash<QmlEventType, int>::Iterator it = d->eventTypeIds.find(typeData); - if (it != d->eventTypeIds.end()) { - eventData.setTypeIndex(it.value()); - } else { - eventData.setTypeIndex(d->eventTypes.size()); - d->eventTypeIds[typeData] = eventData.typeIndex(); - d->eventTypes.append(typeData); + // 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); + d->eventList.append(event); + QmlEvent &appended = d->eventList.last(); + appended.setTypeIndex(typeIndex); + 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: { + d->eventList.append(event); + QmlEvent &appended = d->eventList.last(); + int typeIndex = d->resolveType(type); + appended.setTypeIndex(typeIndex); + d->modelManager->dispatch(appended, d->eventTypes[typeIndex]); + break; } + } +} + +void QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd, + QmlProfilerModelManager::EventLoader loader) const +{ + Q_D(const QmlProfilerDataModel); + QStack<QmlEvent> stack; + foreach (const QmlEvent &event, d->eventList) { + const QmlEventType &type = d->eventTypes[event.typeIndex()]; + if (rangeStart != -1 && rangeEnd != -1) { + if (event.timestamp() < rangeStart) { + if (type.rangeType != MaximumRangeType) { + if (event.rangeStage() == RangeStart) + stack.push(event); + else if (event.rangeStage() == RangeEnd) + stack.pop(); + } + continue; + } else if (event.timestamp() > rangeEnd) { + if (type.rangeType != MaximumRangeType) { + if (event.rangeStage() == RangeEnd) { + if (stack.isEmpty()) { + QmlEvent endEvent(event); + endEvent.setTimestamp(rangeEnd); + loader(event, d->eventTypes[event.typeIndex()]); + } else { + stack.pop(); + } + } else if (event.rangeStage() == RangeStart) { + stack.push(event); + } + } + continue; + } else if (!stack.isEmpty()) { + foreach (QmlEvent stashed, stack) { + stashed.setTimestamp(rangeStart); + loader(stashed, d->eventTypes[stashed.typeIndex()]); + } + stack.clear(); + } + } - d->eventList.append(eventData); + loader(event, type); + } } qint64 QmlProfilerDataModel::lastTimeMark() const @@ -258,22 +336,20 @@ qint64 QmlProfilerDataModel::lastTimeMark() const if (d->eventList.isEmpty()) return 0; - return d->eventList.last().timestamp() + d->eventList.last().duration(); + return d->eventList.last().timestamp(); } -void QmlProfilerDataModel::detailsChanged(int requestId, const QString &newString) +void QmlProfilerDataModel::finalize() { Q_D(QmlProfilerDataModel); - QTC_ASSERT(requestId < d->eventTypes.count(), return); - - QmlEventType *event = &d->eventTypes[requestId]; - event->data = newString; + d->detailsRewriter->reloadDocuments(); } -void QmlProfilerDataModel::detailsDone() +void QmlProfilerDataModel::detailsChanged(int requestId, const QString &newString) { Q_D(QmlProfilerDataModel); - d->modelManager->processingDone(); + QTC_ASSERT(requestId < d->eventTypes.count(), return); + d->eventTypes[requestId].data = newString; } } // namespace QmlProfiler diff --git a/src/plugins/qmlprofiler/qmlprofilerdatamodel.h b/src/plugins/qmlprofiler/qmlprofilerdatamodel.h index 6f7bce387f..5ab239b909 100644 --- a/src/plugins/qmlprofiler/qmlprofilerdatamodel.h +++ b/src/plugins/qmlprofiler/qmlprofilerdatamodel.h @@ -49,22 +49,21 @@ public: const QVector<QmlEventType> &eventTypes() const; void setData(qint64 traceStart, qint64 traceEnd, const QVector<QmlEventType> &types, const QVector<QmlEvent> &events); - void processData(); int count() const; void clear(); bool isEmpty() const; - void addEvent(Message message, RangeType rangeType, int bindingType, qint64 startTime, - qint64 duration, const QString &data, const QmlEventLocation &location, - qint64 ndata1, qint64 ndata2, qint64 ndata3, qint64 ndata4, qint64 ndata5); + void addEvent(const QmlEvent &event, const QmlEventType &type); + void replayEvents(qint64 startTime, qint64 endTime, + QmlProfilerModelManager::EventLoader loader) const; + void finalize(); qint64 lastTimeMark() const; signals: - void requestReload(); + void allTypesLoaded(); protected slots: void detailsChanged(int requestId, const QString &newString); - void detailsDone(); private: class QmlProfilerDataModelPrivate; diff --git a/src/plugins/qmlprofiler/qmlprofilereventsview.h b/src/plugins/qmlprofiler/qmlprofilereventsview.h index 9406c8e971..e48f64ab95 100644 --- a/src/plugins/qmlprofiler/qmlprofilereventsview.h +++ b/src/plugins/qmlprofiler/qmlprofilereventsview.h @@ -38,10 +38,7 @@ class QMLPROFILER_EXPORT QmlProfilerEventsView : public QWidget Q_OBJECT public: QmlProfilerEventsView(QWidget *parent = 0) : QWidget(parent) {} - - virtual void clear() = 0; - virtual void restrictToRange(qint64 rangeStart, qint64 rangeEnd) = 0; - virtual bool isRestrictedToRange() const = 0; + virtual void clear() {} signals: void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber); diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp index e3832d226b..f4b39c63b8 100644 --- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp @@ -37,6 +37,8 @@ #include <QFile> #include <QMessageBox> +#include <functional> + namespace QmlProfiler { namespace Internal { @@ -59,22 +61,19 @@ Q_STATIC_ASSERT(sizeof(ProfileFeatureNames) == sizeof(char *) * MaximumProfileFe ///////////////////////////////////////////////////////////////////// QmlProfilerTraceTime::QmlProfilerTraceTime(QObject *parent) : - QObject(parent), m_startTime(-1), m_endTime(-1) -{ -} - -QmlProfilerTraceTime::~QmlProfilerTraceTime() + QObject(parent), m_startTime(-1), m_endTime(-1), + m_restrictedStartTime(-1), m_restrictedEndTime(-1) { } qint64 QmlProfilerTraceTime::startTime() const { - return m_startTime; + return m_restrictedStartTime != -1 ? m_restrictedStartTime : m_startTime; } qint64 QmlProfilerTraceTime::endTime() const { - return m_endTime; + return m_restrictedEndTime != -1 ? m_restrictedEndTime : m_endTime; } qint64 QmlProfilerTraceTime::duration() const @@ -82,18 +81,22 @@ qint64 QmlProfilerTraceTime::duration() const return endTime() - startTime(); } +bool QmlProfilerTraceTime::isRestrictedToRange() const +{ + return m_restrictedStartTime != -1 || m_restrictedEndTime != -1; +} + void QmlProfilerTraceTime::clear() { + restrictToRange(-1, -1); setTime(-1, -1); } void QmlProfilerTraceTime::setTime(qint64 startTime, qint64 endTime) { - Q_ASSERT(startTime <= endTime); - if (startTime != m_startTime || endTime != m_endTime) { - m_startTime = startTime; - m_endTime = endTime; - } + QTC_ASSERT(startTime <= endTime, endTime = startTime); + m_startTime = startTime; + m_endTime = endTime; } void QmlProfilerTraceTime::decreaseStartTime(qint64 time) @@ -118,6 +121,13 @@ void QmlProfilerTraceTime::increaseEndTime(qint64 time) } } +void QmlProfilerTraceTime::restrictToRange(qint64 startTime, qint64 endTime) +{ + QTC_ASSERT(endTime == -1 || startTime <= endTime, endTime = startTime); + m_restrictedStartTime = startTime; + m_restrictedEndTime = endTime; +} + } // namespace Internal @@ -153,6 +163,8 @@ QmlProfilerModelManager::QmlProfilerModelManager(Utils::FileInProjectFinder *fin d->state = Empty; d->traceTime = new QmlProfilerTraceTime(this); d->notesModel = new QmlProfilerNotesModel(this); + connect(d->model, &QmlProfilerDataModel::allTypesLoaded, + this, &QmlProfilerModelManager::processingDone); } QmlProfilerModelManager::~QmlProfilerModelManager() @@ -247,34 +259,17 @@ const char *QmlProfilerModelManager::featureName(ProfileFeature feature) return ProfileFeatureNames[feature]; } -void QmlProfilerModelManager::addQmlEvent(Message message, RangeType rangeType, int detailType, - qint64 startTime, qint64 length, const QString &data, - const QmlEventLocation &location, qint64 ndata1, - qint64 ndata2, qint64 ndata3, qint64 ndata4, - qint64 ndata5) -{ - // If trace start time was not explicitly set, use the first event - if (d->traceTime->startTime() == -1) - d->traceTime->setTime(startTime, startTime + d->traceTime->duration()); - - QTC_ASSERT(state() == AcquiringData, /**/); - d->model->addEvent(message, rangeType, detailType, startTime, length, data, location, ndata1, - ndata2, ndata3, ndata4, ndata5); -} - -void QmlProfilerModelManager::addDebugMessage(qint64 timestamp, QtMsgType messageType, - const QString &text, const QmlEventLocation &location) +void QmlProfilerModelManager::addQmlEvent(const QmlEvent &event, const QmlEventType &type) { - if (state() == AcquiringData) - d->model->addEvent(DebugMessage, MaximumRangeType, messageType, timestamp, 0, text, - location, 0, 0, 0, 0, 0); + QTC_ASSERT(state() == AcquiringData, return); + d->model->addEvent(event, type); } void QmlProfilerModelManager::acquiringDone() { QTC_ASSERT(state() == AcquiringData, /**/); setState(ProcessingData); - d->model->processData(); + d->model->finalize(); } void QmlProfilerModelManager::processingDone() @@ -282,8 +277,13 @@ void QmlProfilerModelManager::processingDone() QTC_ASSERT(state() == ProcessingData, /**/); // Load notes after the timeline models have been initialized ... // which happens on stateChanged(Done). - setState(Done); + + foreach (const Finalizer &finalizer, d->finalizers) + finalizer(); + d->notesModel->loadData(); + setState(Done); + emit loadFinished(); } @@ -408,6 +408,26 @@ void QmlProfilerModelManager::clear() setState(Empty); } +void QmlProfilerModelManager::restrictToRange(qint64 startTime, qint64 endTime) +{ + setState(ClearingData); + d->notesModel->saveData(); + setVisibleFeatures(0); + + startAcquiring(); + d->model->replayEvents(startTime, endTime, + std::bind(&QmlProfilerModelManager::dispatch, this, + std::placeholders::_1, std::placeholders::_2)); + d->notesModel->loadData(); + d->traceTime->restrictToRange(startTime, endTime); + acquiringDone(); +} + +bool QmlProfilerModelManager::isRestrictedToRange() const +{ + return d->traceTime->isRestrictedToRange(); +} + void QmlProfilerModelManager::startAcquiring() { setState(AcquiringData); diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.h b/src/plugins/qmlprofiler/qmlprofilermodelmanager.h index 92e5f7872c..c796bd65a5 100644 --- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.h +++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.h @@ -48,11 +48,11 @@ class QMLPROFILER_EXPORT QmlProfilerTraceTime : public QObject Q_OBJECT public: explicit QmlProfilerTraceTime(QObject *parent); - ~QmlProfilerTraceTime(); qint64 startTime() const; qint64 endTime() const; qint64 duration() const; + bool isRestrictedToRange() const; public slots: void clear(); @@ -60,10 +60,14 @@ public slots: void setTime(qint64 startTime, qint64 endTime); void decreaseStartTime(qint64 time); void increaseEndTime(qint64 time); + void restrictToRange(qint64 startTime, qint64 endTime); private: qint64 m_startTime; qint64 m_endTime; + + qint64 m_restrictedStartTime; + qint64 m_restrictedEndTime; }; } // End internal namespace @@ -124,13 +128,11 @@ signals: public slots: void clear(); + void restrictToRange(qint64 startTime, qint64 endTime); + bool isRestrictedToRange() const; void startAcquiring(); - void addQmlEvent(Message message, RangeType rangeType, int bindingType, qint64 startTime, - qint64 length, const QString &data, const QmlEventLocation &location, - qint64 ndata1, qint64 ndata2, qint64 ndata3, qint64 ndata4, qint64 ndata5); - void addDebugMessage(qint64 timestamp, QtMsgType type, const QString &text, - const QmlEventLocation &location); + void addQmlEvent(const QmlEvent &event, const QmlEventType &type); void save(const QString &filename); void load(const QString &filename); diff --git a/src/plugins/qmlprofiler/qmlprofilerrangemodel.cpp b/src/plugins/qmlprofiler/qmlprofilerrangemodel.cpp index 2119e94b7f..4c174dbc74 100644 --- a/src/plugins/qmlprofiler/qmlprofilerrangemodel.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerrangemodel.cpp @@ -54,6 +54,7 @@ void QmlProfilerRangeModel::clear() m_expandedRowTypes.clear(); m_expandedRowTypes << -1; m_data.clear(); + m_stack.clear(); QmlProfilerTimelineModel::clear(); } @@ -66,8 +67,14 @@ void QmlProfilerRangeModel::loadEvent(const QmlEvent &event, const QmlEventType { Q_UNUSED(type); // store starttime-based instance - m_data.insert(insert(event.timestamp(), event.duration(), event.typeIndex()), - QmlRangeEventStartInstance()); + if (event.rangeStage() == RangeStart) { + int index = insertStart(event.timestamp(), event.typeIndex()); + m_stack.append(index); + m_data.insert(index, QmlRangeEventStartInstance()); + } else if (event.rangeStage() == RangeEnd) { + int index = m_stack.pop(); + insertEnd(index, event.timestamp() - startTime(index)); + } } void QmlProfilerRangeModel::finalize() diff --git a/src/plugins/qmlprofiler/qmlprofilerrangemodel.h b/src/plugins/qmlprofiler/qmlprofilerrangemodel.h index 3b2af9dba8..553bdb89c7 100644 --- a/src/plugins/qmlprofiler/qmlprofilerrangemodel.h +++ b/src/plugins/qmlprofiler/qmlprofilerrangemodel.h @@ -33,6 +33,7 @@ #include <QVariantList> #include <QColor> +#include <QStack> namespace QmlProfiler { class QmlProfilerModelManager; @@ -85,6 +86,7 @@ private: void findBindingLoops(); QVector<QmlRangeEventStartInstance> m_data; + QStack<int> m_stack; QVector<int> m_expandedRowTypes; }; diff --git a/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp b/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp index ae4d59961c..6833e20548 100644 --- a/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp @@ -37,12 +37,17 @@ #include <QSet> #include <QPointer> +#include <functional> + namespace QmlProfiler { class QmlProfilerStatisticsModel::QmlProfilerStatisticsModelPrivate { public: QHash<int, QmlProfilerStatisticsModel::QmlEventStats> data; + QHash<int, QmlProfilerStatisticsModel::QmlEventStats> workingSet; + + QPointer<QmlProfilerStatisticsRelativesModel> childrenModel; QPointer<QmlProfilerStatisticsRelativesModel> parentsModel; @@ -87,12 +92,34 @@ QmlProfilerStatisticsModel::~QmlProfilerStatisticsModel() delete d; } -void QmlProfilerStatisticsModel::setEventTypeAccepted(RangeType type, bool accepted) +void QmlProfilerStatisticsModel::restrictToFeatures(qint64 features) { - if (accepted && !d->acceptedTypes.contains(type)) - d->acceptedTypes << type; - else if (!accepted && d->acceptedTypes.contains(type)) - d->acceptedTypes.removeOne(type); + bool didChange = false; + for (int i = 0; i < MaximumRangeType; ++i) { + RangeType type = static_cast<RangeType>(i); + quint64 featureFlag = 1ULL << featureFromRangeType(type); + if (Constants::QML_JS_RANGE_FEATURES & featureFlag) { + bool accepted = features & featureFlag; + if (accepted && !d->acceptedTypes.contains(type)) { + d->acceptedTypes << type; + didChange = true; + } else if (!accepted && d->acceptedTypes.contains(type)) { + d->acceptedTypes.removeOne(type); + didChange = true; + } + } + } + if (!didChange || d->modelManager->state() != QmlProfilerModelManager::Done) + return; + + clear(); + d->modelManager->qmlModel()->replayEvents(d->modelManager->traceTime()->startTime(), + d->modelManager->traceTime()->endTime(), + std::bind(&QmlProfilerStatisticsModel::loadEvent, + this, std::placeholders::_1, + std::placeholders::_2)); + finalize(); + notesChanged(-1); // Reload notes } const QHash<int, QmlProfilerStatisticsModel::QmlEventStats> &QmlProfilerStatisticsModel::getData() const @@ -126,12 +153,6 @@ void QmlProfilerStatisticsModel::clear() d->parentsModel->clear(); } -void QmlProfilerStatisticsModel::limitToRange(qint64 rangeStart, qint64 rangeEnd) -{ - if (!d->modelManager->isEmpty()) - loadData(rangeStart, rangeEnd); -} - void QmlProfilerStatisticsModel::setRelativesModel(QmlProfilerStatisticsRelativesModel *relative, QmlProfilerStatisticsRelation relation) { @@ -141,11 +162,14 @@ void QmlProfilerStatisticsModel::setRelativesModel(QmlProfilerStatisticsRelative d->childrenModel = relative; } +QmlProfilerModelManager *QmlProfilerStatisticsModel::modelManager() const +{ + return d->modelManager; +} + void QmlProfilerStatisticsModel::dataChanged() { - if (d->modelManager->state() == QmlProfilerModelManager::ProcessingData) - loadData(); - else if (d->modelManager->state() == QmlProfilerModelManager::ClearingData) + if (d->modelManager->state() == QmlProfilerModelManager::ClearingData) clear(); } @@ -181,80 +205,53 @@ void QmlProfilerStatisticsModel::notesChanged(int typeIndex) emit notesAvailable(typeIndex); } -void QmlProfilerStatisticsModel::loadData(qint64 rangeStart, qint64 rangeEnd) -{ - clear(); - - const bool checkRanges = (rangeStart != -1) && (rangeEnd != -1); - - const QVector<QmlEvent> &eventList = d->modelManager->qmlModel()->events(); - const QVector<QmlEventType> &typesList = d->modelManager->qmlModel()->eventTypes(); - - for (int i = 0; i < eventList.size(); ++i) { - const QmlEvent &event = eventList[i]; - const QmlEventType &type = typesList[event.typeIndex()]; - - if (checkRanges) { - if ((event.timestamp() + event.duration() < rangeStart) - || (event.timestamp() > rangeEnd)) - continue; - } - - loadEvent(event, type); - } - - finalize(); - if (checkRanges) - notesChanged(-1); // Reload notes -} - void QmlProfilerStatisticsModel::loadEvent(const QmlEvent &event, const QmlEventType &type) { if (!d->acceptedTypes.contains(type.rangeType)) return; - // update stats - QmlEventStats *stats = &d->data[event.typeIndex()]; - - stats->duration += event.duration(); - stats->durationSelf += event.duration(); - if (event.duration() < stats->minTime) - stats->minTime = event.duration(); - if (event.duration() > stats->maxTime) - stats->maxTime = event.duration(); - stats->calls++; + switch (event.rangeStage()) { + case RangeStart: + // binding loop detection: check whether event is already in stack + for (int ii = 1; ii < d->callStack.size(); ++ii) { + if (d->callStack.at(ii).typeIndex() == event.typeIndex() + && type.rangeType != Javascript) { + d->eventsInBindingLoop.insert(event.typeIndex()); + break; + } + } + d->callStack.push(event); + break; + case RangeEnd: { + // update stats + QmlEventStats *stats = &d->data[event.typeIndex()]; + qint64 duration = event.timestamp() - d->callStack.top().timestamp(); + stats->duration += duration; + stats->durationSelf += duration; + if (duration < stats->minTime) + stats->minTime = duration; + if (duration > stats->maxTime) + stats->maxTime = duration; + stats->calls++; + // for median computing + d->durations[event.typeIndex()].append(duration); + // qml time computation + if (event.timestamp() > d->lastEndTime) { // assume parent event if starts before last end + d->qmlTime += duration; + d->lastEndTime = event.timestamp(); + } - // for median computing - d->durations[event.typeIndex()].append(event.duration()); + d->callStack.pop(); - // qml time computation - if (event.timestamp() > d->lastEndTime) { // assume parent event if starts before last end - d->qmlTime += event.duration(); - d->lastEndTime = event.timestamp() + event.duration(); - } + if (d->callStack.count() > 1) + d->data[d->callStack.top().typeIndex()].durationSelf -= duration; - // - // binding loop detection - // - const QmlEvent *potentialParent = &(d->callStack.top()); - while (potentialParent->isValid() && - !(potentialParent->timestamp() + potentialParent->duration() > event.timestamp())) { - d->callStack.pop(); - potentialParent = &(d->callStack.top()); + break; } - - // check whether event is already in stack - for (int ii = 1; ii < d->callStack.size(); ++ii) { - if (d->callStack.at(ii).typeIndex() == event.typeIndex()) { - d->eventsInBindingLoop.insert(event.typeIndex()); - break; - } + default: + break; } - if (d->callStack.count() > 1) - d->data[d->callStack.top().typeIndex()].durationSelf -= event.duration(); - d->callStack.push(event); - if (!d->childrenModel.isNull()) d->childrenModel->loadEvent(event); if (!d->parentsModel.isNull()) @@ -294,6 +291,7 @@ void QmlProfilerStatisticsModel::finalize() rootEvent.percentSelf = 1.0 / rootEvent.duration; d->data.insert(-1, rootEvent); + if (!d->childrenModel.isNull()) d->childrenModel->finalize(d->eventsInBindingLoop); if (!d->parentsModel.isNull()) @@ -312,7 +310,7 @@ QmlProfilerStatisticsRelativesModel::QmlProfilerStatisticsRelativesModel( QmlProfilerStatisticsRelation relation, QObject *parent) : QObject(parent), m_relation(relation) { - m_endtimesPerLevel[0] = 0; + m_startTimesPerLevel[0] = 0; QTC_CHECK(modelManager); m_modelManager = modelManager; @@ -346,40 +344,42 @@ const QVector<QmlEventType> &QmlProfilerStatisticsRelativesModel::getTypes() con void QmlProfilerStatisticsRelativesModel::loadEvent(const QmlEvent &event) { // level computation - if (m_endtimesPerLevel[m_level] > event.timestamp()) { - m_level++; - } else { - while (m_level > Constants::QML_MIN_LEVEL && - m_endtimesPerLevel[m_level-1] <= event.timestamp()) - m_level--; + switch (event.rangeStage()) { + case RangeStart: + // now lastparent is the new type + ++m_level; + m_typesPerLevel[m_level] = event.typeIndex(); + m_startTimesPerLevel[m_level] = event.timestamp(); + break; + case RangeEnd: { + int parentTypeIndex = -1; + if (m_level > Constants::QML_MIN_LEVEL && m_typesPerLevel.contains(m_level-1)) + parentTypeIndex = m_typesPerLevel[m_level-1]; + + int relativeTypeIndex = (m_relation == QmlProfilerStatisticsParents) ? parentTypeIndex : + event.typeIndex(); + int selfTypeIndex = (m_relation == QmlProfilerStatisticsParents) ? event.typeIndex() : + parentTypeIndex; + + QmlStatisticsRelativesMap &relativesMap = m_data[selfTypeIndex]; + QmlStatisticsRelativesMap::Iterator it = relativesMap.find(relativeTypeIndex); + if (it != relativesMap.end()) { + it.value().calls++; + it.value().duration += event.timestamp() - m_startTimesPerLevel[m_level]; + } else { + QmlStatisticsRelativesData relative = { + event.timestamp() - m_startTimesPerLevel[m_level], + 1, + false + }; + relativesMap.insert(relativeTypeIndex, relative); + } + --m_level; + break; } - m_endtimesPerLevel[m_level] = event.timestamp() + event.duration(); - - int parentTypeIndex = -1; - if (m_level > Constants::QML_MIN_LEVEL && m_lastParent.contains(m_level-1)) - parentTypeIndex = m_lastParent[m_level-1]; - - int relativeTypeIndex = (m_relation == QmlProfilerStatisticsParents) ? parentTypeIndex : - event.typeIndex(); - int selfTypeIndex = (m_relation == QmlProfilerStatisticsParents) ? event.typeIndex() : - parentTypeIndex; - - QmlStatisticsRelativesMap &relativesMap = m_data[selfTypeIndex]; - QmlStatisticsRelativesMap::Iterator it = relativesMap.find(relativeTypeIndex); - if (it != relativesMap.end()) { - it.value().calls++; - it.value().duration += event.duration(); - } else { - QmlStatisticsRelativesData relative = { - event.duration(), - 1, - false - }; - relativesMap.insert(relativeTypeIndex, relative); + default: + break; } - - // now lastparent is the new type - m_lastParent[m_level] = event.typeIndex(); } void QmlProfilerStatisticsRelativesModel::finalize(const QSet<int> &eventsInBindingLoop) @@ -402,10 +402,10 @@ int QmlProfilerStatisticsRelativesModel::count() const void QmlProfilerStatisticsRelativesModel::clear() { m_data.clear(); - m_endtimesPerLevel.clear(); + m_startTimesPerLevel.clear(); m_level = Constants::QML_MIN_LEVEL; - m_endtimesPerLevel[0] = 0; - m_lastParent.clear(); + m_startTimesPerLevel[0] = 0; + m_typesPerLevel.clear(); } } // namespace QmlProfiler diff --git a/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.h b/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.h index 6c28116ad1..6cc357fe68 100644 --- a/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.h +++ b/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.h @@ -68,7 +68,7 @@ public: QmlProfilerStatisticsModel(QmlProfilerModelManager *modelManager, QObject *parent = 0); ~QmlProfilerStatisticsModel(); - void setEventTypeAccepted(RangeType type, bool accepted); + void restrictToFeatures(qint64 features); const QHash<int, QmlEventStats> &getData() const; const QVector<QmlEventType> &getTypes() const; @@ -77,16 +77,15 @@ public: int count() const; void clear(); - void limitToRange(qint64 rangeStart, qint64 rangeEnd); void setRelativesModel(QmlProfilerStatisticsRelativesModel *childModel, QmlProfilerStatisticsRelation relation); + QmlProfilerModelManager *modelManager() const; signals: void dataAvailable(); void notesAvailable(int typeIndex); private: - void loadData(qint64 rangeStart = -1, qint64 rangeEnd = -1); void loadEvent(const QmlEvent &event, const QmlEventType &type); void finalize(); @@ -133,11 +132,11 @@ protected: QmlProfilerModelManager *m_modelManager; // for level computation - QHash<int, qint64> m_endtimesPerLevel; + QHash<int, qint64> m_startTimesPerLevel; int m_level = Constants::QML_MIN_LEVEL; // compute parent-child relationship and call count - QHash<int, int> m_lastParent; + QHash<int, int> m_typesPerLevel; const QmlProfilerStatisticsRelation m_relation; }; diff --git a/src/plugins/qmlprofiler/qmlprofilerstatisticsview.cpp b/src/plugins/qmlprofiler/qmlprofilerstatisticsview.cpp index 579cafc0c3..3bc34f471c 100644 --- a/src/plugins/qmlprofiler/qmlprofilerstatisticsview.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerstatisticsview.cpp @@ -110,8 +110,6 @@ public: QmlProfilerStatisticsRelativesView *m_eventParents; QmlProfilerStatisticsModel *model; - qint64 rangeStart; - qint64 rangeEnd; }; static void setViewDefaults(Utils::TreeView *view) @@ -228,8 +226,6 @@ QmlProfilerStatisticsView::QmlProfilerStatisticsView(QWidget *parent, splitterVertical->setStretchFactor(1,2); groupLayout->addWidget(splitterVertical); setLayout(groupLayout); - - d->rangeStart = d->rangeEnd = -1; } QmlProfilerStatisticsView::~QmlProfilerStatisticsView() @@ -243,14 +239,6 @@ void QmlProfilerStatisticsView::clear() d->m_eventTree->clear(); d->m_eventChildren->clear(); d->m_eventParents->clear(); - d->rangeStart = d->rangeEnd = -1; -} - -void QmlProfilerStatisticsView::restrictToRange(qint64 rangeStart, qint64 rangeEnd) -{ - d->rangeStart = rangeStart; - d->rangeEnd = rangeEnd; - d->model->limitToRange(rangeStart, rangeEnd); } QModelIndex QmlProfilerStatisticsView::selectedModelIndex() const @@ -285,7 +273,7 @@ void QmlProfilerStatisticsView::contextMenuEvent(QContextMenuEvent *ev) menu.addSeparator(); getGlobalStatsAction = menu.addAction(tr("Show Full Range")); - if (!isRestrictedToRange()) + if (!d->model->modelManager()->isRestrictedToRange()) getGlobalStatsAction->setEnabled(false); QAction *selectedAction = menu.exec(position); @@ -327,18 +315,7 @@ void QmlProfilerStatisticsView::selectByTypeId(int typeIndex) void QmlProfilerStatisticsView::onVisibleFeaturesChanged(quint64 features) { - for (int i = 0; i < MaximumRangeType; ++i) { - RangeType range = static_cast<RangeType>(i); - quint64 featureFlag = 1ULL << featureFromRangeType(range); - if (Constants::QML_JS_RANGE_FEATURES & featureFlag) - d->model->setEventTypeAccepted(range, features & featureFlag); - } - d->model->limitToRange(d->rangeStart, d->rangeEnd); -} - -bool QmlProfilerStatisticsView::isRestrictedToRange() const -{ - return d->rangeStart != -1 || d->rangeEnd != -1; + d->model->restrictToFeatures(features); } void QmlProfilerStatisticsView::setShowExtendedStatistics(bool show) diff --git a/src/plugins/qmlprofiler/qmlprofilerstatisticsview.h b/src/plugins/qmlprofiler/qmlprofilerstatisticsview.h index 0bde5adbec..9b5a693b8c 100644 --- a/src/plugins/qmlprofiler/qmlprofilerstatisticsview.h +++ b/src/plugins/qmlprofiler/qmlprofilerstatisticsview.h @@ -78,10 +78,7 @@ public: explicit QmlProfilerStatisticsView(QWidget *parent, QmlProfilerModelManager *profilerModelManager); ~QmlProfilerStatisticsView(); - void clear() override; - void restrictToRange(qint64 rangeStart, qint64 rangeEnd) override; - bool isRestrictedToRange() const override; public slots: void selectByTypeId(int typeIndex) override; diff --git a/src/plugins/qmlprofiler/qmlprofilertimelinemodel.cpp b/src/plugins/qmlprofiler/qmlprofilertimelinemodel.cpp index 31d3c81ba0..2500f1ac4b 100644 --- a/src/plugins/qmlprofiler/qmlprofilertimelinemodel.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertimelinemodel.cpp @@ -95,7 +95,6 @@ void QmlProfilerTimelineModel::dataChanged() switch (m_modelManager->state()) { case QmlProfilerModelManager::Done: - loadData(); emit emptyChanged(); break; case QmlProfilerModelManager::ClearingData: @@ -139,21 +138,4 @@ QVariantMap QmlProfilerTimelineModel::locationFromTypeId(int index) const return result; } -void QmlProfilerTimelineModel::loadData() -{ - QmlProfilerDataModel *simpleModel = modelManager()->qmlModel(); - if (simpleModel->isEmpty()) - return; - - const QVector<QmlEventType> &types = simpleModel->eventTypes(); - - foreach (const QmlEvent &event, simpleModel->events()) { - const QmlEventType &type = types[event.typeIndex()]; - if (accepted(type)) { - loadEvent(event, type); - } - } - finalize(); -} - } // namespace QmlProfiler diff --git a/src/plugins/qmlprofiler/qmlprofilertimelinemodel.h b/src/plugins/qmlprofiler/qmlprofilertimelinemodel.h index fa9255efee..c5097e8629 100644 --- a/src/plugins/qmlprofiler/qmlprofilertimelinemodel.h +++ b/src/plugins/qmlprofiler/qmlprofilertimelinemodel.h @@ -53,8 +53,6 @@ public: Q_INVOKABLE virtual int bindingLoopDest(int index) const; QVariantMap locationFromTypeId(int index) const; - void loadData(); - virtual void loadEvent(const QmlEvent &event, const QmlEventType &type) = 0; virtual void finalize() = 0; void clear(); diff --git a/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp b/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp index ce3b82c578..ab2eb291f6 100644 --- a/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertraceclient.cpp @@ -24,6 +24,8 @@ ****************************************************************************/ #include "qmlprofilertraceclient.h" +#include "qmltypedevent.h" + #include <qmldebug/qmlenginecontrolclient.h> #include <qmldebug/qdebugmessageclient.h> #include <qmldebug/qpacketprotocol.h> @@ -35,14 +37,12 @@ public: QmlProfilerTraceClientPrivate(QmlProfilerTraceClient *_q, QmlDebug::QmlDebugConnection *client) : q(_q) , engineControl(client) - , inProgressRanges(0) , maximumTime(0) , recording(false) , requestedFeatures(0) , recordedFeatures(0) , flushInterval(0) { - ::memset(rangeCount, 0, MaximumRangeType * sizeof(int)); } void sendRecordingStatus(int engineId); @@ -51,17 +51,14 @@ public: QmlProfilerTraceClient *q; QmlDebug::QmlEngineControlClient engineControl; QScopedPointer<QmlDebug::QDebugMessageClient> messageClient; - qint64 inProgressRanges; - QStack<qint64> rangeStartTimes[MaximumRangeType]; - QStack<QString> rangeDatas[MaximumRangeType]; - QStack<QmlEventLocation> rangeLocations[MaximumRangeType]; - QStack<BindingType> bindingTypes; - int rangeCount[MaximumRangeType]; qint64 maximumTime; bool recording; quint64 requestedFeatures; quint64 recordedFeatures; quint32 flushInterval; + + // Reuse the same event, so that we don't have to constantly reallocate all the data. + QmlTypedEvent currentEvent; }; void QmlProfilerTraceClientPrivate::sendRecordingStatus(int engineId) @@ -94,13 +91,6 @@ QmlProfilerTraceClient::~QmlProfilerTraceClient() void QmlProfilerTraceClient::clearData() { - ::memset(d->rangeCount, 0, MaximumRangeType * sizeof(int)); - for (int eventType = 0; eventType < MaximumRangeType; eventType++) { - d->rangeDatas[eventType].clear(); - d->rangeLocations[eventType].clear(); - d->rangeStartTimes[eventType].clear(); - } - d->bindingTypes.clear(); if (d->recordedFeatures != 0) { d->recordedFeatures = 0; emit recordedFeaturesChanged(0); @@ -146,8 +136,18 @@ void QmlProfilerTraceClient::setRequestedFeatures(quint64 features) const QmlDebug::QDebugContextInfo &context) { d->updateFeatures(ProfileDebugMessages); - emit debugMessage(context.timestamp, type, text, - QmlEventLocation(context.file, context.line, 1)); + d->currentEvent.event.setTimestamp(context.timestamp); + d->currentEvent.event.setTypeIndex(-1); + d->currentEvent.event.setString(text); + d->currentEvent.type.location.filename = context.file; + d->currentEvent.type.location.line = context.line; + d->currentEvent.type.location.column = 1; + d->currentEvent.type.displayName.clear(); + d->currentEvent.type.data.clear(); + d->currentEvent.type.message = DebugMessage; + d->currentEvent.type.rangeType = MaximumRangeType; + d->currentEvent.type.detailType = type; + emit qmlEvent(d->currentEvent.event, d->currentEvent.type); }); } else { d->messageClient.reset(); @@ -189,210 +189,24 @@ void QmlProfilerTraceClient::messageReceived(const QByteArray &data) { QmlDebug::QPacket stream(connection()->currentDataStreamVersion(), data); - qint64 time; - int messageType; - int subtype; - - stream >> time >> messageType; - if (!stream.atEnd()) - stream >> subtype; - else - subtype = -1; - - switch (messageType) { - case Event: { - switch (subtype) { - case StartTrace: { - if (!d->recording) - setRecordingFromServer(true); - QList<int> engineIds; - while (!stream.atEnd()) { - int id; - stream >> id; - engineIds << id; - } - emit traceStarted(time, engineIds); - d->maximumTime = time; - break; - } - case EndTrace: { - QList<int> engineIds; - while (!stream.atEnd()) { - int id; - stream >> id; - engineIds << id; - } - emit traceFinished(time, engineIds); - d->maximumTime = time; - d->maximumTime = qMax(time, d->maximumTime); - break; - } - case AnimationFrame: { - if (!d->updateFeatures(ProfileAnimations)) - break; - int frameRate, animationCount; - int threadId; - stream >> frameRate >> animationCount; - if (!stream.atEnd()) - stream >> threadId; - else - threadId = 0; - - emit rangedEvent(Event, MaximumRangeType, AnimationFrame, time, 0, QString(), - QmlEventLocation(), frameRate, animationCount, threadId, - 0, 0); - d->maximumTime = qMax(time, d->maximumTime); - break; - } - case Key: - case Mouse: - if (!d->updateFeatures(ProfileInputEvents)) - break; - int inputType = (subtype == Key ? InputKeyUnknown : InputMouseUnknown); - if (!stream.atEnd()) - stream >> inputType; - int a = -1; - if (!stream.atEnd()) - stream >> a; - int b = -1; - if (!stream.atEnd()) - stream >> b; + stream >> d->currentEvent; - emit rangedEvent(Event, MaximumRangeType, subtype, time, 0, QString(), - QmlEventLocation(), inputType, a, b, 0, 0); - d->maximumTime = qMax(time, d->maximumTime); - break; - } - - break; - } - case Complete: + d->maximumTime = qMax(d->currentEvent.event.timestamp(), d->maximumTime); + if (d->currentEvent.type.message == Complete) { emit complete(d->maximumTime); setRecordingFromServer(false); - break; - case SceneGraphFrame: { - if (!d->updateFeatures(ProfileSceneGraph)) - break; - - int count = 0; - qint64 params[5]; - - while (!stream.atEnd()) { - stream >> params[count++]; - } - while (count<5) - params[count++] = 0; - emit rangedEvent(SceneGraphFrame, MaximumRangeType, subtype,time, 0, - QString(), QmlEventLocation(), params[0], params[1], - params[2], params[3], params[4]); - break; - } - case PixmapCacheEvent: { - if (!d->updateFeatures(ProfilePixmapCache)) - break; - int width = 0, height = 0, refcount = 0; - QString pixUrl; - stream >> pixUrl; - if (subtype == (int)PixmapReferenceCountChanged || subtype == (int)PixmapCacheCountChanged) { - stream >> refcount; - } else if (subtype == (int)PixmapSizeKnown) { - stream >> width >> height; - refcount = 1; - } - emit rangedEvent(PixmapCacheEvent, MaximumRangeType, subtype, time, 0, - QString(), QmlEventLocation(pixUrl,0,0), width, height, - refcount, 0, 0); - d->maximumTime = qMax(time, d->maximumTime); - break; - } - case MemoryAllocation: { - if (!d->updateFeatures(ProfileMemory)) - break; - - qint64 delta; - stream >> delta; - emit rangedEvent(MemoryAllocation, MaximumRangeType, subtype, time, 0, - QString(), QmlEventLocation(), delta, 0, 0, 0, 0); - d->maximumTime = qMax(time, d->maximumTime); - break; - } - case RangeStart: { - if (!d->updateFeatures(featureFromRangeType(static_cast<RangeType>(subtype)))) - break; - d->rangeStartTimes[subtype].push(time); - d->inProgressRanges |= (static_cast<qint64>(1) << subtype); - ++d->rangeCount[subtype]; - - // read binding type - if ((RangeType)subtype == Binding) { - int bindingType = (int)QmlBinding; - if (!stream.atEnd()) - stream >> bindingType; - d->bindingTypes.push((BindingType)bindingType); - } - break; - } - case RangeData: { - if (!d->updateFeatures(featureFromRangeType(static_cast<RangeType>(subtype)))) - break; - QString data; - stream >> data; - - int count = d->rangeCount[subtype]; - if (count > 0) { - while (d->rangeDatas[subtype].count() < count) - d->rangeDatas[subtype].push(QString()); - d->rangeDatas[subtype][count-1] = data; - } - break; - } - case RangeLocation: { - if (!d->updateFeatures(featureFromRangeType(static_cast<RangeType>(subtype)))) - break; - QString fileName; - int line; - int column = -1; - stream >> fileName >> line; - - if (!stream.atEnd()) - stream >> column; - - if (d->rangeCount[subtype] > 0) - d->rangeLocations[subtype].push(QmlEventLocation(fileName, line, column)); - break; - } - case RangeEnd: { - if (!d->updateFeatures(featureFromRangeType(static_cast<RangeType>(subtype)))) - break; - if (d->rangeCount[subtype] == 0) - break; - --d->rangeCount[subtype]; - if (d->inProgressRanges & (static_cast<qint64>(1) << subtype)) - d->inProgressRanges &= ~(static_cast<qint64>(1) << subtype); - - d->maximumTime = qMax(time, d->maximumTime); - QString data = d->rangeDatas[subtype].count() ? d->rangeDatas[subtype].pop() : QString(); - QmlEventLocation location = d->rangeLocations[subtype].count() ? d->rangeLocations[subtype].pop() : QmlEventLocation(); - - qint64 startTime = d->rangeStartTimes[subtype].pop(); - BindingType bindingType = QmlBinding; - if ((RangeType)subtype == Binding) - bindingType = d->bindingTypes.pop(); - if ((RangeType)subtype == Painting) - bindingType = QPainterEvent; - emit rangedEvent(MaximumMessage, (RangeType)subtype, bindingType, startTime, - time - startTime, data, location, 0, 0, 0, 0, 0); - if (d->rangeCount[subtype] == 0) { - int count = d->rangeDatas[subtype].count() + - d->rangeStartTimes[subtype].count() + - d->rangeLocations[subtype].count(); - if (count != 0) - qWarning() << "incorrectly nested data"; - } - break; - } - default: - break; + } else if (d->currentEvent.type.message == Event + && d->currentEvent.type.detailType == StartTrace) { + if (!d->recording) + setRecordingFromServer(true); + emit traceStarted(d->currentEvent.event.timestamp(), + d->currentEvent.event.numbers<QList<int>, qint32>()); + } else if (d->currentEvent.type.message == Event + && d->currentEvent.type.detailType == EndTrace) { + emit traceFinished(d->currentEvent.event.timestamp(), + d->currentEvent.event.numbers<QList<int>, qint32>()); + } else if (d->updateFeatures(d->currentEvent.type.feature())) { + emit qmlEvent(d->currentEvent.event, d->currentEvent.type); } } diff --git a/src/plugins/qmlprofiler/qmlprofilertraceclient.h b/src/plugins/qmlprofiler/qmlprofilertraceclient.h index c237b1f621..3864a38081 100644 --- a/src/plugins/qmlprofiler/qmlprofilertraceclient.h +++ b/src/plugins/qmlprofiler/qmlprofilertraceclient.h @@ -28,6 +28,7 @@ #include "qmlprofilereventtypes.h" #include "qmleventlocation.h" #include "qmlprofiler_global.h" +#include "qmltypedevent.h" #include <qmldebug/qmldebugclient.h> @@ -60,12 +61,7 @@ signals: void traceFinished(qint64 timestamp, const QList<int> &engineIds); void traceStarted(qint64 timestamp, const QList<int> &engineIds); - void rangedEvent(Message, RangeType, int detailType, qint64 startTime, qint64 length, - const QString &data, const QmlEventLocation &location, qint64 param1, - qint64 param2, qint64 param3, qint64 param4, qint64 param5); - - void debugMessage(qint64 timestamp, QtMsgType type, const QString &text, - const QmlEventLocation &location); + void qmlEvent(const QmlEvent &event, const QmlEventType &type); void recordingChanged(bool arg); void recordedFeaturesChanged(quint64 features); diff --git a/src/plugins/qmlprofiler/qmlprofilertracefile.cpp b/src/plugins/qmlprofiler/qmlprofilertracefile.cpp index ca15d28eb6..e726448303 100644 --- a/src/plugins/qmlprofiler/qmlprofilertracefile.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertracefile.cpp @@ -31,6 +31,7 @@ #include <QStringList> #include <QXmlStreamReader> #include <QXmlStreamWriter> +#include <QStack> #include <QDebug> namespace QmlProfiler { @@ -181,6 +182,9 @@ bool QmlProfilerFileReader::load(QIODevice *device) emit error(tr("Error while parsing trace data file: %1").arg(stream.errorString())); return false; } else { + std::sort(m_events.begin(), m_events.end(), [](const QmlEvent &a, const QmlEvent &b) { + return a.timestamp() < b.timestamp(); + }); emit success(); return true; } @@ -370,46 +374,53 @@ void QmlProfilerFileReader::loadEvents(QXmlStreamReader &stream) } event.setTimestamp(attributes.value(_("startTime")).toLongLong()); - if (attributes.hasAttribute(_("duration"))) - event.setDuration(attributes.value(_("duration")).toLongLong()); - - // attributes for special events - if (attributes.hasAttribute(_("framerate"))) - event.setNumber<qint32>(0, attributes.value(_("framerate")).toInt()); - if (attributes.hasAttribute(_("animationcount"))) - event.setNumber<qint32>(1, attributes.value(_("animationcount")).toInt()); - if (attributes.hasAttribute(_("thread"))) - event.setNumber<qint32>(2, attributes.value(_("thread")).toInt()); - if (attributes.hasAttribute(_("width"))) - event.setNumber<qint32>(0, attributes.value(_("width")).toInt()); - if (attributes.hasAttribute(_("height"))) - event.setNumber<qint32>(1, attributes.value(_("height")).toInt()); - if (attributes.hasAttribute(_("refCount"))) - event.setNumber<qint32>(2, attributes.value(_("refCount")).toInt()); - if (attributes.hasAttribute(_("amount"))) - event.setNumber<qint64>(0, attributes.value(_("amount")).toLongLong()); - if (attributes.hasAttribute(_("timing1"))) - event.setNumber<qint64>(0, attributes.value(_("timing1")).toLongLong()); - if (attributes.hasAttribute(_("timing2"))) - event.setNumber<qint64>(1, attributes.value(_("timing2")).toLongLong()); - if (attributes.hasAttribute(_("timing3"))) - event.setNumber<qint64>(2, attributes.value(_("timing3")).toLongLong()); - if (attributes.hasAttribute(_("timing4"))) - event.setNumber<qint64>(3, attributes.value(_("timing4")).toLongLong()); - if (attributes.hasAttribute(_("timing5"))) - event.setNumber<qint64>(4, attributes.value(_("timing5")).toLongLong()); - if (attributes.hasAttribute(_("type"))) - event.setNumber<qint32>(0, attributes.value(_("type")).toInt()); - if (attributes.hasAttribute(_("data1"))) - event.setNumber<qint32>(1, attributes.value(_("data1")).toInt()); - if (attributes.hasAttribute(_("data2"))) - event.setNumber<qint32>(2, attributes.value(_("data2")).toInt()); - if (attributes.hasAttribute(_("text"))) - event.setString(attributes.value(_("text")).toString()); - event.setTypeIndex(attributes.value(_("eventIndex")).toInt()); - m_events.append(event); + if (attributes.hasAttribute(_("duration"))) { + event.setRangeStage(RangeStart); + m_events.append(event); + QmlEvent rangeEnd(event); + rangeEnd.setRangeStage(RangeEnd); + rangeEnd.setTimestamp(event.timestamp() + + attributes.value(_("duration")).toLongLong()); + m_events.append(rangeEnd); + } else { + // attributes for special events + if (attributes.hasAttribute(_("framerate"))) + event.setNumber<qint32>(0, attributes.value(_("framerate")).toInt()); + if (attributes.hasAttribute(_("animationcount"))) + event.setNumber<qint32>(1, attributes.value(_("animationcount")).toInt()); + if (attributes.hasAttribute(_("thread"))) + event.setNumber<qint32>(2, attributes.value(_("thread")).toInt()); + if (attributes.hasAttribute(_("width"))) + event.setNumber<qint32>(0, attributes.value(_("width")).toInt()); + if (attributes.hasAttribute(_("height"))) + event.setNumber<qint32>(1, attributes.value(_("height")).toInt()); + if (attributes.hasAttribute(_("refCount"))) + event.setNumber<qint32>(2, attributes.value(_("refCount")).toInt()); + if (attributes.hasAttribute(_("amount"))) + event.setNumber<qint64>(0, attributes.value(_("amount")).toLongLong()); + if (attributes.hasAttribute(_("timing1"))) + event.setNumber<qint64>(0, attributes.value(_("timing1")).toLongLong()); + if (attributes.hasAttribute(_("timing2"))) + event.setNumber<qint64>(1, attributes.value(_("timing2")).toLongLong()); + if (attributes.hasAttribute(_("timing3"))) + event.setNumber<qint64>(2, attributes.value(_("timing3")).toLongLong()); + if (attributes.hasAttribute(_("timing4"))) + event.setNumber<qint64>(3, attributes.value(_("timing4")).toLongLong()); + if (attributes.hasAttribute(_("timing5"))) + event.setNumber<qint64>(4, attributes.value(_("timing5")).toLongLong()); + if (attributes.hasAttribute(_("type"))) + event.setNumber<qint32>(0, attributes.value(_("type")).toInt()); + if (attributes.hasAttribute(_("data1"))) + event.setNumber<qint32>(1, attributes.value(_("data1")).toInt()); + if (attributes.hasAttribute(_("data2"))) + event.setNumber<qint32>(2, attributes.value(_("data2")).toInt()); + if (attributes.hasAttribute(_("text"))) + event.setString(attributes.value(_("text")).toString()); + + m_events.append(event); + } } break; } @@ -584,19 +595,29 @@ void QmlProfilerFileWriter::save(QIODevice *device) stream.writeStartElement(_("profilerDataModel")); + QStack<QmlEvent> stack; for (int rangeIndex = 0; rangeIndex < m_events.size(); ++rangeIndex) { if (isCanceled()) return; const QmlEvent &event = m_events[rangeIndex]; + const QmlEventType &type = m_eventTypes[event.typeIndex()]; + if (type.rangeType != MaximumRangeType && event.rangeStage() == RangeStart) { + stack.push(event); + continue; + } stream.writeStartElement(_("range")); - stream.writeAttribute(_("startTime"), QString::number(event.timestamp())); - if (event.duration() > 0) // no need to store duration of instantaneous events - stream.writeAttribute(_("duration"), QString::number(event.duration())); - stream.writeAttribute(_("eventIndex"), QString::number(event.typeIndex())); + if (type.rangeType != MaximumRangeType && event.rangeStage() == RangeEnd) { + QmlEvent start = stack.pop(); + stream.writeAttribute(_("startTime"), QString::number(start.timestamp())); + stream.writeAttribute(_("duration"), + QString::number(event.timestamp() - start.timestamp())); + } else { + stream.writeAttribute(_("startTime"), QString::number(event.timestamp())); + } - const QmlEventType &type = m_eventTypes[event.typeIndex()]; + stream.writeAttribute(_("eventIndex"), QString::number(event.typeIndex())); if (type.message == Event) { if (type.detailType == AnimationFrame) { diff --git a/src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp b/src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp index cba27c6213..a9535db655 100644 --- a/src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp @@ -133,17 +133,12 @@ qint64 QmlProfilerViewManager::selectionEnd() const bool QmlProfilerViewManager::isEventsRestrictedToRange() const { - foreach (QmlProfilerEventsView *view, d->eventsViews) { - if (view->isRestrictedToRange()) - return true; - } - return false; + return d->profilerModelManager->isRestrictedToRange(); } void QmlProfilerViewManager::restrictEventsToRange(qint64 rangeStart, qint64 rangeEnd) { - foreach (QmlProfilerEventsView *view, d->eventsViews) - view->restrictToRange(rangeStart, rangeEnd); + d->profilerModelManager->restrictToRange(rangeStart, rangeEnd); } void QmlProfilerViewManager::raiseTimeline() |