QmlProfiler: Move parts of model manager and trace file to Timeline

This way we can use the trace file loading and saving mechanism for
other profilers.

Change-Id: I98ec1cdde6f7abcea152cabf72e64d4e696dfa59
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Ulf Hermann
2018-04-05 09:47:33 +02:00
parent 7099f21586
commit 1c2e0f387f
37 changed files with 1443 additions and 1001 deletions

View File

@@ -17,7 +17,9 @@ SOURCES += \
$$PWD/timelineabstractrenderer.cpp \
$$PWD/timelineoverviewrenderer.cpp \
$$PWD/timelinetheme.cpp \
$$PWD/timelineformattime.cpp
$$PWD/timelineformattime.cpp \
$$PWD/timelinetracefile.cpp \
$$PWD/timelinetracemanager.cpp
HEADERS += \
$$PWD/timeline_global.h \
@@ -41,8 +43,11 @@ HEADERS += \
$$PWD/timelineoverviewrenderer.h \
$$PWD/timelinetheme.h \
$$PWD/timelineformattime.h \
$$PWD/timelinetracefile.h \
$$PWD/timelinetracemanager.h \
$$PWD/traceevent.h \
$$PWD/traceeventtype.h
$$PWD/traceeventtype.h \
$$PWD/tracestashfile.h
RESOURCES += \
$$PWD/qml/timeline.qrc

View File

@@ -30,8 +30,10 @@ Project {
"timelinerenderstate.cpp", "timelinerenderstate.h", "timelinerenderstate_p.h",
"timelineselectionrenderpass.cpp", "timelineselectionrenderpass.h",
"timelinetheme.cpp", "timelinetheme.h",
"timelinetracefile.cpp", "timelinetracefile.h",
"timelinetracemanager.cpp", "timelinetracemanager.h",
"timelinezoomcontrol.cpp", "timelinezoomcontrol.h",
"traceevent.h", "traceeventtype.h",
"traceevent.h", "traceeventtype.h", "tracestashfile.h"
]
}

View File

@@ -0,0 +1,76 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "timelinetracefile.h"
namespace Timeline {
TimelineTraceFile::TimelineTraceFile(QObject *parent) : QObject(parent)
{
}
void TimelineTraceFile::setFuture(const QFutureInterface<void> &future)
{
m_future = future;
m_future.setProgressRange(MinimumProgress, MaximumProgress);
m_future.setProgressValue(MinimumProgress);
}
QFutureInterface<void> &TimelineTraceFile::future()
{
return m_future;
}
bool TimelineTraceFile::isProgressUpdateNeeded() const
{
return m_future.isProgressUpdateNeeded() || m_future.progressValue() == 0;
}
void TimelineTraceFile::addProgressValue(int progressValue)
{
m_future.setProgressValue(qMax(static_cast<int>(MinimumProgress),
qMin(m_future.progressValue() + progressValue,
static_cast<int>(MaximumProgress))));
}
void TimelineTraceFile::setDeviceProgress(QIODevice *device)
{
m_future.setProgressValue(MinimumProgress + device->pos()
* (MaximumProgress - MinimumProgress) / device->size());
}
bool TimelineTraceFile::isCanceled() const
{
return m_future.isCanceled();
}
void TimelineTraceFile::setTraceTime(qint64 traceStart, qint64 traceEnd, qint64 measuredTime)
{
m_traceStart = traceStart;
m_traceEnd = traceEnd;
m_measuredTime = measuredTime;
}
} // namespace Timeline

View File

@@ -0,0 +1,97 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "timeline_global.h"
#include <QFutureInterface>
#include <QObject>
QT_FORWARD_DECLARE_CLASS(QIODevice)
namespace Timeline {
class TimelineNotesModel;
class TimelineTraceManager;
class TIMELINE_EXPORT TimelineTraceFile : public QObject
{
Q_OBJECT
public:
enum ProgressValues {
MinimumProgress = 0,
MaximumProgress = 1000
};
explicit TimelineTraceFile(QObject *parent = 0);
void setTraceManager(TimelineTraceManager *traceManager) { m_traceManager = traceManager; }
TimelineTraceManager *traceManager() const { return m_traceManager; }
void setNotes(TimelineNotesModel *notes) { m_notes = notes; }
TimelineNotesModel *notes() const { return m_notes; }
void setTraceTime(qint64 startTime, qint64 endTime, qint64 measturedTime);
void setFuture(const QFutureInterface<void> &future);
QFutureInterface<void> &future();
bool isProgressUpdateNeeded() const;
void addProgressValue(int progressValue);
void setDeviceProgress(QIODevice *device);
virtual void save(QIODevice *device) = 0;
virtual void load(QIODevice *device) = 0;
void setTraceStart(qint64 traceStart) { m_traceStart = traceStart; }
qint64 traceStart() const { return m_traceStart; }
void setTraceEnd(qint64 traceEnd) { m_traceEnd = traceEnd; }
qint64 traceEnd() const { return m_traceEnd; }
qint64 measuredTime() const { return m_measuredTime; }
bool isCanceled() const;
quint64 loadedFeatures() const { return m_loadedFeatures; }
void addFeature(quint8 feature) { m_loadedFeatures |= (1ull << feature); }
signals:
void error(const QString &error);
void success();
void canceled();
private:
qint64 m_traceStart = -1;
qint64 m_traceEnd = -1;
qint64 m_measuredTime = -1;
quint64 m_loadedFeatures = 0;
QFutureInterface<void> m_future;
TimelineTraceManager *m_traceManager = nullptr;
TimelineNotesModel *m_notes = nullptr;
};
} // namespace Timeline

View File

@@ -0,0 +1,481 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "timelinetracemanager.h"
#include "timelinetracefile.h"
#include <utils/qtcassert.h>
#include <utils/temporaryfile.h>
#include <utils/runextensions.h>
#include <QFile>
#include <QDataStream>
namespace Timeline {
class TimelineTraceManager::TimelineTraceManagerPrivate
{
public:
TimelineNotesModel *notesModel = nullptr;
TimelineTraceManager::State state = Empty;
int numEvents = 0;
int numEventTypes = 0;
quint64 availableFeatures = 0;
quint64 visibleFeatures = 0;
quint64 recordedFeatures = 0;
bool aggregateTraces = false;
QHash<quint8, QVector<TraceEventLoader>> eventLoaders;
QVector<Initializer> initializers;
QVector<Finalizer> finalizers;
QVector<Clearer> clearers;
qint64 traceStart = -1;
qint64 traceEnd = -1;
qint64 restrictedTraceStart = -1;
qint64 restrictedTraceEnd = -1;
void dispatch(const TraceEvent &event, const TraceEventType &type);
void reset();
void setState(TimelineTraceManager *q, TimelineTraceManager::State state);
void updateTraceTime(qint64 time);
void restrictTraceTimeToRange(qint64 start, qint64 end);
};
TimelineTraceManager::TimelineTraceManager(QObject *parent) :
QObject(parent), d(new TimelineTraceManagerPrivate)
{
}
TimelineTraceManager::~TimelineTraceManager()
{
delete d;
}
TimelineNotesModel *TimelineTraceManager::notesModel() const
{
return d->notesModel;
}
bool TimelineTraceManager::isEmpty() const
{
return d->numEvents == 0;
}
int TimelineTraceManager::numEvents() const
{
return d->numEvents;
}
int TimelineTraceManager::numEventTypes() const
{
return d->numEventTypes;
}
void TimelineTraceManager::addEvent(const TraceEvent &event)
{
d->dispatch(event, lookupType(event.typeIndex()));
}
void TimelineTraceManager::addEventType(const TraceEventType &type)
{
const quint8 feature = type.feature();
d->recordedFeatures |= (1ull << feature);
++(d->numEventTypes);
}
void TimelineTraceManager::registerFeatures(quint64 features, TraceEventLoader eventLoader,
Initializer initializer, Finalizer finalizer,
Clearer clearer)
{
if ((features & d->availableFeatures) != features) {
d->availableFeatures |= features;
emit availableFeaturesChanged(d->availableFeatures);
}
if ((features & d->visibleFeatures) != features) {
d->visibleFeatures |= features;
emit visibleFeaturesChanged(d->visibleFeatures);
}
for (quint8 feature = 0; feature != sizeof(features) * 8; ++feature) {
if (features & (1ULL << feature)) {
if (eventLoader)
d->eventLoaders[feature].append(eventLoader);
}
}
if (initializer)
d->initializers.append(initializer);
if (finalizer)
d->finalizers.append(finalizer);
if (clearer)
d->clearers.append(clearer);
}
quint64 TimelineTraceManager::availableFeatures() const
{
return d->availableFeatures;
}
quint64 TimelineTraceManager::visibleFeatures() const
{
return d->visibleFeatures;
}
void TimelineTraceManager::setVisibleFeatures(quint64 features)
{
if (d->visibleFeatures != features) {
d->visibleFeatures = features;
emit visibleFeaturesChanged(d->visibleFeatures);
}
}
quint64 TimelineTraceManager::recordedFeatures() const
{
return d->recordedFeatures;
}
void TimelineTraceManager::setRecordedFeatures(quint64 features)
{
if (d->recordedFeatures != features) {
d->recordedFeatures = features;
emit recordedFeaturesChanged(d->recordedFeatures);
}
}
bool TimelineTraceManager::aggregateTraces() const
{
return d->aggregateTraces;
}
void TimelineTraceManager::setAggregateTraces(bool aggregateTraces)
{
d->aggregateTraces = aggregateTraces;
}
void TimelineTraceManager::initialize()
{
for (const Initializer &initializer : qAsConst(d->initializers))
initializer();
d->setState(this, AcquiringData);
}
void TimelineTraceManager::finalize()
{
QTC_CHECK(state() == AcquiringData);
// Load notes after the timeline models have been initialized ...
// which happens on stateChanged(Done).
for (const Finalizer &finalizer : qAsConst(d->finalizers))
finalizer();
d->setState(this, Done);
}
QFuture<void> TimelineTraceManager::save(const QString &filename)
{
QFile *file = new QFile(filename);
if (!file->open(QIODevice::WriteOnly)) {
delete file;
return Utils::runAsync([this, filename](QFutureInterface<void> &future) {
future.setProgressRange(0, 1);
future.setProgressValue(1);
emit error(tr("Could not open %1 for writing.").arg(filename));
emit saveFinished();
});
}
TimelineTraceFile *writer = createTraceFile();
writer->setTraceTime(traceStart(), traceEnd(), traceDuration());
writer->setTraceManager(this);
writer->setNotes(d->notesModel);
connect(writer, &QObject::destroyed, this, &TimelineTraceManager::saveFinished,
Qt::QueuedConnection);
connect(writer, &TimelineTraceFile::error, this, [this, file](const QString &message) {
file->close();
file->remove();
delete file;
emit error(message);
}, Qt::QueuedConnection);
connect(writer, &TimelineTraceFile::success, this, [file]() {
file->close();
delete file;
}, Qt::QueuedConnection);
connect(writer, &TimelineTraceFile::canceled, this, [file]() {
file->close();
file->remove();
delete file;
}, Qt::QueuedConnection);
return Utils::runAsync([file, writer] (QFutureInterface<void> &future) {
writer->setFuture(future);
writer->save(file);
writer->deleteLater();
});
}
QFuture<void> TimelineTraceManager::load(const QString &filename)
{
QFile *file = new QFile(filename, this);
if (!file->open(QIODevice::ReadOnly)) {
delete file;
return Utils::runAsync([this, filename] (QFutureInterface<void> &future) {
future.setProgressRange(0, 1);
future.setProgressValue(1);
emit error(tr("Could not open %1 for reading.").arg(filename));
emit loadFinished();
});
}
clearAll();
initialize();
TimelineTraceFile *reader = createTraceFile();
reader->setTraceManager(this);
reader->setNotes(d->notesModel);
connect(reader, &QObject::destroyed, this, &TimelineTraceManager::loadFinished,
Qt::QueuedConnection);
connect(reader, &TimelineTraceFile::success, this, [this, reader]() {
if (reader->traceStart() >= 0)
decreaseTraceStart(reader->traceStart());
if (reader->traceEnd() >= 0)
increaseTraceEnd(reader->traceEnd());
finalize();
delete reader;
}, Qt::QueuedConnection);
connect(reader, &TimelineTraceFile::error, this, [this, reader](const QString &message) {
clearAll();
delete reader;
emit error(message);
}, Qt::QueuedConnection);
connect(reader, &TimelineTraceFile::canceled, this, [this, reader]() {
clearAll();
delete reader;
}, Qt::QueuedConnection);
return Utils::runAsync([file, reader] (QFutureInterface<void> &future) {
reader->setFuture(future);
reader->load(file);
file->close();
file->deleteLater();
});
}
qint64 TimelineTraceManager::traceStart() const
{
return d->restrictedTraceStart != -1 ? d->restrictedTraceStart : d->traceStart;
}
qint64 TimelineTraceManager::traceEnd() const
{
return d->restrictedTraceEnd != -1 ? d->restrictedTraceEnd : d->traceEnd;
}
qint64 TimelineTraceManager::traceDuration() const
{
return traceEnd() - traceStart();
}
void TimelineTraceManager::decreaseTraceStart(qint64 start)
{
QTC_ASSERT(start >= 0, return);
if (d->traceStart > start || d->traceStart == -1) {
d->traceStart = start;
if (d->traceEnd == -1)
d->traceEnd = d->traceStart;
else
QTC_ASSERT(d->traceEnd >= d->traceStart, d->traceEnd = d->traceStart);
}
}
void TimelineTraceManager::increaseTraceEnd(qint64 end)
{
QTC_ASSERT(end >= 0, return);
if (d->traceEnd < end || d->traceEnd == -1) {
d->traceEnd = end;
if (d->traceStart == -1)
d->traceStart = d->traceEnd;
else
QTC_ASSERT(d->traceEnd >= d->traceStart, d->traceStart = d->traceEnd);
}
}
void TimelineTraceManager::TimelineTraceManagerPrivate::setState(
TimelineTraceManager *q, TimelineTraceManager::State newState)
{
// It's not an error, we are continuously calling "AcquiringData" for example
if (newState == state)
return;
switch (newState) {
case ClearingData:
QTC_CHECK(state == Done || state == Empty || state == AcquiringData);
break;
case Empty:
// if it's not empty, complain but go on
QTC_CHECK(q->isEmpty());
break;
case AcquiringData:
break;
case Done:
QTC_ASSERT(state == AcquiringData || state == Empty, return);
break;
default:
QTC_ASSERT(false, return);
break;
}
state = newState;
emit q->stateChanged(state);
}
void TimelineTraceManager::TimelineTraceManagerPrivate::updateTraceTime(qint64 time)
{
QTC_ASSERT(time >= 0, return);
if (traceStart > time || traceStart == -1)
traceStart = time;
if (traceEnd < time || traceEnd == -1)
traceEnd = time;
QTC_ASSERT(traceEnd >= traceStart, traceStart = traceEnd);
}
void TimelineTraceManager::TimelineTraceManagerPrivate::restrictTraceTimeToRange(qint64 start,
qint64 end)
{
QTC_ASSERT(end == -1 || start <= end, end = start);
restrictedTraceStart = start;
restrictedTraceEnd = end;
}
TimelineTraceManager::State TimelineTraceManager::state() const
{
return d->state;
}
void TimelineTraceManager::setNotesModel(TimelineNotesModel *notesModel)
{
d->notesModel = notesModel;
}
void TimelineTraceManager::clearEventStorage()
{
d->reset();
if (d->notesModel)
d->notesModel->clear();
setVisibleFeatures(0);
setRecordedFeatures(0);
}
void TimelineTraceManager::clearTypeStorage()
{
d->numEventTypes = 0;
d->recordedFeatures = 0;
}
void TimelineTraceManager::clear()
{
d->setState(this, ClearingData);
clearEventStorage();
d->setState(this, Empty);
}
void TimelineTraceManager::clearAll()
{
d->setState(this, ClearingData);
clearEventStorage();
clearTypeStorage();
d->setState(this, Empty);
}
void TimelineTraceManager::restrictToRange(qint64 startTime, qint64 endTime)
{
if (d->notesModel)
d->notesModel->stash();
d->setState(this, ClearingData);
d->reset();
setVisibleFeatures(0);
QFutureInterface<void> future;
replayEvents(startTime, endTime,
std::bind(&TimelineTraceManagerPrivate::dispatch, d, std::placeholders::_1,
std::placeholders::_2),
[this, startTime, endTime]() {
d->restrictTraceTimeToRange(startTime, endTime);
initialize();
}, [this]() {
if (d->notesModel)
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));
clearAll();
}, future);
}
bool TimelineTraceManager::isRestrictedToRange() const
{
return d->restrictedTraceStart != -1 || d->restrictedTraceEnd != -1;
}
void TimelineTraceManager::TimelineTraceManagerPrivate::dispatch(const TraceEvent &event,
const TraceEventType &type)
{
for (const TraceEventLoader &loader : eventLoaders[type.feature()])
loader(event, type);
if (event.timestamp() >= 0)
updateTraceTime(event.timestamp());
++numEvents;
}
void TimelineTraceManager::TimelineTraceManagerPrivate::reset()
{
restrictTraceTimeToRange(-1, -1);
traceStart = -1;
traceEnd = -1;
for (const Clearer &clearer : qAsConst(clearers))
clearer();
numEvents = 0;
}
} // namespace Timeline

View File

@@ -0,0 +1,128 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "timeline_global.h"
#include "timelinenotesmodel.h"
#include "traceevent.h"
#include "traceeventtype.h"
#include <QObject>
#include <QFuture>
#include <functional>
namespace Timeline {
class TimelineTraceFile;
class TIMELINE_EXPORT TimelineTraceManager : public QObject
{
Q_OBJECT
public:
enum State {
Empty,
AcquiringData,
ClearingData,
Done
};
typedef std::function<void(const TraceEvent &, const TraceEventType &)> TraceEventLoader;
typedef std::function<void()> Initializer;
typedef std::function<void()> Finalizer;
typedef std::function<void()> Clearer;
typedef std::function<void(const QString &)> ErrorHandler;
explicit TimelineTraceManager(QObject *parent = nullptr);
~TimelineTraceManager();
State state() const;
qint64 traceStart() const;
qint64 traceEnd() const;
qint64 traceDuration() const;
void decreaseTraceStart(qint64 start);
void increaseTraceEnd(qint64 end);
void setNotesModel(TimelineNotesModel *notesModel);
TimelineNotesModel *notesModel() const;
bool isEmpty() const;
int numEvents() const;
int numEventTypes() const;
void registerFeatures(quint64 features, TraceEventLoader eventLoader,
Initializer initializer = Initializer(),
Finalizer finalizer = Finalizer(),
Clearer clearer = Clearer());
quint64 availableFeatures() const;
quint64 visibleFeatures() const;
void setVisibleFeatures(quint64 features);
quint64 recordedFeatures() const;
void setRecordedFeatures(quint64 features);
bool aggregateTraces() const;
void setAggregateTraces(bool aggregateTraces);
virtual void initialize();
virtual void finalize();
virtual void clear();
void clearAll();
void restrictToRange(qint64 startTime, qint64 endTime);
bool isRestrictedToRange() const;
QFuture<void> save(const QString &filename);
QFuture<void> load(const QString &filename);
signals:
void error(const QString &error);
void stateChanged(State state);
void loadFinished();
void saveFinished();
void availableFeaturesChanged(quint64 features);
void visibleFeaturesChanged(quint64 features);
void recordedFeaturesChanged(quint64 features);
protected:
virtual void clearEventStorage();
virtual void clearTypeStorage();
void addEvent(const TraceEvent &event);
void addEventType(const TraceEventType &type);
virtual const TraceEventType &lookupType(int typeId) const = 0;
virtual TimelineTraceFile *createTraceFile() = 0;
virtual void replayEvents(qint64 rangeStart, qint64 rangeEnd, TraceEventLoader loader,
Initializer initializer, Finalizer finalizer,
ErrorHandler errorHandler, QFutureInterface<void> &future) const = 0;
private:
class TimelineTraceManagerPrivate;
TimelineTraceManagerPrivate *d;
};
} // namespace Timeline

View File

@@ -0,0 +1,98 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <utils/temporaryfile.h>
#include <QFile>
#include <QDataStream>
namespace Timeline {
template<typename Event>
class TraceStashFile
{
public:
TraceStashFile(const QString &pattern) : file(pattern) {}
bool open()
{
if (!file.open())
return false;
stream.setDevice(&file);
return true;
}
void append(const Event &event)
{
stream << event;
}
enum ReplayResult {
ReplaySuccess,
ReplayOpenFailed,
ReplayLoadFailed,
ReplayReadPastEnd
};
template<typename Loader>
ReplayResult replay(const Loader &loader) const
{
QFile readFile(file.fileName());
if (!readFile.open(QIODevice::ReadOnly))
return ReplayOpenFailed;
QDataStream readStream(&readFile);
Event event;
while (!readStream.atEnd()) {
readStream >> event;
if (readStream.status() == QDataStream::ReadPastEnd)
return ReplayReadPastEnd;
if (!loader(event))
return ReplayLoadFailed;
}
return ReplaySuccess;
}
void clear()
{
file.remove();
stream.unsetDevice();
}
bool flush()
{
return file.flush();
}
private:
Utils::TemporaryFile file;
QDataStream stream;
};
}

View File

@@ -111,6 +111,7 @@ void DebugMessagesModel::finalize()
{
setCollapsedRowCount(Constants::QML_MIN_LEVEL + 1);
setExpandedRowCount(m_maximumMsgType + 2);
QmlProfilerTimelineModel::finalize();
}
void DebugMessagesModel::clear()

View File

@@ -51,20 +51,18 @@ FlameGraphModel::FlameGraphModel(QmlProfilerModelManager *modelManager,
m_compileStack.append(QmlEvent());
m_callStackTop = &m_stackBottom;
m_compileStackTop = &m_stackBottom;
connect(modelManager, &QmlProfilerModelManager::stateChanged,
this, &FlameGraphModel::onModelManagerStateChanged);
connect(modelManager, &QmlProfilerModelManager::typeDetailsFinished,
this, &FlameGraphModel::onTypeDetailsFinished);
connect(modelManager->notesModel(), &Timeline::TimelineNotesModel::changed,
this, [this](int typeId, int, int){loadNotes(typeId, true);});
m_acceptedFeatures = supportedFeatures();
modelManager->announceFeatures(m_acceptedFeatures,
[this](const QmlEvent &event, const QmlEventType &type) {
loadEvent(event, type);
}, [this](){
finalize();
});
modelManager->registerFeatures(m_acceptedFeatures,
std::bind(&FlameGraphModel::loadEvent, this,
std::placeholders::_1, std::placeholders::_2),
std::bind(&FlameGraphModel::beginResetModel, this),
std::bind(&FlameGraphModel::finalize, this),
std::bind(&FlameGraphModel::clear, this));
}
void FlameGraphModel::clear()
@@ -108,9 +106,6 @@ void FlameGraphModel::loadEvent(const QmlEvent &event, const QmlEventType &type)
if (!(m_acceptedFeatures & (1ULL << type.feature())))
return;
if (m_stackBottom.children.isEmpty())
beginResetModel();
const bool isCompiling = (type.rangeType() == Compiling);
QStack<QmlEvent> &stack = isCompiling ? m_compileStack : m_callStack;
FlameGraphData *&stackTop = isCompiling ? m_compileStackTop : m_callStackTop;
@@ -152,12 +147,6 @@ void FlameGraphModel::finalize()
endResetModel();
}
void FlameGraphModel::onModelManagerStateChanged()
{
if (m_modelManager->state() == QmlProfilerModelManager::ClearingData)
clear();
}
void FlameGraphModel::onTypeDetailsFinished()
{
emit dataChanged(QModelIndex(), QModelIndex(), QVector<int>(1, DetailsRole));
@@ -174,17 +163,19 @@ void FlameGraphModel::restrictToFeatures(quint64 visibleFeatures)
return;
clear();
beginResetModel();
if (!m_modelManager->replayEvents(m_modelManager->traceStart(), m_modelManager->traceEnd(),
std::bind(&FlameGraphModel::loadEvent,
this, std::placeholders::_1,
std::placeholders::_2))) {
emit m_modelManager->error(tr("Could not re-read events from temporary trace file."));
QFutureInterface<void> future;
m_modelManager->replayEvents(m_modelManager->traceStart(), m_modelManager->traceEnd(),
std::bind(&FlameGraphModel::loadEvent, this,
std::placeholders::_1, std::placeholders::_2),
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));
endResetModel();
clear();
} else {
finalize();
}
}, future);
}
static QString nameForType(RangeType typeNumber)
@@ -207,7 +198,7 @@ QVariant FlameGraphModel::lookup(const FlameGraphData &stats, int role) const
QString ret;
if (!m_typeIdsWithNotes.contains(stats.typeIndex))
return ret;
QmlProfilerNotesModel *notes = m_modelManager->notesModel();
Timeline::TimelineNotesModel *notes = m_modelManager->notesModel();
foreach (const QVariant &item, notes->byTypeId(stats.typeIndex)) {
if (ret.isEmpty())
ret = notes->text(item.toInt());

View File

@@ -89,7 +89,6 @@ public:
void loadEvent(const QmlEvent &event, const QmlEventType &type);
void finalize();
void onModelManagerStateChanged();
void onTypeDetailsFinished();
void restrictToFeatures(quint64 visibleFeatures);
void loadNotes(int typeId, bool emitSignal);

View File

@@ -165,6 +165,7 @@ void InputEventsModel::finalize()
{
setCollapsedRowCount(2);
setExpandedRowCount(3);
QmlProfilerTimelineModel::finalize();
}
void InputEventsModel::clear()

View File

@@ -36,8 +36,11 @@ MemoryUsageModel::MemoryUsageModel(QmlProfilerModelManager *manager,
Timeline::TimelineModelAggregator *parent) :
QmlProfilerTimelineModel(manager, MemoryAllocation, MaximumRangeType, ProfileMemory, parent)
{
// Announce additional features. The base class already announces the main feature.
announceFeatures(Constants::QML_JS_RANGE_FEATURES ^ (1 << ProfileCompiling));
// Register additional features. The base class already registers the main feature.
// Don't register initializer, finalizer, or clearer as the base class has done so already.
modelManager()->registerFeatures(Constants::QML_JS_RANGE_FEATURES ^ (1 << ProfileCompiling),
std::bind(&QmlProfilerTimelineModel::loadEvent, this,
std::placeholders::_1, std::placeholders::_2));
}
qint64 MemoryUsageModel::rowMaxValue(int rowNumber) const
@@ -246,6 +249,7 @@ void MemoryUsageModel::finalize()
computeNesting();
setExpandedRowCount(3);
setCollapsedRowCount(3);
QmlProfilerTimelineModel::finalize();
}
void MemoryUsageModel::clear()

View File

@@ -391,6 +391,7 @@ void PixmapCacheModel::finalize()
computeMaxCacheSize();
flattenLoads();
computeNesting();
QmlProfilerTimelineModel::finalize();
}
void PixmapCacheModel::clear()

View File

@@ -102,6 +102,7 @@ void QmlProfilerAnimationsModel::finalize()
computeNesting();
setExpandedRowCount((m_maxGuiThreadAnimations == 0 || m_maxRenderThreadAnimations == 0) ? 2 : 3);
setCollapsedRowCount(expandedRowCount());
QmlProfilerTimelineModel::finalize();
}
int QmlProfilerAnimationsModel::rowFromThreadId(int threadId) const

View File

@@ -30,9 +30,9 @@
#include "qmlprofilerdetailsrewriter.h"
#include <coreplugin/progressmanager/progressmanager.h>
#include <timeline/tracestashfile.h>
#include <utils/runextensions.h>
#include <utils/qtcassert.h>
#include <utils/temporaryfile.h>
#include <QDebug>
#include <QFile>
@@ -43,7 +43,6 @@
#include <functional>
namespace QmlProfiler {
namespace Internal {
static const char *ProfileFeatureNames[] = {
QT_TRANSLATE_NOOP("MainView", "JavaScript"),
@@ -62,65 +61,44 @@ static const char *ProfileFeatureNames[] = {
Q_STATIC_ASSERT(sizeof(ProfileFeatureNames) == sizeof(char *) * MaximumProfileFeature);
} // namespace Internal
using namespace Internal;
class QmlProfilerModelManager::QmlProfilerModelManagerPrivate
{
public:
QmlProfilerModelManagerPrivate() : file("qmlprofiler-data") {}
QmlProfilerNotesModel *notesModel = nullptr;
QmlProfilerTextMarkModel *textMarkModel = nullptr;
QmlProfilerModelManager::State state = Empty;
int numFinishedFinalizers = 0;
int numLoadedEvents = 0;
quint64 availableFeatures = 0;
quint64 visibleFeatures = 0;
quint64 recordedFeatures = 0;
bool aggregateTraces = false;
QHash<ProfileFeature, QVector<EventLoader> > eventLoaders;
QVector<Finalizer> finalizers;
Internal::QmlProfilerTextMarkModel *textMarkModel = nullptr;
QVector<QmlEventType> eventTypes;
QmlProfilerDetailsRewriter *detailsRewriter = nullptr;
Internal::QmlProfilerDetailsRewriter *detailsRewriter = nullptr;
Utils::TemporaryFile file;
QDataStream eventStream;
Timeline::TraceStashFile<QmlEvent> file;
qint64 traceStart = -1;
qint64 traceEnd = -1;
qint64 restrictedTraceStart = -1;
qint64 restrictedTraceEnd = -1;
void writeToStream(const QmlEvent &event);
void addEventType(const QmlEventType &eventType);
void handleError(const QString &message);
void dispatch(const QmlEvent &event, const QmlEventType &type);
void rewriteType(int typeIndex);
int resolveStackTop();
void updateTraceTime(qint64 time);
void restrictTraceTimeToRange(qint64 start, qint64 end);
};
QmlProfilerModelManager::QmlProfilerModelManager(QObject *parent) :
QObject(parent), d(new QmlProfilerModelManagerPrivate)
Timeline::TimelineTraceManager(parent), d(new QmlProfilerModelManagerPrivate)
{
d->notesModel = new QmlProfilerNotesModel(this);
d->textMarkModel = new QmlProfilerTextMarkModel(this);
setNotesModel(new QmlProfilerNotesModel(this));
d->textMarkModel = new Internal::QmlProfilerTextMarkModel(this);
d->detailsRewriter = new QmlProfilerDetailsRewriter(this);
connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::rewriteDetailsString,
this, &QmlProfilerModelManager::detailsChanged);
connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::eventDetailsChanged,
d->detailsRewriter = new Internal::QmlProfilerDetailsRewriter(this);
connect(d->detailsRewriter, &Internal::QmlProfilerDetailsRewriter::rewriteDetailsString,
this, &QmlProfilerModelManager::typeDetailsChanged);
connect(d->detailsRewriter, &Internal::QmlProfilerDetailsRewriter::eventDetailsChanged,
this, &QmlProfilerModelManager::typeDetailsFinished);
if (d->file.open())
d->eventStream.setDevice(&d->file);
else
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);
}
QmlProfilerModelManager::~QmlProfilerModelManager()
@@ -128,123 +106,36 @@ QmlProfilerModelManager::~QmlProfilerModelManager()
delete d;
}
qint64 QmlProfilerModelManager::traceStart() const
{
return d->restrictedTraceStart != -1 ? d->restrictedTraceStart : d->traceStart;
}
qint64 QmlProfilerModelManager::traceEnd() const
{
return d->restrictedTraceEnd != -1 ? d->restrictedTraceEnd : d->traceEnd;
}
qint64 QmlProfilerModelManager::traceDuration() const
{
return traceEnd() - traceStart();
}
void QmlProfilerModelManager::decreaseTraceStart(qint64 start)
{
QTC_ASSERT(start >= 0, return);
if (d->traceStart > start || d->traceStart == -1) {
d->traceStart = start;
if (d->traceEnd == -1)
d->traceEnd = d->traceStart;
else
QTC_ASSERT(d->traceEnd >= d->traceStart, d->traceEnd = d->traceStart);
}
}
void QmlProfilerModelManager::increaseTraceEnd(qint64 end)
{
QTC_ASSERT(end >= 0, return);
if (d->traceEnd < end || d->traceEnd == -1) {
d->traceEnd = end;
if (d->traceStart == -1)
d->traceStart = d->traceEnd;
else
QTC_ASSERT(d->traceEnd >= d->traceStart, d->traceStart = d->traceEnd);
}
}
QmlProfilerNotesModel *QmlProfilerModelManager::notesModel() const
{
return d->notesModel;
}
QmlProfilerTextMarkModel *QmlProfilerModelManager::textMarkModel() const
Internal::QmlProfilerTextMarkModel *QmlProfilerModelManager::textMarkModel() const
{
return d->textMarkModel;
}
bool QmlProfilerModelManager::isEmpty() const
void QmlProfilerModelManager::registerFeatures(quint64 features, QmlEventLoader eventLoader,
Initializer initializer, Finalizer finalizer,
Clearer clearer)
{
return d->file.pos() == 0;
}
const TraceEventLoader traceEventLoader = eventLoader ? [eventLoader](
const Timeline::TraceEvent &event, const Timeline::TraceEventType &type) {
return eventLoader(static_cast<const QmlEvent &>(event),
static_cast<const QmlEventType &>(type));
} : TraceEventLoader();
int QmlProfilerModelManager::numEvents() const
{
return d->numLoadedEvents;
}
int QmlProfilerModelManager::numEventTypes() const
{
return d->eventTypes.count();
}
int QmlProfilerModelManager::numFinishedFinalizers() const
{
return d->numFinishedFinalizers;
}
int QmlProfilerModelManager::numRegisteredFinalizers() const
{
return d->finalizers.count();
Timeline::TimelineTraceManager::registerFeatures(features, traceEventLoader, initializer,
finalizer, clearer);
}
void QmlProfilerModelManager::addEvents(const QVector<QmlEvent> &events)
{
for (const QmlEvent &event : events) {
d->eventStream << event;
d->updateTraceTime(event.timestamp());
d->dispatch(event, d->eventTypes[event.typeIndex()]);
}
}
void QmlProfilerModelManager::addEvent(const QmlEvent &event)
{
d->eventStream << event;
d->updateTraceTime(event.timestamp());
QTC_ASSERT(event.typeIndex() < d->eventTypes.size(),
d->eventTypes.resize(event.typeIndex() + 1));
d->dispatch(event, d->eventTypes.at(event.typeIndex()));
for (const QmlEvent &event : events)
addEvent(event);
}
void QmlProfilerModelManager::addEventTypes(const QVector<QmlEventType> &types)
{
const int firstTypeId = d->eventTypes.length();;
d->eventTypes.append(types);
for (int typeId = firstTypeId, end = d->eventTypes.length(); typeId < end; ++typeId) {
d->rewriteType(typeId);
const QmlEventLocation &location = d->eventTypes[typeId].location();
if (location.isValid()) {
d->textMarkModel->addTextMarkId(typeId, QmlEventLocation(
findLocalFile(location.filename()), location.line(),
location.column()));
}
}
}
void QmlProfilerModelManager::addEventType(const QmlEventType &type)
{
const int typeId = d->eventTypes.count();
d->eventTypes.append(type);
d->rewriteType(typeId);
const QmlEventLocation &location = type.location();
if (location.isValid()) {
d->textMarkModel->addTextMarkId(
typeId, QmlEventLocation(findLocalFile(location.filename()),
location.line(), location.column()));
for (const QmlEventType &type : types) {
d->addEventType(type);
TimelineTraceManager::addEventType(type);
}
}
@@ -253,6 +144,15 @@ const QmlEventType &QmlProfilerModelManager::eventType(int typeId) const
return d->eventTypes.at(typeId);
}
void QmlProfilerModelManager::replayEvents(qint64 rangeStart, qint64 rangeEnd,
TraceEventLoader loader, Initializer initializer,
Finalizer finalizer, ErrorHandler errorHandler,
QFutureInterface<void> &future) const
{
replayEvents(rangeStart, rangeEnd, static_cast<QmlEventLoader>(loader), initializer, finalizer,
errorHandler, future);
}
static bool isStateful(const QmlEventType &type)
{
// Events of these types carry state that has to be taken into account when adding later events:
@@ -262,40 +162,46 @@ static bool isStateful(const QmlEventType &type)
return message == PixmapCacheEvent || message == MemoryAllocation;
}
bool QmlProfilerModelManager::replayEvents(qint64 rangeStart, qint64 rangeEnd,
EventLoader loader) const
void QmlProfilerModelManager::replayEvents(qint64 rangeStart, qint64 rangeEnd,
QmlEventLoader loader, Initializer initializer,
Finalizer finalizer, ErrorHandler errorHandler,
QFutureInterface<void> &future) const
{
if (initializer)
initializer();
QStack<QmlEvent> stack;
QmlEvent event;
QFile file(d->file.fileName());
if (!file.open(QIODevice::ReadOnly))
bool crossedRangeStart = false;
const auto result = d->file.replay([&](const QmlEvent &event) {
if (future.isCanceled())
return false;
QDataStream stream(&file);
bool crossedRangeStart = false;
while (!stream.atEnd()) {
stream >> event;
if (stream.status() == QDataStream::ReadPastEnd)
break;
const QmlEventType &type = d->eventTypes[event.typeIndex()];
if (rangeStart != -1 && rangeEnd != -1) {
// No restrictions: load all events
if (rangeStart == -1 || rangeEnd == -1) {
loader(event, type);
return true;
}
// Double-check if rangeStart has been crossed. Some versions of Qt send dirty data.
qint64 adjustedTimestamp = event.timestamp();
if (event.timestamp() < rangeStart && !crossedRangeStart) {
if (type.rangeType() != MaximumRangeType) {
if (event.rangeStage() == RangeStart)
stack.push(event);
else if (event.rangeStage() == RangeEnd)
stack.pop();
continue;
return true;
} else if (isStateful(type)) {
event.setTimestamp(rangeStart);
adjustedTimestamp = rangeStart;
} else {
continue;
return true;
}
} else {
if (!crossedRangeStart) {
foreach (QmlEvent stashed, stack) {
for (QmlEvent stashed : stack) {
stashed.setTimestamp(rangeStart);
loader(stashed, d->eventTypes[stashed.typeIndex()]);
}
@@ -315,29 +221,43 @@ bool QmlProfilerModelManager::replayEvents(qint64 rangeStart, qint64 rangeEnd,
} else if (event.rangeStage() == RangeStart) {
stack.push(event);
}
continue;
return true;
} else if (isStateful(type)) {
event.setTimestamp(rangeEnd);
adjustedTimestamp = rangeEnd;
} else {
continue;
}
return true;
}
}
}
if (adjustedTimestamp != event.timestamp()) {
QmlEvent adjusted(event);
adjusted.setTimestamp(adjustedTimestamp);
loader(adjusted, type);
} else {
loader(event, type);
}
return true;
}
});
void QmlProfilerModelManager::QmlProfilerModelManagerPrivate::dispatch(const QmlEvent &event,
const QmlEventType &type)
{
for (const EventLoader &loader : eventLoaders.value(
static_cast<ProfileFeature>(type.feature()))) {
loader(event, type);
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;
}
++numLoadedEvents;
}
static QString getDisplayName(const QmlEventType &event)
@@ -374,6 +294,30 @@ static QString getInitialDetails(const QmlEventType &event)
return details;
}
void QmlProfilerModelManager::QmlProfilerModelManagerPrivate::writeToStream(const QmlEvent &event)
{
file.append(event);
}
void QmlProfilerModelManager::QmlProfilerModelManagerPrivate::addEventType(const QmlEventType &type)
{
const int typeId = eventTypes.count();
eventTypes.append(type);
rewriteType(typeId);
const QmlEventLocation &location = type.location();
if (location.isValid()) {
textMarkModel->addTextMarkId(typeId, QmlEventLocation(
detailsRewriter->getLocalFile(location.filename()),
location.line(), location.column()));
}
}
void QmlProfilerModelManager::QmlProfilerModelManagerPrivate::handleError(const QString &message)
{
// What to do here?
qWarning() << message;
}
void QmlProfilerModelManager::QmlProfilerModelManagerPrivate::rewriteType(int typeIndex)
{
QmlEventType &type = eventTypes[typeIndex];
@@ -390,85 +334,6 @@ void QmlProfilerModelManager::QmlProfilerModelManagerPrivate::rewriteType(int ty
detailsRewriter->requestDetailsForLocation(typeIndex, location);
}
void QmlProfilerModelManager::QmlProfilerModelManagerPrivate::updateTraceTime(qint64 time)
{
QTC_ASSERT(time >= 0, return);
if (traceStart > time || traceStart == -1)
traceStart = time;
if (traceEnd < time || traceEnd == -1)
traceEnd = time;
QTC_ASSERT(traceEnd >= traceStart, traceStart = traceEnd);
}
void QmlProfilerModelManager::QmlProfilerModelManagerPrivate::restrictTraceTimeToRange(qint64 start, qint64 end)
{
QTC_ASSERT(end == -1 || start <= end, end = start);
restrictedTraceStart = start;
restrictedTraceEnd = end;
}
void QmlProfilerModelManager::announceFeatures(quint64 features, EventLoader eventLoader,
Finalizer finalizer)
{
if ((features & d->availableFeatures) != features) {
d->availableFeatures |= features;
emit availableFeaturesChanged(d->availableFeatures);
}
if ((features & d->visibleFeatures) != features) {
d->visibleFeatures |= features;
emit visibleFeaturesChanged(d->visibleFeatures);
}
for (int feature = 0; feature != MaximumProfileFeature; ++feature) {
if (features & (1ULL << feature))
d->eventLoaders[static_cast<ProfileFeature>(feature)].append(eventLoader);
}
d->finalizers.append(finalizer);
}
quint64 QmlProfilerModelManager::availableFeatures() const
{
return d->availableFeatures;
}
quint64 QmlProfilerModelManager::visibleFeatures() const
{
return d->visibleFeatures;
}
void QmlProfilerModelManager::setVisibleFeatures(quint64 features)
{
if (d->visibleFeatures != features) {
d->visibleFeatures = features;
emit visibleFeaturesChanged(d->visibleFeatures);
}
}
quint64 QmlProfilerModelManager::recordedFeatures() const
{
return d->recordedFeatures;
}
void QmlProfilerModelManager::setRecordedFeatures(quint64 features)
{
if (d->recordedFeatures != features) {
d->recordedFeatures = features;
emit recordedFeaturesChanged(d->recordedFeatures);
}
}
bool QmlProfilerModelManager::aggregateTraces() const
{
return d->aggregateTraces;
}
void QmlProfilerModelManager::setAggregateTraces(bool aggregateTraces)
{
d->aggregateTraces = aggregateTraces;
}
const char *QmlProfilerModelManager::featureName(ProfileFeature feature)
{
return ProfileFeatureNames[feature];
@@ -477,18 +342,14 @@ const char *QmlProfilerModelManager::featureName(ProfileFeature feature)
void QmlProfilerModelManager::finalize()
{
QTC_ASSERT(state() == AcquiringData, /**/);
d->file.flush();
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 ...
// which happens on stateChanged(Done).
foreach (const Finalizer &finalizer, d->finalizers) {
finalizer();
++d->numFinishedFinalizers;
}
setState(Done);
TimelineTraceManager::finalize();
}
void QmlProfilerModelManager::populateFileFinder(const ProjectExplorer::Target *target)
@@ -501,146 +362,6 @@ QString QmlProfilerModelManager::findLocalFile(const QString &remoteFile)
return d->detailsRewriter->getLocalFile(remoteFile);
}
void QmlProfilerModelManager::save(const QString &filename)
{
QFile *file = new QFile(filename);
if (!file->open(QIODevice::WriteOnly)) {
emit error(tr("Could not open %1 for writing.").arg(filename));
delete file;
emit saveFinished();
return;
}
d->notesModel->stash();
QmlProfilerFileWriter *writer = new QmlProfilerFileWriter(this);
writer->setTraceTime(traceStart(), traceEnd(), traceDuration());
writer->setData(this);
writer->setNotes(d->notesModel->notes());
connect(writer, &QObject::destroyed, this, &QmlProfilerModelManager::saveFinished,
Qt::QueuedConnection);
connect(writer, &QmlProfilerFileWriter::error, this, [this, file](const QString &message) {
file->close();
file->remove();
delete file;
emit error(message);
}, Qt::QueuedConnection);
connect(writer, &QmlProfilerFileWriter::success, this, [file]() {
file->close();
delete file;
}, Qt::QueuedConnection);
connect(writer, &QmlProfilerFileWriter::canceled, this, [file]() {
file->close();
file->remove();
delete file;
}, Qt::QueuedConnection);
QFuture<void> result = Utils::runAsync([file, writer] (QFutureInterface<void> &future) {
writer->setFuture(&future);
if (file->fileName().endsWith(QLatin1String(Constants::QtdFileExtension)))
writer->saveQtd(file);
else
writer->saveQzt(file);
writer->deleteLater();
});
Core::ProgressManager::addTask(result, tr("Saving Trace Data"), Constants::TASK_SAVE,
Core::ProgressManager::ShowInApplicationIcon);
}
void QmlProfilerModelManager::load(const QString &filename)
{
bool isQtd = filename.endsWith(QLatin1String(Constants::QtdFileExtension));
QFile *file = new QFile(filename, this);
if (!file->open(isQtd ? (QIODevice::ReadOnly | QIODevice::Text) : QIODevice::ReadOnly)) {
emit error(tr("Could not open %1 for reading.").arg(filename));
delete file;
emit loadFinished();
return;
}
clear();
setState(AcquiringData);
QmlProfilerFileReader *reader = new QmlProfilerFileReader(this);
connect(reader, &QObject::destroyed, this, &QmlProfilerModelManager::loadFinished,
Qt::QueuedConnection);
connect(reader, &QmlProfilerFileReader::typesLoaded,
this, &QmlProfilerModelManager::addEventTypes);
connect(reader, &QmlProfilerFileReader::notesLoaded,
d->notesModel, &QmlProfilerNotesModel::setNotes);
connect(reader, &QmlProfilerFileReader::qmlEventsLoaded,
this, &QmlProfilerModelManager::addEvents);
connect(reader, &QmlProfilerFileReader::success, this, [this, reader]() {
if (reader->traceStart() >= 0)
decreaseTraceStart(reader->traceStart());
if (reader->traceEnd() >= 0)
increaseTraceEnd(reader->traceEnd());
setRecordedFeatures(reader->loadedFeatures());
delete reader;
finalize();
}, Qt::QueuedConnection);
connect(reader, &QmlProfilerFileReader::error, this, [this, reader](const QString &message) {
clear();
delete reader;
emit error(message);
}, Qt::QueuedConnection);
connect(reader, &QmlProfilerFileReader::canceled, this, [this, reader]() {
clear();
delete reader;
}, Qt::QueuedConnection);
QFuture<void> result = Utils::runAsync([isQtd, file, reader] (QFutureInterface<void> &future) {
reader->setFuture(&future);
if (isQtd)
reader->loadQtd(file);
else
reader->loadQzt(file);
file->close();
file->deleteLater();
});
Core::ProgressManager::addTask(result, tr("Loading Trace Data"), Constants::TASK_LOAD);
}
void QmlProfilerModelManager::setState(QmlProfilerModelManager::State state)
{
// It's not an error, we are continuously calling "AcquiringData" for example
if (d->state == state)
return;
switch (state) {
case ClearingData:
QTC_ASSERT(d->state == Done || d->state == Empty || d->state == AcquiringData, /**/);
break;
case Empty:
// if it's not empty, complain but go on
QTC_ASSERT(isEmpty(), /**/);
break;
case AcquiringData:
break;
case Done:
QTC_ASSERT(d->state == AcquiringData || d->state == Empty, return);
break;
default:
emit error(tr("Trying to set unknown state in events list."));
break;
}
d->state = state;
emit stateChanged();
}
void QmlProfilerModelManager::detailsChanged(int typeId, const QString &newString)
{
QTC_ASSERT(typeId < d->eventTypes.count(), return);
@@ -648,76 +369,40 @@ void QmlProfilerModelManager::detailsChanged(int typeId, const QString &newStrin
emit typeDetailsChanged(typeId);
}
QmlProfilerModelManager::State QmlProfilerModelManager::state() const
const Timeline::TraceEventType &QmlProfilerModelManager::lookupType(int typeIndex) const
{
return d->state;
return eventType(typeIndex);
}
void QmlProfilerModelManager::doClearEvents()
void QmlProfilerModelManager::clearEventStorage()
{
d->numLoadedEvents = 0;
d->numFinishedFinalizers = 0;
d->file.remove();
d->eventStream.unsetDevice();
if (d->file.open())
d->eventStream.setDevice(&d->file);
else
emit error(tr("Cannot open temporary trace file to store events."));
d->restrictTraceTimeToRange(-1, -1);
d->traceStart = -1;
d->traceEnd = -1;
d->notesModel->clear();
setVisibleFeatures(0);
setRecordedFeatures(0);
TimelineTraceManager::clearEventStorage();
d->file.clear();
if (!d->file.open())
emit error(tr("Failed to reset temporary trace file"));
}
void QmlProfilerModelManager::clearEvents()
void QmlProfilerModelManager::clearTypeStorage()
{
setState(ClearingData);
doClearEvents();
setState(Empty);
}
void QmlProfilerModelManager::clear()
{
setState(ClearingData);
doClearEvents();
TimelineTraceManager::clearTypeStorage();
d->eventTypes.clear();
d->detailsRewriter->clear();
setState(Empty);
}
void QmlProfilerModelManager::restrictToRange(qint64 startTime, qint64 endTime)
void QmlProfilerModelManager::addEventType(const QmlEventType &type)
{
d->notesModel->stash();
const QVector<QmlNote> notes = d->notesModel->notes();
d->notesModel->clear();
setState(ClearingData);
setVisibleFeatures(0);
startAcquiring();
if (!replayEvents(startTime, endTime,
std::bind(&QmlProfilerModelManagerPrivate::dispatch, d, std::placeholders::_1,
std::placeholders::_2))) {
emit error(tr("Could not re-read events from temporary trace file. "
"The trace data is lost."));
clear();
} else {
d->notesModel->setNotes(notes);
d->restrictTraceTimeToRange(startTime, endTime);
finalize();
}
d->addEventType(type);
TimelineTraceManager::addEventType(type);
}
bool QmlProfilerModelManager::isRestrictedToRange() const
void QmlProfilerModelManager::addEvent(const QmlEvent &event)
{
return d->restrictedTraceStart != -1 || d->restrictedTraceEnd != -1;
d->writeToStream(event);
TimelineTraceManager::addEvent(event);
}
void QmlProfilerModelManager::startAcquiring()
Timeline::TimelineTraceFile *QmlProfilerModelManager::createTraceFile()
{
setState(AcquiringData);
return new Internal::QmlProfilerTraceFile(this);
}
} // namespace QmlProfiler

View File

@@ -33,6 +33,7 @@
#include "qmlprofilertextmark.h"
#include <utils/fileinprojectfinder.h>
#include <timeline/timelinetracemanager.h>
#include <QObject>
#include <functional>
@@ -44,94 +45,54 @@ class QmlProfilerModelManager;
class QmlProfilerNotesModel;
// Interface between the Data Model and the Engine/Tool
class QMLPROFILER_EXPORT QmlProfilerModelManager : public QObject
class QMLPROFILER_EXPORT QmlProfilerModelManager : public Timeline::TimelineTraceManager
{
Q_OBJECT
public:
enum State {
Empty,
AcquiringData,
ClearingData,
Done
};
typedef std::function<void(const QmlEvent &, const QmlEventType &)> EventLoader;
typedef std::function<void()> Finalizer;
typedef std::function<void(const QmlEvent &, const QmlEventType &)> QmlEventLoader;
explicit QmlProfilerModelManager(QObject *parent = nullptr);
~QmlProfilerModelManager() override;
State state() const;
qint64 traceStart() const;
qint64 traceEnd() const;
qint64 traceDuration() const;
void decreaseTraceStart(qint64 start);
void increaseTraceEnd(qint64 end);
QmlProfilerNotesModel *notesModel() const;
Internal::QmlProfilerTextMarkModel *textMarkModel() const;
bool isEmpty() const;
int numEvents() const;
int numEventTypes() const;
void announceFeatures(quint64 features, EventLoader eventLoader, Finalizer finalizer);
int numFinishedFinalizers() const;
int numRegisteredFinalizers() const;
void registerFeatures(quint64 features, QmlEventLoader eventLoader,
Initializer initializer = nullptr, Finalizer finalizer = nullptr,
Clearer clearer = nullptr);
void addEvents(const QVector<QmlEvent> &events);
void addEvent(const QmlEvent &event);
void addEventTypes(const QVector<QmlEventType> &types);
void addEventType(const QmlEventType &type);
const QmlEventType &eventType(int typeId) const;
bool replayEvents(qint64 rangeStart, qint64 rangeEnd, EventLoader loader) const;
void replayEvents(qint64 rangeStart, qint64 rangeEnd, QmlEventLoader loader,
Initializer initializer, Finalizer finalizer,
ErrorHandler errorHandler, QFutureInterface<void> &future) const;
quint64 availableFeatures() const;
quint64 visibleFeatures() const;
void setVisibleFeatures(quint64 features);
quint64 recordedFeatures() const;
void setRecordedFeatures(quint64 features);
bool aggregateTraces() const;
void setAggregateTraces(bool aggregateTraces);
void finalize();
void finalize() override;
void populateFileFinder(const ProjectExplorer::Target *target = nullptr);
QString findLocalFile(const QString &remoteFile);
static const char *featureName(ProfileFeature feature);
void clearEvents();
void clear();
void restrictToRange(qint64 startTime, qint64 endTime);
bool isRestrictedToRange() const;
void startAcquiring();
void save(const QString &filename);
void load(const QString &filename);
void addEventType(const QmlEventType &type);
void addEvent(const QmlEvent &event);
signals:
void error(const QString &error);
void stateChanged();
void loadFinished();
void saveFinished();
void availableFeaturesChanged(quint64 features);
void visibleFeaturesChanged(quint64 features);
void recordedFeaturesChanged(quint64 features);
void typeDetailsChanged(int typeId);
void typeDetailsFinished();
private:
void setState(State state);
void detailsChanged(int typeId, const QString &newString);
void doClearEvents();
void clearEventStorage() override;
void clearTypeStorage() override;
const Timeline::TraceEventType &lookupType(int typeId) const override;
Timeline::TimelineTraceFile *createTraceFile() override;
void replayEvents(qint64 rangeStart, qint64 rangeEnd, TraceEventLoader loader,
Initializer initializer, Finalizer finalizer,
ErrorHandler errorHandler, QFutureInterface<void> &future) const override;
class QmlProfilerModelManagerPrivate;
QmlProfilerModelManagerPrivate *d;

View File

@@ -132,6 +132,11 @@ void QmlProfilerNotesModel::setNotes(const QVector<QmlNote> &notes)
m_notes = notes;
}
void QmlProfilerNotesModel::addNote(const QmlNote &note)
{
m_notes.append(note);
}
void QmlProfilerNotesModel::clear()
{
TimelineNotesModel::clear();

View File

@@ -42,6 +42,7 @@ public:
const QVector<QmlNote> &notes() const;
void setNotes(const QVector<QmlNote> &notes);
void addNote(const QmlNote &note);
void clear() override;
protected:

View File

@@ -103,6 +103,8 @@ void QmlProfilerRangeModel::finalize()
if (supportsBindingLoops())
findBindingLoops();
QmlProfilerTimelineModel::finalize();
}
void QmlProfilerRangeModel::computeNestingContracted()

View File

@@ -66,19 +66,17 @@ double QmlProfilerStatisticsModel::durationSelfPercent(int typeId) const
QmlProfilerStatisticsModel::QmlProfilerStatisticsModel(QmlProfilerModelManager *modelManager)
: m_modelManager(modelManager)
{
connect(modelManager, &QmlProfilerModelManager::stateChanged,
this, &QmlProfilerStatisticsModel::modelManagerStateChanged);
connect(modelManager->notesModel(), &Timeline::TimelineNotesModel::changed,
this, &QmlProfilerStatisticsModel::notesChanged);
m_acceptedTypes << Compiling << Creating << Binding << HandlingSignal << Javascript;
modelManager->announceFeatures(Constants::QML_JS_RANGE_FEATURES,
[this](const QmlEvent &event, const QmlEventType &type) {
loadEvent(event, type);
}, [this]() {
finalize();
});
modelManager->registerFeatures(Constants::QML_JS_RANGE_FEATURES,
std::bind(&QmlProfilerStatisticsModel::loadEvent, this,
std::placeholders::_1, std::placeholders::_2),
std::bind(&QmlProfilerStatisticsModel::beginResetModel, this),
std::bind(&QmlProfilerStatisticsModel::finalize, this),
std::bind(&QmlProfilerStatisticsModel::clear, this));
}
void QmlProfilerStatisticsModel::restrictToFeatures(quint64 features)
@@ -102,18 +100,20 @@ void QmlProfilerStatisticsModel::restrictToFeatures(quint64 features)
return;
clear();
beginResetModel();
if (!m_modelManager->replayEvents(m_modelManager->traceStart(), m_modelManager->traceEnd(),
std::bind(&QmlProfilerStatisticsModel::loadEvent,
this, std::placeholders::_1,
std::placeholders::_2))) {
endResetModel();
emit m_modelManager->error(tr("Could not re-read events from temporary trace file."));
clear();
} else {
QFutureInterface<void> future;
m_modelManager->replayEvents(m_modelManager->traceStart(), m_modelManager->traceEnd(),
std::bind(&QmlProfilerStatisticsModel::loadEvent, this,
std::placeholders::_1, std::placeholders::_2),
std::bind(&QmlProfilerStatisticsModel::beginResetModel, this),
[this]() {
finalize();
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));
clear();
}, future);
}
bool QmlProfilerStatisticsModel::isRestrictedToRange() const
@@ -381,20 +381,6 @@ QVariant QmlProfilerStatisticsModel::headerData(int section, Qt::Orientation ori
}
}
void QmlProfilerStatisticsModel::modelManagerStateChanged()
{
switch (m_modelManager->state()) {
case QmlProfilerModelManager::ClearingData:
clear();
break;
case QmlProfilerModelManager::AcquiringData:
beginResetModel();
break;
default:
break;
}
}
void QmlProfilerStatisticsModel::typeDetailsChanged(int typeIndex)
{
const QModelIndex index = createIndex(typeIndex, MainDetails);
@@ -404,7 +390,7 @@ void QmlProfilerStatisticsModel::typeDetailsChanged(int typeIndex)
void QmlProfilerStatisticsModel::notesChanged(int typeIndex)
{
static const QVector<int> noteRoles({Qt::ToolTipRole, Qt::TextColorRole});
const QmlProfilerNotesModel *notesModel = m_modelManager->notesModel();
const Timeline::TimelineNotesModel *notesModel = m_modelManager->notesModel();
if (typeIndex == s_invalidTypeId) {
m_notes.clear();
for (int noteId = 0; noteId < notesModel->count(); ++noteId) {

View File

@@ -152,7 +152,6 @@ private:
void loadEvent(const QmlEvent &event, const QmlEventType &type);
void finalize();
void modelManagerStateChanged();
void typeDetailsChanged(int typeIndex);
void notesChanged(int typeIndex);

View File

@@ -35,15 +35,19 @@ QmlProfilerTimelineModel::QmlProfilerTimelineModel(QmlProfilerModelManager *mode
m_modelManager(modelManager)
{
setDisplayName(tr(QmlProfilerModelManager::featureName(mainFeature)));
connect(modelManager, &QmlProfilerModelManager::stateChanged,
this, &QmlProfilerTimelineModel::dataChanged);
connect(modelManager, &QmlProfilerModelManager::typeDetailsFinished,
this, &Timeline::TimelineModel::labelsChanged);
connect(modelManager, &QmlProfilerModelManager::typeDetailsFinished,
this, &Timeline::TimelineModel::detailsChanged);
connect(modelManager, &QmlProfilerModelManager::visibleFeaturesChanged,
this, &QmlProfilerTimelineModel::onVisibleFeaturesChanged);
announceFeatures(1ULL << m_mainFeature);
m_modelManager->registerFeatures(1ULL << m_mainFeature,
std::bind(&QmlProfilerTimelineModel::loadEvent, this,
std::placeholders::_1, std::placeholders::_2),
std::bind(&QmlProfilerTimelineModel::initialize, this),
std::bind(&QmlProfilerTimelineModel::finalize, this),
std::bind(&QmlProfilerTimelineModel::clear, this));
}
RangeType QmlProfilerTimelineModel::rangeType() const
@@ -79,31 +83,6 @@ QmlProfilerModelManager *QmlProfilerTimelineModel::modelManager() const
return m_modelManager;
}
void QmlProfilerTimelineModel::announceFeatures(quint64 features)
{
m_modelManager->announceFeatures(
features, [this](const QmlEvent &event, const QmlEventType &type) {
loadEvent(event, type);
}, [this]() {
finalize();
});
}
void QmlProfilerTimelineModel::dataChanged()
{
switch (m_modelManager->state()) {
case QmlProfilerModelManager::Done:
emit contentChanged();
break;
case QmlProfilerModelManager::ClearingData:
clear();
break;
default:
emit contentChanged();
break;
}
}
void QmlProfilerTimelineModel::onVisibleFeaturesChanged(quint64 features)
{
setHidden(!(features & (1ULL << m_mainFeature)));
@@ -129,4 +108,13 @@ QVariantMap QmlProfilerTimelineModel::locationFromTypeId(int index) const
return result;
}
void QmlProfilerTimelineModel::initialize()
{
}
void QmlProfilerTimelineModel::finalize()
{
emit contentChanged();
}
} // namespace QmlProfiler

View File

@@ -55,13 +55,10 @@ public:
QVariantMap locationFromTypeId(int index) const;
virtual void loadEvent(const QmlEvent &event, const QmlEventType &type) = 0;
virtual void finalize() = 0;
protected:
void announceFeatures(quint64 features);
virtual void initialize();
virtual void finalize();
private:
void dataChanged();
void onVisibleFeaturesChanged(quint64 features);
const Message m_message;

View File

@@ -65,6 +65,7 @@
#include <coreplugin/messagemanager.h>
#include <coreplugin/helpmanager.h>
#include <coreplugin/modemanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/imode.h>
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/actionmanager/actionmanager.h>
@@ -505,14 +506,14 @@ void QmlProfilerTool::showTimeLineSearch()
void QmlProfilerTool::clearEvents()
{
d->m_profilerModelManager->clearEvents();
d->m_profilerModelManager->clear();
d->m_profilerConnections->clearEvents();
setRecordedFeatures(0);
}
void QmlProfilerTool::clearData()
{
d->m_profilerModelManager->clear();
d->m_profilerModelManager->clearAll();
d->m_profilerConnections->clearBufferedData();
setRecordedFeatures(0);
}
@@ -666,7 +667,9 @@ void QmlProfilerTool::showSaveDialog()
filename += zFile;
saveLastTraceFile(filename);
Debugger::enableMainWindow(false);
d->m_profilerModelManager->save(filename);
Core::ProgressManager::addTask(d->m_profilerModelManager->save(filename),
tr("Saving Trace Data"), TASK_SAVE,
Core::ProgressManager::ShowInApplicationIcon);
}
}
@@ -690,7 +693,8 @@ void QmlProfilerTool::showLoadDialog()
connect(d->m_profilerModelManager, &QmlProfilerModelManager::recordedFeaturesChanged,
this, &QmlProfilerTool::setRecordedFeatures);
d->m_profilerModelManager->populateFileFinder();
d->m_profilerModelManager->load(filename);
Core::ProgressManager::addTask(d->m_profilerModelManager->load(filename),
tr("Loading Trace Data"), TASK_LOAD);
}
}
@@ -740,7 +744,7 @@ void QmlProfilerTool::clientsDisconnected()
d->m_profilerState->currentState() == QmlProfilerStateManager::Idle) {
showNonmodalWarning(tr("Application finished before loading profiled data.\n"
"Please use the stop button instead."));
d->m_profilerModelManager->clear();
d->m_profilerModelManager->clearAll();
}
}
}
@@ -912,7 +916,7 @@ void QmlProfilerTool::serverRecordingChanged()
if (!d->m_profilerModelManager->aggregateTraces() ||
d->m_profilerModelManager->state() == QmlProfilerModelManager::Done)
clearEvents();
d->m_profilerModelManager->startAcquiring();
d->m_profilerModelManager->initialize();
} else {
d->m_recordingTimer.stop();
if (!d->m_profilerModelManager->aggregateTraces())

View File

@@ -24,6 +24,8 @@
****************************************************************************/
#include "qmlprofilertracefile.h"
#include "qmlprofilernotesmodel.h"
#include "qmlprofilerconstants.h"
#include <utils/qtcassert.h>
@@ -114,13 +116,7 @@ static QString qmlTypeAsString(Message message, RangeType rangeType)
return QString::number((int)rangeType);
}
QmlProfilerFileReader::QmlProfilerFileReader(QObject *parent) :
QObject(parent),
m_traceStart(-1),
m_traceEnd(-1),
m_future(0),
m_loadedFeatures(0)
QmlProfilerTraceFile::QmlProfilerTraceFile(QObject *parent) : Timeline::TimelineTraceFile(parent)
{
static int meta[] = {
qRegisterMetaType<QVector<QmlEvent> >(),
@@ -130,16 +126,25 @@ QmlProfilerFileReader::QmlProfilerFileReader(QObject *parent) :
Q_UNUSED(meta);
}
void QmlProfilerFileReader::setFuture(QFutureInterface<void> *future)
void QmlProfilerTraceFile::load(QIODevice *device)
{
m_future = future;
if (m_future) {
m_future->setProgressRange(0, 1000);
m_future->setProgressValue(0);
}
const QFile *file = qobject_cast<QFile *>(device);
if (file && file->fileName().endsWith(Constants::QtdFileExtension))
loadQtd(device);
else
loadQzt(device);
}
void QmlProfilerFileReader::loadQtd(QIODevice *device)
void QmlProfilerTraceFile::save(QIODevice *device)
{
const QFile *file = qobject_cast<QFile *>(device);
if (file && file->fileName().endsWith(Constants::QtdFileExtension))
saveQtd(device);
else
saveQzt(device);
}
void QmlProfilerTraceFile::loadQtd(QIODevice *device)
{
QXmlStreamReader stream(device);
@@ -158,14 +163,13 @@ void QmlProfilerFileReader::loadQtd(QIODevice *device)
else
validVersion = false;
if (attributes.hasAttribute(_("traceStart")))
m_traceStart = attributes.value(_("traceStart")).toLongLong();
setTraceStart(attributes.value(_("traceStart")).toLongLong());
if (attributes.hasAttribute(_("traceEnd")))
m_traceEnd = attributes.value(_("traceEnd")).toLongLong();
setTraceEnd(attributes.value(_("traceEnd")).toLongLong());
}
if (elementName == _("eventData")) {
loadEventTypes(stream);
emit typesLoaded(m_eventTypes);
break;
}
@@ -176,7 +180,6 @@ void QmlProfilerFileReader::loadQtd(QIODevice *device)
if (elementName == _("noteData")) {
loadNotes(stream);
emit notesLoaded(m_notes);
break;
}
@@ -194,7 +197,7 @@ void QmlProfilerFileReader::loadQtd(QIODevice *device)
emit success();
}
void QmlProfilerFileReader::loadQzt(QIODevice *device)
void QmlProfilerTraceFile::loadQzt(QIODevice *device)
{
QDataStream stream(device);
stream.setVersion(QDataStream::Qt_5_5);
@@ -215,44 +218,48 @@ void QmlProfilerFileReader::loadQzt(QIODevice *device)
}
stream.setVersion(dataStreamVersion);
stream >> m_traceStart >> m_traceEnd;
qint64 traceStart, traceEnd;
stream >> traceStart >> traceEnd;
setTraceStart(traceStart);
setTraceEnd(traceEnd);
QBuffer buffer;
QDataStream bufferStream(&buffer);
bufferStream.setVersion(dataStreamVersion);
QByteArray data;
updateProgress(device);
setDeviceProgress(device);
if (!isCanceled()) {
stream >> data;
buffer.setData(qUncompress(data));
buffer.open(QIODevice::ReadOnly);
QVector<QmlEventType> eventTypes;
quint32 numEventTypes;
bufferStream >> numEventTypes;
if (numEventTypes > std::numeric_limits<int>::max()) {
emit error(tr("Excessive number of event types: %1").arg(numEventTypes));
return;
}
QTC_ASSERT(m_eventTypes.isEmpty(), m_eventTypes.clear());
m_eventTypes.reserve(static_cast<int>(numEventTypes));
eventTypes.reserve(static_cast<int>(numEventTypes));
QmlEventType type;
for (int typeId = 0; typeId < static_cast<int>(numEventTypes); ++typeId) {
bufferStream >> type;
m_eventTypes.append(type);
eventTypes.append(type);
}
buffer.close();
emit typesLoaded(m_eventTypes);
updateProgress(device);
modelManager()->addEventTypes(eventTypes);
setDeviceProgress(device);
}
if (!isCanceled()) {
stream >> data;
buffer.setData(qUncompress(data));
buffer.open(QIODevice::ReadOnly);
bufferStream >> m_notes;
QVector<QmlNote> notes;
bufferStream >> notes;
buffer.close();
emit notesLoaded(m_notes);
updateProgress(device);
qmlNotes()->setNotes(notes);
setDeviceProgress(device);
}
QVector<QmlEvent> eventBuffer;
@@ -264,11 +271,11 @@ void QmlProfilerFileReader::loadQzt(QIODevice *device)
QmlEvent event;
bufferStream >> event;
if (bufferStream.status() == QDataStream::Ok) {
if (event.typeIndex() >= m_eventTypes.length()) {
if (event.typeIndex() >= traceManager()->numEventTypes()) {
emit error(tr("Invalid type index %1").arg(event.typeIndex()));
return;
}
m_loadedFeatures |= (1ULL << m_eventTypes[event.typeIndex()].feature());
addFeature(modelManager()->eventType(event.typeIndex()).feature());
if (event.timestamp() < 0)
event.setTimestamp(0);
} else if (bufferStream.status() == QDataStream::ReadPastEnd) {
@@ -281,28 +288,35 @@ void QmlProfilerFileReader::loadQzt(QIODevice *device)
}
eventBuffer.append(event);
}
emit qmlEventsLoaded(eventBuffer);
modelManager()->addEvents(eventBuffer);
eventBuffer.clear();
buffer.close();
updateProgress(device);
setDeviceProgress(device);
}
if (isCanceled()) {
emit canceled();
} else {
emit qmlEventsLoaded(eventBuffer);
modelManager()->addEvents(eventBuffer);
emit success();
}
}
quint64 QmlProfilerFileReader::loadedFeatures() const
void QmlProfilerTraceFile::addEventsProgress(qint64 timestamp)
{
return m_loadedFeatures;
addProgressValue(static_cast<float>(timestamp) / static_cast<float>(traceEnd() - traceStart())
* ProgressEvents);
}
void QmlProfilerFileReader::loadEventTypes(QXmlStreamReader &stream)
void QmlProfilerTraceFile::addStageProgress(QmlProfilerTraceFile::ProgressValues stage)
{
addProgressValue(stage);
}
void QmlProfilerTraceFile::loadEventTypes(QXmlStreamReader &stream)
{
QTC_ASSERT(stream.name() == _("eventData"), return);
QVector<QmlEventType> eventTypes;
int typeIndex = -1;
@@ -330,7 +344,7 @@ void QmlProfilerFileReader::loadEventTypes(QXmlStreamReader &stream)
switch (token) {
case QXmlStreamReader::StartElement: {
if (elementName == _("event")) {
updateProgress(stream.device());
setDeviceProgress(stream.device());
clearType();
const QXmlStreamAttributes attributes = stream.attributes();
@@ -407,20 +421,21 @@ void QmlProfilerFileReader::loadEventTypes(QXmlStreamReader &stream)
case QXmlStreamReader::EndElement: {
if (elementName == _("event")) {
if (typeIndex >= 0) {
if (typeIndex >= m_eventTypes.size())
m_eventTypes.resize(typeIndex + 1);
if (typeIndex >= eventTypes.length())
eventTypes.resize(typeIndex + 1);
QmlEventType type(messageAndRange.first, messageAndRange.second, detailType,
QmlEventLocation(filename, line, column), data, displayName);
m_eventTypes[typeIndex] = type;
quint8 feature = type.feature();
eventTypes[typeIndex] = type;
const quint8 feature = type.feature();
if (feature != MaximumProfileFeature)
m_loadedFeatures |= (1ULL << static_cast<uint>(feature));
addFeature(feature);
}
break;
}
if (elementName == _("eventData")) {
// done reading eventData
modelManager()->addEventTypes(eventTypes);
return;
}
break;
@@ -497,7 +512,7 @@ QVector<QmlEvent> EventList::finalize()
return result;
}
void QmlProfilerFileReader::loadEvents(QXmlStreamReader &stream)
void QmlProfilerTraceFile::loadEvents(QXmlStreamReader &stream)
{
QTC_ASSERT(stream.name() == _("profilerDataModel"), return);
EventList events;
@@ -510,7 +525,7 @@ void QmlProfilerFileReader::loadEvents(QXmlStreamReader &stream)
switch (token) {
case QXmlStreamReader::StartElement: {
if (elementName == _("range")) {
updateProgress(stream.device());
setDeviceProgress(stream.device());
QmlEvent event;
const QXmlStreamAttributes attributes = stream.attributes();
@@ -574,7 +589,7 @@ void QmlProfilerFileReader::loadEvents(QXmlStreamReader &stream)
case QXmlStreamReader::EndElement: {
if (elementName == _("profilerDataModel")) {
// done reading profilerDataModel
emit qmlEventsLoaded(events.finalize());
modelManager()->addEvents(events.finalize());
return;
}
break;
@@ -584,7 +599,7 @@ void QmlProfilerFileReader::loadEvents(QXmlStreamReader &stream)
}
}
void QmlProfilerFileReader::loadNotes(QXmlStreamReader &stream)
void QmlProfilerTraceFile::loadNotes(QXmlStreamReader &stream)
{
QmlNote currentNote;
while (!stream.atEnd() && !stream.hasError() && !isCanceled()) {
@@ -595,7 +610,7 @@ void QmlProfilerFileReader::loadNotes(QXmlStreamReader &stream)
switch (token) {
case QXmlStreamReader::StartElement: {
if (elementName == _("note")) {
updateProgress(stream.device());
setDeviceProgress(stream.device());
QXmlStreamAttributes attrs = stream.attributes();
int collapsedRow = attrs.hasAttribute(_("collapsedRow")) ?
attrs.value(_("collapsedRow")).toInt() : -1;
@@ -613,7 +628,7 @@ void QmlProfilerFileReader::loadNotes(QXmlStreamReader &stream)
}
case QXmlStreamReader::EndElement: {
if (elementName == _("note")) {
m_notes.append(currentNote);
qmlNotes()->addNote(currentNote);
} else if (elementName == _("noteData")) {
return;
}
@@ -625,55 +640,7 @@ void QmlProfilerFileReader::loadNotes(QXmlStreamReader &stream)
}
}
void QmlProfilerFileReader::updateProgress(QIODevice *device)
{
if (!m_future)
return;
m_future->setProgressValue(device->pos() * 1000 / device->size());
}
bool QmlProfilerFileReader::isCanceled() const
{
return m_future && m_future->isCanceled();
}
QmlProfilerFileWriter::QmlProfilerFileWriter(QObject *parent) :
QObject(parent),
m_startTime(0),
m_endTime(0),
m_measuredTime(0),
m_future(0)
{
}
void QmlProfilerFileWriter::setTraceTime(qint64 startTime, qint64 endTime, qint64 measuredTime)
{
m_startTime = startTime;
m_endTime = endTime;
m_measuredTime = measuredTime;
}
void QmlProfilerFileWriter::setData(const QmlProfilerModelManager *model)
{
m_modelManager = model;
}
void QmlProfilerFileWriter::setNotes(const QVector<QmlNote> &notes)
{
m_notes = notes;
}
void QmlProfilerFileWriter::setFuture(QFutureInterface<void> *future)
{
m_future = future;
if (m_future) {
m_future->setProgressRange(0, ProgressTotal);
m_future->setProgressValue(0);
}
}
void QmlProfilerFileWriter::saveQtd(QIODevice *device)
void QmlProfilerTraceFile::saveQtd(QIODevice *device)
{
QXmlStreamWriter stream(device);
@@ -683,15 +650,16 @@ void QmlProfilerFileWriter::saveQtd(QIODevice *device)
stream.writeStartElement(_("trace"));
stream.writeAttribute(_("version"), _(PROFILER_FILE_VERSION));
stream.writeAttribute(_("traceStart"), QString::number(m_startTime));
stream.writeAttribute(_("traceEnd"), QString::number(m_endTime));
stream.writeAttribute(_("traceStart"), QString::number(traceStart()));
stream.writeAttribute(_("traceEnd"), QString::number(traceEnd()));
stream.writeStartElement(_("eventData"));
stream.writeAttribute(_("totalTime"), QString::number(m_measuredTime));
for (int typeIndex = 0, end = m_modelManager->numEventTypes();
typeIndex < end && !isCanceled(); ++typeIndex) {
stream.writeAttribute(_("totalTime"), QString::number(measuredTime()));
const QmlProfilerModelManager *manager = modelManager();
for (int typeIndex = 0, end = manager->numEventTypes(); typeIndex < end && !isCanceled();
++typeIndex) {
const QmlEventType &type = m_modelManager->eventType(typeIndex);
const QmlEventType &type = manager->eventType(typeIndex);
stream.writeStartElement(_("event"));
stream.writeAttribute(_("index"), QString::number(typeIndex));
@@ -734,19 +702,17 @@ void QmlProfilerFileWriter::saveQtd(QIODevice *device)
}
stream.writeEndElement();
}
updateProgress(ProgressTypes);
addStageProgress(ProgressTypes);
stream.writeEndElement(); // eventData
if (!isCanceled()) {
stream.writeStartElement(_("profilerDataModel"));
if (isCanceled()) {
emit canceled();
return;
}
QStack<QmlEvent> stack;
const bool success = m_modelManager->replayEvents(
-1, -1, [this, &stack, &stream](const QmlEvent &event,
const QmlEventType &type) {
if (isCanceled())
return;
qint64 lastProgressTimestamp = traceStart();
modelManager()->replayEvents(-1, -1, [&](const QmlEvent &event, const QmlEventType &type) {
if (type.rangeType() != MaximumRangeType && event.rangeStage() == RangeStart) {
stack.push(event);
return;
@@ -811,23 +777,19 @@ void QmlProfilerFileWriter::saveQtd(QIODevice *device)
stream.writeEndElement();
// Update the progress roughly every 4k events. It doesn't have to be precise.
if ((event.timestamp() & 0xfff) == 0)
updateProgress(event.timestamp());
});
if (!success) {
emit error(tr("Could not re-read events from temporary trace file. Saving failed."));
return;
if (isProgressUpdateNeeded()) {
addEventsProgress(event.timestamp() - lastProgressTimestamp);
lastProgressTimestamp = event.timestamp();
}
}, [&stream](){
stream.writeStartElement(_("profilerDataModel"));
}, [this, &stream]() {
stream.writeEndElement(); // profilerDataModel
}
if (!isCanceled()) {
stream.writeStartElement(_("noteData"));
for (int noteIndex = 0; noteIndex < m_notes.size() && !isCanceled(); ++noteIndex) {
const QmlNote &note = m_notes[noteIndex];
const QVector<QmlNote> &notes = qmlNotes()->notes();
for (int noteIndex = 0; noteIndex < notes.length() && !isCanceled(); ++noteIndex) {
const QmlNote &note = notes[noteIndex];
stream.writeStartElement(_("note"));
stream.writeAttribute(_("startTime"), QString::number(note.startTime()));
stream.writeAttribute(_("duration"), QString::number(note.duration()));
@@ -837,60 +799,66 @@ void QmlProfilerFileWriter::saveQtd(QIODevice *device)
stream.writeEndElement(); // note
}
stream.writeEndElement(); // noteData
updateProgress(ProgressNotes);
addStageProgress(ProgressNotes);
}
stream.writeEndElement(); // trace
stream.writeEndDocument();
if (isCanceled()) {
if (isCanceled())
emit canceled();
} else if (stream.hasError()) {
else if (stream.hasError())
emit error(tr("Error writing trace file."));
} else {
else
emit success();
}
}, [this](const QString &message) {
emit error(tr("Could not re-read events from temporary trace file: %s\nSaving failed.")
.arg(message));
}, future());
}
void QmlProfilerFileWriter::saveQzt(QFile *file)
void QmlProfilerTraceFile::saveQzt(QIODevice *device)
{
QDataStream stream(file);
QDataStream stream(device);
stream.setVersion(QDataStream::Qt_5_5);
stream << QByteArray("QMLPROFILER");
stream << static_cast<qint32>(QDataStream::Qt_DefaultCompiledVersion);
stream.setVersion(QDataStream::Qt_DefaultCompiledVersion);
stream << m_startTime << m_endTime;
stream << traceStart() << traceEnd();
QBuffer buffer;
QDataStream bufferStream(&buffer);
buffer.open(QIODevice::WriteOnly);
if (!isCanceled()) {
const int numEventTypes = m_modelManager->numEventTypes();
const QmlProfilerModelManager *manager = modelManager();
const int numEventTypes = manager->numEventTypes();
bufferStream << static_cast<quint32>(numEventTypes);
for (int typeId = 0; typeId < numEventTypes; ++typeId)
bufferStream << m_modelManager->eventType(typeId);
bufferStream << manager->eventType(typeId);
stream << qCompress(buffer.data());
buffer.close();
buffer.buffer().clear();
updateProgress(ProgressTypes);
addStageProgress(ProgressTypes);
}
if (!isCanceled()) {
buffer.open(QIODevice::WriteOnly);
bufferStream << m_notes;
bufferStream << qmlNotes()->notes();
stream << qCompress(buffer.data());
buffer.close();
buffer.buffer().clear();
updateProgress(ProgressNotes);
addStageProgress(ProgressNotes);
}
if (!isCanceled()) {
buffer.open(QIODevice::WriteOnly);
const bool success = m_modelManager->replayEvents(
-1, -1, [this, &stream, &buffer, &bufferStream](const QmlEvent &event,
const QmlEventType &type) {
if (isCanceled()) {
emit canceled();
return;
}
qint64 lastProgressTimestamp = traceStart();
modelManager()->replayEvents(-1, -1, [&](const QmlEvent &event, const QmlEventType &type) {
Q_UNUSED(type);
bufferStream << event;
// 32MB buffer should be plenty for efficient compression
@@ -898,46 +866,38 @@ void QmlProfilerFileWriter::saveQzt(QFile *file)
stream << qCompress(buffer.data());
buffer.close();
buffer.buffer().clear();
if (isCanceled())
return;
buffer.open(QIODevice::WriteOnly);
updateProgress(event.timestamp());
}
});
if (!success) {
emit error(tr("Could not re-read events from temporary trace file. Saving failed."));
return;
if (isProgressUpdateNeeded()) {
addEventsProgress(event.timestamp() - lastProgressTimestamp);
lastProgressTimestamp = event.timestamp();
}
}
}, [&]() {
buffer.open(QIODevice::WriteOnly);
}, [&]() {
if (isCanceled()) {
emit canceled();
} else {
stream << qCompress(buffer.data());
buffer.close();
buffer.buffer().clear();
updateProgress(m_endTime);
addEventsProgress(traceEnd() - lastProgressTimestamp);
emit success();
}
}, [this](const QString &message) {
emit error(tr("Could not re-read events from temporary trace file: %s\nSaving failed.")
.arg(message));
}, future());
}
void QmlProfilerFileWriter::updateProgress(qint64 timestamp)
QmlProfilerModelManager *QmlProfilerTraceFile::modelManager()
{
if (!m_future)
return;
if (timestamp < 0) {
m_future->setProgressValue(m_future->progressValue() - timestamp);
} else {
m_future->setProgressValue(m_future->progressValue()
+ float(m_endTime - timestamp) / float(m_endTime - m_startTime)
* ProgressEvents);
}
return static_cast<QmlProfilerModelManager *>(traceManager());
}
bool QmlProfilerFileWriter::isCanceled() const
QmlProfilerNotesModel *QmlProfilerTraceFile::qmlNotes()
{
return m_future && m_future->isCanceled();
return static_cast<QmlProfilerNotesModel *>(notes());
}
} // namespace Internal

View File

@@ -32,6 +32,8 @@
#include "qmlevent.h"
#include "qmlprofilermodelmanager.h"
#include <timeline/timelinetracefile.h>
#include <QFutureInterface>
#include <QObject>
#include <QVector>
@@ -44,81 +46,36 @@ QT_FORWARD_DECLARE_CLASS(QXmlStreamReader)
namespace QmlProfiler {
namespace Internal {
class QmlProfilerFileReader : public QObject
class QmlProfilerTraceFile : public Timeline::TimelineTraceFile
{
Q_OBJECT
public:
explicit QmlProfilerFileReader(QObject *parent = 0);
explicit QmlProfilerTraceFile(QObject *parent = nullptr);
void setFuture(QFutureInterface<void> *future);
void loadQtd(QIODevice *device);
void loadQzt(QIODevice *device);
quint64 loadedFeatures() const;
qint64 traceStart() const { return m_traceStart; }
qint64 traceEnd() const { return m_traceEnd; }
signals:
void typesLoaded(const QVector<QmlProfiler::QmlEventType> &types);
void notesLoaded(const QVector<QmlProfiler::QmlNote> &notes);
void qmlEventsLoaded(const QVector<QmlProfiler::QmlEvent> &event);
void error(const QString &error);
void success();
void canceled();
void load(QIODevice *device) final;
void save(QIODevice *device) final;
private:
QmlProfilerModelManager *modelManager();
QmlProfilerNotesModel *qmlNotes();
void loadQtd(QIODevice *device);
void loadQzt(QIODevice *device);
void saveQtd(QIODevice *device);
void saveQzt(QIODevice *device);
void loadEventTypes(QXmlStreamReader &reader);
void loadEvents(QXmlStreamReader &reader);
void loadNotes(QXmlStreamReader &reader);
void updateProgress(QIODevice *device);
bool isCanceled() const;
qint64 m_traceStart, m_traceEnd;
QFutureInterface<void> *m_future;
QVector<QmlEventType> m_eventTypes;
QVector<QmlNote> m_notes;
quint64 m_loadedFeatures;
};
class QmlProfilerFileWriter : public QObject
{
Q_OBJECT
public:
explicit QmlProfilerFileWriter(QObject *parent = 0);
void setTraceTime(qint64 startTime, qint64 endTime, qint64 measturedTime);
void setData(const QmlProfilerModelManager *model);
void setNotes(const QVector<QmlNote> &notes);
void setFuture(QFutureInterface<void> *future);
void saveQtd(QIODevice *device);
void saveQzt(QFile *file);
signals:
void error(const QString &error);
void success();
void canceled();
private:
void updateProgress(qint64 timestamp);
bool isCanceled() const;
enum ProgressValues {
ProgressTypes = -128,
ProgressNotes = -32,
ProgressEvents = 1024,
ProgressTotal = ProgressEvents - ProgressTypes - ProgressNotes
ProgressTypes = 128,
ProgressNotes = 32,
ProgressEvents = MaximumProgress - ProgressTypes - ProgressNotes - MinimumProgress,
};
qint64 m_startTime, m_endTime, m_measuredTime;
QFutureInterface<void> *m_future;
const QmlProfilerModelManager *m_modelManager;
QVector<QmlNote> m_notes;
void addEventsProgress(qint64 timestamp);
void addStageProgress(ProgressValues stage);
};

View File

@@ -425,7 +425,7 @@ bool TraceViewFindSupport::findOne(const QString &txt, Core::FindFlags findFlags
bool forwardSearch = !(findFlags & Core::FindBackward);
int increment = forwardSearch ? +1 : -1;
int current = forwardSearch ? start : start - 1;
QmlProfilerNotesModel *model = m_modelManager->notesModel();
Timeline::TimelineNotesModel *model = m_modelManager->notesModel();
while (current >= 0 && current < model->count()) {
QTextDocument doc(model->text(current)); // for automatic handling of WholeWords option
if (!doc.find(regexp, 0, flags).isNull()) {

View File

@@ -219,6 +219,7 @@ void SceneGraphTimelineModel::finalize()
{
computeNesting();
flattenLoads();
QmlProfilerTimelineModel::finalize();
}
void SceneGraphTimelineModel::flattenLoads()

View File

@@ -39,7 +39,7 @@ DebugMessagesModelTest::DebugMessagesModelTest(QObject *parent) :
void DebugMessagesModelTest::initTestCase()
{
manager.startAcquiring();
manager.initialize();
QmlEvent event;
event.setTypeIndex(-1);

View File

@@ -45,7 +45,7 @@ int FlameGraphModelTest::generateData(QmlProfilerModelManager *manager,
int rangeModelId = rangeModel->modelId();
manager->notesModel()->addTimelineModel(rangeModel);
manager->startAcquiring();
manager->initialize();
QmlEvent event;
event.setTypeIndex(-1);
@@ -87,7 +87,8 @@ int FlameGraphModelTest::generateData(QmlProfilerModelManager *manager,
manager->finalize();
manager->notesModel()->setNotes(QVector<QmlNote>({QmlNote(0, 2, 1, 20, "dings")}));
static_cast<QmlProfilerNotesModel *>(manager->notesModel())
->setNotes(QVector<QmlNote>({QmlNote(0, 2, 1, 20, "dings")}));
manager->notesModel()->restore();
return rangeModelId;
@@ -220,7 +221,7 @@ void FlameGraphModelTest::testNotes()
void FlameGraphModelTest::cleanupTestCase()
{
manager.clear();
manager.clearAll();
QCOMPARE(model.rowCount(), 0);
}

View File

@@ -160,7 +160,7 @@ void FlameGraphViewTest::testContextMenu()
void FlameGraphViewTest::cleanupTestCase()
{
manager.clear();
manager.clearAll();
}
} // namespace Internal

View File

@@ -48,7 +48,7 @@ InputEventsModelTest::InputEventsModelTest(QObject *parent) :
void InputEventsModelTest::initTestCase()
{
manager.startAcquiring();
manager.initialize();
QmlEvent event;
for (int i = 0; i < 10; ++i) {

View File

@@ -36,7 +36,7 @@ MemoryUsageModelTest::MemoryUsageModelTest(QObject *parent) : QObject(parent),
void MemoryUsageModelTest::initTestCase()
{
manager.startAcquiring();
manager.initialize();
qint64 timestamp = 0;
@@ -233,7 +233,7 @@ void MemoryUsageModelTest::testAccepted()
void MemoryUsageModelTest::cleanupTestCase()
{
manager.clear();
manager.clearAll();
QCOMPARE(model.count(), 0);
}

View File

@@ -37,7 +37,7 @@ PixmapCacheModelTest::PixmapCacheModelTest(QObject *parent) : QObject(parent),
void PixmapCacheModelTest::initTestCase()
{
manager.startAcquiring();
manager.initialize();
manager.decreaseTraceStart(1);
manager.increaseTraceEnd(300);
@@ -313,7 +313,7 @@ void PixmapCacheModelTest::testLabels()
void PixmapCacheModelTest::cleanupTestCase()
{
manager.clear();
manager.clearAll();
QCOMPARE(model.count(), 0);
}

View File

@@ -42,7 +42,7 @@ static int frameRate(int i)
void QmlProfilerAnimationsModelTest::initTestCase()
{
manager.startAcquiring();
manager.initialize();
QmlEventType type(Event, MaximumRangeType, AnimationFrame);
QmlEvent event;

View File

@@ -69,6 +69,7 @@ void QmlProfilerTraceClientTest::testMessageReceived()
}
traceClient.stateChanged(QmlDebug::QmlDebugClient::NotConnected);
QFutureInterface<void> future;
modelManager.replayEvents(-1, -1, [&](const QmlEvent &event, const QmlEventType &type) {
qint64 timestamp;
qint32 message;
@@ -77,10 +78,19 @@ void QmlProfilerTraceClientTest::testMessageReceived()
QCOMPARE(event.timestamp(), timestamp);
QCOMPARE(type.message(), static_cast<Message>(message));
QCOMPARE(type.rangeType(), static_cast<RangeType>(rangeType));
});
modelManager.clear();
}, nullptr, [this]() {
modelManager.clearAll();
traceClient.clear();
}, [this](const QString &message) {
if (message == 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();
} else {
QFAIL(message.toUtf8().constData());
}
}, future);
}
QVERIFY(checkStream.atEnd());

View File

@@ -37,15 +37,15 @@ QmlProfilerTraceViewTest::QmlProfilerTraceViewTest(QObject *parent) :
void QmlProfilerTraceViewTest::testStateChanges()
{
// Standard acquire-process-clear work flow
modelManager.startAcquiring();
modelManager.initialize();
QVERIFY(traceView.isSuspended());
modelManager.finalize();
QVERIFY(!traceView.isSuspended());
modelManager.clear();
modelManager.clearAll();
QVERIFY(!traceView.isSuspended());
// Restrict to range
modelManager.startAcquiring();
modelManager.initialize();
QVERIFY(traceView.isSuspended());
modelManager.finalize();
QVERIFY(!traceView.isSuspended());
@@ -53,13 +53,13 @@ void QmlProfilerTraceViewTest::testStateChanges()
QVERIFY(!traceView.isSuspended());
modelManager.restrictToRange(-1, -1);
QVERIFY(!traceView.isSuspended());
modelManager.clear();
modelManager.clearAll();
QVERIFY(!traceView.isSuspended());
// Abort Acquiring
modelManager.startAcquiring();
modelManager.initialize();
QVERIFY(traceView.isSuspended());
modelManager.clear();
modelManager.clearAll();
QVERIFY(!traceView.isSuspended());
}