Commit 6d58de0b authored by Ulf Hermann's avatar Ulf Hermann
Browse files

QmlProfiler: Allow preselection of events to be recorded



This allows us to reduce the amount of data we need to handle
if the user isn't interested in certain categories.

Task-number: QTBUG-41118
Change-Id: Ieaac12fb1dec29d6035642f433bc1a1d49e545c2
Reviewed-by: default avatarKai Koehne <kai.koehne@digia.com>
parent 7290c43d
......@@ -120,8 +120,31 @@ enum AnimationThread {
MaximumAnimationThread
};
enum ProfileFeature {
ProfileJavaScript,
ProfileMemory,
ProfilePixmapCache,
ProfileSceneGraph,
ProfileAnimations,
ProfilePainting,
ProfileCompiling,
ProfileCreating,
ProfileBinding,
ProfileHandlingSignal,
ProfileInputEvents,
MaximumProfileFeature
};
namespace Constants {
const int QML_MIN_LEVEL = 1; // Set to 0 to remove the empty line between models in the timeline
// Shorthand for all QML and JS range features.
const quint64 QML_JS_RANGE_FEATURES = (1 << ProfileCompiling) |
(1 << ProfileCreating) |
(1 << ProfileBinding) |
(1 << ProfileHandlingSignal) |
(1 << ProfileJavaScript);
}
} // namespace QmlDebug
......
......@@ -40,6 +40,7 @@ public:
, inProgressRanges(0)
, maximumTime(0)
, recording(false)
, features(0)
{
::memset(rangeCount, 0, MaximumRangeType * sizeof(int));
}
......@@ -56,6 +57,7 @@ public:
int rangeCount[MaximumRangeType];
qint64 maximumTime;
bool recording;
quint64 features;
};
} // namespace QmlDebug
......@@ -68,16 +70,17 @@ void QmlProfilerTraceClientPrivate::sendRecordingStatus(int engineId)
{
QByteArray ba;
QDataStream stream(&ba, QIODevice::WriteOnly);
stream << recording;
if (engineId != -1)
stream << engineId;
stream << recording << engineId; // engineId -1 is OK. It means "all of them"
if (recording)
stream << features;
q->sendMessage(ba);
}
QmlProfilerTraceClient::QmlProfilerTraceClient(QmlDebugConnection *client)
QmlProfilerTraceClient::QmlProfilerTraceClient(QmlDebugConnection *client, quint64 features)
: QmlDebugClient(QLatin1String("CanvasFrameRate"), client)
, d(new QmlProfilerTraceClientPrivate(this, client))
{
d->features = features;
connect(&d->engineControl, SIGNAL(engineAboutToBeAdded(int,QString)),
this, SLOT(sendRecordingStatus(int)));
}
......@@ -131,6 +134,11 @@ void QmlProfilerTraceClient::setRecording(bool v)
emit recordingChanged(v);
}
void QmlProfilerTraceClient::setFeatures(quint64 features)
{
d->features = features;
}
void QmlProfilerTraceClient::setRecordingFromServer(bool v)
{
if (v == d->recording)
......
......@@ -50,7 +50,7 @@ class QMLDEBUG_EXPORT QmlProfilerTraceClient : public QmlDebug::QmlDebugClient
using QObject::event;
public:
QmlProfilerTraceClient(QmlDebugConnection *client);
QmlProfilerTraceClient(QmlDebugConnection *client, quint64 features);
~QmlProfilerTraceClient();
bool isEnabled() const;
......@@ -60,6 +60,7 @@ public:
public slots:
void clearData();
void sendRecordingStatus(int engineId = -1);
void setFeatures(quint64 features);
signals:
void complete(qint64 maximumTime);
......
......@@ -59,6 +59,7 @@ void AbstractTimelineModel::setModelManager(QmlProfilerModelManager *modelManage
d->modelManager = modelManager;
connect(d->modelManager->qmlModel(),SIGNAL(changed()),this,SLOT(dataChanged()));
d->modelId = d->modelManager->registerModelProxy();
d->modelManager->announceFeatures(d->modelId, features());
}
bool AbstractTimelineModel::isEmpty() const
......
......@@ -74,6 +74,7 @@ public:
virtual QVariantMap details(int index) const = 0;
virtual int row(int index) const = 0;
virtual void loadData() = 0;
virtual quint64 features() const = 0;
// Methods which can optionally be implemented by child models.
// returned map should contain "file", "line", "column" properties, or be empty
......
......@@ -162,7 +162,8 @@ void QmlProfilerClientManager::enableServices()
disconnectClientSignals();
d->profilerState->setServerRecording(false); // false by default (will be set to true when connected)
delete d->qmlclientplugin.data();
d->qmlclientplugin = new QmlProfilerTraceClient(d->connection);
d->qmlclientplugin = new QmlProfilerTraceClient(d->connection,
d->profilerState->recordingFeatures());
delete d->v8clientplugin.data();
d->v8clientplugin = new QV8ProfilerClient(d->connection);
connectClientSignals();
......@@ -191,6 +192,8 @@ void QmlProfilerClientManager::connectClientSignals()
// fixme: this should be unified for both clients
connect(d->qmlclientplugin.data(), SIGNAL(recordingChanged(bool)),
d->profilerState, SLOT(setServerRecording(bool)));
connect(d->profilerState, SIGNAL(recordingFeaturesChanged(quint64)),
d->qmlclientplugin.data(), SLOT(setFeatures(quint64)));
}
if (d->v8clientplugin) {
connect(d->v8clientplugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
......@@ -223,6 +226,8 @@ void QmlProfilerClientManager::disconnectClientSignals()
// fixme: this should be unified for both clients
disconnect(d->qmlclientplugin.data(), SIGNAL(recordingChanged(bool)),
d->profilerState, SLOT(setServerRecording(bool)));
disconnect(d->profilerState, SIGNAL(recordingFeaturesChanged(quint64)),
d->qmlclientplugin.data(), SLOT(setFeatures(quint64)));
}
if (d->v8clientplugin) {
disconnect(d->v8clientplugin.data(), SIGNAL(complete()), this, SLOT(v8Complete()));
......
......@@ -74,6 +74,8 @@ QmlProfilerEventsModelProxy::QmlProfilerEventsModelProxy(QmlProfilerModelManager
modelManager->setProxyCountWeight(d->modelId, 2);
d->acceptedTypes << QmlDebug::Compiling << QmlDebug::Creating << QmlDebug::Binding << QmlDebug::HandlingSignal << QmlDebug::Javascript;
modelManager->announceFeatures(d->modelId, QmlDebug::Constants::QML_JS_RANGE_FEATURES);
}
QmlProfilerEventsModelProxy::~QmlProfilerEventsModelProxy()
......
......@@ -40,6 +40,19 @@
namespace QmlProfiler {
namespace Internal {
static const char *ProfileFeatureNames[QmlDebug::MaximumProfileFeature] = {
QT_TRANSLATE_NOOP("MainView", "JavaScript"),
QT_TRANSLATE_NOOP("MainView", "Memory Usage"),
QT_TRANSLATE_NOOP("MainView", "Pixmap Cache"),
QT_TRANSLATE_NOOP("MainView", "Scene Graph"),
QT_TRANSLATE_NOOP("MainView", "Animations"),
QT_TRANSLATE_NOOP("MainView", "Painting"),
QT_TRANSLATE_NOOP("MainView", "Compiling"),
QT_TRANSLATE_NOOP("MainView", "Creating"),
QT_TRANSLATE_NOOP("MainView", "Binding"),
QT_TRANSLATE_NOOP("MainView", "Handling Signal"),
QT_TRANSLATE_NOOP("MainView", "Input Events")
};
/////////////////////////////////////////////////////////////////////
QmlProfilerDataState::QmlProfilerDataState(QmlProfilerModelManager *modelManager, QObject *parent)
......@@ -163,6 +176,8 @@ public:
QVector <double> partialCounts;
QVector <int> partialCountWeights;
quint64 features;
int totalWeight;
double progress;
double previousProgress;
......@@ -251,6 +266,25 @@ void QmlProfilerModelManager::modelProxyCountUpdated(int proxyId, qint64 count,
}
}
void QmlProfilerModelManager::announceFeatures(int proxyId, quint64 features)
{
Q_UNUSED(proxyId); // Will use that later to optimize the event dispatching on loading.
if ((features & d->features) != features) {
d->features |= features;
emit availableFeaturesChanged(d->features);
}
}
quint64 QmlProfilerModelManager::availableFeatures()
{
return d->features;
}
const char *QmlProfilerModelManager::featureName(QmlDebug::ProfileFeature feature)
{
return ProfileFeatureNames[feature];
}
qint64 QmlProfilerModelManager::estimatedProfilingTime() const
{
return d->estimatedTime;
......
......@@ -127,6 +127,9 @@ public:
int registerModelProxy();
void setProxyCountWeight(int proxyId, int weight);
void modelProxyCountUpdated(int proxyId, qint64 count, qint64 max);
void announceFeatures(int proxyId, quint64 features);
quint64 availableFeatures();
static const char *featureName(QmlDebug::ProfileFeature feature);
qint64 estimatedProfilingTime() const;
......@@ -137,6 +140,7 @@ signals:
void dataAvailable();
void requestDetailsForLocation(int eventType, const QmlDebug::QmlEventLocation &location);
void availableFeaturesChanged(quint64 features);
public slots:
void clear();
......
......@@ -58,13 +58,18 @@ private:
};
PaintEventsModelProxy::PaintEventsModelProxy(QObject *parent)
: AbstractTimelineModel(new PaintEventsModelProxyPrivate, tr("Animations"), QmlDebug::Event,
QmlDebug::MaximumRangeType, parent)
: AbstractTimelineModel(new PaintEventsModelProxyPrivate,
tr(QmlProfilerModelManager::featureName(QmlDebug::ProfileAnimations)),
QmlDebug::Event, QmlDebug::MaximumRangeType, parent)
{
Q_D(PaintEventsModelProxy);
d->maxGuiThreadAnimations = d->maxRenderThreadAnimations = 0;
}
quint64 PaintEventsModelProxy::features() const
{
return 1 << QmlDebug::ProfileAnimations;
}
void PaintEventsModelProxy::clear()
{
......
......@@ -75,6 +75,7 @@ public:
QVariantList labels() const;
QVariantMap details(int index) const;
quint64 features() const;
private slots:
bool accepted(const QmlProfilerDataModel::QmlEventTypeData &event) const;
......
......@@ -64,6 +64,7 @@ public:
QmlProfilerStateManager::QmlProfilerState m_currentState;
bool m_clientRecording;
bool m_serverRecording;
quint64 m_recordingFeatures;
};
QmlProfilerStateManager::QmlProfilerStateManager(QObject *parent) :
QObject(parent),d(new QmlProfilerStateManagerPrivate(this))
......@@ -71,6 +72,7 @@ QmlProfilerStateManager::QmlProfilerStateManager(QObject *parent) :
d->m_currentState = Idle;
d->m_clientRecording = true;
d->m_serverRecording = false;
d->m_recordingFeatures = 0;
}
QmlProfilerStateManager::~QmlProfilerStateManager()
......@@ -93,6 +95,11 @@ bool QmlProfilerStateManager::serverRecording()
return d->m_serverRecording;
}
quint64 QmlProfilerStateManager::recordingFeatures() const
{
return d->m_recordingFeatures;
}
QString QmlProfilerStateManager::currentStateAsString()
{
return stringForState(d->m_currentState);
......@@ -173,5 +180,13 @@ void QmlProfilerStateManager::setServerRecording(bool recording)
}
}
void QmlProfilerStateManager::setRecordingFeatures(quint64 features)
{
if (d->m_recordingFeatures != features) {
d->m_recordingFeatures = features;
emit recordingFeaturesChanged(features);
}
}
}
}
......@@ -56,6 +56,7 @@ public:
QmlProfilerState currentState();
bool clientRecording();
bool serverRecording();
quint64 recordingFeatures() const;
QString currentStateAsString();
......@@ -63,11 +64,13 @@ signals:
void stateChanged();
void clientRecordingChanged();
void serverRecordingChanged();
void recordingFeaturesChanged(quint64);
public slots:
void setCurrentState(QmlProfilerState newState);
void setClientRecording(bool recording);
void setServerRecording(bool recording);
void setRecordingFeatures(quint64 features);
private:
class QmlProfilerStateManagerPrivate;
......
......@@ -44,6 +44,15 @@
namespace QmlProfiler {
namespace Internal {
static const QmlDebug::ProfileFeature RangeFeatures[QmlDebug::MaximumRangeType] = {
QmlDebug::ProfilePainting,
QmlDebug::ProfileCompiling,
QmlDebug::ProfileCreating,
QmlDebug::ProfileBinding,
QmlDebug::ProfileHandlingSignal,
QmlDebug::ProfileJavaScript
};
class RangeTimelineModel::RangeTimelineModelPrivate : public AbstractTimelineModelPrivate
{
public:
......@@ -70,6 +79,12 @@ RangeTimelineModel::RangeTimelineModel(QmlDebug::RangeType rangeType, QObject *p
d->contractedRows = 1;
}
quint64 RangeTimelineModel::features() const
{
Q_D(const RangeTimelineModel);
return 1 << RangeFeatures[d->rangeType];
}
void RangeTimelineModel::clear()
{
Q_D(RangeTimelineModel);
......@@ -222,16 +237,19 @@ int RangeTimelineModel::rowCount() const
return d->contractedRows;
}
QString RangeTimelineModel::categoryLabel(int categoryIndex)
QString RangeTimelineModel::categoryLabel(QmlDebug::RangeType rangeType)
{
switch (categoryIndex) {
case 0: return QCoreApplication::translate("MainView", "Painting"); break;
case 1: return QCoreApplication::translate("MainView", "Compiling"); break;
case 2: return QCoreApplication::translate("MainView", "Creating"); break;
case 3: return QCoreApplication::translate("MainView", "Binding"); break;
case 4: return QCoreApplication::translate("MainView", "Handling Signal"); break;
case 5: return QCoreApplication::translate("MainView", "JavaScript"); break;
default: return QString();
switch (rangeType) {
case QmlDebug::Painting:
case QmlDebug::Compiling:
case QmlDebug::Creating:
case QmlDebug::Binding:
case QmlDebug::HandlingSignal:
case QmlDebug::Javascript:
return QCoreApplication::translate("MainView",
QmlProfilerModelManager::featureName(RangeFeatures[rangeType]));
default:
return QString();
}
}
......
......@@ -72,7 +72,8 @@ public:
// QML interface
int rowCount() const;
static QString categoryLabel(int categoryIndex);
static QString categoryLabel(QmlDebug::RangeType categoryIndex);
quint64 features() const;
int row(int index) const;
int eventId(int index) const;
......
......@@ -81,11 +81,13 @@ using namespace Core;
using namespace Core::Constants;
using namespace Analyzer;
using namespace Analyzer::Constants;
using namespace QmlProfiler::Internal;
using namespace QmlProfiler::Constants;
using namespace QmlDebug;
using namespace ProjectExplorer;
namespace QmlProfiler {
namespace Internal {
class QmlProfilerTool::QmlProfilerToolPrivate
{
public:
......@@ -96,6 +98,8 @@ public:
QmlProfilerViewManager *m_viewContainer;
Utils::FileInProjectFinder m_projectFinder;
QToolButton *m_recordButton;
QMenu *m_featuresMenu;
QToolButton *m_clearButton;
// elapsed time display
......@@ -117,6 +121,10 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent)
d->m_profilerState = 0;
d->m_viewContainer = 0;
d->m_recordButton = 0;
d->m_featuresMenu = 0;
d->m_clearButton = 0;
d->m_timeLabel = 0;
qmlRegisterType<TimelineRenderer>("Monitor", 1, 0,"TimelineRenderer");
......@@ -132,6 +140,8 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent)
d->m_profilerModelManager = new QmlProfilerModelManager(&d->m_projectFinder, this);
connect(d->m_profilerModelManager, SIGNAL(stateChanged()), this, SLOT(profilerDataModelStateChanged()));
connect(d->m_profilerModelManager, SIGNAL(error(QString)), this, SLOT(showErrorDialog(QString)));
connect(d->m_profilerModelManager, SIGNAL(availableFeaturesChanged(quint64)),
this, SLOT(setAvailableFeatures(quint64)));
d->m_profilerConnections->setModelManager(d->m_profilerModelManager);
Command *command = 0;
......@@ -247,6 +257,13 @@ QWidget *QmlProfilerTool::createWidgets()
connect(d->m_recordButton,SIGNAL(clicked(bool)), this, SLOT(recordingButtonChanged(bool)));
d->m_recordButton->setChecked(true);
d->m_featuresMenu = new QMenu(d->m_recordButton);
d->m_recordButton->setMenu(d->m_featuresMenu);
d->m_recordButton->setPopupMode(QToolButton::MenuButtonPopup);
setAvailableFeatures(d->m_profilerModelManager->availableFeatures());
connect(d->m_featuresMenu, SIGNAL(triggered(QAction*)),
this, SLOT(toggleRecordingFeature(QAction*)));
setRecording(d->m_profilerState->clientRecording());
layout->addWidget(d->m_recordButton);
......@@ -326,6 +343,9 @@ void QmlProfilerTool::setRecording(bool recording)
} else {
d->m_recordingTimer.stop();
}
d->m_recordButton->menu()->setEnabled(!recording);
} else {
d->m_recordButton->menu()->setEnabled(true);
}
}
......@@ -508,6 +528,36 @@ void QmlProfilerTool::clientsDisconnected()
// If the connection is closed while the app is still running, no special action is needed
}
template<QmlDebug::ProfileFeature feature>
void QmlProfilerTool::updateFeaturesMenu(quint64 features)
{
if (features & (1 << feature)) {
QAction *action = d->m_featuresMenu->addAction(tr(QmlProfilerModelManager::featureName(
static_cast<QmlDebug::ProfileFeature>(feature))));
action->setCheckable(true);
action->setData(static_cast<uint>(feature));
action->setChecked(d->m_profilerState->recordingFeatures() & (1 << feature));
}
updateFeaturesMenu<static_cast<QmlDebug::ProfileFeature>(feature + 1)>(features);
}
template<>
void QmlProfilerTool::updateFeaturesMenu<QmlDebug::MaximumProfileFeature>(quint64 features)
{
Q_UNUSED(features);
return;
}
void QmlProfilerTool::setAvailableFeatures(quint64 features)
{
if (features != d->m_profilerState->recordingFeatures())
d->m_profilerState->setRecordingFeatures(features); // by default, enable them all.
if (d->m_featuresMenu) {
d->m_featuresMenu->clear();
updateFeaturesMenu<static_cast<QmlDebug::ProfileFeature>(0)>(features);
}
}
void QmlProfilerTool::profilerDataModelStateChanged()
{
switch (d->m_profilerModelManager->state()) {
......@@ -608,3 +658,20 @@ void QmlProfilerTool::serverRecordingChanged()
d->m_clearButton->setEnabled(true);
}
}
void QmlProfilerTool::toggleRecordingFeature(QAction *action)
{
uint feature = action->data().toUInt();
if (action->isChecked())
d->m_profilerState->setRecordingFeatures(
d->m_profilerState->recordingFeatures() | (1 << feature));
else
d->m_profilerState->setRecordingFeatures(
d->m_profilerState->recordingFeatures() & (~(1 << feature)));
// Keep the menu open to allow for more features to be toggled
d->m_recordButton->showMenu();
}
}
}
......@@ -32,6 +32,7 @@
#include <analyzerbase/ianalyzertool.h>
#include <analyzerbase/analyzerruncontrol.h>
#include "qmldebug/qmlprofilereventtypes.h"
QT_BEGIN_NAMESPACE
class QMessageBox;
......@@ -68,6 +69,7 @@ public slots:
void clientRecordingChanged();
void serverRecordingChanged();
void clientsDisconnected();
void setAvailableFeatures(quint64 features);
void recordingButtonChanged(bool recording);
void setRecording(bool recording);
......@@ -84,9 +86,13 @@ private slots:
void showSaveDialog();
void showLoadDialog();
void toggleRecordingFeature(QAction *action);
private:
void clearDisplay();
void populateFileFinder(QString projectDirectory = QString(), QString activeSysroot = QString());
template<QmlDebug::ProfileFeature feature>
void updateFeaturesMenu(quint64 features);
class QmlProfilerToolPrivate;
QmlProfilerToolPrivate *d;
......
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