[Kde-imaging] On-demand-loading of KIPI plugins
Achim Bohnet
ach at mpe.mpg.de
Thu Oct 13 15:05:16 CEST 2005
On Wednesday 12 October 2005 23:51, Aurelien Gateau wrote:
> [Resending with bzipped attachements to pass the message size limit. List
> admin please cancel my pending message]
>
> Hello,
Hi,
FWIW (maybe nothing) Back in June Lubos Lunak created a speedup
patch too. '[Kde-imaging] KIPI initialization'. What I remember
is that it depends on a 3.5 feature to explore it's full power.
I'm in a hurry so, maybe it's all already applied. No time to
check.
Achim
>
> We (Gwenview developers) have been receiving a few complaints lately about
> Gwenview memory usage and startup speed.
>
> One way to improve on this would be to implement on-demand-loading of KIPI
> plugins. That is: instead of dlopening all plugins on application startup, we
> would dlopen them only when a plugin action is triggered from the menu. I
> decided to have a look at what it would take to implement this and came up
> with a simple proof-of-concept implementation, which you will find attached to
> this message.
>
> kipi2-libkipi.diff contains all changes to libkipi. kipi2-kipi-plugins.diff
> contains the changes to the kipi-plugins I ported to (helloworld, calendar,
> printwizard and jpeglossless).
>
> I hopefully didn't break source compatibility (I did break binary
> compatibility), so if you fill adventurous you can try to rebuild your app
> with this new lib (I must confess I only tried it with Gwenview)
>
>
> Some numbers
> ------------
>
> Since measuring memory usage is a difficult art, only mastered by a few wise
> people :-) I restricted myself to measuring improvements on startup time. I
> hope you will all agree that not dlopening files leads to less memory usage
> (I would be interested to get some reliable numbers on memory usage,
> nevertheless).
>
> My machine is a Duron 1200, with 768Mb of RAM and a decent UltraDMA IDE disk.
> Here is how I ran my tests:
> * Uninstalled my packaged version of kipi-plugins
>
> * Patched the plugin-loading code of Gwenview like this:
> + QTime chrono;
> + chrono.start();
> // Sets up the plugin interface, and load the plugins
> KIPIInterface* interface = new KIPIInterface(this, mFileViewStack);
> mPluginLoader = new KIPI::PluginLoader(QStringList(), interface );
> connect( mPluginLoader, SIGNAL( replug() ), this, SLOT( slotReplug() ) );
> mPluginLoader->loadPlugins();
> + kdDebug() << "Load plugins: " << chrono.elapsed() << endl;
>
> * Rebuild the current libkipi,kipi-plugins and installed them as well as
> Gwenview to $HOME/opt/debug (my usual debug install dir).
>
> * Ran "export KDEDIRS=$HOME/opt/debug:/usr", then "kbuildsycoca"
>
> * Started Gwenview three times, results (in milliseconds) are:
> 1175 1042 1030 (Mean: 1082.3)
>
>
> Second set of tests, using only the KIPI2 ported plugins:
> * cd'ed into share/services/ and rm'ed the .desktop files for the plugins
> which was not ported to KIPI2.
>
> * run kbuildsycoca
>
> * Started Gwenview three times, results are:
> 264 238 308 (Mean: 270)
>
>
> Third set of tests, this time using KIPI2:
> * Build KIPI2 version of libkipi,kipi-plugins,gwenview and installed them to
> $HOME/opt/kipi2
>
> * Ran "export KDEDIRS=$HOME/opt/kipi2", then "kbuildsycoca"
>
> * Started Gwenview three times, results are:
> 74 56 55 (Mean: 61.6)
>
>
> As you can see, it's more than 4 times faster.
>
>
> How does it work?
> -----------------
>
> KIPI::Plugin acts as a proxy for the real plugin, which inherits from
> KIPI::RealPlugin. KIPI::Plugin objects are instanciated on application startup
> and create KActions based on the action definitions of the plugin desktop
> files.
>
> The desktop file looks like this:
>
> [Desktop]
> ...
> Actions=action1;action2
>
> [Desktop Action action1]
> Name=Action1
> Name[fr]=Action1 FR
> Icon=back
> Category=1
>
> [Desktop Action action2]
> Name=Action2
> Name[fr]=Action2 FR
> Icon=forward
> Category=2
>
>
> All actions of a plugin are connected to the same KIPI::Plugin slot
> (slotActionActivated() ) which will first load and init the plugin if
> necessary, then execute the corresponding plugin slot. To execute the right
> slot It uses a little trick like this:
>
> -------
> // Get the action name: this is the name of the plugin slot to call
> const QObject* obj=sender();
> Q_ASSERT(obj);
> QCString name=obj->name();
>
> // Create the slot based on the action name, then call it
> QSignal signaler;
> signaler.connect(d->m_realPlugin, "1" + name + "()");
> signaler.activate();
> -------
>
> On the plugin side there are no KActions, only slots. In my example, there are
> two slots named action1() and action2().
>
>
> Limitations
> -----------
>
> There is no support for enabling or disabling actions. This can be easily
> implemented through another key in the action group which would specify what
> is necessary for the plugin. Some plugins want to have some images selected,
> others will work without any selection, letting the user choose between the
> application image collections.
>
> There is also no support for submenus. Again, this could be implemented using
> keys in the action group, but from a usability point of view I'm not sure
> it's a good idea: deep nested menus are not very handy to use.
>
> The current code is just a proof of concept, and I tried to avoid breaking
> source compatibility so that it's easier to test, but if we go for this a few
> things should probably be written in a different way (for example the
> PluginInfo and Plugin class should be merged).
>
>
> What do you think about this?
>
> Regards,
> Aurélien
>
--
To me vi is Zen. To use vi is to practice zen. Every command is
a koan. Profound to the user, unintelligible to the uninitiated.
You discover truth everytime you use it.
-- reddy at lion.austin.ibm.com
More information about the Kde-imaging
mailing list