forked from qt-creator/qt-creator
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:
@@ -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
|
||||
|
@@ -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"
|
||||
]
|
||||
}
|
||||
|
||||
|
76
src/libs/timeline/timelinetracefile.cpp
Normal file
76
src/libs/timeline/timelinetracefile.cpp
Normal 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
|
97
src/libs/timeline/timelinetracefile.h
Normal file
97
src/libs/timeline/timelinetracefile.h
Normal 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
|
481
src/libs/timeline/timelinetracemanager.cpp
Normal file
481
src/libs/timeline/timelinetracemanager.cpp
Normal 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
|
128
src/libs/timeline/timelinetracemanager.h
Normal file
128
src/libs/timeline/timelinetracemanager.h
Normal 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
|
98
src/libs/timeline/tracestashfile.h
Normal file
98
src/libs/timeline/tracestashfile.h
Normal 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;
|
||||
};
|
||||
|
||||
}
|
@@ -111,6 +111,7 @@ void DebugMessagesModel::finalize()
|
||||
{
|
||||
setCollapsedRowCount(Constants::QML_MIN_LEVEL + 1);
|
||||
setExpandedRowCount(m_maximumMsgType + 2);
|
||||
QmlProfilerTimelineModel::finalize();
|
||||
}
|
||||
|
||||
void DebugMessagesModel::clear()
|
||||
|
@@ -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());
|
||||
|
@@ -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);
|
||||
|
@@ -165,6 +165,7 @@ void InputEventsModel::finalize()
|
||||
{
|
||||
setCollapsedRowCount(2);
|
||||
setExpandedRowCount(3);
|
||||
QmlProfilerTimelineModel::finalize();
|
||||
}
|
||||
|
||||
void InputEventsModel::clear()
|
||||
|
@@ -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()
|
||||
|
@@ -391,6 +391,7 @@ void PixmapCacheModel::finalize()
|
||||
computeMaxCacheSize();
|
||||
flattenLoads();
|
||||
computeNesting();
|
||||
QmlProfilerTimelineModel::finalize();
|
||||
}
|
||||
|
||||
void PixmapCacheModel::clear()
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -132,6 +132,11 @@ void QmlProfilerNotesModel::setNotes(const QVector<QmlNote> ¬es)
|
||||
m_notes = notes;
|
||||
}
|
||||
|
||||
void QmlProfilerNotesModel::addNote(const QmlNote ¬e)
|
||||
{
|
||||
m_notes.append(note);
|
||||
}
|
||||
|
||||
void QmlProfilerNotesModel::clear()
|
||||
{
|
||||
TimelineNotesModel::clear();
|
||||
|
@@ -42,6 +42,7 @@ public:
|
||||
|
||||
const QVector<QmlNote> ¬es() const;
|
||||
void setNotes(const QVector<QmlNote> ¬es);
|
||||
void addNote(const QmlNote ¬e);
|
||||
void clear() override;
|
||||
|
||||
protected:
|
||||
|
@@ -103,6 +103,8 @@ void QmlProfilerRangeModel::finalize()
|
||||
|
||||
if (supportsBindingLoops())
|
||||
findBindingLoops();
|
||||
|
||||
QmlProfilerTimelineModel::finalize();
|
||||
}
|
||||
|
||||
void QmlProfilerRangeModel::computeNestingContracted()
|
||||
|
@@ -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) {
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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())
|
||||
|
@@ -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> ¬es)
|
||||
{
|
||||
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 ¬e = m_notes[noteIndex];
|
||||
const QVector<QmlNote> ¬es = qmlNotes()->notes();
|
||||
for (int noteIndex = 0; noteIndex < notes.length() && !isCanceled(); ++noteIndex) {
|
||||
const QmlNote ¬e = 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
|
||||
|
@@ -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> ¬es);
|
||||
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> ¬es);
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
|
@@ -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()) {
|
||||
|
@@ -219,6 +219,7 @@ void SceneGraphTimelineModel::finalize()
|
||||
{
|
||||
computeNesting();
|
||||
flattenLoads();
|
||||
QmlProfilerTimelineModel::finalize();
|
||||
}
|
||||
|
||||
void SceneGraphTimelineModel::flattenLoads()
|
||||
|
@@ -39,7 +39,7 @@ DebugMessagesModelTest::DebugMessagesModelTest(QObject *parent) :
|
||||
|
||||
void DebugMessagesModelTest::initTestCase()
|
||||
{
|
||||
manager.startAcquiring();
|
||||
manager.initialize();
|
||||
QmlEvent event;
|
||||
event.setTypeIndex(-1);
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -160,7 +160,7 @@ void FlameGraphViewTest::testContextMenu()
|
||||
|
||||
void FlameGraphViewTest::cleanupTestCase()
|
||||
{
|
||||
manager.clear();
|
||||
manager.clearAll();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -48,7 +48,7 @@ InputEventsModelTest::InputEventsModelTest(QObject *parent) :
|
||||
|
||||
void InputEventsModelTest::initTestCase()
|
||||
{
|
||||
manager.startAcquiring();
|
||||
manager.initialize();
|
||||
QmlEvent event;
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -42,7 +42,7 @@ static int frameRate(int i)
|
||||
|
||||
void QmlProfilerAnimationsModelTest::initTestCase()
|
||||
{
|
||||
manager.startAcquiring();
|
||||
manager.initialize();
|
||||
|
||||
QmlEventType type(Event, MaximumRangeType, AnimationFrame);
|
||||
QmlEvent event;
|
||||
|
@@ -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());
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user