WIP: Functions: new local allocator for better memory reuse and performance #104630

Draft
Jacques Lucke wants to merge 44 commits from JacquesLucke/blender:local-allocator into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
7 changed files with 17 additions and 15 deletions
Showing only changes of commit ae4672bd29 - Show all commits

View File

@ -284,7 +284,7 @@ class LazyFunction {
/** /**
* Destruct the storage created in #init_storage. * Destruct the storage created in #init_storage.
*/ */
virtual void destruct_storage(void *storage) const; virtual void destruct_storage(void *storage, LocalPool<> &allocator) const;
/** /**
* Calls `fn` with the input indices that the given `output_index` may depend on. By default * Calls `fn` with the input indices that the given `output_index` may depend on. By default

View File

@ -93,7 +93,7 @@ inline void execute_lazy_function_eagerly_impl(
BasicParams params{ BasicParams params{
fn, input_pointers, output_pointers, input_usages, output_usages, set_outputs}; fn, input_pointers, output_pointers, input_usages, output_usages, set_outputs};
fn.execute(params, context); fn.execute(params, context);
fn.destruct_storage(context.storage); fn.destruct_storage(context.storage, allocator);
/* Make sure all outputs have been computed. */ /* Make sure all outputs have been computed. */
BLI_assert(!Span(set_outputs).contains(false)); BLI_assert(!Span(set_outputs).contains(false));

View File

@ -89,7 +89,7 @@ class GraphExecutor : public LazyFunction {
const SideEffectProvider *side_effect_provider); const SideEffectProvider *side_effect_provider);
void *init_storage(LocalPool<> &allocator) const override; void *init_storage(LocalPool<> &allocator) const override;
void destruct_storage(void *storage) const override; void destruct_storage(void *storage, LocalPool<> &allocator) const override;
private: private:
void execute_impl(Params &params, const Context &context) const override; void execute_impl(Params &params, const Context &context) const override;

View File

@ -30,7 +30,7 @@ void *LazyFunction::init_storage(LocalPool<> & /*allocator*/) const
return nullptr; return nullptr;
} }
void LazyFunction::destruct_storage(void *storage) const void LazyFunction::destruct_storage(void *storage, LocalPool<> & /*allocator*/) const
{ {
BLI_assert(storage == nullptr); BLI_assert(storage == nullptr);
UNUSED_VARS_NDEBUG(storage); UNUSED_VARS_NDEBUG(storage);

View File

@ -267,7 +267,7 @@ class Executor {
BLI_assert(self_.graph_.node_indices_are_valid()); BLI_assert(self_.graph_.node_indices_are_valid());
} }
~Executor() void destruct_self(LocalPool<> & /*parent_allocator*/)
{ {
if (TaskPool *task_pool = task_pool_.load()) { if (TaskPool *task_pool = task_pool_.load()) {
BLI_task_pool_free(task_pool); BLI_task_pool_free(task_pool);
@ -276,9 +276,10 @@ class Executor {
for (const int node_index : range) { for (const int node_index : range) {
const Node &node = *self_.graph_.nodes()[node_index]; const Node &node = *self_.graph_.nodes()[node_index];
NodeState &node_state = *node_states_[node_index]; NodeState &node_state = *node_states_[node_index];
this->destruct_node_state(node, node_state); this->destruct_node_state(node, node_state, this->get_main_or_local_allocator());
} }
}); });
this->~Executor();
} }
/** /**
@ -364,15 +365,14 @@ class Executor {
node_state.outputs = allocator.construct_array<OutputState>(node_outputs.size()); node_state.outputs = allocator.construct_array<OutputState>(node_outputs.size());
} }
void destruct_node_state(const Node &node, NodeState &node_state) void destruct_node_state(const Node &node, NodeState &node_state, LocalPool<> &allocator)
{ {
if (node.is_function()) { if (node.is_function()) {
const LazyFunction &fn = static_cast<const FunctionNode &>(node).function(); const LazyFunction &fn = static_cast<const FunctionNode &>(node).function();
if (node_state.storage != nullptr) { if (node_state.storage != nullptr) {
fn.destruct_storage(node_state.storage); fn.destruct_storage(node_state.storage, allocator);
} }
} }
LocalPool<> &allocator = this->get_main_or_local_allocator();
for (const int i : node.inputs().index_range()) { for (const int i : node.inputs().index_range()) {
InputState &input_state = node_state.inputs[i]; InputState &input_state = node_state.inputs[i];
const InputSocket &input_socket = node.input(i); const InputSocket &input_socket = node.input(i);
@ -891,7 +891,7 @@ class Executor {
if (node_state.storage != nullptr) { if (node_state.storage != nullptr) {
if (node.is_function()) { if (node.is_function()) {
const FunctionNode &fn_node = static_cast<const FunctionNode &>(node); const FunctionNode &fn_node = static_cast<const FunctionNode &>(node);
fn_node.function().destruct_storage(node_state.storage); fn_node.function().destruct_storage(node_state.storage, allocator);
} }
node_state.storage = nullptr; node_state.storage = nullptr;
} }
@ -1337,9 +1337,11 @@ void *GraphExecutor::init_storage(LocalPool<> &allocator) const
return &executor; return &executor;
} }
void GraphExecutor::destruct_storage(void *storage) const void GraphExecutor::destruct_storage(void *storage, LocalPool<> &allocator) const
{ {
std::destroy_at(static_cast<Executor *>(storage)); Executor *executor = static_cast<Executor *>(storage);
executor->destruct_self(allocator);
allocator.deallocate(executor, sizeof(Executor), alignof(Executor));
} }
void GraphExecutorLogger::log_socket_value(const Socket &socket, void GraphExecutorLogger::log_socket_value(const Socket &socket,

View File

@ -1199,7 +1199,7 @@ static GeometrySet compute_geometry(
param_output_usages, param_output_usages,
param_set_outputs}; param_set_outputs};
graph_executor.execute(lf_params, lf_context); graph_executor.execute(lf_params, lf_context);
graph_executor.destruct_storage(lf_context.storage); graph_executor.destruct_storage(lf_context.storage, allocator);
for (GMutablePointer &ptr : inputs_to_destruct) { for (GMutablePointer &ptr : inputs_to_destruct) {
ptr.destruct(); ptr.destruct();

View File

@ -696,10 +696,10 @@ class LazyFunctionForGroupNode : public LazyFunction {
return s; return s;
} }
void destruct_storage(void *storage) const override void destruct_storage(void *storage, LocalPool<> &allocator) const override
{ {
Storage *s = static_cast<Storage *>(storage); Storage *s = static_cast<Storage *>(storage);
graph_executor_->destruct_storage(s->graph_executor_storage); graph_executor_->destruct_storage(s->graph_executor_storage, allocator);
std::destroy_at(s); std::destroy_at(s);
} }
}; };