Tracing: Move event storage out of trace manager

This is a step toward making the trace manager non-virtual. It should
just juggle the storages for types and events, and manage the threads to
access them. It doesn't need to know what exactly it stores.

Change-Id: I45093c60d8ae921e68aeb09bd48d24d5877ce306
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Ulf Hermann
2018-05-07 13:26:05 +02:00
parent e6d583913e
commit 916883e70f
17 changed files with 218 additions and 136 deletions

View File

@@ -41,10 +41,16 @@ TraceEventTypeStorage::~TraceEventTypeStorage()
{ {
} }
TraceEventStorage::~TraceEventStorage()
{
}
class TimelineTraceManager::TimelineTraceManagerPrivate class TimelineTraceManager::TimelineTraceManagerPrivate
{ {
public: public:
std::unique_ptr<TraceEventTypeStorage> typeStorage; std::unique_ptr<TraceEventTypeStorage> typeStorage;
std::unique_ptr<TraceEventStorage> eventStorage;
TimelineNotesModel *notesModel = nullptr; TimelineNotesModel *notesModel = nullptr;
int numEvents = 0; int numEvents = 0;
@@ -66,10 +72,12 @@ public:
void updateTraceTime(qint64 time); void updateTraceTime(qint64 time);
}; };
TimelineTraceManager::TimelineTraceManager(std::unique_ptr<TraceEventTypeStorage> &&typeStorage, TimelineTraceManager::TimelineTraceManager(std::unique_ptr<TraceEventStorage> &&eventStorage,
std::unique_ptr<TraceEventTypeStorage> &&typeStorage,
QObject *parent) : QObject *parent) :
QObject(parent), d(new TimelineTraceManagerPrivate) QObject(parent), d(new TimelineTraceManagerPrivate)
{ {
d->eventStorage = std::move(eventStorage);
d->typeStorage = std::move(typeStorage); d->typeStorage = std::move(typeStorage);
} }
@@ -85,7 +93,7 @@ TimelineNotesModel *TimelineTraceManager::notesModel() const
bool TimelineTraceManager::isEmpty() const bool TimelineTraceManager::isEmpty() const
{ {
return d->numEvents == 0; return d->eventStorage->size() == 0;
} }
int TimelineTraceManager::numEvents() const int TimelineTraceManager::numEvents() const
@@ -98,14 +106,20 @@ int TimelineTraceManager::numEventTypes() const
return d->typeStorage->size(); return d->typeStorage->size();
} }
const TraceEventStorage *TimelineTraceManager::eventStorage() const
{
return d->eventStorage.get();
}
const TraceEventTypeStorage *TimelineTraceManager::typeStorage() const const TraceEventTypeStorage *TimelineTraceManager::typeStorage() const
{ {
return d->typeStorage.get(); return d->typeStorage.get();
} }
void TimelineTraceManager::addEvent(const TraceEvent &event) void TimelineTraceManager::appendEvent(TraceEvent &&event)
{ {
d->dispatch(event, d->typeStorage->get(event.typeIndex())); d->dispatch(event, d->typeStorage->get(event.typeIndex()));
d->eventStorage->append(std::move(event));
} }
const TraceEventType &TimelineTraceManager::eventType(int typeId) const const TraceEventType &TimelineTraceManager::eventType(int typeId) const
@@ -205,6 +219,8 @@ void TimelineTraceManager::initialize()
void TimelineTraceManager::finalize() void TimelineTraceManager::finalize()
{ {
d->eventStorage->finalize();
// 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).
@@ -237,7 +253,8 @@ QFuture<void> TimelineTraceManager::save(const QString &filename)
file->close(); file->close();
file->remove(); file->remove();
delete file; delete file;
emit error(message); if (!message.isEmpty())
emit error(message);
}, Qt::QueuedConnection); }, Qt::QueuedConnection);
connect(writer, &TimelineTraceFile::success, this, [file]() { connect(writer, &TimelineTraceFile::success, this, [file]() {
@@ -292,7 +309,8 @@ QFuture<void> TimelineTraceManager::load(const QString &filename)
connect(reader, &TimelineTraceFile::error, this, [this, reader](const QString &message) { connect(reader, &TimelineTraceFile::error, this, [this, reader](const QString &message) {
clearAll(); clearAll();
delete reader; delete reader;
emit error(message); if (!message.isEmpty())
emit error(message);
}, Qt::QueuedConnection); }, Qt::QueuedConnection);
connect(reader, &TimelineTraceFile::canceled, this, [this, reader]() { connect(reader, &TimelineTraceFile::canceled, this, [this, reader]() {
@@ -369,6 +387,7 @@ void TimelineTraceManager::clearEventStorage()
d->notesModel->clear(); d->notesModel->clear();
setVisibleFeatures(0); setVisibleFeatures(0);
setRecordedFeatures(0); setRecordedFeatures(0);
d->eventStorage->clear();
} }
void TimelineTraceManager::clearTypeStorage() void TimelineTraceManager::clearTypeStorage()
@@ -406,8 +425,10 @@ void TimelineTraceManager::restrictByFilter(TraceEventFilter filter)
d->notesModel->restore(); d->notesModel->restore();
finalize(); finalize();
}, [this](const QString &message) { }, [this](const QString &message) {
emit error(tr("Could not re-read events from temporary trace file: %1\n" if (!message.isEmpty()) {
"The trace data is lost.").arg(message)); emit error(tr("Could not re-read events from temporary trace file: %1\n"
"The trace data is lost.").arg(message));
}
clearAll(); clearAll();
}, future); }, future);
} }

View File

@@ -49,6 +49,17 @@ public:
virtual void clear() = 0; virtual void clear() = 0;
}; };
class TRACING_EXPORT TraceEventStorage
{
public:
virtual ~TraceEventStorage();
virtual int append(TraceEvent &&event) = 0;
virtual int size() const = 0;
virtual void clear() = 0;
virtual void finalize() = 0;
virtual bool replay(const std::function<bool(TraceEvent &&)> &receiver) const = 0;
};
class TimelineTraceFile; class TimelineTraceFile;
class TRACING_EXPORT TimelineTraceManager : public QObject class TRACING_EXPORT TimelineTraceManager : public QObject
{ {
@@ -61,7 +72,8 @@ public:
typedef std::function<void()> Clearer; typedef std::function<void()> Clearer;
typedef std::function<void(const QString &)> ErrorHandler; typedef std::function<void(const QString &)> ErrorHandler;
explicit TimelineTraceManager(std::unique_ptr<TraceEventTypeStorage> &&typeStorage, explicit TimelineTraceManager(std::unique_ptr<TraceEventStorage> &&eventStorage,
std::unique_ptr<TraceEventTypeStorage> &&typeStorage,
QObject *parent = nullptr); QObject *parent = nullptr);
~TimelineTraceManager() override; ~TimelineTraceManager() override;
@@ -78,6 +90,7 @@ public:
int numEvents() const; int numEvents() const;
int numEventTypes() const; int numEventTypes() const;
const TraceEventStorage *eventStorage() const;
const TraceEventTypeStorage *typeStorage() const; const TraceEventTypeStorage *typeStorage() const;
void registerFeatures(quint64 features, TraceEventLoader eventLoader, void registerFeatures(quint64 features, TraceEventLoader eventLoader,
@@ -117,8 +130,7 @@ protected:
void restrictByFilter(TraceEventFilter filter); void restrictByFilter(TraceEventFilter filter);
void addEvent(const TraceEvent &event); void appendEvent(TraceEvent &&event);
const TraceEventType &eventType(int typeId) const; const TraceEventType &eventType(int typeId) const;
void setEventType(int typeId, TraceEventType &&type); void setEventType(int typeId, TraceEventType &&type);
int appendEventType(TraceEventType &&type); int appendEventType(TraceEventType &&type);

View File

@@ -67,12 +67,12 @@ public:
return ReplayOpenFailed; return ReplayOpenFailed;
QDataStream readStream(&readFile); QDataStream readStream(&readFile);
Event event;
while (!readStream.atEnd()) { while (!readStream.atEnd()) {
Event event;
readStream >> event; readStream >> event;
if (readStream.status() == QDataStream::ReadPastEnd) if (readStream.status() == QDataStream::ReadPastEnd)
return ReplayReadPastEnd; return ReplayReadPastEnd;
if (!loader(event)) if (!loader(std::move(event)))
return ReplayLoadFailed; return ReplayLoadFailed;
} }

View File

@@ -170,8 +170,10 @@ void FlameGraphModel::restrictToFeatures(quint64 visibleFeatures)
std::bind(&FlameGraphModel::beginResetModel, this), std::bind(&FlameGraphModel::beginResetModel, this),
std::bind(&FlameGraphModel::finalize, this), std::bind(&FlameGraphModel::finalize, this),
[this](const QString &message) { [this](const QString &message) {
emit m_modelManager->error(tr("Could not re-read events from temporary trace file: %1") if (!message.isEmpty()) {
.arg(message)); emit m_modelManager->error(tr("Could not re-read events from temporary trace file: %1")
.arg(message));
}
endResetModel(); endResetModel();
clear(); clear();
}, future); }, future);

View File

@@ -74,19 +74,37 @@ private:
std::vector<QmlEventType> m_types; std::vector<QmlEventType> m_types;
}; };
class QmlProfilerEventStorage : public Timeline::TraceEventStorage
{
Q_DECLARE_TR_FUNCTIONS(QmlProfilerEventStorage)
public:
using ErrorHandler = std::function<void(const QString &)>;
QmlProfilerEventStorage(const ErrorHandler &errorHandler);
int append(Timeline::TraceEvent &&event) override;
int size() const override;
void clear() override;
bool replay(const std::function<bool(Timeline::TraceEvent &&)> &receiver) const override;
void finalize() override;
ErrorHandler errorHandler() const;
void setErrorHandler(const ErrorHandler &errorHandler);
private:
Timeline::TraceStashFile<QmlEvent> m_file;
std::function<void(const QString &)> m_errorHandler;
int m_size = 0;
};
class QmlProfilerModelManager::QmlProfilerModelManagerPrivate class QmlProfilerModelManager::QmlProfilerModelManagerPrivate
{ {
public: public:
QmlProfilerModelManagerPrivate() : file("qmlprofiler-data") {}
Internal::QmlProfilerTextMarkModel *textMarkModel = nullptr; Internal::QmlProfilerTextMarkModel *textMarkModel = nullptr;
Internal::QmlProfilerDetailsRewriter *detailsRewriter = nullptr; Internal::QmlProfilerDetailsRewriter *detailsRewriter = nullptr;
Timeline::TraceStashFile<QmlEvent> file;
bool isRestrictedToRange = false; bool isRestrictedToRange = false;
void writeToStream(const QmlEvent &event);
void addEventType(const QmlEventType &eventType); void addEventType(const QmlEventType &eventType);
void handleError(const QString &message); void handleError(const QString &message);
@@ -94,7 +112,10 @@ public:
}; };
QmlProfilerModelManager::QmlProfilerModelManager(QObject *parent) : QmlProfilerModelManager::QmlProfilerModelManager(QObject *parent) :
Timeline::TimelineTraceManager(std::make_unique<QmlProfilerEventTypeStorage>(), parent), Timeline::TimelineTraceManager(
std::make_unique<QmlProfilerEventStorage>(
std::bind(&Timeline::TimelineTraceManager::error, this, std::placeholders::_1)),
std::make_unique<QmlProfilerEventTypeStorage>(), parent),
d(new QmlProfilerModelManagerPrivate) d(new QmlProfilerModelManagerPrivate)
{ {
setNotesModel(new QmlProfilerNotesModel(this)); setNotesModel(new QmlProfilerNotesModel(this));
@@ -106,9 +127,6 @@ QmlProfilerModelManager::QmlProfilerModelManager(QObject *parent) :
connect(d->detailsRewriter, &Internal::QmlProfilerDetailsRewriter::eventDetailsChanged, connect(d->detailsRewriter, &Internal::QmlProfilerDetailsRewriter::eventDetailsChanged,
this, &QmlProfilerModelManager::typeDetailsFinished); this, &QmlProfilerModelManager::typeDetailsFinished);
if (!d->file.open())
emit error(tr("Cannot open temporary trace file to store events."));
quint64 allFeatures = 0; quint64 allFeatures = 0;
for (quint8 i = 0; i <= MaximumProfileFeature; ++i) for (quint8 i = 0; i <= MaximumProfileFeature; ++i)
allFeatures |= (1ull << i); allFeatures |= (1ull << i);
@@ -138,12 +156,6 @@ void QmlProfilerModelManager::registerFeatures(quint64 features, QmlEventLoader
finalizer, clearer); finalizer, clearer);
} }
void QmlProfilerModelManager::addEvents(const QVector<QmlEvent> &events)
{
for (const QmlEvent &event : events)
addEvent(event);
}
const QmlEventType &QmlProfilerModelManager::eventType(int typeId) const const QmlEventType &QmlProfilerModelManager::eventType(int typeId) const
{ {
return static_cast<const QmlEventType &>(TimelineTraceManager::eventType(typeId)); return static_cast<const QmlEventType &>(TimelineTraceManager::eventType(typeId));
@@ -174,31 +186,19 @@ void QmlProfilerModelManager::replayQmlEvents(QmlEventLoader loader,
if (initializer) if (initializer)
initializer(); initializer();
const auto result = d->file.replay([&](const QmlEvent &event) { const auto result = eventStorage()->replay([&](Timeline::TraceEvent &&event) {
if (future.isCanceled()) if (future.isCanceled())
return false; return false;
loader(event, eventType(event.typeIndex())); loader(static_cast<QmlEvent &&>(event), eventType(event.typeIndex()));
return true; return true;
}); });
switch (result) { if (!result && errorHandler) {
case Timeline::TraceStashFile<QmlEvent>::ReplaySuccess: errorHandler(future.isCanceled() ? QString()
if (finalizer) : tr("Failed to replay QML events from stash file."));
finalizer(); } else if (result && finalizer) {
break; finalizer();
case Timeline::TraceStashFile<QmlEvent>::ReplayOpenFailed:
if (errorHandler)
errorHandler(tr("Could not re-open temporary trace file"));
break;
case Timeline::TraceStashFile<QmlEvent>::ReplayLoadFailed:
if (errorHandler)
errorHandler(tr("Could not load events from temporary trace file"));
break;
case Timeline::TraceStashFile<QmlEvent>::ReplayReadPastEnd:
if (errorHandler)
errorHandler(tr("Read past end in temporary trace file"));
break;
} }
} }
@@ -236,11 +236,6 @@ static QString getInitialDetails(const QmlEventType &event)
return details; return details;
} }
void QmlProfilerModelManager::QmlProfilerModelManagerPrivate::writeToStream(const QmlEvent &event)
{
file.append(event);
}
void QmlProfilerModelManager::QmlProfilerModelManagerPrivate::handleError(const QString &message) void QmlProfilerModelManager::QmlProfilerModelManagerPrivate::handleError(const QString &message)
{ {
// What to do here? // What to do here?
@@ -254,8 +249,6 @@ const char *QmlProfilerModelManager::featureName(ProfileFeature feature)
void QmlProfilerModelManager::finalize() void QmlProfilerModelManager::finalize()
{ {
if (!d->file.flush())
emit error(tr("Failed to flush temporary trace file"));
d->detailsRewriter->reloadDocuments(); d->detailsRewriter->reloadDocuments();
// Load notes after the timeline models have been initialized ... // Load notes after the timeline models have been initialized ...
@@ -299,14 +292,6 @@ void QmlProfilerModelManager::restrictByFilter(QmlProfilerModelManager::QmlEvent
}); });
} }
void QmlProfilerModelManager::clearEventStorage()
{
TimelineTraceManager::clearEventStorage();
d->file.clear();
if (!d->file.open())
emit error(tr("Failed to reset temporary trace file"));
}
int QmlProfilerModelManager::appendEventType(QmlEventType &&type) int QmlProfilerModelManager::appendEventType(QmlEventType &&type)
{ {
type.setDisplayName(getDisplayName(type)); type.setDisplayName(getDisplayName(type));
@@ -351,10 +336,9 @@ void QmlProfilerModelManager::setEventType(int typeIndex, QmlEventType &&type)
} }
void QmlProfilerModelManager::addEvent(const QmlEvent &event) void QmlProfilerModelManager::appendEvent(QmlEvent &&event)
{ {
d->writeToStream(event); TimelineTraceManager::appendEvent(std::move(event));
TimelineTraceManager::addEvent(event);
} }
void QmlProfilerModelManager::restrictToRange(qint64 start, qint64 end) void QmlProfilerModelManager::restrictToRange(qint64 start, qint64 end)
@@ -480,4 +464,67 @@ void QmlProfilerEventTypeStorage::clear()
m_types.clear(); m_types.clear();
} }
QmlProfilerEventStorage::QmlProfilerEventStorage(
const std::function<void (const QString &)> &errorHandler)
: m_file("qmlprofiler-data"), m_errorHandler(errorHandler)
{
if (!m_file.open())
errorHandler(tr("Cannot open temporary trace file to store events."));
}
int QmlProfilerEventStorage::append(Timeline::TraceEvent &&event)
{
m_file.append(std::move(static_cast<QmlEvent &&>(event)));
return m_size++;
}
int QmlProfilerEventStorage::size() const
{
return m_size;
}
void QmlProfilerEventStorage::clear()
{
m_size = 0;
m_file.clear();
if (!m_file.open())
m_errorHandler(tr("Failed to reset temporary trace file"));
}
void QmlProfilerEventStorage::finalize()
{
if (!m_file.flush())
m_errorHandler(tr("Failed to flush temporary trace file"));
}
QmlProfilerEventStorage::ErrorHandler QmlProfilerEventStorage::errorHandler() const
{
return m_errorHandler;
}
void QmlProfilerEventStorage::setErrorHandler(
const QmlProfilerEventStorage::ErrorHandler &errorHandler)
{
m_errorHandler = errorHandler;
}
bool QmlProfilerEventStorage::replay(
const std::function<bool (Timeline::TraceEvent &&)> &receiver) const
{
switch (m_file.replay(receiver)) {
case Timeline::TraceStashFile<QmlEvent>::ReplaySuccess:
return true;
case Timeline::TraceStashFile<QmlEvent>::ReplayOpenFailed:
m_errorHandler(tr("Could not re-open temporary trace file"));
break;
case Timeline::TraceStashFile<QmlEvent>::ReplayLoadFailed:
// Happens if the loader rejects an event. Not an actual error
break;
case Timeline::TraceStashFile<QmlEvent>::ReplayReadPastEnd:
m_errorHandler(tr("Read past end in temporary trace file"));
break;
}
return false;
}
} // namespace QmlProfiler } // namespace QmlProfiler

View File

@@ -61,7 +61,6 @@ public:
Initializer initializer = nullptr, Finalizer finalizer = nullptr, Initializer initializer = nullptr, Finalizer finalizer = nullptr,
Clearer clearer = nullptr); Clearer clearer = nullptr);
void addEvents(const QVector<QmlEvent> &events);
const QmlEventType &eventType(int typeId) const; const QmlEventType &eventType(int typeId) const;
void replayQmlEvents(QmlEventLoader loader, Initializer initializer, Finalizer finalizer, void replayQmlEvents(QmlEventLoader loader, Initializer initializer, Finalizer finalizer,
@@ -76,7 +75,7 @@ public:
int appendEventType(QmlEventType &&type); int appendEventType(QmlEventType &&type);
void setEventType(int typeId, QmlEventType &&type); void setEventType(int typeId, QmlEventType &&type);
void addEvent(const QmlEvent &event); void appendEvent(QmlEvent &&event);
void restrictToRange(qint64 start, qint64 end); void restrictToRange(qint64 start, qint64 end);
bool isRestrictedToRange() const; bool isRestrictedToRange() const;
@@ -91,8 +90,6 @@ private:
void detailsChanged(int typeId, const QString &newString); void detailsChanged(int typeId, const QString &newString);
void restrictByFilter(QmlEventFilter filter); void restrictByFilter(QmlEventFilter filter);
void clearEventStorage() override;
Timeline::TimelineTraceFile *createTraceFile() override; Timeline::TimelineTraceFile *createTraceFile() override;
void replayEvents(TraceEventLoader loader, Initializer initializer, Finalizer finalizer, void replayEvents(TraceEventLoader loader, Initializer initializer, Finalizer finalizer,
ErrorHandler errorHandler, QFutureInterface<void> &future) const override; ErrorHandler errorHandler, QFutureInterface<void> &future) const override;

View File

@@ -112,8 +112,10 @@ void QmlProfilerStatisticsModel::restrictToFeatures(quint64 features)
notesChanged(QmlProfilerStatisticsModel::s_invalidTypeId); // Reload notes notesChanged(QmlProfilerStatisticsModel::s_invalidTypeId); // Reload notes
}, [this](const QString &message) { }, [this](const QString &message) {
endResetModel(); endResetModel();
emit m_modelManager->error(tr("Could not re-read events from temporary trace file: %1") if (!message.isEmpty()) {
.arg(message)); emit m_modelManager->error(tr("Could not re-read events from temporary trace file: %1")
.arg(message));
}
clear(); clear();
}, future); }, future);
} }

View File

@@ -75,7 +75,7 @@ public:
bool updateFeatures(quint8 feature); bool updateFeatures(quint8 feature);
int resolveType(const QmlTypedEvent &type); int resolveType(const QmlTypedEvent &type);
int resolveStackTop(); int resolveStackTop();
void forwardEvents(const QmlEvent &last); void forwardEvents(QmlEvent &&last);
void processCurrentEvent(); void processCurrentEvent();
void finalize(); void finalize();
@@ -143,17 +143,17 @@ int QmlProfilerTraceClientPrivate::resolveStackTop()
&& pendingMessages.head().timestamp() < typedEvent.event.timestamp()) { && pendingMessages.head().timestamp() < typedEvent.event.timestamp()) {
forwardEvents(pendingMessages.dequeue()); forwardEvents(pendingMessages.dequeue());
} }
forwardEvents(typedEvent.event); forwardEvents(QmlEvent(typedEvent.event));
return typeIndex; return typeIndex;
} }
void QmlProfilerTraceClientPrivate::forwardEvents(const QmlEvent &last) void QmlProfilerTraceClientPrivate::forwardEvents(QmlEvent &&last)
{ {
while (!pendingDebugMessages.isEmpty() while (!pendingDebugMessages.isEmpty()
&& pendingDebugMessages.front().timestamp() <= last.timestamp()) { && pendingDebugMessages.front().timestamp() <= last.timestamp()) {
modelManager->addEvent(pendingDebugMessages.dequeue()); modelManager->appendEvent(pendingDebugMessages.dequeue());
} }
modelManager->addEvent(last); modelManager->appendEvent(std::move(last));
} }
void QmlProfilerTraceClientPrivate::processCurrentEvent() void QmlProfilerTraceClientPrivate::processCurrentEvent()
@@ -176,7 +176,7 @@ void QmlProfilerTraceClientPrivate::processCurrentEvent()
currentEvent.event.setTypeIndex(typeIndex); currentEvent.event.setTypeIndex(typeIndex);
while (!pendingMessages.isEmpty()) while (!pendingMessages.isEmpty())
forwardEvents(pendingMessages.dequeue()); forwardEvents(pendingMessages.dequeue());
forwardEvents(currentEvent.event); forwardEvents(QmlEvent(currentEvent.event));
rangesInProgress.pop(); rangesInProgress.pop();
break; break;
} }
@@ -196,7 +196,7 @@ void QmlProfilerTraceClientPrivate::processCurrentEvent()
int typeIndex = resolveType(currentEvent); int typeIndex = resolveType(currentEvent);
currentEvent.event.setTypeIndex(typeIndex); currentEvent.event.setTypeIndex(typeIndex);
if (rangesInProgress.isEmpty()) if (rangesInProgress.isEmpty())
forwardEvents(currentEvent.event); forwardEvents(QmlEvent(currentEvent.event));
else else
pendingMessages.enqueue(currentEvent.event); pendingMessages.enqueue(currentEvent.event);
break; break;
@@ -214,7 +214,7 @@ void QmlProfilerTraceClientPrivate::finalize()
} }
QTC_CHECK(pendingMessages.isEmpty()); QTC_CHECK(pendingMessages.isEmpty());
while (!pendingDebugMessages.isEmpty()) while (!pendingDebugMessages.isEmpty())
modelManager->addEvent(pendingDebugMessages.dequeue()); modelManager->appendEvent(pendingDebugMessages.dequeue());
} }
void QmlProfilerTraceClientPrivate::sendRecordingStatus(int engineId) void QmlProfilerTraceClientPrivate::sendRecordingStatus(int engineId)

View File

@@ -261,7 +261,6 @@ void QmlProfilerTraceFile::loadQzt(QIODevice *device)
setDeviceProgress(device); setDeviceProgress(device);
} }
QVector<QmlEvent> eventBuffer;
while (!stream.atEnd() && !isCanceled()) { while (!stream.atEnd() && !isCanceled()) {
stream >> data; stream >> data;
buffer.setData(qUncompress(data)); buffer.setData(qUncompress(data));
@@ -285,10 +284,8 @@ void QmlProfilerTraceFile::loadQzt(QIODevice *device)
} else { } else {
Q_UNREACHABLE(); Q_UNREACHABLE();
} }
eventBuffer.append(event); manager->appendEvent(std::move(event));
} }
manager->addEvents(eventBuffer);
eventBuffer.clear();
buffer.close(); buffer.close();
setDeviceProgress(device); setDeviceProgress(device);
} }
@@ -296,7 +293,6 @@ void QmlProfilerTraceFile::loadQzt(QIODevice *device)
if (isCanceled()) { if (isCanceled()) {
emit canceled(); emit canceled();
} else { } else {
manager->addEvents(eventBuffer);
emit success(); emit success();
} }
} }
@@ -447,7 +443,7 @@ public:
void addEvent(const QmlEvent &event); void addEvent(const QmlEvent &event);
void addRange(const QmlEvent &start, const QmlEvent &end); void addRange(const QmlEvent &start, const QmlEvent &end);
QVector<QmlEvent> finalize(); void finalize(QmlProfilerModelManager *modelManager);
private: private:
struct QmlRange { struct QmlRange {
@@ -468,7 +464,7 @@ void EventList::addRange(const QmlEvent &start, const QmlEvent &end)
ranges.append({start, end}); ranges.append({start, end});
} }
QVector<QmlEvent> EventList::finalize() void EventList::finalize(QmlProfilerModelManager *modelManager)
{ {
std::sort(ranges.begin(), ranges.end(), [](const QmlRange &a, const QmlRange &b) { std::sort(ranges.begin(), ranges.end(), [](const QmlRange &a, const QmlRange &b) {
if (a.begin.timestamp() < b.begin.timestamp()) if (a.begin.timestamp() < b.begin.timestamp())
@@ -482,15 +478,13 @@ QVector<QmlEvent> EventList::finalize()
}); });
QList<QmlEvent> ends; QList<QmlEvent> ends;
QVector<QmlEvent> result;
while (!ranges.isEmpty()) { while (!ranges.isEmpty()) {
// This is more expensive than just iterating, but we don't want to double the already // This is more expensive than just iterating, but we don't want to double the already
// high memory footprint. // high memory footprint.
QmlRange range = ranges.takeFirst(); QmlRange range = ranges.takeFirst();
while (!ends.isEmpty() && ends.last().timestamp() <= range.begin.timestamp()) while (!ends.isEmpty() && ends.last().timestamp() <= range.begin.timestamp())
result.append(ends.takeLast()); modelManager->appendEvent(ends.takeLast());
result.append(range.begin);
if (range.end.isValid()) { if (range.end.isValid()) {
auto it = ends.end(); auto it = ends.end();
for (auto begin = ends.begin(); it != begin;) { for (auto begin = ends.begin(); it != begin;) {
@@ -501,11 +495,10 @@ QVector<QmlEvent> EventList::finalize()
} }
ends.insert(it, range.end); ends.insert(it, range.end);
} }
modelManager->appendEvent(std::move(range.begin));
} }
while (!ends.isEmpty()) while (!ends.isEmpty())
result.append(ends.takeLast()); modelManager->appendEvent(ends.takeLast());
return result;
} }
void QmlProfilerTraceFile::loadEvents(QXmlStreamReader &stream) void QmlProfilerTraceFile::loadEvents(QXmlStreamReader &stream)
@@ -585,7 +578,7 @@ void QmlProfilerTraceFile::loadEvents(QXmlStreamReader &stream)
case QXmlStreamReader::EndElement: { case QXmlStreamReader::EndElement: {
if (elementName == _("profilerDataModel")) { if (elementName == _("profilerDataModel")) {
// done reading profilerDataModel // done reading profilerDataModel
modelManager()->addEvents(events.finalize()); events.finalize(modelManager());
return; return;
} }
break; break;

View File

@@ -40,17 +40,16 @@ DebugMessagesModelTest::DebugMessagesModelTest(QObject *parent) :
void DebugMessagesModelTest::initTestCase() void DebugMessagesModelTest::initTestCase()
{ {
manager.initialize(); manager.initialize();
QmlEvent event;
event.setTypeIndex(-1);
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
QmlEvent event;
event.setTimestamp(i); event.setTimestamp(i);
event.setString(QString::fromLatin1("message %1").arg(i)); event.setString(QString::fromLatin1("message %1").arg(i));
QmlEventType type(DebugMessage, MaximumRangeType, i % (QtMsgType::QtInfoMsg + 1), QmlEventType type(DebugMessage, MaximumRangeType, i % (QtMsgType::QtInfoMsg + 1),
QmlEventLocation("somefile.js", i, 10 - i)); QmlEventLocation("somefile.js", i, 10 - i));
event.setTypeIndex(manager.numEventTypes()); event.setTypeIndex(manager.numEventTypes());
manager.appendEventType(std::move(type)); manager.appendEventType(std::move(type));
manager.addEvent(event); manager.appendEvent(std::move(event));
} }
manager.finalize(); manager.finalize();
} }

View File

@@ -46,14 +46,13 @@ int FlameGraphModelTest::generateData(QmlProfilerModelManager *manager,
manager->notesModel()->addTimelineModel(rangeModel); manager->notesModel()->addTimelineModel(rangeModel);
manager->initialize(); manager->initialize();
QmlEvent event;
event.setTypeIndex(-1);
QStack<int> typeIndices; QStack<int> typeIndices;
int i = 0; int i = 0;
int typeIndex = -1;
while (i < 10) { while (i < 10) {
int typeIndex = -1; QmlEvent event;
if (i < 5) { if (i < 5) {
typeIndex = manager->appendEventType( typeIndex = manager->appendEventType(
QmlEventType(MaximumMessage, QmlEventType(MaximumMessage,
@@ -66,26 +65,29 @@ int FlameGraphModelTest::generateData(QmlProfilerModelManager *manager,
event.setTypeIndex(typeIndex); event.setTypeIndex(typeIndex);
event.setTimestamp(++i); event.setTimestamp(++i);
event.setRangeStage(RangeStart); event.setRangeStage(RangeStart);
manager->addEvent(event); manager->appendEvent(std::move(event));
typeIndices.push(typeIndex); typeIndices.push(typeIndex);
} }
QmlEvent event;
event.setTypeIndex(typeIndex);
event.setRangeStage(RangeEnd); event.setRangeStage(RangeEnd);
event.setTypeIndex(typeIndices.pop()); event.setTypeIndex(typeIndices.pop());
event.setTimestamp(++i); event.setTimestamp(++i);
manager->addEvent(event); manager->appendEvent(QmlEvent(event));
event.setRangeStage(RangeStart); event.setRangeStage(RangeStart);
event.setTypeIndex(0); // Have it accepted by the JavaScript range model above event.setTypeIndex(0); // Have it accepted by the JavaScript range model above
typeIndices.push(0); typeIndices.push(0);
event.setTimestamp(++i); event.setTimestamp(++i);
manager->addEvent(event); manager->appendEvent(std::move(event));
while (!typeIndices.isEmpty()) { while (!typeIndices.isEmpty()) {
QmlEvent event;
event.setTimestamp(++i); event.setTimestamp(++i);
event.setRangeStage(RangeEnd); event.setRangeStage(RangeEnd);
event.setTypeIndex(typeIndices.pop()); event.setTypeIndex(typeIndices.pop());
manager->addEvent(event); manager->appendEvent(std::move(event));
} }
manager->finalize(); manager->finalize();

View File

@@ -48,16 +48,16 @@ InputEventsModelTest::InputEventsModelTest(QObject *parent) :
void InputEventsModelTest::initTestCase() void InputEventsModelTest::initTestCase()
{ {
manager.initialize(); manager.initialize();
QmlEvent event;
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
QmlEvent event;
event.setTimestamp(i); event.setTimestamp(i);
InputEventType type = inputType(i); InputEventType type = inputType(i);
event.setTypeIndex(type <= InputKeyUnknown ? keyTypeId : mouseTypeId); event.setTypeIndex(type <= InputKeyUnknown ? keyTypeId : mouseTypeId);
event.setNumbers({static_cast<qint32>(type), event.setNumbers({static_cast<qint32>(type),
(i * 32) % 256, (i * 32) % 256,
static_cast<qint32>((i * 0x02000000) & Qt::KeyboardModifierMask)}); static_cast<qint32>((i * 0x02000000) & Qt::KeyboardModifierMask)});
manager.addEvent(event); manager.appendEvent(std::move(event));
} }
manager.finalize(); manager.finalize();

View File

@@ -52,23 +52,23 @@ void MemoryUsageModelTest::initTestCase()
event.setTimestamp(++timestamp); event.setTimestamp(++timestamp);
event.setTypeIndex(heapPageTypeId); event.setTypeIndex(heapPageTypeId);
event.setNumbers({2048}); event.setNumbers({2048});
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
manager.addEvent(event); // allocate two of them and make the model summarize manager.appendEvent(QmlEvent(event)); // allocate two of them and make the model summarize
event.setTimestamp(++timestamp); event.setTimestamp(++timestamp);
event.setTypeIndex(smallItemTypeId); event.setTypeIndex(smallItemTypeId);
event.setNumbers({32}); event.setNumbers({32});
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
event.setTimestamp(++timestamp); event.setTimestamp(++timestamp);
event.setTypeIndex(largeItemTypeId); event.setTypeIndex(largeItemTypeId);
event.setNumbers({1024}); event.setNumbers({1024});
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
event.setTimestamp(++timestamp); event.setTimestamp(++timestamp);
event.setTypeIndex(smallItemTypeId); event.setTypeIndex(smallItemTypeId);
event.setNumbers({-32}); event.setNumbers({-32});
manager.addEvent(event); manager.appendEvent(std::move(event));
}; };
addMemoryEvents(); addMemoryEvents();
@@ -82,19 +82,19 @@ void MemoryUsageModelTest::initTestCase()
event.setRangeStage(RangeStart); event.setRangeStage(RangeStart);
event.setTimestamp(++timestamp); event.setTimestamp(++timestamp);
event.setTypeIndex(rangeTypeId); event.setTypeIndex(rangeTypeId);
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
addMemoryEvents(); addMemoryEvents();
addMemoryEvents(); // twice to also trigger summary in first row addMemoryEvents(); // twice to also trigger summary in first row
event.setRangeStage(RangeEnd); event.setRangeStage(RangeEnd);
event.setTimestamp(++timestamp); event.setTimestamp(++timestamp);
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
event.setTimestamp(++timestamp); event.setTimestamp(++timestamp);
event.setTypeIndex(largeItemTypeId); event.setTypeIndex(largeItemTypeId);
event.setNumbers({-1024}); event.setNumbers({-1024});
manager.addEvent(event); manager.appendEvent(std::move(event));
manager.finalize(); manager.finalize();
QCOMPARE(model.count(), 11); QCOMPARE(model.count(), 11);

View File

@@ -53,7 +53,7 @@ void PixmapCacheModelTest::initTestCase()
event.setTypeIndex(eventTypeIndices[(i * 13) % MaximumPixmapEventType]); event.setTypeIndex(eventTypeIndices[(i * 13) % MaximumPixmapEventType]);
event.setTimestamp(i); event.setTimestamp(i);
event.setNumbers({i + 1, i - 1, i * 2}); event.setNumbers({i + 1, i - 1, i * 2});
manager.addEvent(event); manager.appendEvent(std::move(event));
} }
for (int i = 0; i < MaximumPixmapEventType; ++i) { for (int i = 0; i < MaximumPixmapEventType; ++i) {
@@ -68,27 +68,27 @@ void PixmapCacheModelTest::initTestCase()
QmlEvent event; QmlEvent event;
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingStarted]); event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingStarted]);
event.setTimestamp(101); event.setTimestamp(101);
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncached); QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncached);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading); QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapCacheCountChanged]); event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapCacheCountChanged]);
event.setNumbers({0, 0, 200}); // cache count increase event.setNumbers({0, 0, 200}); // cache count increase
event.setTimestamp(102); event.setTimestamp(102);
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::ToBeCached); QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::ToBeCached);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading); QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingError]); event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingError]);
event.setTimestamp(103); event.setTimestamp(103);
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Corrupt); QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Corrupt);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Error); QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Error);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapCacheCountChanged]); event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapCacheCountChanged]);
event.setNumbers({0, 0, 199}); // cache count decrease event.setNumbers({0, 0, 199}); // cache count decrease
event.setTimestamp(104); event.setTimestamp(104);
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncacheable); QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncacheable);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Error); QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Error);
@@ -97,13 +97,13 @@ void PixmapCacheModelTest::initTestCase()
QCOMPARE(model.count(), nextItem); QCOMPARE(model.count(), nextItem);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingStarted]); event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingStarted]);
event.setTimestamp(105); event.setTimestamp(105);
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncached); QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncached);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading); QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingError]); event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingError]);
event.setTimestamp(106); event.setTimestamp(106);
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncacheable); QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncacheable);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Error); QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Error);
@@ -112,7 +112,7 @@ void PixmapCacheModelTest::initTestCase()
// This way we get a corrupt cache entry ... // This way we get a corrupt cache entry ...
event.setNumbers({0, 0, 200}); event.setNumbers({0, 0, 200});
event.setTimestamp(107); event.setTimestamp(107);
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem - 1), PixmapCacheModel::Corrupt); QCOMPARE(model.cacheState(nextItem - 1), PixmapCacheModel::Corrupt);
QCOMPARE(model.loadState(nextItem - 1), PixmapCacheModel::Error); QCOMPARE(model.loadState(nextItem - 1), PixmapCacheModel::Error);
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncacheable); QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncacheable);
@@ -122,7 +122,7 @@ void PixmapCacheModelTest::initTestCase()
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapCacheCountChanged]); event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapCacheCountChanged]);
event.setNumbers({0, 0, 199}); // cache count decrease, removes the corrupt entry event.setNumbers({0, 0, 199}); // cache count decrease, removes the corrupt entry
event.setTimestamp(108); event.setTimestamp(108);
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem - 1), PixmapCacheModel::Uncacheable); QCOMPARE(model.cacheState(nextItem - 1), PixmapCacheModel::Uncacheable);
QCOMPARE(model.loadState(nextItem - 1), PixmapCacheModel::Error); QCOMPARE(model.loadState(nextItem - 1), PixmapCacheModel::Error);
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncacheable); QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncacheable);
@@ -133,28 +133,28 @@ void PixmapCacheModelTest::initTestCase()
QCOMPARE(model.count(), nextItem); QCOMPARE(model.count(), nextItem);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingStarted]); event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingStarted]);
event.setTimestamp(109); event.setTimestamp(109);
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncached); QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncached);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading); QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapCacheCountChanged]); event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapCacheCountChanged]);
event.setNumbers({0, 0, 200}); // cache count increase event.setNumbers({0, 0, 200}); // cache count increase
event.setTimestamp(110); event.setTimestamp(110);
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::ToBeCached); QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::ToBeCached);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading); QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapSizeKnown]); event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapSizeKnown]);
event.setNumbers({50, 50}); event.setNumbers({50, 50});
event.setTimestamp(111); event.setTimestamp(111);
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Cached); QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Cached);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading); QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapCacheCountChanged]); event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapCacheCountChanged]);
event.setNumbers({0, 0, 199}); // cache count decrease event.setNumbers({0, 0, 199}); // cache count decrease
event.setTimestamp(112); event.setTimestamp(112);
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncached); QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncached);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading); QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading);
@@ -163,13 +163,13 @@ void PixmapCacheModelTest::initTestCase()
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapSizeKnown]); event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapSizeKnown]);
event.setNumbers({20, 30}); event.setNumbers({20, 30});
event.setTimestamp(113); event.setTimestamp(113);
manager.addEvent(event); // Results in Uncached, with valid size manager.appendEvent(QmlEvent(event)); // Results in Uncached, with valid size
QCOMPARE(model.count(), nextItem + 3); // no item added here; we just store the size QCOMPARE(model.count(), nextItem + 3); // no item added here; we just store the size
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingError]); event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingError]);
event.setTimestamp(114); event.setTimestamp(114);
// terminates the still loading item, adding another cache count change // terminates the still loading item, adding another cache count change
manager.addEvent(event); manager.appendEvent(std::move(event));
QCOMPARE(model.count(), nextItem + 4); QCOMPARE(model.count(), nextItem + 4);
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncacheable); QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncacheable);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Error); QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Error);
@@ -182,7 +182,7 @@ void PixmapCacheModelTest::initTestCase()
event.setTypeIndex(eventTypeIndices[i]); event.setTypeIndex(eventTypeIndices[i]);
event.setTimestamp(i + j + 200); event.setTimestamp(i + j + 200);
event.setNumbers({i + 1, i - 1, i - j}); event.setNumbers({i + 1, i - 1, i - j});
manager.addEvent(event); manager.appendEvent(std::move(event));
} }
} }

View File

@@ -51,7 +51,7 @@ void QmlProfilerAnimationsModelTest::initTestCase()
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
event.setTimestamp(i); event.setTimestamp(i);
event.setNumbers<int>({frameRate(i), 9 - i, (i % 2) ? RenderThread : GuiThread}); event.setNumbers<int>({frameRate(i), 9 - i, (i % 2) ? RenderThread : GuiThread});
manager.addEvent(event); manager.appendEvent(QmlEvent(event));
} }
manager.finalize(); manager.finalize();
} }

View File

@@ -102,7 +102,7 @@ void QmlProfilerToolTest::testClearEvents()
QCOMPARE(modelManager->numEvents(), 0); QCOMPARE(modelManager->numEvents(), 0);
const int typeIndex = modelManager->appendEventType(QmlEventType()); const int typeIndex = modelManager->appendEventType(QmlEventType());
QCOMPARE(typeIndex, 0); QCOMPARE(typeIndex, 0);
modelManager->addEvent(QmlEvent(0, typeIndex, "")); modelManager->appendEvent(QmlEvent(0, typeIndex, ""));
QCOMPARE(modelManager->numEventTypes(), 1); QCOMPARE(modelManager->numEventTypes(), 1);
QCOMPARE(modelManager->numEvents(), 1); QCOMPARE(modelManager->numEvents(), 1);
stateManager->setServerRecording(false); stateManager->setServerRecording(false);
@@ -111,7 +111,7 @@ void QmlProfilerToolTest::testClearEvents()
stateManager->setServerRecording(true); // clears previous events, but not types stateManager->setServerRecording(true); // clears previous events, but not types
QCOMPARE(modelManager->numEventTypes(), 1); QCOMPARE(modelManager->numEventTypes(), 1);
QCOMPARE(modelManager->numEvents(), 0); QCOMPARE(modelManager->numEvents(), 0);
modelManager->addEvent(QmlEvent(0, typeIndex, "")); modelManager->appendEvent(QmlEvent(0, typeIndex, ""));
QCOMPARE(modelManager->numEventTypes(), 1); QCOMPARE(modelManager->numEventTypes(), 1);
QCOMPARE(modelManager->numEvents(), 1); QCOMPARE(modelManager->numEvents(), 1);
} }

View File

@@ -70,6 +70,11 @@ void QmlProfilerTraceClientTest::testMessageReceived()
traceClient.stateChanged(QmlDebug::QmlDebugClient::NotConnected); traceClient.stateChanged(QmlDebug::QmlDebugClient::NotConnected);
QFutureInterface<void> future; QFutureInterface<void> future;
QString lastError;
connect(&modelManager, &Timeline::TimelineTraceManager::error,
this, [&](const QString &message) { lastError = message; });
modelManager.replayQmlEvents([&](const QmlEvent &event, const QmlEventType &type) { modelManager.replayQmlEvents([&](const QmlEvent &event, const QmlEventType &type) {
qint64 timestamp; qint64 timestamp;
qint32 message; qint32 message;
@@ -81,14 +86,16 @@ void QmlProfilerTraceClientTest::testMessageReceived()
}, nullptr, [this]() { }, nullptr, [this]() {
modelManager.clearAll(); modelManager.clearAll();
traceClient.clear(); traceClient.clear();
}, [this](const QString &message) { }, [this, &lastError](const QString &message) {
if (message == QmlProfilerModelManager::tr("Read past end in temporary trace file")) { QVERIFY(!message.isEmpty());
if (lastError == QmlProfilerModelManager::tr("Read past end in temporary trace file")) {
// Ignore read-past-end errors: Our test traces are somewhat dirty and don't end on // Ignore read-past-end errors: Our test traces are somewhat dirty and don't end on
// packet boundaries // packet boundaries
modelManager.clearAll(); modelManager.clearAll();
traceClient.clear(); traceClient.clear();
lastError.clear();
} else { } else {
QFAIL(message.toUtf8().constData()); QFAIL((message + " " + lastError).toUtf8().constData());
} }
}, future); }, future);
} }