forked from qt-creator/qt-creator
QmlProfiler: get rid of hash strings
Using strings to identify equal events is terribly inefficient. By keeping a global list of event types we can assign each event a numerical type index and use that to compare them. We can also avoid excessive string copying and data duplication by referring to the global type list where event type information is needed. Task-number: QTCREATORBUG-11823 Change-Id: I837bd5d0f5395b0003002ef8dd278fb27679c65d Reviewed-by: Kai Koehne <kai.koehne@digia.com>
This commit is contained in:
@@ -153,9 +153,9 @@ const QVariantMap AbstractTimelineModel::getEventLocation(int index) const
|
||||
return map;
|
||||
}
|
||||
|
||||
int AbstractTimelineModel::getEventIdForHash(const QString &eventHash) const
|
||||
int AbstractTimelineModel::getEventIdForTypeIndex(int typeIndex) const
|
||||
{
|
||||
Q_UNUSED(eventHash);
|
||||
Q_UNUSED(typeIndex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ void AbstractTimelineModel::dataChanged()
|
||||
emit expandedChanged();
|
||||
}
|
||||
|
||||
bool AbstractTimelineModel::eventAccepted(const QmlProfilerDataModel::QmlEventData &event) const
|
||||
bool AbstractTimelineModel::eventAccepted(const QmlProfilerDataModel::QmlEventTypeData &event) const
|
||||
{
|
||||
Q_D(const AbstractTimelineModel);
|
||||
return (event.rangeType == d->rangeType && event.message == d->message);
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
int findFirstIndexNoParents(qint64 startTime) const;
|
||||
int findLastIndex(qint64 endTime) const;
|
||||
int count() const;
|
||||
bool eventAccepted(const QmlProfilerDataModel::QmlEventData &event) const;
|
||||
bool eventAccepted(const QmlProfilerDataModel::QmlEventTypeData &event) const;
|
||||
bool expanded() const;
|
||||
void setExpanded(bool expanded);
|
||||
const QString title() const;
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
// Methods which can optionally be implemented by child models.
|
||||
// returned map should contain "file", "line", "column" properties, or be empty
|
||||
Q_INVOKABLE virtual const QVariantMap getEventLocation(int index) const;
|
||||
Q_INVOKABLE virtual int getEventIdForHash(const QString &eventHash) const;
|
||||
Q_INVOKABLE virtual int getEventIdForTypeIndex(int typeIndex) const;
|
||||
Q_INVOKABLE virtual int getEventIdForLocation(const QString &filename, int line, int column) const;
|
||||
Q_INVOKABLE virtual int getBindingLoopDest(int index) const;
|
||||
Q_INVOKABLE virtual float getHeight(int index) const;
|
||||
|
||||
@@ -43,16 +43,16 @@ class QmlProfilerDataModel::QmlProfilerDataModelPrivate :
|
||||
{
|
||||
public:
|
||||
QmlProfilerDataModelPrivate(QmlProfilerDataModel *qq) : QmlProfilerBaseModelPrivate(qq) {}
|
||||
QVector<QmlEventTypeData> eventTypes;
|
||||
QVector<QmlEventData> eventList;
|
||||
QHash<QmlEventTypeData, int> eventTypeIds;
|
||||
private:
|
||||
Q_DECLARE_PUBLIC(QmlProfilerDataModel)
|
||||
};
|
||||
|
||||
QmlDebug::QmlEventLocation getLocation(const QmlProfilerDataModel::QmlEventData &event);
|
||||
QString getDisplayName(const QmlProfilerDataModel::QmlEventData &event);
|
||||
QString getInitialDetails(const QmlProfilerDataModel::QmlEventData &event);
|
||||
QString getInitialDetails(const QmlProfilerDataModel::QmlEventTypeData &event);
|
||||
|
||||
QmlDebug::QmlEventLocation getLocation(const QmlProfilerDataModel::QmlEventData &event)
|
||||
QmlDebug::QmlEventLocation getLocation(const QmlProfilerDataModel::QmlEventTypeData &event)
|
||||
{
|
||||
QmlDebug::QmlEventLocation eventLocation = event.location;
|
||||
if ((event.rangeType == QmlDebug::Creating || event.rangeType == QmlDebug::Compiling)
|
||||
@@ -64,7 +64,7 @@ QmlDebug::QmlEventLocation getLocation(const QmlProfilerDataModel::QmlEventData
|
||||
return eventLocation;
|
||||
}
|
||||
|
||||
QString getDisplayName(const QmlProfilerDataModel::QmlEventData &event)
|
||||
QString getDisplayName(const QmlProfilerDataModel::QmlEventTypeData &event)
|
||||
{
|
||||
const QmlDebug::QmlEventLocation eventLocation = getLocation(event);
|
||||
QString displayName;
|
||||
@@ -81,7 +81,7 @@ QString getDisplayName(const QmlProfilerDataModel::QmlEventData &event)
|
||||
return displayName;
|
||||
}
|
||||
|
||||
QString getInitialDetails(const QmlProfilerDataModel::QmlEventData &event)
|
||||
QString getInitialDetails(const QmlProfilerDataModel::QmlEventTypeData &event)
|
||||
{
|
||||
QString details;
|
||||
// generate details string
|
||||
@@ -124,6 +124,12 @@ const QVector<QmlProfilerDataModel::QmlEventData> &QmlProfilerDataModel::getEven
|
||||
return d->eventList;
|
||||
}
|
||||
|
||||
const QVector<QmlProfilerDataModel::QmlEventTypeData> &QmlProfilerDataModel::getEventTypes() const
|
||||
{
|
||||
Q_D(const QmlProfilerDataModel);
|
||||
return d->eventTypes;
|
||||
}
|
||||
|
||||
int QmlProfilerDataModel::count() const
|
||||
{
|
||||
Q_D(const QmlProfilerDataModel);
|
||||
@@ -134,6 +140,8 @@ void QmlProfilerDataModel::clear()
|
||||
{
|
||||
Q_D(QmlProfilerDataModel);
|
||||
d->eventList.clear();
|
||||
d->eventTypes.clear();
|
||||
d->eventTypeIds.clear();
|
||||
// This call emits changed(). Don't emit it again here.
|
||||
QmlProfilerBaseModel::clear();
|
||||
}
|
||||
@@ -150,6 +158,26 @@ inline static bool operator<(const QmlProfilerDataModel::QmlEventData &t1,
|
||||
return t1.startTime < t2.startTime;
|
||||
}
|
||||
|
||||
inline static uint qHash(const QmlProfilerDataModel::QmlEventTypeData &type)
|
||||
{
|
||||
return qHash(type.location.filename) ^
|
||||
((type.location.line & 0xfff) | // 12 bits of line number
|
||||
((type.message << 12) & 0xf000) | // 4 bits of message
|
||||
((type.location.column << 16) & 0xff0000) | // 8 bits of column
|
||||
((type.rangeType << 24) & 0xf000000) | // 4 bits of rangeType
|
||||
((type.detailType << 28) & 0xf0000000)); // 4 bits of detailType
|
||||
}
|
||||
|
||||
inline static bool operator==(const QmlProfilerDataModel::QmlEventTypeData &type1,
|
||||
const QmlProfilerDataModel::QmlEventTypeData &type2)
|
||||
{
|
||||
return type1.message == type2.message && type1.rangeType == type2.rangeType &&
|
||||
type1.detailType == type2.detailType && type1.location.line == type2.location.line &&
|
||||
type1.location.column == type2.location.column &&
|
||||
// compare filename last as it's expensive.
|
||||
type1.location.filename == type2.location.filename;
|
||||
}
|
||||
|
||||
void QmlProfilerDataModel::complete()
|
||||
{
|
||||
Q_D(QmlProfilerDataModel);
|
||||
@@ -159,9 +187,9 @@ void QmlProfilerDataModel::complete()
|
||||
std::sort(d->eventList.begin(), d->eventList.end());
|
||||
|
||||
// rewrite strings
|
||||
int n = d->eventList.count();
|
||||
int n = d->eventTypes.count();
|
||||
for (int i = 0; i < n; i++) {
|
||||
QmlEventData *event = &d->eventList[i];
|
||||
QmlEventTypeData *event = &d->eventTypes[i];
|
||||
event->location = getLocation(*event);
|
||||
event->displayName = getDisplayName(*event);
|
||||
event->data = getInitialDetails(*event);
|
||||
@@ -207,24 +235,24 @@ void QmlProfilerDataModel::addQmlEvent(QmlDebug::Message message, QmlDebug::Rang
|
||||
QString::number(location.line));
|
||||
}
|
||||
|
||||
QmlEventData eventData = {displayName, message, rangeType, detailType, startTime, duration,
|
||||
data, location, ndata1, ndata2, ndata3, ndata4, ndata5};
|
||||
QmlEventTypeData typeData = {displayName, location, message, rangeType, detailType, data};
|
||||
QmlEventData eventData = {-1, startTime, duration, ndata1, ndata2, ndata3, ndata4, ndata5};
|
||||
|
||||
QHash<QmlEventTypeData, int>::Iterator it = d->eventTypeIds.find(typeData);
|
||||
if (it != d->eventTypeIds.end()) {
|
||||
eventData.typeIndex = it.value();
|
||||
} else {
|
||||
eventData.typeIndex = d->eventTypes.size();
|
||||
d->eventTypeIds[typeData] = eventData.typeIndex;
|
||||
d->eventTypes.append(typeData);
|
||||
}
|
||||
|
||||
d->eventList.append(eventData);
|
||||
|
||||
d->modelManager->modelProxyCountUpdated(d->modelId, startTime,
|
||||
d->modelManager->estimatedProfilingTime() * 2);
|
||||
}
|
||||
|
||||
QString QmlProfilerDataModel::getHashString(const QmlProfilerDataModel::QmlEventData &event)
|
||||
{
|
||||
return QString::fromLatin1("%1:%2:%3:%4:%5").arg(
|
||||
event.location.filename,
|
||||
QString::number(event.location.line),
|
||||
QString::number(event.location.column),
|
||||
QString::number((event.message << 8) | event.rangeType),
|
||||
QString::number(event.detailType));
|
||||
}
|
||||
|
||||
qint64 QmlProfilerDataModel::lastTimeMark() const
|
||||
{
|
||||
Q_D(const QmlProfilerDataModel);
|
||||
@@ -237,9 +265,9 @@ qint64 QmlProfilerDataModel::lastTimeMark() const
|
||||
void QmlProfilerDataModel::detailsChanged(int requestId, const QString &newString)
|
||||
{
|
||||
Q_D(QmlProfilerDataModel);
|
||||
QTC_ASSERT(requestId < d->eventList.count(), return);
|
||||
QTC_ASSERT(requestId < d->eventTypes.count(), return);
|
||||
|
||||
QmlEventData *event = &d->eventList[requestId];
|
||||
QmlEventTypeData *event = &d->eventTypes[requestId];
|
||||
event->data = newString;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,15 +39,19 @@ class QMLPROFILER_EXPORT QmlProfilerDataModel : public QmlProfilerBaseModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct QmlEventData {
|
||||
struct QmlEventTypeData {
|
||||
QString displayName;
|
||||
QmlDebug::QmlEventLocation location;
|
||||
QmlDebug::Message message;
|
||||
QmlDebug::RangeType rangeType;
|
||||
int detailType; // can be EventType, BindingType, PixmapEventType or SceneGraphFrameType
|
||||
QString data;
|
||||
};
|
||||
|
||||
struct QmlEventData {
|
||||
int typeIndex;
|
||||
qint64 startTime;
|
||||
qint64 duration;
|
||||
QString data;
|
||||
QmlDebug::QmlEventLocation location;
|
||||
qint64 numericData1;
|
||||
qint64 numericData2;
|
||||
qint64 numericData3;
|
||||
@@ -58,6 +62,7 @@ public:
|
||||
explicit QmlProfilerDataModel(Utils::FileInProjectFinder *fileFinder, QmlProfilerModelManager *parent = 0);
|
||||
|
||||
const QVector<QmlEventData> &getEvents() const;
|
||||
const QVector<QmlEventTypeData> &getEventTypes() const;
|
||||
int count() const;
|
||||
virtual void clear();
|
||||
virtual bool isEmpty() const;
|
||||
@@ -66,7 +71,6 @@ public:
|
||||
qint64 startTime, qint64 duration, const QString &data,
|
||||
const QmlDebug::QmlEventLocation &location, qint64 ndata1, qint64 ndata2,
|
||||
qint64 ndata3, qint64 ndata4, qint64 ndata5);
|
||||
static QString getHashString(const QmlProfilerDataModel::QmlEventData &event);
|
||||
qint64 lastTimeMark() const;
|
||||
|
||||
protected slots:
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
QmlProfilerEventsModelProxyPrivate(QmlProfilerEventsModelProxy *qq) : q(qq) {}
|
||||
~QmlProfilerEventsModelProxyPrivate() {}
|
||||
|
||||
QHash<QString, QmlProfilerEventsModelProxy::QmlEventStats> data;
|
||||
QHash<int, QmlProfilerEventsModelProxy::QmlEventStats> data;
|
||||
|
||||
QmlProfilerModelManager *modelManager;
|
||||
QmlProfilerEventsModelProxy *q;
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
int modelId;
|
||||
|
||||
QList<QmlDebug::RangeType> acceptedTypes;
|
||||
QSet<QString> eventsInBindingLoop;
|
||||
QSet<int> eventsInBindingLoop;
|
||||
};
|
||||
|
||||
QmlProfilerEventsModelProxy::QmlProfilerEventsModelProxy(QmlProfilerModelManager *modelManager, QObject *parent)
|
||||
@@ -93,9 +93,14 @@ bool QmlProfilerEventsModelProxy::eventTypeAccepted(QmlDebug::RangeType type) co
|
||||
return d->acceptedTypes.contains(type);
|
||||
}
|
||||
|
||||
const QList<QmlProfilerEventsModelProxy::QmlEventStats> QmlProfilerEventsModelProxy::getData() const
|
||||
const QHash<int, QmlProfilerEventsModelProxy::QmlEventStats> &QmlProfilerEventsModelProxy::getData() const
|
||||
{
|
||||
return d->data.values();
|
||||
return d->data;
|
||||
}
|
||||
|
||||
const QVector<QmlProfilerDataModel::QmlEventTypeData> &QmlProfilerEventsModelProxy::getTypes() const
|
||||
{
|
||||
return d->modelManager->qmlModel()->getEventTypes();
|
||||
}
|
||||
|
||||
void QmlProfilerEventsModelProxy::clear()
|
||||
@@ -118,7 +123,7 @@ void QmlProfilerEventsModelProxy::dataChanged()
|
||||
clear();
|
||||
}
|
||||
|
||||
QSet<QString> QmlProfilerEventsModelProxy::eventsInBindingLoop() const
|
||||
const QSet<int> &QmlProfilerEventsModelProxy::eventsInBindingLoop() const
|
||||
{
|
||||
return d->eventsInBindingLoop;
|
||||
}
|
||||
@@ -129,22 +134,24 @@ void QmlProfilerEventsModelProxy::loadData(qint64 rangeStart, qint64 rangeEnd)
|
||||
|
||||
qint64 qmlTime = 0;
|
||||
qint64 lastEndTime = 0;
|
||||
QHash <QString, QVector<qint64> > durations;
|
||||
QHash <int, QVector<qint64> > durations;
|
||||
|
||||
const bool checkRanges = (rangeStart != -1) && (rangeEnd != -1);
|
||||
|
||||
const QVector<QmlProfilerDataModel::QmlEventData> eventList
|
||||
const QVector<QmlProfilerDataModel::QmlEventData> &eventList
|
||||
= d->modelManager->qmlModel()->getEvents();
|
||||
const QVector<QmlProfilerDataModel::QmlEventTypeData> &typesList
|
||||
= d->modelManager->qmlModel()->getEventTypes();
|
||||
|
||||
// used by binding loop detection
|
||||
typedef QPair<QString, const QmlProfilerDataModel::QmlEventData*> CallStackEntry;
|
||||
QStack<CallStackEntry> callStack;
|
||||
callStack.push(CallStackEntry(QString(), 0)); // artificial root
|
||||
QStack<const QmlProfilerDataModel::QmlEventData*> callStack;
|
||||
callStack.push(0); // artificial root
|
||||
|
||||
for (int i = 0; i < eventList.size(); ++i) {
|
||||
const QmlProfilerDataModel::QmlEventData *event = &eventList[i];
|
||||
const QmlProfilerDataModel::QmlEventTypeData *type = &typesList[event->typeIndex];
|
||||
|
||||
if (!d->acceptedTypes.contains(event->rangeType))
|
||||
if (!d->acceptedTypes.contains(type->rangeType))
|
||||
continue;
|
||||
|
||||
if (checkRanges) {
|
||||
@@ -153,46 +160,18 @@ void QmlProfilerEventsModelProxy::loadData(qint64 rangeStart, qint64 rangeEnd)
|
||||
continue;
|
||||
}
|
||||
|
||||
// put event in hash
|
||||
QString hash = QmlProfilerDataModel::getHashString(*event);
|
||||
if (!d->data.contains(hash)) {
|
||||
QmlEventStats stats = {
|
||||
event->displayName,
|
||||
hash,
|
||||
event->data,
|
||||
event->location,
|
||||
event->message,
|
||||
event->rangeType,
|
||||
event->detailType,
|
||||
event->duration,
|
||||
1, //calls
|
||||
event->duration, //minTime
|
||||
event->duration, // maxTime
|
||||
0, //timePerCall
|
||||
0, //percentOfTime
|
||||
0, //medianTime
|
||||
false //isBindingLoop
|
||||
};
|
||||
// update stats
|
||||
QmlEventStats *stats = &d->data[event->typeIndex];
|
||||
|
||||
d->data.insert(hash, stats);
|
||||
stats->duration += event->duration;
|
||||
if (event->duration < stats->minTime)
|
||||
stats->minTime = event->duration;
|
||||
if (event->duration > stats->maxTime)
|
||||
stats->maxTime = event->duration;
|
||||
stats->calls++;
|
||||
|
||||
// for median computing
|
||||
durations.insert(hash, QVector<qint64>());
|
||||
durations[hash].append(event->duration);
|
||||
} else {
|
||||
// update stats
|
||||
QmlEventStats *stats = &d->data[hash];
|
||||
|
||||
stats->duration += event->duration;
|
||||
if (event->duration < stats->minTime)
|
||||
stats->minTime = event->duration;
|
||||
if (event->duration > stats->maxTime)
|
||||
stats->maxTime = event->duration;
|
||||
stats->calls++;
|
||||
|
||||
// for median computing
|
||||
durations[hash].append(event->duration);
|
||||
}
|
||||
// for median computing
|
||||
durations[event->typeIndex].append(event->duration);
|
||||
|
||||
// qml time computation
|
||||
if (event->startTime > lastEndTime) { // assume parent event if starts before last end
|
||||
@@ -204,25 +183,22 @@ void QmlProfilerEventsModelProxy::loadData(qint64 rangeStart, qint64 rangeEnd)
|
||||
//
|
||||
// binding loop detection
|
||||
//
|
||||
const QmlProfilerDataModel::QmlEventData *potentialParent = callStack.top().second;
|
||||
const QmlProfilerDataModel::QmlEventData *potentialParent = callStack.top();
|
||||
while (potentialParent
|
||||
&& !(potentialParent->startTime + potentialParent->duration > event->startTime)) {
|
||||
callStack.pop();
|
||||
potentialParent = callStack.top().second;
|
||||
potentialParent = callStack.top();
|
||||
}
|
||||
|
||||
// check whether event is already in stack
|
||||
bool inLoop = false;
|
||||
for (int ii = 1; ii < callStack.size(); ++ii) {
|
||||
if (callStack.at(ii).first == hash)
|
||||
inLoop = true;
|
||||
if (inLoop)
|
||||
d->eventsInBindingLoop.insert(hash);
|
||||
if (callStack.at(ii)->typeIndex == event->typeIndex) {
|
||||
d->eventsInBindingLoop.insert(event->typeIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CallStackEntry newEntry(hash, event);
|
||||
callStack.push(newEntry);
|
||||
callStack.push(event);
|
||||
|
||||
d->modelManager->modelProxyCountUpdated(d->modelId, i, eventList.count()*2);
|
||||
}
|
||||
@@ -230,12 +206,13 @@ void QmlProfilerEventsModelProxy::loadData(qint64 rangeStart, qint64 rangeEnd)
|
||||
// post-process: calc mean time, median time, percentoftime
|
||||
int i = d->data.size();
|
||||
int total = i * 2;
|
||||
foreach (const QString &hash, d->data.keys()) {
|
||||
QmlEventStats* stats = &d->data[hash];
|
||||
|
||||
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.value(hash);
|
||||
QVector<qint64> eventDurations = durations[it.key()];
|
||||
if (!eventDurations.isEmpty()) {
|
||||
qSort(eventDurations);
|
||||
stats->medianTime = eventDurations.at(eventDurations.count()/2);
|
||||
@@ -246,32 +223,17 @@ void QmlProfilerEventsModelProxy::loadData(qint64 rangeStart, qint64 rangeEnd)
|
||||
}
|
||||
|
||||
// set binding loop flag
|
||||
foreach (const QString &eventHash, d->eventsInBindingLoop)
|
||||
d->data[eventHash].isBindingLoop = true;
|
||||
|
||||
QString rootEventName = tr("<program>");
|
||||
QmlDebug::QmlEventLocation rootEventLocation(rootEventName, 1, 1);
|
||||
foreach (int typeIndex, d->eventsInBindingLoop)
|
||||
d->data[typeIndex].isBindingLoop = true;
|
||||
|
||||
// insert root event
|
||||
QmlEventStats rootEvent = {
|
||||
rootEventName, //event.displayName,
|
||||
rootEventName, // hash
|
||||
tr("Main Program"), //event.details,
|
||||
rootEventLocation, // location
|
||||
QmlDebug::MaximumMessage,
|
||||
QmlDebug::Binding, // event type
|
||||
0, // binding type
|
||||
qmlTime + 1,
|
||||
1, //calls
|
||||
qmlTime + 1, //minTime
|
||||
qmlTime + 1, // maxTime
|
||||
qmlTime + 1, //timePerCall
|
||||
100.0, //percentOfTime
|
||||
qmlTime + 1, //medianTime;
|
||||
false
|
||||
};
|
||||
QmlEventStats rootEvent;
|
||||
rootEvent.duration = rootEvent.minTime = rootEvent.maxTime = rootEvent.timePerCall
|
||||
= rootEvent.medianTime = qmlTime + 1;
|
||||
rootEvent.calls = 1;
|
||||
rootEvent.percentOfTime = 100.0;
|
||||
|
||||
d->data.insert(rootEventName, rootEvent);
|
||||
d->data.insert(-1, rootEvent);
|
||||
|
||||
d->modelManager->modelProxyCountUpdated(d->modelId, 1, 1);
|
||||
emit dataAvailable();
|
||||
@@ -303,11 +265,20 @@ QmlProfilerEventRelativesModelProxy::~QmlProfilerEventRelativesModelProxy()
|
||||
{
|
||||
}
|
||||
|
||||
const QmlProfilerEventRelativesModelProxy::QmlEventRelativesMap QmlProfilerEventRelativesModelProxy::getData(const QString &hash) const
|
||||
const QmlProfilerEventRelativesModelProxy::QmlEventRelativesMap &QmlProfilerEventRelativesModelProxy::getData(int typeId) const
|
||||
{
|
||||
if (m_data.contains(hash))
|
||||
return m_data[hash];
|
||||
return QmlEventRelativesMap();
|
||||
QHash <int, QmlEventRelativesMap>::ConstIterator it = m_data.find(typeId);
|
||||
if (it != m_data.end()) {
|
||||
return it.value();
|
||||
} else {
|
||||
static const QmlEventRelativesMap emptyMap;
|
||||
return emptyMap;
|
||||
}
|
||||
}
|
||||
|
||||
const QVector<QmlProfilerDataModel::QmlEventTypeData> &QmlProfilerEventRelativesModelProxy::getTypes() const
|
||||
{
|
||||
return m_modelManager->qmlModel()->getEventTypes();
|
||||
}
|
||||
|
||||
int QmlProfilerEventRelativesModelProxy::count() const
|
||||
@@ -345,35 +316,20 @@ void QmlProfilerEventParentsModelProxy::loadData()
|
||||
if (simpleModel->isEmpty())
|
||||
return;
|
||||
|
||||
QHash<QString, QmlProfilerDataModel::QmlEventData> cachedEvents;
|
||||
QString rootEventName = tr("<program>");
|
||||
QmlProfilerDataModel::QmlEventData rootEvent = {
|
||||
rootEventName,
|
||||
QmlDebug::MaximumMessage,
|
||||
QmlDebug::Binding,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
tr("Main Program"),
|
||||
QmlDebug::QmlEventLocation(rootEventName, 0, 0),
|
||||
0,0,0,0,0 // numericData fields
|
||||
};
|
||||
cachedEvents.insert(rootEventName, rootEvent);
|
||||
|
||||
// for level computation
|
||||
QHash<int, qint64> endtimesPerLevel;
|
||||
int level = QmlDebug::Constants::QML_MIN_LEVEL;
|
||||
endtimesPerLevel[0] = 0;
|
||||
|
||||
const QSet<QString> eventsInBindingLoop = m_eventsModel->eventsInBindingLoop();
|
||||
const QSet<int> &eventsInBindingLoop = m_eventsModel->eventsInBindingLoop();
|
||||
|
||||
// compute parent-child relationship and call count
|
||||
QHash<int, QString> lastParent;
|
||||
//for (int index = fromIndex; index <= toIndex; index++) {
|
||||
QHash<int, int> lastParent;
|
||||
const QVector<QmlProfilerDataModel::QmlEventData> eventList = simpleModel->getEvents();
|
||||
const QVector<QmlProfilerDataModel::QmlEventTypeData> typesList = simpleModel->getEventTypes();
|
||||
foreach (const QmlProfilerDataModel::QmlEventData &event, eventList) {
|
||||
// whitelist
|
||||
if (!m_eventsModel->eventTypeAccepted(event.rangeType))
|
||||
if (!m_eventsModel->eventTypeAccepted(typesList[event.typeIndex].rangeType))
|
||||
continue;
|
||||
|
||||
// level computation
|
||||
@@ -385,40 +341,26 @@ void QmlProfilerEventParentsModelProxy::loadData()
|
||||
}
|
||||
endtimesPerLevel[level] = event.startTime + event.duration;
|
||||
|
||||
|
||||
QString parentHash = rootEventName;
|
||||
QString eventHash = QmlProfilerDataModel::getHashString(event);
|
||||
|
||||
// save in cache
|
||||
if (!cachedEvents.contains(eventHash))
|
||||
cachedEvents.insert(eventHash, event);
|
||||
|
||||
int parentTypeIndex = -1;
|
||||
if (level > QmlDebug::Constants::QML_MIN_LEVEL && lastParent.contains(level-1))
|
||||
parentHash = lastParent[level-1];
|
||||
parentTypeIndex = lastParent[level-1];
|
||||
|
||||
QmlProfilerDataModel::QmlEventData *parentEvent = &(cachedEvents[parentHash]);
|
||||
|
||||
// generate placeholder if needed
|
||||
if (!m_data.contains(eventHash))
|
||||
m_data.insert(eventHash, QmlEventRelativesMap());
|
||||
|
||||
if (m_data[eventHash].contains(parentHash)) {
|
||||
QmlEventRelativesData *parent = &(m_data[eventHash][parentHash]);
|
||||
parent->calls++;
|
||||
parent->duration += event.duration;
|
||||
QmlEventRelativesMap &relativesMap = m_data[event.typeIndex];
|
||||
QmlEventRelativesMap::Iterator it = relativesMap.find(parentTypeIndex);
|
||||
if (it != relativesMap.end()) {
|
||||
it.value().calls++;
|
||||
it.value().duration += event.duration;
|
||||
} else {
|
||||
m_data[eventHash].insert(parentHash, QmlEventRelativesData());
|
||||
QmlEventRelativesData *parent = &(m_data[eventHash][parentHash]);
|
||||
parent->displayName = parentEvent->displayName;
|
||||
parent->rangeType = parentEvent->rangeType;
|
||||
parent->duration = event.duration;
|
||||
parent->calls = 1;
|
||||
parent->details = parentEvent->data;
|
||||
parent->isBindingLoop = eventsInBindingLoop.contains(parentHash);
|
||||
QmlEventRelativesData parent {
|
||||
event.duration,
|
||||
1,
|
||||
eventsInBindingLoop.contains(parentTypeIndex)
|
||||
};
|
||||
relativesMap.insert(parentTypeIndex, parent);
|
||||
}
|
||||
|
||||
// now lastparent is a string with the hash
|
||||
lastParent[level] = eventHash;
|
||||
// now lastparent is the new type
|
||||
lastParent[level] = event.typeIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,21 +381,20 @@ void QmlProfilerEventChildrenModelProxy::loadData()
|
||||
if (simpleModel->isEmpty())
|
||||
return;
|
||||
|
||||
QString rootEventName = tr("<program>");
|
||||
|
||||
// for level computation
|
||||
QHash<int, qint64> endtimesPerLevel;
|
||||
int level = QmlDebug::Constants::QML_MIN_LEVEL;
|
||||
endtimesPerLevel[0] = 0;
|
||||
|
||||
const QSet<QString> eventsInBindingLoop = m_eventsModel->eventsInBindingLoop();
|
||||
const QSet<int> &eventsInBindingLoop = m_eventsModel->eventsInBindingLoop();
|
||||
|
||||
// compute parent-child relationship and call count
|
||||
QHash<int, QString> lastParent;
|
||||
const QVector<QmlProfilerDataModel::QmlEventData> eventList = simpleModel->getEvents();
|
||||
QHash<int, int> lastParent;
|
||||
const QVector<QmlProfilerDataModel::QmlEventData> &eventList = simpleModel->getEvents();
|
||||
const QVector<QmlProfilerDataModel::QmlEventTypeData> &typesList = simpleModel->getEventTypes();
|
||||
foreach (const QmlProfilerDataModel::QmlEventData &event, eventList) {
|
||||
// whitelist
|
||||
if (!m_eventsModel->eventTypeAccepted(event.rangeType))
|
||||
if (!m_eventsModel->eventTypeAccepted(typesList[event.typeIndex].rangeType))
|
||||
continue;
|
||||
|
||||
// level computation
|
||||
@@ -465,33 +406,27 @@ void QmlProfilerEventChildrenModelProxy::loadData()
|
||||
}
|
||||
endtimesPerLevel[level] = event.startTime + event.duration;
|
||||
|
||||
QString parentHash = rootEventName;
|
||||
QString eventHash = QmlProfilerDataModel::getHashString(event);
|
||||
int parentId = -1;
|
||||
|
||||
if (level > QmlDebug::Constants::QML_MIN_LEVEL && lastParent.contains(level-1))
|
||||
parentHash = lastParent[level-1];
|
||||
parentId = lastParent[level-1];
|
||||
|
||||
// generate placeholder if needed
|
||||
if (!m_data.contains(parentHash))
|
||||
m_data.insert(parentHash, QmlEventRelativesMap());
|
||||
|
||||
if (m_data[parentHash].contains(eventHash)) {
|
||||
QmlEventRelativesData *child = &(m_data[parentHash][eventHash]);
|
||||
child->calls++;
|
||||
child->duration += event.duration;
|
||||
QmlEventRelativesMap &relativesMap = m_data[parentId];
|
||||
QmlEventRelativesMap::Iterator it = relativesMap.find(event.typeIndex);
|
||||
if (it != relativesMap.end()) {
|
||||
it.value().calls++;
|
||||
it.value().duration += event.duration;
|
||||
} else {
|
||||
m_data[parentHash].insert(eventHash, QmlEventRelativesData());
|
||||
QmlEventRelativesData *child = &(m_data[parentHash][eventHash]);
|
||||
child->displayName = event.displayName;
|
||||
child->rangeType = event.rangeType;
|
||||
child->duration = event.duration;
|
||||
child->calls = 1;
|
||||
child->details = event.data;
|
||||
child->isBindingLoop = eventsInBindingLoop.contains(parentHash);
|
||||
QmlEventRelativesData child {
|
||||
event.duration,
|
||||
1,
|
||||
eventsInBindingLoop.contains(parentId)
|
||||
};
|
||||
relativesMap.insert(event.typeIndex, child);
|
||||
}
|
||||
|
||||
// now lastparent is a string with the hash
|
||||
lastParent[level] = eventHash;
|
||||
// now lastparent is the new type
|
||||
lastParent[level] = event.typeIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,14 +49,8 @@ class QmlProfilerEventsModelProxy : public QObject
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct QmlEventStats {
|
||||
QString displayName;
|
||||
QString eventHashStr;
|
||||
QString details;
|
||||
QmlDebug::QmlEventLocation location;
|
||||
QmlDebug::Message message;
|
||||
QmlDebug::RangeType rangeType;
|
||||
int bindingType;
|
||||
|
||||
QmlEventStats() : duration(0), calls(0), minTime(std::numeric_limits<qint64>::max()),
|
||||
maxTime(0), timePerCall(0), percentOfTime(0), medianTime(0), isBindingLoop(false) {}
|
||||
qint64 duration;
|
||||
qint64 calls;
|
||||
qint64 minTime;
|
||||
@@ -74,7 +68,8 @@ public:
|
||||
void setEventTypeAccepted(QmlDebug::RangeType type, bool accepted);
|
||||
bool eventTypeAccepted(QmlDebug::RangeType) const;
|
||||
|
||||
const QList<QmlEventStats> getData() const;
|
||||
const QHash<int, QmlEventStats> &getData() const;
|
||||
const QVector<QmlProfilerDataModel::QmlEventTypeData> &getTypes() const;
|
||||
int count() const;
|
||||
void clear();
|
||||
|
||||
@@ -86,7 +81,7 @@ signals:
|
||||
private:
|
||||
void loadData(qint64 rangeStart = -1, qint64 rangeEnd = -1);
|
||||
|
||||
QSet<QString> eventsInBindingLoop() const;
|
||||
const QSet<int> &eventsInBindingLoop() const;
|
||||
|
||||
private slots:
|
||||
void dataChanged();
|
||||
@@ -104,14 +99,11 @@ class QmlProfilerEventRelativesModelProxy : public QObject
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct QmlEventRelativesData {
|
||||
QString displayName;
|
||||
QmlDebug::RangeType rangeType;
|
||||
qint64 duration;
|
||||
qint64 calls;
|
||||
QString details;
|
||||
bool isBindingLoop;
|
||||
};
|
||||
typedef QHash <QString, QmlEventRelativesData> QmlEventRelativesMap;
|
||||
typedef QHash <int, QmlEventRelativesData> QmlEventRelativesMap;
|
||||
|
||||
QmlProfilerEventRelativesModelProxy(QmlProfilerModelManager *modelManager,
|
||||
QmlProfilerEventsModelProxy *eventsModel,
|
||||
@@ -122,7 +114,8 @@ public:
|
||||
int count() const;
|
||||
void clear();
|
||||
|
||||
const QmlEventRelativesMap getData(const QString &hash) const;
|
||||
const QmlEventRelativesMap &getData(int typeId) const;
|
||||
const QVector<QmlProfilerDataModel::QmlEventTypeData> &getTypes() const;
|
||||
|
||||
protected:
|
||||
virtual void loadData() = 0;
|
||||
@@ -134,7 +127,7 @@ protected slots:
|
||||
void dataChanged();
|
||||
|
||||
protected:
|
||||
QHash <QString, QmlEventRelativesMap> m_data;
|
||||
QHash <int, QmlEventRelativesMap> m_data;
|
||||
QmlProfilerModelManager *m_modelManager;
|
||||
QmlProfilerEventsModelProxy *m_eventsModel;
|
||||
};
|
||||
|
||||
@@ -64,7 +64,21 @@ struct Colors {
|
||||
QColor bindingLoopBackground;
|
||||
};
|
||||
|
||||
struct RootEventType : public QmlProfilerDataModel::QmlEventTypeData {
|
||||
RootEventType()
|
||||
{
|
||||
QString rootEventName = QmlProfilerEventsMainView::tr("<program>");
|
||||
displayName = rootEventName;
|
||||
location = QmlDebug::QmlEventLocation(rootEventName, 1, 1);
|
||||
message = QmlDebug::MaximumMessage;
|
||||
rangeType = QmlDebug::MaximumRangeType;
|
||||
detailType = -1;
|
||||
data = QmlProfilerEventsMainView::tr("Main Program");
|
||||
}
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(Colors, colors)
|
||||
Q_GLOBAL_STATIC(RootEventType, rootEventType)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -130,7 +144,8 @@ QmlProfilerEventsWidget::QmlProfilerEventsWidget(QWidget *parent,
|
||||
|
||||
d->m_eventTree = new QmlProfilerEventsMainView(this, d->modelProxy);
|
||||
connect(d->m_eventTree, SIGNAL(gotoSourceLocation(QString,int,int)), this, SIGNAL(gotoSourceLocation(QString,int,int)));
|
||||
connect(d->m_eventTree, SIGNAL(eventSelected(QString)), this, SIGNAL(eventSelectedByHash(QString)));
|
||||
connect(d->m_eventTree, SIGNAL(eventSelected(int)),
|
||||
this, SIGNAL(eventSelectedByTypeIndex(int)));
|
||||
|
||||
d->m_eventChildren = new QmlProfilerEventRelativesView(
|
||||
profilerModelManager,
|
||||
@@ -140,10 +155,10 @@ QmlProfilerEventsWidget::QmlProfilerEventsWidget(QWidget *parent,
|
||||
profilerModelManager,
|
||||
new QmlProfilerEventParentsModelProxy(profilerModelManager, d->modelProxy, this),
|
||||
this);
|
||||
connect(d->m_eventTree, SIGNAL(eventSelected(QString)), d->m_eventChildren, SLOT(displayEvent(QString)));
|
||||
connect(d->m_eventTree, SIGNAL(eventSelected(QString)), d->m_eventParents, SLOT(displayEvent(QString)));
|
||||
connect(d->m_eventChildren, SIGNAL(eventClicked(QString)), d->m_eventTree, SLOT(selectEvent(QString)));
|
||||
connect(d->m_eventParents, SIGNAL(eventClicked(QString)), d->m_eventTree, SLOT(selectEvent(QString)));
|
||||
connect(d->m_eventTree, SIGNAL(eventSelected(int)), d->m_eventChildren, SLOT(displayEvent(int)));
|
||||
connect(d->m_eventTree, SIGNAL(eventSelected(int)), d->m_eventParents, SLOT(displayEvent(int)));
|
||||
connect(d->m_eventChildren, SIGNAL(eventClicked(int)), d->m_eventTree, SLOT(selectEvent(int)));
|
||||
connect(d->m_eventParents, SIGNAL(eventClicked(int)), d->m_eventTree, SLOT(selectEvent(int)));
|
||||
|
||||
// widget arrangement
|
||||
QVBoxLayout *groupLayout = new QVBoxLayout;
|
||||
@@ -291,10 +306,10 @@ void QmlProfilerEventsWidget::copyRowToClipboard() const
|
||||
d->m_eventTree->copyRowToClipboard();
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::updateSelectedEvent(const QString &eventHash) const
|
||||
void QmlProfilerEventsWidget::updateSelectedEvent(int typeIndex) const
|
||||
{
|
||||
if (d->m_eventTree->selectedEventHash() != eventHash)
|
||||
d->m_eventTree->selectEvent(eventHash);
|
||||
if (d->m_eventTree->selectedTypeIndex() != typeIndex)
|
||||
d->m_eventTree->selectEvent(typeIndex);
|
||||
}
|
||||
|
||||
void QmlProfilerEventsWidget::selectBySourceLocation(const QString &filename, int line, int column)
|
||||
@@ -552,8 +567,15 @@ void QmlProfilerEventsMainView::buildModel()
|
||||
|
||||
void QmlProfilerEventsMainView::parseModelProxy()
|
||||
{
|
||||
const QList <QmlProfilerEventsModelProxy::QmlEventStats> eventList = d->modelProxy->getData();
|
||||
foreach (const QmlProfilerEventsModelProxy::QmlEventStats &event, eventList) {
|
||||
const QHash<int, QmlProfilerEventsModelProxy::QmlEventStats> &eventList = d->modelProxy->getData();
|
||||
const QVector<QmlProfilerDataModel::QmlEventTypeData> &typeList = d->modelProxy->getTypes();
|
||||
|
||||
QHash<int, QmlProfilerEventsModelProxy::QmlEventStats>::ConstIterator it;
|
||||
for (it = eventList.constBegin(); it != eventList.constEnd(); ++it) {
|
||||
int typeIndex = it.key();
|
||||
const QmlProfilerEventsModelProxy::QmlEventStats &stats = it.value();
|
||||
const QmlProfilerDataModel::QmlEventTypeData &event =
|
||||
(typeIndex != -1 ? typeList[typeIndex] : *rootEventType());
|
||||
QStandardItem *parentItem = d->m_model->invisibleRootItem();
|
||||
QList<QStandardItem *> newRow;
|
||||
|
||||
@@ -564,10 +586,10 @@ void QmlProfilerEventsMainView::parseModelProxy()
|
||||
QString typeString = QmlProfilerEventsMainView::nameForType(event.rangeType);
|
||||
QString toolTipText;
|
||||
if (event.rangeType == Binding) {
|
||||
if (event.bindingType == (int)OptimizedBinding) {
|
||||
if (event.detailType == (int)OptimizedBinding) {
|
||||
typeString = typeString + QLatin1Char(' ') + tr("(Opt)");
|
||||
toolTipText = tr("Binding is evaluated by the optimized engine.");
|
||||
} else if (event.bindingType == (int)V8Binding) {
|
||||
} else if (event.detailType == (int)V8Binding) {
|
||||
toolTipText = tr("Binding not optimized (might have side effects or assignments,\n"
|
||||
"references to elements in other files, loops, and so on.)");
|
||||
|
||||
@@ -580,43 +602,43 @@ void QmlProfilerEventsMainView::parseModelProxy()
|
||||
}
|
||||
|
||||
if (d->m_fieldShown[TimeInPercent]) {
|
||||
newRow << new EventsViewItem(QString::number(event.percentOfTime,'f',2)+QLatin1String(" %"));
|
||||
newRow.last()->setData(QVariant(event.percentOfTime));
|
||||
newRow << new EventsViewItem(QString::number(stats.percentOfTime,'f',2)+QLatin1String(" %"));
|
||||
newRow.last()->setData(QVariant(stats.percentOfTime));
|
||||
}
|
||||
|
||||
if (d->m_fieldShown[TotalTime]) {
|
||||
newRow << new EventsViewItem(QmlProfilerBaseModel::formatTime(event.duration));
|
||||
newRow.last()->setData(QVariant(event.duration));
|
||||
newRow << new EventsViewItem(QmlProfilerBaseModel::formatTime(stats.duration));
|
||||
newRow.last()->setData(QVariant(stats.duration));
|
||||
}
|
||||
|
||||
if (d->m_fieldShown[CallCount]) {
|
||||
newRow << new EventsViewItem(QString::number(event.calls));
|
||||
newRow.last()->setData(QVariant(event.calls));
|
||||
newRow << new EventsViewItem(QString::number(stats.calls));
|
||||
newRow.last()->setData(QVariant(stats.calls));
|
||||
}
|
||||
|
||||
if (d->m_fieldShown[TimePerCall]) {
|
||||
newRow << new EventsViewItem(QmlProfilerBaseModel::formatTime(event.timePerCall));
|
||||
newRow.last()->setData(QVariant(event.timePerCall));
|
||||
newRow << new EventsViewItem(QmlProfilerBaseModel::formatTime(stats.timePerCall));
|
||||
newRow.last()->setData(QVariant(stats.timePerCall));
|
||||
}
|
||||
|
||||
if (d->m_fieldShown[MedianTime]) {
|
||||
newRow << new EventsViewItem(QmlProfilerBaseModel::formatTime(event.medianTime));
|
||||
newRow.last()->setData(QVariant(event.medianTime));
|
||||
newRow << new EventsViewItem(QmlProfilerBaseModel::formatTime(stats.medianTime));
|
||||
newRow.last()->setData(QVariant(stats.medianTime));
|
||||
}
|
||||
|
||||
if (d->m_fieldShown[MaxTime]) {
|
||||
newRow << new EventsViewItem(QmlProfilerBaseModel::formatTime(event.maxTime));
|
||||
newRow.last()->setData(QVariant(event.maxTime));
|
||||
newRow << new EventsViewItem(QmlProfilerBaseModel::formatTime(stats.maxTime));
|
||||
newRow.last()->setData(QVariant(stats.maxTime));
|
||||
}
|
||||
|
||||
if (d->m_fieldShown[MinTime]) {
|
||||
newRow << new EventsViewItem(QmlProfilerBaseModel::formatTime(event.minTime));
|
||||
newRow.last()->setData(QVariant(event.minTime));
|
||||
newRow << new EventsViewItem(QmlProfilerBaseModel::formatTime(stats.minTime));
|
||||
newRow.last()->setData(QVariant(stats.minTime));
|
||||
}
|
||||
|
||||
if (d->m_fieldShown[Details]) {
|
||||
newRow << new EventsViewItem(event.details);
|
||||
newRow.last()->setData(QVariant(event.details));
|
||||
newRow << new EventsViewItem(event.data);
|
||||
newRow.last()->setData(QVariant(event.data));
|
||||
}
|
||||
|
||||
|
||||
@@ -627,12 +649,12 @@ void QmlProfilerEventsMainView::parseModelProxy()
|
||||
item->setEditable(false);
|
||||
|
||||
// metadata
|
||||
newRow.at(0)->setData(QVariant(event.eventHashStr),EventHashStrRole);
|
||||
newRow.at(0)->setData(QVariant(typeIndex),EventTypeIndexRole);
|
||||
newRow.at(0)->setData(QVariant(event.location.filename),FilenameRole);
|
||||
newRow.at(0)->setData(QVariant(event.location.line),LineRole);
|
||||
newRow.at(0)->setData(QVariant(event.location.column),ColumnRole);
|
||||
|
||||
if (event.isBindingLoop) {
|
||||
if (stats.isBindingLoop) {
|
||||
foreach (QStandardItem *item, newRow) {
|
||||
item->setBackground(colors()->bindingLoopBackground);
|
||||
item->setToolTip(tr("Binding loop detected."));
|
||||
@@ -663,13 +685,13 @@ void QmlProfilerEventsMainView::getStatisticsInRange(qint64 rangeStart, qint64 r
|
||||
d->modelProxy->limitToRange(rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
QString QmlProfilerEventsMainView::selectedEventHash() const
|
||||
int QmlProfilerEventsMainView::selectedTypeIndex() const
|
||||
{
|
||||
QModelIndex index = selectedItem();
|
||||
if (!index.isValid())
|
||||
return QString();
|
||||
return -1;
|
||||
QStandardItem *item = d->m_model->item(index.row(), 0);
|
||||
return item->data(EventHashStrRole).toString();
|
||||
return item->data(EventTypeIndexRole).toInt();
|
||||
}
|
||||
|
||||
|
||||
@@ -694,7 +716,7 @@ void QmlProfilerEventsMainView::jumpToItem(const QModelIndex &index)
|
||||
emit gotoSourceLocation(fileName, line, column);
|
||||
|
||||
// show in callers/callees subwindow
|
||||
emit eventSelected(infoItem->data(EventHashStrRole).toString());
|
||||
emit eventSelected(infoItem->data(EventTypeIndexRole).toInt());
|
||||
|
||||
d->m_preventSelectBounce = false;
|
||||
}
|
||||
@@ -709,11 +731,11 @@ void QmlProfilerEventsMainView::selectItem(const QStandardItem *item)
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerEventsMainView::selectEvent(const QString &eventHash)
|
||||
void QmlProfilerEventsMainView::selectEvent(int typeIndex)
|
||||
{
|
||||
for (int i=0; i<d->m_model->rowCount(); i++) {
|
||||
QStandardItem *infoItem = d->m_model->item(i, 0);
|
||||
if (infoItem->data(EventHashStrRole).toString() == eventHash) {
|
||||
if (infoItem->data(EventTypeIndexRole).toInt() == typeIndex) {
|
||||
selectItem(infoItem);
|
||||
return;
|
||||
}
|
||||
@@ -842,9 +864,9 @@ QmlProfilerEventRelativesView::~QmlProfilerEventRelativesView()
|
||||
delete d;
|
||||
}
|
||||
|
||||
void QmlProfilerEventRelativesView::displayEvent(const QString &eventHash)
|
||||
void QmlProfilerEventRelativesView::displayEvent(int typeIndex)
|
||||
{
|
||||
rebuildTree(d->modelProxy->getData(eventHash));
|
||||
rebuildTree(d->modelProxy->getData(typeIndex));
|
||||
|
||||
updateHeader();
|
||||
resizeColumnToContents(0);
|
||||
@@ -852,27 +874,33 @@ void QmlProfilerEventRelativesView::displayEvent(const QString &eventHash)
|
||||
sortByColumn(2);
|
||||
}
|
||||
|
||||
void QmlProfilerEventRelativesView::rebuildTree(QmlProfilerEventRelativesModelProxy::QmlEventRelativesMap eventMap)
|
||||
void QmlProfilerEventRelativesView::rebuildTree(
|
||||
const QmlProfilerEventRelativesModelProxy::QmlEventRelativesMap &eventMap)
|
||||
{
|
||||
Q_ASSERT(treeModel());
|
||||
treeModel()->clear();
|
||||
|
||||
QStandardItem *topLevelItem = treeModel()->invisibleRootItem();
|
||||
const QVector<QmlProfilerDataModel::QmlEventTypeData> &typeList = d->modelProxy->getTypes();
|
||||
|
||||
foreach (const QString &key, eventMap.keys()) {
|
||||
const QmlProfilerEventRelativesModelProxy::QmlEventRelativesData &event = eventMap[key];
|
||||
QmlProfilerEventRelativesModelProxy::QmlEventRelativesMap::const_iterator it;
|
||||
for (it = eventMap.constBegin(); it != eventMap.constEnd(); ++it) {
|
||||
const QmlProfilerEventRelativesModelProxy::QmlEventRelativesData &event = it.value();
|
||||
int typeIndex = it.key();
|
||||
const QmlProfilerDataModel::QmlEventTypeData &type =
|
||||
(typeIndex != -1 ? typeList[typeIndex] : *rootEventType());
|
||||
QList<QStandardItem *> newRow;
|
||||
|
||||
// ToDo: here we were going to search for the data in the other modelproxy
|
||||
// maybe we should store the data in this proxy and get it here
|
||||
// no indirections at this level of abstraction!
|
||||
newRow << new EventsViewItem(event.displayName);
|
||||
newRow << new EventsViewItem(QmlProfilerEventsMainView::nameForType(event.rangeType));
|
||||
newRow << new EventsViewItem(type.displayName);
|
||||
newRow << new EventsViewItem(QmlProfilerEventsMainView::nameForType(type.rangeType));
|
||||
newRow << new EventsViewItem(QmlProfilerBaseModel::formatTime(event.duration));
|
||||
newRow << new EventsViewItem(QString::number(event.calls));
|
||||
newRow << new EventsViewItem(event.details);
|
||||
newRow << new EventsViewItem(type.data);
|
||||
|
||||
newRow.at(0)->setData(QVariant(key), EventHashStrRole);
|
||||
newRow.at(0)->setData(QVariant(typeIndex), EventTypeIndexRole);
|
||||
newRow.at(2)->setData(QVariant(event.duration));
|
||||
newRow.at(3)->setData(QVariant(event.calls));
|
||||
|
||||
@@ -934,7 +962,7 @@ void QmlProfilerEventRelativesView::jumpToItem(const QModelIndex &index)
|
||||
{
|
||||
if (treeModel()) {
|
||||
QStandardItem *infoItem = treeModel()->item(index.row(), 0);
|
||||
emit eventClicked(infoItem->data(EventHashStrRole).toString());
|
||||
emit eventClicked(infoItem->data(EventTypeIndexRole).toInt());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class QmlProfilerEventChildrenView;
|
||||
class QmlProfilerEventRelativesView;
|
||||
|
||||
enum ItemRole {
|
||||
EventHashStrRole = Qt::UserRole+1,
|
||||
EventTypeIndexRole = Qt::UserRole+1,
|
||||
FilenameRole = Qt::UserRole+2,
|
||||
LineRole = Qt::UserRole+3,
|
||||
ColumnRole = Qt::UserRole+4,
|
||||
@@ -85,11 +85,11 @@ public:
|
||||
|
||||
signals:
|
||||
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
|
||||
void eventSelectedByHash(const QString &eventHash);
|
||||
void eventSelectedByTypeIndex(int typeIndex);
|
||||
void resized();
|
||||
|
||||
public slots:
|
||||
void updateSelectedEvent(const QString &eventHash) const;
|
||||
void updateSelectedEvent(int typeIndex) const;
|
||||
void selectBySourceLocation(const QString &filename, int line, int column);
|
||||
|
||||
private slots:
|
||||
@@ -122,7 +122,7 @@ public:
|
||||
static QString nameForType(QmlDebug::RangeType typeNumber);
|
||||
|
||||
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
|
||||
QString selectedEventHash() const;
|
||||
int selectedTypeIndex() const;
|
||||
|
||||
void setShowExtendedStatistics(bool);
|
||||
bool showExtendedStatistics() const;
|
||||
@@ -130,12 +130,12 @@ public:
|
||||
|
||||
signals:
|
||||
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
|
||||
void eventSelected(const QString &eventHash);
|
||||
void eventSelected(int typeIndex);
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
void jumpToItem(const QModelIndex &index);
|
||||
void selectEvent(const QString &eventHash);
|
||||
void selectEvent(int typeIndex);
|
||||
void selectEventByLocation(const QString &filename, int line, int column);
|
||||
void buildModel();
|
||||
|
||||
@@ -163,15 +163,15 @@ public:
|
||||
~QmlProfilerEventRelativesView();
|
||||
|
||||
signals:
|
||||
void eventClicked(const QString &eventHash);
|
||||
void eventClicked(int typeIndex);
|
||||
|
||||
public slots:
|
||||
void displayEvent(const QString &eventHash);
|
||||
void displayEvent(int typeIndex);
|
||||
void jumpToItem(const QModelIndex &);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
void rebuildTree(QmlProfilerEventParentsModelProxy::QmlEventRelativesMap eventMap);
|
||||
void rebuildTree(const QmlProfilerEventParentsModelProxy::QmlEventRelativesMap &eventMap);
|
||||
void updateHeader();
|
||||
QStandardItemModel *treeModel();
|
||||
|
||||
|
||||
@@ -322,7 +322,7 @@ void QmlProfilerModelManager::save(const QString &filename)
|
||||
|
||||
writer.setTraceTime(traceTime()->startTime(), traceTime()->endTime(), traceTime()->duration());
|
||||
writer.setV8DataModel(d->v8Model);
|
||||
writer.setQmlEvents(d->model->getEvents());
|
||||
writer.setQmlEvents(d->model->getEventTypes(), d->model->getEvents());
|
||||
writer.save(&file);
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ void PaintEventsModelProxy::clear()
|
||||
d->modelManager->modelProxyCountUpdated(d->modelId, 0, 1);
|
||||
}
|
||||
|
||||
bool PaintEventsModelProxy::eventAccepted(const QmlProfilerDataModel::QmlEventData &event) const
|
||||
bool PaintEventsModelProxy::eventAccepted(const QmlProfilerDataModel::QmlEventTypeData &event) const
|
||||
{
|
||||
return AbstractTimelineModel::eventAccepted(event) &&
|
||||
event.detailType== QmlDebug::AnimationFrame;
|
||||
@@ -96,14 +96,16 @@ void PaintEventsModelProxy::loadData()
|
||||
return;
|
||||
|
||||
// collect events
|
||||
const QVector<QmlProfilerDataModel::QmlEventData> referenceList = simpleModel->getEvents();
|
||||
const QVector<QmlProfilerDataModel::QmlEventData> &referenceList = simpleModel->getEvents();
|
||||
const QVector<QmlProfilerDataModel::QmlEventTypeData> &typeList = simpleModel->getEventTypes();
|
||||
|
||||
QmlPaintEventData lastEvent;
|
||||
qint64 minNextStartTimes[] = {0, 0};
|
||||
|
||||
foreach (const QmlProfilerDataModel::QmlEventData &event, referenceList) {
|
||||
if (!eventAccepted(event)) {
|
||||
if (event.rangeType == QmlDebug::Painting)
|
||||
const QmlProfilerDataModel::QmlEventTypeData &type = typeList[event.typeIndex];
|
||||
if (!eventAccepted(type)) {
|
||||
if (type.rangeType == QmlDebug::Painting)
|
||||
d->seenForeignPaintEvent = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
Q_INVOKABLE const QVariantList getEventDetails(int index) const;
|
||||
|
||||
private slots:
|
||||
bool eventAccepted(const QmlProfilerDataModel::QmlEventData &event) const;
|
||||
bool eventAccepted(const QmlProfilerDataModel::QmlEventTypeData &event) const;
|
||||
|
||||
private:
|
||||
class PaintEventsModelProxyPrivate;
|
||||
|
||||
@@ -55,9 +55,7 @@ public:
|
||||
void computeExpandedLevels();
|
||||
void findBindingLoops();
|
||||
|
||||
QVector <RangeTimelineModel::QmlRangeEventData> eventDict;
|
||||
QVector <QString> eventHashes;
|
||||
int expandedRows;
|
||||
QVector<int> expandedRowTypes;
|
||||
int contractedRows;
|
||||
bool seenPaintEvent;
|
||||
private:
|
||||
@@ -71,7 +69,8 @@ RangeTimelineModel::RangeTimelineModel(QmlDebug::RangeType rangeType, QObject *p
|
||||
{
|
||||
Q_D(RangeTimelineModel);
|
||||
d->seenPaintEvent = false;
|
||||
d->expandedRows = 1;
|
||||
d->expandedRowTypes.clear();
|
||||
d->expandedRowTypes << -1;
|
||||
d->contractedRows = 1;
|
||||
}
|
||||
|
||||
@@ -79,9 +78,8 @@ void RangeTimelineModel::clear()
|
||||
{
|
||||
Q_D(RangeTimelineModel);
|
||||
d->clear();
|
||||
d->eventDict.clear();
|
||||
d->eventHashes.clear();
|
||||
d->expandedRows = 1;
|
||||
d->expandedRowTypes.clear();
|
||||
d->expandedRowTypes << -1;
|
||||
d->contractedRows = 1;
|
||||
d->seenPaintEvent = false;
|
||||
d->expanded = false;
|
||||
@@ -97,40 +95,18 @@ void RangeTimelineModel::loadData()
|
||||
if (simpleModel->isEmpty())
|
||||
return;
|
||||
|
||||
int lastEventId = 0;
|
||||
|
||||
QMap<QString, int> eventIdsByHash;
|
||||
|
||||
// collect events
|
||||
const QVector<QmlProfilerDataModel::QmlEventData> eventList = simpleModel->getEvents();
|
||||
const QVector<QmlProfilerDataModel::QmlEventData> &eventList = simpleModel->getEvents();
|
||||
const QVector<QmlProfilerDataModel::QmlEventTypeData> &typesList = simpleModel->getEventTypes();
|
||||
foreach (const QmlProfilerDataModel::QmlEventData &event, eventList) {
|
||||
if (!eventAccepted(event))
|
||||
const QmlProfilerDataModel::QmlEventTypeData &type = typesList[event.typeIndex];
|
||||
if (!eventAccepted(type))
|
||||
continue;
|
||||
if (event.rangeType == QmlDebug::Painting)
|
||||
if (type.rangeType == QmlDebug::Painting)
|
||||
d->seenPaintEvent = true;
|
||||
|
||||
QString eventHash = QmlProfilerDataModel::getHashString(event);
|
||||
|
||||
// store in dictionary
|
||||
int eventId;
|
||||
QMap<QString, int>::const_iterator i = eventIdsByHash.constFind(eventHash);
|
||||
if (i == eventIdsByHash.cend()) {
|
||||
QmlRangeEventData rangeEventData = {
|
||||
event.displayName,
|
||||
event.data,
|
||||
event.location,
|
||||
lastEventId++ // event id
|
||||
};
|
||||
d->eventDict << rangeEventData;
|
||||
eventId = d->eventHashes.size();
|
||||
eventIdsByHash.insert(eventHash, eventId);
|
||||
d->eventHashes << eventHash;
|
||||
} else {
|
||||
eventId = i.value();
|
||||
}
|
||||
|
||||
// store starttime-based instance
|
||||
d->insert(event.startTime, event.duration, QmlRangeEventStartInstance(eventId));
|
||||
d->insert(event.startTime, event.duration, QmlRangeEventStartInstance(event.typeIndex));
|
||||
|
||||
d->modelManager->modelProxyCountUpdated(d->modelId, d->count(), eventList.count() * 6);
|
||||
}
|
||||
@@ -194,7 +170,8 @@ void RangeTimelineModel::RangeTimelineModelPrivate::computeExpandedLevels()
|
||||
for (int i = 0; i < eventCount; i++) {
|
||||
int eventId = ranges[i].eventId;
|
||||
if (!eventRow.contains(eventId)) {
|
||||
eventRow[eventId] = expandedRows++;
|
||||
eventRow[eventId] = expandedRowTypes.length();
|
||||
expandedRowTypes << eventId;
|
||||
}
|
||||
ranges[i].displayRowExpanded = eventRow[eventId];
|
||||
}
|
||||
@@ -205,13 +182,12 @@ void RangeTimelineModel::RangeTimelineModelPrivate::findBindingLoops()
|
||||
if (rangeType != QmlDebug::Binding && rangeType != QmlDebug::HandlingSignal)
|
||||
return;
|
||||
|
||||
typedef QPair<QString, int> CallStackEntry;
|
||||
typedef QPair<int, int> CallStackEntry;
|
||||
QStack<CallStackEntry> callStack;
|
||||
|
||||
for (int i = 0; i < count(); ++i) {
|
||||
Range *event = &ranges[i];
|
||||
|
||||
const QString eventHash = eventHashes.at(event->eventId);
|
||||
const Range *potentialParent = callStack.isEmpty()
|
||||
? 0 : &ranges[callStack.top().second];
|
||||
|
||||
@@ -224,14 +200,14 @@ void RangeTimelineModel::RangeTimelineModelPrivate::findBindingLoops()
|
||||
|
||||
// check whether event is already in stack
|
||||
for (int ii = 0; ii < callStack.size(); ++ii) {
|
||||
if (callStack.at(ii).first == eventHash) {
|
||||
if (callStack.at(ii).first == event->eventId) {
|
||||
event->bindingLoopHead = callStack.at(ii).second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CallStackEntry newEntry(eventHash, i);
|
||||
CallStackEntry newEntry(event->eventId, i);
|
||||
callStack.push(newEntry);
|
||||
}
|
||||
|
||||
@@ -246,7 +222,7 @@ int RangeTimelineModel::rowCount() const
|
||||
if (d->rangeType == QmlDebug::Painting && !d->seenPaintEvent)
|
||||
return 0;
|
||||
if (d->expanded)
|
||||
return d->expandedRows;
|
||||
return d->expandedRowTypes.length();
|
||||
else
|
||||
return d->contractedRows;
|
||||
}
|
||||
@@ -296,12 +272,15 @@ const QVariantList RangeTimelineModel::getLabels() const
|
||||
QVariantList result;
|
||||
|
||||
if (d->expanded) {
|
||||
int eventCount = d->eventDict.count();
|
||||
for (int i = 0; i < eventCount; i++) {
|
||||
const QVector<QmlProfilerDataModel::QmlEventTypeData> &types =
|
||||
d->modelManager->qmlModel()->getEventTypes();
|
||||
int eventCount = d->expandedRowTypes.count();
|
||||
for (int i = 1; i < eventCount; i++) { // Ignore the -1 for the first row
|
||||
QVariantMap element;
|
||||
element.insert(QLatin1String("displayName"), QVariant(d->eventDict[i].displayName));
|
||||
element.insert(QLatin1String("description"), QVariant(d->eventDict[i].details));
|
||||
element.insert(QLatin1String("id"), QVariant(d->eventDict[i].eventId));
|
||||
int typeId = d->expandedRowTypes[i];
|
||||
element.insert(QLatin1String("displayName"), QVariant(types[typeId].displayName));
|
||||
element.insert(QLatin1String("description"), QVariant(types[typeId].data));
|
||||
element.insert(QLatin1String("id"), QVariant(typeId));
|
||||
result << element;
|
||||
}
|
||||
}
|
||||
@@ -314,6 +293,8 @@ const QVariantList RangeTimelineModel::getEventDetails(int index) const
|
||||
Q_D(const RangeTimelineModel);
|
||||
QVariantList result;
|
||||
int eventId = getEventId(index);
|
||||
const QVector<QmlProfilerDataModel::QmlEventTypeData> &types =
|
||||
d->modelManager->qmlModel()->getEventTypes();
|
||||
|
||||
static const char trContext[] = "RangeDetails";
|
||||
{
|
||||
@@ -333,17 +314,19 @@ const QVariantList RangeTimelineModel::getEventDetails(int index) const
|
||||
// details
|
||||
{
|
||||
QVariantMap valuePair;
|
||||
QString detailsString = d->eventDict[eventId].details;
|
||||
QString detailsString = types[eventId].data;
|
||||
if (detailsString.length() > 40)
|
||||
detailsString = detailsString.left(40) + QLatin1String("...");
|
||||
valuePair.insert(QCoreApplication::translate(trContext, "Details:"), QVariant(detailsString));
|
||||
valuePair.insert(QCoreApplication::translate(trContext, "Details:"),
|
||||
QVariant(detailsString));
|
||||
result << valuePair;
|
||||
}
|
||||
|
||||
// location
|
||||
{
|
||||
QVariantMap valuePair;
|
||||
valuePair.insert(QCoreApplication::translate(trContext, "Location:"), QVariant(d->eventDict[eventId].displayName));
|
||||
valuePair.insert(QCoreApplication::translate(trContext, "Location:"),
|
||||
QVariant(types[eventId].displayName));
|
||||
result << valuePair;
|
||||
}
|
||||
|
||||
@@ -361,7 +344,7 @@ const QVariantMap RangeTimelineModel::getEventLocation(int index) const
|
||||
int eventId = getEventId(index);
|
||||
|
||||
QmlDebug::QmlEventLocation location
|
||||
= d->eventDict.at(eventId).location;
|
||||
= d->modelManager->qmlModel()->getEventTypes().at(eventId).location;
|
||||
|
||||
result.insert(QLatin1String("file"), location.filename);
|
||||
result.insert(QLatin1String("line"), location.line);
|
||||
@@ -370,21 +353,31 @@ const QVariantMap RangeTimelineModel::getEventLocation(int index) const
|
||||
return result;
|
||||
}
|
||||
|
||||
int RangeTimelineModel::getEventIdForHash(const QString &eventHash) const
|
||||
int RangeTimelineModel::getEventIdForTypeIndex(int typeIndex) const
|
||||
{
|
||||
Q_D(const RangeTimelineModel);
|
||||
return d->eventHashes.indexOf(eventHash);
|
||||
if (typeIndex < 0)
|
||||
return -1;
|
||||
const QmlProfilerDataModel::QmlEventTypeData &type =
|
||||
d->modelManager->qmlModel()->getEventTypes().at(typeIndex);
|
||||
if (type.message != d->message || type.rangeType != d->rangeType)
|
||||
return -1;
|
||||
return typeIndex;
|
||||
}
|
||||
|
||||
int RangeTimelineModel::getEventIdForLocation(const QString &filename, int line, int column) const
|
||||
{
|
||||
Q_D(const RangeTimelineModel);
|
||||
// if this is called from v8 view, we don't have the column number, it will be -1
|
||||
foreach (const QmlRangeEventData &eventData, d->eventDict) {
|
||||
const QVector<QmlProfilerDataModel::QmlEventTypeData> &types =
|
||||
d->modelManager->qmlModel()->getEventTypes();
|
||||
for (int i = 0; i < d->expandedRowTypes.length(); ++i) {
|
||||
int typeId = d->expandedRowTypes[i];
|
||||
const QmlProfilerDataModel::QmlEventTypeData &eventData = types[typeId];
|
||||
if (eventData.location.filename == filename &&
|
||||
eventData.location.line == line &&
|
||||
(column == -1 || eventData.location.column == column))
|
||||
return eventData.eventId;
|
||||
return typeId;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -47,13 +47,6 @@ class RangeTimelineModel : public AbstractTimelineModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct QmlRangeEventData
|
||||
{
|
||||
QString displayName;
|
||||
QString details;
|
||||
QmlDebug::QmlEventLocation location;
|
||||
int eventId; // separate
|
||||
};
|
||||
|
||||
struct QmlRangeEventStartInstance {
|
||||
QmlRangeEventStartInstance(int eventId = -1) :
|
||||
@@ -90,7 +83,7 @@ public:
|
||||
Q_INVOKABLE const QVariantList getEventDetails(int index) const;
|
||||
Q_INVOKABLE const QVariantMap getEventLocation(int index) const;
|
||||
|
||||
Q_INVOKABLE int getEventIdForHash(const QString &eventHash) const;
|
||||
Q_INVOKABLE int getEventIdForTypeIndex(int typeIndex) const;
|
||||
Q_INVOKABLE int getEventIdForLocation(const QString &filename, int line, int column) const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -193,17 +193,15 @@ void QmlProfilerFileReader::loadEventData(QXmlStreamReader &stream)
|
||||
QXmlStreamAttributes attributes = stream.attributes();
|
||||
|
||||
int eventIndex = -1;
|
||||
QmlEvent event = {
|
||||
QmlProfilerDataModel::QmlEventTypeData event = {
|
||||
QString(), // displayname
|
||||
QString(), // filename
|
||||
QString(), // details
|
||||
QmlEventLocation(),
|
||||
MaximumMessage,
|
||||
Painting, // type
|
||||
QmlBinding, // bindingType, set for backwards compatibility
|
||||
0, // line
|
||||
0 // column
|
||||
QString(), // details
|
||||
};
|
||||
const QmlEvent defaultEvent = event;
|
||||
const QmlProfilerDataModel::QmlEventTypeData defaultEvent = event;
|
||||
|
||||
while (!stream.atEnd() && !stream.hasError()) {
|
||||
QXmlStreamReader::TokenType token = stream.readNext();
|
||||
@@ -243,22 +241,22 @@ void QmlProfilerFileReader::loadEventData(QXmlStreamReader &stream)
|
||||
}
|
||||
|
||||
if (elementName == _("filename")) {
|
||||
event.filename = readData;
|
||||
event.location.filename = readData;
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == _("line")) {
|
||||
event.line = readData.toInt();
|
||||
event.location.line = readData.toInt();
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == _("column")) {
|
||||
event.column = readData.toInt();
|
||||
event.location.column = readData.toInt();
|
||||
break;
|
||||
}
|
||||
|
||||
if (elementName == _("details")) {
|
||||
event.details = readData;
|
||||
event.data = readData;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -316,7 +314,7 @@ void QmlProfilerFileReader::loadProfilerDataModel(QXmlStreamReader &stream)
|
||||
switch (token) {
|
||||
case QXmlStreamReader::StartElement: {
|
||||
if (elementName == _("range")) {
|
||||
Range range = { 0, 0, 0, 0, 0, 0, 0 };
|
||||
QmlProfilerDataModel::QmlEventData range = { -1, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
const QXmlStreamAttributes attributes = stream.attributes();
|
||||
if (!attributes.hasAttribute(_("startTime"))
|
||||
@@ -353,11 +351,9 @@ void QmlProfilerFileReader::loadProfilerDataModel(QXmlStreamReader &stream)
|
||||
if (attributes.hasAttribute(_("timing5")))
|
||||
range.numericData5 = attributes.value(_("timing5")).toString().toLongLong();
|
||||
|
||||
range.typeIndex = attributes.value(_("eventIndex")).toString().toInt();
|
||||
|
||||
int eventIndex = attributes.value(_("eventIndex")).toString().toInt();
|
||||
|
||||
|
||||
m_ranges.append(QPair<Range,int>(range, eventIndex));
|
||||
m_ranges.append(range);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -376,8 +372,8 @@ void QmlProfilerFileReader::loadProfilerDataModel(QXmlStreamReader &stream)
|
||||
void QmlProfilerFileReader::processQmlEvents()
|
||||
{
|
||||
for (int i = 0; i < m_ranges.size(); ++i) {
|
||||
Range range = m_ranges[i].first;
|
||||
int eventIndex = m_ranges[i].second;
|
||||
const QmlProfilerDataModel::QmlEventData &range = m_ranges[i];
|
||||
int eventIndex = range.typeIndex;
|
||||
|
||||
if (eventIndex < 0 || eventIndex >= m_qmlEvents.size()) {
|
||||
qWarning() << ".qtd file - range index" << eventIndex
|
||||
@@ -385,11 +381,10 @@ void QmlProfilerFileReader::processQmlEvents()
|
||||
continue;
|
||||
}
|
||||
|
||||
QmlEvent &event = m_qmlEvents[eventIndex];
|
||||
const QmlProfilerDataModel::QmlEventTypeData &event = m_qmlEvents[eventIndex];
|
||||
|
||||
emit rangedEvent(event.message, event.rangeType, event.detailType, range.startTime,
|
||||
range.duration, event.details,
|
||||
QmlEventLocation(event.filename, event.line, event.column),
|
||||
range.duration, event.data, event.location,
|
||||
range.numericData1,range.numericData2, range.numericData3,
|
||||
range.numericData4, range.numericData5);
|
||||
|
||||
@@ -420,29 +415,12 @@ void QmlProfilerFileWriter::setV8DataModel(QV8ProfilerDataModel *dataModel)
|
||||
m_v8Model = dataModel;
|
||||
}
|
||||
|
||||
void QmlProfilerFileWriter::setQmlEvents(const QVector<QmlProfilerDataModel::QmlEventData> &events)
|
||||
void QmlProfilerFileWriter::setQmlEvents(const QVector<QmlProfilerDataModel::QmlEventTypeData> &types,
|
||||
const QVector<QmlProfilerDataModel::QmlEventData> &events)
|
||||
{
|
||||
foreach (const QmlProfilerDataModel::QmlEventData &event, events) {
|
||||
const QString hashStr = QmlProfilerDataModel::getHashString(event);
|
||||
if (!m_qmlEvents.contains(hashStr)) {
|
||||
QmlEvent e = {
|
||||
event.displayName,
|
||||
event.location.filename,
|
||||
event.data,
|
||||
event.message,
|
||||
event.rangeType,
|
||||
event.detailType,
|
||||
event.location.line,
|
||||
event.location.column
|
||||
};
|
||||
m_qmlEvents.insert(hashStr, e);
|
||||
}
|
||||
|
||||
Range r = { event.startTime, event.duration, event.numericData1, event.numericData2, event.numericData3, event.numericData4, event.numericData5 };
|
||||
m_ranges.append(QPair<Range, QString>(r, hashStr));
|
||||
}
|
||||
|
||||
calculateMeasuredTime(events);
|
||||
m_qmlEvents = types;
|
||||
m_ranges = events;
|
||||
calculateMeasuredTime();
|
||||
}
|
||||
|
||||
void QmlProfilerFileWriter::save(QIODevice *device)
|
||||
@@ -461,25 +439,19 @@ void QmlProfilerFileWriter::save(QIODevice *device)
|
||||
stream.writeStartElement(_("eventData"));
|
||||
stream.writeAttribute(_("totalTime"), QString::number(m_measuredTime));
|
||||
|
||||
QMap<QString, QString> keys;
|
||||
int i = 0;
|
||||
foreach (const QString &key, m_qmlEvents.keys())
|
||||
keys[key] = QString::number(i++);
|
||||
|
||||
QHash<QString,QmlEvent>::const_iterator eventIter = m_qmlEvents.constBegin();
|
||||
for (; eventIter != m_qmlEvents.constEnd(); ++eventIter) {
|
||||
QmlEvent event = eventIter.value();
|
||||
for (int typeIndex = 0; typeIndex < m_qmlEvents.size(); ++typeIndex) {
|
||||
const QmlProfilerDataModel::QmlEventTypeData &event = m_qmlEvents[typeIndex];
|
||||
|
||||
stream.writeStartElement(_("event"));
|
||||
stream.writeAttribute(_("index"), keys[eventIter.key()]);
|
||||
stream.writeAttribute(_("index"), QString::number(typeIndex));
|
||||
stream.writeTextElement(_("displayname"), event.displayName);
|
||||
stream.writeTextElement(_("type"), qmlTypeAsString(event.message, event.rangeType));
|
||||
if (!event.filename.isEmpty()) {
|
||||
stream.writeTextElement(_("filename"), event.filename);
|
||||
stream.writeTextElement(_("line"), QString::number(event.line));
|
||||
stream.writeTextElement(_("column"), QString::number(event.column));
|
||||
if (!event.location.filename.isEmpty()) {
|
||||
stream.writeTextElement(_("filename"), event.location.filename);
|
||||
stream.writeTextElement(_("line"), QString::number(event.location.line));
|
||||
stream.writeTextElement(_("column"), QString::number(event.location.column));
|
||||
}
|
||||
stream.writeTextElement(_("details"), event.details);
|
||||
stream.writeTextElement(_("details"), event.data);
|
||||
if (event.rangeType == Binding)
|
||||
stream.writeTextElement(_("bindingType"), QString::number(event.detailType));
|
||||
if (event.message == Event && event.detailType == AnimationFrame)
|
||||
@@ -494,18 +466,16 @@ void QmlProfilerFileWriter::save(QIODevice *device)
|
||||
|
||||
stream.writeStartElement(_("profilerDataModel"));
|
||||
|
||||
QVector<QPair<Range, QString> >::const_iterator rangeIter = m_ranges.constBegin();
|
||||
for (; rangeIter != m_ranges.constEnd(); ++rangeIter) {
|
||||
Range range = rangeIter->first;
|
||||
QString eventHash = rangeIter->second;
|
||||
for (int rangeIndex = 0; rangeIndex < m_ranges.size(); ++rangeIndex) {
|
||||
const QmlProfilerDataModel::QmlEventData &range = m_ranges[rangeIndex];
|
||||
|
||||
stream.writeStartElement(_("range"));
|
||||
stream.writeAttribute(_("startTime"), QString::number(range.startTime));
|
||||
if (range.duration > 0) // no need to store duration of instantaneous events
|
||||
stream.writeAttribute(_("duration"), QString::number(range.duration));
|
||||
stream.writeAttribute(_("eventIndex"), keys[eventHash]);
|
||||
stream.writeAttribute(_("eventIndex"), QString::number(range.typeIndex));
|
||||
|
||||
QmlEvent event = m_qmlEvents.value(eventHash);
|
||||
const QmlProfilerDataModel::QmlEventTypeData &event = m_qmlEvents[range.typeIndex];
|
||||
|
||||
// special: animation event
|
||||
if (event.message == QmlDebug::Event && event.detailType == QmlDebug::AnimationFrame) {
|
||||
@@ -549,7 +519,7 @@ void QmlProfilerFileWriter::save(QIODevice *device)
|
||||
stream.writeEndDocument();
|
||||
}
|
||||
|
||||
void QmlProfilerFileWriter::calculateMeasuredTime(const QVector<QmlProfilerDataModel::QmlEventData> &events)
|
||||
void QmlProfilerFileWriter::calculateMeasuredTime()
|
||||
{
|
||||
// measured time isn't used, but old clients might still need it
|
||||
// -> we calculate it explicitly
|
||||
@@ -560,10 +530,11 @@ void QmlProfilerFileWriter::calculateMeasuredTime(const QVector<QmlProfilerDataM
|
||||
int level = QmlDebug::Constants::QML_MIN_LEVEL;
|
||||
endtimesPerLevel[0] = 0;
|
||||
|
||||
foreach (const QmlProfilerDataModel::QmlEventData &event, events) {
|
||||
foreach (const QmlProfilerDataModel::QmlEventData &event, m_ranges) {
|
||||
// whitelist
|
||||
if (!m_acceptedRangeTypes.contains(event.rangeType) &&
|
||||
!m_acceptedMessages.contains(event.message))
|
||||
const QmlProfilerDataModel::QmlEventTypeData &type = m_qmlEvents[event.typeIndex];
|
||||
if (!m_acceptedRangeTypes.contains(type.rangeType) &&
|
||||
!m_acceptedMessages.contains(type.message))
|
||||
continue;
|
||||
|
||||
// level computation
|
||||
|
||||
@@ -47,30 +47,6 @@ QT_FORWARD_DECLARE_CLASS(QXmlStreamReader)
|
||||
namespace QmlProfiler {
|
||||
namespace Internal {
|
||||
|
||||
|
||||
struct QmlEvent {
|
||||
QString displayName;
|
||||
QString filename;
|
||||
QString details;
|
||||
QmlDebug::Message message;
|
||||
QmlDebug::RangeType rangeType;
|
||||
int detailType;
|
||||
int line;
|
||||
int column;
|
||||
};
|
||||
|
||||
struct Range {
|
||||
qint64 startTime;
|
||||
qint64 duration;
|
||||
|
||||
// numeric data used by animations, pixmap cache, scenegraph
|
||||
qint64 numericData1;
|
||||
qint64 numericData2;
|
||||
qint64 numericData3;
|
||||
qint64 numericData4;
|
||||
qint64 numericData5;
|
||||
};
|
||||
|
||||
class QmlProfilerFileReader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -100,8 +76,8 @@ private:
|
||||
|
||||
|
||||
QV8ProfilerDataModel *m_v8Model;
|
||||
QVector<QmlEvent> m_qmlEvents;
|
||||
QVector<QPair<Range, int> > m_ranges;
|
||||
QVector<QmlProfilerDataModel::QmlEventTypeData> m_qmlEvents;
|
||||
QVector<QmlProfilerDataModel::QmlEventData> m_ranges;
|
||||
};
|
||||
|
||||
|
||||
@@ -114,18 +90,19 @@ public:
|
||||
|
||||
void setTraceTime(qint64 startTime, qint64 endTime, qint64 measturedTime);
|
||||
void setV8DataModel(QV8ProfilerDataModel *dataModel);
|
||||
void setQmlEvents(const QVector<QmlProfilerDataModel::QmlEventData> &events);
|
||||
void setQmlEvents(const QVector<QmlProfilerDataModel::QmlEventTypeData> &types,
|
||||
const QVector<QmlProfilerDataModel::QmlEventData> &events);
|
||||
|
||||
void save(QIODevice *device);
|
||||
|
||||
private:
|
||||
void calculateMeasuredTime(const QVector<QmlProfilerDataModel::QmlEventData> &events);
|
||||
void calculateMeasuredTime();
|
||||
|
||||
|
||||
qint64 m_startTime, m_endTime, m_measuredTime;
|
||||
QV8ProfilerDataModel *m_v8Model;
|
||||
QHash<QString,QmlEvent> m_qmlEvents;
|
||||
QVector<QPair<Range, QString> > m_ranges;
|
||||
QVector<QmlProfilerDataModel::QmlEventTypeData> m_qmlEvents;
|
||||
QVector<QmlProfilerDataModel::QmlEventData> m_ranges;
|
||||
QVector<QmlDebug::RangeType> m_acceptedRangeTypes;
|
||||
QVector<QmlDebug::Message> m_acceptedMessages;
|
||||
};
|
||||
|
||||
@@ -259,14 +259,14 @@ void QmlProfilerTraceView::clear()
|
||||
QMetaObject::invokeMethod(d->m_mainView->rootObject(), "clear");
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::selectByHash(const QString &hash)
|
||||
void QmlProfilerTraceView::selectByTypeIndex(int typeIndex)
|
||||
{
|
||||
QQuickItem *rootObject = d->m_mainView->rootObject();
|
||||
if (!rootObject)
|
||||
return;
|
||||
|
||||
for (int modelIndex = 0; modelIndex < d->m_modelProxy->modelCount(); ++modelIndex) {
|
||||
int eventId = d->m_modelProxy->getEventIdForHash(modelIndex, hash);
|
||||
int eventId = d->m_modelProxy->getEventIdForTypeIndex(modelIndex, typeIndex);
|
||||
if (eventId != -1) {
|
||||
QMetaObject::invokeMethod(rootObject, "selectById",
|
||||
Q_ARG(QVariant,QVariant(modelIndex)),
|
||||
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
void selectByHash(const QString &eventHash);
|
||||
void selectByTypeIndex(int typeIndex);
|
||||
void selectBySourceLocation(const QString &filename, int line, int column);
|
||||
|
||||
private slots:
|
||||
|
||||
@@ -105,8 +105,8 @@ void QmlProfilerViewManager::createViews()
|
||||
d->profilerModelManager);
|
||||
connect(d->eventsView, SIGNAL(gotoSourceLocation(QString,int,int)), this,
|
||||
SIGNAL(gotoSourceLocation(QString,int,int)));
|
||||
connect(d->eventsView, SIGNAL(eventSelectedByHash(QString)),
|
||||
d->traceView, SLOT(selectByHash(QString)));
|
||||
connect(d->eventsView, SIGNAL(eventSelectedByTypeIndex(int)),
|
||||
d->traceView, SLOT(selectByTypeIndex(int)));
|
||||
connect(d->traceView, SIGNAL(gotoSourceLocation(QString,int,int)),
|
||||
d->eventsView, SLOT(selectBySourceLocation(QString,int,int)));
|
||||
|
||||
|
||||
@@ -230,9 +230,9 @@ const QVariantMap TimelineModelAggregator::getEventLocation(int modelIndex, int
|
||||
return d->modelList[modelIndex]->getEventLocation(index);
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::getEventIdForHash(int modelIndex, const QString &hash) const
|
||||
int TimelineModelAggregator::getEventIdForTypeIndex(int modelIndex, int typeIndex) const
|
||||
{
|
||||
return d->modelList[modelIndex]->getEventIdForHash(hash);
|
||||
return d->modelList[modelIndex]->getEventIdForTypeIndex(typeIndex);
|
||||
}
|
||||
|
||||
int TimelineModelAggregator::getEventIdForLocation(int modelIndex, const QString &filename,
|
||||
|
||||
@@ -85,7 +85,7 @@ public:
|
||||
Q_INVOKABLE const QVariantList getEventDetails(int modelIndex, int index) const;
|
||||
Q_INVOKABLE const QVariantMap getEventLocation(int modelIndex, int index) const;
|
||||
|
||||
Q_INVOKABLE int getEventIdForHash(int modelIndex, const QString &hash) const;
|
||||
Q_INVOKABLE int getEventIdForTypeIndex(int modelIndex, int typeIndex) const;
|
||||
Q_INVOKABLE int getEventIdForLocation(int modelIndex, const QString &filename, int line,
|
||||
int column) const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user