Commit c3e1ccf7 authored by Joerg Bornemann's avatar Joerg Bornemann
Browse files

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: default avatarUlf Hermann <ulf.hermann@theqtcompany.com>
parent 24049741
......@@ -470,4 +470,13 @@ Rectangle {
modelProxy: timelineModelAggregator
zoomer: zoomControl
}
Rectangle {
// Opal glass pane for visualizing the "disabled" state.
anchors.fill: parent
z: 10
color: parent.color
opacity: 0.5
visible: !parent.enabled
}
}
......@@ -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 &notes = 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> &notes);
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();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment