[gnome-software: 1/2] gs-plugin-job-refine: Parallelize same order plugins




commit 82feb9fd5c045fd8ad32f96b3ed5a0feafe5ec15
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Fri Aug 19 12:15:46 2022 -0300

    gs-plugin-job-refine: Parallelize same order plugins
    
    The GsPluginJobRefine job runs each plugin's refine asynchronously
    and in order. This works great, but there's a small optimization
    we can make: run plugins with the same order in parallel.
    
    Let's say we have 5 plugins: A, B, C, D, and E. Imagine Software
    loaded them, and determined that their orders are, respectivelly,
    0, 0, 1, 1, and 2. With the current refine job chain, plugins
    would run sequentially, as follows:
    
        A → B → C → D → E
    
    Which is technically correct, since it respects the plugin order.
    In theory, plugins of the same order don't conflict, so we could
    improve this by running A and B, and C and D, in parallel, like
    this:
    
        (A, B)  →  (C, D)  →  E
           ^         ^        ^
         Order 0  Order 1   Order 2
    
    This should still preserve the order that Software determined, and
    allows cutting some time.
    
    Do just that.
    
    According to Sysprof, this reduces refining times 100~250 ms, which
    is not much, but it's good to have nonetheless.

 lib/gs-plugin-job-refine.c | 45 +++++++++++++++++++++++++++++++++++++--------
 1 file changed, 37 insertions(+), 8 deletions(-)
---
diff --git a/lib/gs-plugin-job-refine.c b/lib/gs-plugin-job-refine.c
index f9618cd47..4028c8e6f 100644
--- a/lib/gs-plugin-job-refine.c
+++ b/lib/gs-plugin-job-refine.c
@@ -87,6 +87,7 @@
 #include "gs-app-private.h"
 #include "gs-app-list-private.h"
 #include "gs-enums.h"
+#include "gs-plugin-private.h"
 #include "gs-plugin-job-private.h"
 #include "gs-plugin-job-refine.h"
 #include "gs-utils.h"
@@ -239,6 +240,7 @@ typedef struct {
        guint n_pending_ops;
        guint n_pending_recursions;
        guint next_plugin_index;
+       guint next_plugin_order;
 
        /* Output data. */
        GError *error;  /* (nullable) (owned) */
@@ -275,6 +277,7 @@ run_refine_internal_async (GsPluginJobRefine   *self,
        g_autoptr(GTask) task = NULL;
        RefineInternalData *data;
        g_autoptr(RefineInternalData) data_owned = NULL;
+       gboolean anything_ran = FALSE;
 
        task = g_task_new (self, cancellable, callback, user_data);
        g_task_set_source_tag (task, run_refine_internal_async);
@@ -289,6 +292,7 @@ run_refine_internal_async (GsPluginJobRefine   *self,
        gs_plugin_loader_run_adopt (plugin_loader, list);
 
        data->n_pending_ops = 0;
+       data->next_plugin_order = 0;
 
        /* run each plugin
         *
@@ -306,11 +310,21 @@ run_refine_internal_async (GsPluginJobRefine   *self,
                GsPlugin *plugin = g_ptr_array_index (plugins, i);
                GsPluginClass *plugin_class = GS_PLUGIN_GET_CLASS (plugin);
 
+               if (gs_plugin_get_order (plugin) > data->next_plugin_order) {
+                       if (!anything_ran)
+                               data->next_plugin_order = gs_plugin_get_order (plugin);
+                       else
+                               return;
+               }
+
                if (!gs_plugin_get_enabled (plugin))
                        continue;
                if (plugin_class->refine_async == NULL)
                        continue;
 
+               /* at least one plugin supports this vfunc */
+               anything_ran = TRUE;
+
                /* FIXME: The next refine_async() call is made in
                 * finish_refine_internal_op(). */
                data->next_plugin_index = i + 1;
@@ -319,12 +333,11 @@ run_refine_internal_async (GsPluginJobRefine   *self,
                data->n_pending_ops++;
                plugin_class->refine_async (plugin, list, flags,
                                            cancellable, plugin_refine_cb, g_object_ref (task));
-
-               /* FIXME: The next refine_async() call is made in
-                * finish_refine_internal_op(). */
-               return;
        }
 
+       if (!anything_ran)
+               g_debug ("no plugin could handle refining apps");
+
        data->n_pending_ops++;
        finish_refine_internal_op (task, NULL);
 }
@@ -377,6 +390,7 @@ finish_refine_internal_op (GTask  *task,
        GsOdrsProvider *odrs_provider;
        GsOdrsProviderRefineFlags odrs_refine_flags = 0;
        GPtrArray *plugins;  /* (element-type GsPlugin) */
+       gboolean anything_ran = FALSE;
 
        if (data->error == NULL && error_owned != NULL) {
                data->error = g_steal_pointer (&error_owned);
@@ -387,16 +401,35 @@ finish_refine_internal_op (GTask  *task,
        g_assert (data->n_pending_ops > 0);
        data->n_pending_ops--;
 
+       if (data->n_pending_ops > 0)
+               return;
+
+       /* We reach this line after all plugins of a certain order ran, and now
+        * we need to run the next set of plugins. */
+       data->next_plugin_order++;
+
        plugins = gs_plugin_loader_get_plugins (plugin_loader);
 
        for (guint i = data->next_plugin_index; i < plugins->len; i++) {
                GsPlugin *plugin = g_ptr_array_index (plugins, i);
                GsPluginClass *plugin_class = GS_PLUGIN_GET_CLASS (plugin);
 
+               if (gs_plugin_get_order (plugin) > data->next_plugin_order) {
+                       if (!anything_ran)
+                               data->next_plugin_order = gs_plugin_get_order (plugin);
+                       else
+                               return;
+               }
+
                if (!gs_plugin_get_enabled (plugin))
                        continue;
                if (plugin_class->refine_async == NULL)
                        continue;
+               if (gs_plugin_get_order (plugin) < data->next_plugin_order)
+                       continue;
+
+               /* at least one plugin supports this vfunc */
+               anything_ran = TRUE;
 
                /* FIXME: The next refine_async() call is made in
                 * finish_refine_internal_op(). */
@@ -406,10 +439,6 @@ finish_refine_internal_op (GTask  *task,
                data->n_pending_ops++;
                plugin_class->refine_async (plugin, list, flags,
                                            cancellable, plugin_refine_cb, g_object_ref (task));
-
-               /* FIXME: The next refine_async() call is made in
-                * finish_refine_internal_op(). */
-               return;
        }
 
        if (data->next_plugin_index == plugins->len) {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]