forked from qt-creator/qt-creator
QmlProfiler: Drive event loading from the model manager
We want to get rid of the big master list of QmlEvent in QmlProfilerDataModel, as that gets very large for longer traces. In order to reduce the dependencies on that list we load the events on the fly into the child models while they are being received, rather than having the child models query QmlProfilerDataModel for the event list later. As the trace client so far only emitted rangedEvent() for complete ranges we run into problems with models that need their events sorted. The rangedEvent() signals were sorted by end time, rather than start time which makes it inconvenient to analyze them in a stack based way, for aggregation. This is solved by passing on all the details from the trace client to the models, with the QmlProfilerDataModel aggregating the type information before having the events dispatched to the child models. Change-Id: I5831a20551f21cf91e27d298a709f604ebd96c3e Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
@@ -63,7 +63,7 @@ FlameGraphModel::FlameGraphModel(QmlProfilerModelManager *modelManager,
|
|||||||
void FlameGraphModel::clear()
|
void FlameGraphModel::clear()
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_stackBottom = FlameGraphData();
|
m_stackBottom = FlameGraphData(0, -1, 1);
|
||||||
m_callStack.clear();
|
m_callStack.clear();
|
||||||
m_callStack.append(QmlEvent());
|
m_callStack.append(QmlEvent());
|
||||||
m_stackTop = &m_stackBottom;
|
m_stackTop = &m_stackBottom;
|
||||||
@@ -102,15 +102,16 @@ void FlameGraphModel::loadEvent(const QmlEvent &event, const QmlEventType &type)
|
|||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
|
||||||
const QmlEvent *potentialParent = &(m_callStack.top());
|
const QmlEvent *potentialParent = &(m_callStack.top());
|
||||||
while (potentialParent->isValid() &&
|
if (event.rangeStage() == RangeEnd) {
|
||||||
potentialParent->timestamp() + potentialParent->duration() <= event.timestamp()) {
|
m_stackTop->duration += event.timestamp() - potentialParent->timestamp();
|
||||||
m_callStack.pop();
|
m_callStack.pop();
|
||||||
m_stackTop = m_stackTop->parent;
|
m_stackTop = m_stackTop->parent;
|
||||||
potentialParent = &(m_callStack.top());
|
potentialParent = &(m_callStack.top());
|
||||||
|
} else {
|
||||||
|
QTC_ASSERT(event.rangeStage() == RangeStart, return);
|
||||||
|
m_callStack.push(event);
|
||||||
|
m_stackTop = pushChild(m_stackTop, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_callStack.push(event);
|
|
||||||
m_stackTop = pushChild(m_stackTop, event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlameGraphModel::finalize()
|
void FlameGraphModel::finalize()
|
||||||
@@ -126,31 +127,6 @@ void FlameGraphModel::onModelManagerStateChanged()
|
|||||||
{
|
{
|
||||||
if (m_modelManager->state() == QmlProfilerModelManager::ClearingData)
|
if (m_modelManager->state() == QmlProfilerModelManager::ClearingData)
|
||||||
clear();
|
clear();
|
||||||
else if (m_modelManager->state() == QmlProfilerModelManager::ProcessingData)
|
|
||||||
loadData();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlameGraphModel::loadData(qint64 rangeStart, qint64 rangeEnd)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
const bool checkRanges = (rangeStart != -1) && (rangeEnd != -1);
|
|
||||||
|
|
||||||
const QVector<QmlEvent> &eventList = m_modelManager->qmlModel()->events();
|
|
||||||
const QVector<QmlEventType> &typesList = m_modelManager->qmlModel()->eventTypes();
|
|
||||||
|
|
||||||
for (int i = 0; i < eventList.size(); ++i) {
|
|
||||||
const QmlEvent &event = eventList[i];
|
|
||||||
|
|
||||||
if (checkRanges) {
|
|
||||||
if ((event.timestamp() + event.duration() < rangeStart)
|
|
||||||
|| (event.timestamp() > rangeEnd))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
loadEvent(event, typesList[event.typeIndex()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
finalize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString nameForType(RangeType typeNumber)
|
static QString nameForType(RangeType typeNumber)
|
||||||
@@ -223,12 +199,11 @@ FlameGraphData *FlameGraphModel::pushChild(FlameGraphData *parent, const QmlEven
|
|||||||
foreach (FlameGraphData *child, parent->children) {
|
foreach (FlameGraphData *child, parent->children) {
|
||||||
if (child->typeIndex == data.typeIndex()) {
|
if (child->typeIndex == data.typeIndex()) {
|
||||||
++child->calls;
|
++child->calls;
|
||||||
child->duration += data.duration();
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlameGraphData *child = new FlameGraphData(parent, data.typeIndex(), data.duration());
|
FlameGraphData *child = new FlameGraphData(parent, data.typeIndex());
|
||||||
parent->children.append(child);
|
parent->children.append(child);
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
@@ -293,5 +268,10 @@ QHash<int, QByteArray> FlameGraphModel::roleNames() const
|
|||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QmlProfilerModelManager *FlameGraphModel::modelManager() const
|
||||||
|
{
|
||||||
|
return m_modelManager;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace QmlProfiler
|
} // namespace QmlProfiler
|
||||||
|
@@ -80,12 +80,12 @@ public:
|
|||||||
int columnCount(const QModelIndex &parent) const override;
|
int columnCount(const QModelIndex &parent) const override;
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
QmlProfilerModelManager *modelManager() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void loadEvent(const QmlEvent &event, const QmlEventType &type);
|
void loadEvent(const QmlEvent &event, const QmlEventType &type);
|
||||||
void finalize();
|
void finalize();
|
||||||
void onModelManagerStateChanged();
|
void onModelManagerStateChanged();
|
||||||
void loadData(qint64 rangeStart = -1, qint64 rangeEnd = -1);
|
|
||||||
void loadNotes(int typeId, bool emitSignal);
|
void loadNotes(int typeId, bool emitSignal);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
@@ -37,7 +37,7 @@ namespace Internal {
|
|||||||
|
|
||||||
FlameGraphView::FlameGraphView(QWidget *parent, QmlProfilerModelManager *manager) :
|
FlameGraphView::FlameGraphView(QWidget *parent, QmlProfilerModelManager *manager) :
|
||||||
QmlProfilerEventsView(parent), m_content(new QQuickWidget(this)),
|
QmlProfilerEventsView(parent), m_content(new QQuickWidget(this)),
|
||||||
m_model(new FlameGraphModel(manager, this)), m_isRestrictedToRange(false)
|
m_model(new FlameGraphModel(manager, this))
|
||||||
{
|
{
|
||||||
setWindowTitle(QStringLiteral("Flamegraph"));
|
setWindowTitle(QStringLiteral("Flamegraph"));
|
||||||
setObjectName(QStringLiteral("QmlProfilerFlamegraph"));
|
setObjectName(QStringLiteral("QmlProfilerFlamegraph"));
|
||||||
@@ -66,22 +66,6 @@ FlameGraphView::FlameGraphView(QWidget *parent, QmlProfilerModelManager *manager
|
|||||||
this, SIGNAL(gotoSourceLocation(QString,int,int)));
|
this, SIGNAL(gotoSourceLocation(QString,int,int)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlameGraphView::clear()
|
|
||||||
{
|
|
||||||
m_isRestrictedToRange = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlameGraphView::restrictToRange(qint64 rangeStart, qint64 rangeEnd)
|
|
||||||
{
|
|
||||||
m_isRestrictedToRange = (rangeStart != -1 || rangeEnd != -1);
|
|
||||||
m_model->loadData(rangeStart, rangeEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FlameGraphView::isRestrictedToRange() const
|
|
||||||
{
|
|
||||||
return m_isRestrictedToRange;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlameGraphView::selectByTypeId(int typeIndex)
|
void FlameGraphView::selectByTypeId(int typeIndex)
|
||||||
{
|
{
|
||||||
m_content->rootObject()->setProperty("selectedTypeId", typeIndex);
|
m_content->rootObject()->setProperty("selectedTypeId", typeIndex);
|
||||||
@@ -107,7 +91,7 @@ void FlameGraphView::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
menu.addActions(QmlProfilerTool::profilerContextMenuActions());
|
menu.addActions(QmlProfilerTool::profilerContextMenuActions());
|
||||||
menu.addSeparator();
|
menu.addSeparator();
|
||||||
getGlobalStatsAction = menu.addAction(tr("Show Full Range"));
|
getGlobalStatsAction = menu.addAction(tr("Show Full Range"));
|
||||||
if (!isRestrictedToRange())
|
if (!m_model->modelManager()->isRestrictedToRange())
|
||||||
getGlobalStatsAction->setEnabled(false);
|
getGlobalStatsAction->setEnabled(false);
|
||||||
|
|
||||||
if (menu.exec(position) == getGlobalStatsAction)
|
if (menu.exec(position) == getGlobalStatsAction)
|
||||||
|
@@ -40,10 +40,6 @@ class FlameGraphView : public QmlProfilerEventsView
|
|||||||
public:
|
public:
|
||||||
FlameGraphView(QWidget *parent, QmlProfilerModelManager *manager);
|
FlameGraphView(QWidget *parent, QmlProfilerModelManager *manager);
|
||||||
|
|
||||||
void clear() override;
|
|
||||||
void restrictToRange(qint64 rangeStart, qint64 rangeEnd) override;
|
|
||||||
bool isRestrictedToRange() const override;
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void selectByTypeId(int typeIndex) override;
|
void selectByTypeId(int typeIndex) override;
|
||||||
void onVisibleFeaturesChanged(quint64 features) override;
|
void onVisibleFeaturesChanged(quint64 features) override;
|
||||||
@@ -54,7 +50,6 @@ protected:
|
|||||||
private:
|
private:
|
||||||
QQuickWidget *m_content;
|
QQuickWidget *m_content;
|
||||||
FlameGraphModel *m_model;
|
FlameGraphModel *m_model;
|
||||||
bool m_isRestrictedToRange;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -142,12 +142,12 @@ bool MemoryUsageModel::accepted(const QmlEventType &type) const
|
|||||||
|
|
||||||
void MemoryUsageModel::loadEvent(const QmlEvent &event, const QmlEventType &type)
|
void MemoryUsageModel::loadEvent(const QmlEvent &event, const QmlEventType &type)
|
||||||
{
|
{
|
||||||
while (!m_rangeStack.empty() && m_rangeStack.top().endTime < event.timestamp())
|
|
||||||
m_rangeStack.pop();
|
|
||||||
if (type.message != MemoryAllocation) {
|
if (type.message != MemoryAllocation) {
|
||||||
if (type.rangeType != MaximumRangeType) {
|
if (type.rangeType != MaximumRangeType) {
|
||||||
m_rangeStack.push(RangeStackFrame(event.typeIndex(), event.timestamp(),
|
if (event.rangeStage() == RangeStart)
|
||||||
event.timestamp() + event.duration()));
|
m_rangeStack.push(RangeStackFrame(event.typeIndex(), event.timestamp()));
|
||||||
|
else if (event.rangeStage() == RangeEnd)
|
||||||
|
m_rangeStack.pop();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -76,12 +76,11 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
struct RangeStackFrame {
|
struct RangeStackFrame {
|
||||||
RangeStackFrame() : originTypeIndex(-1), startTime(-1), endTime(-1) {}
|
RangeStackFrame() : originTypeIndex(-1), startTime(-1) {}
|
||||||
RangeStackFrame(int originTypeIndex, qint64 startTime, qint64 endTime) :
|
RangeStackFrame(int originTypeIndex, qint64 startTime) :
|
||||||
originTypeIndex(originTypeIndex), startTime(startTime), endTime(endTime) {}
|
originTypeIndex(originTypeIndex), startTime(startTime) {}
|
||||||
int originTypeIndex;
|
int originTypeIndex;
|
||||||
qint64 startTime;
|
qint64 startTime;
|
||||||
qint64 endTime;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static QString memoryTypeName(int type);
|
static QString memoryTypeName(int type);
|
||||||
|
@@ -198,10 +198,6 @@ void QmlProfilerClientManager::connectClientSignals()
|
|||||||
this, &QmlProfilerClientManager::qmlComplete);
|
this, &QmlProfilerClientManager::qmlComplete);
|
||||||
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::newEngine,
|
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::newEngine,
|
||||||
this, &QmlProfilerClientManager::qmlNewEngine);
|
this, &QmlProfilerClientManager::qmlNewEngine);
|
||||||
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::rangedEvent,
|
|
||||||
d->modelManager, &QmlProfilerModelManager::addQmlEvent);
|
|
||||||
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::debugMessage,
|
|
||||||
d->modelManager, &QmlProfilerModelManager::addDebugMessage);
|
|
||||||
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::traceFinished,
|
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::traceFinished,
|
||||||
d->modelManager->traceTime(), &QmlProfilerTraceTime::increaseEndTime);
|
d->modelManager->traceTime(), &QmlProfilerTraceTime::increaseEndTime);
|
||||||
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::traceStarted,
|
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::traceStarted,
|
||||||
@@ -212,6 +208,8 @@ void QmlProfilerClientManager::connectClientSignals()
|
|||||||
d->qmlclientplugin.data(), &QmlProfilerTraceClient::setRequestedFeatures);
|
d->qmlclientplugin.data(), &QmlProfilerTraceClient::setRequestedFeatures);
|
||||||
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::recordedFeaturesChanged,
|
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::recordedFeaturesChanged,
|
||||||
d->profilerState, &QmlProfilerStateManager::setRecordedFeatures);
|
d->profilerState, &QmlProfilerStateManager::setRecordedFeatures);
|
||||||
|
connect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::qmlEvent,
|
||||||
|
d->modelManager, &QmlProfilerModelManager::addQmlEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,10 +220,6 @@ void QmlProfilerClientManager::disconnectClientSignals()
|
|||||||
this, &QmlProfilerClientManager::qmlComplete);
|
this, &QmlProfilerClientManager::qmlComplete);
|
||||||
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::newEngine,
|
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::newEngine,
|
||||||
this, &QmlProfilerClientManager::qmlNewEngine);
|
this, &QmlProfilerClientManager::qmlNewEngine);
|
||||||
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::rangedEvent,
|
|
||||||
d->modelManager, &QmlProfilerModelManager::addQmlEvent);
|
|
||||||
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::debugMessage,
|
|
||||||
d->modelManager, &QmlProfilerModelManager::addDebugMessage);
|
|
||||||
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::traceFinished,
|
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::traceFinished,
|
||||||
d->modelManager->traceTime(), &QmlProfilerTraceTime::increaseEndTime);
|
d->modelManager->traceTime(), &QmlProfilerTraceTime::increaseEndTime);
|
||||||
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::traceStarted,
|
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::traceStarted,
|
||||||
@@ -236,6 +230,8 @@ void QmlProfilerClientManager::disconnectClientSignals()
|
|||||||
d->qmlclientplugin.data(), &QmlProfilerTraceClient::setRequestedFeatures);
|
d->qmlclientplugin.data(), &QmlProfilerTraceClient::setRequestedFeatures);
|
||||||
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::recordedFeaturesChanged,
|
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::recordedFeaturesChanged,
|
||||||
d->profilerState, &QmlProfilerStateManager::setRecordedFeatures);
|
d->profilerState, &QmlProfilerStateManager::setRecordedFeatures);
|
||||||
|
disconnect(d->qmlclientplugin.data(), &QmlProfilerTraceClient::qmlEvent,
|
||||||
|
d->modelManager, &QmlProfilerModelManager::addQmlEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -28,10 +28,12 @@
|
|||||||
#include "qmlprofilernotesmodel.h"
|
#include "qmlprofilernotesmodel.h"
|
||||||
#include "qmlprofilerdetailsrewriter.h"
|
#include "qmlprofilerdetailsrewriter.h"
|
||||||
#include "qmlprofilereventtypes.h"
|
#include "qmlprofilereventtypes.h"
|
||||||
|
#include "qmltypedevent.h"
|
||||||
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QStack>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace QmlProfiler {
|
namespace QmlProfiler {
|
||||||
@@ -39,10 +41,16 @@ namespace QmlProfiler {
|
|||||||
class QmlProfilerDataModel::QmlProfilerDataModelPrivate
|
class QmlProfilerDataModel::QmlProfilerDataModelPrivate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
void rewriteType(int typeIndex);
|
||||||
|
int resolveType(const QmlEventType &type);
|
||||||
|
int resolveStackTop();
|
||||||
|
|
||||||
QVector<QmlEventType> eventTypes;
|
QVector<QmlEventType> eventTypes;
|
||||||
QVector<QmlEvent> eventList;
|
QVector<QmlEvent> eventList;
|
||||||
QHash<QmlEventType, int> eventTypeIds;
|
QHash<QmlEventType, int> eventTypeIds;
|
||||||
|
|
||||||
|
QStack<QmlTypedEvent> rangesInProgress;
|
||||||
|
|
||||||
QmlProfilerModelManager *modelManager;
|
QmlProfilerModelManager *modelManager;
|
||||||
int modelId;
|
int modelId;
|
||||||
Internal::QmlProfilerDetailsRewriter *detailsRewriter;
|
Internal::QmlProfilerDetailsRewriter *detailsRewriter;
|
||||||
@@ -108,9 +116,7 @@ QmlProfilerDataModel::QmlProfilerDataModel(Utils::FileInProjectFinder *fileFinde
|
|||||||
connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::rewriteDetailsString,
|
connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::rewriteDetailsString,
|
||||||
this, &QmlProfilerDataModel::detailsChanged);
|
this, &QmlProfilerDataModel::detailsChanged);
|
||||||
connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::eventDetailsChanged,
|
connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::eventDetailsChanged,
|
||||||
this, &QmlProfilerDataModel::detailsDone);
|
this, &QmlProfilerDataModel::allTypesLoaded);
|
||||||
connect(this, &QmlProfilerDataModel::requestReload,
|
|
||||||
d->detailsRewriter, &QmlProfilerDetailsRewriter::reloadDocuments);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlProfilerDataModel::~QmlProfilerDataModel()
|
QmlProfilerDataModel::~QmlProfilerDataModel()
|
||||||
@@ -142,6 +148,9 @@ void QmlProfilerDataModel::setData(qint64 traceStart, qint64 traceEnd,
|
|||||||
d->eventTypes = types;
|
d->eventTypes = types;
|
||||||
for (int id = 0; id < types.count(); ++id)
|
for (int id = 0; id < types.count(); ++id)
|
||||||
d->eventTypeIds[types[id]] = id;
|
d->eventTypeIds[types[id]] = id;
|
||||||
|
|
||||||
|
foreach (const QmlEvent &event, d->eventList)
|
||||||
|
d->modelManager->dispatch(event, d->eventTypes[event.typeIndex()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int QmlProfilerDataModel::count() const
|
int QmlProfilerDataModel::count() const
|
||||||
@@ -156,6 +165,7 @@ void QmlProfilerDataModel::clear()
|
|||||||
d->eventList.clear();
|
d->eventList.clear();
|
||||||
d->eventTypes.clear();
|
d->eventTypes.clear();
|
||||||
d->eventTypeIds.clear();
|
d->eventTypeIds.clear();
|
||||||
|
d->rangesInProgress.clear();
|
||||||
d->detailsRewriter->clearRequests();
|
d->detailsRewriter->clearRequests();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,11 +175,6 @@ bool QmlProfilerDataModel::isEmpty() const
|
|||||||
return d->eventList.isEmpty();
|
return d->eventList.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static bool operator<(const QmlEvent &t1, const QmlEvent &t2)
|
|
||||||
{
|
|
||||||
return t1.timestamp() < t2.timestamp();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static uint qHash(const QmlEventType &type)
|
inline static uint qHash(const QmlEventType &type)
|
||||||
{
|
{
|
||||||
return qHash(type.location.filename) ^
|
return qHash(type.location.filename) ^
|
||||||
@@ -190,66 +195,139 @@ inline static bool operator==(const QmlEventType &type1,
|
|||||||
type1.location.filename == type2.location.filename;
|
type1.location.filename == type2.location.filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerDataModel::processData()
|
void QmlProfilerDataModel::QmlProfilerDataModelPrivate::rewriteType(int typeIndex)
|
||||||
{
|
{
|
||||||
Q_D(QmlProfilerDataModel);
|
QmlEventType &type = eventTypes[typeIndex];
|
||||||
// post-processing
|
type.displayName = getDisplayName(type);
|
||||||
|
type.data = getInitialDetails(type);
|
||||||
|
|
||||||
// sort events by start time, using above operator<
|
// Only bindings and signal handlers need rewriting
|
||||||
std::sort(d->eventList.begin(), d->eventList.end());
|
if (type.rangeType != Binding && type.rangeType != HandlingSignal)
|
||||||
|
return;
|
||||||
|
|
||||||
// rewrite strings
|
// There is no point in looking for invalid locations
|
||||||
int n = d->eventTypes.count();
|
if (type.location.filename.isEmpty() || type.location.line < 0 || type.location.column < 0)
|
||||||
for (int i = 0; i < n; i++) {
|
return;
|
||||||
QmlEventType *event = &d->eventTypes[i];
|
|
||||||
event->displayName = getDisplayName(*event);
|
|
||||||
event->data = getInitialDetails(*event);
|
|
||||||
|
|
||||||
//
|
detailsRewriter->requestDetailsForLocation(typeIndex, type.location);
|
||||||
// request further details from files
|
|
||||||
//
|
|
||||||
|
|
||||||
if (event->rangeType != Binding && event->rangeType != HandlingSignal)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// This skips anonymous bindings in Qt4.8 (we don't have valid location data for them)
|
|
||||||
if (event->location.filename.isEmpty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Skip non-anonymous bindings from Qt4.8 (we already have correct details for them)
|
|
||||||
if (event->location.column == -1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
d->detailsRewriter->requestDetailsForLocation(i, event->location);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit requestReload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerDataModel::addEvent(Message message, RangeType rangeType, int detailType,
|
int QmlProfilerDataModel::QmlProfilerDataModelPrivate::resolveType(const QmlEventType &type)
|
||||||
qint64 startTime, qint64 duration, const QString &data,
|
{
|
||||||
const QmlEventLocation &location, qint64 ndata1, qint64 ndata2,
|
QHash<QmlEventType, int>::ConstIterator it = eventTypeIds.constFind(type);
|
||||||
qint64 ndata3, qint64 ndata4, qint64 ndata5)
|
|
||||||
|
int typeIndex = -1;
|
||||||
|
if (it != eventTypeIds.constEnd()) {
|
||||||
|
typeIndex = it.value();
|
||||||
|
} else {
|
||||||
|
typeIndex = eventTypes.size();
|
||||||
|
eventTypeIds[type] = typeIndex;
|
||||||
|
eventTypes.append(type);
|
||||||
|
rewriteType(typeIndex);
|
||||||
|
}
|
||||||
|
return typeIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
int QmlProfilerDataModel::QmlProfilerDataModelPrivate::resolveStackTop()
|
||||||
|
{
|
||||||
|
if (rangesInProgress.isEmpty())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
QmlTypedEvent &typedEvent = rangesInProgress.top();
|
||||||
|
int typeIndex = typedEvent.event.typeIndex();
|
||||||
|
if (typeIndex >= 0)
|
||||||
|
return typeIndex;
|
||||||
|
|
||||||
|
typeIndex = resolveType(typedEvent.type);
|
||||||
|
typedEvent.event.setTypeIndex(typeIndex);
|
||||||
|
eventList.append(typedEvent.event);
|
||||||
|
modelManager->dispatch(eventList.last(), eventTypes[typeIndex]);
|
||||||
|
return typeIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlProfilerDataModel::addEvent(const QmlEvent &event, const QmlEventType &type)
|
||||||
{
|
{
|
||||||
Q_D(QmlProfilerDataModel);
|
Q_D(QmlProfilerDataModel);
|
||||||
QString displayName;
|
|
||||||
|
|
||||||
QmlEventType typeData(displayName, location, message, rangeType, detailType,
|
// RangeData and RangeLocation always apply to the range on the top of the stack. Furthermore,
|
||||||
message == DebugMessage ? QString() : data);
|
// all ranges are perfectly nested. This is why we can defer the type resolution until either
|
||||||
QmlEvent eventData = (message == DebugMessage) ?
|
// the range ends or a child range starts. With only the information in RangeStart we wouldn't
|
||||||
QmlEvent(startTime, duration, -1, data) :
|
// be able to uniquely identify the event type.
|
||||||
QmlEvent(startTime, duration, -1, {ndata1, ndata2, ndata3, ndata4, ndata5});
|
Message rangeStage = type.rangeType == MaximumRangeType ? type.message : event.rangeStage();
|
||||||
|
switch (rangeStage) {
|
||||||
QHash<QmlEventType, int>::Iterator it = d->eventTypeIds.find(typeData);
|
case RangeStart:
|
||||||
if (it != d->eventTypeIds.end()) {
|
d->resolveStackTop();
|
||||||
eventData.setTypeIndex(it.value());
|
d->rangesInProgress.push(QmlTypedEvent({event, type}));
|
||||||
} else {
|
break;
|
||||||
eventData.setTypeIndex(d->eventTypes.size());
|
case RangeEnd: {
|
||||||
d->eventTypeIds[typeData] = eventData.typeIndex();
|
int typeIndex = d->resolveStackTop();
|
||||||
d->eventTypes.append(typeData);
|
QTC_ASSERT(typeIndex != -1, break);
|
||||||
|
d->eventList.append(event);
|
||||||
|
QmlEvent &appended = d->eventList.last();
|
||||||
|
appended.setTypeIndex(typeIndex);
|
||||||
|
d->modelManager->dispatch(appended, d->eventTypes[typeIndex]);
|
||||||
|
d->rangesInProgress.pop();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case RangeData:
|
||||||
|
d->rangesInProgress.top().type.data = type.data;
|
||||||
|
break;
|
||||||
|
case RangeLocation:
|
||||||
|
d->rangesInProgress.top().type.location = type.location;
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
d->eventList.append(event);
|
||||||
|
QmlEvent &appended = d->eventList.last();
|
||||||
|
int typeIndex = d->resolveType(type);
|
||||||
|
appended.setTypeIndex(typeIndex);
|
||||||
|
d->modelManager->dispatch(appended, d->eventTypes[typeIndex]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
d->eventList.append(eventData);
|
void QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd,
|
||||||
|
QmlProfilerModelManager::EventLoader loader) const
|
||||||
|
{
|
||||||
|
Q_D(const QmlProfilerDataModel);
|
||||||
|
QStack<QmlEvent> stack;
|
||||||
|
foreach (const QmlEvent &event, d->eventList) {
|
||||||
|
const QmlEventType &type = d->eventTypes[event.typeIndex()];
|
||||||
|
if (rangeStart != -1 && rangeEnd != -1) {
|
||||||
|
if (event.timestamp() < rangeStart) {
|
||||||
|
if (type.rangeType != MaximumRangeType) {
|
||||||
|
if (event.rangeStage() == RangeStart)
|
||||||
|
stack.push(event);
|
||||||
|
else if (event.rangeStage() == RangeEnd)
|
||||||
|
stack.pop();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if (event.timestamp() > rangeEnd) {
|
||||||
|
if (type.rangeType != MaximumRangeType) {
|
||||||
|
if (event.rangeStage() == RangeEnd) {
|
||||||
|
if (stack.isEmpty()) {
|
||||||
|
QmlEvent endEvent(event);
|
||||||
|
endEvent.setTimestamp(rangeEnd);
|
||||||
|
loader(event, d->eventTypes[event.typeIndex()]);
|
||||||
|
} else {
|
||||||
|
stack.pop();
|
||||||
|
}
|
||||||
|
} else if (event.rangeStage() == RangeStart) {
|
||||||
|
stack.push(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if (!stack.isEmpty()) {
|
||||||
|
foreach (QmlEvent stashed, stack) {
|
||||||
|
stashed.setTimestamp(rangeStart);
|
||||||
|
loader(stashed, d->eventTypes[stashed.typeIndex()]);
|
||||||
|
}
|
||||||
|
stack.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loader(event, type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 QmlProfilerDataModel::lastTimeMark() const
|
qint64 QmlProfilerDataModel::lastTimeMark() const
|
||||||
@@ -258,22 +336,20 @@ qint64 QmlProfilerDataModel::lastTimeMark() const
|
|||||||
if (d->eventList.isEmpty())
|
if (d->eventList.isEmpty())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return d->eventList.last().timestamp() + d->eventList.last().duration();
|
return d->eventList.last().timestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QmlProfilerDataModel::finalize()
|
||||||
|
{
|
||||||
|
Q_D(QmlProfilerDataModel);
|
||||||
|
d->detailsRewriter->reloadDocuments();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerDataModel::detailsChanged(int requestId, const QString &newString)
|
void QmlProfilerDataModel::detailsChanged(int requestId, const QString &newString)
|
||||||
{
|
{
|
||||||
Q_D(QmlProfilerDataModel);
|
Q_D(QmlProfilerDataModel);
|
||||||
QTC_ASSERT(requestId < d->eventTypes.count(), return);
|
QTC_ASSERT(requestId < d->eventTypes.count(), return);
|
||||||
|
d->eventTypes[requestId].data = newString;
|
||||||
QmlEventType *event = &d->eventTypes[requestId];
|
|
||||||
event->data = newString;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlProfilerDataModel::detailsDone()
|
|
||||||
{
|
|
||||||
Q_D(QmlProfilerDataModel);
|
|
||||||
d->modelManager->processingDone();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace QmlProfiler
|
} // namespace QmlProfiler
|
||||||
|
@@ -49,22 +49,21 @@ public:
|
|||||||
const QVector<QmlEventType> &eventTypes() const;
|
const QVector<QmlEventType> &eventTypes() const;
|
||||||
void setData(qint64 traceStart, qint64 traceEnd, const QVector<QmlEventType> &types,
|
void setData(qint64 traceStart, qint64 traceEnd, const QVector<QmlEventType> &types,
|
||||||
const QVector<QmlEvent> &events);
|
const QVector<QmlEvent> &events);
|
||||||
void processData();
|
|
||||||
|
|
||||||
int count() const;
|
int count() const;
|
||||||
void clear();
|
void clear();
|
||||||
bool isEmpty() const;
|
bool isEmpty() const;
|
||||||
void addEvent(Message message, RangeType rangeType, int bindingType, qint64 startTime,
|
void addEvent(const QmlEvent &event, const QmlEventType &type);
|
||||||
qint64 duration, const QString &data, const QmlEventLocation &location,
|
void replayEvents(qint64 startTime, qint64 endTime,
|
||||||
qint64 ndata1, qint64 ndata2, qint64 ndata3, qint64 ndata4, qint64 ndata5);
|
QmlProfilerModelManager::EventLoader loader) const;
|
||||||
|
void finalize();
|
||||||
qint64 lastTimeMark() const;
|
qint64 lastTimeMark() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void requestReload();
|
void allTypesLoaded();
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void detailsChanged(int requestId, const QString &newString);
|
void detailsChanged(int requestId, const QString &newString);
|
||||||
void detailsDone();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class QmlProfilerDataModelPrivate;
|
class QmlProfilerDataModelPrivate;
|
||||||
|
@@ -38,10 +38,7 @@ class QMLPROFILER_EXPORT QmlProfilerEventsView : public QWidget
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
QmlProfilerEventsView(QWidget *parent = 0) : QWidget(parent) {}
|
QmlProfilerEventsView(QWidget *parent = 0) : QWidget(parent) {}
|
||||||
|
virtual void clear() {}
|
||||||
virtual void clear() = 0;
|
|
||||||
virtual void restrictToRange(qint64 rangeStart, qint64 rangeEnd) = 0;
|
|
||||||
virtual bool isRestrictedToRange() const = 0;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
|
void gotoSourceLocation(const QString &fileName, int lineNumber, int columnNumber);
|
||||||
|
@@ -37,6 +37,8 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace QmlProfiler {
|
namespace QmlProfiler {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
@@ -59,22 +61,19 @@ Q_STATIC_ASSERT(sizeof(ProfileFeatureNames) == sizeof(char *) * MaximumProfileFe
|
|||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
QmlProfilerTraceTime::QmlProfilerTraceTime(QObject *parent) :
|
QmlProfilerTraceTime::QmlProfilerTraceTime(QObject *parent) :
|
||||||
QObject(parent), m_startTime(-1), m_endTime(-1)
|
QObject(parent), m_startTime(-1), m_endTime(-1),
|
||||||
{
|
m_restrictedStartTime(-1), m_restrictedEndTime(-1)
|
||||||
}
|
|
||||||
|
|
||||||
QmlProfilerTraceTime::~QmlProfilerTraceTime()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 QmlProfilerTraceTime::startTime() const
|
qint64 QmlProfilerTraceTime::startTime() const
|
||||||
{
|
{
|
||||||
return m_startTime;
|
return m_restrictedStartTime != -1 ? m_restrictedStartTime : m_startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 QmlProfilerTraceTime::endTime() const
|
qint64 QmlProfilerTraceTime::endTime() const
|
||||||
{
|
{
|
||||||
return m_endTime;
|
return m_restrictedEndTime != -1 ? m_restrictedEndTime : m_endTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 QmlProfilerTraceTime::duration() const
|
qint64 QmlProfilerTraceTime::duration() const
|
||||||
@@ -82,18 +81,22 @@ qint64 QmlProfilerTraceTime::duration() const
|
|||||||
return endTime() - startTime();
|
return endTime() - startTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QmlProfilerTraceTime::isRestrictedToRange() const
|
||||||
|
{
|
||||||
|
return m_restrictedStartTime != -1 || m_restrictedEndTime != -1;
|
||||||
|
}
|
||||||
|
|
||||||
void QmlProfilerTraceTime::clear()
|
void QmlProfilerTraceTime::clear()
|
||||||
{
|
{
|
||||||
|
restrictToRange(-1, -1);
|
||||||
setTime(-1, -1);
|
setTime(-1, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerTraceTime::setTime(qint64 startTime, qint64 endTime)
|
void QmlProfilerTraceTime::setTime(qint64 startTime, qint64 endTime)
|
||||||
{
|
{
|
||||||
Q_ASSERT(startTime <= endTime);
|
QTC_ASSERT(startTime <= endTime, endTime = startTime);
|
||||||
if (startTime != m_startTime || endTime != m_endTime) {
|
m_startTime = startTime;
|
||||||
m_startTime = startTime;
|
m_endTime = endTime;
|
||||||
m_endTime = endTime;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerTraceTime::decreaseStartTime(qint64 time)
|
void QmlProfilerTraceTime::decreaseStartTime(qint64 time)
|
||||||
@@ -118,6 +121,13 @@ void QmlProfilerTraceTime::increaseEndTime(qint64 time)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlProfilerTraceTime::restrictToRange(qint64 startTime, qint64 endTime)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(endTime == -1 || startTime <= endTime, endTime = startTime);
|
||||||
|
m_restrictedStartTime = startTime;
|
||||||
|
m_restrictedEndTime = endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|
||||||
@@ -153,6 +163,8 @@ QmlProfilerModelManager::QmlProfilerModelManager(Utils::FileInProjectFinder *fin
|
|||||||
d->state = Empty;
|
d->state = Empty;
|
||||||
d->traceTime = new QmlProfilerTraceTime(this);
|
d->traceTime = new QmlProfilerTraceTime(this);
|
||||||
d->notesModel = new QmlProfilerNotesModel(this);
|
d->notesModel = new QmlProfilerNotesModel(this);
|
||||||
|
connect(d->model, &QmlProfilerDataModel::allTypesLoaded,
|
||||||
|
this, &QmlProfilerModelManager::processingDone);
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlProfilerModelManager::~QmlProfilerModelManager()
|
QmlProfilerModelManager::~QmlProfilerModelManager()
|
||||||
@@ -247,34 +259,17 @@ const char *QmlProfilerModelManager::featureName(ProfileFeature feature)
|
|||||||
return ProfileFeatureNames[feature];
|
return ProfileFeatureNames[feature];
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerModelManager::addQmlEvent(Message message, RangeType rangeType, int detailType,
|
void QmlProfilerModelManager::addQmlEvent(const QmlEvent &event, const QmlEventType &type)
|
||||||
qint64 startTime, qint64 length, const QString &data,
|
|
||||||
const QmlEventLocation &location, qint64 ndata1,
|
|
||||||
qint64 ndata2, qint64 ndata3, qint64 ndata4,
|
|
||||||
qint64 ndata5)
|
|
||||||
{
|
{
|
||||||
// If trace start time was not explicitly set, use the first event
|
QTC_ASSERT(state() == AcquiringData, return);
|
||||||
if (d->traceTime->startTime() == -1)
|
d->model->addEvent(event, type);
|
||||||
d->traceTime->setTime(startTime, startTime + d->traceTime->duration());
|
|
||||||
|
|
||||||
QTC_ASSERT(state() == AcquiringData, /**/);
|
|
||||||
d->model->addEvent(message, rangeType, detailType, startTime, length, data, location, ndata1,
|
|
||||||
ndata2, ndata3, ndata4, ndata5);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlProfilerModelManager::addDebugMessage(qint64 timestamp, QtMsgType messageType,
|
|
||||||
const QString &text, const QmlEventLocation &location)
|
|
||||||
{
|
|
||||||
if (state() == AcquiringData)
|
|
||||||
d->model->addEvent(DebugMessage, MaximumRangeType, messageType, timestamp, 0, text,
|
|
||||||
location, 0, 0, 0, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerModelManager::acquiringDone()
|
void QmlProfilerModelManager::acquiringDone()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(state() == AcquiringData, /**/);
|
QTC_ASSERT(state() == AcquiringData, /**/);
|
||||||
setState(ProcessingData);
|
setState(ProcessingData);
|
||||||
d->model->processData();
|
d->model->finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerModelManager::processingDone()
|
void QmlProfilerModelManager::processingDone()
|
||||||
@@ -282,8 +277,13 @@ void QmlProfilerModelManager::processingDone()
|
|||||||
QTC_ASSERT(state() == ProcessingData, /**/);
|
QTC_ASSERT(state() == ProcessingData, /**/);
|
||||||
// Load notes after the timeline models have been initialized ...
|
// Load notes after the timeline models have been initialized ...
|
||||||
// which happens on stateChanged(Done).
|
// which happens on stateChanged(Done).
|
||||||
setState(Done);
|
|
||||||
|
foreach (const Finalizer &finalizer, d->finalizers)
|
||||||
|
finalizer();
|
||||||
|
|
||||||
d->notesModel->loadData();
|
d->notesModel->loadData();
|
||||||
|
setState(Done);
|
||||||
|
|
||||||
emit loadFinished();
|
emit loadFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,6 +408,26 @@ void QmlProfilerModelManager::clear()
|
|||||||
setState(Empty);
|
setState(Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlProfilerModelManager::restrictToRange(qint64 startTime, qint64 endTime)
|
||||||
|
{
|
||||||
|
setState(ClearingData);
|
||||||
|
d->notesModel->saveData();
|
||||||
|
setVisibleFeatures(0);
|
||||||
|
|
||||||
|
startAcquiring();
|
||||||
|
d->model->replayEvents(startTime, endTime,
|
||||||
|
std::bind(&QmlProfilerModelManager::dispatch, this,
|
||||||
|
std::placeholders::_1, std::placeholders::_2));
|
||||||
|
d->notesModel->loadData();
|
||||||
|
d->traceTime->restrictToRange(startTime, endTime);
|
||||||
|
acquiringDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QmlProfilerModelManager::isRestrictedToRange() const
|
||||||
|
{
|
||||||
|
return d->traceTime->isRestrictedToRange();
|
||||||
|
}
|
||||||
|
|
||||||
void QmlProfilerModelManager::startAcquiring()
|
void QmlProfilerModelManager::startAcquiring()
|
||||||
{
|
{
|
||||||
setState(AcquiringData);
|
setState(AcquiringData);
|
||||||
|
@@ -48,11 +48,11 @@ class QMLPROFILER_EXPORT QmlProfilerTraceTime : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit QmlProfilerTraceTime(QObject *parent);
|
explicit QmlProfilerTraceTime(QObject *parent);
|
||||||
~QmlProfilerTraceTime();
|
|
||||||
|
|
||||||
qint64 startTime() const;
|
qint64 startTime() const;
|
||||||
qint64 endTime() const;
|
qint64 endTime() const;
|
||||||
qint64 duration() const;
|
qint64 duration() const;
|
||||||
|
bool isRestrictedToRange() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void clear();
|
void clear();
|
||||||
@@ -60,10 +60,14 @@ public slots:
|
|||||||
void setTime(qint64 startTime, qint64 endTime);
|
void setTime(qint64 startTime, qint64 endTime);
|
||||||
void decreaseStartTime(qint64 time);
|
void decreaseStartTime(qint64 time);
|
||||||
void increaseEndTime(qint64 time);
|
void increaseEndTime(qint64 time);
|
||||||
|
void restrictToRange(qint64 startTime, qint64 endTime);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
qint64 m_startTime;
|
qint64 m_startTime;
|
||||||
qint64 m_endTime;
|
qint64 m_endTime;
|
||||||
|
|
||||||
|
qint64 m_restrictedStartTime;
|
||||||
|
qint64 m_restrictedEndTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // End internal namespace
|
} // End internal namespace
|
||||||
@@ -124,13 +128,11 @@ signals:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void clear();
|
void clear();
|
||||||
|
void restrictToRange(qint64 startTime, qint64 endTime);
|
||||||
|
bool isRestrictedToRange() const;
|
||||||
|
|
||||||
void startAcquiring();
|
void startAcquiring();
|
||||||
void addQmlEvent(Message message, RangeType rangeType, int bindingType, qint64 startTime,
|
void addQmlEvent(const QmlEvent &event, const QmlEventType &type);
|
||||||
qint64 length, const QString &data, const QmlEventLocation &location,
|
|
||||||
qint64 ndata1, qint64 ndata2, qint64 ndata3, qint64 ndata4, qint64 ndata5);
|
|
||||||
void addDebugMessage(qint64 timestamp, QtMsgType type, const QString &text,
|
|
||||||
const QmlEventLocation &location);
|
|
||||||
|
|
||||||
void save(const QString &filename);
|
void save(const QString &filename);
|
||||||
void load(const QString &filename);
|
void load(const QString &filename);
|
||||||
|
@@ -54,6 +54,7 @@ void QmlProfilerRangeModel::clear()
|
|||||||
m_expandedRowTypes.clear();
|
m_expandedRowTypes.clear();
|
||||||
m_expandedRowTypes << -1;
|
m_expandedRowTypes << -1;
|
||||||
m_data.clear();
|
m_data.clear();
|
||||||
|
m_stack.clear();
|
||||||
QmlProfilerTimelineModel::clear();
|
QmlProfilerTimelineModel::clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,8 +67,14 @@ void QmlProfilerRangeModel::loadEvent(const QmlEvent &event, const QmlEventType
|
|||||||
{
|
{
|
||||||
Q_UNUSED(type);
|
Q_UNUSED(type);
|
||||||
// store starttime-based instance
|
// store starttime-based instance
|
||||||
m_data.insert(insert(event.timestamp(), event.duration(), event.typeIndex()),
|
if (event.rangeStage() == RangeStart) {
|
||||||
QmlRangeEventStartInstance());
|
int index = insertStart(event.timestamp(), event.typeIndex());
|
||||||
|
m_stack.append(index);
|
||||||
|
m_data.insert(index, QmlRangeEventStartInstance());
|
||||||
|
} else if (event.rangeStage() == RangeEnd) {
|
||||||
|
int index = m_stack.pop();
|
||||||
|
insertEnd(index, event.timestamp() - startTime(index));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerRangeModel::finalize()
|
void QmlProfilerRangeModel::finalize()
|
||||||
|
@@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include <QVariantList>
|
#include <QVariantList>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
#include <QStack>
|
||||||
|
|
||||||
namespace QmlProfiler {
|
namespace QmlProfiler {
|
||||||
class QmlProfilerModelManager;
|
class QmlProfilerModelManager;
|
||||||
@@ -85,6 +86,7 @@ private:
|
|||||||
void findBindingLoops();
|
void findBindingLoops();
|
||||||
|
|
||||||
QVector<QmlRangeEventStartInstance> m_data;
|
QVector<QmlRangeEventStartInstance> m_data;
|
||||||
|
QStack<int> m_stack;
|
||||||
QVector<int> m_expandedRowTypes;
|
QVector<int> m_expandedRowTypes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -37,12 +37,17 @@
|
|||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace QmlProfiler {
|
namespace QmlProfiler {
|
||||||
|
|
||||||
class QmlProfilerStatisticsModel::QmlProfilerStatisticsModelPrivate
|
class QmlProfilerStatisticsModel::QmlProfilerStatisticsModelPrivate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QHash<int, QmlProfilerStatisticsModel::QmlEventStats> data;
|
QHash<int, QmlProfilerStatisticsModel::QmlEventStats> data;
|
||||||
|
QHash<int, QmlProfilerStatisticsModel::QmlEventStats> workingSet;
|
||||||
|
|
||||||
|
|
||||||
QPointer<QmlProfilerStatisticsRelativesModel> childrenModel;
|
QPointer<QmlProfilerStatisticsRelativesModel> childrenModel;
|
||||||
QPointer<QmlProfilerStatisticsRelativesModel> parentsModel;
|
QPointer<QmlProfilerStatisticsRelativesModel> parentsModel;
|
||||||
|
|
||||||
@@ -87,12 +92,34 @@ QmlProfilerStatisticsModel::~QmlProfilerStatisticsModel()
|
|||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerStatisticsModel::setEventTypeAccepted(RangeType type, bool accepted)
|
void QmlProfilerStatisticsModel::restrictToFeatures(qint64 features)
|
||||||
{
|
{
|
||||||
if (accepted && !d->acceptedTypes.contains(type))
|
bool didChange = false;
|
||||||
d->acceptedTypes << type;
|
for (int i = 0; i < MaximumRangeType; ++i) {
|
||||||
else if (!accepted && d->acceptedTypes.contains(type))
|
RangeType type = static_cast<RangeType>(i);
|
||||||
d->acceptedTypes.removeOne(type);
|
quint64 featureFlag = 1ULL << featureFromRangeType(type);
|
||||||
|
if (Constants::QML_JS_RANGE_FEATURES & featureFlag) {
|
||||||
|
bool accepted = features & featureFlag;
|
||||||
|
if (accepted && !d->acceptedTypes.contains(type)) {
|
||||||
|
d->acceptedTypes << type;
|
||||||
|
didChange = true;
|
||||||
|
} else if (!accepted && d->acceptedTypes.contains(type)) {
|
||||||
|
d->acceptedTypes.removeOne(type);
|
||||||
|
didChange = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!didChange || d->modelManager->state() != QmlProfilerModelManager::Done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
clear();
|
||||||
|
d->modelManager->qmlModel()->replayEvents(d->modelManager->traceTime()->startTime(),
|
||||||
|
d->modelManager->traceTime()->endTime(),
|
||||||
|
std::bind(&QmlProfilerStatisticsModel::loadEvent,
|
||||||
|
this, std::placeholders::_1,
|
||||||
|
std::placeholders::_2));
|
||||||
|
finalize();
|
||||||
|
notesChanged(-1); // Reload notes
|
||||||
}
|
}
|
||||||
|
|
||||||
const QHash<int, QmlProfilerStatisticsModel::QmlEventStats> &QmlProfilerStatisticsModel::getData() const
|
const QHash<int, QmlProfilerStatisticsModel::QmlEventStats> &QmlProfilerStatisticsModel::getData() const
|
||||||
@@ -126,12 +153,6 @@ void QmlProfilerStatisticsModel::clear()
|
|||||||
d->parentsModel->clear();
|
d->parentsModel->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerStatisticsModel::limitToRange(qint64 rangeStart, qint64 rangeEnd)
|
|
||||||
{
|
|
||||||
if (!d->modelManager->isEmpty())
|
|
||||||
loadData(rangeStart, rangeEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlProfilerStatisticsModel::setRelativesModel(QmlProfilerStatisticsRelativesModel *relative,
|
void QmlProfilerStatisticsModel::setRelativesModel(QmlProfilerStatisticsRelativesModel *relative,
|
||||||
QmlProfilerStatisticsRelation relation)
|
QmlProfilerStatisticsRelation relation)
|
||||||
{
|
{
|
||||||
@@ -141,11 +162,14 @@ void QmlProfilerStatisticsModel::setRelativesModel(QmlProfilerStatisticsRelative
|
|||||||
d->childrenModel = relative;
|
d->childrenModel = relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QmlProfilerModelManager *QmlProfilerStatisticsModel::modelManager() const
|
||||||
|
{
|
||||||
|
return d->modelManager;
|
||||||
|
}
|
||||||
|
|
||||||
void QmlProfilerStatisticsModel::dataChanged()
|
void QmlProfilerStatisticsModel::dataChanged()
|
||||||
{
|
{
|
||||||
if (d->modelManager->state() == QmlProfilerModelManager::ProcessingData)
|
if (d->modelManager->state() == QmlProfilerModelManager::ClearingData)
|
||||||
loadData();
|
|
||||||
else if (d->modelManager->state() == QmlProfilerModelManager::ClearingData)
|
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,79 +205,52 @@ void QmlProfilerStatisticsModel::notesChanged(int typeIndex)
|
|||||||
emit notesAvailable(typeIndex);
|
emit notesAvailable(typeIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerStatisticsModel::loadData(qint64 rangeStart, qint64 rangeEnd)
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
|
|
||||||
const bool checkRanges = (rangeStart != -1) && (rangeEnd != -1);
|
|
||||||
|
|
||||||
const QVector<QmlEvent> &eventList = d->modelManager->qmlModel()->events();
|
|
||||||
const QVector<QmlEventType> &typesList = d->modelManager->qmlModel()->eventTypes();
|
|
||||||
|
|
||||||
for (int i = 0; i < eventList.size(); ++i) {
|
|
||||||
const QmlEvent &event = eventList[i];
|
|
||||||
const QmlEventType &type = typesList[event.typeIndex()];
|
|
||||||
|
|
||||||
if (checkRanges) {
|
|
||||||
if ((event.timestamp() + event.duration() < rangeStart)
|
|
||||||
|| (event.timestamp() > rangeEnd))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
loadEvent(event, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
finalize();
|
|
||||||
if (checkRanges)
|
|
||||||
notesChanged(-1); // Reload notes
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlProfilerStatisticsModel::loadEvent(const QmlEvent &event, const QmlEventType &type)
|
void QmlProfilerStatisticsModel::loadEvent(const QmlEvent &event, const QmlEventType &type)
|
||||||
{
|
{
|
||||||
if (!d->acceptedTypes.contains(type.rangeType))
|
if (!d->acceptedTypes.contains(type.rangeType))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// update stats
|
switch (event.rangeStage()) {
|
||||||
QmlEventStats *stats = &d->data[event.typeIndex()];
|
case RangeStart:
|
||||||
|
// binding loop detection: check whether event is already in stack
|
||||||
stats->duration += event.duration();
|
for (int ii = 1; ii < d->callStack.size(); ++ii) {
|
||||||
stats->durationSelf += event.duration();
|
if (d->callStack.at(ii).typeIndex() == event.typeIndex()
|
||||||
if (event.duration() < stats->minTime)
|
&& type.rangeType != Javascript) {
|
||||||
stats->minTime = event.duration();
|
d->eventsInBindingLoop.insert(event.typeIndex());
|
||||||
if (event.duration() > stats->maxTime)
|
break;
|
||||||
stats->maxTime = event.duration();
|
}
|
||||||
stats->calls++;
|
}
|
||||||
|
d->callStack.push(event);
|
||||||
// for median computing
|
break;
|
||||||
d->durations[event.typeIndex()].append(event.duration());
|
case RangeEnd: {
|
||||||
|
// update stats
|
||||||
// qml time computation
|
QmlEventStats *stats = &d->data[event.typeIndex()];
|
||||||
if (event.timestamp() > d->lastEndTime) { // assume parent event if starts before last end
|
qint64 duration = event.timestamp() - d->callStack.top().timestamp();
|
||||||
d->qmlTime += event.duration();
|
stats->duration += duration;
|
||||||
d->lastEndTime = event.timestamp() + event.duration();
|
stats->durationSelf += duration;
|
||||||
}
|
if (duration < stats->minTime)
|
||||||
|
stats->minTime = duration;
|
||||||
//
|
if (duration > stats->maxTime)
|
||||||
// binding loop detection
|
stats->maxTime = duration;
|
||||||
//
|
stats->calls++;
|
||||||
const QmlEvent *potentialParent = &(d->callStack.top());
|
// for median computing
|
||||||
while (potentialParent->isValid() &&
|
d->durations[event.typeIndex()].append(duration);
|
||||||
!(potentialParent->timestamp() + potentialParent->duration() > event.timestamp())) {
|
// qml time computation
|
||||||
d->callStack.pop();
|
if (event.timestamp() > d->lastEndTime) { // assume parent event if starts before last end
|
||||||
potentialParent = &(d->callStack.top());
|
d->qmlTime += duration;
|
||||||
}
|
d->lastEndTime = event.timestamp();
|
||||||
|
|
||||||
// check whether event is already in stack
|
|
||||||
for (int ii = 1; ii < d->callStack.size(); ++ii) {
|
|
||||||
if (d->callStack.at(ii).typeIndex() == event.typeIndex()) {
|
|
||||||
d->eventsInBindingLoop.insert(event.typeIndex());
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (d->callStack.count() > 1)
|
d->callStack.pop();
|
||||||
d->data[d->callStack.top().typeIndex()].durationSelf -= event.duration();
|
|
||||||
d->callStack.push(event);
|
if (d->callStack.count() > 1)
|
||||||
|
d->data[d->callStack.top().typeIndex()].durationSelf -= duration;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!d->childrenModel.isNull())
|
if (!d->childrenModel.isNull())
|
||||||
d->childrenModel->loadEvent(event);
|
d->childrenModel->loadEvent(event);
|
||||||
@@ -294,6 +291,7 @@ void QmlProfilerStatisticsModel::finalize()
|
|||||||
rootEvent.percentSelf = 1.0 / rootEvent.duration;
|
rootEvent.percentSelf = 1.0 / rootEvent.duration;
|
||||||
|
|
||||||
d->data.insert(-1, rootEvent);
|
d->data.insert(-1, rootEvent);
|
||||||
|
|
||||||
if (!d->childrenModel.isNull())
|
if (!d->childrenModel.isNull())
|
||||||
d->childrenModel->finalize(d->eventsInBindingLoop);
|
d->childrenModel->finalize(d->eventsInBindingLoop);
|
||||||
if (!d->parentsModel.isNull())
|
if (!d->parentsModel.isNull())
|
||||||
@@ -312,7 +310,7 @@ QmlProfilerStatisticsRelativesModel::QmlProfilerStatisticsRelativesModel(
|
|||||||
QmlProfilerStatisticsRelation relation, QObject *parent) :
|
QmlProfilerStatisticsRelation relation, QObject *parent) :
|
||||||
QObject(parent), m_relation(relation)
|
QObject(parent), m_relation(relation)
|
||||||
{
|
{
|
||||||
m_endtimesPerLevel[0] = 0;
|
m_startTimesPerLevel[0] = 0;
|
||||||
|
|
||||||
QTC_CHECK(modelManager);
|
QTC_CHECK(modelManager);
|
||||||
m_modelManager = modelManager;
|
m_modelManager = modelManager;
|
||||||
@@ -346,40 +344,42 @@ const QVector<QmlEventType> &QmlProfilerStatisticsRelativesModel::getTypes() con
|
|||||||
void QmlProfilerStatisticsRelativesModel::loadEvent(const QmlEvent &event)
|
void QmlProfilerStatisticsRelativesModel::loadEvent(const QmlEvent &event)
|
||||||
{
|
{
|
||||||
// level computation
|
// level computation
|
||||||
if (m_endtimesPerLevel[m_level] > event.timestamp()) {
|
switch (event.rangeStage()) {
|
||||||
m_level++;
|
case RangeStart:
|
||||||
} else {
|
// now lastparent is the new type
|
||||||
while (m_level > Constants::QML_MIN_LEVEL &&
|
++m_level;
|
||||||
m_endtimesPerLevel[m_level-1] <= event.timestamp())
|
m_typesPerLevel[m_level] = event.typeIndex();
|
||||||
m_level--;
|
m_startTimesPerLevel[m_level] = event.timestamp();
|
||||||
|
break;
|
||||||
|
case RangeEnd: {
|
||||||
|
int parentTypeIndex = -1;
|
||||||
|
if (m_level > Constants::QML_MIN_LEVEL && m_typesPerLevel.contains(m_level-1))
|
||||||
|
parentTypeIndex = m_typesPerLevel[m_level-1];
|
||||||
|
|
||||||
|
int relativeTypeIndex = (m_relation == QmlProfilerStatisticsParents) ? parentTypeIndex :
|
||||||
|
event.typeIndex();
|
||||||
|
int selfTypeIndex = (m_relation == QmlProfilerStatisticsParents) ? event.typeIndex() :
|
||||||
|
parentTypeIndex;
|
||||||
|
|
||||||
|
QmlStatisticsRelativesMap &relativesMap = m_data[selfTypeIndex];
|
||||||
|
QmlStatisticsRelativesMap::Iterator it = relativesMap.find(relativeTypeIndex);
|
||||||
|
if (it != relativesMap.end()) {
|
||||||
|
it.value().calls++;
|
||||||
|
it.value().duration += event.timestamp() - m_startTimesPerLevel[m_level];
|
||||||
|
} else {
|
||||||
|
QmlStatisticsRelativesData relative = {
|
||||||
|
event.timestamp() - m_startTimesPerLevel[m_level],
|
||||||
|
1,
|
||||||
|
false
|
||||||
|
};
|
||||||
|
relativesMap.insert(relativeTypeIndex, relative);
|
||||||
|
}
|
||||||
|
--m_level;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
m_endtimesPerLevel[m_level] = event.timestamp() + event.duration();
|
default:
|
||||||
|
break;
|
||||||
int parentTypeIndex = -1;
|
|
||||||
if (m_level > Constants::QML_MIN_LEVEL && m_lastParent.contains(m_level-1))
|
|
||||||
parentTypeIndex = m_lastParent[m_level-1];
|
|
||||||
|
|
||||||
int relativeTypeIndex = (m_relation == QmlProfilerStatisticsParents) ? parentTypeIndex :
|
|
||||||
event.typeIndex();
|
|
||||||
int selfTypeIndex = (m_relation == QmlProfilerStatisticsParents) ? event.typeIndex() :
|
|
||||||
parentTypeIndex;
|
|
||||||
|
|
||||||
QmlStatisticsRelativesMap &relativesMap = m_data[selfTypeIndex];
|
|
||||||
QmlStatisticsRelativesMap::Iterator it = relativesMap.find(relativeTypeIndex);
|
|
||||||
if (it != relativesMap.end()) {
|
|
||||||
it.value().calls++;
|
|
||||||
it.value().duration += event.duration();
|
|
||||||
} else {
|
|
||||||
QmlStatisticsRelativesData relative = {
|
|
||||||
event.duration(),
|
|
||||||
1,
|
|
||||||
false
|
|
||||||
};
|
|
||||||
relativesMap.insert(relativeTypeIndex, relative);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// now lastparent is the new type
|
|
||||||
m_lastParent[m_level] = event.typeIndex();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerStatisticsRelativesModel::finalize(const QSet<int> &eventsInBindingLoop)
|
void QmlProfilerStatisticsRelativesModel::finalize(const QSet<int> &eventsInBindingLoop)
|
||||||
@@ -402,10 +402,10 @@ int QmlProfilerStatisticsRelativesModel::count() const
|
|||||||
void QmlProfilerStatisticsRelativesModel::clear()
|
void QmlProfilerStatisticsRelativesModel::clear()
|
||||||
{
|
{
|
||||||
m_data.clear();
|
m_data.clear();
|
||||||
m_endtimesPerLevel.clear();
|
m_startTimesPerLevel.clear();
|
||||||
m_level = Constants::QML_MIN_LEVEL;
|
m_level = Constants::QML_MIN_LEVEL;
|
||||||
m_endtimesPerLevel[0] = 0;
|
m_startTimesPerLevel[0] = 0;
|
||||||
m_lastParent.clear();
|
m_typesPerLevel.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace QmlProfiler
|
} // namespace QmlProfiler
|
||||||
|
@@ -68,7 +68,7 @@ public:
|
|||||||
QmlProfilerStatisticsModel(QmlProfilerModelManager *modelManager, QObject *parent = 0);
|
QmlProfilerStatisticsModel(QmlProfilerModelManager *modelManager, QObject *parent = 0);
|
||||||
~QmlProfilerStatisticsModel();
|
~QmlProfilerStatisticsModel();
|
||||||
|
|
||||||
void setEventTypeAccepted(RangeType type, bool accepted);
|
void restrictToFeatures(qint64 features);
|
||||||
|
|
||||||
const QHash<int, QmlEventStats> &getData() const;
|
const QHash<int, QmlEventStats> &getData() const;
|
||||||
const QVector<QmlEventType> &getTypes() const;
|
const QVector<QmlEventType> &getTypes() const;
|
||||||
@@ -77,16 +77,15 @@ public:
|
|||||||
int count() const;
|
int count() const;
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
void limitToRange(qint64 rangeStart, qint64 rangeEnd);
|
|
||||||
void setRelativesModel(QmlProfilerStatisticsRelativesModel *childModel,
|
void setRelativesModel(QmlProfilerStatisticsRelativesModel *childModel,
|
||||||
QmlProfilerStatisticsRelation relation);
|
QmlProfilerStatisticsRelation relation);
|
||||||
|
QmlProfilerModelManager *modelManager() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void dataAvailable();
|
void dataAvailable();
|
||||||
void notesAvailable(int typeIndex);
|
void notesAvailable(int typeIndex);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadData(qint64 rangeStart = -1, qint64 rangeEnd = -1);
|
|
||||||
void loadEvent(const QmlEvent &event, const QmlEventType &type);
|
void loadEvent(const QmlEvent &event, const QmlEventType &type);
|
||||||
void finalize();
|
void finalize();
|
||||||
|
|
||||||
@@ -133,11 +132,11 @@ protected:
|
|||||||
QmlProfilerModelManager *m_modelManager;
|
QmlProfilerModelManager *m_modelManager;
|
||||||
|
|
||||||
// for level computation
|
// for level computation
|
||||||
QHash<int, qint64> m_endtimesPerLevel;
|
QHash<int, qint64> m_startTimesPerLevel;
|
||||||
int m_level = Constants::QML_MIN_LEVEL;
|
int m_level = Constants::QML_MIN_LEVEL;
|
||||||
|
|
||||||
// compute parent-child relationship and call count
|
// compute parent-child relationship and call count
|
||||||
QHash<int, int> m_lastParent;
|
QHash<int, int> m_typesPerLevel;
|
||||||
const QmlProfilerStatisticsRelation m_relation;
|
const QmlProfilerStatisticsRelation m_relation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -110,8 +110,6 @@ public:
|
|||||||
QmlProfilerStatisticsRelativesView *m_eventParents;
|
QmlProfilerStatisticsRelativesView *m_eventParents;
|
||||||
|
|
||||||
QmlProfilerStatisticsModel *model;
|
QmlProfilerStatisticsModel *model;
|
||||||
qint64 rangeStart;
|
|
||||||
qint64 rangeEnd;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void setViewDefaults(Utils::TreeView *view)
|
static void setViewDefaults(Utils::TreeView *view)
|
||||||
@@ -228,8 +226,6 @@ QmlProfilerStatisticsView::QmlProfilerStatisticsView(QWidget *parent,
|
|||||||
splitterVertical->setStretchFactor(1,2);
|
splitterVertical->setStretchFactor(1,2);
|
||||||
groupLayout->addWidget(splitterVertical);
|
groupLayout->addWidget(splitterVertical);
|
||||||
setLayout(groupLayout);
|
setLayout(groupLayout);
|
||||||
|
|
||||||
d->rangeStart = d->rangeEnd = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlProfilerStatisticsView::~QmlProfilerStatisticsView()
|
QmlProfilerStatisticsView::~QmlProfilerStatisticsView()
|
||||||
@@ -243,14 +239,6 @@ void QmlProfilerStatisticsView::clear()
|
|||||||
d->m_eventTree->clear();
|
d->m_eventTree->clear();
|
||||||
d->m_eventChildren->clear();
|
d->m_eventChildren->clear();
|
||||||
d->m_eventParents->clear();
|
d->m_eventParents->clear();
|
||||||
d->rangeStart = d->rangeEnd = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QmlProfilerStatisticsView::restrictToRange(qint64 rangeStart, qint64 rangeEnd)
|
|
||||||
{
|
|
||||||
d->rangeStart = rangeStart;
|
|
||||||
d->rangeEnd = rangeEnd;
|
|
||||||
d->model->limitToRange(rangeStart, rangeEnd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex QmlProfilerStatisticsView::selectedModelIndex() const
|
QModelIndex QmlProfilerStatisticsView::selectedModelIndex() const
|
||||||
@@ -285,7 +273,7 @@ void QmlProfilerStatisticsView::contextMenuEvent(QContextMenuEvent *ev)
|
|||||||
|
|
||||||
menu.addSeparator();
|
menu.addSeparator();
|
||||||
getGlobalStatsAction = menu.addAction(tr("Show Full Range"));
|
getGlobalStatsAction = menu.addAction(tr("Show Full Range"));
|
||||||
if (!isRestrictedToRange())
|
if (!d->model->modelManager()->isRestrictedToRange())
|
||||||
getGlobalStatsAction->setEnabled(false);
|
getGlobalStatsAction->setEnabled(false);
|
||||||
|
|
||||||
QAction *selectedAction = menu.exec(position);
|
QAction *selectedAction = menu.exec(position);
|
||||||
@@ -327,18 +315,7 @@ void QmlProfilerStatisticsView::selectByTypeId(int typeIndex)
|
|||||||
|
|
||||||
void QmlProfilerStatisticsView::onVisibleFeaturesChanged(quint64 features)
|
void QmlProfilerStatisticsView::onVisibleFeaturesChanged(quint64 features)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MaximumRangeType; ++i) {
|
d->model->restrictToFeatures(features);
|
||||||
RangeType range = static_cast<RangeType>(i);
|
|
||||||
quint64 featureFlag = 1ULL << featureFromRangeType(range);
|
|
||||||
if (Constants::QML_JS_RANGE_FEATURES & featureFlag)
|
|
||||||
d->model->setEventTypeAccepted(range, features & featureFlag);
|
|
||||||
}
|
|
||||||
d->model->limitToRange(d->rangeStart, d->rangeEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QmlProfilerStatisticsView::isRestrictedToRange() const
|
|
||||||
{
|
|
||||||
return d->rangeStart != -1 || d->rangeEnd != -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerStatisticsView::setShowExtendedStatistics(bool show)
|
void QmlProfilerStatisticsView::setShowExtendedStatistics(bool show)
|
||||||
|
@@ -78,10 +78,7 @@ public:
|
|||||||
explicit QmlProfilerStatisticsView(QWidget *parent,
|
explicit QmlProfilerStatisticsView(QWidget *parent,
|
||||||
QmlProfilerModelManager *profilerModelManager);
|
QmlProfilerModelManager *profilerModelManager);
|
||||||
~QmlProfilerStatisticsView();
|
~QmlProfilerStatisticsView();
|
||||||
|
|
||||||
void clear() override;
|
void clear() override;
|
||||||
void restrictToRange(qint64 rangeStart, qint64 rangeEnd) override;
|
|
||||||
bool isRestrictedToRange() const override;
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void selectByTypeId(int typeIndex) override;
|
void selectByTypeId(int typeIndex) override;
|
||||||
|
@@ -95,7 +95,6 @@ void QmlProfilerTimelineModel::dataChanged()
|
|||||||
|
|
||||||
switch (m_modelManager->state()) {
|
switch (m_modelManager->state()) {
|
||||||
case QmlProfilerModelManager::Done:
|
case QmlProfilerModelManager::Done:
|
||||||
loadData();
|
|
||||||
emit emptyChanged();
|
emit emptyChanged();
|
||||||
break;
|
break;
|
||||||
case QmlProfilerModelManager::ClearingData:
|
case QmlProfilerModelManager::ClearingData:
|
||||||
@@ -139,21 +138,4 @@ QVariantMap QmlProfilerTimelineModel::locationFromTypeId(int index) const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerTimelineModel::loadData()
|
|
||||||
{
|
|
||||||
QmlProfilerDataModel *simpleModel = modelManager()->qmlModel();
|
|
||||||
if (simpleModel->isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const QVector<QmlEventType> &types = simpleModel->eventTypes();
|
|
||||||
|
|
||||||
foreach (const QmlEvent &event, simpleModel->events()) {
|
|
||||||
const QmlEventType &type = types[event.typeIndex()];
|
|
||||||
if (accepted(type)) {
|
|
||||||
loadEvent(event, type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace QmlProfiler
|
} // namespace QmlProfiler
|
||||||
|
@@ -53,8 +53,6 @@ public:
|
|||||||
Q_INVOKABLE virtual int bindingLoopDest(int index) const;
|
Q_INVOKABLE virtual int bindingLoopDest(int index) const;
|
||||||
QVariantMap locationFromTypeId(int index) const;
|
QVariantMap locationFromTypeId(int index) const;
|
||||||
|
|
||||||
void loadData();
|
|
||||||
|
|
||||||
virtual void loadEvent(const QmlEvent &event, const QmlEventType &type) = 0;
|
virtual void loadEvent(const QmlEvent &event, const QmlEventType &type) = 0;
|
||||||
virtual void finalize() = 0;
|
virtual void finalize() = 0;
|
||||||
void clear();
|
void clear();
|
||||||
|
@@ -24,6 +24,8 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "qmlprofilertraceclient.h"
|
#include "qmlprofilertraceclient.h"
|
||||||
|
#include "qmltypedevent.h"
|
||||||
|
|
||||||
#include <qmldebug/qmlenginecontrolclient.h>
|
#include <qmldebug/qmlenginecontrolclient.h>
|
||||||
#include <qmldebug/qdebugmessageclient.h>
|
#include <qmldebug/qdebugmessageclient.h>
|
||||||
#include <qmldebug/qpacketprotocol.h>
|
#include <qmldebug/qpacketprotocol.h>
|
||||||
@@ -35,14 +37,12 @@ public:
|
|||||||
QmlProfilerTraceClientPrivate(QmlProfilerTraceClient *_q, QmlDebug::QmlDebugConnection *client)
|
QmlProfilerTraceClientPrivate(QmlProfilerTraceClient *_q, QmlDebug::QmlDebugConnection *client)
|
||||||
: q(_q)
|
: q(_q)
|
||||||
, engineControl(client)
|
, engineControl(client)
|
||||||
, inProgressRanges(0)
|
|
||||||
, maximumTime(0)
|
, maximumTime(0)
|
||||||
, recording(false)
|
, recording(false)
|
||||||
, requestedFeatures(0)
|
, requestedFeatures(0)
|
||||||
, recordedFeatures(0)
|
, recordedFeatures(0)
|
||||||
, flushInterval(0)
|
, flushInterval(0)
|
||||||
{
|
{
|
||||||
::memset(rangeCount, 0, MaximumRangeType * sizeof(int));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendRecordingStatus(int engineId);
|
void sendRecordingStatus(int engineId);
|
||||||
@@ -51,17 +51,14 @@ public:
|
|||||||
QmlProfilerTraceClient *q;
|
QmlProfilerTraceClient *q;
|
||||||
QmlDebug::QmlEngineControlClient engineControl;
|
QmlDebug::QmlEngineControlClient engineControl;
|
||||||
QScopedPointer<QmlDebug::QDebugMessageClient> messageClient;
|
QScopedPointer<QmlDebug::QDebugMessageClient> messageClient;
|
||||||
qint64 inProgressRanges;
|
|
||||||
QStack<qint64> rangeStartTimes[MaximumRangeType];
|
|
||||||
QStack<QString> rangeDatas[MaximumRangeType];
|
|
||||||
QStack<QmlEventLocation> rangeLocations[MaximumRangeType];
|
|
||||||
QStack<BindingType> bindingTypes;
|
|
||||||
int rangeCount[MaximumRangeType];
|
|
||||||
qint64 maximumTime;
|
qint64 maximumTime;
|
||||||
bool recording;
|
bool recording;
|
||||||
quint64 requestedFeatures;
|
quint64 requestedFeatures;
|
||||||
quint64 recordedFeatures;
|
quint64 recordedFeatures;
|
||||||
quint32 flushInterval;
|
quint32 flushInterval;
|
||||||
|
|
||||||
|
// Reuse the same event, so that we don't have to constantly reallocate all the data.
|
||||||
|
QmlTypedEvent currentEvent;
|
||||||
};
|
};
|
||||||
|
|
||||||
void QmlProfilerTraceClientPrivate::sendRecordingStatus(int engineId)
|
void QmlProfilerTraceClientPrivate::sendRecordingStatus(int engineId)
|
||||||
@@ -94,13 +91,6 @@ QmlProfilerTraceClient::~QmlProfilerTraceClient()
|
|||||||
|
|
||||||
void QmlProfilerTraceClient::clearData()
|
void QmlProfilerTraceClient::clearData()
|
||||||
{
|
{
|
||||||
::memset(d->rangeCount, 0, MaximumRangeType * sizeof(int));
|
|
||||||
for (int eventType = 0; eventType < MaximumRangeType; eventType++) {
|
|
||||||
d->rangeDatas[eventType].clear();
|
|
||||||
d->rangeLocations[eventType].clear();
|
|
||||||
d->rangeStartTimes[eventType].clear();
|
|
||||||
}
|
|
||||||
d->bindingTypes.clear();
|
|
||||||
if (d->recordedFeatures != 0) {
|
if (d->recordedFeatures != 0) {
|
||||||
d->recordedFeatures = 0;
|
d->recordedFeatures = 0;
|
||||||
emit recordedFeaturesChanged(0);
|
emit recordedFeaturesChanged(0);
|
||||||
@@ -146,8 +136,18 @@ void QmlProfilerTraceClient::setRequestedFeatures(quint64 features)
|
|||||||
const QmlDebug::QDebugContextInfo &context)
|
const QmlDebug::QDebugContextInfo &context)
|
||||||
{
|
{
|
||||||
d->updateFeatures(ProfileDebugMessages);
|
d->updateFeatures(ProfileDebugMessages);
|
||||||
emit debugMessage(context.timestamp, type, text,
|
d->currentEvent.event.setTimestamp(context.timestamp);
|
||||||
QmlEventLocation(context.file, context.line, 1));
|
d->currentEvent.event.setTypeIndex(-1);
|
||||||
|
d->currentEvent.event.setString(text);
|
||||||
|
d->currentEvent.type.location.filename = context.file;
|
||||||
|
d->currentEvent.type.location.line = context.line;
|
||||||
|
d->currentEvent.type.location.column = 1;
|
||||||
|
d->currentEvent.type.displayName.clear();
|
||||||
|
d->currentEvent.type.data.clear();
|
||||||
|
d->currentEvent.type.message = DebugMessage;
|
||||||
|
d->currentEvent.type.rangeType = MaximumRangeType;
|
||||||
|
d->currentEvent.type.detailType = type;
|
||||||
|
emit qmlEvent(d->currentEvent.event, d->currentEvent.type);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
d->messageClient.reset();
|
d->messageClient.reset();
|
||||||
@@ -189,210 +189,24 @@ void QmlProfilerTraceClient::messageReceived(const QByteArray &data)
|
|||||||
{
|
{
|
||||||
QmlDebug::QPacket stream(connection()->currentDataStreamVersion(), data);
|
QmlDebug::QPacket stream(connection()->currentDataStreamVersion(), data);
|
||||||
|
|
||||||
qint64 time;
|
stream >> d->currentEvent;
|
||||||
int messageType;
|
|
||||||
int subtype;
|
|
||||||
|
|
||||||
stream >> time >> messageType;
|
d->maximumTime = qMax(d->currentEvent.event.timestamp(), d->maximumTime);
|
||||||
if (!stream.atEnd())
|
if (d->currentEvent.type.message == Complete) {
|
||||||
stream >> subtype;
|
|
||||||
else
|
|
||||||
subtype = -1;
|
|
||||||
|
|
||||||
switch (messageType) {
|
|
||||||
case Event: {
|
|
||||||
switch (subtype) {
|
|
||||||
case StartTrace: {
|
|
||||||
if (!d->recording)
|
|
||||||
setRecordingFromServer(true);
|
|
||||||
QList<int> engineIds;
|
|
||||||
while (!stream.atEnd()) {
|
|
||||||
int id;
|
|
||||||
stream >> id;
|
|
||||||
engineIds << id;
|
|
||||||
}
|
|
||||||
emit traceStarted(time, engineIds);
|
|
||||||
d->maximumTime = time;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case EndTrace: {
|
|
||||||
QList<int> engineIds;
|
|
||||||
while (!stream.atEnd()) {
|
|
||||||
int id;
|
|
||||||
stream >> id;
|
|
||||||
engineIds << id;
|
|
||||||
}
|
|
||||||
emit traceFinished(time, engineIds);
|
|
||||||
d->maximumTime = time;
|
|
||||||
d->maximumTime = qMax(time, d->maximumTime);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AnimationFrame: {
|
|
||||||
if (!d->updateFeatures(ProfileAnimations))
|
|
||||||
break;
|
|
||||||
int frameRate, animationCount;
|
|
||||||
int threadId;
|
|
||||||
stream >> frameRate >> animationCount;
|
|
||||||
if (!stream.atEnd())
|
|
||||||
stream >> threadId;
|
|
||||||
else
|
|
||||||
threadId = 0;
|
|
||||||
|
|
||||||
emit rangedEvent(Event, MaximumRangeType, AnimationFrame, time, 0, QString(),
|
|
||||||
QmlEventLocation(), frameRate, animationCount, threadId,
|
|
||||||
0, 0);
|
|
||||||
d->maximumTime = qMax(time, d->maximumTime);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Key:
|
|
||||||
case Mouse:
|
|
||||||
if (!d->updateFeatures(ProfileInputEvents))
|
|
||||||
break;
|
|
||||||
int inputType = (subtype == Key ? InputKeyUnknown : InputMouseUnknown);
|
|
||||||
if (!stream.atEnd())
|
|
||||||
stream >> inputType;
|
|
||||||
int a = -1;
|
|
||||||
if (!stream.atEnd())
|
|
||||||
stream >> a;
|
|
||||||
int b = -1;
|
|
||||||
if (!stream.atEnd())
|
|
||||||
stream >> b;
|
|
||||||
|
|
||||||
emit rangedEvent(Event, MaximumRangeType, subtype, time, 0, QString(),
|
|
||||||
QmlEventLocation(), inputType, a, b, 0, 0);
|
|
||||||
d->maximumTime = qMax(time, d->maximumTime);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Complete:
|
|
||||||
emit complete(d->maximumTime);
|
emit complete(d->maximumTime);
|
||||||
setRecordingFromServer(false);
|
setRecordingFromServer(false);
|
||||||
break;
|
} else if (d->currentEvent.type.message == Event
|
||||||
case SceneGraphFrame: {
|
&& d->currentEvent.type.detailType == StartTrace) {
|
||||||
if (!d->updateFeatures(ProfileSceneGraph))
|
if (!d->recording)
|
||||||
break;
|
setRecordingFromServer(true);
|
||||||
|
emit traceStarted(d->currentEvent.event.timestamp(),
|
||||||
int count = 0;
|
d->currentEvent.event.numbers<QList<int>, qint32>());
|
||||||
qint64 params[5];
|
} else if (d->currentEvent.type.message == Event
|
||||||
|
&& d->currentEvent.type.detailType == EndTrace) {
|
||||||
while (!stream.atEnd()) {
|
emit traceFinished(d->currentEvent.event.timestamp(),
|
||||||
stream >> params[count++];
|
d->currentEvent.event.numbers<QList<int>, qint32>());
|
||||||
}
|
} else if (d->updateFeatures(d->currentEvent.type.feature())) {
|
||||||
while (count<5)
|
emit qmlEvent(d->currentEvent.event, d->currentEvent.type);
|
||||||
params[count++] = 0;
|
|
||||||
emit rangedEvent(SceneGraphFrame, MaximumRangeType, subtype,time, 0,
|
|
||||||
QString(), QmlEventLocation(), params[0], params[1],
|
|
||||||
params[2], params[3], params[4]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PixmapCacheEvent: {
|
|
||||||
if (!d->updateFeatures(ProfilePixmapCache))
|
|
||||||
break;
|
|
||||||
int width = 0, height = 0, refcount = 0;
|
|
||||||
QString pixUrl;
|
|
||||||
stream >> pixUrl;
|
|
||||||
if (subtype == (int)PixmapReferenceCountChanged || subtype == (int)PixmapCacheCountChanged) {
|
|
||||||
stream >> refcount;
|
|
||||||
} else if (subtype == (int)PixmapSizeKnown) {
|
|
||||||
stream >> width >> height;
|
|
||||||
refcount = 1;
|
|
||||||
}
|
|
||||||
emit rangedEvent(PixmapCacheEvent, MaximumRangeType, subtype, time, 0,
|
|
||||||
QString(), QmlEventLocation(pixUrl,0,0), width, height,
|
|
||||||
refcount, 0, 0);
|
|
||||||
d->maximumTime = qMax(time, d->maximumTime);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MemoryAllocation: {
|
|
||||||
if (!d->updateFeatures(ProfileMemory))
|
|
||||||
break;
|
|
||||||
|
|
||||||
qint64 delta;
|
|
||||||
stream >> delta;
|
|
||||||
emit rangedEvent(MemoryAllocation, MaximumRangeType, subtype, time, 0,
|
|
||||||
QString(), QmlEventLocation(), delta, 0, 0, 0, 0);
|
|
||||||
d->maximumTime = qMax(time, d->maximumTime);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RangeStart: {
|
|
||||||
if (!d->updateFeatures(featureFromRangeType(static_cast<RangeType>(subtype))))
|
|
||||||
break;
|
|
||||||
d->rangeStartTimes[subtype].push(time);
|
|
||||||
d->inProgressRanges |= (static_cast<qint64>(1) << subtype);
|
|
||||||
++d->rangeCount[subtype];
|
|
||||||
|
|
||||||
// read binding type
|
|
||||||
if ((RangeType)subtype == Binding) {
|
|
||||||
int bindingType = (int)QmlBinding;
|
|
||||||
if (!stream.atEnd())
|
|
||||||
stream >> bindingType;
|
|
||||||
d->bindingTypes.push((BindingType)bindingType);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RangeData: {
|
|
||||||
if (!d->updateFeatures(featureFromRangeType(static_cast<RangeType>(subtype))))
|
|
||||||
break;
|
|
||||||
QString data;
|
|
||||||
stream >> data;
|
|
||||||
|
|
||||||
int count = d->rangeCount[subtype];
|
|
||||||
if (count > 0) {
|
|
||||||
while (d->rangeDatas[subtype].count() < count)
|
|
||||||
d->rangeDatas[subtype].push(QString());
|
|
||||||
d->rangeDatas[subtype][count-1] = data;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RangeLocation: {
|
|
||||||
if (!d->updateFeatures(featureFromRangeType(static_cast<RangeType>(subtype))))
|
|
||||||
break;
|
|
||||||
QString fileName;
|
|
||||||
int line;
|
|
||||||
int column = -1;
|
|
||||||
stream >> fileName >> line;
|
|
||||||
|
|
||||||
if (!stream.atEnd())
|
|
||||||
stream >> column;
|
|
||||||
|
|
||||||
if (d->rangeCount[subtype] > 0)
|
|
||||||
d->rangeLocations[subtype].push(QmlEventLocation(fileName, line, column));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RangeEnd: {
|
|
||||||
if (!d->updateFeatures(featureFromRangeType(static_cast<RangeType>(subtype))))
|
|
||||||
break;
|
|
||||||
if (d->rangeCount[subtype] == 0)
|
|
||||||
break;
|
|
||||||
--d->rangeCount[subtype];
|
|
||||||
if (d->inProgressRanges & (static_cast<qint64>(1) << subtype))
|
|
||||||
d->inProgressRanges &= ~(static_cast<qint64>(1) << subtype);
|
|
||||||
|
|
||||||
d->maximumTime = qMax(time, d->maximumTime);
|
|
||||||
QString data = d->rangeDatas[subtype].count() ? d->rangeDatas[subtype].pop() : QString();
|
|
||||||
QmlEventLocation location = d->rangeLocations[subtype].count() ? d->rangeLocations[subtype].pop() : QmlEventLocation();
|
|
||||||
|
|
||||||
qint64 startTime = d->rangeStartTimes[subtype].pop();
|
|
||||||
BindingType bindingType = QmlBinding;
|
|
||||||
if ((RangeType)subtype == Binding)
|
|
||||||
bindingType = d->bindingTypes.pop();
|
|
||||||
if ((RangeType)subtype == Painting)
|
|
||||||
bindingType = QPainterEvent;
|
|
||||||
emit rangedEvent(MaximumMessage, (RangeType)subtype, bindingType, startTime,
|
|
||||||
time - startTime, data, location, 0, 0, 0, 0, 0);
|
|
||||||
if (d->rangeCount[subtype] == 0) {
|
|
||||||
int count = d->rangeDatas[subtype].count() +
|
|
||||||
d->rangeStartTimes[subtype].count() +
|
|
||||||
d->rangeLocations[subtype].count();
|
|
||||||
if (count != 0)
|
|
||||||
qWarning() << "incorrectly nested data";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#include "qmlprofilereventtypes.h"
|
#include "qmlprofilereventtypes.h"
|
||||||
#include "qmleventlocation.h"
|
#include "qmleventlocation.h"
|
||||||
#include "qmlprofiler_global.h"
|
#include "qmlprofiler_global.h"
|
||||||
|
#include "qmltypedevent.h"
|
||||||
|
|
||||||
#include <qmldebug/qmldebugclient.h>
|
#include <qmldebug/qmldebugclient.h>
|
||||||
|
|
||||||
@@ -60,12 +61,7 @@ signals:
|
|||||||
void traceFinished(qint64 timestamp, const QList<int> &engineIds);
|
void traceFinished(qint64 timestamp, const QList<int> &engineIds);
|
||||||
void traceStarted(qint64 timestamp, const QList<int> &engineIds);
|
void traceStarted(qint64 timestamp, const QList<int> &engineIds);
|
||||||
|
|
||||||
void rangedEvent(Message, RangeType, int detailType, qint64 startTime, qint64 length,
|
void qmlEvent(const QmlEvent &event, const QmlEventType &type);
|
||||||
const QString &data, const QmlEventLocation &location, qint64 param1,
|
|
||||||
qint64 param2, qint64 param3, qint64 param4, qint64 param5);
|
|
||||||
|
|
||||||
void debugMessage(qint64 timestamp, QtMsgType type, const QString &text,
|
|
||||||
const QmlEventLocation &location);
|
|
||||||
|
|
||||||
void recordingChanged(bool arg);
|
void recordingChanged(bool arg);
|
||||||
void recordedFeaturesChanged(quint64 features);
|
void recordedFeaturesChanged(quint64 features);
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QXmlStreamReader>
|
#include <QXmlStreamReader>
|
||||||
#include <QXmlStreamWriter>
|
#include <QXmlStreamWriter>
|
||||||
|
#include <QStack>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
namespace QmlProfiler {
|
namespace QmlProfiler {
|
||||||
@@ -181,6 +182,9 @@ bool QmlProfilerFileReader::load(QIODevice *device)
|
|||||||
emit error(tr("Error while parsing trace data file: %1").arg(stream.errorString()));
|
emit error(tr("Error while parsing trace data file: %1").arg(stream.errorString()));
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
std::sort(m_events.begin(), m_events.end(), [](const QmlEvent &a, const QmlEvent &b) {
|
||||||
|
return a.timestamp() < b.timestamp();
|
||||||
|
});
|
||||||
emit success();
|
emit success();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -370,46 +374,53 @@ void QmlProfilerFileReader::loadEvents(QXmlStreamReader &stream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
event.setTimestamp(attributes.value(_("startTime")).toLongLong());
|
event.setTimestamp(attributes.value(_("startTime")).toLongLong());
|
||||||
if (attributes.hasAttribute(_("duration")))
|
|
||||||
event.setDuration(attributes.value(_("duration")).toLongLong());
|
|
||||||
|
|
||||||
// attributes for special events
|
|
||||||
if (attributes.hasAttribute(_("framerate")))
|
|
||||||
event.setNumber<qint32>(0, attributes.value(_("framerate")).toInt());
|
|
||||||
if (attributes.hasAttribute(_("animationcount")))
|
|
||||||
event.setNumber<qint32>(1, attributes.value(_("animationcount")).toInt());
|
|
||||||
if (attributes.hasAttribute(_("thread")))
|
|
||||||
event.setNumber<qint32>(2, attributes.value(_("thread")).toInt());
|
|
||||||
if (attributes.hasAttribute(_("width")))
|
|
||||||
event.setNumber<qint32>(0, attributes.value(_("width")).toInt());
|
|
||||||
if (attributes.hasAttribute(_("height")))
|
|
||||||
event.setNumber<qint32>(1, attributes.value(_("height")).toInt());
|
|
||||||
if (attributes.hasAttribute(_("refCount")))
|
|
||||||
event.setNumber<qint32>(2, attributes.value(_("refCount")).toInt());
|
|
||||||
if (attributes.hasAttribute(_("amount")))
|
|
||||||
event.setNumber<qint64>(0, attributes.value(_("amount")).toLongLong());
|
|
||||||
if (attributes.hasAttribute(_("timing1")))
|
|
||||||
event.setNumber<qint64>(0, attributes.value(_("timing1")).toLongLong());
|
|
||||||
if (attributes.hasAttribute(_("timing2")))
|
|
||||||
event.setNumber<qint64>(1, attributes.value(_("timing2")).toLongLong());
|
|
||||||
if (attributes.hasAttribute(_("timing3")))
|
|
||||||
event.setNumber<qint64>(2, attributes.value(_("timing3")).toLongLong());
|
|
||||||
if (attributes.hasAttribute(_("timing4")))
|
|
||||||
event.setNumber<qint64>(3, attributes.value(_("timing4")).toLongLong());
|
|
||||||
if (attributes.hasAttribute(_("timing5")))
|
|
||||||
event.setNumber<qint64>(4, attributes.value(_("timing5")).toLongLong());
|
|
||||||
if (attributes.hasAttribute(_("type")))
|
|
||||||
event.setNumber<qint32>(0, attributes.value(_("type")).toInt());
|
|
||||||
if (attributes.hasAttribute(_("data1")))
|
|
||||||
event.setNumber<qint32>(1, attributes.value(_("data1")).toInt());
|
|
||||||
if (attributes.hasAttribute(_("data2")))
|
|
||||||
event.setNumber<qint32>(2, attributes.value(_("data2")).toInt());
|
|
||||||
if (attributes.hasAttribute(_("text")))
|
|
||||||
event.setString(attributes.value(_("text")).toString());
|
|
||||||
|
|
||||||
event.setTypeIndex(attributes.value(_("eventIndex")).toInt());
|
event.setTypeIndex(attributes.value(_("eventIndex")).toInt());
|
||||||
|
|
||||||
m_events.append(event);
|
if (attributes.hasAttribute(_("duration"))) {
|
||||||
|
event.setRangeStage(RangeStart);
|
||||||
|
m_events.append(event);
|
||||||
|
QmlEvent rangeEnd(event);
|
||||||
|
rangeEnd.setRangeStage(RangeEnd);
|
||||||
|
rangeEnd.setTimestamp(event.timestamp()
|
||||||
|
+ attributes.value(_("duration")).toLongLong());
|
||||||
|
m_events.append(rangeEnd);
|
||||||
|
} else {
|
||||||
|
// attributes for special events
|
||||||
|
if (attributes.hasAttribute(_("framerate")))
|
||||||
|
event.setNumber<qint32>(0, attributes.value(_("framerate")).toInt());
|
||||||
|
if (attributes.hasAttribute(_("animationcount")))
|
||||||
|
event.setNumber<qint32>(1, attributes.value(_("animationcount")).toInt());
|
||||||
|
if (attributes.hasAttribute(_("thread")))
|
||||||
|
event.setNumber<qint32>(2, attributes.value(_("thread")).toInt());
|
||||||
|
if (attributes.hasAttribute(_("width")))
|
||||||
|
event.setNumber<qint32>(0, attributes.value(_("width")).toInt());
|
||||||
|
if (attributes.hasAttribute(_("height")))
|
||||||
|
event.setNumber<qint32>(1, attributes.value(_("height")).toInt());
|
||||||
|
if (attributes.hasAttribute(_("refCount")))
|
||||||
|
event.setNumber<qint32>(2, attributes.value(_("refCount")).toInt());
|
||||||
|
if (attributes.hasAttribute(_("amount")))
|
||||||
|
event.setNumber<qint64>(0, attributes.value(_("amount")).toLongLong());
|
||||||
|
if (attributes.hasAttribute(_("timing1")))
|
||||||
|
event.setNumber<qint64>(0, attributes.value(_("timing1")).toLongLong());
|
||||||
|
if (attributes.hasAttribute(_("timing2")))
|
||||||
|
event.setNumber<qint64>(1, attributes.value(_("timing2")).toLongLong());
|
||||||
|
if (attributes.hasAttribute(_("timing3")))
|
||||||
|
event.setNumber<qint64>(2, attributes.value(_("timing3")).toLongLong());
|
||||||
|
if (attributes.hasAttribute(_("timing4")))
|
||||||
|
event.setNumber<qint64>(3, attributes.value(_("timing4")).toLongLong());
|
||||||
|
if (attributes.hasAttribute(_("timing5")))
|
||||||
|
event.setNumber<qint64>(4, attributes.value(_("timing5")).toLongLong());
|
||||||
|
if (attributes.hasAttribute(_("type")))
|
||||||
|
event.setNumber<qint32>(0, attributes.value(_("type")).toInt());
|
||||||
|
if (attributes.hasAttribute(_("data1")))
|
||||||
|
event.setNumber<qint32>(1, attributes.value(_("data1")).toInt());
|
||||||
|
if (attributes.hasAttribute(_("data2")))
|
||||||
|
event.setNumber<qint32>(2, attributes.value(_("data2")).toInt());
|
||||||
|
if (attributes.hasAttribute(_("text")))
|
||||||
|
event.setString(attributes.value(_("text")).toString());
|
||||||
|
|
||||||
|
m_events.append(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -584,19 +595,29 @@ void QmlProfilerFileWriter::save(QIODevice *device)
|
|||||||
|
|
||||||
stream.writeStartElement(_("profilerDataModel"));
|
stream.writeStartElement(_("profilerDataModel"));
|
||||||
|
|
||||||
|
QStack<QmlEvent> stack;
|
||||||
for (int rangeIndex = 0; rangeIndex < m_events.size(); ++rangeIndex) {
|
for (int rangeIndex = 0; rangeIndex < m_events.size(); ++rangeIndex) {
|
||||||
if (isCanceled())
|
if (isCanceled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QmlEvent &event = m_events[rangeIndex];
|
const QmlEvent &event = m_events[rangeIndex];
|
||||||
|
const QmlEventType &type = m_eventTypes[event.typeIndex()];
|
||||||
|
if (type.rangeType != MaximumRangeType && event.rangeStage() == RangeStart) {
|
||||||
|
stack.push(event);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
stream.writeStartElement(_("range"));
|
stream.writeStartElement(_("range"));
|
||||||
stream.writeAttribute(_("startTime"), QString::number(event.timestamp()));
|
if (type.rangeType != MaximumRangeType && event.rangeStage() == RangeEnd) {
|
||||||
if (event.duration() > 0) // no need to store duration of instantaneous events
|
QmlEvent start = stack.pop();
|
||||||
stream.writeAttribute(_("duration"), QString::number(event.duration()));
|
stream.writeAttribute(_("startTime"), QString::number(start.timestamp()));
|
||||||
stream.writeAttribute(_("eventIndex"), QString::number(event.typeIndex()));
|
stream.writeAttribute(_("duration"),
|
||||||
|
QString::number(event.timestamp() - start.timestamp()));
|
||||||
|
} else {
|
||||||
|
stream.writeAttribute(_("startTime"), QString::number(event.timestamp()));
|
||||||
|
}
|
||||||
|
|
||||||
const QmlEventType &type = m_eventTypes[event.typeIndex()];
|
stream.writeAttribute(_("eventIndex"), QString::number(event.typeIndex()));
|
||||||
|
|
||||||
if (type.message == Event) {
|
if (type.message == Event) {
|
||||||
if (type.detailType == AnimationFrame) {
|
if (type.detailType == AnimationFrame) {
|
||||||
|
@@ -133,17 +133,12 @@ qint64 QmlProfilerViewManager::selectionEnd() const
|
|||||||
|
|
||||||
bool QmlProfilerViewManager::isEventsRestrictedToRange() const
|
bool QmlProfilerViewManager::isEventsRestrictedToRange() const
|
||||||
{
|
{
|
||||||
foreach (QmlProfilerEventsView *view, d->eventsViews) {
|
return d->profilerModelManager->isRestrictedToRange();
|
||||||
if (view->isRestrictedToRange())
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerViewManager::restrictEventsToRange(qint64 rangeStart, qint64 rangeEnd)
|
void QmlProfilerViewManager::restrictEventsToRange(qint64 rangeStart, qint64 rangeEnd)
|
||||||
{
|
{
|
||||||
foreach (QmlProfilerEventsView *view, d->eventsViews)
|
d->profilerModelManager->restrictToRange(rangeStart, rangeEnd);
|
||||||
view->restrictToRange(rangeStart, rangeEnd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerViewManager::raiseTimeline()
|
void QmlProfilerViewManager::raiseTimeline()
|
||||||
|
Reference in New Issue
Block a user