[KPhotoAlbum] More "loading" efficiency issues

Robert Krawitz rlk at alum.mit.edu
Sat May 26 22:47:22 BST 2018

I found two more loading (in)efficiency issues:

1) When converting RAW files into images, the loader tries to use the
   embedded preview if available.  This in turn uses
   KDcraw::loadRawPreview(), which internally converts it from JPEG to
   QImage.  Assuming that it uses libjpeg, it does so inefficiently
   because it makes a lot of system calls, reading the image in small
   chunks, and as a result doing a lot of extra work.  I changed it
   (on the load performance branch) to use the much more efficient
   in-memory JPEG decoding.

   This has no direct effect on wall-clock performance on my system
   that I'm aware of unless I'm reading from the SSD using 2 or more
   scouts.  However, it greatly reduces the user and system CPU time,
   so people with lots of RAW files and either slower CPUs or very
   fast storage will benefit, and in any event it will hit the system
   less hard (both in CPU time and IOPS) when loading RAW files.

   The result of this is that MD5 computation actually takes over 50%
   of the user CPU time (estimated by kcachegrind) when loading RAW
   files, and building thumbnails takes about 44% of the time on my
   system.  But given that I'm seeing CPU consumption under 20%
   (vs. about 50%) while more or less pinning the I/O rate, it should
   be able to take pretty good advantage of NVMe or other fast

2) I wanted to see if there was still anything using the slow path
   JPEG loader.  When I put debug messages in, and went into the
   viewer and quickly ran through that, I was surprised to see a lot
   of files being queued and loaded repeatedly.  It looks like the
   problem is that ImageManager::AsyncLoader::loadImage() is not
   correctly detecting whether a request is already queued.  The
   problem is that the list of images being loaded is a
   QSet<ImageRequest*> rather than QSet<ImageRequest&> or the like, so
   it does a pointer comparison rather than a value comparison.  The
   patch below does a value comparison, unfortunately having to
   iterate over the queue to find a duplicate request.

   There are enough uses of ImageRequest that I didn't want to
   completely rewrite the logic.

   Unfortunately, with or without this change, the viewer can get
   behind the loader, in which case the viewer freezes for a few
   seconds until it reaches an active request in the queue.  What we
   really need to do is something like put high priority requests on
   the front of the queue or something, but that's going to be a
   harder problem.

   I'm going to commit this separately from #1, so if it turns out to
   cause problems, we can pull it out easily.

diff --git a/ImageManager/AsyncLoader.cpp b/ImageManager/AsyncLoader.cpp
index e7f81223..84698add 100644
--- a/ImageManager/AsyncLoader.cpp
+++ b/ImageManager/AsyncLoader.cpp
@@ -134,6 +134,17 @@ void ImageManager::AsyncLoader::loadImage( ImageRequest* request )
         return; // We are currently loading it, calm down and wait please ;-)
+    // Try harder to find a pending request.  Unfortunately, we can't simply use
+    // m_currentLoading.contains() because that will compare pointers
+    // when we want to compare values.
+    for (req = m_currentLoading.begin(); req != m_currentLoading.end(); req++) {
+        ImageRequest *r = *req;
+        if (*request == *r) {
+            delete request;
+            return; // We are currently loading it, calm down and wait please ;-)
+        }
+    }
     // if request is "fresh" (not yet pending):
     if (m_loadList.addRequest( request ))

Robert Krawitz                                     <rlk at alum.mit.edu>

***  MIT Engineers   A Proud Tradition   http://mitathletics.com  ***
Member of the League for Programming Freedom  --  http://ProgFree.org
Project lead for Gutenprint   --    http://gimp-print.sourceforge.net

"Linux doesn't dictate how I work, I dictate how Linux works."
--Eric Crampton

More information about the Kphotoalbum mailing list