diff options
-rw-r--r-- | src/plugins/qmlprofiler/flamegraphmodel.cpp | 101 | ||||
-rw-r--r-- | src/plugins/qmlprofiler/flamegraphmodel.h | 12 | ||||
-rw-r--r-- | src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp | 355 | ||||
-rw-r--r-- | src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.h | 54 | ||||
-rw-r--r-- | src/plugins/qmlprofiler/qmlprofilerstatisticsview.cpp | 8 | ||||
-rw-r--r-- | src/plugins/qmlprofiler/qmlprofilerstatisticsview.h | 2 |
6 files changed, 247 insertions, 285 deletions
diff --git a/src/plugins/qmlprofiler/flamegraphmodel.cpp b/src/plugins/qmlprofiler/flamegraphmodel.cpp index d28cec914e..2a2055a0df 100644 --- a/src/plugins/qmlprofiler/flamegraphmodel.cpp +++ b/src/plugins/qmlprofiler/flamegraphmodel.cpp @@ -33,7 +33,6 @@ #include <QVector> #include <QString> -#include <QStack> #include <QQueue> #include <QSet> @@ -44,8 +43,10 @@ FlameGraphModel::FlameGraphModel(QmlProfilerModelManager *modelManager, QObject *parent) : QAbstractItemModel(parent) { m_modelManager = modelManager; - connect(modelManager->qmlModel(), &QmlProfilerDataModel::changed, - this, [this](){loadData();}); + m_callStack.append(QmlEvent()); + m_stackTop = &m_stackBottom; + connect(modelManager, &QmlProfilerModelManager::stateChanged, + this, &FlameGraphModel::onModelManagerStateChanged); connect(modelManager->notesModel(), &Timeline::TimelineNotesModel::changed, this, [this](int typeId, int, int){loadNotes(typeId, true);}); m_modelId = modelManager->registerModelProxy(); @@ -61,8 +62,13 @@ FlameGraphModel::FlameGraphModel(QmlProfilerModelManager *modelManager, void FlameGraphModel::clear() { + beginResetModel(); m_stackBottom = FlameGraphData(); + m_callStack.clear(); + m_callStack.append(QmlEvent()); + m_stackTop = &m_stackBottom; m_typeIdsWithNotes.clear(); + endResetModel(); } void FlameGraphModel::loadNotes(int typeIndex, bool emitSignal) @@ -87,62 +93,64 @@ void FlameGraphModel::loadNotes(int typeIndex, bool emitSignal) emit dataChanged(QModelIndex(), QModelIndex(), QVector<int>() << NoteRole); } -void FlameGraphModel::loadData(qint64 rangeStart, qint64 rangeEnd) +void FlameGraphModel::loadEvent(const QmlEvent &event, const QmlEventType &type) { - const bool checkRanges = (rangeStart != -1) && (rangeEnd != -1); - if (m_modelManager->state() == QmlProfilerModelManager::ClearingData) { - beginResetModel(); - clear(); - endResetModel(); - return; - } else if (m_modelManager->state() != QmlProfilerModelManager::ProcessingData && - m_modelManager->state() != QmlProfilerModelManager::Done) { + if (!m_acceptedTypes.contains(type.rangeType)) return; + + if (m_stackBottom.children.isEmpty()) + beginResetModel(); + + const QmlEvent *potentialParent = &(m_callStack.top()); + while (potentialParent->isValid() && + potentialParent->timestamp() + potentialParent->duration() <= event.timestamp()) { + m_callStack.pop(); + m_stackTop = m_stackTop->parent; + potentialParent = &(m_callStack.top()); } - beginResetModel(); + m_callStack.push(event); + m_stackTop = pushChild(m_stackTop, event); +} + +void FlameGraphModel::finalize() +{ + foreach (FlameGraphData *child, m_stackBottom.children) + m_stackBottom.duration += child->duration; + + loadNotes(-1, false); + endResetModel(); +} + +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(); - // used by binding loop detection - QStack<const QmlEvent *> callStack; - callStack.append(0); - FlameGraphData *stackTop = &m_stackBottom; - for (int i = 0; i < eventList.size(); ++i) { - const QmlEvent *event = &eventList[i]; - int typeIndex = event->typeIndex(); - const QmlEventType *type = &typesList[typeIndex]; - - if (!m_acceptedTypes.contains(type->rangeType)) - continue; + const QmlEvent &event = eventList[i]; if (checkRanges) { - if ((event->timestamp() + event->duration() < rangeStart) - || (event->timestamp() > rangeEnd)) + if ((event.timestamp() + event.duration() < rangeStart) + || (event.timestamp() > rangeEnd)) continue; } - const QmlEvent *potentialParent = callStack.top(); - while (potentialParent && - potentialParent->timestamp() + potentialParent->duration() <= event->timestamp()) { - callStack.pop(); - stackTop = stackTop->parent; - potentialParent = callStack.top(); - } - - callStack.push(event); - stackTop = pushChild(stackTop, event); + loadEvent(event, typesList[event.typeIndex()]); } - foreach (FlameGraphData *child, m_stackBottom.children) - m_stackBottom.duration += child->duration; - - loadNotes(-1, false); - - endResetModel(); + finalize(); } static QString nameForType(RangeType typeNumber) @@ -210,18 +218,17 @@ FlameGraphData::~FlameGraphData() qDeleteAll(children); } -FlameGraphData *FlameGraphModel::pushChild( - FlameGraphData *parent, const QmlEvent *data) +FlameGraphData *FlameGraphModel::pushChild(FlameGraphData *parent, const QmlEvent &data) { foreach (FlameGraphData *child, parent->children) { - if (child->typeIndex == data->typeIndex()) { + if (child->typeIndex == data.typeIndex()) { ++child->calls; - child->duration += data->duration(); + child->duration += data.duration(); return child; } } - FlameGraphData *child = new FlameGraphData(parent, data->typeIndex(), data->duration()); + FlameGraphData *child = new FlameGraphData(parent, data.typeIndex(), data.duration()); parent->children.append(child); return child; } diff --git a/src/plugins/qmlprofiler/flamegraphmodel.h b/src/plugins/qmlprofiler/flamegraphmodel.h index 096a18add3..547d3bc890 100644 --- a/src/plugins/qmlprofiler/flamegraphmodel.h +++ b/src/plugins/qmlprofiler/flamegraphmodel.h @@ -32,6 +32,7 @@ #include <QSet> #include <QVector> +#include <QStack> #include <QAbstractItemModel> namespace QmlProfiler { @@ -81,8 +82,12 @@ public: QHash<int, QByteArray> roleNames() const override; 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(); private: friend class FlameGraphRelativesModel; @@ -90,11 +95,14 @@ private: friend class FlameGraphChildrenModel; QVariant lookup(const FlameGraphData &data, int role) const; - void clear(); - FlameGraphData *pushChild(FlameGraphData *parent, const QmlEvent *data); + FlameGraphData *pushChild(FlameGraphData *parent, const QmlEvent &data); int m_selectedTypeIndex; + + // used by binding loop detection + QStack<QmlEvent> m_callStack; FlameGraphData m_stackBottom; + FlameGraphData *m_stackTop; int m_modelId; QmlProfilerModelManager *m_modelManager; diff --git a/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp b/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp index 5ee49e123d..ae4d59961c 100644 --- a/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp @@ -35,6 +35,7 @@ #include <QString> #include <QStack> #include <QSet> +#include <QPointer> namespace QmlProfiler { @@ -42,6 +43,8 @@ class QmlProfilerStatisticsModel::QmlProfilerStatisticsModelPrivate { public: QHash<int, QmlProfilerStatisticsModel::QmlEventStats> data; + QPointer<QmlProfilerStatisticsRelativesModel> childrenModel; + QPointer<QmlProfilerStatisticsRelativesModel> parentsModel; QmlProfilerModelManager *modelManager; @@ -50,6 +53,11 @@ public: QList<RangeType> acceptedTypes; QSet<int> eventsInBindingLoop; QHash<int, QString> notes; + + QStack<QmlEvent> callStack; + qint64 qmlTime = 0; + qint64 lastEndTime = 0; + QHash <int, QVector<qint64> > durations; }; QmlProfilerStatisticsModel::QmlProfilerStatisticsModel(QmlProfilerModelManager *modelManager, @@ -57,7 +65,8 @@ QmlProfilerStatisticsModel::QmlProfilerStatisticsModel(QmlProfilerModelManager * QObject(parent), d(new QmlProfilerStatisticsModelPrivate) { d->modelManager = modelManager; - connect(modelManager->qmlModel(), &QmlProfilerDataModel::changed, + d->callStack.push(QmlEvent()); + connect(modelManager, &QmlProfilerModelManager::stateChanged, this, &QmlProfilerStatisticsModel::dataChanged); connect(modelManager->notesModel(), &Timeline::TimelineNotesModel::changed, this, &QmlProfilerStatisticsModel::notesChanged); @@ -86,11 +95,6 @@ void QmlProfilerStatisticsModel::setEventTypeAccepted(RangeType type, bool accep d->acceptedTypes.removeOne(type); } -bool QmlProfilerStatisticsModel::eventTypeAccepted(RangeType type) const -{ - return d->acceptedTypes.contains(type); -} - const QHash<int, QmlProfilerStatisticsModel::QmlEventStats> &QmlProfilerStatisticsModel::getData() const { return d->data; @@ -111,6 +115,15 @@ void QmlProfilerStatisticsModel::clear() d->data.clear(); d->eventsInBindingLoop.clear(); d->notes.clear(); + d->callStack.clear(); + d->callStack.push(QmlEvent()); + d->qmlTime = 0; + d->lastEndTime = 0; + d->durations.clear(); + if (!d->childrenModel.isNull()) + d->childrenModel->clear(); + if (!d->parentsModel.isNull()) + d->parentsModel->clear(); } void QmlProfilerStatisticsModel::limitToRange(qint64 rangeStart, qint64 rangeEnd) @@ -119,6 +132,15 @@ void QmlProfilerStatisticsModel::limitToRange(qint64 rangeStart, qint64 rangeEnd loadData(rangeStart, rangeEnd); } +void QmlProfilerStatisticsModel::setRelativesModel(QmlProfilerStatisticsRelativesModel *relative, + QmlProfilerStatisticsRelation relation) +{ + if (relation == QmlProfilerStatisticsParents) + d->parentsModel = relative; + else + d->childrenModel = relative; +} + void QmlProfilerStatisticsModel::dataChanged() { if (d->modelManager->state() == QmlProfilerModelManager::ProcessingData) @@ -159,98 +181,103 @@ void QmlProfilerStatisticsModel::notesChanged(int typeIndex) emit notesAvailable(typeIndex); } -const QSet<int> &QmlProfilerStatisticsModel::eventsInBindingLoop() const -{ - return d->eventsInBindingLoop; -} - void QmlProfilerStatisticsModel::loadData(qint64 rangeStart, qint64 rangeEnd) { clear(); - qint64 qmlTime = 0; - qint64 lastEndTime = 0; - QHash <int, QVector<qint64> > durations; - const bool checkRanges = (rangeStart != -1) && (rangeEnd != -1); const QVector<QmlEvent> &eventList = d->modelManager->qmlModel()->events(); const QVector<QmlEventType> &typesList = d->modelManager->qmlModel()->eventTypes(); - // used by binding loop detection - QStack<const QmlEvent*> callStack; - callStack.push(0); // artificial root - for (int i = 0; i < eventList.size(); ++i) { - const QmlEvent *event = &eventList[i]; - const QmlEventType *type = &typesList[event->typeIndex()]; - - if (!d->acceptedTypes.contains(type->rangeType)) - continue; + const QmlEvent &event = eventList[i]; + const QmlEventType &type = typesList[event.typeIndex()]; if (checkRanges) { - if ((event->timestamp() + event->duration() < rangeStart) - || (event->timestamp() > rangeEnd)) + if ((event.timestamp() + event.duration() < rangeStart) + || (event.timestamp() > rangeEnd)) continue; } - // update stats - QmlEventStats *stats = &d->data[event->typeIndex()]; + loadEvent(event, type); + } - 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++; + finalize(); + if (checkRanges) + notesChanged(-1); // Reload notes +} - // for median computing - durations[event->typeIndex()].append(event->duration()); +void QmlProfilerStatisticsModel::loadEvent(const QmlEvent &event, const QmlEventType &type) +{ + if (!d->acceptedTypes.contains(type.rangeType)) + return; - // qml time computation - if (event->timestamp() > lastEndTime) { // assume parent event if starts before last end - qmlTime += event->duration(); - lastEndTime = event->timestamp() + event->duration(); - } + // update stats + QmlEventStats *stats = &d->data[event.typeIndex()]; - // - // binding loop detection - // - const QmlEvent *potentialParent = callStack.top(); - while (potentialParent && !(potentialParent->timestamp() + potentialParent->duration() > - event->timestamp())) { - callStack.pop(); - potentialParent = callStack.top(); - } + 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++; - // check whether event is already in stack - for (int ii = 1; ii < callStack.size(); ++ii) { - if (callStack.at(ii)->typeIndex() == event->typeIndex()) { - d->eventsInBindingLoop.insert(event->typeIndex()); - break; - } - } + // for median computing + d->durations[event.typeIndex()].append(event.duration()); - if (callStack.count() > 1) - d->data[callStack.top()->typeIndex()].durationSelf -= event->duration(); - callStack.push(event); + // 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(); } + // + // 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()); + } + + // 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; + } + } + + 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()) + d->parentsModel->loadEvent(event); +} + + +void QmlProfilerStatisticsModel::finalize() +{ // post-process: calc mean time, median time, percentoftime for (QHash<int, QmlEventStats>::iterator it = d->data.begin(); it != d->data.end(); ++it) { QmlEventStats* stats = &it.value(); if (stats->calls > 0) stats->timePerCall = stats->duration / (double)stats->calls; - QVector<qint64> eventDurations = durations[it.key()]; + QVector<qint64> eventDurations = d->durations[it.key()]; if (!eventDurations.isEmpty()) { Utils::sort(eventDurations); stats->medianTime = eventDurations.at(eventDurations.count()/2); } - stats->percentOfTime = stats->duration * 100.0 / qmlTime; - stats->percentSelf = stats->durationSelf * 100.0 / qmlTime; + stats->percentOfTime = stats->duration * 100.0 / d->qmlTime; + stats->percentSelf = stats->durationSelf * 100.0 / d->qmlTime; } // set binding loop flag @@ -260,13 +287,17 @@ void QmlProfilerStatisticsModel::loadData(qint64 rangeStart, qint64 rangeEnd) // insert root event QmlEventStats rootEvent; rootEvent.duration = rootEvent.minTime = rootEvent.maxTime = rootEvent.timePerCall - = rootEvent.medianTime = qmlTime + 1; + = rootEvent.medianTime = d->qmlTime + 1; rootEvent.durationSelf = 1; rootEvent.calls = 1; rootEvent.percentOfTime = 100.0; rootEvent.percentSelf = 1.0 / rootEvent.duration; d->data.insert(-1, rootEvent); + if (!d->childrenModel.isNull()) + d->childrenModel->finalize(d->eventsInBindingLoop); + if (!d->parentsModel.isNull()) + d->parentsModel->finalize(d->eventsInBindingLoop); emit dataAvailable(); } @@ -278,18 +309,21 @@ int QmlProfilerStatisticsModel::count() const QmlProfilerStatisticsRelativesModel::QmlProfilerStatisticsRelativesModel( QmlProfilerModelManager *modelManager, QmlProfilerStatisticsModel *statisticsModel, - QObject *parent) : QObject(parent) + QmlProfilerStatisticsRelation relation, QObject *parent) : + QObject(parent), m_relation(relation) { + m_endtimesPerLevel[0] = 0; + QTC_CHECK(modelManager); m_modelManager = modelManager; QTC_CHECK(statisticsModel); - m_statisticsModel = statisticsModel; + statisticsModel->setRelativesModel(this, relation); // Load the child models whenever the parent model is done to get the filtering for JS/QML // right. - connect(m_statisticsModel, &QmlProfilerStatisticsModel::dataAvailable, - this, &QmlProfilerStatisticsRelativesModel::dataChanged); + connect(statisticsModel, &QmlProfilerStatisticsModel::dataAvailable, + this, &QmlProfilerStatisticsRelativesModel::dataAvailable); } const QmlProfilerStatisticsRelativesModel::QmlStatisticsRelativesMap & @@ -309,146 +343,69 @@ const QVector<QmlEventType> &QmlProfilerStatisticsRelativesModel::getTypes() con return m_modelManager->qmlModel()->eventTypes(); } -int QmlProfilerStatisticsRelativesModel::count() const -{ - return m_data.count(); -} - -void QmlProfilerStatisticsRelativesModel::clear() +void QmlProfilerStatisticsRelativesModel::loadEvent(const QmlEvent &event) { - m_data.clear(); -} - -void QmlProfilerStatisticsRelativesModel::dataChanged() -{ - loadData(); + // 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--; + } + 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); + } - emit dataAvailable(); + // now lastparent is the new type + m_lastParent[m_level] = event.typeIndex(); } -QmlProfilerStatisticsParentsModel::QmlProfilerStatisticsParentsModel( - QmlProfilerModelManager *modelManager, QmlProfilerStatisticsModel *statisticsModel, - QObject *parent) : - QmlProfilerStatisticsRelativesModel(modelManager, statisticsModel, parent) -{} - -void QmlProfilerStatisticsParentsModel::loadData() +void QmlProfilerStatisticsRelativesModel::finalize(const QSet<int> &eventsInBindingLoop) { - clear(); - QmlProfilerDataModel *simpleModel = m_modelManager->qmlModel(); - if (simpleModel->isEmpty()) - return; - - // for level computation - QHash<int, qint64> endtimesPerLevel; - int level = Constants::QML_MIN_LEVEL; - endtimesPerLevel[0] = 0; - - const QSet<int> &eventsInBindingLoop = m_statisticsModel->eventsInBindingLoop(); - - // compute parent-child relationship and call count - QHash<int, int> lastParent; - const QVector<QmlEvent> eventList = simpleModel->events(); - const QVector<QmlEventType> typesList = simpleModel->eventTypes(); - foreach (const QmlEvent &event, eventList) { - // whitelist - if (!m_statisticsModel->eventTypeAccepted(typesList[event.typeIndex()].rangeType)) - continue; - - // level computation - if (endtimesPerLevel[level] > event.timestamp()) { - level++; - } else { - while (level > Constants::QML_MIN_LEVEL && - endtimesPerLevel[level-1] <= event.timestamp()) - level--; - } - endtimesPerLevel[level] = event.timestamp() + event.duration(); - - int parentTypeIndex = -1; - if (level > Constants::QML_MIN_LEVEL && lastParent.contains(level-1)) - parentTypeIndex = lastParent[level-1]; - - QmlStatisticsRelativesMap &relativesMap = m_data[event.typeIndex()]; - QmlStatisticsRelativesMap::Iterator it = relativesMap.find(parentTypeIndex); - if (it != relativesMap.end()) { - it.value().calls++; - it.value().duration += event.duration(); - } else { - QmlStatisticsRelativesData parent = { - event.duration(), - 1, - eventsInBindingLoop.contains(parentTypeIndex) - }; - relativesMap.insert(parentTypeIndex, parent); + for (auto map = m_data.begin(), mapEnd = m_data.end(); map != mapEnd; ++map) { + auto itemEnd = map->end(); + foreach (int typeIndex, eventsInBindingLoop) { + auto item = map->find(typeIndex); + if (item != itemEnd) + item->isBindingLoop = true; } - - // now lastparent is the new type - lastParent[level] = event.typeIndex(); } } -QmlProfilerStatisticsChildrenModel::QmlProfilerStatisticsChildrenModel( - QmlProfilerModelManager *modelManager, QmlProfilerStatisticsModel *statisticsModel, - QObject *parent) : - QmlProfilerStatisticsRelativesModel(modelManager, statisticsModel, parent) -{} - -void QmlProfilerStatisticsChildrenModel::loadData() +int QmlProfilerStatisticsRelativesModel::count() const { - clear(); - QmlProfilerDataModel *simpleModel = m_modelManager->qmlModel(); - if (simpleModel->isEmpty()) - return; - - // for level computation - QHash<int, qint64> endtimesPerLevel; - int level = Constants::QML_MIN_LEVEL; - endtimesPerLevel[0] = 0; - - const QSet<int> &eventsInBindingLoop = m_statisticsModel->eventsInBindingLoop(); - - // compute parent-child relationship and call count - QHash<int, int> lastParent; - const QVector<QmlEvent> &eventList = simpleModel->events(); - const QVector<QmlEventType> &typesList = simpleModel->eventTypes(); - foreach (const QmlEvent &event, eventList) { - // whitelist - if (!m_statisticsModel->eventTypeAccepted(typesList[event.typeIndex()].rangeType)) - continue; - - // level computation - if (endtimesPerLevel[level] > event.timestamp()) { - level++; - } else { - while (level > Constants::QML_MIN_LEVEL && - endtimesPerLevel[level-1] <= event.timestamp()) - level--; - } - endtimesPerLevel[level] = event.timestamp() + event.duration(); - - int parentId = -1; - - if (level > Constants::QML_MIN_LEVEL && lastParent.contains(level-1)) - parentId = lastParent[level-1]; - - QmlStatisticsRelativesMap &relativesMap = m_data[parentId]; - QmlStatisticsRelativesMap::Iterator it = relativesMap.find(event.typeIndex()); - if (it != relativesMap.end()) { - it.value().calls++; - it.value().duration += event.duration(); - } else { - QmlStatisticsRelativesData child = { - event.duration(), - 1, - eventsInBindingLoop.contains(parentId) - }; - relativesMap.insert(event.typeIndex(), child); - } - - // now lastparent is the new type - lastParent[level] = event.typeIndex(); - } + return m_data.count(); } +void QmlProfilerStatisticsRelativesModel::clear() +{ + m_data.clear(); + m_endtimesPerLevel.clear(); + m_level = Constants::QML_MIN_LEVEL; + m_endtimesPerLevel[0] = 0; + m_lastParent.clear(); } + +} // namespace QmlProfiler diff --git a/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.h b/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.h index 5068e0fe2c..6c28116ad1 100644 --- a/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.h +++ b/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.h @@ -37,6 +37,12 @@ namespace QmlProfiler { class QmlProfilerModelManager; +class QmlProfilerStatisticsRelativesModel; + +enum QmlProfilerStatisticsRelation { + QmlProfilerStatisticsChilden, + QmlProfilerStatisticsParents +}; class QmlProfilerStatisticsModel : public QObject { @@ -63,7 +69,6 @@ public: ~QmlProfilerStatisticsModel(); void setEventTypeAccepted(RangeType type, bool accepted); - bool eventTypeAccepted(RangeType) const; const QHash<int, QmlEventStats> &getData() const; const QVector<QmlEventType> &getTypes() const; @@ -73,6 +78,8 @@ public: void clear(); void limitToRange(qint64 rangeStart, qint64 rangeEnd); + void setRelativesModel(QmlProfilerStatisticsRelativesModel *childModel, + QmlProfilerStatisticsRelation relation); signals: void dataAvailable(); @@ -80,7 +87,8 @@ signals: private: void loadData(qint64 rangeStart = -1, qint64 rangeEnd = -1); - const QSet<int> &eventsInBindingLoop() const; + void loadEvent(const QmlEvent &event, const QmlEventType &type); + void finalize(); private slots: void dataChanged(); @@ -89,15 +97,13 @@ private slots: private: class QmlProfilerStatisticsModelPrivate; QmlProfilerStatisticsModelPrivate *d; - - friend class QmlProfilerStatisticsParentsModel; - friend class QmlProfilerStatisticsChildrenModel; }; class QmlProfilerStatisticsRelativesModel : public QObject { Q_OBJECT public: + struct QmlStatisticsRelativesData { qint64 duration; qint64 calls; @@ -107,6 +113,7 @@ public: QmlProfilerStatisticsRelativesModel(QmlProfilerModelManager *modelManager, QmlProfilerStatisticsModel *statisticsModel, + QmlProfilerStatisticsRelation relation, QObject *parent = 0); int count() const; @@ -115,42 +122,23 @@ public: const QmlStatisticsRelativesMap &getData(int typeId) const; const QVector<QmlEventType> &getTypes() const; -protected: - virtual void loadData() = 0; + void loadEvent(const QmlEvent &event); + void finalize(const QSet<int> &eventsInBindingLoop); signals: void dataAvailable(); -protected slots: - void dataChanged(); - protected: QHash <int, QmlStatisticsRelativesMap> m_data; QmlProfilerModelManager *m_modelManager; - QmlProfilerStatisticsModel *m_statisticsModel; -}; - -class QmlProfilerStatisticsParentsModel : public QmlProfilerStatisticsRelativesModel -{ - Q_OBJECT -public: - QmlProfilerStatisticsParentsModel(QmlProfilerModelManager *modelManager, - QmlProfilerStatisticsModel *statisticsModel, - QObject *parent = 0); -protected: - virtual void loadData(); -}; -class QmlProfilerStatisticsChildrenModel : public QmlProfilerStatisticsRelativesModel -{ - Q_OBJECT -public: - QmlProfilerStatisticsChildrenModel(QmlProfilerModelManager *modelManager, - QmlProfilerStatisticsModel *statisticsModel, - QObject *parent = 0); + // for level computation + QHash<int, qint64> m_endtimesPerLevel; + int m_level = Constants::QML_MIN_LEVEL; -protected: - virtual void loadData(); + // compute parent-child relationship and call count + QHash<int, int> m_lastParent; + const QmlProfilerStatisticsRelation m_relation; }; -} +} // namespace QmlProfiler diff --git a/src/plugins/qmlprofiler/qmlprofilerstatisticsview.cpp b/src/plugins/qmlprofiler/qmlprofilerstatisticsview.cpp index 46574cde7b..579cafc0c3 100644 --- a/src/plugins/qmlprofiler/qmlprofilerstatisticsview.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerstatisticsview.cpp @@ -191,10 +191,12 @@ QmlProfilerStatisticsView::QmlProfilerStatisticsView(QWidget *parent, this, &QmlProfilerStatisticsView::typeSelected); d->m_eventChildren = new QmlProfilerStatisticsRelativesView( - new QmlProfilerStatisticsChildrenModel(profilerModelManager, d->model, this), + new QmlProfilerStatisticsRelativesModel(profilerModelManager, d->model, + QmlProfilerStatisticsChilden, this), this); d->m_eventParents = new QmlProfilerStatisticsRelativesView( - new QmlProfilerStatisticsParentsModel(profilerModelManager, d->model, this), + new QmlProfilerStatisticsRelativesModel(profilerModelManager, d->model, + QmlProfilerStatisticsParents, this), this); connect(d->m_eventTree, &QmlProfilerStatisticsMainView::typeSelected, d->m_eventChildren, &QmlProfilerStatisticsRelativesView::displayType); @@ -935,7 +937,7 @@ void QmlProfilerStatisticsRelativesView::clear() void QmlProfilerStatisticsRelativesView::updateHeader() { - bool calleesView = qobject_cast<QmlProfilerStatisticsChildrenModel *>(d->model) != 0; + bool calleesView = qobject_cast<QmlProfilerStatisticsRelativesModel *>(d->model) != 0; if (treeModel()) { treeModel()->setColumnCount(5); diff --git a/src/plugins/qmlprofiler/qmlprofilerstatisticsview.h b/src/plugins/qmlprofiler/qmlprofilerstatisticsview.h index 891b23db5a..0bde5adbec 100644 --- a/src/plugins/qmlprofiler/qmlprofilerstatisticsview.h +++ b/src/plugins/qmlprofiler/qmlprofilerstatisticsview.h @@ -164,7 +164,7 @@ public slots: void clear(); private: - void rebuildTree(const QmlProfilerStatisticsParentsModel::QmlStatisticsRelativesMap &map); + void rebuildTree(const QmlProfilerStatisticsRelativesModel::QmlStatisticsRelativesMap &map); void updateHeader(); QStandardItemModel *treeModel(); |