[Xfce4-commits] <thunar:master> Reduce D-Bus noise by grouping thumbnail requests in 100ms time slots.
Jannis Pohlmann
jannis at xfce.org
Fri Sep 4 03:22:01 CEST 2009
Updating branch refs/heads/master
to 4911ff1ed0f3fe2d7299a35cb72f0d6dcffcac79 (commit)
from e99cdb4cfae6392f15dc677c3e1c3b0e892a789a (commit)
commit 4911ff1ed0f3fe2d7299a35cb72f0d6dcffcac79
Author: Jannis Pohlmann <jannis at xfce.org>
Date: Fri Sep 4 03:11:05 2009 +0200
Reduce D-Bus noise by grouping thumbnail requests in 100ms time slots.
Just like the rest of ThunarThumbnailer, this code is somewhat scary.
ThunarThumbnailer now queues individual thumbnail request in a wait
queue which is triggered at most every 100ms. All requests made in this
time slot are grouped and sent out as *one* request.
For each time slot, the local optimization is 3+n D-Bus messages (1
request, 1 started signal, 1 finished signal and n ready signals) as
compared to 4*n messages we had before (1 request and 1 started,
finished and ready signal for each individual file).
Of course this calculation is naive. In theory our users scroll up and
down like crazy, sometimes slower, sometimes faster, everyeone using
different Thunar window and icon sizes.
As a result the grouped requests are sometimes very small and sometimes
very large. It's worth noting that this optimization performs better,
the more files are visible in the window and the faster a user scrolls
(as this means that more files are made visible within 100ms and thus,
the size of group requests grows). So I guess we're good.
thunar/thunar-thumbnailer.c | 308 +++++++++++++++++++++++++++++++------------
1 files changed, 221 insertions(+), 87 deletions(-)
diff --git a/thunar/thunar-thumbnailer.c b/thunar/thunar-thumbnailer.c
index bdd9822..a73ca39 100644
--- a/thunar/thunar-thumbnailer.c
+++ b/thunar/thunar-thumbnailer.c
@@ -48,41 +48,45 @@ typedef enum
typedef struct _ThunarThumbnailerCall ThunarThumbnailerCall;
typedef struct _ThunarThumbnailerIdle ThunarThumbnailerIdle;
+typedef struct _ThunarThumbnailerItem ThunarThumbnailerItem;
#endif
-static void thunar_thumbnailer_finalize (GObject *object);
-#ifdef HAVE_DBUS
-static void thunar_thumbnailer_init_thumbnailer_proxy (ThunarThumbnailer *thumbnailer,
- DBusGConnection *connection);
-static void thunar_thumbnailer_init_manager_proxy (ThunarThumbnailer *thumbnailer,
- DBusGConnection *connection);
-static gboolean thunar_thumbnailer_file_is_supported (ThunarThumbnailer *thumbnailer,
- ThunarFile *file);
-static void thunar_thumbnailer_thumbnailer_finished (DBusGProxy *proxy,
- guint handle,
- ThunarThumbnailer *thumbnailer);
-static void thunar_thumbnailer_thumbnailer_error (DBusGProxy *proxy,
- guint handle,
- const gchar **uris,
- gint code,
- const gchar *message,
- ThunarThumbnailer *thumbnailer);
-static void thunar_thumbnailer_thumbnailer_ready (DBusGProxy *proxy,
- const gchar **uris,
- ThunarThumbnailer *thumbnailer);
-static void thunar_thumbnailer_thumbnailer_started (DBusGProxy *proxy,
- guint handle,
- ThunarThumbnailer *thumbnailer);
-static gpointer thunar_thumbnailer_queue_async (ThunarThumbnailer *thumbnailer,
- const gchar **uris,
- const gchar **mime_hints);
-static gboolean thunar_thumbnailer_error_idle (gpointer user_data);
-static gboolean thunar_thumbnailer_ready_idle (gpointer user_data);
-static gboolean thunar_thumbnailer_started_idle (gpointer user_data);
-static void thunar_thumbnailer_call_free (ThunarThumbnailerCall *call);
-static void thunar_thumbnailer_idle_free (gpointer data);
+static void thunar_thumbnailer_finalize (GObject *object);
+#ifdef HAVE_DBUS
+static void thunar_thumbnailer_init_thumbnailer_proxy (ThunarThumbnailer *thumbnailer,
+ DBusGConnection *connection);
+static void thunar_thumbnailer_init_manager_proxy (ThunarThumbnailer *thumbnailer,
+ DBusGConnection *connection);
+static gboolean thunar_thumbnailer_file_is_supported (ThunarThumbnailer *thumbnailer,
+ ThunarFile *file);
+static void thunar_thumbnailer_thumbnailer_finished (DBusGProxy *proxy,
+ guint handle,
+ ThunarThumbnailer *thumbnailer);
+static void thunar_thumbnailer_thumbnailer_error (DBusGProxy *proxy,
+ guint handle,
+ const gchar **uris,
+ gint code,
+ const gchar *message,
+ ThunarThumbnailer *thumbnailer);
+static void thunar_thumbnailer_thumbnailer_ready (DBusGProxy *proxy,
+ const gchar **uris,
+ ThunarThumbnailer *thumbnailer);
+static void thunar_thumbnailer_thumbnailer_started (DBusGProxy *proxy,
+ guint handle,
+ ThunarThumbnailer *thumbnailer);
+static gpointer thunar_thumbnailer_queue_async (ThunarThumbnailer *thumbnailer,
+ const gchar **uris,
+ const gchar **mime_hints);
+static gboolean thunar_thumbnailer_error_idle (gpointer user_data);
+static gboolean thunar_thumbnailer_ready_idle (gpointer user_data);
+static gboolean thunar_thumbnailer_started_idle (gpointer user_data);
+static void thunar_thumbnailer_call_free (ThunarThumbnailerCall *call);
+static void thunar_thumbnailer_idle_free (gpointer data);
+static ThunarThumbnailerItem *thunar_thumbnailer_item_new (GFile *file,
+ const gchar *mime_hint);
+static void thunar_thumbnailer_item_free (gpointer data);
#endif
@@ -101,6 +105,10 @@ struct _ThunarThumbnailer
DBusGProxy *manager_proxy;
DBusGProxy *thumbnailer_proxy;
+ /* wait queue used to delay (and thereby group) thumbnail requests */
+ GList *wait_queue;
+ guint wait_queue_idle_id;
+
/* hash table to map D-Bus service handles to ThunarThumbnailer requests */
GHashTable *handle_request_mapping;
@@ -145,6 +153,12 @@ struct _ThunarThumbnailerIdle
gpointer request;
} data;
};
+
+struct _ThunarThumbnailerItem
+{
+ GFile *file;
+ gchar *mime_hint;
+};
#endif
@@ -182,6 +196,7 @@ thunar_thumbnailer_init (ThunarThumbnailer *thumbnailer)
thumbnailer->supported_types = NULL;
thumbnailer->last_request = GUINT_TO_POINTER (0);
thumbnailer->idles = NULL;
+ thumbnailer->wait_queue_idle_id = 0;
/* try to connect to D-Bus */
connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
@@ -225,6 +240,14 @@ thunar_thumbnailer_finalize (GObject *object)
/* acquire the thumbnailer lock */
g_mutex_lock (thumbnailer->lock);
+ /* clear the request queue */
+ g_list_foreach (thumbnailer->wait_queue, (GFunc) thunar_thumbnailer_item_free, NULL);
+ g_list_free (thumbnailer->wait_queue);
+
+ /* remove the request queue processing idle handler */
+ if (thumbnailer->wait_queue_idle_id > 0)
+ g_source_remove (thumbnailer->wait_queue_idle_id);
+
/* abort all pending idle functions */
for (lp = thumbnailer->idles; lp != NULL; lp = lp->next)
{
@@ -811,6 +834,97 @@ thunar_thumbnailer_started_idle (gpointer user_data)
static gboolean
+thunar_thumbnailer_file_is_in_wait_queue (ThunarThumbnailer *thumbnailer,
+ ThunarFile *file)
+{
+ ThunarThumbnailerItem *item;
+ gboolean in_wait_queue = FALSE;
+ GList *lp;
+
+ g_mutex_lock (thumbnailer->lock);
+
+ for (lp = thumbnailer->wait_queue; !in_wait_queue && lp != NULL; lp = lp->next)
+ {
+ item = lp->data;
+
+ if (g_file_equal (item->file, thunar_file_get_file (file)))
+ in_wait_queue = TRUE;
+ }
+
+ g_mutex_unlock (thumbnailer->lock);
+
+ return in_wait_queue;
+}
+
+
+
+static gboolean
+thunar_thumbnailer_process_wait_queue (ThunarThumbnailer *thumbnailer)
+{
+ ThunarThumbnailerItem *item;
+ gpointer request;
+ GList *lp;
+ gchar **mime_hints;
+ gchar **uris;
+ guint n_items;
+ guint n;
+
+ _thunar_return_val_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer), FALSE);
+
+ g_mutex_lock (thumbnailer->lock);
+
+ /* determine how many URIs are in the wait queue */
+ n_items = g_list_length (thumbnailer->wait_queue);
+
+ /* allocate arrays for URIs and mime hints */
+ uris = g_new0 (gchar *, n_items + 1);
+ mime_hints = g_new0 (gchar *, n_items + 1);
+
+ /* fill URI and MIME hint arrays with items from the wait queue */
+ for (lp = g_list_last (thumbnailer->wait_queue), n = 0; lp != NULL; lp = lp->prev, ++n)
+ {
+ /* fetch the next item from the queue */
+ item = lp->data;
+
+ /* save URI and MIME hint in the arrays */
+ uris[n] = g_file_get_uri (item->file);
+ mime_hints[n] = item->mime_hint;
+
+ /* destroy the GFile and the queue item. The MIME hints are free'd later */
+ g_object_unref (item->file);
+ g_slice_free (ThunarThumbnailerItem, item);
+ }
+
+ /* NULL-terminate both arrays */
+ uris[n] = NULL;
+ mime_hints[n] = NULL;
+
+ /* queue a thumbnail request for the URIs from the wait queue */
+ request = thunar_thumbnailer_queue_async (thumbnailer,
+ (const gchar **)uris,
+ (const gchar **)mime_hints);
+
+ /* remember the URIs for this request */
+ g_hash_table_insert (thumbnailer->request_uris_mapping, request, uris);
+
+ /* free mime hints array */
+ g_strfreev (mime_hints);
+
+ /* clear the wait queue */
+ g_list_free (thumbnailer->wait_queue);
+ thumbnailer->wait_queue = NULL;
+
+ /* reset the wait queue idle ID */
+ thumbnailer->wait_queue_idle_id = 0;
+
+ g_mutex_unlock (thumbnailer->lock);
+
+ return FALSE;
+}
+
+
+
+static gboolean
thunar_thumbnailer_file_is_queued (ThunarThumbnailer *thumbnailer,
ThunarFile *file)
{
@@ -927,6 +1041,35 @@ thunar_thumbnailer_idle_free (gpointer data)
/* free the struct */
g_slice_free (ThunarThumbnailerIdle, idle);
}
+
+
+
+static ThunarThumbnailerItem *
+thunar_thumbnailer_item_new (GFile *file,
+ const gchar *mime_hint)
+{
+ ThunarThumbnailerItem *item;
+
+ _thunar_return_val_if_fail (G_IS_FILE (file), NULL);
+ _thunar_return_val_if_fail (mime_hint != NULL && mime_hint != '\0', NULL);
+
+ item = g_slice_new0 (ThunarThumbnailerItem);
+ item->file = g_object_ref (file);
+ item->mime_hint = g_strdup (mime_hint);
+
+ return item;
+}
+
+
+static void
+thunar_thumbnailer_item_free (gpointer data)
+{
+ ThunarThumbnailerItem *item = data;
+
+ g_object_unref (item->file);
+ g_free (item->mime_hint);
+ g_slice_free (ThunarThumbnailerItem, item);
+}
#endif /* HAVE_DBUS */
@@ -974,15 +1117,13 @@ gboolean
thunar_thumbnailer_queue_files (ThunarThumbnailer *thumbnailer,
GList *files)
{
- gboolean success = FALSE;
#ifdef HAVE_DBUS
- const gchar **mime_hints;
- gpointer request;
- GList *lp;
- GList *supported_files = NULL;
- gchar **uris;
- guint n_supported = 0;
- guint n;
+ ThunarThumbnailerItem *item;
+#endif
+ gboolean success = FALSE;
+#ifdef HAVE_DBUS
+ GList *lp;
+ GList *supported_files = NULL;
#endif
_thunar_return_val_if_fail (THUNAR_IS_THUMBNAILER (thumbnailer), FALSE);
@@ -992,71 +1133,64 @@ thunar_thumbnailer_queue_files (ThunarThumbnailer *thumbnailer,
/* acquire the thumbnailer lock */
g_mutex_lock (thumbnailer->lock);
- if (thumbnailer->thumbnailer_proxy != NULL)
+ if (thumbnailer->thumbnailer_proxy == NULL)
{
+ /* release the lock and abort */
g_mutex_unlock (thumbnailer->lock);
+ return FALSE;
+ }
- /* collect all supported files from the list */
- for (lp = g_list_last (files); lp != NULL; lp = lp->prev)
- if (thunar_thumbnailer_file_is_supported (thumbnailer, lp->data))
+ /* release the thumbnailer lock */
+ g_mutex_unlock (thumbnailer->lock);
+
+ /* collect all supported files from the list that are neither in the
+ * about to be queued (wait queue), nor already queued, nor already
+ * processed (and awaiting to be refreshed) */
+ for (lp = g_list_last (files); lp != NULL; lp = lp->prev)
+ if (thunar_thumbnailer_file_is_supported (thumbnailer, lp->data))
+ {
+ if (!thunar_thumbnailer_file_is_in_wait_queue (thumbnailer, lp->data)
+ && !thunar_thumbnailer_file_is_queued (thumbnailer, lp->data)
+ && !thunar_thumbnailer_file_is_ready (thumbnailer, lp->data))
{
supported_files = g_list_prepend (supported_files, lp->data);
- n_supported += 1;
}
+ }
- /* remove all files from the supported list for which we have pending requests */
+ /* check if we have any supported files */
+ if (supported_files != NULL)
+ {
for (lp = supported_files; lp != NULL; lp = lp->next)
{
- /* check queued requests and ready idle structs */
- if (thunar_thumbnailer_file_is_queued (thumbnailer, lp->data)
- || thunar_thumbnailer_file_is_ready (thumbnailer, lp->data))
- {
- /* remove the link if the file is present in either of the above */
- supported_files = g_list_delete_link (supported_files, lp);
- }
- }
-
- g_mutex_lock (thumbnailer->lock);
-
- /* check if we have any supported files */
- if (supported_files != NULL)
- {
- /* allocate arrays for URIs and mime hints */
- uris = g_new0 (gchar *, n_supported + 1);
- mime_hints = g_new0 (const gchar *, n_supported + 1);
+ g_mutex_lock (thumbnailer->lock);
- /* fill arrays with data from the supported files */
- for (lp = supported_files, n = 0; lp != NULL; lp = lp->next, ++n)
- {
- uris[n] = thunar_file_dup_uri (lp->data);
- mime_hints[n] = thunar_file_get_content_type (lp->data);
- }
+ /* allocate a thumbnailer item for the wait queue */
+ item = thunar_thumbnailer_item_new (thunar_file_get_file (lp->data),
+ thunar_file_get_content_type (lp->data));
- /* NULL-terminate both arrays */
- uris[n] = NULL;
- mime_hints[n] = NULL;
+ /* add the item to the wait queue */
+ thumbnailer->wait_queue = g_list_prepend (thumbnailer->wait_queue, item);
- /* queue a thumbnail request for the supported files */
- request = thunar_thumbnailer_queue_async (thumbnailer,
- (const gchar **)uris,
- mime_hints);
+ g_mutex_unlock (thumbnailer->lock);
+ }
- /* remember the URIs for this request */
- g_hash_table_insert (thumbnailer->request_uris_mapping, request, uris);
+ g_mutex_lock (thumbnailer->lock);
- /* free mime hints array */
- g_free (mime_hints);
+ if (thumbnailer->wait_queue_idle_id == 0)
+ {
+ thumbnailer->wait_queue_idle_id =
+ g_timeout_add (100, (GSourceFunc) thunar_thumbnailer_process_wait_queue,
+ thumbnailer);
+ }
- /* free the list of supported files */
- g_list_free (supported_files);
+ g_mutex_unlock (thumbnailer->lock);
+
+ /* free the list of supported files */
+ g_list_free (supported_files);
- /* we assume success if we've come so far */
- success = TRUE;
- }
+ /* we assume success if we've come so far */
+ success = TRUE;
}
-
- /* release the thumbnailer lock */
- g_mutex_unlock (thumbnailer->lock);
#endif /* HAVE_DBUS */
return success;
More information about the Xfce4-commits
mailing list