[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