Skip to content
Snippets Groups Projects
Commit 0924ee5e authored by Ulf Hermann's avatar Ulf Hermann
Browse files

QmlProfiler: Move type resolution logic into trace client


This way we will be able to use server-provided type IDs for more
efficient lookup of event types.

Change-Id: I37cd592a7829e5f36c6cfc04e400013d1dc37155
Reviewed-by: default avatarJoerg Bornemann <joerg.bornemann@qt.io>
parent ebd6d269
No related branches found
No related tags found
No related merge requests found
...@@ -43,13 +43,9 @@ class QmlProfilerDataModel::QmlProfilerDataModelPrivate ...@@ -43,13 +43,9 @@ class QmlProfilerDataModel::QmlProfilerDataModelPrivate
{ {
public: public:
void rewriteType(int typeIndex); void rewriteType(int typeIndex);
int resolveType(const QmlEventType &type);
int resolveStackTop(); int resolveStackTop();
QVector<QmlEventType> eventTypes; QVector<QmlEventType> eventTypes;
QHash<QmlEventType, int> eventTypeIds;
QStack<QmlTypedEvent> rangesInProgress;
QmlProfilerModelManager *modelManager; QmlProfilerModelManager *modelManager;
int modelId; int modelId;
...@@ -141,8 +137,15 @@ void QmlProfilerDataModel::setEventTypes(const QVector<QmlEventType> &types) ...@@ -141,8 +137,15 @@ void QmlProfilerDataModel::setEventTypes(const QVector<QmlEventType> &types)
{ {
Q_D(QmlProfilerDataModel); Q_D(QmlProfilerDataModel);
d->eventTypes = types; d->eventTypes = types;
for (int id = 0; id < types.count(); ++id) }
d->eventTypeIds[types[id]] = id;
int QmlProfilerDataModel::addEventType(const QmlEventType &type)
{
Q_D(QmlProfilerDataModel);
int typeIndex = d->eventTypes.length();
d->eventTypes.append(type);
d->rewriteType(typeIndex);
return typeIndex;
} }
void QmlProfilerDataModel::addEvent(const QmlEvent &event) void QmlProfilerDataModel::addEvent(const QmlEvent &event)
...@@ -159,8 +162,6 @@ void QmlProfilerDataModel::clear() ...@@ -159,8 +162,6 @@ void QmlProfilerDataModel::clear()
d->file.open(); d->file.open();
d->eventStream.setDevice(&d->file); d->eventStream.setDevice(&d->file);
d->eventTypes.clear(); d->eventTypes.clear();
d->eventTypeIds.clear();
d->rangesInProgress.clear();
d->detailsRewriter->clearRequests(); d->detailsRewriter->clearRequests();
} }
...@@ -170,26 +171,6 @@ bool QmlProfilerDataModel::isEmpty() const ...@@ -170,26 +171,6 @@ bool QmlProfilerDataModel::isEmpty() const
return d->file.pos() == 0; return d->file.pos() == 0;
} }
inline static uint qHash(const QmlEventType &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 QmlEventType &type1,
const QmlEventType &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::QmlProfilerDataModelPrivate::rewriteType(int typeIndex) void QmlProfilerDataModel::QmlProfilerDataModelPrivate::rewriteType(int typeIndex)
{ {
QmlEventType &type = eventTypes[typeIndex]; QmlEventType &type = eventTypes[typeIndex];
...@@ -207,80 +188,6 @@ void QmlProfilerDataModel::QmlProfilerDataModelPrivate::rewriteType(int typeInde ...@@ -207,80 +188,6 @@ void QmlProfilerDataModel::QmlProfilerDataModelPrivate::rewriteType(int typeInde
detailsRewriter->requestDetailsForLocation(typeIndex, type.location); detailsRewriter->requestDetailsForLocation(typeIndex, type.location);
} }
int QmlProfilerDataModel::QmlProfilerDataModelPrivate::resolveType(const QmlEventType &type)
{
QHash<QmlEventType, int>::ConstIterator it = eventTypeIds.constFind(type);
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);
eventStream << typedEvent.event;
modelManager->dispatch(typedEvent.event, eventTypes[typeIndex]);
return typeIndex;
}
void QmlProfilerDataModel::addTypedEvent(const QmlEvent &event, const QmlEventType &type)
{
Q_D(QmlProfilerDataModel);
// RangeData and RangeLocation always apply to the range on the top of the stack. Furthermore,
// all ranges are perfectly nested. This is why we can defer the type resolution until either
// the range ends or a child range starts. With only the information in RangeStart we wouldn't
// be able to uniquely identify the event type.
Message rangeStage = type.rangeType == MaximumRangeType ? type.message : event.rangeStage();
switch (rangeStage) {
case RangeStart:
d->resolveStackTop();
d->rangesInProgress.push(QmlTypedEvent({event, type}));
break;
case RangeEnd: {
int typeIndex = d->resolveStackTop();
QTC_ASSERT(typeIndex != -1, break);
QmlEvent appended = event;
appended.setTypeIndex(typeIndex);
d->eventStream << appended;
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: {
QmlEvent appended = event;
int typeIndex = d->resolveType(type);
appended.setTypeIndex(typeIndex);
d->eventStream << appended;
d->modelManager->dispatch(appended, d->eventTypes[typeIndex]);
break;
}
}
}
void QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd, void QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd,
QmlProfilerModelManager::EventLoader loader) const QmlProfilerModelManager::EventLoader loader) const
{ {
......
...@@ -47,11 +47,11 @@ public: ...@@ -47,11 +47,11 @@ public:
const QVector<QmlEventType> &eventTypes() const; const QVector<QmlEventType> &eventTypes() const;
void setEventTypes(const QVector<QmlEventType> &types); void setEventTypes(const QVector<QmlEventType> &types);
int addEventType(const QmlEventType &type);
void clear(); void clear();
bool isEmpty() const; bool isEmpty() const;
void addEvent(const QmlEvent &event); void addEvent(const QmlEvent &event);
void addTypedEvent(const QmlEvent &event, const QmlEventType &type);
void replayEvents(qint64 startTime, qint64 endTime, void replayEvents(qint64 startTime, qint64 endTime,
QmlProfilerModelManager::EventLoader loader) const; QmlProfilerModelManager::EventLoader loader) const;
void finalize(); void finalize();
......
...@@ -30,9 +30,30 @@ ...@@ -30,9 +30,30 @@
#include <qmldebug/qmlenginecontrolclient.h> #include <qmldebug/qmlenginecontrolclient.h>
#include <qmldebug/qdebugmessageclient.h> #include <qmldebug/qdebugmessageclient.h>
#include <qmldebug/qpacketprotocol.h> #include <qmldebug/qpacketprotocol.h>
#include <utils/qtcassert.h>
namespace QmlProfiler { namespace QmlProfiler {
inline static uint qHash(const QmlEventType &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 QmlEventType &type1,
const QmlEventType &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;
}
class QmlProfilerTraceClientPrivate { class QmlProfilerTraceClientPrivate {
public: public:
QmlProfilerTraceClientPrivate(QmlProfilerTraceClient *_q, QmlDebug::QmlDebugConnection *client, QmlProfilerTraceClientPrivate(QmlProfilerTraceClient *_q, QmlDebug::QmlDebugConnection *client,
...@@ -50,6 +71,9 @@ public: ...@@ -50,6 +71,9 @@ public:
void sendRecordingStatus(int engineId); void sendRecordingStatus(int engineId);
bool updateFeatures(ProfileFeature feature); bool updateFeatures(ProfileFeature feature);
int resolveType(const QmlEventType &type);
int resolveStackTop();
void processCurrentEvent();
QmlProfilerTraceClient *q; QmlProfilerTraceClient *q;
QmlProfilerDataModel *model; QmlProfilerDataModel *model;
...@@ -63,8 +87,76 @@ public: ...@@ -63,8 +87,76 @@ public:
// Reuse the same event, so that we don't have to constantly reallocate all the data. // Reuse the same event, so that we don't have to constantly reallocate all the data.
QmlTypedEvent currentEvent; QmlTypedEvent currentEvent;
QHash<QmlEventType, int> eventTypeIds;
QStack<QmlTypedEvent> rangesInProgress;
}; };
int QmlProfilerTraceClientPrivate::resolveType(const QmlEventType &type)
{
QHash<QmlEventType, int>::ConstIterator it = eventTypeIds.constFind(type);
int typeIndex = -1;
if (it != eventTypeIds.constEnd()) {
typeIndex = it.value();
} else {
typeIndex = model->addEventType(type);
eventTypeIds[type] = typeIndex;
}
return typeIndex;
}
int QmlProfilerTraceClientPrivate::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);
model->addEvent(typedEvent.event);
return typeIndex;
}
void QmlProfilerTraceClientPrivate::processCurrentEvent()
{
// RangeData and RangeLocation always apply to the range on the top of the stack. Furthermore,
// all ranges are perfectly nested. This is why we can defer the type resolution until either
// the range ends or a child range starts. With only the information in RangeStart we wouldn't
// be able to uniquely identify the event type.
Message rangeStage = currentEvent.type.rangeType == MaximumRangeType ?
currentEvent.type.message : currentEvent.event.rangeStage();
switch (rangeStage) {
case RangeStart:
resolveStackTop();
rangesInProgress.push(currentEvent);
break;
case RangeEnd: {
int typeIndex = resolveStackTop();
QTC_ASSERT(typeIndex != -1, break);
currentEvent.event.setTypeIndex(typeIndex);
model->addEvent(currentEvent.event);
rangesInProgress.pop();
break;
}
case RangeData:
rangesInProgress.top().type.data = currentEvent.type.data;
break;
case RangeLocation:
rangesInProgress.top().type.location = currentEvent.type.location;
break;
default: {
int typeIndex = resolveType(currentEvent.type);
currentEvent.event.setTypeIndex(typeIndex);
model->addEvent(currentEvent.event);
break;
}
}
}
void QmlProfilerTraceClientPrivate::sendRecordingStatus(int engineId) void QmlProfilerTraceClientPrivate::sendRecordingStatus(int engineId)
{ {
QmlDebug::QPacket stream(q->connection()->currentDataStreamVersion()); QmlDebug::QPacket stream(q->connection()->currentDataStreamVersion());
...@@ -96,6 +188,8 @@ QmlProfilerTraceClient::~QmlProfilerTraceClient() ...@@ -96,6 +188,8 @@ QmlProfilerTraceClient::~QmlProfilerTraceClient()
void QmlProfilerTraceClient::clearData() void QmlProfilerTraceClient::clearData()
{ {
d->eventTypeIds.clear();
d->rangesInProgress.clear();
if (d->recordedFeatures != 0) { if (d->recordedFeatures != 0) {
d->recordedFeatures = 0; d->recordedFeatures = 0;
emit recordedFeaturesChanged(0); emit recordedFeaturesChanged(0);
...@@ -152,7 +246,7 @@ void QmlProfilerTraceClient::setRequestedFeatures(quint64 features) ...@@ -152,7 +246,7 @@ void QmlProfilerTraceClient::setRequestedFeatures(quint64 features)
d->currentEvent.type.message = DebugMessage; d->currentEvent.type.message = DebugMessage;
d->currentEvent.type.rangeType = MaximumRangeType; d->currentEvent.type.rangeType = MaximumRangeType;
d->currentEvent.type.detailType = type; d->currentEvent.type.detailType = type;
d->model->addTypedEvent(d->currentEvent.event, d->currentEvent.type); d->processCurrentEvent();
}); });
} else { } else {
d->messageClient.reset(); d->messageClient.reset();
...@@ -211,7 +305,7 @@ void QmlProfilerTraceClient::messageReceived(const QByteArray &data) ...@@ -211,7 +305,7 @@ void QmlProfilerTraceClient::messageReceived(const QByteArray &data)
emit traceFinished(d->currentEvent.event.timestamp(), emit traceFinished(d->currentEvent.event.timestamp(),
d->currentEvent.event.numbers<QList<int>, qint32>()); d->currentEvent.event.numbers<QList<int>, qint32>());
} else if (d->updateFeatures(d->currentEvent.type.feature())) { } else if (d->updateFeatures(d->currentEvent.type.feature())) {
d->model->addTypedEvent(d->currentEvent.event, d->currentEvent.type); d->processCurrentEvent();
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment