[Bf-blender-cvs] [b4a5df88fa0] functions: try using BufferCache instead of ArrayAllocator

Jacques Lucke noreply at git.blender.org
Mon Jan 27 22:10:48 CET 2020


Commit: b4a5df88fa0112273021fb3ed6241574cfb05694
Author: Jacques Lucke
Date:   Mon Jan 27 21:07:03 2020 +0100
Branches: functions
https://developer.blender.org/rBb4a5df88fa0112273021fb3ed6241574cfb05694

try using BufferCache instead of ArrayAllocator

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

A	source/blender/blenlib/BLI_buffer_cache.h
M	source/blender/blenlib/CMakeLists.txt
M	source/blender/functions/intern/multi_functions/network.cc

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

diff --git a/source/blender/blenlib/BLI_buffer_cache.h b/source/blender/blenlib/BLI_buffer_cache.h
new file mode 100644
index 00000000000..2c7ef82c2dc
--- /dev/null
+++ b/source/blender/blenlib/BLI_buffer_cache.h
@@ -0,0 +1,85 @@
+#ifndef __BLI_BUFFER_ALLOCATOR_H__
+#define __BLI_BUFFER_ALLOCATOR_H__
+
+#include "BLI_vector.h"
+
+namespace BLI {
+
+class BufferCache {
+ private:
+  static const int Alignment = 64;
+
+  struct BufferHead {
+    uint buffer_size_in_bytes;
+
+    void *user_ptr()
+    {
+      BLI_STATIC_ASSERT(sizeof(BufferHead) <= Alignment, "");
+      return POINTER_OFFSET(this, Alignment);
+    }
+
+    static BufferHead *FromUserPtr(void *ptr)
+    {
+      return (BufferHead *)POINTER_OFFSET(ptr, -Alignment);
+    }
+  };
+
+  Vector<BufferHead *, 16> m_all_buffers;
+  Vector<BufferHead *, 16> m_cached_buffers;
+
+ public:
+  BufferCache() = default;
+
+  ~BufferCache()
+  {
+    BLI_assert(m_cached_buffers.size() == m_all_buffers.size());
+
+    for (BufferHead *head : m_all_buffers) {
+      MEM_freeN((void *)head);
+    }
+  }
+
+  void *allocate(uint size, uint alignment)
+  {
+    UNUSED_VARS_NDEBUG(alignment);
+    BLI_assert(alignment <= Alignment);
+
+    /* Only use buffer sizes that are a power of two, to make them easier to reuse. */
+    uint padded_size = power_of_2_max_u(size);
+
+    /* Try to use a cached memory buffer. Start searching from the back to prefer buffers that have
+     * been used "just before". */
+    for (int i = m_cached_buffers.size() - 1; i >= 0; i--) {
+      BufferHead *head = m_cached_buffers[i];
+      if (head->buffer_size_in_bytes == padded_size) {
+        void *user_ptr = head->user_ptr();
+        m_cached_buffers.remove_and_reorder(i);
+        // std::cout << "Reuse buffer\n";
+        return user_ptr;
+      }
+    }
+
+    BufferHead *new_head = (BufferHead *)MEM_mallocN_aligned(
+        padded_size + Alignment, Alignment, "allocate in BufferCache");
+    new_head->buffer_size_in_bytes = padded_size;
+    m_all_buffers.append(new_head);
+    // std::cout << "New buffer\n";
+    return new_head->user_ptr();
+  }
+
+  void deallocate(void *buffer)
+  {
+    BufferHead *head = BufferHead::FromUserPtr(buffer);
+    BLI_assert(m_all_buffers.contains(head));
+    m_cached_buffers.append(head);
+  }
+
+  void *allocate(uint element_amount, uint element_size, uint alignment)
+  {
+    return this->allocate(element_amount * element_size, alignment);
+  }
+};
+
+}  // namespace BLI
+
+#endif /* __BLI_BUFFER_ALLOCATOR_H__ */
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index efe7c6f8c8a..d87bfe94e85 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -279,6 +279,7 @@ set(SRC
   BLI_index_to_ref_map.h
   BLI_rand_cxx.h
   BLI_array_allocator.h
+  BLI_buffer_cache.h
 )
 
 set(LIB
diff --git a/source/blender/functions/intern/multi_functions/network.cc b/source/blender/functions/intern/multi_functions/network.cc
index ea196217643..b5272495c13 100644
--- a/source/blender/functions/intern/multi_functions/network.cc
+++ b/source/blender/functions/intern/multi_functions/network.cc
@@ -1,10 +1,10 @@
 #include "network.h"
 
-#include "BLI_array_allocator.h"
+#include "BLI_buffer_cache.h"
 
 namespace FN {
 
-using BLI::ArrayAllocator;
+using BLI::BufferCache;
 using BLI::ScopedVector;
 
 namespace OutputValueType {
@@ -71,19 +71,18 @@ struct VectorValue : public OutputValue {
 class NetworkEvaluationStorage {
  private:
   MonotonicAllocator<256> m_allocator;
-  ArrayAllocator &m_array_allocator;
+  BufferCache &m_buffer_cache;
   IndexMask m_mask;
   Array<OutputValue *> m_value_per_output_id;
   uint m_min_array_size;
 
  public:
-  NetworkEvaluationStorage(ArrayAllocator &array_allocator, IndexMask mask, uint socket_id_amount)
-      : m_array_allocator(array_allocator),
+  NetworkEvaluationStorage(BufferCache &buffer_cache, IndexMask mask, uint socket_id_amount)
+      : m_buffer_cache(buffer_cache),
         m_mask(mask),
         m_value_per_output_id(socket_id_amount, nullptr),
         m_min_array_size(mask.min_array_size())
   {
-    BLI_assert(array_allocator.array_size() >= m_min_array_size);
   }
 
   ~NetworkEvaluationStorage()
@@ -100,8 +99,8 @@ class NetworkEvaluationStorage {
           type.destruct(array_ref.buffer());
         }
         else {
-          type.destruct_indices(value->array_ref.buffer(), m_mask);
-          m_array_allocator.deallocate(type.size(), value->array_ref.buffer());
+          type.destruct_indices(array_ref.buffer(), m_mask);
+          m_buffer_cache.deallocate(array_ref.buffer());
         }
       }
       else if (any_value->type == OutputValueType::Vector) {
@@ -165,8 +164,8 @@ class NetworkEvaluationStorage {
             type.destruct(array_ref.buffer());
           }
           else {
-            type.destruct_indices(value->array_ref.buffer(), m_mask);
-            m_array_allocator.deallocate(type.size(), value->array_ref.buffer());
+            type.destruct_indices(array_ref.buffer(), m_mask);
+            m_buffer_cache.deallocate(array_ref.buffer());
           }
           m_value_per_output_id[origin.id()] = nullptr;
         }
@@ -215,7 +214,7 @@ class NetworkEvaluationStorage {
     BLI_assert(m_value_per_output_id[socket.id()] == nullptr);
 
     const CPPType &type = socket.data_type().single__cpp_type();
-    void *buffer = m_array_allocator.allocate(type.size(), type.alignment());
+    void *buffer = m_buffer_cache.allocate(m_min_array_size, type.size(), type.alignment());
     GenericMutableArrayRef array_ref(type, buffer, m_min_array_size);
 
     auto *value = m_allocator.construct<SingleValue>(array_ref, socket.target_amount(), false);
@@ -289,7 +288,7 @@ class NetworkEvaluationStorage {
 
     GenericVirtualListRef list_ref = this->get_single_input__full(input);
     const CPPType &type = list_ref.type();
-    void *new_buffer = m_array_allocator.allocate(type.size(), type.alignment());
+    void *new_buffer = m_buffer_cache.allocate(m_min_array_size, type.size(), type.alignment());
     GenericMutableArrayRef new_array_ref(type, new_buffer, m_min_array_size);
     list_ref.materialize_to_uninitialized(m_mask, new_array_ref);
 
@@ -545,10 +544,10 @@ void MF_EvaluateNetwork::call(IndexMask mask, MFParams params, MFContext context
     return;
   }
 
-  ArrayAllocator array_allocator(mask.min_array_size());
+  BufferCache buffer_cache;
   const MFNetwork &network = m_outputs[0]->node().network();
 
-  Storage storage(array_allocator, mask, network.socket_ids().size());
+  Storage storage(buffer_cache, mask, network.socket_ids().size());
   this->copy_inputs_to_storage(params, storage);
   this->evaluate_network_to_compute_outputs(context, storage);
   this->copy_computed_values_to_outputs(params, storage);



More information about the Bf-blender-cvs mailing list