forked from qt-creator/qt-creator
QmlProfiler: save trace data in background thread
Trace data is saved in the background, progress is emitted, and the save operation can be canceled. While data is being saved the views are disabled and a semitransparent layer is put on top of the trace view. Task-number: QTCREATORBUG-11822 Change-Id: I94ec93147fb1788fc85939ddc591961d058050b5 Reviewed-by: Ulf Hermann <ulf.hermann@theqtcompany.com>
This commit is contained in:
@@ -36,6 +36,7 @@ namespace Constants {
|
||||
|
||||
const char ATTACH[] = "Menu.Analyzer.Attach";
|
||||
const char TraceFileExtension[] = ".qtd";
|
||||
const char TASK_SAVE[] = "QmlProfiler.TaskSave";
|
||||
|
||||
} // namespace Constants
|
||||
} // namespace QmlProfiler
|
||||
|
||||
@@ -29,11 +29,14 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
#include "qmlprofilerconstants.h"
|
||||
#include "qmlprofilerdatamodel.h"
|
||||
#include "qv8profilerdatamodel.h"
|
||||
#include "qmlprofilertracefile.h"
|
||||
#include "qmlprofilernotesmodel.h"
|
||||
|
||||
#include <coreplugin/progressmanager/progressmanager.h>
|
||||
#include <utils/runextensions.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QDebug>
|
||||
@@ -363,20 +366,31 @@ void QmlProfilerModelManager::modelProcessingDone()
|
||||
|
||||
void QmlProfilerModelManager::save(const QString &filename)
|
||||
{
|
||||
QFile file(filename);
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
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;
|
||||
}
|
||||
|
||||
QmlProfilerFileWriter writer;
|
||||
|
||||
d->notesModel->saveData();
|
||||
writer.setTraceTime(traceTime()->startTime(), traceTime()->endTime(), traceTime()->duration());
|
||||
writer.setV8DataModel(d->v8Model);
|
||||
writer.setQmlEvents(d->model->getEventTypes(), d->model->getEvents());
|
||||
writer.setNotes(d->model->getEventNotes());
|
||||
writer.save(&file);
|
||||
|
||||
QFuture<void> result = QtConcurrent::run<void>([this, file] (QFutureInterface<void> &future) {
|
||||
QmlProfilerFileWriter writer;
|
||||
writer.setTraceTime(traceTime()->startTime(), traceTime()->endTime(),
|
||||
traceTime()->duration());
|
||||
writer.setV8DataModel(d->v8Model);
|
||||
writer.setQmlEvents(d->model->getEventTypes(), d->model->getEvents());
|
||||
writer.setNotes(d->model->getEventNotes());
|
||||
writer.setFuture(&future);
|
||||
writer.save(file);
|
||||
file->deleteLater();
|
||||
QMetaObject::invokeMethod(this, "saveFinished", Qt::QueuedConnection);
|
||||
});
|
||||
|
||||
Core::ProgressManager::addTask(result, tr("Saving Trace Data"), Constants::TASK_SAVE,
|
||||
Core::ProgressManager::ShowInApplicationIcon);
|
||||
}
|
||||
|
||||
void QmlProfilerModelManager::load(const QString &filename)
|
||||
|
||||
@@ -137,6 +137,7 @@ signals:
|
||||
void stateChanged();
|
||||
void progressChanged();
|
||||
void dataAvailable();
|
||||
void saveFinished();
|
||||
|
||||
void requestDetailsForLocation(int eventType, const QmlDebug::QmlEventLocation &location);
|
||||
void availableFeaturesChanged(quint64 features);
|
||||
|
||||
@@ -150,6 +150,8 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent)
|
||||
connect(d->m_profilerModelManager, SIGNAL(error(QString)), this, SLOT(showErrorDialog(QString)));
|
||||
connect(d->m_profilerModelManager, SIGNAL(availableFeaturesChanged(quint64)),
|
||||
this, SLOT(setAvailableFeatures(quint64)));
|
||||
connect(d->m_profilerModelManager, &QmlProfilerModelManager::saveFinished,
|
||||
this, &QmlProfilerTool::onSaveFinished);
|
||||
|
||||
d->m_profilerConnections->setModelManager(d->m_profilerModelManager);
|
||||
Command *command = 0;
|
||||
@@ -590,10 +592,16 @@ void QmlProfilerTool::showSaveDialog()
|
||||
if (!filename.isEmpty()) {
|
||||
if (!filename.endsWith(QLatin1String(TraceFileExtension)))
|
||||
filename += QLatin1String(TraceFileExtension);
|
||||
AnalyzerManager::mainWindow()->setEnabled(false);
|
||||
d->m_profilerModelManager->save(filename);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTool::onSaveFinished()
|
||||
{
|
||||
AnalyzerManager::mainWindow()->setEnabled(true);
|
||||
}
|
||||
|
||||
void QmlProfilerTool::showLoadDialog()
|
||||
{
|
||||
if (!checkForUnsavedNotes())
|
||||
|
||||
@@ -95,6 +95,7 @@ private slots:
|
||||
void showSaveOption();
|
||||
void showLoadOption();
|
||||
void showSaveDialog();
|
||||
void onSaveFinished();
|
||||
void showLoadDialog();
|
||||
|
||||
void toggleRecordingFeature(QAction *action);
|
||||
|
||||
@@ -425,7 +425,8 @@ QmlProfilerFileWriter::QmlProfilerFileWriter(QObject *parent) :
|
||||
m_startTime(0),
|
||||
m_endTime(0),
|
||||
m_measuredTime(0),
|
||||
m_v8Model(0)
|
||||
m_v8Model(0),
|
||||
m_future(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -453,8 +454,21 @@ void QmlProfilerFileWriter::setNotes(const QVector<QmlProfilerDataModel::QmlEven
|
||||
m_notes = notes;
|
||||
}
|
||||
|
||||
void QmlProfilerFileWriter::setFuture(QFutureInterface<void> *future)
|
||||
{
|
||||
m_future = future;
|
||||
}
|
||||
|
||||
void QmlProfilerFileWriter::save(QIODevice *device)
|
||||
{
|
||||
if (m_future) {
|
||||
m_future->setProgressRange(0,
|
||||
qMax(m_qmlEvents.size() + m_ranges.size() + m_notes.size()
|
||||
+ m_v8Model->numberOfV8Events(), 1));
|
||||
m_future->setProgressValue(0);
|
||||
m_newProgressValue = 0;
|
||||
}
|
||||
|
||||
QXmlStreamWriter stream(device);
|
||||
|
||||
stream.setAutoFormatting(true);
|
||||
@@ -469,7 +483,10 @@ void QmlProfilerFileWriter::save(QIODevice *device)
|
||||
stream.writeStartElement(_("eventData"));
|
||||
stream.writeAttribute(_("totalTime"), QString::number(m_measuredTime));
|
||||
|
||||
for (int typeIndex = 0; typeIndex < m_qmlEvents.size(); ++typeIndex) {
|
||||
for (int typeIndex = 0; typeIndex < m_qmlEvents.size(); ++typeIndex) {
|
||||
if (isCanceled())
|
||||
return;
|
||||
|
||||
const QmlProfilerDataModel::QmlEventTypeData &event = m_qmlEvents[typeIndex];
|
||||
|
||||
stream.writeStartElement(_("event"));
|
||||
@@ -496,12 +513,16 @@ void QmlProfilerFileWriter::save(QIODevice *device)
|
||||
if (event.message == MemoryAllocation)
|
||||
stream.writeTextElement(_("memoryEventType"), QString::number(event.detailType));
|
||||
stream.writeEndElement();
|
||||
incrementProgress();
|
||||
}
|
||||
stream.writeEndElement(); // eventData
|
||||
|
||||
stream.writeStartElement(_("profilerDataModel"));
|
||||
|
||||
for (int rangeIndex = 0; rangeIndex < m_ranges.size(); ++rangeIndex) {
|
||||
if (isCanceled())
|
||||
return;
|
||||
|
||||
const QmlProfilerDataModel::QmlEventData &range = m_ranges[rangeIndex];
|
||||
|
||||
stream.writeStartElement(_("range"));
|
||||
@@ -550,11 +571,15 @@ void QmlProfilerFileWriter::save(QIODevice *device)
|
||||
stream.writeAttribute(_("amount"), QString::number(range.numericData1));
|
||||
|
||||
stream.writeEndElement();
|
||||
incrementProgress();
|
||||
}
|
||||
stream.writeEndElement(); // profilerDataModel
|
||||
|
||||
stream.writeStartElement(_("noteData"));
|
||||
for (int noteIndex = 0; noteIndex < m_notes.size(); ++noteIndex) {
|
||||
if (isCanceled())
|
||||
return;
|
||||
|
||||
const QmlProfilerDataModel::QmlEventNoteData ¬es = m_notes[noteIndex];
|
||||
stream.writeStartElement(_("note"));
|
||||
stream.writeAttribute(_("startTime"), QString::number(notes.startTime));
|
||||
@@ -562,15 +587,35 @@ void QmlProfilerFileWriter::save(QIODevice *device)
|
||||
stream.writeAttribute(_("eventIndex"), QString::number(notes.typeIndex));
|
||||
stream.writeCharacters(notes.text);
|
||||
stream.writeEndElement(); // note
|
||||
incrementProgress();
|
||||
}
|
||||
stream.writeEndElement(); // noteData
|
||||
|
||||
m_v8Model->save(stream);
|
||||
if (isCanceled())
|
||||
return;
|
||||
m_v8Model->save(stream, m_future);
|
||||
|
||||
stream.writeEndElement(); // trace
|
||||
stream.writeEndDocument();
|
||||
}
|
||||
|
||||
void QmlProfilerFileWriter::incrementProgress()
|
||||
{
|
||||
if (!m_future)
|
||||
return;
|
||||
|
||||
m_newProgressValue++;
|
||||
if (float(m_newProgressValue - m_future->progressValue())
|
||||
/ float(m_future->progressMaximum() - m_future->progressMinimum()) >= 0.01) {
|
||||
m_future->setProgressValue(m_newProgressValue);
|
||||
}
|
||||
}
|
||||
|
||||
bool QmlProfilerFileWriter::isCanceled() const
|
||||
{
|
||||
return m_future && m_future->isCanceled();
|
||||
}
|
||||
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#ifndef QMLPROFILERTRACEFILE_H
|
||||
#define QMLPROFILERTRACEFILE_H
|
||||
|
||||
#include <QFutureInterface>
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
#include <QString>
|
||||
@@ -88,17 +89,22 @@ public:
|
||||
void setQmlEvents(const QVector<QmlProfilerDataModel::QmlEventTypeData> &types,
|
||||
const QVector<QmlProfilerDataModel::QmlEventData> &events);
|
||||
void setNotes(const QVector<QmlProfilerDataModel::QmlEventNoteData> ¬es);
|
||||
void setFuture(QFutureInterface<void> *future);
|
||||
|
||||
void save(QIODevice *device);
|
||||
|
||||
private:
|
||||
void calculateMeasuredTime();
|
||||
void incrementProgress();
|
||||
bool isCanceled() const;
|
||||
|
||||
qint64 m_startTime, m_endTime, m_measuredTime;
|
||||
QV8ProfilerDataModel *m_v8Model;
|
||||
QFutureInterface<void> *m_future;
|
||||
QVector<QmlProfilerDataModel::QmlEventTypeData> m_qmlEvents;
|
||||
QVector<QmlProfilerDataModel::QmlEventData> m_ranges;
|
||||
QVector<QmlProfilerDataModel::QmlEventNoteData> m_notes;
|
||||
int m_newProgressValue;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -326,5 +326,13 @@ void QmlProfilerTraceView::profilerDataModelStateChanged()
|
||||
}
|
||||
}
|
||||
|
||||
void QmlProfilerTraceView::changeEvent(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::EnabledChange) {
|
||||
QQuickItem *rootObject = d->m_mainView->rootObject();
|
||||
rootObject->setProperty("enabled", isEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
||||
@@ -71,6 +71,7 @@ private slots:
|
||||
void profilerDataModelStateChanged();
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent *e) Q_DECL_OVERRIDE;
|
||||
virtual void contextMenuEvent(QContextMenuEvent *event);
|
||||
virtual void mousePressEvent(QMouseEvent *event);
|
||||
virtual void mouseReleaseEvent(QMouseEvent *event);
|
||||
|
||||
@@ -164,6 +164,12 @@ QList<QV8ProfilerDataModel::QV8EventData *> QV8ProfilerDataModel::getV8Events()
|
||||
return d->v8EventHash.values();
|
||||
}
|
||||
|
||||
int QV8ProfilerDataModel::numberOfV8Events() const
|
||||
{
|
||||
Q_D(const QV8ProfilerDataModel);
|
||||
return d->v8EventHash.size();
|
||||
}
|
||||
|
||||
QString getHashStringForV8Event(const QString &displayName, const QString &function)
|
||||
{
|
||||
return QString::fromLatin1("%1:%2").arg(displayName, function);
|
||||
@@ -323,7 +329,7 @@ void QV8ProfilerDataModel::clearV8RootEvent()
|
||||
d->v8RootEvent.childrenHash.clear();
|
||||
}
|
||||
|
||||
void QV8ProfilerDataModel::save(QXmlStreamWriter &stream)
|
||||
void QV8ProfilerDataModel::save(QXmlStreamWriter &stream, QFutureInterface<void> *future)
|
||||
{
|
||||
Q_D(QV8ProfilerDataModel);
|
||||
stream.writeStartElement(QLatin1String("v8profile")); // v8 profiler output
|
||||
@@ -359,6 +365,9 @@ void QV8ProfilerDataModel::save(QXmlStreamWriter &stream)
|
||||
stream.writeEndElement();
|
||||
}
|
||||
stream.writeEndElement();
|
||||
|
||||
if (future)
|
||||
future->setProgressValue(future->progressValue() + 1);
|
||||
}
|
||||
stream.writeEndElement(); // v8 profiler output
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "qmlprofilerbasemodel.h"
|
||||
#include <utils/fileinprojectfinder.h>
|
||||
|
||||
#include <QFutureInterface>
|
||||
#include <QObject>
|
||||
#include <QHash>
|
||||
|
||||
@@ -82,11 +83,12 @@ public:
|
||||
void clear();
|
||||
bool isEmpty() const;
|
||||
QList<QV8EventData *> getV8Events() const;
|
||||
int numberOfV8Events() const;
|
||||
QV8EventData *v8EventDescription(int typeId) const;
|
||||
|
||||
qint64 v8MeasuredTime() const;
|
||||
|
||||
void save(QXmlStreamWriter &stream);
|
||||
void save(QXmlStreamWriter &stream, QFutureInterface<void> *future = 0);
|
||||
void load(QXmlStreamReader &stream);
|
||||
|
||||
void complete();
|
||||
|
||||
Reference in New Issue
Block a user