From c050fe03d3158233e7b8e6155c10b8e20b70850d Mon Sep 17 00:00:00 2001
From: Ludovico de Nittis <ludovico.denittis@collabora.com>
Date: Tue, 23 Feb 2021 18:05:12 +0100
Subject: [PATCH] runtime: improve libraries binding speed

Instead of calling bwrap every time we need to bind a library, or the
dependencies of a library, we group them together to speed up the whole
process.

In `bind_icd()`, to decide whether to use a numbered subdir or not, we
check if a symlink for the same library already exists. It also compares
the directory size before and after the binding to check if we were
actually able to capture it.
For this reason we decided to not group together the ICDs/Layers, to
avoid having side effects like in the previous commit
"runtime: improve ICDs binding speed" and to avoid an overly complicated
hard to follow implementation. Instead we group together only the
libraries that need to be binded in `arch->libdir_in_current_namespace`.

Signed-off-by: Ludovico de Nittis <ludovico.denittis@collabora.com>
---
 pressure-vessel/runtime.c | 218 ++++++++++++++++++++++----------------
 1 file changed, 128 insertions(+), 90 deletions(-)

diff --git a/pressure-vessel/runtime.c b/pressure-vessel/runtime.c
index 90ed82324..015aa5d28 100644
--- a/pressure-vessel/runtime.c
+++ b/pressure-vessel/runtime.c
@@ -1481,6 +1481,41 @@ icd_details_free (IcdDetails *self)
 
 G_DEFINE_AUTOPTR_CLEANUP_FUNC (IcdDetails, icd_details_free)
 
+/*
+ * @destination: (not nullable): where to capture the libraries
+ * @patterns: (not nullable): array of patterns for capsule-capture-libs
+ */
+static gboolean
+bind_icd_from_ptr_array (PvRuntime *self,
+                         RuntimeArchitecture *arch,
+                         const gchar *destination,
+                         GPtrArray *patterns,
+                         GError **error)
+{
+  g_autoptr(FlatpakBwrap) temp_bwrap = NULL;
+  gsize i;
+
+  g_return_val_if_fail (runtime_architecture_check_valid (arch), FALSE);
+  g_return_val_if_fail (destination != NULL, FALSE);
+  g_return_val_if_fail (patterns != NULL, FALSE);
+
+  if (!pv_runtime_provide_container_access (self, error))
+    return FALSE;
+
+  temp_bwrap = pv_runtime_get_capsule_capture_libs (self, arch);
+  flatpak_bwrap_add_args (temp_bwrap, "--dest", destination, NULL);
+
+  for (i = 0; i < patterns->len; i++)
+    flatpak_bwrap_add_arg (temp_bwrap, (gchar *)g_ptr_array_index (patterns, i));
+
+  flatpak_bwrap_finish (temp_bwrap);
+
+  if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
+    return FALSE;
+
+  return TRUE;
+}
+
 /*
  * @sequence_number: numbered directory to use to disambiguate between
  *  colliding files with the same basename
@@ -1488,11 +1523,16 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (IcdDetails, icd_details_free)
  * @use_numbered_subdirs: (inout) (not optional): if %TRUE, use a
  *  numbered subdirectory per ICD, for the rare case where not all
  *  drivers have a unique basename or where order matters
- * @use_subdir_for_soname: if %TRUE, the @requested_subdir will be always
+ * @use_subdir_for_kind_soname: if %TRUE, the @requested_subdir will be always
  *  used. If %FALSE, the @requested_subdir will not be used when the provided
  *  library is of the kind "ICD_KIND_SONAME".
+ * @dependency_patterns: (inout) (not nullable): array of patterns for
+ *  capsule-capture-libs
  * @search_path: (nullable): Add the parent directory of the resulting
  *  ICD to this search path if necessary
+ *
+ * Bind the provided @details ICD without its dependencies, and update
+ * @dependency_patterns with @details dependency pattern.
  */
 static gboolean
 bind_icd (PvRuntime *self,
@@ -1502,6 +1542,7 @@ bind_icd (PvRuntime *self,
           IcdDetails *details,
           gboolean *use_numbered_subdirs,
           gboolean use_subdir_for_kind_soname,
+          GPtrArray *dependency_patterns,
           GString *search_path,
           GError **error)
 {
@@ -1530,6 +1571,7 @@ bind_icd (PvRuntime *self,
   g_return_val_if_fail (details->paths_in_container[multiarch_index] == NULL,
                         FALSE);
   g_return_val_if_fail (use_numbered_subdirs != NULL, FALSE);
+  g_return_val_if_fail (dependency_patterns != NULL, FALSE);
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
   g_info ("Capturing loadable module: %s", details->resolved_library);
@@ -1648,17 +1690,7 @@ bind_icd (PvRuntime *self,
       pv_search_path_append (search_path, in_container);
     }
 
-  temp_bwrap = pv_runtime_get_capsule_capture_libs (self, arch);
-  flatpak_bwrap_add_args (temp_bwrap,
-                          "--dest", arch->libdir_in_current_namespace,
-                          dependency_pattern,
-                          NULL);
-  flatpak_bwrap_finish (temp_bwrap);
-
-  if (!pv_bwrap_run_sync (temp_bwrap, NULL, error))
-    return FALSE;
-
-  g_clear_pointer (&temp_bwrap, flatpak_bwrap_free);
+  g_ptr_array_add (dependency_patterns, g_steal_pointer (&dependency_pattern));
 
   if (details->kinds[multiarch_index] == ICD_KIND_ABSOLUTE)
     {
@@ -2753,12 +2785,14 @@ setup_each_json_manifest (PvRuntime *self,
 static gboolean
 collect_vulkan_layers (PvRuntime *self,
                        const GPtrArray *layer_details,
+                       GPtrArray *dependency_patterns,
                        RuntimeArchitecture *arch,
                        const gchar *dir_name,
                        GError **error)
 {
   gsize j;
 
+  g_return_val_if_fail (dependency_patterns != NULL, FALSE);
   g_return_val_if_fail (dir_name != NULL, FALSE);
 
   for (j = 0; j < layer_details->len; j++)
@@ -2834,9 +2868,8 @@ collect_vulkan_layers (PvRuntime *self,
             }
         }
 
-      if (!bind_icd (self, arch, j, dir_name, details,
-                     &use_numbered_subdirs, use_subdir_for_kind_soname,
-                     NULL, error))
+      if (!bind_icd (self, arch, j, dir_name, details, &use_numbered_subdirs,
+                     use_subdir_for_kind_soname, dependency_patterns, NULL, error))
         return FALSE;
     }
 
@@ -2937,70 +2970,68 @@ pv_runtime_get_ld_so (PvRuntime *self,
   return TRUE;
 }
 
-static gboolean
-pv_runtime_collect_graphics_libraries (PvRuntime *self,
-                                       RuntimeArchitecture *arch,
-                                       GError **error)
+/*
+ * @patterns: (inout) (not nullable):
+ */
+static void
+collect_graphics_libraries_patterns (GPtrArray *patterns)
 {
-  g_autoptr(FlatpakBwrap) temp_bwrap = NULL;
-
-  temp_bwrap = pv_runtime_get_capsule_capture_libs (self, arch);
-  flatpak_bwrap_add_args (temp_bwrap,
-                          "--dest", arch->libdir_in_current_namespace,
-                          /* Mesa GLX, etc. */
-                          "gl:",
-                          /* Vulkan */
-                          "if-exists:if-same-abi:soname:libvulkan.so.1",
-                          /* VDPAU */
-                          "if-exists:if-same-abi:soname:libvdpau.so.1",
-                          /* VA-API */
-                          "if-exists:if-same-abi:soname:libva.so.1",
-                          "if-exists:if-same-abi:soname:libva-drm.so.1",
-                          "if-exists:if-same-abi:soname:libva-glx.so.1",
-                          "if-exists:if-same-abi:soname:libva-x11.so.1",
-                          "if-exists:if-same-abi:soname:libva.so.2",
-                          "if-exists:if-same-abi:soname:libva-drm.so.2",
-                          "if-exists:if-same-abi:soname:libva-glx.so.2",
-                          "if-exists:if-same-abi:soname:libva-x11.so.2",
-                          /* NVIDIA proprietary stack */
-                          "if-exists:even-if-older:soname-match:libEGL.so.*",
-                          "if-exists:even-if-older:soname-match:libEGL_nvidia.so.*",
-                          "if-exists:even-if-older:soname-match:libGL.so.*",
-                          "if-exists:even-if-older:soname-match:libGLESv1_CM.so.*",
-                          "if-exists:even-if-older:soname-match:libGLESv1_CM_nvidia.so.*",
-                          "if-exists:even-if-older:soname-match:libGLESv2.so.*",
-                          "if-exists:even-if-older:soname-match:libGLESv2_nvidia.so.*",
-                          "if-exists:even-if-older:soname-match:libGLX.so.*",
-                          "if-exists:even-if-older:soname-match:libGLX_nvidia.so.*",
-                          "if-exists:even-if-older:soname-match:libGLX_indirect.so.*",
-                          "if-exists:even-if-older:soname-match:libGLdispatch.so.*",
-                          "if-exists:even-if-older:soname-match:libOpenGL.so.*",
-                          "if-exists:even-if-older:soname-match:libcuda.so.*",
-                          "if-exists:even-if-older:soname-match:libglx.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-cbl.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-cfg.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-compiler.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-egl-wayland.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-eglcore.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-encode.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-fatbinaryloader.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-fbc.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-glcore.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-glsi.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-glvkspirv.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-ifr.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-ml.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-opencl.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-opticalflow.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-ptxjitcompiler.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-rtcore.so.*",
-                          "if-exists:even-if-older:soname-match:libnvidia-tls.so.*",
-                          "if-exists:even-if-older:soname-match:libOpenCL.so.*",
-                          "if-exists:even-if-older:soname-match:libvdpau_nvidia.so.*",
-                          NULL);
-  flatpak_bwrap_finish (temp_bwrap);
-
-  return pv_bwrap_run_sync (temp_bwrap, NULL, error);
+  g_return_if_fail (patterns != NULL);
+
+  /* Mesa GLX, etc. */
+  g_ptr_array_add (patterns, g_strdup ("gl:"));
+
+  /* Vulkan */
+  g_ptr_array_add (patterns, g_strdup ("if-exists:if-same-abi:soname:libvulkan.so.1"));
+
+  /* VDPAU */
+  g_ptr_array_add (patterns, g_strdup ("if-exists:if-same-abi:soname:libvdpau.so.1"));
+
+  /* VA-API */
+  g_ptr_array_add (patterns, g_strdup ("if-exists:if-same-abi:soname:libva.so.1"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:if-same-abi:soname:libva-drm.so.1"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:if-same-abi:soname:libva-glx.so.1"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:if-same-abi:soname:libva-x11.so.1"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:if-same-abi:soname:libva.so.2"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:if-same-abi:soname:libva-drm.so.2"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:if-same-abi:soname:libva-glx.so.2"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:if-same-abi:soname:libva-x11.so.2"));
+
+  /* NVIDIA proprietary stack */
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libEGL.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libEGL_nvidia.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libGL.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libGLESv1_CM.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libGLESv1_CM_nvidia.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libGLESv2.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libGLESv2_nvidia.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libGLX.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libGLX_nvidia.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libGLX_indirect.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libGLdispatch.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libOpenGL.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libcuda.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libglx.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-cbl.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-cfg.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-compiler.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-egl-wayland.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-eglcore.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-encode.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-fatbinaryloader.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-fbc.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-glcore.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-glsi.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-glvkspirv.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-ifr.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-ml.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-opencl.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-opticalflow.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-ptxjitcompiler.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-rtcore.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libnvidia-tls.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libOpenCL.so.*"));
+  g_ptr_array_add (patterns, g_strdup ("if-exists:even-if-older:soname-match:libvdpau_nvidia.so.*"));
 }
 
 static gboolean
@@ -3537,6 +3568,7 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
           g_autoptr(SrtObjectList) va_api_drivers = NULL;
           gboolean use_numbered_subdirs;
           gboolean use_subdir_for_kind_soname;
+          g_autoptr(GPtrArray) patterns = NULL;
 
           if (!pv_runtime_get_ld_so (self, arch, &ld_so_in_runtime, error))
             return FALSE;
@@ -3549,6 +3581,10 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
               continue;
             }
 
+          /* Reserve a size of 128 to avoid frequent reallocation due to the
+           * expected high number of patterns that will be added to the array. */
+          patterns = g_ptr_array_new_full (128, g_free);
+
           any_architecture_works = TRUE;
           g_debug ("Container path: %s -> %s",
                    arch->ld_so, ld_so_in_runtime);
@@ -3558,11 +3594,9 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
 
           g_mkdir_with_parents (arch->libdir_in_current_namespace, 0755);
 
-
           g_debug ("Collecting graphics drivers from provider system...");
 
-          if (!pv_runtime_collect_graphics_libraries (self, arch, error))
-            return FALSE;
+          collect_graphics_libraries_patterns (patterns);
 
           g_debug ("Collecting %s EGL drivers from host system...",
                    arch->details->tuple);
@@ -3586,7 +3620,7 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
 
               if (!bind_icd (self, arch, j, "glvnd", details,
                              &use_numbered_subdirs, use_subdir_for_kind_soname,
-                             NULL, error))
+                             patterns, NULL, error))
                 return FALSE;
             }
 
@@ -3612,20 +3646,20 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
 
               if (!bind_icd (self, arch, j, "vulkan", details,
                              &use_numbered_subdirs, use_subdir_for_kind_soname,
-                             NULL, error))
+                             patterns, NULL, error))
                 return FALSE;
             }
 
           if (self->flags & PV_RUNTIME_FLAGS_IMPORT_VULKAN_LAYERS)
             {
               g_debug ("Collecting Vulkan explicit layers from host system...");
-              if (!collect_vulkan_layers (self, vulkan_exp_layer_details, arch,
-                                          "vulkan_exp_layer", error))
+              if (!collect_vulkan_layers (self, vulkan_exp_layer_details,
+                                          patterns, arch, "vulkan_exp_layer", error))
                 return FALSE;
 
               g_debug ("Collecting Vulkan implicit layers from host system...");
-              if (!collect_vulkan_layers (self, vulkan_imp_layer_details, arch,
-                                          "vulkan_imp_layer", error))
+              if (!collect_vulkan_layers (self, vulkan_imp_layer_details,
+                                          patterns, arch, "vulkan_imp_layer", error))
                 return FALSE;
             }
 
@@ -3653,7 +3687,7 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
                * ends up in a numbered subdirectory won't get used. */
               if (!bind_icd (self, arch, j, "vdpau", details,
                              &use_numbered_subdirs, use_subdir_for_kind_soname,
-                             NULL, error))
+                             patterns, NULL, error))
                 return FALSE;
             }
 
@@ -3679,7 +3713,7 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
 
               if (!bind_icd (self, arch, j, "dri", details,
                              &use_numbered_subdirs, use_subdir_for_kind_soname,
-                             dri_path, error))
+                             patterns, dri_path, error))
                 return FALSE;
             }
 
@@ -3705,10 +3739,14 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self,
 
               if (!bind_icd (self, arch, j, "dri", details,
                              &use_numbered_subdirs, use_subdir_for_kind_soname,
-                             va_api_path, error))
+                             patterns, va_api_path, error))
                 return FALSE;
             }
 
+          if (!bind_icd_from_ptr_array (self, arch, arch->libdir_in_current_namespace,
+                                        patterns, error))
+            return FALSE;
+
           libc = g_build_filename (arch->libdir_in_current_namespace, "libc.so.6", NULL);
 
           /* If we are going to use the provider's libc6 (likely)
-- 
GitLab