qmlprofiler: Allow specification of features to record
authorUlf Hermann <ulf.hermann@theqtcompany.com>
Thu, 21 May 2015 08:35:42 +0000 (10:35 +0200)
committerSimon Hausmann <simon.hausmann@theqtcompany.com>
Tue, 9 Jun 2015 18:31:55 +0000 (18:31 +0000)
Task-number: QTBUG-43066
Change-Id: I963a5a483f961dd150f00de3d96c723c8b62edb8
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
tools/qmlprofiler/qmlprofilerapplication.cpp
tools/qmlprofiler/qmlprofilerapplication.h
tools/qmlprofiler/qmlprofilerclient.cpp
tools/qmlprofiler/qmlprofilerclient.h

index fbea376..02dabea 100644 (file)
@@ -59,6 +59,20 @@ static const char commandTextC[] =
         "    Terminate the program if started from qmlprofiler,\n"
         "    and qmlprofiler itself.";
 
+static const char *features[] = {
+    "javascript",
+    "memory",
+    "pixmapcache",
+    "scenegraph",
+    "animations",
+    "painting",
+    "compiling",
+    "creating",
+    "binding",
+    "handlingsignal",
+    "inputevents"
+};
+
 static const char TraceFileExtension[] = ".qtd";
 
 QmlProfilerApplication::QmlProfilerApplication(int &argc, char **argv) :
@@ -172,6 +186,26 @@ void QmlProfilerApplication::parseArguments()
                               QLatin1String("on|off"), QLatin1String("on"));
     parser.addOption(record);
 
+    QStringList featureList;
+    for (int i = 0; i < QQmlProfilerService::MaximumProfileFeature; ++i)
+        featureList << QLatin1String(features[i]);
+
+    QCommandLineOption include(QLatin1String("include"),
+                               tr("Comma-separated list of features to record. By default all "
+                                  "features supported by the QML engine are recorded. If --include "
+                                  "is specified, only the given features will be recorded. "
+                                  "The following features are unserstood by qmlprofiler: %1").arg(
+                                   featureList.join(", ")),
+                               QLatin1String("feature,..."));
+    parser.addOption(include);
+
+    QCommandLineOption exclude(QLatin1String("exclude"),
+                            tr("Comma-separated list of features to exclude when recording. By "
+                               "default all features supported by the QML engine are recorded. "
+                               "See --include for the features understood by qmlprofiler."),
+                            QLatin1String("feature,..."));
+    parser.addOption(exclude);
+
     QCommandLineOption interactive(QLatin1String("interactive"),
                                    tr("Manually control the recording from the command line. The "
                                       "profiler will not terminate itself when the application "
@@ -213,6 +247,23 @@ void QmlProfilerApplication::parseArguments()
     m_recording = (parser.value(record) == QLatin1String("on"));
     m_interactive = parser.isSet(interactive);
 
+    quint64 features = std::numeric_limits<quint64>::max();
+    if (parser.isSet(include)) {
+        if (parser.isSet(exclude)) {
+            logError(tr("qmlprofiler can only process either --include or --exclude, not both."));
+            parser.showHelp(4);
+        }
+        features = parseFeatures(featureList, parser.value(include), false);
+    }
+
+    if (parser.isSet(exclude))
+        features = parseFeatures(featureList, parser.value(exclude), true);
+
+    if (features == 0)
+        parser.showHelp(4);
+
+    m_qmlProfilerClient.setFeatures(features);
+
     if (parser.isSet(verbose))
         m_verbose = true;
 
@@ -244,6 +295,27 @@ bool QmlProfilerApplication::isInteractive() const
     return m_interactive;
 }
 
+quint64 QmlProfilerApplication::parseFeatures(const QStringList &featureList, const QString &values,
+                                              bool exclude)
+{
+    quint64 features = exclude ? std::numeric_limits<quint64>::max() : 0;
+    QStringList givenFeatures = values.split(QLatin1Char(','));
+    foreach (const QString &f, givenFeatures) {
+        int index =  featureList.indexOf(f);
+        if (index < 0) {
+            logError(tr("Unknown feature '%1'").arg(f));
+            return 0;
+        }
+        quint64 flag = static_cast<quint64>(1) << index;
+        features = (exclude ? (features ^ flag) : (features | flag));
+    }
+    if (features == 0) {
+        logError(exclude ? tr("No features remaining to record after processing --exclude.") :
+                           tr("No features specified for --include."));
+    }
+    return features;
+}
+
 void QmlProfilerApplication::flush()
 {
     if (m_recording) {
index 183bb9d..25d9cf1 100644 (file)
@@ -90,6 +90,7 @@ private slots:
     void v8Complete();
 
 private:
+    quint64 parseFeatures(const QStringList &featureList, const QString &values, bool exclude);
     bool checkOutputFile(PendingRequest pending);
     void flush();
     void output();
index 4f06514..4976a5a 100644 (file)
@@ -71,7 +71,7 @@ class QmlProfilerClientPrivate
 {
 public:
     QmlProfilerClientPrivate()
-        : inProgressRanges(0)
+        : inProgressRanges(0) , features(std::numeric_limits<quint64>::max())
     {
         ::memset(rangeCount, 0,
                  QQmlProfilerService::MaximumRangeType * sizeof(int));
@@ -83,6 +83,8 @@ public:
     QStack<QmlEventLocation> rangeLocations[QQmlProfilerService::MaximumRangeType];
     QStack<QQmlProfilerService::BindingType> bindingTypes;
     int rangeCount[QQmlProfilerService::MaximumRangeType];
+
+    quint64 features;
 };
 
 QmlProfilerClient::QmlProfilerClient(
@@ -97,6 +99,11 @@ QmlProfilerClient::~QmlProfilerClient()
     delete d;
 }
 
+void QmlProfilerClient::setFeatures(quint64 features)
+{
+    d->features = features;
+}
+
 void QmlProfilerClient::clearData()
 {
     ::memset(d->rangeCount, 0,
@@ -109,15 +116,39 @@ void QmlProfilerClient::sendRecordingStatus(bool record)
 {
     QByteArray ba;
     QDataStream stream(&ba, QIODevice::WriteOnly);
-    stream << record;
+    stream << record << -1 << d->features;
     sendMessage(ba);
 }
 
+inline QQmlProfilerService::ProfileFeature featureFromRangeType(
+        QQmlProfilerService::RangeType range)
+{
+    switch (range) {
+        case QQmlProfilerService::Painting:
+            return QQmlProfilerService::ProfilePainting;
+        case QQmlProfilerService::Compiling:
+            return QQmlProfilerService::ProfileCompiling;
+        case QQmlProfilerService::Creating:
+            return QQmlProfilerService::ProfileCreating;
+        case QQmlProfilerService::Binding:
+            return QQmlProfilerService::ProfileBinding;
+        case QQmlProfilerService::HandlingSignal:
+            return QQmlProfilerService::ProfileHandlingSignal;
+        case QQmlProfilerService::Javascript:
+            return QQmlProfilerService::ProfileJavaScript;
+        default:
+            return QQmlProfilerService::MaximumProfileFeature;
+    }
+}
+
 void QmlProfilerClient::messageReceived(const QByteArray &data)
 {
     QByteArray rwData = data;
     QDataStream stream(&rwData, QIODevice::ReadOnly);
 
+    // Force all the 1 << <FLAG> expressions to be done in 64 bit, to silence some warnings
+    const quint64 one = static_cast<quint64>(1);
+
     qint64 time;
     int messageType;
 
@@ -133,6 +164,8 @@ void QmlProfilerClient::messageReceived(const QByteArray &data)
         if (event == QQmlProfilerService::EndTrace) {
             emit this->traceFinished(time);
         } else if (event == QQmlProfilerService::AnimationFrame) {
+            if (!(d->features & one << QQmlProfilerService::ProfileAnimations))
+                return;
             int frameRate, animationCount;
             int threadId = 0;
             stream >> frameRate >> animationCount;
@@ -149,6 +182,8 @@ void QmlProfilerClient::messageReceived(const QByteArray &data)
     } else if (messageType == QQmlProfilerService::Complete) {
         emit complete();
     } else if (messageType == QQmlProfilerService::SceneGraphFrame) {
+        if (!(d->features & one << QQmlProfilerService::ProfileSceneGraph))
+            return;
         int sgEventType;
         int count = 0;
         qint64 params[5];
@@ -162,6 +197,8 @@ void QmlProfilerClient::messageReceived(const QByteArray &data)
         emit sceneGraphFrame((QQmlProfilerService::SceneGraphFrameType)sgEventType, time,
                              params[0], params[1], params[2], params[3], params[4]);
     } else if (messageType == QQmlProfilerService::PixmapCacheEvent) {
+        if (!(d->features & one << QQmlProfilerService::ProfilePixmapCache))
+            return;
         int pixEvTy, width = 0, height = 0, refcount = 0;
         QString pixUrl;
         stream >> pixEvTy >> pixUrl;
@@ -175,6 +212,8 @@ void QmlProfilerClient::messageReceived(const QByteArray &data)
         emit pixmapCache((QQmlProfilerService::PixmapEventType)pixEvTy, time,
                          QmlEventLocation(pixUrl,0,0), width, height, refcount);
     } else if (messageType == QQmlProfilerService::MemoryAllocation) {
+        if (!(d->features & one << QQmlProfilerService::ProfileMemory))
+            return;
         int type;
         qint64 delta;
         stream >> type >> delta;
@@ -186,6 +225,10 @@ void QmlProfilerClient::messageReceived(const QByteArray &data)
         if (range >= QQmlProfilerService::MaximumRangeType)
             return;
 
+        if (!(d->features & one << featureFromRangeType(
+                  static_cast<QQmlProfilerService::RangeType>(range))))
+            return;
+
         if (messageType == QQmlProfilerService::RangeStart) {
             d->rangeStartTimes[range].push(time);
             d->inProgressRanges |= (static_cast<qint64>(1) << range);
index 1dd5ccf..f41ebbd 100644 (file)
@@ -74,6 +74,8 @@ public:
     QmlProfilerClient(QQmlDebugConnection *client);
     ~QmlProfilerClient();
 
+    void setFeatures(quint64 features);
+
 public slots:
     void clearData();
     void sendRecordingStatus(bool record);