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
```
This commit is contained in:
2021-11-26 11:05:47 +01:00
parent 004172de38
commit 658fd8df0b
13 changed files with 264 additions and 163 deletions

View File

@@ -1045,7 +1045,7 @@ static void execute_call_instruction(const MFCallInstruction &instruction,
}
try {
fn.call(mask, params, context);
fn.call_auto(mask, params, context);
}
catch (...) {
/* Multi-functions must not throw exceptions. */
@@ -1236,4 +1236,12 @@ void MFProcedureExecutor::call(IndexMask full_mask, MFParams params, MFContext c
}
}
MultiFunction::ExecutionHints MFProcedureExecutor::get_execution_hints() const
{
ExecutionHints hints;
hints.allocates_array = true;
hints.min_grain_size = 10000;
return hints;
}
} // namespace blender::fn