[Bf-blender-cvs] [0eb570cbbb3] temp-parallel-multi-function: progress

Jacques Lucke noreply at git.blender.org
Fri Sep 10 11:02:28 CEST 2021


Commit: 0eb570cbbb32b43048be13b6ba86de7ee30e6978
Author: Jacques Lucke
Date:   Thu Sep 9 18:55:38 2021 +0200
Branches: temp-parallel-multi-function
https://developer.blender.org/rB0eb570cbbb32b43048be13b6ba86de7ee30e6978

progress

===================================================================

M	source/blender/blenlib/BLI_virtual_array.hh
M	source/blender/functions/CMakeLists.txt
M	source/blender/functions/FN_multi_function_procedure.hh
A	source/blender/functions/FN_multi_function_procedure_optimization.hh
M	source/blender/functions/intern/field.cc
A	source/blender/functions/intern/multi_function_procedure_optimization.cc

===================================================================

diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
index e99036d06a9..8caa61dc8ef 100644
--- a/source/blender/blenlib/BLI_virtual_array.hh
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -622,50 +622,42 @@ inline void devirtualize_varray2(const VArray<T1> &varray1,
                                  const Func &func,
                                  bool enable = true)
 {
-  devirtualize_varray(
-      varray1,
-      [&](const auto &varray1) {
-        devirtualize_varray(
-            varray2, [&](const auto &varray2) { func(varray1, varray2); }, enable);
-      },
-      enable);
-
-  // /* Support disabling the devirtualization to simplify benchmarking. */
-  // if (enable) {
-  //   const bool is_span1 = varray1.is_span();
-  //   const bool is_span2 = varray2.is_span();
-  //   const bool is_single1 = varray1.is_single();
-  //   const bool is_single2 = varray2.is_single();
-  //   if (is_span1 && is_span2) {
-  //     const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()};
-  //     const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()};
-  //     func(varray1_span, varray2_span);
-  //     return;
-  //   }
-  //   if (is_span1 && is_single2) {
-  //     const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()};
-  //     const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()};
-  //     func(varray1_span, varray2_single);
-  //     return;
-  //   }
-  //   if (is_single1 && is_span2) {
-  //     const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()};
-  //     const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()};
-  //     func(varray1_single, varray2_span);
-  //     return;
-  //   }
-  //   if (is_single1 && is_single2) {
-  //     const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()};
-  //     const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()};
-  //     func(varray1_single, varray2_single);
-  //     return;
-  //   }
-  // }
-  // /* This fallback is used even when one of the inputs could be optimized. It's probably not
-  // worth
-  //  * it to optimize just one of the inputs, because then the compiler still has to call into
-  //  * unknown code, which inhibits many compiler optimizations. */
-  // func(varray1, varray2);
+  /* Support disabling the devirtualization to simplify benchmarking. */
+  if (enable) {
+    const bool is_span1 = varray1.is_span();
+    const bool is_span2 = varray2.is_span();
+    const bool is_single1 = varray1.is_single();
+    const bool is_single2 = varray2.is_single();
+    if (is_span1 && is_span2) {
+      const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()};
+      const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()};
+      func(varray1_span, varray2_span);
+      return;
+    }
+    if (is_span1 && is_single2) {
+      const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()};
+      const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()};
+      func(varray1_span, varray2_single);
+      return;
+    }
+    if (is_single1 && is_span2) {
+      const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()};
+      const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()};
+      func(varray1_single, varray2_span);
+      return;
+    }
+    if (is_single1 && is_single2) {
+      const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()};
+      const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()};
+      func(varray1_single, varray2_single);
+      return;
+    }
+  }
+  /* This fallback is used even when one of the inputs could be optimized. It's probably not
+  worth
+   * it to optimize just one of the inputs, because then the compiler still has to call into
+   * unknown code, which inhibits many compiler optimizations. */
+  func(varray1, varray2);
 }
 
 }  // namespace blender
diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt
index 856668f01d7..168d03792a7 100644
--- a/source/blender/functions/CMakeLists.txt
+++ b/source/blender/functions/CMakeLists.txt
@@ -38,6 +38,7 @@ set(SRC
   intern/multi_function_procedure.cc
   intern/multi_function_procedure_builder.cc
   intern/multi_function_procedure_executor.cc
+  intern/multi_function_procedure_optimization.cc
 
   FN_cpp_type.hh
   FN_cpp_type_make.hh
@@ -59,6 +60,7 @@ set(SRC
   FN_multi_function_procedure.hh
   FN_multi_function_procedure_builder.hh
   FN_multi_function_procedure_executor.hh
+  FN_multi_function_procedure_optimization.hh
   FN_multi_function_signature.hh
 )
 
diff --git a/source/blender/functions/FN_multi_function_procedure.hh b/source/blender/functions/FN_multi_function_procedure.hh
index 62f2292c1d9..407d87fde63 100644
--- a/source/blender/functions/FN_multi_function_procedure.hh
+++ b/source/blender/functions/FN_multi_function_procedure.hh
@@ -246,6 +246,9 @@ class MFProcedure : NonCopyable, NonMovable {
   Span<MFVariable *> variables();
   Span<const MFVariable *> variables() const;
 
+  Span<MFDestructInstruction *> destruct_instructions();
+  Span<const MFDestructInstruction *> destruct_instructions() const;
+
   std::string to_dot() const;
 
   bool validate() const;
@@ -449,4 +452,14 @@ inline Span<const MFVariable *> MFProcedure::variables() const
   return variables_;
 }
 
+inline Span<MFDestructInstruction *> MFProcedure::destruct_instructions()
+{
+  return destruct_instructions_;
+}
+
+inline Span<const MFDestructInstruction *> MFProcedure::destruct_instructions() const
+{
+  return destruct_instructions_;
+}
+
 }  // namespace blender::fn
diff --git a/source/blender/functions/FN_multi_function_procedure_optimization.hh b/source/blender/functions/FN_multi_function_procedure_optimization.hh
new file mode 100644
index 00000000000..0f2717642d9
--- /dev/null
+++ b/source/blender/functions/FN_multi_function_procedure_optimization.hh
@@ -0,0 +1,29 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup fn
+ */
+
+#include "FN_multi_function_procedure.hh"
+
+namespace blender::fn::procedure_optimization {
+
+void move_destructs_up(MFProcedure &procedure);
+
+}
diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc
index f680c7ba5ff..5f695e14988 100644
--- a/source/blender/functions/intern/field.cc
+++ b/source/blender/functions/intern/field.cc
@@ -23,6 +23,7 @@
 
 #include "FN_field.hh"
 #include "FN_multi_function_parallel.hh"
+#include "FN_multi_function_procedure_optimization.hh"
 
 #include "FN_field.hh"
 
@@ -339,9 +340,12 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope,
     MFProcedure procedure;
     build_multi_function_procedure_for_fields(
         procedure, scope, field_tree_info, varying_fields_to_evaluate);
+    std::cout << procedure.to_dot() << "\n";
+    fn::procedure_optimization::move_destructs_up(procedure);
+    std::cout << procedure.to_dot() << "\n";
     MFProcedureExecutor procedure_executor{"Procedure", procedure};
-    fn::ParallelMultiFunction parallel_fn{procedure_executor, 20000};
-    const MultiFunction &fn_to_execute = procedure_executor;
+    fn::ParallelMultiFunction parallel_fn{procedure_executor, 10000};
+    const MultiFunction &fn_to_execute = parallel_fn;
 
     MFParamsBuilder mf_params{fn_to_execute, array_size};
     MFContextBuilder mf_context;
diff --git a/source/blender/functions/intern/multi_function_procedure_optimization.cc b/source/blender/functions/intern/multi_function_procedure_optimization.cc
new file mode 100644
index 00000000000..8321dc7d405
--- /dev/null
+++ b/source/blender/functions/intern/multi_function_procedure_optimization.cc
@@ -0,0 +1,71 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "FN_multi_function_procedure_optimization.hh"
+
+namespace blender::fn::procedure_optimization {
+
+void move_destructs_up(MFProcedure &procedure)
+{
+  for (MFDestructInstruction *destruct_instr : procedure.destruct_instructions()) {
+    MFVariable *variable = destruct_instr->variable();
+    if (variable == nullptr) {
+      continue;
+    }
+    if (variable->users().size() != 3) {
+      /* Only support the simple case with two uses of the variable for now. */
+      continue;
+    }
+    /* TODO: This is not working yet. */
+    MFCallInstruction *last_call_instr = nullptr;
+    for (MFInstruction *instr : variable->users()) {
+      if (instr->type() == MFInstructionType::Call) {
+        MFCallInstruction *call_instr = static_cast<MFCallInstruction *>(instr);
+        const int first_param_index = call_instr->params().first_i

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list