[Kde-imaging] Fwd: On-demand-loading of KIPI plugins
Jesper K. Pedersen
blackie at blackie.dk
Fri Nov 25 03:41:44 CET 2005
I'm all for this change. Faster start up is a good thing.
Having said that, I don't have any time to put into this (just see how long it
took to answer this email ;)
If you are going for this, I think it would be really good if the two kipi
versions could co exists. Also it would be really nice to have a check up on
KIPI over all if we break BIC. See the libkipi/TODO for some suggestions.
On Monday 24 October 2005 16:18, Aurelien Gateau wrote:
| Here is my proposal.
| ---------- Message transmis ----------
| Subject: [Kde-imaging] On-demand-loading of KIPI plugins
| Date: Mercredi 12 Octobre 2005 23:51
| From: Aurelien Gateau <aurelien.gateau at free.fr>
| To: kde-imaging at kde.org
| 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() ) );
| + 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 Action action1]
| Name[fr]=Action1 FR
| [Desktop Action action2]
| Name[fr]=Action2 FR
| 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();
| QCString name=obj->name();
| // Create the slot based on the action name, then call it
| QSignal signaler;
| signaler.connect(d->m_realPlugin, "1" + name + "()");
| On the plugin side there are no KActions, only slots. In my example, there
| are two slots named action1() and action2().
| 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?
Jesper K. Pedersen | Klarälvdalens Datakonsult
Senior Software Engineer | www.klaralvdalens-datakonsult.se
Prinsensgade 4a st. |
9800 Hjørring | Platform-independent
Denmark | software solutions
More information about the Kde-imaging