LibOverride: Make diffing several times faster.
authorBastien Montagne <b.mont29@gmail.com>
Fri, 22 Nov 2019 11:26:36 +0000 (12:26 +0100)
committerBastien Montagne <b.mont29@gmail.com>
Fri, 22 Nov 2019 11:26:36 +0000 (12:26 +0100)
Diffing on undo steps is a critical performance point of override
system, although not required for override itself, it gives user
immediate feedback ove what is overridden.

Profiling showed that rna path text search over overrides operations was
by far the most costly thing here, so now using a runtime temp ghash
mapping for this search instead.

Seems to give at least 5 times speedup on big production rig.

source/blender/blenkernel/intern/library_override.c
source/blender/blenloader/intern/readfile.c
source/blender/makesdna/DNA_ID.h
source/blender/makesrna/intern/rna_access_compare_override.c

index 4f10a5bca6bf74054fdeef71754011c637354530..ae6d1c26a2b6f34e627a27e556187bb0e3ccb3d9 100644 (file)
@@ -36,6 +36,7 @@
 #include "BKE_main.h"
 
 #include "BLI_utildefines.h"
+#include "BLI_ghash.h"
 #include "BLI_listbase.h"
 #include "BLI_string.h"
 
@@ -148,6 +149,10 @@ void BKE_override_library_clear(IDOverrideLibrary *override, const bool do_id_us
 {
   BLI_assert(override != NULL);
 
+  if (override->runtime != NULL) {
+    BLI_ghash_clear(override->runtime, NULL, NULL);
+  }
+
   for (IDOverrideLibraryProperty *op = override->properties.first; op; op = op->next) {
     bke_override_property_clear(op);
   }
@@ -164,6 +169,11 @@ void BKE_override_library_free(struct IDOverrideLibrary **override, const bool d
 {
   BLI_assert(*override != NULL);
 
+  if ((*override)->runtime != NULL) {
+    BLI_ghash_free((*override)->runtime, NULL, NULL);
+    (*override)->runtime = NULL;
+  }
+
   BKE_override_library_clear(*override, do_id_user);
   MEM_freeN(*override);
   *override = NULL;
@@ -285,15 +295,28 @@ bool BKE_override_library_create_from_tag(Main *bmain)
   return ret;
 }
 
+/* We only build override GHash on request. */
+BLI_INLINE IDOverrideLibraryRuntime *override_library_rna_path_mapping_ensure(
+    IDOverrideLibrary *override)
+{
+  if (override->runtime == NULL) {
+    override->runtime = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
+    for (IDOverrideLibraryProperty *op = override->properties.first; op != NULL; op = op->next) {
+      BLI_ghash_insert(override->runtime, op->rna_path, op);
+    }
+  }
+
+  return override->runtime;
+}
+
 /**
  * Find override property from given RNA path, if it exists.
  */
 IDOverrideLibraryProperty *BKE_override_library_property_find(IDOverrideLibrary *override,
                                                               const char *rna_path)
 {
-  /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */
-  return BLI_findstring_ptr(
-      &override->properties, rna_path, offsetof(IDOverrideLibraryProperty, rna_path));
+  IDOverrideLibraryRuntime *override_runtime = override_library_rna_path_mapping_ensure(override);
+  return BLI_ghash_lookup(override_runtime, rna_path);
 }
 
 /**
@@ -303,7 +326,6 @@ IDOverrideLibraryProperty *BKE_override_library_property_get(IDOverrideLibrary *
                                                              const char *rna_path,
                                                              bool *r_created)
 {
-  /* XXX TODO we'll most likely want a runtime ghash to store that mapping at some point. */
   IDOverrideLibraryProperty *op = BKE_override_library_property_find(override, rna_path);
 
   if (op == NULL) {
@@ -311,6 +333,10 @@ IDOverrideLibraryProperty *BKE_override_library_property_get(IDOverrideLibrary *
     op->rna_path = BLI_strdup(rna_path);
     BLI_addtail(&override->properties, op);
 
+    IDOverrideLibraryRuntime *override_runtime = override_library_rna_path_mapping_ensure(
+        override);
+    BLI_ghash_insert(override_runtime, op->rna_path, op);
+
     if (r_created) {
       *r_created = true;
     }
@@ -355,6 +381,9 @@ void BKE_override_library_property_delete(IDOverrideLibrary *override,
                                           IDOverrideLibraryProperty *override_property)
 {
   bke_override_property_clear(override_property);
+  if (override->runtime != NULL) {
+    BLI_ghash_remove(override->runtime, override_property->rna_path, NULL, NULL);
+  }
   BLI_freelinkN(&override->properties, override_property);
 }
 
index f6c1cd0380a1b87f46acb3d613f656ae6b68d318..145d36626c1849496bb8d914ecd0a6fe8c18b493 100644 (file)
@@ -2668,6 +2668,7 @@ static void direct_link_id(FileData *fd, ID *id)
   if (id->override_library) {
     id->override_library = newdataadr(fd, id->override_library);
     link_list_ex(fd, &id->override_library->properties, direct_link_id_override_property_cb);
+    id->override_library->runtime = NULL;
   }
 
   DrawDataList *drawdata = DRW_drawdatalist_from_id(id);
index f303f7720c3b393c9f63b1939e01fbfccad3954f..fce68b11fe431d8af25295cb546072c1ce59e16a 100644 (file)
@@ -32,6 +32,7 @@ extern "C" {
 #endif
 
 struct FileData;
+struct GHash;
 struct GPUTexture;
 struct ID;
 struct Library;
@@ -206,6 +207,9 @@ typedef struct IDOverrideLibraryProperty {
   ListBase operations;
 } IDOverrideLibraryProperty;
 
+/* We do not need a full struct for that currently, just a GHash. */
+typedef struct GHash IDOverrideLibraryRuntime;
+
 /* Main container for all overriding data info of a data-block. */
 typedef struct IDOverrideLibrary {
   /** Reference linked ID which this one overrides. */
@@ -220,6 +224,8 @@ typedef struct IDOverrideLibrary {
   /* Temp ID storing extra override data (used for differential operations only currently).
    * Always NULL outside of read/write context. */
   struct ID *storage;
+
+  IDOverrideLibraryRuntime *runtime;
 } IDOverrideLibrary;
 
 enum eOverrideLibrary_Flag {
index 7dae3cbf339ec59247a311336ce0c277607760e1..c3a81f0c6e125297cc1fb630ed05a24fa4ada7f8 100644 (file)
@@ -27,6 +27,8 @@
 #include "BLI_utildefines.h"
 #include "BLI_string.h"
 
+#define DEBUG_OVERRIDE_TIMEIT
+
 #ifdef DEBUG_OVERRIDE_TIMEIT
 #  include "PIL_time_utildefines.h"
 #endif