forked from qt-creator/qt-creator
QmlProfiler: Guard against the temporary trace file going away
If we cannot open a temporary file to cache a trace or retrieve a previously cached trace, the QML profiler won't work correctly. Show an error in this case. Change-Id: I468d74d9c33033b9ad19501bccbd69a9fe164fed Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -101,8 +101,10 @@ QmlProfilerDataModel::QmlProfilerDataModel(QObject *parent) :
|
|||||||
this, &QmlProfilerDataModel::detailsChanged);
|
this, &QmlProfilerDataModel::detailsChanged);
|
||||||
connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::eventDetailsChanged,
|
connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::eventDetailsChanged,
|
||||||
this, &QmlProfilerDataModel::allTypesLoaded);
|
this, &QmlProfilerDataModel::allTypesLoaded);
|
||||||
d->file.open();
|
if (!d->file.open())
|
||||||
d->eventStream.setDevice(&d->file);
|
emit traceFileError();
|
||||||
|
else
|
||||||
|
d->eventStream.setDevice(&d->file);
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlProfilerDataModel::~QmlProfilerDataModel()
|
QmlProfilerDataModel::~QmlProfilerDataModel()
|
||||||
@@ -170,8 +172,11 @@ void QmlProfilerDataModel::clear()
|
|||||||
{
|
{
|
||||||
Q_D(QmlProfilerDataModel);
|
Q_D(QmlProfilerDataModel);
|
||||||
d->file.remove();
|
d->file.remove();
|
||||||
d->file.open();
|
d->eventStream.unsetDevice();
|
||||||
d->eventStream.setDevice(&d->file);
|
if (!d->file.open())
|
||||||
|
emit traceFileError();
|
||||||
|
else
|
||||||
|
d->eventStream.setDevice(&d->file);
|
||||||
d->eventTypes.clear();
|
d->eventTypes.clear();
|
||||||
d->detailsRewriter->clearRequests();
|
d->detailsRewriter->clearRequests();
|
||||||
}
|
}
|
||||||
@@ -207,14 +212,16 @@ static bool isStateful(const QmlEventType &type)
|
|||||||
return message == PixmapCacheEvent || message == MemoryAllocation;
|
return message == PixmapCacheEvent || message == MemoryAllocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd,
|
bool QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd,
|
||||||
QmlProfilerModelManager::EventLoader loader) const
|
QmlProfilerModelManager::EventLoader loader) const
|
||||||
{
|
{
|
||||||
Q_D(const QmlProfilerDataModel);
|
Q_D(const QmlProfilerDataModel);
|
||||||
QStack<QmlEvent> stack;
|
QStack<QmlEvent> stack;
|
||||||
QmlEvent event;
|
QmlEvent event;
|
||||||
QFile file(d->file.fileName());
|
QFile file(d->file.fileName());
|
||||||
file.open(QIODevice::ReadOnly);
|
if (!file.open(QIODevice::ReadOnly))
|
||||||
|
return false;
|
||||||
|
|
||||||
QDataStream stream(&file);
|
QDataStream stream(&file);
|
||||||
bool crossedRangeStart = false;
|
bool crossedRangeStart = false;
|
||||||
while (!stream.atEnd()) {
|
while (!stream.atEnd()) {
|
||||||
@@ -271,6 +278,7 @@ void QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd,
|
|||||||
|
|
||||||
loader(event, type);
|
loader(event, type);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerDataModel::finalize()
|
void QmlProfilerDataModel::finalize()
|
||||||
|
@@ -55,12 +55,13 @@ public:
|
|||||||
bool isEmpty() const;
|
bool isEmpty() const;
|
||||||
void addEvent(const QmlEvent &event);
|
void addEvent(const QmlEvent &event);
|
||||||
void addEvents(const QVector<QmlEvent> &events);
|
void addEvents(const QVector<QmlEvent> &events);
|
||||||
void replayEvents(qint64 startTime, qint64 endTime,
|
bool replayEvents(qint64 startTime, qint64 endTime,
|
||||||
QmlProfilerModelManager::EventLoader loader) const;
|
QmlProfilerModelManager::EventLoader loader) const;
|
||||||
void finalize();
|
void finalize();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void allTypesLoaded();
|
void allTypesLoaded();
|
||||||
|
void traceFileError();
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void detailsChanged(int typeId, const QString &newString);
|
void detailsChanged(int typeId, const QString &newString);
|
||||||
|
@@ -176,6 +176,10 @@ QmlProfilerModelManager::QmlProfilerModelManager(QObject *parent) :
|
|||||||
d->textMarkModel = new QmlProfilerTextMarkModel(this);
|
d->textMarkModel = new QmlProfilerTextMarkModel(this);
|
||||||
connect(d->model, &QmlProfilerDataModel::allTypesLoaded,
|
connect(d->model, &QmlProfilerDataModel::allTypesLoaded,
|
||||||
this, &QmlProfilerModelManager::processingDone);
|
this, &QmlProfilerModelManager::processingDone);
|
||||||
|
connect(d->model, &QmlProfilerDataModel::traceFileError,
|
||||||
|
this, [this]() {
|
||||||
|
emit error(tr("Could not open a temporary file for storing QML traces."));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlProfilerModelManager::~QmlProfilerModelManager()
|
QmlProfilerModelManager::~QmlProfilerModelManager()
|
||||||
@@ -543,12 +547,17 @@ void QmlProfilerModelManager::restrictToRange(qint64 startTime, qint64 endTime)
|
|||||||
setVisibleFeatures(0);
|
setVisibleFeatures(0);
|
||||||
|
|
||||||
startAcquiring();
|
startAcquiring();
|
||||||
d->model->replayEvents(startTime, endTime,
|
if (!d->model->replayEvents(startTime, endTime,
|
||||||
std::bind(&QmlProfilerModelManagerPrivate::dispatch, d,
|
std::bind(&QmlProfilerModelManagerPrivate::dispatch, d,
|
||||||
std::placeholders::_1, std::placeholders::_2));
|
std::placeholders::_1, std::placeholders::_2))) {
|
||||||
d->notesModel->setNotes(notes);
|
emit error(tr("Could not re-read events from temporary trace file. "
|
||||||
d->traceTime->restrictToRange(startTime, endTime);
|
"The trace data is lost."));
|
||||||
acquiringDone();
|
clear();
|
||||||
|
} else {
|
||||||
|
d->notesModel->setNotes(notes);
|
||||||
|
d->traceTime->restrictToRange(startTime, endTime);
|
||||||
|
acquiringDone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QmlProfilerModelManager::isRestrictedToRange() const
|
bool QmlProfilerModelManager::isRestrictedToRange() const
|
||||||
|
@@ -120,13 +120,17 @@ void QmlProfilerStatisticsModel::restrictToFeatures(qint64 features)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
d->modelManager->qmlModel()->replayEvents(d->modelManager->traceTime()->startTime(),
|
if (!d->modelManager->qmlModel()->replayEvents(d->modelManager->traceTime()->startTime(),
|
||||||
d->modelManager->traceTime()->endTime(),
|
d->modelManager->traceTime()->endTime(),
|
||||||
std::bind(&QmlProfilerStatisticsModel::loadEvent,
|
std::bind(&QmlProfilerStatisticsModel::loadEvent,
|
||||||
this, std::placeholders::_1,
|
this, std::placeholders::_1,
|
||||||
std::placeholders::_2));
|
std::placeholders::_2))) {
|
||||||
finalize();
|
emit d->modelManager->error(tr("Could not re-read events from temporary trace file."));
|
||||||
notesChanged(-1); // Reload notes
|
clear();
|
||||||
|
} else {
|
||||||
|
finalize();
|
||||||
|
notesChanged(-1); // Reload notes
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const QHash<int, QmlProfilerStatisticsModel::QmlEventStats> &QmlProfilerStatisticsModel::getData() const
|
const QHash<int, QmlProfilerStatisticsModel::QmlEventStats> &QmlProfilerStatisticsModel::getData() const
|
||||||
|
@@ -668,8 +668,9 @@ void QmlProfilerFileWriter::saveQtd(QIODevice *device)
|
|||||||
stream.writeStartElement(_("profilerDataModel"));
|
stream.writeStartElement(_("profilerDataModel"));
|
||||||
|
|
||||||
QStack<QmlEvent> stack;
|
QStack<QmlEvent> stack;
|
||||||
m_model->replayEvents(-1, -1, [this, &stack, &stream](const QmlEvent &event,
|
const bool success = m_model->replayEvents(
|
||||||
const QmlEventType &type) {
|
-1, -1, [this, &stack, &stream](const QmlEvent &event,
|
||||||
|
const QmlEventType &type) {
|
||||||
if (isCanceled())
|
if (isCanceled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -741,6 +742,10 @@ void QmlProfilerFileWriter::saveQtd(QIODevice *device)
|
|||||||
if ((event.timestamp() & 0xfff) == 0)
|
if ((event.timestamp() & 0xfff) == 0)
|
||||||
updateProgress(event.timestamp());
|
updateProgress(event.timestamp());
|
||||||
});
|
});
|
||||||
|
if (!success) {
|
||||||
|
emit error(tr("Could not re-read events from temporary trace file. Saving failed."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
stream.writeEndElement(); // profilerDataModel
|
stream.writeEndElement(); // profilerDataModel
|
||||||
}
|
}
|
||||||
@@ -807,8 +812,9 @@ void QmlProfilerFileWriter::saveQzt(QFile *file)
|
|||||||
|
|
||||||
if (!isCanceled()) {
|
if (!isCanceled()) {
|
||||||
buffer.open(QIODevice::WriteOnly);
|
buffer.open(QIODevice::WriteOnly);
|
||||||
m_model->replayEvents(-1, -1, [this, &stream, &buffer, &bufferStream](
|
const bool success = m_model->replayEvents(
|
||||||
const QmlEvent &event, const QmlEventType &type) {
|
-1, -1, [this, &stream, &buffer, &bufferStream](const QmlEvent &event,
|
||||||
|
const QmlEventType &type) {
|
||||||
Q_UNUSED(type);
|
Q_UNUSED(type);
|
||||||
bufferStream << event;
|
bufferStream << event;
|
||||||
// 32MB buffer should be plenty for efficient compression
|
// 32MB buffer should be plenty for efficient compression
|
||||||
@@ -822,6 +828,10 @@ void QmlProfilerFileWriter::saveQzt(QFile *file)
|
|||||||
updateProgress(event.timestamp());
|
updateProgress(event.timestamp());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (!success) {
|
||||||
|
emit error(tr("Could not re-read events from temporary trace file. Saving failed."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCanceled()) {
|
if (isCanceled()) {
|
||||||
|
Reference in New Issue
Block a user