From dd87df7e5d338663283cfd1fa24b7c069a580167 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 26 Apr 2016 16:38:56 +0200 Subject: [PATCH] QmlProfiler: Load data event by event in aggregated models This paves the way for driving the event loading from the model manager. Also, unify the loading and eliminate the two different classes for the children models. Change-Id: Ic89e757963292d75b3b6fd7d6012f09194dff5a9 Reviewed-by: Alex Blasche Reviewed-by: Ulf Hermann --- src/plugins/qmlprofiler/flamegraphmodel.cpp | 115 +++--- src/plugins/qmlprofiler/flamegraphmodel.h | 12 +- .../qmlprofilerstatisticsmodel.cpp | 373 ++++++++---------- .../qmlprofiler/qmlprofilerstatisticsmodel.h | 58 ++- .../qmlprofiler/qmlprofilerstatisticsview.cpp | 8 +- .../qmlprofiler/qmlprofilerstatisticsview.h | 2 +- 6 files changed, 265 insertions(+), 303 deletions(-) diff --git a/src/plugins/qmlprofiler/flamegraphmodel.cpp b/src/plugins/qmlprofiler/flamegraphmodel.cpp index d28cec914e6..2a2055a0dff 100644 --- a/src/plugins/qmlprofiler/flamegraphmodel.cpp +++ b/src/plugins/qmlprofiler/flamegraphmodel.cpp @@ -33,7 +33,6 @@ #include #include -#include #include #include @@ -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,64 +93,66 @@ void FlameGraphModel::loadNotes(int typeIndex, bool emitSignal) emit dataChanged(QModelIndex(), QModelIndex(), QVector() << 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) { + if (!m_acceptedTypes.contains(type.rangeType)) + return; + + if (m_stackBottom.children.isEmpty()) beginResetModel(); - clear(); - endResetModel(); - return; - } else if (m_modelManager->state() != QmlProfilerModelManager::ProcessingData && - m_modelManager->state() != QmlProfilerModelManager::Done) { - return; + + 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(); - clear(); - - const QVector &eventList = m_modelManager->qmlModel()->events(); - const QVector &typesList = m_modelManager->qmlModel()->eventTypes(); - - // used by binding loop detection - QStack 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; - - if (checkRanges) { - 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); - } + 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 &eventList = m_modelManager->qmlModel()->events(); + const QVector &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) { switch (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 096a18add3f..547d3bc8904 100644 --- a/src/plugins/qmlprofiler/flamegraphmodel.h +++ b/src/plugins/qmlprofiler/flamegraphmodel.h @@ -32,6 +32,7 @@ #include #include +#include #include namespace QmlProfiler { @@ -81,8 +82,12 @@ public: QHash 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 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 5ee49e123d3..ae4d59961c5 100644 --- a/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp @@ -35,6 +35,7 @@ #include #include #include +#include namespace QmlProfiler { @@ -42,6 +43,8 @@ class QmlProfilerStatisticsModel::QmlProfilerStatisticsModelPrivate { public: QHash data; + QPointer childrenModel; + QPointer parentsModel; QmlProfilerModelManager *modelManager; @@ -50,6 +53,11 @@ public: QList acceptedTypes; QSet eventsInBindingLoop; QHash notes; + + QStack callStack; + qint64 qmlTime = 0; + qint64 lastEndTime = 0; + QHash > 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 &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 &QmlProfilerStatisticsModel::eventsInBindingLoop() const -{ - return d->eventsInBindingLoop; -} - void QmlProfilerStatisticsModel::loadData(qint64 rangeStart, qint64 rangeEnd) { clear(); - qint64 qmlTime = 0; - qint64 lastEndTime = 0; - QHash > durations; - const bool checkRanges = (rangeStart != -1) && (rangeEnd != -1); const QVector &eventList = d->modelManager->qmlModel()->events(); const QVector &typesList = d->modelManager->qmlModel()->eventTypes(); - // used by binding loop detection - QStack 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()]; - - 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++; - - // for median computing - durations[event->typeIndex()].append(event->duration()); - - // qml time computation - if (event->timestamp() > lastEndTime) { // assume parent event if starts before last end - qmlTime += event->duration(); - lastEndTime = event->timestamp() + event->duration(); - } - - // - // binding loop detection - // - const QmlEvent *potentialParent = callStack.top(); - while (potentialParent && !(potentialParent->timestamp() + potentialParent->duration() > - event->timestamp())) { - callStack.pop(); - potentialParent = callStack.top(); - } - - // 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; - } - } - - if (callStack.count() > 1) - d->data[callStack.top()->typeIndex()].durationSelf -= event->duration(); - callStack.push(event); + 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++; + + // for median computing + d->durations[event.typeIndex()].append(event.duration()); + + // 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::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 eventDurations = durations[it.key()]; + QVector 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,6 +343,57 @@ const QVector &QmlProfilerStatisticsRelativesModel::getTypes() con return m_modelManager->qmlModel()->eventTypes(); } +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--; + } + 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); + } + + // now lastparent is the new type + m_lastParent[m_level] = event.typeIndex(); +} + +void QmlProfilerStatisticsRelativesModel::finalize(const QSet &eventsInBindingLoop) +{ + 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; + } + } +} + int QmlProfilerStatisticsRelativesModel::count() const { return m_data.count(); @@ -317,138 +402,10 @@ int QmlProfilerStatisticsRelativesModel::count() const void QmlProfilerStatisticsRelativesModel::clear() { m_data.clear(); + m_endtimesPerLevel.clear(); + m_level = Constants::QML_MIN_LEVEL; + m_endtimesPerLevel[0] = 0; + m_lastParent.clear(); } -void QmlProfilerStatisticsRelativesModel::dataChanged() -{ - loadData(); - - emit dataAvailable(); -} - -QmlProfilerStatisticsParentsModel::QmlProfilerStatisticsParentsModel( - QmlProfilerModelManager *modelManager, QmlProfilerStatisticsModel *statisticsModel, - QObject *parent) : - QmlProfilerStatisticsRelativesModel(modelManager, statisticsModel, parent) -{} - -void QmlProfilerStatisticsParentsModel::loadData() -{ - clear(); - QmlProfilerDataModel *simpleModel = m_modelManager->qmlModel(); - if (simpleModel->isEmpty()) - return; - - // for level computation - QHash endtimesPerLevel; - int level = Constants::QML_MIN_LEVEL; - endtimesPerLevel[0] = 0; - - const QSet &eventsInBindingLoop = m_statisticsModel->eventsInBindingLoop(); - - // compute parent-child relationship and call count - QHash lastParent; - const QVector eventList = simpleModel->events(); - const QVector 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); - } - - // 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() -{ - clear(); - QmlProfilerDataModel *simpleModel = m_modelManager->qmlModel(); - if (simpleModel->isEmpty()) - return; - - // for level computation - QHash endtimesPerLevel; - int level = Constants::QML_MIN_LEVEL; - endtimesPerLevel[0] = 0; - - const QSet &eventsInBindingLoop = m_statisticsModel->eventsInBindingLoop(); - - // compute parent-child relationship and call count - QHash lastParent; - const QVector &eventList = simpleModel->events(); - const QVector &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(); - } -} - -} +} // namespace QmlProfiler diff --git a/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.h b/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.h index 5068e0fe2cd..6c28116ad16 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 &getData() const; const QVector &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 &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 &getTypes() const; -protected: - virtual void loadData() = 0; + void loadEvent(const QmlEvent &event); + void finalize(const QSet &eventsInBindingLoop); signals: void dataAvailable(); -protected slots: - void dataChanged(); - protected: QHash m_data; QmlProfilerModelManager *m_modelManager; - QmlProfilerStatisticsModel *m_statisticsModel; + + // for level computation + QHash m_endtimesPerLevel; + int m_level = Constants::QML_MIN_LEVEL; + + // compute parent-child relationship and call count + QHash m_lastParent; + const QmlProfilerStatisticsRelation m_relation; }; -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); - -protected: - virtual void loadData(); -}; - -} +} // namespace QmlProfiler diff --git a/src/plugins/qmlprofiler/qmlprofilerstatisticsview.cpp b/src/plugins/qmlprofiler/qmlprofilerstatisticsview.cpp index 46574cde7bb..579cafc0c3a 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(d->model) != 0; + bool calleesView = qobject_cast(d->model) != 0; if (treeModel()) { treeModel()->setColumnCount(5); diff --git a/src/plugins/qmlprofiler/qmlprofilerstatisticsview.h b/src/plugins/qmlprofiler/qmlprofilerstatisticsview.h index 891b23db5ad..0bde5adbec2 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();