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

View File

@@ -49,6 +49,17 @@ public:
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 TRACING_EXPORT TimelineTraceManager : public QObject
{
@@ -61,7 +72,8 @@ public:
typedef std::function<void()> Clearer;
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);
~TimelineTraceManager() override;
@@ -78,6 +90,7 @@ public:
int numEvents() const;
int numEventTypes() const;
const TraceEventStorage *eventStorage() const;
const TraceEventTypeStorage *typeStorage() const;
void registerFeatures(quint64 features, TraceEventLoader eventLoader,
@@ -117,8 +130,7 @@ protected:
void restrictByFilter(TraceEventFilter filter);
void addEvent(const TraceEvent &event);
void appendEvent(TraceEvent &&event);
const TraceEventType &eventType(int typeId) const;
void setEventType(int typeId, TraceEventType &&type);
int appendEventType(TraceEventType &&type);

View File

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

View File

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

View File

@@ -74,19 +74,37 @@ private:
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
{
public:
QmlProfilerModelManagerPrivate() : file("qmlprofiler-data") {}
Internal::QmlProfilerTextMarkModel *textMarkModel = nullptr;
Internal::QmlProfilerDetailsRewriter *detailsRewriter = nullptr;
Timeline::TraceStashFile<QmlEvent> file;
bool isRestrictedToRange = false;
void writeToStream(const QmlEvent &event);
void addEventType(const QmlEventType &eventType);
void handleError(const QString &message);
@@ -94,7 +112,10 @@ public:
};
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)
{
setNotesModel(new QmlProfilerNotesModel(this));
@@ -106,9 +127,6 @@ QmlProfilerModelManager::QmlProfilerModelManager(QObject *parent) :
connect(d->detailsRewriter, &Internal::QmlProfilerDetailsRewriter::eventDetailsChanged,
this, &QmlProfilerModelManager::typeDetailsFinished);
if (!d->file.open())
emit error(tr("Cannot open temporary trace file to store events."));
quint64 allFeatures = 0;
for (quint8 i = 0; i <= MaximumProfileFeature; ++i)
allFeatures |= (1ull << i);
@@ -138,12 +156,6 @@ void QmlProfilerModelManager::registerFeatures(quint64 features, QmlEventLoader
finalizer, clearer);
}
void QmlProfilerModelManager::addEvents(const QVector<QmlEvent> &events)
{
for (const QmlEvent &event : events)
addEvent(event);
}
const QmlEventType &QmlProfilerModelManager::eventType(int typeId) const
{
return static_cast<const QmlEventType &>(TimelineTraceManager::eventType(typeId));
@@ -174,31 +186,19 @@ void QmlProfilerModelManager::replayQmlEvents(QmlEventLoader loader,
if (initializer)
initializer();
const auto result = d->file.replay([&](const QmlEvent &event) {
const auto result = eventStorage()->replay([&](Timeline::TraceEvent &&event) {
if (future.isCanceled())
return false;
loader(event, eventType(event.typeIndex()));
loader(static_cast<QmlEvent &&>(event), eventType(event.typeIndex()));
return true;
});
switch (result) {
case Timeline::TraceStashFile<QmlEvent>::ReplaySuccess:
if (finalizer)
if (!result && errorHandler) {
errorHandler(future.isCanceled() ? QString()
: tr("Failed to replay QML events from stash file."));
} else if (result && finalizer) {
finalizer();
break;
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;
}
void QmlProfilerModelManager::QmlProfilerModelManagerPrivate::writeToStream(const QmlEvent &event)
{
file.append(event);
}
void QmlProfilerModelManager::QmlProfilerModelManagerPrivate::handleError(const QString &message)
{
// What to do here?
@@ -254,8 +249,6 @@ const char *QmlProfilerModelManager::featureName(ProfileFeature feature)
void QmlProfilerModelManager::finalize()
{
if (!d->file.flush())
emit error(tr("Failed to flush temporary trace file"));
d->detailsRewriter->reloadDocuments();
// 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)
{
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::addEvent(event);
TimelineTraceManager::appendEvent(std::move(event));
}
void QmlProfilerModelManager::restrictToRange(qint64 start, qint64 end)
@@ -480,4 +464,67 @@ void QmlProfilerEventTypeStorage::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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -53,7 +53,7 @@ void PixmapCacheModelTest::initTestCase()
event.setTypeIndex(eventTypeIndices[(i * 13) % MaximumPixmapEventType]);
event.setTimestamp(i);
event.setNumbers({i + 1, i - 1, i * 2});
manager.addEvent(event);
manager.appendEvent(std::move(event));
}
for (int i = 0; i < MaximumPixmapEventType; ++i) {
@@ -68,27 +68,27 @@ void PixmapCacheModelTest::initTestCase()
QmlEvent event;
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingStarted]);
event.setTimestamp(101);
manager.addEvent(event);
manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncached);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapCacheCountChanged]);
event.setNumbers({0, 0, 200}); // cache count increase
event.setTimestamp(102);
manager.addEvent(event);
manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::ToBeCached);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingError]);
event.setTimestamp(103);
manager.addEvent(event);
manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Corrupt);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Error);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapCacheCountChanged]);
event.setNumbers({0, 0, 199}); // cache count decrease
event.setTimestamp(104);
manager.addEvent(event);
manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncacheable);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Error);
@@ -97,13 +97,13 @@ void PixmapCacheModelTest::initTestCase()
QCOMPARE(model.count(), nextItem);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingStarted]);
event.setTimestamp(105);
manager.addEvent(event);
manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncached);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingError]);
event.setTimestamp(106);
manager.addEvent(event);
manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncacheable);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Error);
@@ -112,7 +112,7 @@ void PixmapCacheModelTest::initTestCase()
// This way we get a corrupt cache entry ...
event.setNumbers({0, 0, 200});
event.setTimestamp(107);
manager.addEvent(event);
manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem - 1), PixmapCacheModel::Corrupt);
QCOMPARE(model.loadState(nextItem - 1), PixmapCacheModel::Error);
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncacheable);
@@ -122,7 +122,7 @@ void PixmapCacheModelTest::initTestCase()
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapCacheCountChanged]);
event.setNumbers({0, 0, 199}); // cache count decrease, removes the corrupt entry
event.setTimestamp(108);
manager.addEvent(event);
manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem - 1), PixmapCacheModel::Uncacheable);
QCOMPARE(model.loadState(nextItem - 1), PixmapCacheModel::Error);
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncacheable);
@@ -133,28 +133,28 @@ void PixmapCacheModelTest::initTestCase()
QCOMPARE(model.count(), nextItem);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingStarted]);
event.setTimestamp(109);
manager.addEvent(event);
manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncached);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapCacheCountChanged]);
event.setNumbers({0, 0, 200}); // cache count increase
event.setTimestamp(110);
manager.addEvent(event);
manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::ToBeCached);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapSizeKnown]);
event.setNumbers({50, 50});
event.setTimestamp(111);
manager.addEvent(event);
manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Cached);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading);
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapCacheCountChanged]);
event.setNumbers({0, 0, 199}); // cache count decrease
event.setTimestamp(112);
manager.addEvent(event);
manager.appendEvent(QmlEvent(event));
QCOMPARE(model.cacheState(nextItem), PixmapCacheModel::Uncached);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Loading);
@@ -163,13 +163,13 @@ void PixmapCacheModelTest::initTestCase()
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapSizeKnown]);
event.setNumbers({20, 30});
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
event.setTypeIndex(eventTypeIndices[MaximumPixmapEventType + PixmapLoadingError]);
event.setTimestamp(114);
// 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.cacheState(nextItem), PixmapCacheModel::Uncacheable);
QCOMPARE(model.loadState(nextItem), PixmapCacheModel::Error);
@@ -182,7 +182,7 @@ void PixmapCacheModelTest::initTestCase()
event.setTypeIndex(eventTypeIndices[i]);
event.setTimestamp(i + j + 200);
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) {
event.setTimestamp(i);
event.setNumbers<int>({frameRate(i), 9 - i, (i % 2) ? RenderThread : GuiThread});
manager.addEvent(event);
manager.appendEvent(QmlEvent(event));
}
manager.finalize();
}

View File

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

View File

@@ -70,6 +70,11 @@ void QmlProfilerTraceClientTest::testMessageReceived()
traceClient.stateChanged(QmlDebug::QmlDebugClient::NotConnected);
QFutureInterface<void> future;
QString lastError;
connect(&modelManager, &Timeline::TimelineTraceManager::error,
this, [&](const QString &message) { lastError = message; });
modelManager.replayQmlEvents([&](const QmlEvent &event, const QmlEventType &type) {
qint64 timestamp;
qint32 message;
@@ -81,14 +86,16 @@ void QmlProfilerTraceClientTest::testMessageReceived()
}, nullptr, [this]() {
modelManager.clearAll();
traceClient.clear();
}, [this](const QString &message) {
if (message == QmlProfilerModelManager::tr("Read past end in temporary trace file")) {
}, [this, &lastError](const QString &message) {
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
// packet boundaries
modelManager.clearAll();
traceClient.clear();
lastError.clear();
} else {
QFAIL(message.toUtf8().constData());
QFAIL((message + " " + lastError).toUtf8().constData());
}
}, future);
}