QmlProfiler: Use the SortedTimelineModel for basic timeline model

Change-Id: I259d2e49c247fc512b0c5ced2d3f3a5a68312c4b
Reviewed-by: Kai Koehne <kai.koehne@digia.com>
This commit is contained in:
Ulf Hermann
2013-12-04 16:05:02 +01:00
parent 52ea8b54bd
commit 96a0e5eea3
2 changed files with 46 additions and 202 deletions

View File

@@ -30,6 +30,7 @@
#include "qmlprofilertimelinemodelproxy.h" #include "qmlprofilertimelinemodelproxy.h"
#include "qmlprofilermodelmanager.h" #include "qmlprofilermodelmanager.h"
#include "qmlprofilersimplemodel.h" #include "qmlprofilersimplemodel.h"
#include "sortedtimelinemodel.h"
#include <QCoreApplication> #include <QCoreApplication>
#include <QVector> #include <QVector>
@@ -51,7 +52,7 @@ struct CategorySpan {
bool empty; bool empty;
}; };
class BasicTimelineModel::BasicTimelineModelPrivate class BasicTimelineModel::BasicTimelineModelPrivate : public SortedTimelineModel<BasicTimelineModel::QmlRangeEventStartInstance>
{ {
public: public:
BasicTimelineModelPrivate(BasicTimelineModel *qq) : q(qq) {} BasicTimelineModelPrivate(BasicTimelineModel *qq) : q(qq) {}
@@ -61,7 +62,6 @@ public:
void prepare(); void prepare();
void computeNestingContracted(); void computeNestingContracted();
void computeExpandedLevels(); void computeExpandedLevels();
void buildEndTimeList();
void findBindingLoops(); void findBindingLoops();
void computeRowStarts(); void computeRowStarts();
@@ -69,8 +69,6 @@ public:
QVector <BasicTimelineModel::QmlRangeEventData> eventDict; QVector <BasicTimelineModel::QmlRangeEventData> eventDict;
QVector <QString> eventHashes; QVector <QString> eventHashes;
QVector <BasicTimelineModel::QmlRangeEventStartInstance> startTimeData;
QVector <BasicTimelineModel::QmlRangeEventEndInstance> endTimeData;
QVector <CategorySpan> categorySpan; QVector <CategorySpan> categorySpan;
BasicTimelineModel *q; BasicTimelineModel *q;
@@ -104,27 +102,11 @@ QString BasicTimelineModel::name() const
return QLatin1String("BasicTimelineModel"); return QLatin1String("BasicTimelineModel");
} }
const QVector<BasicTimelineModel::QmlRangeEventStartInstance> BasicTimelineModel::getData() const
{
return d->startTimeData;
}
const QVector<BasicTimelineModel::QmlRangeEventStartInstance> BasicTimelineModel::getData(qint64 fromTime, qint64 toTime) const
{
int fromIndex = findFirstIndex(fromTime);
int toIndex = findLastIndex(toTime);
if (fromIndex != -1 && toIndex > fromIndex)
return d->startTimeData.mid(fromIndex, toIndex - fromIndex + 1);
else
return QVector<BasicTimelineModel::QmlRangeEventStartInstance>();
}
void BasicTimelineModel::clear() void BasicTimelineModel::clear()
{ {
d->SortedTimelineModel::clear();
d->eventDict.clear(); d->eventDict.clear();
d->eventHashes.clear(); d->eventHashes.clear();
d->startTimeData.clear();
d->endTimeData.clear();
d->categorySpan.clear(); d->categorySpan.clear();
m_modelManager->modelProxyCountUpdated(m_modelId, 0, 1); m_modelManager->modelProxyCountUpdated(m_modelId, 0, 1);
@@ -139,16 +121,6 @@ void BasicTimelineModel::BasicTimelineModelPrivate::prepare()
} }
} }
bool compareStartTimes(const BasicTimelineModel::QmlRangeEventStartInstance&t1, const BasicTimelineModel::QmlRangeEventStartInstance &t2)
{
return t1.startTime < t2.startTime;
}
bool compareEndTimes(const BasicTimelineModel::QmlRangeEventEndInstance &t1, const BasicTimelineModel::QmlRangeEventEndInstance &t2)
{
return t1.endTime < t2.endTime;
}
bool BasicTimelineModel::eventAccepted(const QmlProfilerSimpleModel::QmlEventData &event) const bool BasicTimelineModel::eventAccepted(const QmlProfilerSimpleModel::QmlEventData &event) const
{ {
// only accept Qt4.x Painting events // only accept Qt4.x Painting events
@@ -191,42 +163,30 @@ void BasicTimelineModel::loadData()
} }
// store starttime-based instance // store starttime-based instance
QmlRangeEventStartInstance eventStartInstance = { d->insert(event.startTime, event.duration, QmlRangeEventStartInstance(d->eventHashes.indexOf(eventHash)));
event.startTime,
event.duration,
d->eventHashes.indexOf(eventHash), // event id
QmlDebug::Constants::QML_MIN_LEVEL, // displayRowExpanded;
QmlDebug::Constants::QML_MIN_LEVEL, // displayRowCollapsed;
1,
-1 // bindingLoopHead
};
d->startTimeData.append(eventStartInstance);
m_modelManager->modelProxyCountUpdated(m_modelId, d->startTimeData.count(), eventList.count() * 7); m_modelManager->modelProxyCountUpdated(m_modelId, d->count(), eventList.count() * 6);
} }
qSort(d->startTimeData.begin(), d->startTimeData.end(), compareStartTimes); m_modelManager->modelProxyCountUpdated(m_modelId, 2, 6);
m_modelManager->modelProxyCountUpdated(m_modelId, 2, 7); // compute range nesting
d->computeNesting();
// compute nestingLevel - nonexpanded // compute nestingLevel - nonexpanded
d->computeNestingContracted(); d->computeNestingContracted();
m_modelManager->modelProxyCountUpdated(m_modelId, 3, 7); m_modelManager->modelProxyCountUpdated(m_modelId, 3, 6);
// compute nestingLevel - expanded // compute nestingLevel - expanded
d->computeExpandedLevels(); d->computeExpandedLevels();
m_modelManager->modelProxyCountUpdated(m_modelId, 4, 7); m_modelManager->modelProxyCountUpdated(m_modelId, 4, 6);
// populate endtimelist
d->buildEndTimeList();
m_modelManager->modelProxyCountUpdated(m_modelId, 5, 7);
d->findBindingLoops(); d->findBindingLoops();
m_modelManager->modelProxyCountUpdated(m_modelId, 6, 7); m_modelManager->modelProxyCountUpdated(m_modelId, 5, 6);
d->computeRowStarts(); d->computeRowStarts();
@@ -238,15 +198,10 @@ void BasicTimelineModel::loadData()
void BasicTimelineModel::BasicTimelineModelPrivate::computeNestingContracted() void BasicTimelineModel::BasicTimelineModelPrivate::computeNestingContracted()
{ {
int i; int i;
int eventCount = startTimeData.count(); int eventCount = count();
QHash<int, qint64> endtimesPerLevel;
QList<int> nestingLevels; QList<int> nestingLevels;
QList< QHash<int, qint64> > endtimesPerNestingLevel; QList< QHash<int, qint64> > endtimesPerNestingLevel;
int level = QmlDebug::Constants::QML_MIN_LEVEL;
endtimesPerLevel[QmlDebug::Constants::QML_MIN_LEVEL] = 0;
int lastBaseEventIndex = 0;
qint64 lastBaseEventEndTime = q->m_modelManager->traceTime()->startTime();
for (i = 0; i < QmlDebug::MaximumQmlEventType; i++) { for (i = 0; i < QmlDebug::MaximumQmlEventType; i++) {
nestingLevels << QmlDebug::Constants::QML_MIN_LEVEL; nestingLevels << QmlDebug::Constants::QML_MIN_LEVEL;
@@ -256,18 +211,9 @@ void BasicTimelineModel::BasicTimelineModelPrivate::computeNestingContracted()
} }
for (i = 0; i < eventCount; i++) { for (i = 0; i < eventCount; i++) {
qint64 st = startTimeData[i].startTime; qint64 st = ranges[i].start;
int type = q->getEventType(i); int type = q->getEventType(i);
// general level
if (endtimesPerLevel[level] > st) {
level++;
} else {
while (level > QmlDebug::Constants::QML_MIN_LEVEL && endtimesPerLevel[level-1] <= st)
level--;
}
endtimesPerLevel[level] = st + startTimeData[i].duration;
// per type // per type
if (endtimesPerNestingLevel[type][nestingLevels[type]] > st) { if (endtimesPerNestingLevel[type][nestingLevels[type]] > st) {
nestingLevels[type]++; nestingLevels[type]++;
@@ -277,67 +223,42 @@ void BasicTimelineModel::BasicTimelineModelPrivate::computeNestingContracted()
nestingLevels[type]--; nestingLevels[type]--;
} }
endtimesPerNestingLevel[type][nestingLevels[type]] = endtimesPerNestingLevel[type][nestingLevels[type]] =
st + startTimeData[i].duration; st + ranges[i].duration;
startTimeData[i].displayRowCollapsed = nestingLevels[type]; ranges[i].displayRowCollapsed = nestingLevels[type];
if (level == QmlDebug::Constants::QML_MIN_LEVEL) {
if (lastBaseEventEndTime < startTimeData[i].startTime) {
lastBaseEventIndex = i;
lastBaseEventEndTime = startTimeData[i].startTime + startTimeData[i].duration;
}
}
startTimeData[i].baseEventIndex = lastBaseEventIndex;
} }
// nestingdepth // nestingdepth
for (i = 0; i < eventCount; i++) { for (i = 0; i < eventCount; i++) {
int eventType = q->getEventType(i); int eventType = q->getEventType(i);
categorySpan[eventType].empty = false; categorySpan[eventType].empty = false;
if (categorySpan[eventType].contractedRows <= startTimeData[i].displayRowCollapsed) if (categorySpan[eventType].contractedRows <= ranges[i].displayRowCollapsed)
categorySpan[eventType].contractedRows = startTimeData[i].displayRowCollapsed + 1; categorySpan[eventType].contractedRows = ranges[i].displayRowCollapsed + 1;
} }
} }
void BasicTimelineModel::BasicTimelineModelPrivate::computeExpandedLevels() void BasicTimelineModel::BasicTimelineModelPrivate::computeExpandedLevels()
{ {
QHash<int, int> eventRow; QHash<int, int> eventRow;
int eventCount = startTimeData.count(); int eventCount = count();
for (int i = 0; i < eventCount; i++) { for (int i = 0; i < eventCount; i++) {
int eventId = startTimeData[i].eventId; int eventId = ranges[i].eventId;
int eventType = eventDict[eventId].eventType; int eventType = eventDict[eventId].eventType;
if (!eventRow.contains(eventId)) { if (!eventRow.contains(eventId)) {
categorySpan[eventType].empty = false; categorySpan[eventType].empty = false;
eventRow[eventId] = categorySpan[eventType].expandedRows++; eventRow[eventId] = categorySpan[eventType].expandedRows++;
} }
startTimeData[i].displayRowExpanded = eventRow[eventId]; ranges[i].displayRowExpanded = eventRow[eventId];
} }
} }
void BasicTimelineModel::BasicTimelineModelPrivate::buildEndTimeList()
{
endTimeData.clear();
int eventCount = startTimeData.count();
for (int i = 0; i < eventCount; i++) {
BasicTimelineModel::QmlRangeEventEndInstance endInstance = {
i,
startTimeData[i].startTime + startTimeData[i].duration
};
endTimeData << endInstance;
}
qSort(endTimeData.begin(), endTimeData.end(), compareEndTimes);
}
void BasicTimelineModel::BasicTimelineModelPrivate::findBindingLoops() void BasicTimelineModel::BasicTimelineModelPrivate::findBindingLoops()
{ {
typedef QPair<QString, int> CallStackEntry; typedef QPair<QString, int> CallStackEntry;
QStack<CallStackEntry> callStack; QStack<CallStackEntry> callStack;
for (int i = 0; i < startTimeData.size(); ++i) { for (int i = 0; i < count(); ++i) {
QmlRangeEventStartInstance *event = &startTimeData[i]; Range *event = &ranges[i];
BasicTimelineModel::QmlRangeEventData data = eventDict.at(event->eventId); BasicTimelineModel::QmlRangeEventData data = eventDict.at(event->eventId);
@@ -349,14 +270,14 @@ void BasicTimelineModel::BasicTimelineModelPrivate::findBindingLoops()
continue; continue;
const QString eventHash = eventHashes.at(event->eventId); const QString eventHash = eventHashes.at(event->eventId);
const QmlRangeEventStartInstance *potentialParent = callStack.isEmpty() const Range *potentialParent = callStack.isEmpty()
? 0 : &startTimeData[callStack.top().second]; ? 0 : &ranges[callStack.top().second];
while (potentialParent while (potentialParent
&& !(potentialParent->startTime + potentialParent->duration > event->startTime)) { && !(potentialParent->start + potentialParent->duration > event->start)) {
callStack.pop(); callStack.pop();
potentialParent = callStack.isEmpty() ? 0 potentialParent = callStack.isEmpty() ? 0
: &startTimeData[callStack.top().second]; : &ranges[callStack.top().second];
} }
// check whether event is already in stack // check whether event is already in stack
@@ -392,12 +313,12 @@ bool BasicTimelineModel::isEmpty() const
int BasicTimelineModel::count() const int BasicTimelineModel::count() const
{ {
return d->startTimeData.count(); return d->count();
} }
qint64 BasicTimelineModel::lastTimeMark() const qint64 BasicTimelineModel::lastTimeMark() const
{ {
return d->startTimeData.last().startTime + d->startTimeData.last().duration; return d->lastEndTime();
} }
bool BasicTimelineModel::expanded(int category) const bool BasicTimelineModel::expanded(int category) const
@@ -450,95 +371,22 @@ const QString BasicTimelineModel::categoryLabel(int categoryIndex) const
int BasicTimelineModel::findFirstIndex(qint64 startTime) const int BasicTimelineModel::findFirstIndex(qint64 startTime) const
{ {
int candidate = -1; return d->findFirstIndex(startTime);
// in the "endtime" list, find the first event that ends after startTime
if (d->endTimeData.isEmpty())
return -1;
if (d->endTimeData.count() == 1 || d->endTimeData.first().endTime >= startTime)
candidate = 0;
else
if (d->endTimeData.last().endTime <= startTime)
return -1;
if (candidate == -1)
{
int fromIndex = 0;
int toIndex = d->endTimeData.count()-1;
while (toIndex - fromIndex > 1) {
int midIndex = (fromIndex + toIndex)/2;
if (d->endTimeData[midIndex].endTime < startTime)
fromIndex = midIndex;
else
toIndex = midIndex;
}
candidate = toIndex;
}
int eventIndex = d->endTimeData[candidate].startTimeIndex;
return d->startTimeData[eventIndex].baseEventIndex;
} }
int BasicTimelineModel::findFirstIndexNoParents(qint64 startTime) const int BasicTimelineModel::findFirstIndexNoParents(qint64 startTime) const
{ {
int candidate = -1; return d->findFirstIndexNoParents(startTime);
// in the "endtime" list, find the first event that ends after startTime
if (d->endTimeData.isEmpty())
return -1;
if (d->endTimeData.count() == 1 || d->endTimeData.first().endTime >= startTime)
candidate = 0;
else
if (d->endTimeData.last().endTime <= startTime)
return -1;
if (candidate == -1) {
int fromIndex = 0;
int toIndex = d->endTimeData.count()-1;
while (toIndex - fromIndex > 1) {
int midIndex = (fromIndex + toIndex)/2;
if (d->endTimeData[midIndex].endTime < startTime)
fromIndex = midIndex;
else
toIndex = midIndex;
}
candidate = toIndex;
}
int ndx = d->endTimeData[candidate].startTimeIndex;
return ndx;
} }
int BasicTimelineModel::findLastIndex(qint64 endTime) const int BasicTimelineModel::findLastIndex(qint64 endTime) const
{ {
// in the "starttime" list, find the last event that starts before endtime return d->findLastIndex(endTime);
if (d->startTimeData.isEmpty())
return -1;
if (d->startTimeData.first().startTime >= endTime)
return -1;
if (d->startTimeData.count() == 1)
return 0;
if (d->startTimeData.last().startTime <= endTime)
return d->startTimeData.count()-1;
int fromIndex = 0;
int toIndex = d->startTimeData.count()-1;
while (toIndex - fromIndex > 1) {
int midIndex = (fromIndex + toIndex)/2;
if (d->startTimeData[midIndex].startTime < endTime)
fromIndex = midIndex;
else
toIndex = midIndex;
}
return fromIndex;
} }
int BasicTimelineModel::getEventType(int index) const int BasicTimelineModel::getEventType(int index) const
{ {
return d->eventDict[d->startTimeData[index].eventId].eventType; return d->eventDict[d->range(index).eventId].eventType;
} }
int BasicTimelineModel::getEventCategory(int index) const int BasicTimelineModel::getEventCategory(int index) const
@@ -553,34 +401,34 @@ int BasicTimelineModel::getEventCategory(int index) const
int BasicTimelineModel::getEventRow(int index) const int BasicTimelineModel::getEventRow(int index) const
{ {
if (d->categorySpan[getEventType(index)].expanded) if (d->categorySpan[getEventType(index)].expanded)
return d->startTimeData[index].displayRowExpanded + d->categorySpan[getEventType(index)].rowStart; return d->range(index).displayRowExpanded + d->categorySpan[getEventType(index)].rowStart;
else else
return d->startTimeData[index].displayRowCollapsed + d->categorySpan[getEventType(index)].rowStart; return d->range(index).displayRowCollapsed + d->categorySpan[getEventType(index)].rowStart;
} }
qint64 BasicTimelineModel::getDuration(int index) const qint64 BasicTimelineModel::getDuration(int index) const
{ {
return d->startTimeData[index].duration; return d->range(index).duration;
} }
qint64 BasicTimelineModel::getStartTime(int index) const qint64 BasicTimelineModel::getStartTime(int index) const
{ {
return d->startTimeData[index].startTime; return d->range(index).start;
} }
qint64 BasicTimelineModel::getEndTime(int index) const qint64 BasicTimelineModel::getEndTime(int index) const
{ {
return d->startTimeData[index].startTime + d->startTimeData[index].duration; return d->range(index).start + d->range(index).duration;
} }
int BasicTimelineModel::getEventId(int index) const int BasicTimelineModel::getEventId(int index) const
{ {
return d->startTimeData[index].eventId; return d->range(index).eventId;
} }
int BasicTimelineModel::getBindingLoopDest(int index) const int BasicTimelineModel::getBindingLoopDest(int index) const
{ {
return d->startTimeData[index].bindingLoopHead; return d->range(index).bindingLoopHead;
} }
QColor BasicTimelineModel::getColor(int index) const QColor BasicTimelineModel::getColor(int index) const
@@ -641,7 +489,7 @@ const QVariantList BasicTimelineModel::getEventDetails(int index) const
// duration // duration
{ {
QVariantMap valuePair; QVariantMap valuePair;
valuePair.insert(QCoreApplication::translate(trContext, "Duration:"), QVariant(d->displayTime(d->startTimeData[index].duration))); valuePair.insert(QCoreApplication::translate(trContext, "Duration:"), QVariant(d->displayTime(d->range(index).duration)));
result << valuePair; result << valuePair;
} }

View File

@@ -65,22 +65,20 @@ public:
}; };
struct QmlRangeEventStartInstance { struct QmlRangeEventStartInstance {
qint64 startTime; QmlRangeEventStartInstance(int eventId = -1) :
qint64 duration; eventId(eventId),
displayRowExpanded(QmlDebug::Constants::QML_MIN_LEVEL),
displayRowCollapsed(QmlDebug::Constants::QML_MIN_LEVEL),
bindingLoopHead(-1) {}
int eventId; int eventId;
// not-expanded, per type // not-expanded, per type
int displayRowExpanded; int displayRowExpanded;
int displayRowCollapsed; int displayRowCollapsed;
int baseEventIndex; // used by findfirstindex
int bindingLoopHead; int bindingLoopHead;
}; };
struct QmlRangeEventEndInstance {
int startTimeIndex;
qint64 endTime;
};
BasicTimelineModel(QObject *parent = 0); BasicTimelineModel(QObject *parent = 0);
~BasicTimelineModel(); ~BasicTimelineModel();
@@ -89,8 +87,6 @@ public:
QStringList categoryTitles() const; QStringList categoryTitles() const;
QString name() const; QString name() const;
const QVector<QmlRangeEventStartInstance> getData() const;
const QVector<QmlRangeEventStartInstance> getData(qint64 fromTime, qint64 toTime) const;
void loadData(); void loadData();
Q_INVOKABLE int count() const; Q_INVOKABLE int count() const;
void clear(); void clear();