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.
Cheers
Jesper.
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|| Hello,
|| 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
|| -------------------------------------------------------
--
Jesper K. Pedersen | Klarälvdalens Datakonsult
Senior Software Engineer | www.klaralvdalens-datakonsult.se
Prinsensgade 4a st. |
9800 Hjørring | Platform-independent
Denmark | software solutions