try to preload certain applets in a smart way

Summary:
preload popups of some applets after init in the background
based on a value of X-Plasma-PreloadWeight in the desktop file
if present, otherwise some default values based on the applet
type (Provides)

Save the weight in the config, if an applet is never opened,
slowly decrease the weight, when it reaches 0 don't preload it
next start, increase every time it gets opened, so at the moment
it's quite aggressive about preloading, in order to not do it
a lot of plasma startups without touching the applet are needed

Applet with a very big weigth will be preloaded immediately,
therefore having an impact on the time it will take to have
a panel visible and usable, while lesser weigths will preload
after a random number of seconds between 2 and 10, so will load
in the background after everything is started

Test Plan:
Plasma starts up correctly, applets load correctly and can be added
correctly both those expanded or collapsed.
plasmashell appears correctly usable without too big hiccups even
while it's loading things in the background

some numbers:
without preloading, plasma takes around 64 mb of memory after startup
when preloading everything about 94, so it's a cost of about 30 mb
which is not negligible.
don't have precise timing, but if everything gets preloaded immediately,
the time to get an usable desktop appears to be at least doubled,
while the delayed preloading (except just a couple of applets) doesn't
seem to have a big impact on the time needed to get an usable desktop

Reviewers: #plasma

Subscribers: davidedmundson, broulik, apol, ngraham, plasma-devel, #frameworks

Tags: #plasma, #frameworks

Differential Revision: https://phabricator.kde.org/D10512
This commit is contained in:
Marco Martin 2018-02-19 18:29:27 +01:00
parent c05b1bdec7
commit 6cbea20bf9
4 changed files with 97 additions and 1 deletions

View File

@ -83,6 +83,9 @@ Type=QString
[PropertyDef::X-Plasma-Provides] [PropertyDef::X-Plasma-Provides]
Type=QStringList Type=QStringList
[PropertyDef::X-Plasma-PreloadWeight]
Type=int
[PropertyDef::X-Plasma-ConfigPlugins] [PropertyDef::X-Plasma-ConfigPlugins]
Type=QStringList Type=QStringList

View File

@ -6,6 +6,7 @@ endif()
set(plasmaquick_LIB_SRC set(plasmaquick_LIB_SRC
appletquickitem.cpp appletquickitem.cpp
debug_p.cpp
dialog.cpp dialog.cpp
dialogshadows.cpp dialogshadows.cpp
view.cpp view.cpp
@ -20,6 +21,8 @@ set(plasmaquick_LIB_SRC
../declarativeimports/core/units.cpp ../declarativeimports/core/units.cpp
) )
ecm_qt_declare_logging_category(PlasmaQuick_LIB_SRCS HEADER debug_p.h IDENTIFIER LOG_PLASMAQUICK CATEGORY_NAME org.kde.plasmaquick)
add_library(KF5PlasmaQuick SHARED ${plasmaquick_LIB_SRC}) add_library(KF5PlasmaQuick SHARED ${plasmaquick_LIB_SRC})
add_library(KF5::PlasmaQuick ALIAS KF5PlasmaQuick) add_library(KF5::PlasmaQuick ALIAS KF5PlasmaQuick)
target_include_directories(KF5PlasmaQuick PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_BINARY_DIR}/..>") target_include_directories(KF5PlasmaQuick PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR};${CMAKE_CURRENT_BINARY_DIR}/..>")

View File

@ -19,6 +19,7 @@
#include "appletquickitem.h" #include "appletquickitem.h"
#include "private/appletquickitem_p.h" #include "private/appletquickitem_p.h"
#include "debug_p.h"
#include <QQmlComponent> #include <QQmlComponent>
#include <QQmlExpression> #include <QQmlExpression>
@ -43,6 +44,7 @@ namespace PlasmaQuick
QHash<QObject *, AppletQuickItem *> AppletQuickItemPrivate::s_rootObjects = QHash<QObject *, AppletQuickItem *>(); QHash<QObject *, AppletQuickItem *> AppletQuickItemPrivate::s_rootObjects = QHash<QObject *, AppletQuickItem *>();
AppletQuickItemPrivate::PreloadPolicy AppletQuickItemPrivate::s_preloadPolicy = AppletQuickItemPrivate::Uninitialized;
AppletQuickItemPrivate::AppletQuickItemPrivate(Plasma::Applet *a, AppletQuickItem *item) AppletQuickItemPrivate::AppletQuickItemPrivate(Plasma::Applet *a, AppletQuickItem *item)
: q(item), : q(item),
@ -52,6 +54,19 @@ AppletQuickItemPrivate::AppletQuickItemPrivate(Plasma::Applet *a, AppletQuickIte
expanded(false), expanded(false),
activationTogglesExpanded(false) activationTogglesExpanded(false)
{ {
if (s_preloadPolicy == Uninitialized) {
if (qEnvironmentVariableIsSet("PLASMA_PRELOAD_POLICY")) {
const QString policy = QString::fromUtf8(qgetenv("PLASMA_PRELOAD_POLICY")).toLower();
if (policy == QStringLiteral("aggressive")) {
s_preloadPolicy = Aggressive;
} else if (policy == QStringLiteral("none")) {
s_preloadPolicy = None;
//default as Adaptive
} else {
s_preloadPolicy = Adaptive;
}
}
}
} }
void AppletQuickItemPrivate::init() void AppletQuickItemPrivate::init()
@ -70,6 +85,21 @@ void AppletQuickItemPrivate::init()
} }
} }
int AppletQuickItemPrivate::preloadWeight() const
{
int defaultWeight;
const QStringList provides(KPluginMetaData::readStringList(applet->pluginMetaData().rawData(), QStringLiteral("X-Plasma-Provides")));
//some applet types we want a bigger weight
if (provides.contains(QStringLiteral("org.kde.plasma.launchermenu"))) {
defaultWeight = DefaultLauncherPreloadWeight;
} else {
defaultWeight = DefaultPreloadWeight;
}
//default widgets to be barely preloaded
return qBound(0, applet->config().readEntry(QStringLiteral("PreloadWeight"), qMax(defaultWeight, applet->pluginMetaData().rawData().value(QStringLiteral("X-Plasma-PreloadWeight")).toInt())), 100);
}
void AppletQuickItemPrivate::connectLayoutAttached(QObject *item) void AppletQuickItemPrivate::connectLayoutAttached(QObject *item)
{ {
QObject *layout = 0; QObject *layout = 0;
@ -218,7 +248,7 @@ QQuickItem *AppletQuickItemPrivate::createFullRepresentationItem()
if (fullRepresentation && fullRepresentation != qmlObject->mainComponent()) { if (fullRepresentation && fullRepresentation != qmlObject->mainComponent()) {
QVariantHash initialProperties; QVariantHash initialProperties;
initialProperties[QStringLiteral("parent")] = QVariant::fromValue(q); initialProperties[QStringLiteral("parent")] = QVariant();
fullRepresentationItem = qobject_cast<QQuickItem*>(qmlObject->createObjectFromComponent(fullRepresentation, QtQml::qmlContext(qmlObject->rootObject()), initialProperties)); fullRepresentationItem = qobject_cast<QQuickItem*>(qmlObject->createObjectFromComponent(fullRepresentation, QtQml::qmlContext(qmlObject->rootObject()), initialProperties));
} else { } else {
fullRepresentation = qmlObject->mainComponent(); fullRepresentation = qmlObject->mainComponent();
@ -437,6 +467,11 @@ AppletQuickItem::AppletQuickItem(Plasma::Applet *applet, QQuickItem *parent)
AppletQuickItem::~AppletQuickItem() AppletQuickItem::~AppletQuickItem()
{ {
//decrease weight
if (d->s_preloadPolicy >= AppletQuickItemPrivate::Adaptive) {
d->applet->config().writeEntry(QStringLiteral("PreloadWeight"), qMax(0, d->preloadWeight() - AppletQuickItemPrivate::PreloadWeightDecrement));
}
//Here the order is important //Here the order is important
delete d->compactRepresentationItem; delete d->compactRepresentationItem;
delete d->fullRepresentationItem; delete d->fullRepresentationItem;
@ -598,6 +633,33 @@ void AppletQuickItem::init()
d->compactRepresentationCheck(); d->compactRepresentationCheck();
qmlObject()->engine()->rootContext()->setBaseUrl(qmlObject()->source()); qmlObject()->engine()->rootContext()->setBaseUrl(qmlObject()->source());
qmlObject()->engine()->setContextForObject(this, qmlObject()->engine()->rootContext()); qmlObject()->engine()->setContextForObject(this, qmlObject()->engine()->rootContext());
//if we're expanded we don't care about preloading because it will already be the case
//as well as for containments
if (d->applet->isContainment() ||
d->expanded || d->preferredRepresentation == d->fullRepresentation) {
return;
}
if (d->s_preloadPolicy >= AppletQuickItemPrivate::Adaptive) {
const int preloadWeight = d->preloadWeight();
qCInfo(LOG_PLASMAQUICK) << "New Applet " << d->applet->title() << "with a weight of" << preloadWeight;
//don't preload applets less then a certain weigth
if (d->s_preloadPolicy >= AppletQuickItemPrivate::Aggressive || preloadWeight >= AppletQuickItemPrivate::DelayedPreloadWeight) {
//spread the creation over a random delay to make it look
//plasma started already, and load the popup in the background
//without big noticeable freezes, the bigger the weight the smaller is likely
//to be the delay, smaller minimum walue, smaller spread
const int min = (100 - preloadWeight) * 20;
const int max = (100 - preloadWeight) * 100;
const int delay = qrand() % ((max + 1) - min) + min;
QTimer::singleShot(delay, this, [this, delay]() {
qCInfo(LOG_PLASMAQUICK) << "Delayed preload of " << d->applet->title() << "after" << (qreal)delay/1000 << "seconds";
d->createFullRepresentationItem();
});
}
}
} }
@ -726,6 +788,7 @@ void AppletQuickItem::setExpanded(bool expanded)
} }
if (expanded) { if (expanded) {
qint64 time = QDateTime::currentMSecsSinceEpoch();
d->createFullRepresentationItem(); d->createFullRepresentationItem();
if (!d->applet->isContainment() && if (!d->applet->isContainment() &&
(!d->preferredRepresentation || (!d->preferredRepresentation ||
@ -738,6 +801,14 @@ void AppletQuickItem::setExpanded(bool expanded)
} else { } else {
d->fullRepresentationItem->setProperty("parent", QVariant::fromValue<QObject*>(this)); d->fullRepresentationItem->setProperty("parent", QVariant::fromValue<QObject*>(this));
} }
//increase on open, ignore containments
if (d->s_preloadPolicy >= AppletQuickItemPrivate::Adaptive && !d->applet->isContainment()) {
const int newWeight = qMin(d->preloadWeight() + AppletQuickItemPrivate::PreloadWeightIncrement, 100);
d->applet->config().writeEntry(QStringLiteral("PreloadWeight"), newWeight);
qCInfo(LOG_PLASMAQUICK) << "Increasing score for" << d->applet->title() << "to" << newWeight;
}
qCInfo(LOG_PLASMAQUICK) << "Applet" << d->applet->title() << "opened after" << ( QDateTime::currentMSecsSinceEpoch() - time) << "msec";
} }
d->expanded = expanded; d->expanded = expanded;

View File

@ -55,10 +55,28 @@ class AppletQuickItem;
class AppletQuickItemPrivate class AppletQuickItemPrivate
{ {
public: public:
//weight values for the logic for when or if to preload
enum PreloadWeights {
DefaultPreloadWeight = 50,
DefaultLauncherPreloadWeight = 100,
DelayedPreloadWeight = 25,
PreloadWeightIncrement = 5,
PreloadWeightDecrement = 8
};
enum PreloadPolicy {
Uninitialized = -1,
None = 0,
Adaptive = 1,
Aggressive = 2
};
AppletQuickItemPrivate(Plasma::Applet *a, AppletQuickItem *item); AppletQuickItemPrivate(Plasma::Applet *a, AppletQuickItem *item);
void init(); void init();
int preloadWeight() const;
QQuickItem *createCompactRepresentationItem(); QQuickItem *createCompactRepresentationItem();
QQuickItem *createFullRepresentationItem(); QQuickItem *createFullRepresentationItem();
QQuickItem *createCompactRepresentationExpanderItem(); QQuickItem *createCompactRepresentationExpanderItem();
@ -80,6 +98,7 @@ public:
AppletQuickItem *q; AppletQuickItem *q;
static PreloadPolicy s_preloadPolicy;
int switchWidth; int switchWidth;
int switchHeight; int switchHeight;