QmlProfiler: Make statistics models QAbstractItemModels

This way we will be able to replace the QStandardItemModels in a next
step.

Change-Id: I863fde958d29c8bf8c36aa1f501cb1224720ad7a
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Ulf Hermann
2018-03-23 12:43:16 +01:00
parent 42386dbdbc
commit 495b9aa9c2
3 changed files with 362 additions and 36 deletions

View File

@@ -26,6 +26,7 @@
#include "qmlprofilerstatisticsmodel.h" #include "qmlprofilerstatisticsmodel.h"
#include "qmlprofilermodelmanager.h" #include "qmlprofilermodelmanager.h"
#include <timeline/timelineformattime.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -214,6 +215,189 @@ void QmlProfilerStatisticsModel::setRelativesModel(QmlProfilerStatisticsRelative
m_calleesModel = relative; m_calleesModel = relative;
} }
int QmlProfilerStatisticsModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_data.count() + 1;
}
int QmlProfilerStatisticsModel::columnCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : MaxMainField;
}
QVariant QmlProfilerStatisticsModel::dataForMainEntry(const QModelIndex &index, int role) const
{
switch (role) {
case FilterRole:
return m_rootDuration > 0 ? "+" : "-";
case TypeIdRole:
return -1;
case Qt::TextColorRole:
return Utils::creatorTheme()->color(Utils::Theme::Timeline_TextColor);
case SortRole:
switch (index.column()) {
case MainTimeInPercent:
return 100;
case MainSelfTimeInPercent:
case MainSelfTime:
return 0;
case MainTotalTime:
case MainTimePerCall:
case MainMedianTime:
case MainMaxTime:
case MainMinTime:
return m_rootDuration;
}
Q_FALLTHROUGH();
case Qt::DisplayRole:
switch (index.column()) {
case MainLocation:
return "<program>";
case MainTimeInPercent:
return "100 %";
case MainSelfTimeInPercent:
return "0.00 %";
case MainSelfTime:
return Timeline::formatTime(0);
case MainCallCount:
return m_rootDuration > 0 ? 1 : 0;
case MainTotalTime:
case MainTimePerCall:
case MainMedianTime:
case MainMaxTime:
case MainMinTime:
return Timeline::formatTime(m_rootDuration);
case MainDetails:
return tr("Main program");
default:
break;
}
Q_FALLTHROUGH();
default:
return QVariant();
}
}
QVariant QmlProfilerStatisticsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (index.row() == m_data.count())
return dataForMainEntry(index, role);
const int typeIndex = index.row();
const QmlEventType &type = m_modelManager->eventTypes().at(typeIndex);
const QmlEventStats &stats = m_data.at(typeIndex);
switch (role) {
case FilterRole:
return stats.calls > 0 ? "+" : "-";
case TypeIdRole:
return typeIndex;
case FilenameRole:
return type.location().filename();
case LineRole:
return type.location().line();
case ColumnRole:
return type.location().column();
case Qt::ToolTipRole:
if (stats.recursive > 0) {
return (tr("+%1 in recursive calls")
.arg(Timeline::formatTime(stats.recursive)));
} else {
auto it = m_notes.constFind(typeIndex);
return it == m_notes.constEnd() ? QString() : it.value();
}
case Qt::TextColorRole:
return (stats.recursive > 0 || m_notes.contains(typeIndex))
? Utils::creatorTheme()->color(Utils::Theme::Timeline_HighlightColor)
: Utils::creatorTheme()->color(Utils::Theme::Timeline_TextColor);
case SortRole:
switch (index.column()) {
case MainLocation:
return type.displayName();
case MainTimeInPercent:
return durationPercent(typeIndex);
case MainTotalTime:
return stats.totalNonRecursive();
case MainSelfTimeInPercent:
return durationSelfPercent(typeIndex);
case MainSelfTime:
return stats.self;
case MainTimePerCall:
return stats.average();
case MainMedianTime:
return stats.median;
case MainMaxTime:
return stats.maximum;
case MainMinTime:
return stats.minimum;
case MainDetails:
return type.data();
default:
break;
}
Q_FALLTHROUGH(); // Rest is same as Qt::DisplayRole
case Qt::DisplayRole:
switch (index.column()) {
case MainLocation:
return type.displayName().isEmpty() ? tr("<bytecode>") : type.displayName();
case MainType:
return nameForType(type.rangeType());
case MainTimeInPercent:
return QString::fromLatin1("%1 %").arg(durationPercent(typeIndex), 0, 'f', 2);
case MainTotalTime:
return Timeline::formatTime(stats.totalNonRecursive());
case MainSelfTimeInPercent:
return QString::fromLatin1("%1 %").arg(durationSelfPercent(typeIndex), 0, 'f', 2);
case MainSelfTime:
return Timeline::formatTime(stats.self);
case MainCallCount:
return stats.calls;
case MainTimePerCall:
return Timeline::formatTime(stats.average());
case MainMedianTime:
return Timeline::formatTime(stats.median);
case MainMaxTime:
return Timeline::formatTime(stats.maximum);
case MainMinTime:
return Timeline::formatTime(stats.minimum);
case MainDetails:
return type.data().isEmpty() ? tr("Source code not available")
: type.data();
default:
QTC_ASSERT(false, return QVariant());
}
default:
return QVariant();
}
}
QVariant QmlProfilerStatisticsModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (role != Qt::DisplayRole || orientation != Qt::Horizontal)
return QAbstractTableModel::headerData(section, orientation, role);
switch (section) {
case MainCallCount: return tr("Calls");
case MainDetails: return tr("Details");
case MainLocation: return tr("Location");
case MainMaxTime: return tr("Longest Time");
case MainTimePerCall: return tr("Mean Time");
case MainSelfTime: return tr("Self Time");
case MainSelfTimeInPercent: return tr("Self Time in Percent");
case MainMinTime: return tr("Shortest Time");
case MainTimeInPercent: return tr("Time in Percent");
case MainTotalTime: return tr("Total Time");
case MainType: return tr("Type");
case MainMedianTime: return tr("Median Time");
case MaxMainField:
default: QTC_ASSERT(false, return QString());
}
}
void QmlProfilerStatisticsModel::modelManagerStateChanged() void QmlProfilerStatisticsModel::modelManagerStateChanged()
{ {
if (m_modelManager->state() == QmlProfilerModelManager::ClearingData) if (m_modelManager->state() == QmlProfilerModelManager::ClearingData)
@@ -402,6 +586,131 @@ QmlProfilerStatisticsRelation QmlProfilerStatisticsRelativesModel::relation() co
return m_relation; return m_relation;
} }
int QmlProfilerStatisticsRelativesModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_data[m_relativeTypeIndex].count();
}
int QmlProfilerStatisticsRelativesModel::columnCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : MaxRelativeField;
}
QVariant QmlProfilerStatisticsRelativesModel::dataForMainEntry(qint64 totalDuration, int role,
int column) const
{
switch (role) {
case TypeIdRole:
return -1;
case Qt::TextColorRole:
return Utils::creatorTheme()->color(Utils::Theme::Timeline_TextColor);
case SortRole:
if (column == RelativeTotalTime)
return totalDuration;
Q_FALLTHROUGH(); // rest is same as Qt::DisplayRole
case Qt::DisplayRole:
switch (column) {
case RelativeLocation: return "<program>";
case RelativeTotalTime: return Timeline::formatTime(totalDuration);
case RelativeCallCount: return 1;
case RelativeDetails: return tr("Main Program");
}
default:
return QVariant();
}
}
QVariant QmlProfilerStatisticsRelativesModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
const int row = index.row();
auto main_it = m_data.find(m_relativeTypeIndex);
QTC_ASSERT(main_it != m_data.end(), return QVariant());
const QVector<QmlStatisticsRelativesData> &data = main_it.value();
QTC_ASSERT(row >= 0 && row < data.length(), return QVariant());
const QmlStatisticsRelativesData &stats = data.at(row);
if (stats.typeIndex < 0)
return dataForMainEntry(stats.duration, role, index.column());
const QmlEventType &type = m_modelManager->eventTypes().at(stats.typeIndex);
switch (role) {
case TypeIdRole:
return stats.typeIndex;
case FilenameRole:
return type.location().filename();
case LineRole:
return type.location().line();
case ColumnRole:
return type.location().column();
case Qt::ToolTipRole:
return stats.isRecursive ? tr("called recursively") : QString();
case Qt::TextColorRole:
return stats.isRecursive
? Utils::creatorTheme()->color(Utils::Theme::Timeline_HighlightColor)
: Utils::creatorTheme()->color(Utils::Theme::Timeline_TextColor);
case SortRole:
switch (index.column()) {
case RelativeLocation:
return type.displayName();
case RelativeTotalTime:
return stats.duration;
case RelativeDetails:
return type.data();
default: break;
}
Q_FALLTHROUGH(); // rest is same as Qt::DisplayRole
case Qt::DisplayRole:
switch (index.column()) {
case RelativeLocation:
return type.displayName().isEmpty() ? tr("<bytecode>") : type.displayName();
case RelativeType:
return QmlProfilerStatisticsModel::nameForType(type.rangeType());
case RelativeTotalTime:
return Timeline::formatTime(stats.duration);
case RelativeCallCount:
return stats.calls;
case RelativeDetails:
return type.data().isEmpty() ? tr("Source code not available")
: type.data();
default:
QTC_ASSERT(false, return QVariant());
}
default:
return QVariant();
}
}
QVariant QmlProfilerStatisticsRelativesModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (role != Qt::DisplayRole || orientation != Qt::Horizontal)
return QAbstractTableModel::headerData(section, orientation, role);
switch (section) {
case RelativeLocation:
return relation() == QmlProfilerStatisticsCallees ? tr("Callee") : tr("Caller");
case RelativeType:
return tr("Type");
case RelativeTotalTime:
return tr("Total Time");
case RelativeCallCount:
return tr("Calls");
case RelativeDetails:
return relation() == QmlProfilerStatisticsCallees ? tr("Callee Description")
: tr("Caller Description");
case MaxRelativeField:
default:
QTC_ASSERT(false, return QString());
}
}
int QmlProfilerStatisticsRelativesModel::count() const int QmlProfilerStatisticsRelativesModel::count() const
{ {
return m_data.count(); return m_data.count();
@@ -409,6 +718,7 @@ int QmlProfilerStatisticsRelativesModel::count() const
void QmlProfilerStatisticsRelativesModel::clear() void QmlProfilerStatisticsRelativesModel::clear()
{ {
m_relativeTypeIndex = std::numeric_limits<int>::max();
m_data.clear(); m_data.clear();
m_callStack.clear(); m_callStack.clear();
m_compileStack.clear(); m_compileStack.clear();

View File

@@ -35,8 +35,8 @@
#include <QHash> #include <QHash>
#include <QStack> #include <QStack>
#include <QVector> #include <QVector>
#include <QObject>
#include <QPointer> #include <QPointer>
#include <QAbstractTableModel>
namespace QmlProfiler { namespace QmlProfiler {
class QmlProfilerModelManager; class QmlProfilerModelManager;
@@ -47,7 +47,41 @@ enum QmlProfilerStatisticsRelation {
QmlProfilerStatisticsCallers QmlProfilerStatisticsCallers
}; };
class QmlProfilerStatisticsModel : public QObject enum ItemRole {
SortRole = Qt::UserRole + 1, // Sort by data, not by displayed string
FilterRole, // Filter out non-range types
TypeIdRole,
FilenameRole,
LineRole,
ColumnRole
};
enum MainField {
MainLocation,
MainType,
MainTimeInPercent,
MainTotalTime,
MainSelfTimeInPercent,
MainSelfTime,
MainCallCount,
MainTimePerCall,
MainMedianTime,
MainMaxTime,
MainMinTime,
MainDetails,
MaxMainField
};
enum RelativeField {
RelativeLocation,
RelativeType,
RelativeTotalTime,
RelativeCallCount,
RelativeDetails,
MaxRelativeField
};
class QmlProfilerStatisticsModel : public QAbstractTableModel
{ {
Q_OBJECT Q_OBJECT
public: public:
@@ -118,6 +152,11 @@ public:
void setRelativesModel(QmlProfilerStatisticsRelativesModel *childModel, void setRelativesModel(QmlProfilerStatisticsRelativesModel *childModel,
QmlProfilerStatisticsRelation relation); QmlProfilerStatisticsRelation relation);
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
signals: signals:
void dataAvailable(); void dataAvailable();
void notesAvailable(int typeIndex); void notesAvailable(int typeIndex);
@@ -129,6 +168,8 @@ private:
void modelManagerStateChanged(); void modelManagerStateChanged();
void notesChanged(int typeIndex); void notesChanged(int typeIndex);
QVariant dataForMainEntry(const QModelIndex &index, int role) const;
QVector<QmlEventStats> m_data; QVector<QmlEventStats> m_data;
QPointer<QmlProfilerStatisticsRelativesModel> m_calleesModel; QPointer<QmlProfilerStatisticsRelativesModel> m_calleesModel;
@@ -144,7 +185,7 @@ private:
qint64 m_rootDuration = 0; qint64 m_rootDuration = 0;
}; };
class QmlProfilerStatisticsRelativesModel : public QObject class QmlProfilerStatisticsRelativesModel : public QAbstractTableModel
{ {
Q_OBJECT Q_OBJECT
public: public:
@@ -173,13 +214,21 @@ public:
QmlProfilerStatisticsRelation relation() const; QmlProfilerStatisticsRelation relation() const;
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
signals: signals:
void dataAvailable(); void dataAvailable();
protected: protected:
QVariant dataForMainEntry(qint64 totalDuration, int role, int column) const;
QHash<int, QVector<QmlStatisticsRelativesData>> m_data; QHash<int, QVector<QmlStatisticsRelativesData>> m_data;
QPointer<QmlProfilerModelManager> m_modelManager; QPointer<QmlProfilerModelManager> m_modelManager;
int m_relativeTypeIndex = std::numeric_limits<int>::max();
struct Frame { struct Frame {
Frame(qint64 startTime = 0, int typeId = -1) : startTime(startTime), typeId(typeId) {} Frame(qint64 startTime = 0, int typeId = -1) : startTime(startTime), typeId(typeId) {}
qint64 startTime; qint64 startTime;

View File

@@ -42,39 +42,6 @@ namespace Internal {
class QmlProfilerStatisticsMainView; class QmlProfilerStatisticsMainView;
class QmlProfilerStatisticsRelativesView; class QmlProfilerStatisticsRelativesView;
enum ItemRole {
SortRole = Qt::UserRole + 1, // Sort by data, not by displayed string
TypeIdRole,
FilenameRole,
LineRole,
ColumnRole
};
enum MainField {
MainLocation,
MainType,
MainTimeInPercent,
MainTotalTime,
MainSelfTimeInPercent,
MainSelfTime,
MainCallCount,
MainTimePerCall,
MainMedianTime,
MainMaxTime,
MainMinTime,
MainDetails,
MaxMainField
};
enum RelativeField {
RelativeLocation,
RelativeType,
RelativeTotalTime,
RelativeCallCount,
RelativeDetails,
MaxRelativeField
};
class QmlProfilerStatisticsView : public QmlProfilerEventsView class QmlProfilerStatisticsView : public QmlProfilerEventsView
{ {
Q_OBJECT Q_OBJECT