From eae2f6297077e1e19b45d8144ae989e4cf52a67c Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Tue, 2 Mar 2010 12:33:51 +0100
Subject: [PATCH] Add -profile option that dumps plugin load/initialization
 times. Reviewed-by: con

---
 src/libs/extensionsystem/optionsparser.cpp | 13 ++++-
 src/libs/extensionsystem/optionsparser.h   |  2 +
 src/libs/extensionsystem/pluginmanager.cpp | 67 +++++++++++++++++++---
 src/libs/extensionsystem/pluginmanager_p.h |  9 +++
 src/libs/extensionsystem/pluginspec.cpp    |  2 +-
 5 files changed, 82 insertions(+), 11 deletions(-)

diff --git a/src/libs/extensionsystem/optionsparser.cpp b/src/libs/extensionsystem/optionsparser.cpp
index 28d3e205331..6158bb3e773 100644
--- a/src/libs/extensionsystem/optionsparser.cpp
+++ b/src/libs/extensionsystem/optionsparser.cpp
@@ -34,9 +34,10 @@
 using namespace ExtensionSystem;
 using namespace ExtensionSystem::Internal;
 
-static const char *END_OF_OPTIONS = "--";
+static const char END_OF_OPTIONS[] = "--";
 const char *OptionsParser::NO_LOAD_OPTION = "-noload";
 const char *OptionsParser::TEST_OPTION = "-test";
+const char *OptionsParser::PROFILE_OPTION = "-profile";
 
 OptionsParser::OptionsParser(const QStringList &args,
         const QMap<QString, bool> &appOptions,
@@ -69,6 +70,8 @@ bool OptionsParser::parse()
             break;
         if (checkForNoLoadOption())
             continue;
+        if (checkForProfilingOption())
+            continue;
         if (checkForTestOption())
             continue;
         if (checkForAppOption())
@@ -148,6 +151,14 @@ bool OptionsParser::checkForAppOption()
     return true;
 }
 
+bool OptionsParser::checkForProfilingOption()
+{
+    if (m_currentArg != QLatin1String(PROFILE_OPTION))
+        return false;
+    m_pmPrivate->initProfiling();
+    return true;
+}
+
 bool OptionsParser::checkForPluginOption()
 {
     bool requiresParameter;
diff --git a/src/libs/extensionsystem/optionsparser.h b/src/libs/extensionsystem/optionsparser.h
index 435ea956a2e..13693081a82 100644
--- a/src/libs/extensionsystem/optionsparser.h
+++ b/src/libs/extensionsystem/optionsparser.h
@@ -51,6 +51,7 @@ public:
 
     static const char *NO_LOAD_OPTION;
     static const char *TEST_OPTION;
+    static const char *PROFILE_OPTION;
 private:
     // return value indicates if the option was processed
     // it doesn't indicate success (--> m_hasError)
@@ -59,6 +60,7 @@ private:
     bool checkForTestOption();
     bool checkForAppOption();
     bool checkForPluginOption();
+    bool checkForProfilingOption();
     bool checkForUnknownOption();
 
     enum TokenType { OptionalToken, RequiredToken };
diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp
index 5e0f100e083..a7565140287 100644
--- a/src/libs/extensionsystem/pluginmanager.cpp
+++ b/src/libs/extensionsystem/pluginmanager.cpp
@@ -38,6 +38,8 @@
 #include <QtCore/QDir>
 #include <QtCore/QTextStream>
 #include <QtCore/QWriteLocker>
+#include <QtCore/QTime>
+#include <QtCore/QDateTime>
 #include <QtDebug>
 #ifdef WITH_TESTS
 #include <QTest>
@@ -465,6 +467,9 @@ void PluginManager::formatOptions(QTextStream &str, int optionIndentation, int d
     formatOption(str, QLatin1String(OptionsParser::NO_LOAD_OPTION),
                  QLatin1String("plugin"), QLatin1String("Do not load <plugin>"),
                  optionIndentation, descriptionIndentation);
+    formatOption(str, QLatin1String(OptionsParser::PROFILE_OPTION),
+                 QString(), QLatin1String("Profile plugin loading"),
+                 optionIndentation, descriptionIndentation);
 }
 
 /*!
@@ -573,8 +578,10 @@ PluginSpecPrivate *PluginManagerPrivate::privateSpec(PluginSpec *spec)
     \fn PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager)
     \internal
 */
-PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager)
-    : extension("xml"), q(pluginManager)
+PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager) :
+    extension(QLatin1String("xml")),
+    m_profileElapsedMS(0),
+    q(pluginManager)
 {
 }
 
@@ -740,14 +747,19 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt
 {
     if (spec->hasError())
         return;
-    if (destState == PluginSpec::Running) {
+    switch (destState) {
+    case PluginSpec::Running:
+        profilingReport(">initializeExtensions", spec);
         spec->d->initializeExtensions();
+        profilingReport("<initializeExtensions", spec);
         return;
-    } else if (destState == PluginSpec::Deleted) {
+    case PluginSpec::Deleted:
         spec->d->kill();
         return;
+    default:
+        break;
     }
-    foreach (PluginSpec *depSpec, spec->dependencySpecs()) {
+    foreach (const PluginSpec *depSpec, spec->dependencySpecs()) {
         if (depSpec->state() != destState) {
             spec->d->hasError = true;
             spec->d->errorString =
@@ -756,12 +768,25 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt
             return;
         }
     }
-    if (destState == PluginSpec::Loaded)
+    switch (destState) {
+    case PluginSpec::Loaded:
+        profilingReport(">loadLibrary", spec);
         spec->d->loadLibrary();
-    else if (destState == PluginSpec::Initialized)
+        profilingReport("<loadLibrary", spec);
+        break;
+    case PluginSpec::Initialized:
+        profilingReport(">initializePlugin", spec);
         spec->d->initializePlugin();
-    else if (destState == PluginSpec::Stopped)
+        profilingReport("<initializePlugin", spec);
+        break;
+    case PluginSpec::Stopped:
+        profilingReport(">stop", spec);
         spec->d->stop();
+        profilingReport("<stop", spec);
+        break;
+    default:
+        break;
+    }
 }
 
 /*!
@@ -787,7 +812,8 @@ void PluginManagerPrivate::readPluginPaths()
     QStringList searchPaths = pluginPaths;
     while (!searchPaths.isEmpty()) {
         const QDir dir(searchPaths.takeFirst());
-        const QFileInfoList files = dir.entryInfoList(QStringList() << QString("*.%1").arg(extension), QDir::Files);
+        const QString pattern = QLatin1String("*.") + extension;
+        const QFileInfoList files = dir.entryInfoList(QStringList(pattern), QDir::Files);
         foreach (const QFileInfo &file, files)
             specFiles << file.absoluteFilePath();
         const QFileInfoList dirs = dir.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot);
@@ -844,3 +870,26 @@ PluginSpec *PluginManagerPrivate::pluginByName(const QString &name) const
     return 0;
 }
 
+void PluginManagerPrivate::initProfiling()
+{
+    if (m_profileTimer.isNull()) {
+        m_profileTimer.reset(new QTime);
+        m_profileTimer->start();
+        m_profileElapsedMS = 0;
+        qDebug("Profiling started");
+    }
+}
+
+void PluginManagerPrivate::profilingReport(const char *what, const PluginSpec *spec /* = 0 */)
+{
+    if (!m_profileTimer.isNull()) {
+        const int absoluteElapsedMS = m_profileTimer->elapsed();
+        const int elapsedMS = absoluteElapsedMS - m_profileElapsedMS;
+        m_profileElapsedMS = absoluteElapsedMS;
+        if (spec) {
+            qDebug("%-22s %-22s %8dms (%8dms)", what, qPrintable(spec->name()), absoluteElapsedMS, elapsedMS);
+        } else {
+            qDebug("%-22s %8dms (%8dms)", what, absoluteElapsedMS, elapsedMS);
+        }
+    }
+}
diff --git a/src/libs/extensionsystem/pluginmanager_p.h b/src/libs/extensionsystem/pluginmanager_p.h
index 2dfd46ea368..b0505dd0f2c 100644
--- a/src/libs/extensionsystem/pluginmanager_p.h
+++ b/src/libs/extensionsystem/pluginmanager_p.h
@@ -36,6 +36,11 @@
 #include <QtCore/QSet>
 #include <QtCore/QStringList>
 #include <QtCore/QObject>
+#include <QtCore/QScopedPointer>
+
+QT_BEGIN_NAMESPACE
+class QTime;
+QT_END_NAMESPACE
 
 namespace ExtensionSystem {
 
@@ -61,6 +66,8 @@ public:
     QList<PluginSpec *> loadQueue();
     void loadPlugin(PluginSpec *spec, PluginSpec::State destState);
     void resolveDependencies();
+    void initProfiling();
+    void profilingReport(const char *what, const PluginSpec *spec = 0);
 
     QList<PluginSpec *> pluginSpecs;
     QList<PluginSpec *> testSpecs;
@@ -69,6 +76,8 @@ public:
     QList<QObject *> allObjects; // ### make this a QList<QPointer<QObject> > > ?
 
     QStringList arguments;
+    QScopedPointer<QTime> m_profileTimer;
+    int m_profileElapsedMS;
 
     // Look in argument descriptions of the specs for the option.
     PluginSpec *pluginForOption(const QString &option, bool *requiresArgument) const;
diff --git a/src/libs/extensionsystem/pluginspec.cpp b/src/libs/extensionsystem/pluginspec.cpp
index 0dd8aadc9d1..f2a77c7a2cc 100644
--- a/src/libs/extensionsystem/pluginspec.cpp
+++ b/src/libs/extensionsystem/pluginspec.cpp
@@ -734,7 +734,7 @@ bool PluginSpecPrivate::resolveDependencies(const QList<PluginSpec *> &specs)
         if (!found) {
             hasError = true;
             if (!errorString.isEmpty())
-                errorString.append("\n");
+                errorString.append(QLatin1Char('\n'));
             errorString.append(QCoreApplication::translate("PluginSpec", "Could not resolve dependency '%1(%2)'")
                 .arg(dependency.name).arg(dependency.version));
             continue;
-- 
GitLab