forked from qt-creator/qt-creator
QmlProfiler: Remove template/virtual magic from SortedTimelineModel
We actually don't have to save the actual data in the SortedTimelineModel if we keep the data synchronized to the ranges. This is easy to do by just keeping track of the indices when new ranges are inserted. Like that we can eliminate the virtual function calls from AbstractTimelineModelPrivate and simplify the type hierarchy. Change-Id: Ia7aa02df57380932b689ddfe9a50ff2031198a7d Reviewed-by: Kai Koehne <kai.koehne@digia.com>
This commit is contained in:
@@ -35,7 +35,7 @@ namespace QmlProfiler {
|
|||||||
AbstractTimelineModel::AbstractTimelineModel(AbstractTimelineModelPrivate *dd,
|
AbstractTimelineModel::AbstractTimelineModel(AbstractTimelineModelPrivate *dd,
|
||||||
const QString &displayName, QmlDebug::Message message, QmlDebug::RangeType rangeType,
|
const QString &displayName, QmlDebug::Message message, QmlDebug::RangeType rangeType,
|
||||||
QObject *parent) :
|
QObject *parent) :
|
||||||
QObject(parent), d_ptr(dd)
|
SortedTimelineModel(parent), d_ptr(dd)
|
||||||
{
|
{
|
||||||
Q_D(AbstractTimelineModel);
|
Q_D(AbstractTimelineModel);
|
||||||
d->q_ptr = this;
|
d->q_ptr = this;
|
||||||
@@ -61,48 +61,6 @@ void AbstractTimelineModel::setModelManager(QmlProfilerModelManager *modelManage
|
|||||||
d->modelId = d->modelManager->registerModelProxy();
|
d->modelId = d->modelManager->registerModelProxy();
|
||||||
}
|
}
|
||||||
|
|
||||||
int AbstractTimelineModel::count() const
|
|
||||||
{
|
|
||||||
Q_D(const AbstractTimelineModel);
|
|
||||||
return d->count();
|
|
||||||
}
|
|
||||||
|
|
||||||
int AbstractTimelineModel::firstIndex(qint64 startTime) const
|
|
||||||
{
|
|
||||||
Q_D(const AbstractTimelineModel);
|
|
||||||
return d->firstIndex(startTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
int AbstractTimelineModel::firstIndexNoParents(qint64 startTime) const
|
|
||||||
{
|
|
||||||
Q_D(const AbstractTimelineModel);
|
|
||||||
return d->firstIndexNoParents(startTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
int AbstractTimelineModel::lastIndex(qint64 endTime) const
|
|
||||||
{
|
|
||||||
Q_D(const AbstractTimelineModel);
|
|
||||||
return d->lastIndex(endTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 AbstractTimelineModel::duration(int index) const
|
|
||||||
{
|
|
||||||
Q_D(const AbstractTimelineModel);
|
|
||||||
return d->duration(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 AbstractTimelineModel::startTime(int index) const
|
|
||||||
{
|
|
||||||
Q_D(const AbstractTimelineModel);
|
|
||||||
return d->startTime(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 AbstractTimelineModel::endTime(int index) const
|
|
||||||
{
|
|
||||||
Q_D(const AbstractTimelineModel);
|
|
||||||
return d->startTime(index) + d->duration(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AbstractTimelineModel::isEmpty() const
|
bool AbstractTimelineModel::isEmpty() const
|
||||||
{
|
{
|
||||||
return count() == 0;
|
return count() == 0;
|
||||||
@@ -241,8 +199,6 @@ void AbstractTimelineModel::dataChanged()
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
d->rowOffsets.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AbstractTimelineModel::accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const
|
bool AbstractTimelineModel::accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const
|
||||||
@@ -272,4 +228,19 @@ QString AbstractTimelineModel::displayName() const
|
|||||||
return d->displayName;
|
return d->displayName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AbstractTimelineModel::clear()
|
||||||
|
{
|
||||||
|
Q_D(AbstractTimelineModel);
|
||||||
|
bool wasExpanded = d->expanded;
|
||||||
|
bool hadRowHeights = !d->rowOffsets.empty();
|
||||||
|
d->rowOffsets.clear();
|
||||||
|
d->expanded = false;
|
||||||
|
SortedTimelineModel::clear();
|
||||||
|
if (hadRowHeights)
|
||||||
|
emit rowHeightChanged();
|
||||||
|
if (wasExpanded)
|
||||||
|
emit expandedChanged();
|
||||||
|
d->modelManager->modelProxyCountUpdated(d->modelId, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,13 +34,13 @@
|
|||||||
#include "qmlprofiler_global.h"
|
#include "qmlprofiler_global.h"
|
||||||
#include "qmlprofilermodelmanager.h"
|
#include "qmlprofilermodelmanager.h"
|
||||||
#include "qmlprofilerdatamodel.h"
|
#include "qmlprofilerdatamodel.h"
|
||||||
#include <QObject>
|
#include "sortedtimelinemodel.h"
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
|
||||||
namespace QmlProfiler {
|
namespace QmlProfiler {
|
||||||
|
|
||||||
class QMLPROFILER_EXPORT AbstractTimelineModel : public QObject
|
class QMLPROFILER_EXPORT AbstractTimelineModel : public SortedTimelineModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@@ -61,13 +61,6 @@ public:
|
|||||||
qint64 traceStartTime() const;
|
qint64 traceStartTime() const;
|
||||||
qint64 traceEndTime() const;
|
qint64 traceEndTime() const;
|
||||||
qint64 traceDuration() const;
|
qint64 traceDuration() const;
|
||||||
qint64 duration(int index) const;
|
|
||||||
qint64 startTime(int index) const;
|
|
||||||
qint64 endTime(int index) const;
|
|
||||||
int firstIndex(qint64 startTime) const;
|
|
||||||
int firstIndexNoParents(qint64 startTime) const;
|
|
||||||
int lastIndex(qint64 endTime) const;
|
|
||||||
int count() const;
|
|
||||||
bool accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const;
|
bool accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const;
|
||||||
bool expanded() const;
|
bool expanded() const;
|
||||||
void setExpanded(bool expanded);
|
void setExpanded(bool expanded);
|
||||||
@@ -81,7 +74,6 @@ public:
|
|||||||
virtual QVariantMap details(int index) const = 0;
|
virtual QVariantMap details(int index) const = 0;
|
||||||
virtual int row(int index) const = 0;
|
virtual int row(int index) const = 0;
|
||||||
virtual void loadData() = 0;
|
virtual void loadData() = 0;
|
||||||
virtual void clear() = 0;
|
|
||||||
|
|
||||||
// Methods which can optionally be implemented by child models.
|
// Methods which can optionally be implemented by child models.
|
||||||
// returned map should contain "file", "line", "column" properties, or be empty
|
// returned map should contain "file", "line", "column" properties, or be empty
|
||||||
@@ -92,6 +84,7 @@ public:
|
|||||||
virtual float height(int index) const;
|
virtual float height(int index) const;
|
||||||
virtual int rowMinValue(int rowNumber) const;
|
virtual int rowMinValue(int rowNumber) const;
|
||||||
virtual int rowMaxValue(int rowNumber) const;
|
virtual int rowMaxValue(int rowNumber) const;
|
||||||
|
virtual void clear();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void expandedChanged();
|
void expandedChanged();
|
||||||
|
|||||||
@@ -36,17 +36,6 @@ namespace QmlProfiler {
|
|||||||
|
|
||||||
class QMLPROFILER_EXPORT AbstractTimelineModel::AbstractTimelineModelPrivate {
|
class QMLPROFILER_EXPORT AbstractTimelineModel::AbstractTimelineModelPrivate {
|
||||||
public:
|
public:
|
||||||
virtual ~AbstractTimelineModelPrivate() {}
|
|
||||||
|
|
||||||
virtual int count() const = 0;
|
|
||||||
virtual qint64 duration(int index) const = 0;
|
|
||||||
virtual qint64 startTime(int index) const = 0;
|
|
||||||
virtual qint64 lastEndTime() const = 0;
|
|
||||||
virtual qint64 firstStartTime() const = 0;
|
|
||||||
virtual int firstIndex(qint64 startTime) const = 0;
|
|
||||||
virtual int firstIndexNoParents(qint64 startTime) const = 0;
|
|
||||||
virtual int lastIndex(qint64 endTime) const = 0;
|
|
||||||
|
|
||||||
QVector<int> rowOffsets;
|
QVector<int> rowOffsets;
|
||||||
QmlProfilerModelManager *modelManager;
|
QmlProfilerModelManager *modelManager;
|
||||||
int modelId;
|
int modelId;
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
#include "qmlprofilerpainteventsmodelproxy.h"
|
#include "qmlprofilerpainteventsmodelproxy.h"
|
||||||
#include "qmlprofilermodelmanager.h"
|
#include "qmlprofilermodelmanager.h"
|
||||||
#include "qmlprofilerdatamodel.h"
|
#include "qmlprofilerdatamodel.h"
|
||||||
#include "sortedtimelinemodel.h"
|
|
||||||
#include "abstracttimelinemodel_p.h"
|
#include "abstracttimelinemodel_p.h"
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
@@ -46,12 +45,10 @@
|
|||||||
namespace QmlProfiler {
|
namespace QmlProfiler {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class PaintEventsModelProxy::PaintEventsModelProxyPrivate :
|
class PaintEventsModelProxy::PaintEventsModelProxyPrivate : public AbstractTimelineModelPrivate
|
||||||
public SortedTimelineModel<QmlPaintEventData,
|
|
||||||
AbstractTimelineModel::AbstractTimelineModelPrivate>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
QVector<PaintEventsModelProxy::QmlPaintEventData> data;
|
||||||
int maxGuiThreadAnimations;
|
int maxGuiThreadAnimations;
|
||||||
int maxRenderThreadAnimations;
|
int maxRenderThreadAnimations;
|
||||||
int rowFromThreadId(QmlDebug::AnimationThread threadId) const;
|
int rowFromThreadId(QmlDebug::AnimationThread threadId) const;
|
||||||
@@ -72,10 +69,9 @@ PaintEventsModelProxy::PaintEventsModelProxy(QObject *parent)
|
|||||||
void PaintEventsModelProxy::clear()
|
void PaintEventsModelProxy::clear()
|
||||||
{
|
{
|
||||||
Q_D(PaintEventsModelProxy);
|
Q_D(PaintEventsModelProxy);
|
||||||
d->clear();
|
|
||||||
d->maxGuiThreadAnimations = d->maxRenderThreadAnimations = 0;
|
d->maxGuiThreadAnimations = d->maxRenderThreadAnimations = 0;
|
||||||
d->expanded = false;
|
d->data.clear();
|
||||||
d->modelManager->modelProxyCountUpdated(d->modelId, 0, 1);
|
AbstractTimelineModel::clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PaintEventsModelProxy::accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const
|
bool PaintEventsModelProxy::accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const
|
||||||
@@ -125,7 +121,7 @@ void PaintEventsModelProxy::loadData()
|
|||||||
lastEvent.animationcount = (int)event.numericData2;
|
lastEvent.animationcount = (int)event.numericData2;
|
||||||
QTC_ASSERT(lastEvent.animationcount > 0, continue);
|
QTC_ASSERT(lastEvent.animationcount > 0, continue);
|
||||||
|
|
||||||
d->insert(realStartTime, realEndTime - realStartTime, lastEvent);
|
d->data.insert(insert(realStartTime, realEndTime - realStartTime), lastEvent);
|
||||||
|
|
||||||
if (lastEvent.threadId == QmlDebug::GuiThread)
|
if (lastEvent.threadId == QmlDebug::GuiThread)
|
||||||
d->maxGuiThreadAnimations = qMax(lastEvent.animationcount, d->maxGuiThreadAnimations);
|
d->maxGuiThreadAnimations = qMax(lastEvent.animationcount, d->maxGuiThreadAnimations);
|
||||||
@@ -135,10 +131,10 @@ void PaintEventsModelProxy::loadData()
|
|||||||
|
|
||||||
minNextStartTimes[lastEvent.threadId] = event.startTime + 1;
|
minNextStartTimes[lastEvent.threadId] = event.startTime + 1;
|
||||||
|
|
||||||
d->modelManager->modelProxyCountUpdated(d->modelId, d->count(), referenceList.count());
|
d->modelManager->modelProxyCountUpdated(d->modelId, count(), referenceList.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
d->computeNesting();
|
computeNesting();
|
||||||
|
|
||||||
d->modelManager->modelProxyCountUpdated(d->modelId, 1, 1);
|
d->modelManager->modelProxyCountUpdated(d->modelId, 1, 1);
|
||||||
}
|
}
|
||||||
@@ -163,7 +159,7 @@ int PaintEventsModelProxy::PaintEventsModelProxyPrivate::rowFromThreadId(
|
|||||||
int PaintEventsModelProxy::row(int index) const
|
int PaintEventsModelProxy::row(int index) const
|
||||||
{
|
{
|
||||||
Q_D(const PaintEventsModelProxy);
|
Q_D(const PaintEventsModelProxy);
|
||||||
return d->rowFromThreadId(d->range(index).threadId);
|
return d->rowFromThreadId(d->data[index].threadId);
|
||||||
}
|
}
|
||||||
|
|
||||||
int PaintEventsModelProxy::rowMaxValue(int rowNumber) const
|
int PaintEventsModelProxy::rowMaxValue(int rowNumber) const
|
||||||
@@ -183,13 +179,13 @@ int PaintEventsModelProxy::rowMaxValue(int rowNumber) const
|
|||||||
int PaintEventsModelProxy::eventId(int index) const
|
int PaintEventsModelProxy::eventId(int index) const
|
||||||
{
|
{
|
||||||
Q_D(const PaintEventsModelProxy);
|
Q_D(const PaintEventsModelProxy);
|
||||||
return d->range(index).threadId;
|
return d->data[index].threadId;
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor PaintEventsModelProxy::color(int index) const
|
QColor PaintEventsModelProxy::color(int index) const
|
||||||
{
|
{
|
||||||
Q_D(const PaintEventsModelProxy);
|
Q_D(const PaintEventsModelProxy);
|
||||||
double fpsFraction = d->range(index).framerate / 60.0;
|
double fpsFraction = d->data[index].framerate / 60.0;
|
||||||
if (fpsFraction > 1.0)
|
if (fpsFraction > 1.0)
|
||||||
fpsFraction = 1.0;
|
fpsFraction = 1.0;
|
||||||
if (fpsFraction < 0.0)
|
if (fpsFraction < 0.0)
|
||||||
@@ -200,16 +196,16 @@ QColor PaintEventsModelProxy::color(int index) const
|
|||||||
float PaintEventsModelProxy::height(int index) const
|
float PaintEventsModelProxy::height(int index) const
|
||||||
{
|
{
|
||||||
Q_D(const PaintEventsModelProxy);
|
Q_D(const PaintEventsModelProxy);
|
||||||
const PaintEventsModelProxyPrivate::Range &range = d->range(index);
|
const QmlPaintEventData &data = d->data[index];
|
||||||
|
|
||||||
// Add some height to the events if we're far from the scale threshold of 2 * DefaultRowHeight.
|
// Add some height to the events if we're far from the scale threshold of 2 * DefaultRowHeight.
|
||||||
// Like that you can see the smaller events more easily.
|
// Like that you can see the smaller events more easily.
|
||||||
int scaleThreshold = 2 * DefaultRowHeight - rowHeight(d->rowFromThreadId(range.threadId));
|
int scaleThreshold = 2 * DefaultRowHeight - rowHeight(d->rowFromThreadId(data.threadId));
|
||||||
float boost = scaleThreshold > 0 ? (0.15 * scaleThreshold / DefaultRowHeight) : 0;
|
float boost = scaleThreshold > 0 ? (0.15 * scaleThreshold / DefaultRowHeight) : 0;
|
||||||
|
|
||||||
return boost + (1.0 - boost) * (float)range.animationcount /
|
return boost + (1.0 - boost) * (float)data.animationcount /
|
||||||
(float)(range.threadId == QmlDebug::GuiThread ? d->maxGuiThreadAnimations :
|
(float)(data.threadId == QmlDebug::GuiThread ? d->maxGuiThreadAnimations :
|
||||||
d->maxRenderThreadAnimations);
|
d->maxRenderThreadAnimations);
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantList PaintEventsModelProxy::labels() const
|
QVariantList PaintEventsModelProxy::labels() const
|
||||||
@@ -242,10 +238,10 @@ QVariantMap PaintEventsModelProxy::details(int index) const
|
|||||||
QVariantMap result;
|
QVariantMap result;
|
||||||
|
|
||||||
result.insert(QStringLiteral("displayName"), displayName());
|
result.insert(QStringLiteral("displayName"), displayName());
|
||||||
result.insert(tr("Duration"), QmlProfilerBaseModel::formatTime(d->range(index).duration));
|
result.insert(tr("Duration"), QmlProfilerBaseModel::formatTime(range(index).duration));
|
||||||
result.insert(tr("Framerate"), QString::fromLatin1("%1 FPS").arg(d->range(index).framerate));
|
result.insert(tr("Framerate"), QString::fromLatin1("%1 FPS").arg(d->data[index].framerate));
|
||||||
result.insert(tr("Animations"), QString::fromLatin1("%1").arg(d->range(index).animationcount));
|
result.insert(tr("Animations"), QString::fromLatin1("%1").arg(d->data[index].animationcount));
|
||||||
result.insert(tr("Context"), tr(d->range(index).threadId == QmlDebug::GuiThread ?
|
result.insert(tr("Context"), tr(d->data[index].threadId == QmlDebug::GuiThread ?
|
||||||
"GUI Thread" : "Render Thread"));
|
"GUI Thread" : "Render Thread"));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
#include "qmlprofilertimelinemodelproxy.h"
|
#include "qmlprofilertimelinemodelproxy.h"
|
||||||
#include "qmlprofilermodelmanager.h"
|
#include "qmlprofilermodelmanager.h"
|
||||||
#include "qmlprofilerdatamodel.h"
|
#include "qmlprofilerdatamodel.h"
|
||||||
#include "sortedtimelinemodel.h"
|
|
||||||
#include "abstracttimelinemodel_p.h"
|
#include "abstracttimelinemodel_p.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
@@ -45,9 +44,7 @@
|
|||||||
namespace QmlProfiler {
|
namespace QmlProfiler {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class RangeTimelineModel::RangeTimelineModelPrivate :
|
class RangeTimelineModel::RangeTimelineModelPrivate : public AbstractTimelineModelPrivate
|
||||||
public SortedTimelineModel<RangeTimelineModel::QmlRangeEventStartInstance,
|
|
||||||
AbstractTimelineModel::AbstractTimelineModelPrivate>
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// convenience functions
|
// convenience functions
|
||||||
@@ -55,6 +52,7 @@ public:
|
|||||||
void computeExpandedLevels();
|
void computeExpandedLevels();
|
||||||
void findBindingLoops();
|
void findBindingLoops();
|
||||||
|
|
||||||
|
QVector<QmlRangeEventStartInstance> data;
|
||||||
QVector<int> expandedRowTypes;
|
QVector<int> expandedRowTypes;
|
||||||
int contractedRows;
|
int contractedRows;
|
||||||
bool seenPaintEvent;
|
bool seenPaintEvent;
|
||||||
@@ -68,7 +66,6 @@ RangeTimelineModel::RangeTimelineModel(QmlDebug::RangeType rangeType, QObject *p
|
|||||||
{
|
{
|
||||||
Q_D(RangeTimelineModel);
|
Q_D(RangeTimelineModel);
|
||||||
d->seenPaintEvent = false;
|
d->seenPaintEvent = false;
|
||||||
d->expandedRowTypes.clear();
|
|
||||||
d->expandedRowTypes << -1;
|
d->expandedRowTypes << -1;
|
||||||
d->contractedRows = 1;
|
d->contractedRows = 1;
|
||||||
}
|
}
|
||||||
@@ -76,14 +73,12 @@ RangeTimelineModel::RangeTimelineModel(QmlDebug::RangeType rangeType, QObject *p
|
|||||||
void RangeTimelineModel::clear()
|
void RangeTimelineModel::clear()
|
||||||
{
|
{
|
||||||
Q_D(RangeTimelineModel);
|
Q_D(RangeTimelineModel);
|
||||||
d->clear();
|
|
||||||
d->expandedRowTypes.clear();
|
d->expandedRowTypes.clear();
|
||||||
d->expandedRowTypes << -1;
|
d->expandedRowTypes << -1;
|
||||||
d->contractedRows = 1;
|
d->contractedRows = 1;
|
||||||
d->seenPaintEvent = false;
|
d->seenPaintEvent = false;
|
||||||
d->expanded = false;
|
d->data.clear();
|
||||||
|
AbstractTimelineModel::clear();
|
||||||
d->modelManager->modelProxyCountUpdated(d->modelId, 0, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RangeTimelineModel::loadData()
|
void RangeTimelineModel::loadData()
|
||||||
@@ -105,15 +100,15 @@ void RangeTimelineModel::loadData()
|
|||||||
d->seenPaintEvent = true;
|
d->seenPaintEvent = true;
|
||||||
|
|
||||||
// store starttime-based instance
|
// store starttime-based instance
|
||||||
d->insert(event.startTime, event.duration, QmlRangeEventStartInstance(event.typeIndex));
|
d->data.insert(insert(event.startTime, event.duration),
|
||||||
|
QmlRangeEventStartInstance(event.typeIndex));
|
||||||
d->modelManager->modelProxyCountUpdated(d->modelId, d->count(), eventList.count() * 6);
|
d->modelManager->modelProxyCountUpdated(d->modelId, count(), eventList.count() * 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
d->modelManager->modelProxyCountUpdated(d->modelId, 2, 6);
|
d->modelManager->modelProxyCountUpdated(d->modelId, 2, 6);
|
||||||
|
|
||||||
// compute range nesting
|
// compute range nesting
|
||||||
d->computeNesting();
|
computeNesting();
|
||||||
|
|
||||||
// compute nestingLevel - nonexpanded
|
// compute nestingLevel - nonexpanded
|
||||||
d->computeNestingContracted();
|
d->computeNestingContracted();
|
||||||
@@ -134,8 +129,9 @@ void RangeTimelineModel::loadData()
|
|||||||
|
|
||||||
void RangeTimelineModel::RangeTimelineModelPrivate::computeNestingContracted()
|
void RangeTimelineModel::RangeTimelineModelPrivate::computeNestingContracted()
|
||||||
{
|
{
|
||||||
|
Q_Q(RangeTimelineModel);
|
||||||
int i;
|
int i;
|
||||||
int eventCount = count();
|
int eventCount = q->count();
|
||||||
|
|
||||||
int nestingLevels = QmlDebug::Constants::QML_MIN_LEVEL;
|
int nestingLevels = QmlDebug::Constants::QML_MIN_LEVEL;
|
||||||
contractedRows = nestingLevels + 1;
|
contractedRows = nestingLevels + 1;
|
||||||
@@ -143,7 +139,7 @@ void RangeTimelineModel::RangeTimelineModelPrivate::computeNestingContracted()
|
|||||||
nestingEndTimes.fill(0, nestingLevels + 1);
|
nestingEndTimes.fill(0, nestingLevels + 1);
|
||||||
|
|
||||||
for (i = 0; i < eventCount; i++) {
|
for (i = 0; i < eventCount; i++) {
|
||||||
qint64 st = ranges[i].start;
|
qint64 st = q->ranges[i].start;
|
||||||
|
|
||||||
// per type
|
// per type
|
||||||
if (nestingEndTimes[nestingLevels] > st) {
|
if (nestingEndTimes[nestingLevels] > st) {
|
||||||
@@ -156,57 +152,57 @@ void RangeTimelineModel::RangeTimelineModelPrivate::computeNestingContracted()
|
|||||||
nestingEndTimes[nestingLevels-1] <= st)
|
nestingEndTimes[nestingLevels-1] <= st)
|
||||||
nestingLevels--;
|
nestingLevels--;
|
||||||
}
|
}
|
||||||
nestingEndTimes[nestingLevels] = st + ranges[i].duration;
|
nestingEndTimes[nestingLevels] = st + q->ranges[i].duration;
|
||||||
|
|
||||||
ranges[i].displayRowCollapsed = nestingLevels;
|
data[i].displayRowCollapsed = nestingLevels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RangeTimelineModel::RangeTimelineModelPrivate::computeExpandedLevels()
|
void RangeTimelineModel::RangeTimelineModelPrivate::computeExpandedLevels()
|
||||||
{
|
{
|
||||||
|
Q_Q(RangeTimelineModel);
|
||||||
QHash<int, int> eventRow;
|
QHash<int, int> eventRow;
|
||||||
int eventCount = count();
|
int eventCount = q->count();
|
||||||
for (int i = 0; i < eventCount; i++) {
|
for (int i = 0; i < eventCount; i++) {
|
||||||
int eventId = ranges[i].eventId;
|
int eventId = data[i].eventId;
|
||||||
if (!eventRow.contains(eventId)) {
|
if (!eventRow.contains(eventId)) {
|
||||||
eventRow[eventId] = expandedRowTypes.size();
|
eventRow[eventId] = expandedRowTypes.size();
|
||||||
expandedRowTypes << eventId;
|
expandedRowTypes << eventId;
|
||||||
}
|
}
|
||||||
ranges[i].displayRowExpanded = eventRow[eventId];
|
data[i].displayRowExpanded = eventRow[eventId];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RangeTimelineModel::RangeTimelineModelPrivate::findBindingLoops()
|
void RangeTimelineModel::RangeTimelineModelPrivate::findBindingLoops()
|
||||||
{
|
{
|
||||||
|
Q_Q(RangeTimelineModel);
|
||||||
if (rangeType != QmlDebug::Binding && rangeType != QmlDebug::HandlingSignal)
|
if (rangeType != QmlDebug::Binding && rangeType != QmlDebug::HandlingSignal)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
typedef QPair<int, int> CallStackEntry;
|
typedef QPair<int, int> CallStackEntry;
|
||||||
QStack<CallStackEntry> callStack;
|
QStack<CallStackEntry> callStack;
|
||||||
|
|
||||||
for (int i = 0; i < count(); ++i) {
|
for (int i = 0; i < q->count(); ++i) {
|
||||||
Range *event = &ranges[i];
|
|
||||||
|
|
||||||
const Range *potentialParent = callStack.isEmpty()
|
const Range *potentialParent = callStack.isEmpty()
|
||||||
? 0 : &ranges[callStack.top().second];
|
? 0 : &q->ranges[callStack.top().second];
|
||||||
|
|
||||||
while (potentialParent
|
while (potentialParent
|
||||||
&& !(potentialParent->start + potentialParent->duration > event->start)) {
|
&& !(potentialParent->start + potentialParent->duration > q->ranges[i].start)) {
|
||||||
callStack.pop();
|
callStack.pop();
|
||||||
potentialParent = callStack.isEmpty() ? 0
|
potentialParent = callStack.isEmpty() ? 0
|
||||||
: &ranges[callStack.top().second];
|
: &q->ranges[callStack.top().second];
|
||||||
}
|
}
|
||||||
|
|
||||||
// check whether event is already in stack
|
// check whether event is already in stack
|
||||||
for (int ii = 0; ii < callStack.size(); ++ii) {
|
for (int ii = 0; ii < callStack.size(); ++ii) {
|
||||||
if (callStack.at(ii).first == event->eventId) {
|
if (callStack.at(ii).first == data[i].eventId) {
|
||||||
event->bindingLoopHead = callStack.at(ii).second;
|
data[i].bindingLoopHead = callStack.at(ii).second;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CallStackEntry newEntry(event->eventId, i);
|
CallStackEntry newEntry(data[i].eventId, i);
|
||||||
callStack.push(newEntry);
|
callStack.push(newEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,21 +239,21 @@ int RangeTimelineModel::row(int index) const
|
|||||||
{
|
{
|
||||||
Q_D(const RangeTimelineModel);
|
Q_D(const RangeTimelineModel);
|
||||||
if (d->expanded)
|
if (d->expanded)
|
||||||
return d->range(index).displayRowExpanded;
|
return d->data[index].displayRowExpanded;
|
||||||
else
|
else
|
||||||
return d->range(index).displayRowCollapsed;
|
return d->data[index].displayRowCollapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RangeTimelineModel::eventId(int index) const
|
int RangeTimelineModel::eventId(int index) const
|
||||||
{
|
{
|
||||||
Q_D(const RangeTimelineModel);
|
Q_D(const RangeTimelineModel);
|
||||||
return d->range(index).eventId;
|
return d->data[index].eventId;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RangeTimelineModel::bindingLoopDest(int index) const
|
int RangeTimelineModel::bindingLoopDest(int index) const
|
||||||
{
|
{
|
||||||
Q_D(const RangeTimelineModel);
|
Q_D(const RangeTimelineModel);
|
||||||
return d->range(index).bindingLoopHead;
|
return d->data[index].bindingLoopHead;
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor RangeTimelineModel::color(int index) const
|
QColor RangeTimelineModel::color(int index) const
|
||||||
@@ -296,7 +292,7 @@ QVariantMap RangeTimelineModel::details(int index) const
|
|||||||
d->modelManager->qmlModel()->getEventTypes();
|
d->modelManager->qmlModel()->getEventTypes();
|
||||||
|
|
||||||
result.insert(QStringLiteral("displayName"), categoryLabel(d->rangeType));
|
result.insert(QStringLiteral("displayName"), categoryLabel(d->rangeType));
|
||||||
result.insert(tr("Duration"), QmlProfilerBaseModel::formatTime(d->range(index).duration));
|
result.insert(tr("Duration"), QmlProfilerBaseModel::formatTime(range(index).duration));
|
||||||
|
|
||||||
QString detailsString = types[id].data;
|
QString detailsString = types[id].data;
|
||||||
if (detailsString.length() > 40)
|
if (detailsString.length() > 40)
|
||||||
|
|||||||
@@ -27,6 +27,9 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "sortedtimelinemodel.h"
|
||||||
|
namespace QmlProfiler {
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class QmlProfiler::SortedTimelineModel
|
\class QmlProfiler::SortedTimelineModel
|
||||||
\brief The SortedTimelineModel class provides a sorted model for timeline data.
|
\brief The SortedTimelineModel class provides a sorted model for timeline data.
|
||||||
@@ -49,6 +52,11 @@
|
|||||||
\fn SortedTimelineModel::clear()
|
\fn SortedTimelineModel::clear()
|
||||||
Clears the ranges and their end times.
|
Clears the ranges and their end times.
|
||||||
*/
|
*/
|
||||||
|
void SortedTimelineModel::clear()
|
||||||
|
{
|
||||||
|
ranges.clear();
|
||||||
|
endTimes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn int SortedTimelineModel::count() const
|
\fn int SortedTimelineModel::count() const
|
||||||
@@ -66,18 +74,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn const SortedTimelineModel<Data>::Range &SortedTimelineModel::range(int index) const
|
\fn const SortedTimelineModel::Range &SortedTimelineModel::range(int index) const
|
||||||
Returns the range data at the specified index.
|
Returns the range data at the specified index.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn Data &SortedTimelineModel::data(int index)
|
\fn int SortedTimelineModel::insert(qint64 startTime, qint64 duration)
|
||||||
Returns modifiable user data for the range at the specified index.
|
Inserts a range at the given time position and returns its index.
|
||||||
*/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\fn int SortedTimelineModel::insert(qint64 startTime, qint64 duration, const Data &item)
|
|
||||||
Inserts the given data at the given time position and returns its index.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -114,7 +117,48 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn void computeNesting()
|
\fn void SortedTimelineModel::computeNesting()
|
||||||
Compute all ranges' parents.
|
Compute all ranges' parents.
|
||||||
\sa findFirstIndex
|
\sa findFirstIndex
|
||||||
*/
|
*/
|
||||||
|
void SortedTimelineModel::computeNesting()
|
||||||
|
{
|
||||||
|
QLinkedList<int> parents;
|
||||||
|
for (int range = 0; range != count(); ++range) {
|
||||||
|
Range ¤t = ranges[range];
|
||||||
|
for (QLinkedList<int>::iterator parentIt = parents.begin();;) {
|
||||||
|
Range &parent = ranges[*parentIt];
|
||||||
|
qint64 parentEnd = parent.start + parent.duration;
|
||||||
|
if (parentEnd < current.start) {
|
||||||
|
if (parent.start == current.start) {
|
||||||
|
if (parent.parent == -1) {
|
||||||
|
parent.parent = range;
|
||||||
|
} else {
|
||||||
|
Range &ancestor = ranges[parent.parent];
|
||||||
|
if (ancestor.start == current.start &&
|
||||||
|
ancestor.duration < current.duration)
|
||||||
|
parent.parent = range;
|
||||||
|
}
|
||||||
|
// Just switch the old parent range for the new, larger one
|
||||||
|
*parentIt = range;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
parentIt = parents.erase(parentIt);
|
||||||
|
}
|
||||||
|
} else if (parentEnd >= current.start + current.duration) {
|
||||||
|
// no need to insert
|
||||||
|
current.parent = *parentIt;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
++parentIt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentIt == parents.end()) {
|
||||||
|
parents.append(range);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,22 +30,21 @@
|
|||||||
#ifndef SORTEDTIMELINEMODEL_H
|
#ifndef SORTEDTIMELINEMODEL_H
|
||||||
#define SORTEDTIMELINEMODEL_H
|
#define SORTEDTIMELINEMODEL_H
|
||||||
|
|
||||||
#include "abstracttimelinemodel_p.h"
|
#include "qmlprofiler_global.h"
|
||||||
|
#include <QObject>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QLinkedList>
|
#include <QLinkedList>
|
||||||
|
|
||||||
namespace QmlProfiler {
|
namespace QmlProfiler {
|
||||||
|
|
||||||
// The template has to be inserted into the hierarchy of public/private classes when Data is known.
|
class QMLPROFILER_EXPORT SortedTimelineModel : public QObject {
|
||||||
// Otherwise we'd have to add implementation details to the public headers. This is why the class to
|
Q_OBJECT
|
||||||
// be derived from is given as template parameter.
|
|
||||||
template<class Data, class Base = AbstractTimelineModel::AbstractTimelineModelPrivate>
|
|
||||||
class SortedTimelineModel : public Base {
|
|
||||||
public:
|
public:
|
||||||
struct Range : public Data {
|
struct Range {
|
||||||
Range() : Data(), start(-1), duration(-1), parent(-1) {}
|
Range() : start(-1), duration(-1), parent(-1) {}
|
||||||
Range(qint64 start, qint64 duration, const Data &item) :
|
Range(qint64 start, qint64 duration) :
|
||||||
Data(item), start(start), duration(duration), parent(-1) {}
|
start(start), duration(duration), parent(-1) {}
|
||||||
qint64 start;
|
qint64 start;
|
||||||
qint64 duration;
|
qint64 duration;
|
||||||
int parent;
|
int parent;
|
||||||
@@ -61,37 +60,35 @@ public:
|
|||||||
inline qint64 timestamp() const {return end;}
|
inline qint64 timestamp() const {return end;}
|
||||||
};
|
};
|
||||||
|
|
||||||
void clear()
|
SortedTimelineModel(QObject *parent = 0) : QObject(parent) {}
|
||||||
{
|
|
||||||
ranges.clear();
|
void clear();
|
||||||
endTimes.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int count() const { return ranges.count(); }
|
inline int count() const { return ranges.count(); }
|
||||||
|
|
||||||
qint64 duration(int index) const { return range(index).duration; }
|
qint64 duration(int index) const { return ranges[index].duration; }
|
||||||
qint64 startTime(int index) const { return range(index).start; }
|
qint64 startTime(int index) const { return ranges[index].start; }
|
||||||
|
qint64 endTime(int index) const { return ranges[index].start + ranges[index].duration; }
|
||||||
|
|
||||||
inline qint64 lastEndTime() const { return endTimes.last().end; }
|
inline qint64 lastEndTime() const { return endTimes.last().end; }
|
||||||
inline qint64 firstStartTime() const { return ranges.first().start; }
|
inline qint64 firstStartTime() const { return ranges.first().start; }
|
||||||
|
|
||||||
inline const Range &range(int index) const { return ranges[index]; }
|
inline const Range &range(int index) const { return ranges[index]; }
|
||||||
inline Data &data(int index) { return ranges[index]; }
|
|
||||||
|
|
||||||
inline int insert(qint64 startTime, qint64 duration, const Data &item)
|
inline int insert(qint64 startTime, qint64 duration)
|
||||||
{
|
{
|
||||||
/* Doing insert-sort here is preferable as most of the time the times will actually be
|
/* Doing insert-sort here is preferable as most of the time the times will actually be
|
||||||
* presorted in the right way. So usually this will just result in appending. */
|
* presorted in the right way. So usually this will just result in appending. */
|
||||||
int index = insertSorted(ranges, Range(startTime, duration, item));
|
int index = insertSorted(ranges, Range(startTime, duration));
|
||||||
if (index < ranges.size() - 1)
|
if (index < ranges.size() - 1)
|
||||||
incrementStartIndices(index);
|
incrementStartIndices(index);
|
||||||
insertSorted(endTimes, RangeEnd(index, startTime + duration));
|
insertSorted(endTimes, RangeEnd(index, startTime + duration));
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int insertStart(qint64 startTime, const Data &item)
|
inline int insertStart(qint64 startTime)
|
||||||
{
|
{
|
||||||
int index = insertSorted(ranges, Range(startTime, 0, item));
|
int index = insertSorted(ranges, Range(startTime, 0));
|
||||||
if (index < ranges.size() - 1)
|
if (index < ranges.size() - 1)
|
||||||
incrementStartIndices(index);
|
incrementStartIndices(index);
|
||||||
return index;
|
return index;
|
||||||
@@ -138,47 +135,9 @@ public:
|
|||||||
return lowerBound(ranges, endTime);
|
return lowerBound(ranges, endTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void computeNesting()
|
|
||||||
{
|
|
||||||
QLinkedList<int> parents;
|
|
||||||
for (int range = 0; range != count(); ++range) {
|
|
||||||
Range ¤t = ranges[range];
|
|
||||||
for (QLinkedList<int>::iterator parentIt = parents.begin();;) {
|
|
||||||
Range &parent = ranges[*parentIt];
|
|
||||||
qint64 parentEnd = parent.start + parent.duration;
|
|
||||||
if (parentEnd < current.start) {
|
|
||||||
if (parent.start == current.start) {
|
|
||||||
if (parent.parent == -1) {
|
|
||||||
parent.parent = range;
|
|
||||||
} else {
|
|
||||||
Range &ancestor = ranges[parent.parent];
|
|
||||||
if (ancestor.start == current.start &&
|
|
||||||
ancestor.duration < current.duration)
|
|
||||||
parent.parent = range;
|
|
||||||
}
|
|
||||||
// Just switch the old parent range for the new, larger one
|
|
||||||
*parentIt = range;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
parentIt = parents.erase(parentIt);
|
|
||||||
}
|
|
||||||
} else if (parentEnd >= current.start + current.duration) {
|
|
||||||
// no need to insert
|
|
||||||
current.parent = *parentIt;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
++parentIt;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentIt == parents.end()) {
|
|
||||||
parents.append(range);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void computeNesting();
|
||||||
|
|
||||||
void incrementStartIndices(int index)
|
void incrementStartIndices(int index)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < endTimes.size(); ++i) {
|
for (int i = 0; i < endTimes.size(); ++i) {
|
||||||
|
|||||||
Reference in New Issue
Block a user