forked from qt-creator/qt-creator
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:
@@ -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,7 +253,8 @@ QFuture<void> TimelineTraceManager::save(const QString &filename)
|
||||
file->close();
|
||||
file->remove();
|
||||
delete file;
|
||||
emit error(message);
|
||||
if (!message.isEmpty())
|
||||
emit error(message);
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
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) {
|
||||
clearAll();
|
||||
delete reader;
|
||||
emit error(message);
|
||||
if (!message.isEmpty())
|
||||
emit error(message);
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
connect(reader, &TimelineTraceFile::canceled, this, [this, reader]() {
|
||||
@@ -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) {
|
||||
emit error(tr("Could not re-read events from temporary trace file: %1\n"
|
||||
"The trace data is lost.").arg(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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -170,8 +170,10 @@ void FlameGraphModel::restrictToFeatures(quint64 visibleFeatures)
|
||||
std::bind(&FlameGraphModel::beginResetModel, this),
|
||||
std::bind(&FlameGraphModel::finalize, this),
|
||||
[this](const QString &message) {
|
||||
emit m_modelManager->error(tr("Could not re-read events from temporary trace file: %1")
|
||||
.arg(message));
|
||||
if (!message.isEmpty()) {
|
||||
emit m_modelManager->error(tr("Could not re-read events from temporary trace file: %1")
|
||||
.arg(message));
|
||||
}
|
||||
endResetModel();
|
||||
clear();
|
||||
}, future);
|
||||
|
||||
@@ -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)
|
||||
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;
|
||||
if (!result && errorHandler) {
|
||||
errorHandler(future.isCanceled() ? QString()
|
||||
: tr("Failed to replay QML events from stash file."));
|
||||
} else if (result && finalizer) {
|
||||
finalizer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -112,8 +112,10 @@ void QmlProfilerStatisticsModel::restrictToFeatures(quint64 features)
|
||||
notesChanged(QmlProfilerStatisticsModel::s_invalidTypeId); // Reload notes
|
||||
}, [this](const QString &message) {
|
||||
endResetModel();
|
||||
emit m_modelManager->error(tr("Could not re-read events from temporary trace file: %1")
|
||||
.arg(message));
|
||||
if (!message.isEmpty()) {
|
||||
emit m_modelManager->error(tr("Could not re-read events from temporary trace file: %1")
|
||||
.arg(message));
|
||||
}
|
||||
clear();
|
||||
}, future);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
int typeIndex = -1;
|
||||
while (i < 10) {
|
||||
int typeIndex = -1;
|
||||
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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user