diff options
author | Jacques Lucke <jacques@blender.org> | 2021-11-26 13:05:47 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2021-11-26 13:06:16 +0300 |
commit | 658fd8df0bd2427cd77e7fc4bcca8a102f67b626 (patch) | |
tree | 574c5a6f4c11db7047a98ca38c6d6f129a4b10e2 /source/blender/functions/FN_multi_function_params.hh | |
parent | 004172de38d5483b715a5b13d06c2aa5dd3de3f5 (diff) |
Geometry Nodes: refactor multi-threading in field evaluation
Previously, there was a fixed grain size for all multi-functions. That was
not sufficient because some functions could benefit a lot from smaller
grain sizes.
This refactors adds a new `MultiFunction::call_auto` method which has the
same effect as just calling `MultiFunction::call` but additionally figures
out how to execute the specific multi-function efficiently. It determines
a good grain size and decides whether the mask indices should be shifted
or not.
Most multi-function evaluations benefit from this, but medium sized work
loads (1000 - 50000 elements) benefit from it the most. Especially when
expensive multi-functions (e.g. noise) is involved. This is because for
smaller work loads, threading is rarely used and for larger work loads
threading worked fine before already.
With this patch, multi-functions can specify execution hints, that allow
the caller to execute it most efficiently. These execution hints still
have to be added to more functions.
Some performance measurements of a field evaluation involving noise and
math nodes, ordered by the number of elements being evaluated:
```
1,000,000: 133 ms -> 120 ms
100,000: 30 ms -> 18 ms
10,000: 20 ms -> 2.7 ms
1,000: 4 ms -> 0.5 ms
100: 0.5 ms -> 0.4 ms
```
Diffstat (limited to 'source/blender/functions/FN_multi_function_params.hh')
-rw-r--r-- | source/blender/functions/FN_multi_function_params.hh | 29 |
1 files changed, 14 insertions, 15 deletions
diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh index 5c7e75230f3..f4ddc4f2881 100644 --- a/source/blender/functions/FN_multi_function_params.hh +++ b/source/blender/functions/FN_multi_function_params.hh @@ -25,6 +25,8 @@ * the function. `MFParams` is then used inside the called function to access the parameters. */ +#include <mutex> + #include "BLI_resource_scope.hh" #include "FN_generic_pointer.hh" @@ -45,6 +47,9 @@ class MFParamsBuilder { Vector<const GVVectorArray *> virtual_vector_arrays_; Vector<GVectorArray *> vector_arrays_; + std::mutex mutex_; + Vector<std::pair<int, GMutableSpan>> dummy_output_spans_; + friend class MFParams; MFParamsBuilder(const MFSignature &signature, const IndexMask mask) @@ -62,8 +67,8 @@ class MFParamsBuilder { template<typename T> void add_readonly_single_input_value(T value, StringRef expected_name = "") { - T *value_ptr = &scope_.add_value<T>(std::move(value)); - this->add_readonly_single_input(value_ptr, expected_name); + this->add_readonly_single_input(VArray<T>::ForSingle(std::move(value), min_array_size_), + expected_name); } template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "") { @@ -254,20 +259,12 @@ class MFParams { this->assert_correct_param(param_index, name, MFParamType::SingleOutput); int data_index = builder_->signature_->data_index(param_index); GMutableSpan span = builder_->mutable_spans_[data_index]; - if (span.is_empty()) { - /* The output is ignored by the caller, but the multi-function does not handle this case. So - * create a temporary buffer that the multi-function can write to. */ - const CPPType &type = span.type(); - void *buffer = builder_->scope_.linear_allocator().allocate( - builder_->min_array_size_ * type.size(), type.alignment()); - if (!type.is_trivially_destructible()) { - /* Make sure the temporary elements will be destructed in the end. */ - builder_->scope_.add_destruct_call( - [&type, buffer, mask = builder_->mask_]() { type.destruct_indices(buffer, mask); }); - } - span = GMutableSpan{type, buffer, builder_->min_array_size_}; + if (!span.is_empty()) { + return span; } - return span; + /* The output is ignored by the caller, but the multi-function does not handle this case. So + * create a temporary buffer that the multi-function can write to. */ + return this->ensure_dummy_single_output(data_index); } /** @@ -356,6 +353,8 @@ class MFParams { } #endif } + + GMutableSpan ensure_dummy_single_output(int data_index); }; } // namespace blender::fn |