Commit accc92ae authored by Ulf Hermann's avatar Ulf Hermann
Browse files

QmlProfiler: Allow only one category per model in timeline



This simplifies the code a lot and allows for more flexibility
when interacting with the data.

Change-Id: I69630071eee66840e905fcd95ba8c708742d58b6
Reviewed-by: default avatarKai Koehne <kai.koehne@digia.com>
parent eef83495
......@@ -57,14 +57,6 @@ void AbstractTimelineModel::setModelManager(QmlProfilerModelManager *modelManage
d->modelId = d->modelManager->registerModelProxy();
}
QStringList AbstractTimelineModel::categoryTitles() const
{
QStringList retString;
for (int i = 0; i < categoryCount(); i++)
retString << categoryLabel(i);
return retString;
}
QString AbstractTimelineModel::name() const
{
Q_D(const AbstractTimelineModel);
......@@ -169,14 +161,6 @@ int AbstractTimelineModel::getEventIdForLocation(const QString &filename, int li
return -1;
}
int AbstractTimelineModel::rowCount() const
{
int count = 0;
for (int i=0; i<categoryCount(); i++)
count += categoryDepth(i);
return count;
}
int AbstractTimelineModel::getBindingLoopDest(int index) const
{
Q_UNUSED(index);
......
......@@ -50,7 +50,6 @@ public:
// Trivial methods implemented by the abstract model itself
void setModelManager(QmlProfilerModelManager *modelManager);
QStringList categoryTitles() const;
QString name() const;
bool isEmpty() const;
......@@ -60,7 +59,6 @@ public:
Q_INVOKABLE qint64 traceEndTime() const;
Q_INVOKABLE qint64 traceDuration() const;
Q_INVOKABLE int getState() const;
Q_INVOKABLE int rowCount() const;
Q_INVOKABLE qint64 getDuration(int index) const;
Q_INVOKABLE qint64 getStartTime(int index) const;
Q_INVOKABLE qint64 getEndTime(int index) const;
......@@ -70,17 +68,15 @@ public:
int count() const;
// Methods that have to be implemented by child models
Q_INVOKABLE virtual bool expanded(int category) const = 0;
Q_INVOKABLE virtual void setExpanded(int category, bool expanded) = 0;
Q_INVOKABLE virtual int categoryDepth(int categoryIndex) const = 0;
Q_INVOKABLE virtual int categoryCount() const = 0;
Q_INVOKABLE virtual const QString categoryLabel(int categoryIndex) const = 0;
virtual bool expanded() const = 0;
virtual void setExpanded(bool expanded) = 0;
virtual int rowCount() const = 0;
virtual const QString title() const = 0;
Q_INVOKABLE virtual int getEventId(int index) const = 0;
Q_INVOKABLE virtual QColor getColor(int index) const = 0;
Q_INVOKABLE virtual const QVariantList getLabelsForCategory(int category) const = 0;
virtual const QVariantList getLabels() const = 0;
Q_INVOKABLE virtual const QVariantList getEventDetails(int index) const = 0;
virtual int getEventType(int index) const = 0;
virtual int getEventCategory(int index) const = 0;
virtual int getEventRow(int index) const = 0;
virtual void loadData() = 0;
virtual void clear() = 0;
......
......@@ -31,16 +31,15 @@ import QtQuick 2.1
Item {
id: labelContainer
property string text: qmlProfilerModelProxy.categoryLabel(modelIndex, categoryIndex)
property string text: qmlProfilerModelProxy.title(modelIndex)
property bool expanded: false
property int categoryIndex: qmlProfilerModelProxy.correctedCategoryIndexForModel(modelIndex, index)
property int modelIndex: qmlProfilerModelProxy.modelIndexForCategory(index);
property int modelIndex: index;
property var descriptions: []
property var extdescriptions: []
property var eventIds: []
visible: qmlProfilerModelProxy.categoryDepth(modelIndex, categoryIndex) > 0;
visible: qmlProfilerModelProxy.rowCount(modelIndex) > 0;
height: root.singleRowHeight
width: 150
......@@ -50,18 +49,18 @@ Item {
}
function updateHeight() {
height = root.singleRowHeight * qmlProfilerModelProxy.categoryDepth(modelIndex, categoryIndex);
height = root.singleRowHeight * qmlProfilerModelProxy.rowCount(modelIndex);
}
function getDescriptions() {
visible = qmlProfilerModelProxy.categoryDepth(modelIndex, categoryIndex) > 0;
visible = qmlProfilerModelProxy.rowCount(modelIndex) > 0;
if (!visible)
return;
var desc=[];
var ids=[];
var extdesc=[];
var labelList = qmlProfilerModelProxy.getLabelsForCategory(modelIndex, categoryIndex);
var labelList = qmlProfilerModelProxy.getLabels(modelIndex);
for (var i = 0; i < labelList.length; i++ ) {
desc[i] = labelList[i].description;
ids[i] = labelList[i].id;
......@@ -76,7 +75,7 @@ Item {
Connections {
target: qmlProfilerModelProxy
onExpandedChanged: {
expanded = qmlProfilerModelProxy.expanded(modelIndex, categoryIndex);
expanded = qmlProfilerModelProxy.expanded(modelIndex);
backgroundMarks.requestPaint();
getDescriptions();
}
......@@ -155,7 +154,7 @@ Item {
onClicked: {
// Don't try to expand empty models.
if (expanded || qmlProfilerModelProxy.count(modelIndex) > 0)
qmlProfilerModelProxy.setExpanded(modelIndex, categoryIndex, !expanded);
qmlProfilerModelProxy.setExpanded(modelIndex, !expanded);
}
}
}
......
......@@ -208,7 +208,7 @@ Rectangle {
color: root.color
height: col.height
property int rowCount: qmlProfilerModelProxy.categoryCount();
property int rowCount: qmlProfilerModelProxy.modelCount();
Column {
id: col
......
......@@ -48,13 +48,10 @@ function drawData(canvas, ctxt)
var bump = 10;
var height = canvas.height - bump;
var typeCount = qmlProfilerModelProxy.visibleCategories();
var blockHeight = height / typeCount;
var blockHeight = height / qmlProfilerModelProxy.modelCount();
var spacing = width / qmlProfilerModelProxy.traceDuration();
var modelRowStart = 0;
for (var modelIndex = 0; modelIndex < qmlProfilerModelProxy.modelCount(); ++modelIndex) {
for (var ii = canvas.offset; ii < qmlProfilerModelProxy.count(modelIndex);
ii += canvas.increment) {
......@@ -69,22 +66,18 @@ function drawData(canvas, ctxt)
xx = Math.round(xx);
var rowNumber = modelRowStart + qmlProfilerModelProxy.getEventCategoryInModel(modelIndex, ii);
var itemHeight = qmlProfilerModelProxy.getHeight(modelIndex,ii) * blockHeight;
var yy = (rowNumber + 1) * blockHeight - itemHeight ;
var yy = (modelIndex + 1) * blockHeight - itemHeight ;
ctxt.fillStyle = qmlProfilerModelProxy.getColor(modelIndex, ii);
ctxt.fillRect(xx, bump + yy, eventWidth, itemHeight);
}
modelRowStart += qmlProfilerModelProxy.categoryCount(modelIndex);
}
// binding loops
ctxt.strokeStyle = "orange";
ctxt.lineWidth = 2;
var radius = 1;
modelRowStart = 0;
for (modelIndex = 0; modelIndex < qmlProfilerModelProxy.modelCount(); ++modelIndex) {
for (ii = canvas.offset; ii < qmlProfilerModelProxy.count(modelIndex);
ii += canvas.increment) {
......@@ -92,15 +85,12 @@ function drawData(canvas, ctxt)
var xcenter = Math.round(qmlProfilerModelProxy.getStartTime(modelIndex,ii) +
qmlProfilerModelProxy.getDuration(modelIndex,ii) -
qmlProfilerModelProxy.traceStartTime()) * spacing;
var ycenter = Math.round(bump + (modelRowStart +
qmlProfilerModelProxy.getEventCategoryInModel(modelIndex, ii)) *
blockHeight + blockHeight/2);
var ycenter = Math.round(bump + blockHeight * modelIndex + blockHeight / 2);
ctxt.beginPath();
ctxt.arc(xcenter, ycenter, radius, 0, 2*Math.PI, true);
ctxt.stroke();
}
}
modelRowStart += qmlProfilerModelProxy.categoryCount(modelIndex);
}
}
......
......@@ -114,17 +114,15 @@ Canvas {
// separators
var cumulatedHeight = 0;
for (var modelIndex = 0; modelIndex < qmlProfilerModelProxy.modelCount() && cumulatedHeight < y + height; modelIndex++) {
for (var i=0; i<qmlProfilerModelProxy.categoryCount(modelIndex); i++) {
cumulatedHeight += root.singleRowHeight * qmlProfilerModelProxy.categoryDepth(modelIndex, i);
if (cumulatedHeight < y)
continue;
cumulatedHeight += root.singleRowHeight * qmlProfilerModelProxy.rowCount(modelIndex);
if (cumulatedHeight < y)
continue;
context.strokeStyle = "#B0B0B0";
context.beginPath();
context.moveTo(0, cumulatedHeight - y);
context.lineTo(width, cumulatedHeight - y);
context.stroke();
}
context.strokeStyle = "#B0B0B0";
context.beginPath();
context.moveTo(0, cumulatedHeight - y);
context.lineTo(width, cumulatedHeight - y);
context.stroke();
}
// bottom
......
......@@ -149,9 +149,8 @@ void PaintEventsModelProxy::loadData()
/////////////////// QML interface
int PaintEventsModelProxy::categoryDepth(int categoryIndex) const
int PaintEventsModelProxy::rowCount() const
{
Q_UNUSED(categoryIndex);
Q_D(const PaintEventsModelProxy);
if (isEmpty())
return d->seenForeignPaintEvent ? 0 : 1;
......@@ -191,9 +190,8 @@ float PaintEventsModelProxy::getHeight(int index) const
d->maxGuiThreadAnimations : d->maxRenderThreadAnimations) * 0.85f + 0.15f;
}
const QVariantList PaintEventsModelProxy::getLabelsForCategory(int category) const
const QVariantList PaintEventsModelProxy::getLabels() const
{
Q_UNUSED(category);
Q_D(const PaintEventsModelProxy);
QVariantList result;
......@@ -224,7 +222,7 @@ const QVariantList PaintEventsModelProxy::getEventDetails(int index) const
static const char trContext[] = "RangeDetails";
{
QVariantMap valuePair;
valuePair.insert(QLatin1String("title"), QVariant(categoryLabel(0)));
valuePair.insert(QLatin1String("title"), QVariant(title()));
result << valuePair;
}
......
......@@ -64,14 +64,14 @@ public:
void loadData();
void clear();
Q_INVOKABLE int categoryDepth(int categoryIndex) const;
Q_INVOKABLE int rowCount() const;
Q_INVOKABLE int getEventId(int index) const;
int getEventRow(int index) const;
Q_INVOKABLE QColor getColor(int index) const;
Q_INVOKABLE float getHeight(int index) const;
Q_INVOKABLE const QVariantList getLabelsForCategory(int category) const;
Q_INVOKABLE const QVariantList getLabels() const;
Q_INVOKABLE const QVariantList getEventDetails(int index) const;
private slots:
......
......@@ -31,6 +31,7 @@
#include "qmlprofilermodelmanager.h"
#include "qmlprofilerdatamodel.h"
#include "sortedtimelinemodel.h"
#include "singlecategorytimelinemodel_p.h"
#include <QCoreApplication>
#include <QVector>
......@@ -44,69 +45,53 @@
namespace QmlProfiler {
namespace Internal {
struct CategorySpan {
bool expanded;
int expandedRows;
int contractedRows;
int rowStart;
};
class BasicTimelineModel::BasicTimelineModelPrivate : public SortedTimelineModel<BasicTimelineModel::QmlRangeEventStartInstance>
class RangeTimelineModel::RangeTimelineModelPrivate :
public SortedTimelineModel<RangeTimelineModel::QmlRangeEventStartInstance,
SingleCategoryTimelineModel::SingleCategoryTimelineModelPrivate>
{
public:
// convenience functions
void prepare();
void computeNestingContracted();
void computeExpandedLevels();
void findBindingLoops();
void computeRowStarts();
QVector <BasicTimelineModel::QmlRangeEventData> eventDict;
QVector <RangeTimelineModel::QmlRangeEventData> eventDict;
QVector <QString> eventHashes;
QVector <CategorySpan> categorySpan;
int expandedRows;
int contractedRows;
bool seenPaintEvent;
private:
Q_DECLARE_PUBLIC(BasicTimelineModel)
Q_DECLARE_PUBLIC(RangeTimelineModel)
};
BasicTimelineModel::BasicTimelineModel(QObject *parent)
: AbstractTimelineModel(new BasicTimelineModelPrivate, QLatin1String("BasicTimelineModel"),
parent)
RangeTimelineModel::RangeTimelineModel(QmlDebug::RangeType rangeType, QObject *parent)
: SingleCategoryTimelineModel(new RangeTimelineModelPrivate,
QLatin1String("RangeTimelineModel"), categoryLabel(rangeType),
QmlDebug::MaximumMessage, rangeType, parent)
{
Q_D(BasicTimelineModel);
Q_D(RangeTimelineModel);
d->seenPaintEvent = false;
d->expandedRows = 1;
d->contractedRows = 1;
}
void BasicTimelineModel::clear()
void RangeTimelineModel::clear()
{
Q_D(BasicTimelineModel);
Q_D(RangeTimelineModel);
d->clear();
d->eventDict.clear();
d->eventHashes.clear();
d->categorySpan.clear();
d->expandedRows = 1;
d->contractedRows = 1;
d->seenPaintEvent = false;
d->expanded = false;
d->modelManager->modelProxyCountUpdated(d->modelId, 0, 1);
}
void BasicTimelineModel::BasicTimelineModelPrivate::prepare()
void RangeTimelineModel::loadData()
{
categorySpan.clear();
for (int i = 0; i < QmlDebug::MaximumRangeType; i++) {
CategorySpan newCategory = {false, 1, 1, i};
categorySpan << newCategory;
}
}
bool BasicTimelineModel::eventAccepted(const QmlProfilerDataModel::QmlEventData &event) const
{
// Accept all range types. Qt5 paint events aren't ranges
return (event.rangeType != QmlDebug::MaximumRangeType);
}
void BasicTimelineModel::loadData()
{
Q_D(BasicTimelineModel);
Q_D(RangeTimelineModel);
clear();
QmlProfilerDataModel *simpleModel = d->modelManager->qmlModel();
if (simpleModel->isEmpty())
......@@ -114,8 +99,6 @@ void BasicTimelineModel::loadData()
int lastEventId = 0;
d->prepare();
QMap<QString, int> eventIdsByHash;
// collect events
......@@ -136,7 +119,6 @@ void BasicTimelineModel::loadData()
event.displayName,
event.data.join(QLatin1String(" ")),
event.location,
event.rangeType,
lastEventId++ // event id
};
d->eventDict << rangeEventData;
......@@ -168,19 +150,16 @@ void BasicTimelineModel::loadData()
d->modelManager->modelProxyCountUpdated(d->modelId, 4, 6);
d->findBindingLoops();
d->modelManager->modelProxyCountUpdated(d->modelId, 5, 6);
d->computeRowStarts();
d->modelManager->modelProxyCountUpdated(d->modelId, 1, 1);
}
void BasicTimelineModel::BasicTimelineModelPrivate::computeNestingContracted()
void RangeTimelineModel::RangeTimelineModelPrivate::computeNestingContracted()
{
Q_Q(BasicTimelineModel);
Q_Q(RangeTimelineModel);
int i;
int eventCount = count();
......@@ -214,42 +193,35 @@ void BasicTimelineModel::BasicTimelineModelPrivate::computeNestingContracted()
// nestingdepth
for (i = 0; i < eventCount; i++) {
int eventType = q->getEventType(i);
if (categorySpan[eventType].contractedRows <= ranges[i].displayRowCollapsed)
categorySpan[eventType].contractedRows = ranges[i].displayRowCollapsed + 1;
if (contractedRows <= ranges[i].displayRowCollapsed)
contractedRows = ranges[i].displayRowCollapsed + 1;
}
}
void BasicTimelineModel::BasicTimelineModelPrivate::computeExpandedLevels()
void RangeTimelineModel::RangeTimelineModelPrivate::computeExpandedLevels()
{
QHash<int, int> eventRow;
int eventCount = count();
for (int i = 0; i < eventCount; i++) {
int eventId = ranges[i].eventId;
int eventType = eventDict[eventId].eventType;
if (!eventRow.contains(eventId)) {
eventRow[eventId] = categorySpan[eventType].expandedRows++;
eventRow[eventId] = expandedRows++;
}
ranges[i].displayRowExpanded = eventRow[eventId];
}
}
void BasicTimelineModel::BasicTimelineModelPrivate::findBindingLoops()
void RangeTimelineModel::RangeTimelineModelPrivate::findBindingLoops()
{
if (rangeType != QmlDebug::Binding && rangeType != QmlDebug::HandlingSignal)
return;
typedef QPair<QString, int> CallStackEntry;
QStack<CallStackEntry> callStack;
for (int i = 0; i < count(); ++i) {
Range *event = &ranges[i];
BasicTimelineModel::QmlRangeEventData data = eventDict.at(event->eventId);
static QVector<QmlDebug::RangeType> acceptedTypes =
QVector<QmlDebug::RangeType>() << QmlDebug::Binding << QmlDebug::HandlingSignal;
if (!acceptedTypes.contains(data.eventType))
continue;
const QString eventHash = eventHashes.at(event->eventId);
const Range *potentialParent = callStack.isEmpty()
? 0 : &ranges[callStack.top().second];
......@@ -276,57 +248,21 @@ void BasicTimelineModel::BasicTimelineModelPrivate::findBindingLoops()
}
void BasicTimelineModel::BasicTimelineModelPrivate::computeRowStarts()
{
Q_Q(BasicTimelineModel);
int rowStart = 0;
for (int i = 0; i < categorySpan.count(); i++) {
categorySpan[i].rowStart = rowStart;
rowStart += q->categoryDepth(i);
}
}
/////////////////// QML interface
bool BasicTimelineModel::expanded(int category) const
{
Q_D(const BasicTimelineModel);
if (d->categorySpan.count() <= category)
return false;
return d->categorySpan[category].expanded;
}
void BasicTimelineModel::setExpanded(int category, bool expanded)
{
Q_D(BasicTimelineModel);
if (d->categorySpan.count() <= category)
return;
d->categorySpan[category].expanded = expanded;
d->computeRowStarts();
emit expandedChanged();
}
int BasicTimelineModel::categoryDepth(int categoryIndex) const
int RangeTimelineModel::rowCount() const
{
Q_D(const BasicTimelineModel);
Q_D(const RangeTimelineModel);
// special for paint events: show only when empty model or there's actual events
if (categoryIndex == QmlDebug::Painting && !d->seenPaintEvent)
if (d->rangeType == QmlDebug::Painting && !d->seenPaintEvent)
return 0;
if (d->categorySpan.count() <= categoryIndex)
return 1;
if (d->categorySpan[categoryIndex].expanded)
return d->categorySpan[categoryIndex].expandedRows;
if (d->expanded)
return d->expandedRows;
else
return d->categorySpan[categoryIndex].contractedRows;
}
int BasicTimelineModel::categoryCount() const
{
return 6;
return d->contractedRows;
}
const QString BasicTimelineModel::categoryLabel(int categoryIndex) const
QString RangeTimelineModel::categoryLabel(int categoryIndex)
{
switch (categoryIndex) {
case 0: return QCoreApplication::translate("MainView", "Painting"); break;
......@@ -339,79 +275,68 @@ const QString BasicTimelineModel::categoryLabel(int categoryIndex) const
}
}
int BasicTimelineModel::getEventType(int index) const
int RangeTimelineModel::getEventType(int index) const
{
Q_D(const BasicTimelineModel);
return d->eventDict[d->range(index).eventId].eventType;
Q_D(const RangeTimelineModel);
Q_UNUSED(index);
return d->rangeType;
}
int BasicTimelineModel::getEventCategory(int index) const
int RangeTimelineModel::getEventRow(int index) const
{
Q_D(const BasicTimelineModel);
int evTy = getEventType(index);
// special: paint events shown?
if (!d->seenPaintEvent)
return evTy - 1;
return evTy;
}
int BasicTimelineModel::getEventRow(int index) const
{
Q_D(const BasicTimelineModel);
if (d->categorySpan[getEventType(index)].expanded)
return d->range(index).displayRowExpanded + d->categorySpan[getEventType(index)].rowStart;
Q_D(const RangeTimelineModel);
if (d->expanded)
return d->range(index).displayRowExpanded;
else
return d->range(index).displayRowCollapsed + d->categorySpan[getEventType(index)].rowStart;
return d->range(index).displayRowCollapsed;
}
int BasicTimelineModel::getEventId(int index) const
int RangeTimelineModel::getEventId(int index) const
{
Q_D(const BasicTimelineModel);
Q_D(const RangeTimelineModel);
return d->range(index).eventId;
}
int BasicTimelineModel::getBindingLoopDest(int index) const
int RangeTimelineModel::getBindingLoopDest(int index) const
{
Q_D(const BasicTimelineModel);
Q_D(const RangeTimelineModel);
return d->range(index).bindingLoopHead;
}
QColor BasicTimelineModel::getColor(int index) const
QColor RangeTimelineModel::getColor(int index) const
{
return getEventColor(index);
}
const QVariantList BasicTimelineModel::getLabelsForCategory(int category) const
const QVariantList RangeTimelineModel