From af01c2e953704b0a039456e5b747dc5f2241f74e Mon Sep 17 00:00:00 2001 From: Kai Uwe Broulik Date: Mon, 23 Jul 2018 16:24:27 +0200 Subject: [PATCH] [Plasma PluginLoader] Cache plugins during startup Similar to KPackage's cache this speeds up startup where plugins are repeatedly looked up. Especially the fallback path of looking in the plugin root directly causes quite some slowdown. Differential Revision: https://phabricator.kde.org/D14009 --- src/plasma/pluginloader.cpp | 57 +++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/src/plasma/pluginloader.cpp b/src/plasma/pluginloader.cpp index 3686ca2c4..7da0f6d5d 100644 --- a/src/plasma/pluginloader.cpp +++ b/src/plasma/pluginloader.cpp @@ -72,6 +72,16 @@ public: static QString s_plasmoidsPluginDir; static QString s_servicesPluginDir; static QString s_containmentActionsPluginDir; + + // We only use this cache during start of the process to speed up many consecutive calls + // After that, we're too afraid to produce race conditions and it's not that time-critical anyway + // the 20 seconds here means that the cache is only used within 20sec during startup, after that, + // complexity goes up and we'd have to update the cache in order to avoid subtle bugs + // just not using the cache is way easier then, since it doesn't make *that* much of a difference, + // anyway + int maxCacheAge = 20; + qint64 pluginCacheAge = 0; + QHash> pluginCache; }; QSet PluginLoaderPrivate::s_customCategories; @@ -180,19 +190,48 @@ Applet *PluginLoader::loadApplet(const QString &name, uint appletId, const QVari appletId = ++AppletPrivate::s_maxAppletId; } + const qint64 now = qRound64(QDateTime::currentMSecsSinceEpoch() / 1000.0); + bool useRuntimeCache = true; + if (now - d->pluginCacheAge > d->maxCacheAge && d->pluginCacheAge != 0) { + // cache is old and we're not within a few seconds of startup anymore + useRuntimeCache = false; + d->pluginCache.clear(); + } + + if (d->pluginCacheAge == 0) { + // Find all the plugins now, but only once + d->pluginCacheAge = now; + + auto insertIntoCache = [this](const QString &pluginPath) { + KPluginMetaData metadata(pluginPath); + if (!metadata.isValid()) { + return; + } + + d->pluginCache[metadata.pluginId()].append(metadata); + }; + + KPluginLoader::forEachPlugin(PluginLoaderPrivate::s_plasmoidsPluginDir, insertIntoCache); + // COMPAT CODE for applets installed into the toplevel plugins dir by mistake. + KPluginLoader::forEachPlugin(QString(), insertIntoCache); + } //if name wasn't a path, pluginName == name - const auto pluginName = name.splitRef(QLatin1Char('/')).last(); + const QString pluginName = name.section(QLatin1Char('/'), -1); - // Look for C++ plugins first - auto filter = [&pluginName](const KPluginMetaData &md) -> bool - { - return md.pluginId() == pluginName; - }; - QVector plugins = KPluginLoader::findPlugins(PluginLoaderPrivate::s_plasmoidsPluginDir, filter); - if (plugins.isEmpty()) { + QVector plugins; + + if (useRuntimeCache) { + auto it = d->pluginCache.constFind(pluginName); + if (it != d->pluginCache.constEnd()) { + plugins = *it; + } + } else { + plugins = KPluginLoader::findPluginsById(PluginLoaderPrivate::s_plasmoidsPluginDir, pluginName); // COMPAT CODE for applets installed into the toplevel plugins dir by mistake. - plugins = KPluginLoader::findPlugins(QString(), filter); + if (plugins.isEmpty()) { + plugins = KPluginLoader::findPluginsById(QString(), pluginName); + } } const KPackage::Package p = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/Applet"), name);