aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp
diff options
context:
space:
mode:
authorUlf Hermann <[email protected]>2016-04-26 16:38:56 +0200
committerUlf Hermann <[email protected]>2016-05-23 12:31:28 +0000
commitdd87df7e5d338663283cfd1fa24b7c069a580167 (patch)
tree6c8404483c4210fef831432d4406cc870fe9495c /src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp
parentbc18fafffd95cdecc093c50fc463060dfb56f0cb (diff)
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 <[email protected]> Reviewed-by: Ulf Hermann <[email protected]>
Diffstat (limited to 'src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp')
-rw-r--r--src/plugins/qmlprofiler/qmlprofilerstatisticsmodel.cpp355
1 files changed, 156 insertions, 199 deletions
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 <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