[Bf-blender-cvs] [8aa6ff8ec9a] functions: Reimplement the way many arrays are allocated

Jacques Lucke noreply at git.blender.org
Mon Aug 12 15:56:58 CEST 2019


Commit: 8aa6ff8ec9ad852f6cc3bfde31bd9a0dae59d37d
Author: Jacques Lucke
Date:   Mon Aug 12 15:50:08 2019 +0200
Branches: functions
https://developer.blender.org/rB8aa6ff8ec9ad852f6cc3bfde31bd9a0dae59d37d

Reimplement the way many arrays are allocated

This new implementation is more generic and easier to use.

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

D	source/blender/blenlib/BLI_array_allocator.hpp
A	source/blender/blenlib/BLI_temporary_allocator.h
A	source/blender/blenlib/BLI_temporary_allocator.hpp
M	source/blender/blenlib/CMakeLists.txt
A	source/blender/blenlib/intern/BLI_temporary_allocator.cpp
M	source/blender/simulations/bparticles/action_interface.hpp
M	source/blender/simulations/bparticles/attributes.hpp
M	source/blender/simulations/bparticles/events.cpp
M	source/blender/simulations/bparticles/integrator.cpp
M	source/blender/simulations/bparticles/particle_function.cpp
M	source/blender/simulations/bparticles/particle_function.hpp
M	source/blender/simulations/bparticles/particle_function_builder.cpp
M	source/blender/simulations/bparticles/simulate.cpp
M	source/blender/simulations/bparticles/step_description_interfaces.cpp
M	source/blender/simulations/bparticles/step_description_interfaces.hpp
M	source/blender/windowmanager/intern/wm_init_exit.c
D	tests/gtests/blenlib/BLI_array_allocator_test.cc
A	tests/gtests/blenlib/BLI_temporary_allocator_test.cc
M	tests/gtests/blenlib/CMakeLists.txt

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

diff --git a/source/blender/blenlib/BLI_array_allocator.hpp b/source/blender/blenlib/BLI_array_allocator.hpp
deleted file mode 100644
index dc19caa4f12..00000000000
--- a/source/blender/blenlib/BLI_array_allocator.hpp
+++ /dev/null
@@ -1,228 +0,0 @@
-#pragma once
-
-/**
- * This allocator should be used, when arrays of the same length are often allocated and
- * deallocated. Knowing that all arrays have the same length makes it possible to just store the
- * size of a single element to identify the buffer length, which is a small number usually.
- */
-
-#include "BLI_stack.hpp"
-#include "BLI_vector_adaptor.hpp"
-
-namespace BLI {
-
-class ArrayAllocator {
- private:
-  Vector<void *, 16> m_all_pointers;
-  Vector<Stack<void *>, 16> m_pointer_stacks;
-  uint m_array_length;
-
- public:
-  /**
-   * Create a new allocator that will allocate arrays with the given length (the element size may
-   * vary).
-   */
-  ArrayAllocator(uint array_length) : m_array_length(array_length)
-  {
-  }
-
-  ArrayAllocator(ArrayAllocator &other) = delete;
-
-  ~ArrayAllocator()
-  {
-    for (void *ptr : m_all_pointers) {
-      MEM_freeN(ptr);
-    }
-  }
-
-  /**
-   * Get the number of elements in the arrays allocated by this allocator.
-   */
-  uint array_size() const
-  {
-    return m_array_length;
-  }
-
-  /**
-   * Allocate an array buffer in which every element has the given size.
-   */
-  void *allocate(uint element_size)
-  {
-    Stack<void *> &stack = this->stack_for_element_size(element_size);
-    if (stack.size() > 0) {
-      return stack.pop();
-    }
-    void *ptr = MEM_mallocN_aligned(m_array_length * element_size, 64, __func__);
-    m_all_pointers.append(ptr);
-    return ptr;
-  }
-
-  /**
-   * Deallocate an array buffer that has been allocated with this allocator before.
-   */
-  void deallocate(void *ptr, uint element_size)
-  {
-    Stack<void *> &stack = this->stack_for_element_size(element_size);
-    BLI_assert(!stack.contains(ptr));
-    stack.push(ptr);
-  }
-
-  /**
-   * Allocate a new array of the given type.
-   */
-  template<typename T> T *allocate()
-  {
-    return (T *)this->allocate(sizeof(T));
-  }
-
-  /**
-   * Deallocate an array of the given type. It has to be allocated with this allocator before.
-   */
-  template<typename T> void deallocate(T *ptr)
-  {
-    return this->deallocate(ptr, sizeof(T));
-  }
-
-  /**
-   * A wrapper for allocated arrays so that they will be deallocated automatically when they go out
-   * of scope.
-   */
-  template<typename T> class ScopedAllocation {
-   private:
-    ArrayAllocator &m_allocator;
-    void *m_ptr;
-    uint m_element_size;
-
-   public:
-    ScopedAllocation(ArrayAllocator &allocator, T *ptr, uint element_size)
-        : m_allocator(allocator), m_ptr(ptr), m_element_size(element_size)
-    {
-    }
-
-    ScopedAllocation(ScopedAllocation &other) = delete;
-    ScopedAllocation(ScopedAllocation &&other)
-        : m_allocator(other.m_allocator), m_ptr(other.m_ptr), m_element_size(other.m_element_size)
-    {
-      other.m_ptr = nullptr;
-    }
-
-    ScopedAllocation &operator=(ScopedAllocation &other) = delete;
-    ScopedAllocation &operator=(ScopedAllocation &&other)
-    {
-      this->~ScopedAllocation();
-      new (this) ScopedAllocation(std::move(other));
-      return *this;
-    }
-
-    ~ScopedAllocation()
-    {
-      if (m_ptr != nullptr) {
-        m_allocator.deallocate(m_ptr, m_element_size);
-      }
-    }
-
-    operator T *() const
-    {
-      return (T *)m_ptr;
-    }
-
-    ArrayAllocator &allocator()
-    {
-      return m_allocator;
-    }
-  };
-
-  /**
-   * Allocate an array with the given element size. The return value is a wrapper around the
-   * pointer, so that it is automatically deallocated.
-   */
-  ScopedAllocation<void> allocate_scoped(uint element_size)
-  {
-    return ScopedAllocation<void>(*this, this->allocate(element_size), element_size);
-  }
-
-  /**
-   * Allocate an array of the given type. The return value is a wrapper around the pointer, so that
-   * it is automatically deallocated.
-   */
-  template<typename T> ScopedAllocation<T> allocate_scoped()
-  {
-    return ScopedAllocation<T>(*this, this->allocate<T>(), sizeof(T));
-  }
-
-  /**
-   * This is a simple vector that has been allocated using an array allocator. The maximum size of
-   * the vector is determined by the allocator.
-   */
-  template<typename T> class VectorAdapter {
-   private:
-    ScopedAllocation<T> m_ptr;
-    VectorAdaptor<T> m_vector;
-
-   public:
-    VectorAdapter(ArrayAllocator &allocator)
-        : m_ptr(allocator.allocate_scoped<T>()), m_vector(m_ptr, allocator.array_size())
-    {
-    }
-
-    ~VectorAdapter() = default;
-
-    operator VectorAdaptor<T> &()
-    {
-      return m_vector;
-    }
-
-    operator ArrayRef<T>()
-    {
-      return m_vector;
-    }
-  };
-
-  /**
-   * This is a simple fixed size array that has been allocated using an array allocator.
-   */
-  template<typename T> class Array {
-   private:
-    ScopedAllocation<T> m_ptr;
-    uint m_size;
-
-   public:
-    Array(ArrayAllocator &allocator) : Array(allocator, allocator.array_size())
-    {
-    }
-
-    Array(ArrayAllocator &allocator, uint size)
-        : m_ptr(allocator.allocate_scoped<T>()), m_size(size)
-    {
-      BLI_assert(size <= allocator.array_size());
-    }
-
-    operator ArrayRef<T>()
-    {
-      return ArrayRef<T>(m_ptr, m_size);
-    }
-
-    T &operator[](uint index)
-    {
-      return ((T *)m_ptr)[index];
-    }
-
-    ArrayRef<T> as_array_ref()
-    {
-      return ArrayRef<T>(m_ptr, m_size);
-    }
-  };
-
- private:
-  Stack<void *> &stack_for_element_size(uint element_size)
-  {
-    BLI_assert(element_size > 0);
-    uint index = element_size - 1;
-    if (index >= m_pointer_stacks.size()) {
-      m_pointer_stacks.append_n_times({}, index - m_pointer_stacks.size() + 1);
-    }
-    return m_pointer_stacks[index];
-  }
-};
-
-};  // namespace BLI
diff --git a/source/blender/blenlib/BLI_temporary_allocator.h b/source/blender/blenlib/BLI_temporary_allocator.h
new file mode 100644
index 00000000000..56b88d641ff
--- /dev/null
+++ b/source/blender/blenlib/BLI_temporary_allocator.h
@@ -0,0 +1,14 @@
+#ifndef __BLI_TEMPORARY_ALLOCATOR_H__
+#define __BLI_TEMPORARY_ALLOCATOR_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void BLI_temporary_buffers_free_all(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BLI_TEMPORARY_ALLOCATOR_H__ */
diff --git a/source/blender/blenlib/BLI_temporary_allocator.hpp b/source/blender/blenlib/BLI_temporary_allocator.hpp
new file mode 100644
index 00000000000..e133a67734f
--- /dev/null
+++ b/source/blender/blenlib/BLI_temporary_allocator.hpp
@@ -0,0 +1,167 @@
+/**
+ * This allocation method should be used when a chunk of memory is only used for a short amount
+ * of time. This makes it possible to cache potentially large buffers for reuse.
+ *
+ * Many cpu-bound algorithms can benefit from being split up into several stages, whereby the
+ * output of one stage is written into an array that is read by the next stage. This improves
+ * debugability as well as profilability. Often a reason this is not done is that the memory
+ * allocation might be expensive. The goal of this allocator is to make this a non-issue, by
+ * reusing the same long buffers over and over again.
+ *
+ * The number of allocated buffers should stay in O(number of threads * max depth of stack trace).
+ * Since these numbers are pretty much constant in Blender, the number of chunks allocated should
+ * not increase over time. For that reason, memory might never be deallocated until Blender exists.
+ */
+
+#pragma once
+
+#include "BLI_utildefines.h"
+#include "BLI_vector_adaptor.hpp"
+
+namespace BLI {
+
+void *allocate_temp_buffer(uint size);
+void free_temp_buffer(void *buffer);
+
+template<typename T> T *allocate_temp_array(uint size)
+{
+  return (T *)allocate_temp_buffer(sizeof(T) * size);
+}
+
+class TemporaryBuffer {
+ private:
+  void *m_ptr;
+  uint m_size = 0;
+
+ public:
+  TemporaryBuffer(uint size) : m_ptr(allocate_temp_buffer(size)), m_size(size)
+  {
+  }
+
+  TemporaryBuffer(const TemporaryBuffer &other) = delete;
+  TemporaryBuffer(TemporaryBuffer &&other) : m_ptr(other.m_ptr)
+  {
+    other.m_ptr = nullptr;
+  }
+
+  ~TemporaryBuffer()
+  {
+    if (m_ptr != nullptr) {
+      free_temp_buffer(m_ptr);
+    }
+  }
+
+  TemporaryBuffer &operator=(TemporaryBuffer &other) = delete;
+  TemporaryBuffer &operator=(TemporaryBuffer &&other)
+  {
+    if (this == &other) {
+      return *this;
+    }
+
+    this->~TemporaryBuffer();
+    new (this) TemporaryBuffer(std::move(other));
+    return *this;
+  }
+
+  uint size() const
+  {
+    return m_size;
+  }
+
+  void *ptr() const
+  {
+    return m_ptr;
+  }
+
+  /**
+   * Take ownership over the pointer.
+   */
+  void *extract_ptr()
+  {
+    void *ptr = m_ptr;
+    m_ptr = nullptr;
+    m_size = 0;
+    return ptr;
+  }
+};
+
+template<typename T> class TemporaryVector {
+ private:
+  TemporaryBuffer m_buffer;
+  VectorAdaptor<T> m_vector;
+
+ public:
+  TemporaryVector(uint capacity)
+      : m_buffer(capacity * sizeof(T)), m_vector((T *)m_buffer.ptr(), capacity)
+  {
+  }
+
+  ~TemporaryVector()
+  {
+    m_vector.clear();
+  }
+
+  operator VectorAdaptor<T> &()
+  {
+    return m_vector;
+  }
+
+  operator ArrayRef<T>()
+  {
+    return m_vector;
+  }
+
+  T &operator[](uint index)
+  {
+    return m_vector[index];
+  }
+
+  VectorAdaptor<T> *operator->()
+  {
+    return &m_vector;
+  }
+};
+
+template<typename T> class TemporaryArray {
+ private:
+  TemporaryBuffer m_buffer;
+  ArrayRef<T> m_array;
+
+ public:
+  TemporaryArray(uint size) : m_buffer(size * sizeof(T)), m_array((T *)m_buffer.ptr(), size)
+  {
+  }
+
+  operator ArrayRef<T>()
+  {
+    return m_array;
+  }
+
+  ArrayRef<T> *operator->()
+  {
+    return &m_array;
+  }
+
+  T &operator[](uint index)
+  {
+    return m_array[index];
+  }
+
+  T *ptr()
+  {
+    return (T *)m_buffer.ptr();
+  }
+
+  /**
+   * Get the array ref and take ownership of the data.
+   */
+  ArrayRef<T> extract()
+  {
+    ArrayRef<T> array_ref = m_array;
+    m_array = {};
+    m_buffer.extract_ptr();
+   

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list