diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2016-12-29 15:02:06 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2017-02-24 11:55:53 +0000 |
commit | c84f650fb2019df63e83316d14a7b97cadcdfa86 (patch) | |
tree | 18dcce0c54aaa4abaf0114436c4aed4049f578e7 /src | |
parent | 78daf47a257a498cffc67cbff6820b5b93dba92e (diff) |
QmlProfiler: Integrate QmlProfilerDataModel into model manager
There is no need to keep them separate as the data model is not
accessed from the outside anymore. This removes a lot of indirection.
Change-Id: I91da4dfa816295300c8cfcca22430d5c5b3298c0
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/qmlprofiler/qmlprofiler.pro | 2 | ||||
-rw-r--r-- | src/plugins/qmlprofiler/qmlprofiler.qbs | 1 | ||||
-rw-r--r-- | src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp | 298 | ||||
-rw-r--r-- | src/plugins/qmlprofiler/qmlprofilerdatamodel.h | 75 | ||||
-rw-r--r-- | src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp | 226 | ||||
-rw-r--r-- | src/plugins/qmlprofiler/qmlprofilermodelmanager.h | 3 |
6 files changed, 192 insertions, 413 deletions
diff --git a/src/plugins/qmlprofiler/qmlprofiler.pro b/src/plugins/qmlprofiler/qmlprofiler.pro index 3d4c392d001..799b627abf9 100644 --- a/src/plugins/qmlprofiler/qmlprofiler.pro +++ b/src/plugins/qmlprofiler/qmlprofiler.pro @@ -21,7 +21,6 @@ SOURCES += \ qmlprofilerbindingloopsrenderpass.cpp \ qmlprofilerclientmanager.cpp \ qmlprofilerconfigwidget.cpp \ - qmlprofilerdatamodel.cpp \ qmlprofilerdetailsrewriter.cpp \ qmlprofilermodelmanager.cpp \ qmlprofilernotesmodel.cpp \ @@ -65,7 +64,6 @@ HEADERS += \ qmlprofilerclientmanager.h \ qmlprofilerconfigwidget.h \ qmlprofilerconstants.h \ - qmlprofilerdatamodel.h \ qmlprofilerdetailsrewriter.h \ qmlprofilereventsview.h \ qmlprofilereventtypes.h \ diff --git a/src/plugins/qmlprofiler/qmlprofiler.qbs b/src/plugins/qmlprofiler/qmlprofiler.qbs index ac6a89e4c6c..5202d0eb375 100644 --- a/src/plugins/qmlprofiler/qmlprofiler.qbs +++ b/src/plugins/qmlprofiler/qmlprofiler.qbs @@ -38,7 +38,6 @@ QtcPlugin { "qmlprofilerclientmanager.cpp", "qmlprofilerclientmanager.h", "qmlprofilerconfigwidget.cpp", "qmlprofilerconfigwidget.h", "qmlprofilerconfigwidget.ui", "qmlprofilerconstants.h", - "qmlprofilerdatamodel.cpp", "qmlprofilerdatamodel.h", "qmlprofilerdetailsrewriter.cpp", "qmlprofilerdetailsrewriter.h", "qmlprofilereventsview.h", "qmlprofilereventtypes.h", diff --git a/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp b/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp deleted file mode 100644 index b7e3abffd57..00000000000 --- a/src/plugins/qmlprofiler/qmlprofilerdatamodel.cpp +++ /dev/null @@ -1,298 +0,0 @@ -/**************************************************************************** -** -** 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 "qmlprofilerdatamodel.h" -#include "qmlprofilermodelmanager.h" -#include "qmlprofilernotesmodel.h" -#include "qmlprofilerdetailsrewriter.h" -#include "qmlprofilereventtypes.h" -#include "qmltypedevent.h" - -#include <utils/qtcassert.h> -#include <utils/temporaryfile.h> - -#include <QUrl> -#include <QDebug> -#include <QStack> -#include <algorithm> - -namespace QmlProfiler { - -class QmlProfilerDataModel::QmlProfilerDataModelPrivate -{ -public: - QmlProfilerDataModelPrivate() : file("qmlprofiler-data") { } - void rewriteType(int typeIndex); - int resolveStackTop(); - - QVector<QmlEventType> eventTypes; - Internal::QmlProfilerDetailsRewriter *detailsRewriter = 0; - - Utils::TemporaryFile file; - QDataStream eventStream; -}; - -QString getDisplayName(const QmlEventType &event) -{ - if (event.location().filename().isEmpty()) { - return QmlProfilerModelManager::tr("<bytecode>"); - } else { - const QString filePath = QUrl(event.location().filename()).path(); - return filePath.mid(filePath.lastIndexOf(QLatin1Char('/')) + 1) + QLatin1Char(':') + - QString::number(event.location().line()); - } -} - -QString getInitialDetails(const QmlEventType &event) -{ - QString details = event.data(); - // generate details string - if (!details.isEmpty()) { - details = details.replace(QLatin1Char('\n'),QLatin1Char(' ')).simplified(); - if (details.isEmpty()) { - if (event.rangeType() == Javascript) - details = QmlProfilerDataModel::tr("anonymous function"); - } else { - QRegExp rewrite(QLatin1String("\\(function \\$(\\w+)\\(\\) \\{ (return |)(.+) \\}\\)")); - bool match = rewrite.exactMatch(details); - if (match) - details = rewrite.cap(1) + QLatin1String(": ") + rewrite.cap(3); - if (details.startsWith(QLatin1String("file://")) || - details.startsWith(QLatin1String("qrc:/"))) - details = details.mid(details.lastIndexOf(QLatin1Char('/')) + 1); - } - } else if (event.rangeType() == Painting) { - // QtQuick1 animations always run in GUI thread. - details = QmlProfilerDataModel::tr("GUI Thread"); - } - - return details; -} - -QmlProfilerDataModel::QmlProfilerDataModel(QObject *parent) : - QObject(parent), d_ptr(new QmlProfilerDataModelPrivate) -{ - Q_D(QmlProfilerDataModel); - Q_ASSERT(parent); - d->detailsRewriter = new QmlProfilerDetailsRewriter(this); - connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::rewriteDetailsString, - this, &QmlProfilerDataModel::detailsChanged); - connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::eventDetailsChanged, - this, &QmlProfilerDataModel::allTypesLoaded); - if (!d->file.open()) - emit traceFileError(); - else - d->eventStream.setDevice(&d->file); -} - -QmlProfilerDataModel::~QmlProfilerDataModel() -{ - Q_D(QmlProfilerDataModel); - delete d; -} - -const QmlEventType &QmlProfilerDataModel::eventType(int typeId) const -{ - Q_D(const QmlProfilerDataModel); - return d->eventTypes.at(typeId); -} - -const QVector<QmlEventType> &QmlProfilerDataModel::eventTypes() const -{ - Q_D(const QmlProfilerDataModel); - return d->eventTypes; -} - -void QmlProfilerDataModel::addEventTypes(const QVector<QmlEventType> &types) -{ - Q_D(QmlProfilerDataModel); - int typeIndex = d->eventTypes.length(); - d->eventTypes.append(types); - for (const int end = d->eventTypes.length(); typeIndex < end; ++typeIndex) - d->rewriteType(typeIndex); -} - -void QmlProfilerDataModel::addEventType(const QmlEventType &type) -{ - Q_D(QmlProfilerDataModel); - int typeIndex = d->eventTypes.length(); - d->eventTypes.append(type); - d->rewriteType(typeIndex); -} - -void QmlProfilerDataModel::populateFileFinder( - const ProjectExplorer::RunConfiguration *runConfiguration) -{ - Q_D(QmlProfilerDataModel); - d->detailsRewriter->populateFileFinder(runConfiguration); -} - -QString QmlProfilerDataModel::findLocalFile(const QString &remoteFile) -{ - Q_D(QmlProfilerDataModel); - return d->detailsRewriter->getLocalFile(remoteFile); -} - -void QmlProfilerDataModel::addEvent(const QmlEvent &event) -{ - Q_D(QmlProfilerDataModel); - d->eventStream << event; -} - -void QmlProfilerDataModel::addEvents(const QVector<QmlEvent> &events) -{ - Q_D(QmlProfilerDataModel); - for (const QmlEvent &event : events) - d->eventStream << event; -} - -void QmlProfilerDataModel::clear() -{ - Q_D(QmlProfilerDataModel); - d->file.remove(); - d->eventStream.unsetDevice(); - if (!d->file.open()) - emit traceFileError(); - else - d->eventStream.setDevice(&d->file); - d->eventTypes.clear(); - d->detailsRewriter->clearRequests(); -} - -bool QmlProfilerDataModel::isEmpty() const -{ - Q_D(const QmlProfilerDataModel); - return d->file.pos() == 0; -} - -void QmlProfilerDataModel::QmlProfilerDataModelPrivate::rewriteType(int typeIndex) -{ - QmlEventType &type = eventTypes[typeIndex]; - type.setDisplayName(getDisplayName(type)); - type.setData(getInitialDetails(type)); - - const QmlEventLocation &location = type.location(); - // There is no point in looking for invalid locations - if (!location.isValid()) - return; - - // Only bindings and signal handlers need rewriting - if (type.rangeType() == Binding || type.rangeType() == HandlingSignal) - detailsRewriter->requestDetailsForLocation(typeIndex, location); -} - -static bool isStateful(const QmlEventType &type) -{ - // Events of these types carry state that has to be taken into account when adding later events: - // PixmapCacheEvent: Total size of the cache and size of pixmap currently being loaded - // MemoryAllocation: Total size of the JS heap and the amount of it currently in use - const Message message = type.message(); - return message == PixmapCacheEvent || message == MemoryAllocation; -} - -bool QmlProfilerDataModel::replayEvents(qint64 rangeStart, qint64 rangeEnd, - QmlProfilerModelManager::EventLoader loader) const -{ - Q_D(const QmlProfilerDataModel); - QStack<QmlEvent> stack; - QmlEvent event; - QFile file(d->file.fileName()); - if (!file.open(QIODevice::ReadOnly)) - 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) { - // Double-check if rangeStart has been crossed. Some versions of Qt send dirty data. - if (event.timestamp() < rangeStart && !crossedRangeStart) { - if (type.rangeType() != MaximumRangeType) { - if (event.rangeStage() == RangeStart) - stack.push(event); - else if (event.rangeStage() == RangeEnd) - stack.pop(); - continue; - } else if (isStateful(type)) { - event.setTimestamp(rangeStart); - } else { - continue; - } - } else { - if (!crossedRangeStart) { - foreach (QmlEvent stashed, stack) { - stashed.setTimestamp(rangeStart); - loader(stashed, d->eventTypes[stashed.typeIndex()]); - } - stack.clear(); - crossedRangeStart = true; - } - if (event.timestamp() > rangeEnd) { - if (type.rangeType() != MaximumRangeType) { - if (event.rangeStage() == RangeEnd) { - if (stack.isEmpty()) { - QmlEvent endEvent(event); - endEvent.setTimestamp(rangeEnd); - loader(endEvent, d->eventTypes[event.typeIndex()]); - } else { - stack.pop(); - } - } else if (event.rangeStage() == RangeStart) { - stack.push(event); - } - continue; - } else if (isStateful(type)) { - event.setTimestamp(rangeEnd); - } else { - continue; - } - } - } - } - - loader(event, type); - } - return true; -} - -void QmlProfilerDataModel::finalize() -{ - Q_D(QmlProfilerDataModel); - d->file.flush(); - d->detailsRewriter->reloadDocuments(); -} - -void QmlProfilerDataModel::detailsChanged(int typeId, const QString &newString) -{ - Q_D(QmlProfilerDataModel); - QTC_ASSERT(typeId < d->eventTypes.count(), return); - d->eventTypes[typeId].setData(newString); -} - -} // namespace QmlProfiler diff --git a/src/plugins/qmlprofiler/qmlprofilerdatamodel.h b/src/plugins/qmlprofiler/qmlprofilerdatamodel.h deleted file mode 100644 index 66ba9f6e887..00000000000 --- a/src/plugins/qmlprofiler/qmlprofilerdatamodel.h +++ /dev/null @@ -1,75 +0,0 @@ -/**************************************************************************** -** -** 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 "qmlprofilermodelmanager.h" -#include "qmlprofilereventtypes.h" -#include "qmleventlocation.h" -#include "qmleventtype.h" -#include "qmlevent.h" - -#include <utils/fileinprojectfinder.h> -#include <projectexplorer/runconfiguration.h> - -namespace QmlProfiler { - -class QMLPROFILER_EXPORT QmlProfilerDataModel : public QObject -{ - Q_OBJECT -public: - explicit QmlProfilerDataModel(QObject *parent = nullptr); - ~QmlProfilerDataModel(); - - const QmlEventType &eventType(int typeId) const; - const QVector<QmlEventType> &eventTypes() const; - void addEventTypes(const QVector<QmlEventType> &types); - void addEventType(const QmlEventType &type); - - void populateFileFinder(const ProjectExplorer::RunConfiguration *runConfiguration = nullptr); - QString findLocalFile(const QString &remoteFile); - - void clear(); - bool isEmpty() const; - void addEvent(const QmlEvent &event); - void addEvents(const QVector<QmlEvent> &events); - bool replayEvents(qint64 startTime, qint64 endTime, - QmlProfilerModelManager::EventLoader loader) const; - void finalize(); - -signals: - void allTypesLoaded(); - void traceFileError(); - -protected slots: - void detailsChanged(int typeId, const QString &newString); - -private: - class QmlProfilerDataModelPrivate; - QmlProfilerDataModelPrivate *d_ptr; - Q_DECLARE_PRIVATE(QmlProfilerDataModel) -}; - -} // namespace QmlProfiler diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp index 4eca2d3c8af..5af506302cf 100644 --- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp @@ -25,17 +25,19 @@ #include "qmlprofilermodelmanager.h" #include "qmlprofilerconstants.h" -#include "qmlprofilerdatamodel.h" #include "qmlprofilertracefile.h" #include "qmlprofilernotesmodel.h" +#include "qmlprofilerdetailsrewriter.h" #include <coreplugin/progressmanager/progressmanager.h> #include <utils/runextensions.h> #include <utils/qtcassert.h> +#include <utils/temporaryfile.h> #include <QDebug> #include <QFile> #include <QMessageBox> +#include <QStack> #include <functional> @@ -136,7 +138,8 @@ void QmlProfilerTraceTime::restrictToRange(qint64 startTime, qint64 endTime) class QmlProfilerModelManager::QmlProfilerModelManagerPrivate { public: - QmlProfilerDataModel *model; + QmlProfilerModelManagerPrivate() : file("qmlprofiler-data") {} + QmlProfilerNotesModel *notesModel; QmlProfilerTextMarkModel *textMarkModel; @@ -155,7 +158,15 @@ public: QHash<ProfileFeature, QVector<EventLoader> > eventLoaders; QVector<Finalizer> finalizers; + QVector<QmlEventType> eventTypes; + QmlProfilerDetailsRewriter *detailsRewriter; + + Utils::TemporaryFile file; + QDataStream eventStream; + void dispatch(const QmlEvent &event, const QmlEventType &type); + void rewriteType(int typeIndex); + int resolveStackTop(); }; @@ -169,17 +180,21 @@ QmlProfilerModelManager::QmlProfilerModelManager(QObject *parent) : d->visibleFeatures = 0; d->recordedFeatures = 0; d->aggregateTraces = false; - d->model = new QmlProfilerDataModel(this); d->state = Empty; d->traceTime = new QmlProfilerTraceTime(this); d->notesModel = new QmlProfilerNotesModel(this); d->textMarkModel = new QmlProfilerTextMarkModel(this); - connect(d->model, &QmlProfilerDataModel::allTypesLoaded, + + d->detailsRewriter = new QmlProfilerDetailsRewriter(this); + connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::rewriteDetailsString, + this, &QmlProfilerModelManager::detailsChanged); + connect(d->detailsRewriter, &QmlProfilerDetailsRewriter::eventDetailsChanged, this, &QmlProfilerModelManager::processingDone); - connect(d->model, &QmlProfilerDataModel::traceFileError, - this, [this]() { - emit error(tr("Could not open a temporary file for storing QML traces.")); - }); + + if (d->file.open()) + d->eventStream.setDevice(&d->file); + else + emit error(tr("Cannot open temporary trace file to store events.")); } QmlProfilerModelManager::~QmlProfilerModelManager() @@ -204,7 +219,7 @@ QmlProfilerTextMarkModel *QmlProfilerModelManager::textMarkModel() const bool QmlProfilerModelManager::isEmpty() const { - return d->model->isEmpty(); + return d->file.pos() == 0; } uint QmlProfilerModelManager::numLoadedEvents() const @@ -214,7 +229,7 @@ uint QmlProfilerModelManager::numLoadedEvents() const uint QmlProfilerModelManager::numLoadedEventTypes() const { - return d->model->eventTypes().count(); + return d->eventTypes.count(); } int QmlProfilerModelManager::registerModelProxy() @@ -234,28 +249,28 @@ int QmlProfilerModelManager::numRegisteredFinalizers() const void QmlProfilerModelManager::addEvents(const QVector<QmlEvent> &events) { - d->model->addEvents(events); - const QVector<QmlEventType> &types = d->model->eventTypes(); - for (const QmlEvent &event : events) - d->dispatch(event, types[event.typeIndex()]); + for (const QmlEvent &event : events) { + d->eventStream << event; + d->dispatch(event, d->eventTypes[event.typeIndex()]); + } } void QmlProfilerModelManager::addEvent(const QmlEvent &event) { - d->model->addEvent(event); - d->dispatch(event, d->model->eventType(event.typeIndex())); + d->eventStream << event; + d->dispatch(event, d->eventTypes.at(event.typeIndex())); } void QmlProfilerModelManager::addEventTypes(const QVector<QmlEventType> &types) { - const int firstTypeId = d->model->eventTypes().count(); - d->model->addEventTypes(types); - for (int i = 0, end = types.length(); i < end; ++i) { - const QmlEventLocation &location = types[i].location(); + 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( - firstTypeId + i, QmlEventLocation( - d->model->findLocalFile(location.filename()), location.line(), + d->textMarkModel->addTextMarkId(typeId, QmlEventLocation( + findLocalFile(location.filename()), location.line(), location.column())); } } @@ -263,25 +278,97 @@ void QmlProfilerModelManager::addEventTypes(const QVector<QmlEventType> &types) void QmlProfilerModelManager::addEventType(const QmlEventType &type) { - const int typeId = d->model->eventTypes().count(); - d->model->addEventType(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(d->model->findLocalFile(location.filename()), + typeId, QmlEventLocation(findLocalFile(location.filename()), location.line(), location.column())); } } const QVector<QmlEventType> &QmlProfilerModelManager::eventTypes() const { - return d->model->eventTypes(); + return d->eventTypes; } -bool QmlProfilerModelManager::replayEvents(qint64 startTime, qint64 endTime, +static bool isStateful(const QmlEventType &type) +{ + // Events of these types carry state that has to be taken into account when adding later events: + // PixmapCacheEvent: Total size of the cache and size of pixmap currently being loaded + // MemoryAllocation: Total size of the JS heap and the amount of it currently in use + const Message message = type.message(); + return message == PixmapCacheEvent || message == MemoryAllocation; +} + +bool QmlProfilerModelManager::replayEvents(qint64 rangeStart, qint64 rangeEnd, EventLoader loader) const { - return d->model->replayEvents(startTime, endTime, loader); + QStack<QmlEvent> stack; + QmlEvent event; + QFile file(d->file.fileName()); + if (!file.open(QIODevice::ReadOnly)) + 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) { + // Double-check if rangeStart has been crossed. Some versions of Qt send dirty data. + if (event.timestamp() < rangeStart && !crossedRangeStart) { + if (type.rangeType() != MaximumRangeType) { + if (event.rangeStage() == RangeStart) + stack.push(event); + else if (event.rangeStage() == RangeEnd) + stack.pop(); + continue; + } else if (isStateful(type)) { + event.setTimestamp(rangeStart); + } else { + continue; + } + } else { + if (!crossedRangeStart) { + foreach (QmlEvent stashed, stack) { + stashed.setTimestamp(rangeStart); + loader(stashed, d->eventTypes[stashed.typeIndex()]); + } + stack.clear(); + crossedRangeStart = true; + } + if (event.timestamp() > rangeEnd) { + if (type.rangeType() != MaximumRangeType) { + if (event.rangeStage() == RangeEnd) { + if (stack.isEmpty()) { + QmlEvent endEvent(event); + endEvent.setTimestamp(rangeEnd); + loader(endEvent, d->eventTypes[event.typeIndex()]); + } else { + stack.pop(); + } + } else if (event.rangeStage() == RangeStart) { + stack.push(event); + } + continue; + } else if (isStateful(type)) { + event.setTimestamp(rangeEnd); + } else { + continue; + } + } + } + } + + loader(event, type); + } + return true; } void QmlProfilerModelManager::QmlProfilerModelManagerPrivate::dispatch(const QmlEvent &event, @@ -292,6 +379,59 @@ void QmlProfilerModelManager::QmlProfilerModelManagerPrivate::dispatch(const Qml ++numLoadedEvents; } +static QString getDisplayName(const QmlEventType &event) +{ + if (event.location().filename().isEmpty()) { + return QmlProfilerModelManager::tr("<bytecode>"); + } else { + const QString filePath = QUrl(event.location().filename()).path(); + return filePath.mid(filePath.lastIndexOf(QLatin1Char('/')) + 1) + QLatin1Char(':') + + QString::number(event.location().line()); + } +} + +static QString getInitialDetails(const QmlEventType &event) +{ + QString details = event.data(); + // generate details string + if (!details.isEmpty()) { + details = details.replace(QLatin1Char('\n'),QLatin1Char(' ')).simplified(); + if (details.isEmpty()) { + if (event.rangeType() == Javascript) + details = QmlProfilerModelManager::tr("anonymous function"); + } else { + QRegExp rewrite(QLatin1String("\\(function \\$(\\w+)\\(\\) \\{ (return |)(.+) \\}\\)")); + bool match = rewrite.exactMatch(details); + if (match) + details = rewrite.cap(1) + QLatin1String(": ") + rewrite.cap(3); + if (details.startsWith(QLatin1String("file://")) || + details.startsWith(QLatin1String("qrc:/"))) + details = details.mid(details.lastIndexOf(QLatin1Char('/')) + 1); + } + } else if (event.rangeType() == Painting) { + // QtQuick1 animations always run in GUI thread. + details = QmlProfilerModelManager::tr("GUI Thread"); + } + + return details; +} + +void QmlProfilerModelManager::QmlProfilerModelManagerPrivate::rewriteType(int typeIndex) +{ + QmlEventType &type = eventTypes[typeIndex]; + type.setDisplayName(getDisplayName(type)); + type.setData(getInitialDetails(type)); + + const QmlEventLocation &location = type.location(); + // There is no point in looking for invalid locations + if (!location.isValid()) + return; + + // Only bindings and signal handlers need rewriting + if (type.rangeType() == Binding || type.rangeType() == HandlingSignal) + detailsRewriter->requestDetailsForLocation(typeIndex, location); +} + void QmlProfilerModelManager::announceFeatures(quint64 features, EventLoader eventLoader, Finalizer finalizer) { @@ -363,7 +503,8 @@ void QmlProfilerModelManager::acquiringDone() { QTC_ASSERT(state() == AcquiringData, /**/); setState(ProcessingData); - d->model->finalize(); + d->file.flush(); + d->detailsRewriter->reloadDocuments(); } void QmlProfilerModelManager::processingDone() @@ -383,12 +524,12 @@ void QmlProfilerModelManager::processingDone() void QmlProfilerModelManager::populateFileFinder(const ProjectExplorer::RunConfiguration *runConfiguration) { - d->model->populateFileFinder(runConfiguration); + d->detailsRewriter->populateFileFinder(runConfiguration); } QString QmlProfilerModelManager::findLocalFile(const QString &remoteFile) { - return d->model->findLocalFile(remoteFile); + return d->detailsRewriter->getLocalFile(remoteFile); } void QmlProfilerModelManager::save(const QString &filename) @@ -534,6 +675,12 @@ void QmlProfilerModelManager::setState(QmlProfilerModelManager::State state) emit stateChanged(); } +void QmlProfilerModelManager::detailsChanged(int typeId, const QString &newString) +{ + QTC_ASSERT(typeId < d->eventTypes.count(), return); + d->eventTypes[typeId].setData(newString); +} + QmlProfilerModelManager::State QmlProfilerModelManager::state() const { return d->state; @@ -544,7 +691,14 @@ void QmlProfilerModelManager::clear() setState(ClearingData); d->numLoadedEvents = 0; d->numFinishedFinalizers = 0; - d->model->clear(); + 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->eventTypes.clear(); + d->detailsRewriter->clearRequests(); d->traceTime->clear(); d->notesModel->clear(); setVisibleFeatures(0); @@ -563,9 +717,9 @@ void QmlProfilerModelManager::restrictToRange(qint64 startTime, qint64 endTime) setVisibleFeatures(0); startAcquiring(); - if (!d->model->replayEvents(startTime, endTime, - std::bind(&QmlProfilerModelManagerPrivate::dispatch, d, - std::placeholders::_1, std::placeholders::_2))) { + 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(); diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.h b/src/plugins/qmlprofiler/qmlprofilermodelmanager.h index d1ea5a01a4b..91fc6b278cb 100644 --- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.h +++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.h @@ -115,7 +115,7 @@ public: void addEventType(const QmlEventType &type); const QVector<QmlEventType> &eventTypes() const; - bool replayEvents(qint64 startTime, qint64 endTime, EventLoader loader) const; + bool replayEvents(qint64 rangeStart, qint64 rangeEnd, EventLoader loader) const; quint64 availableFeatures() const; quint64 visibleFeatures() const; @@ -155,6 +155,7 @@ public slots: private: void setState(State state); + void detailsChanged(int typeId, const QString &newString); private: class QmlProfilerModelManagerPrivate; |