Commit 47ce17b1 authored by Ulf Hermann's avatar Ulf Hermann
Browse files

QmlProfiler: Sanitize the signal exchange between models a bit



The model manager should only set its state to 'Done' if all models are
actually done. When that is the case it can safely emit dataAvailable,
too, freeing us of the need to apply a heuristic to the progress
percentage. In order to have a unified interface to the completion of
model processing an abstract base class for QML and V8 models is
introduced.

Task-number: QTCREATORBUG-11466
Change-Id: Id89c7ef5e24004baab7f37ee5486b69e7611aee0
Reviewed-by: default avatarChristian Stenger <christian.stenger@digia.com>
Reviewed-by: default avatarKai Koehne <kai.koehne@digia.com>
parent 5d2654e4
......@@ -81,7 +81,7 @@ int AbstractTimelineModel::getBindingLoopDest(int index) const
void AbstractTimelineModel::dataChanged()
{
switch (m_modelManager->state()) {
case QmlProfilerDataState::Done:
case QmlProfilerDataState::ProcessingData:
loadData();
break;
case QmlProfilerDataState::ClearingData:
......
......@@ -31,7 +31,8 @@ SOURCES += \
abstracttimelinemodel.cpp \
timelinemodelaggregator.cpp \
qmlprofilerpainteventsmodelproxy.cpp \
sortedtimelinemodel.cpp
sortedtimelinemodel.cpp \
qmlprofilerbasemodel.cpp
HEADERS += \
qmlprofilerconstants.h \
......@@ -63,7 +64,8 @@ HEADERS += \
abstracttimelinemodel.h \
timelinemodelaggregator.h \
qmlprofilerpainteventsmodelproxy.h \
sortedtimelinemodel.h
sortedtimelinemodel.h \
qmlprofilerbasemodel.h
RESOURCES += \
qml/qmlprofiler.qrc
......
......@@ -28,6 +28,7 @@ QtcPlugin {
"localqmlprofilerrunner.cpp", "localqmlprofilerrunner.h",
"qmlprofiler_global.h",
"qmlprofilerattachdialog.cpp", "qmlprofilerattachdialog.h",
"qmlprofilerbasemodel.cpp", "qmlprofilerbasemodel.h",
"qmlprofilerclientmanager.cpp", "qmlprofilerclientmanager.h",
"qmlprofilerconstants.h",
"qmlprofilerdetailsrewriter.cpp", "qmlprofilerdetailsrewriter.h",
......
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "qmlprofilerbasemodel.h"
#include "qmlprofilermodelmanager.h"
namespace QmlProfiler {
QmlProfilerBaseModel::QmlProfilerBaseModel(QmlProfilerModelManager *manager) :
m_modelManager(manager), m_processingDone(false)
{
Q_ASSERT(m_modelManager);
m_modelId = m_modelManager->registerModelProxy();
}
void QmlProfilerBaseModel::clear()
{
m_modelManager->modelProxyCountUpdated(m_modelId, 0, 1);
m_processingDone = false;
emit changed();
}
void QmlProfilerBaseModel::complete()
{
emit changed();
m_processingDone = true;
m_modelManager->modelProxyCountUpdated(m_modelId, isEmpty() ? 0 : 1, 1);
m_modelManager->modelProcessingDone();
}
}
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** 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 Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef QMLPROFILERBASEMODEL_H
#define QMLPROFILERBASEMODEL_H
#include "qmlprofiler_global.h"
#include <QObject>
namespace QmlProfiler {
class QmlProfilerModelManager;
class QMLPROFILER_EXPORT QmlProfilerBaseModel : public QObject {
Q_OBJECT
public:
QmlProfilerBaseModel(QmlProfilerModelManager *manager);
virtual ~QmlProfilerBaseModel() {}
virtual void complete();
virtual void clear();
virtual bool isEmpty() const = 0;
bool processingDone() const { return m_processingDone; }
protected:
QmlProfilerModelManager *m_modelManager;
int m_modelId;
bool m_processingDone;
signals:
void changed();
};
}
#endif // QMLPROFILERBASEMODEL_H
......@@ -96,7 +96,7 @@ void QmlProfilerEventsModelProxy::limitToRange(qint64 rangeStart, qint64 rangeEn
void QmlProfilerEventsModelProxy::dataChanged()
{
if (d->modelManager->state() == QmlProfilerDataState::Done)
if (d->modelManager->state() == QmlProfilerDataState::ProcessingData)
loadData();
else if (d->modelManager->state() == QmlProfilerDataState::ClearingData)
clear();
......
......@@ -216,8 +216,6 @@ void QmlProfilerModelManager::modelProxyCountUpdated(int proxyId, qint64 count,
d->progress += d->partialCounts[proxyId] / d->partialCounts.count();
emit progressChanged();
if (d->progress > 0.99)
emit dataAvailable();
}
qint64 QmlProfilerModelManager::estimatedProfilingTime() const
......@@ -259,25 +257,37 @@ void QmlProfilerModelManager::addV8Event(int depth, const QString &function, con
void QmlProfilerModelManager::complete()
{
if (state() == QmlProfilerDataState::AcquiringData) {
switch (state()) {
case QmlProfilerDataState::ProcessingData:
setState(QmlProfilerDataState::Done);
emit dataAvailable();
break;
case QmlProfilerDataState::AcquiringData:
// If trace end time was not explicitly set, use the last event
if (d->traceTime->endTime() == 0)
d->traceTime->setEndTime(d->model->lastTimeMark());
setState(QmlProfilerDataState::ProcessingData);
d->model->complete();
d->v8Model->complete();
break;
case QmlProfilerDataState::Empty:
setState(QmlProfilerDataState::Done);
} else
if (state() == QmlProfilerDataState::Empty) {
setState(QmlProfilerDataState::Done);
} else
if (state() == QmlProfilerDataState::Done) {
// repeated Done states are ignored
} else {
break;
case QmlProfilerDataState::Done:
break;
default:
emit error(tr("Unexpected complete signal in data model."));
break;
}
}
void QmlProfilerModelManager::modelProcessingDone()
{
Q_ASSERT(state() == QmlProfilerDataState::ProcessingData);
if (d->model->processingDone() && d->v8Model->processingDone())
complete();
}
void QmlProfilerModelManager::save(const QString &filename)
{
QFile file(filename);
......
......@@ -141,6 +141,7 @@ public slots:
double totalTime, double selfTime);
void complete();
void modelProcessingDone();
void save(const QString &filename);
void load(const QString &filename);
......
......@@ -28,6 +28,7 @@
****************************************************************************/
#include "qmlprofilerprocessedmodel.h"
#include "qmlprofilermodelmanager.h"
#include <qmldebug/qmlprofilereventtypes.h>
#include <utils/qtcassert.h>
#include <QUrl>
......@@ -96,10 +97,9 @@ bool compareStartTimes(const QmlProfilerSimpleModel::QmlEventData &t1, const Qml
//////////////////////////////////////////////////////////////////////////////
QmlProfilerProcessedModel::QmlProfilerProcessedModel(Utils::FileInProjectFinder *fileFinder, QObject *parent)
QmlProfilerProcessedModel::QmlProfilerProcessedModel(Utils::FileInProjectFinder *fileFinder, QmlProfilerModelManager *parent)
: QmlProfilerSimpleModel(parent)
, m_detailsRewriter(new QmlProfilerDetailsRewriter(this, fileFinder))
, m_emitChanged(false)
{
connect(m_detailsRewriter, SIGNAL(rewriteDetailsString(int,QString)),
this, SLOT(detailsChanged(int,QString)));
......@@ -117,8 +117,6 @@ void QmlProfilerProcessedModel::clear()
// This call emits changed(). Don't emit it again here.
QmlProfilerSimpleModel::clear();
m_emitChanged = false;
}
void QmlProfilerProcessedModel::complete()
......@@ -154,12 +152,9 @@ void QmlProfilerProcessedModel::complete()
m_detailsRewriter->requestDetailsForLocation(i, event->location);
}
// Allow QmlProfilerBaseModel::complete() only after documents have been reloaded to avoid
// unnecessary updates of child models.
m_detailsRewriter->reloadDocuments();
// This call emits changed(). Don't emit it again here.
QmlProfilerSimpleModel::complete();
m_emitChanged = false;
}
void QmlProfilerProcessedModel::detailsChanged(int requestId, const QString &newString)
......@@ -168,16 +163,13 @@ void QmlProfilerProcessedModel::detailsChanged(int requestId, const QString &new
QmlEventData *event = &eventList[requestId];
event->data = QStringList(newString);
m_emitChanged = true;
}
void QmlProfilerProcessedModel::detailsDone()
{
if (m_emitChanged) {
emit changed();
m_emitChanged = false;
}
// The child models are supposed to synchronously update on changed(), triggered by
// QmlProfilerBaseModel::complete().
QmlProfilerSimpleModel::complete();
}
}
......
......@@ -41,7 +41,7 @@ class QmlProfilerProcessedModel : public QmlProfilerSimpleModel
Q_OBJECT
public:
explicit QmlProfilerProcessedModel(Utils::FileInProjectFinder *fileFinder, QObject *parent = 0);
explicit QmlProfilerProcessedModel(Utils::FileInProjectFinder *fileFinder, QmlProfilerModelManager *parent = 0);
~QmlProfilerProcessedModel();
virtual void clear();
......@@ -53,7 +53,6 @@ private slots:
private:
QmlProfilerDetailsRewriter *m_detailsRewriter;
bool m_emitChanged;
};
}
......
......@@ -39,12 +39,9 @@
namespace QmlProfiler {
QmlProfilerSimpleModel::QmlProfilerSimpleModel(QObject *parent)
: QObject(parent)
QmlProfilerSimpleModel::QmlProfilerSimpleModel(QmlProfilerModelManager *parent)
: QmlProfilerBaseModel(parent)
{
m_modelManager = qobject_cast<QmlProfilerModelManager *>(parent);
Q_ASSERT(m_modelManager);
m_modelId = m_modelManager->registerModelProxy();
}
QmlProfilerSimpleModel::~QmlProfilerSimpleModel()
......@@ -53,9 +50,8 @@ QmlProfilerSimpleModel::~QmlProfilerSimpleModel()
void QmlProfilerSimpleModel::clear()
{
m_modelManager->modelProxyCountUpdated(m_modelId, 0, 1);
eventList.clear();
emit changed();
QmlProfilerBaseModel::clear();
}
bool QmlProfilerSimpleModel::isEmpty() const
......@@ -98,12 +94,6 @@ qint64 QmlProfilerSimpleModel::lastTimeMark() const
return eventList.last().startTime + eventList.last().duration;
}
void QmlProfilerSimpleModel::complete()
{
m_modelManager->modelProxyCountUpdated(m_modelId, isEmpty() ? 0 : 1, 1);
emit changed();
}
QString QmlProfilerSimpleModel::getHashString(const QmlProfilerSimpleModel::QmlEventData &event)
{
return QString::fromLatin1("%1:%2:%3:%4:%5").arg(
......
......@@ -31,6 +31,7 @@
#define QMLPROFILERSIMPLEMODEL_H
#include "qmlprofiler_global.h"
#include "qmlprofilerbasemodel.h"
#include <qmldebug/qmlprofilereventlocation.h>
......@@ -43,7 +44,7 @@ namespace QmlProfiler {
class QmlProfilerModelManager;
// stores the data from the client as-is
class QMLPROFILER_EXPORT QmlProfilerSimpleModel : public QObject
class QMLPROFILER_EXPORT QmlProfilerSimpleModel : public QmlProfilerBaseModel
{
Q_OBJECT
public:
......@@ -62,7 +63,7 @@ public:
qint64 numericData5;
};
explicit QmlProfilerSimpleModel(QObject *parent = 0);
explicit QmlProfilerSimpleModel(QmlProfilerModelManager *parent);
~QmlProfilerSimpleModel();
virtual void clear();
......@@ -72,17 +73,11 @@ public:
void addQmlEvent(int type, int bindingType, qint64 startTime, qint64 duration, const QStringList &data, const QmlDebug::QmlEventLocation &location,
qint64 ndata1, qint64 ndata2, qint64 ndata3, qint64 ndata4, qint64 ndata5);
qint64 lastTimeMark() const;
virtual void complete();
static QString getHashString(const QmlProfilerSimpleModel::QmlEventData &event);
signals:
void changed();
protected:
QVector<QmlEventData> eventList;
QmlProfilerModelManager *m_modelManager;
int m_modelId;
};
}
......
......@@ -261,7 +261,7 @@ void QmlProfilerStateWidget::updateDisplay()
void QmlProfilerStateWidget::dataStateChanged()
{
// consider possible rounding errors
d->loadingDone = d->m_modelManager->progress() >= 0.99 ||
d->loadingDone = d->m_modelManager->state() == QmlProfilerDataState::Done ||
d->m_modelManager->state() == QmlProfilerDataState::Empty;
d->traceAvailable = d->m_modelManager->traceTime()->duration() > 0;
d->emptyList = d->m_modelManager->isEmpty() || d->m_modelManager->progress() == 0;
......
......@@ -28,6 +28,7 @@
****************************************************************************/
#include "qv8profilerdatamodel.h"
#include "qmlprofilermodelmanager.h"
#include <QStringList>
......@@ -107,8 +108,8 @@ public:
qint64 v8MeasuredTime;
};
QV8ProfilerDataModel::QV8ProfilerDataModel(QObject *parent)
: QObject(parent)
QV8ProfilerDataModel::QV8ProfilerDataModel(QmlProfilerModelManager *parent)
: QmlProfilerBaseModel(parent)
, d(new QV8ProfilerDataModelPrivate(this))
{
d->v8MeasuredTime = 0;
......@@ -128,7 +129,7 @@ void QV8ProfilerDataModel::clear()
d->clearV8RootEvent();
d->v8MeasuredTime = 0;
emit changed();
QmlProfilerBaseModel::clear();
}
bool QV8ProfilerDataModel::isEmpty() const
......@@ -482,7 +483,7 @@ void QV8ProfilerDataModel::load(QXmlStreamReader &stream)
void QV8ProfilerDataModel::complete()
{
collectV8Statistics();
emit changed();
QmlProfilerBaseModel::complete();
}
} // namespace Internal
......
......@@ -30,6 +30,8 @@
#ifndef QV8PROFILERDATAMODEL_H
#define QV8PROFILERDATAMODEL_H
#include "qmlprofilerbasemodel.h"
#include <QObject>
#include <QHash>
......@@ -70,11 +72,11 @@ struct QV8EventSub {
qint64 totalTime;
};
class QV8ProfilerDataModel : public QObject
class QV8ProfilerDataModel : public QmlProfilerBaseModel
{
Q_OBJECT
public:
QV8ProfilerDataModel(QObject *parent = 0);
QV8ProfilerDataModel(QmlProfilerModelManager *parent);
~QV8ProfilerDataModel();
void clear();
......@@ -90,9 +92,6 @@ public:
void complete();
signals:
void changed();
public slots:
void addV8Event(int depth,
const QString &function,
......
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