[Bf-blender-cvs] [8d860d4a9b3] functions: use shared particle allocator instead of one per thread

Jacques Lucke noreply at git.blender.org
Fri Sep 20 16:38:24 CEST 2019


Commit: 8d860d4a9b3ca4c0bd7b97d3087caf63ce7f22ba
Author: Jacques Lucke
Date:   Fri Sep 20 16:00:26 2019 +0200
Branches: functions
https://developer.blender.org/rB8d860d4a9b3ca4c0bd7b97d3087caf63ce7f22ba

use shared particle allocator instead of one per thread

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

M	source/blender/blenlib/BLI_task_cxx.h
M	source/blender/simulations/bparticles/particle_allocator.cpp
M	source/blender/simulations/bparticles/particle_allocator.hpp
M	source/blender/simulations/bparticles/simulate.cpp

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

diff --git a/source/blender/blenlib/BLI_task_cxx.h b/source/blender/blenlib/BLI_task_cxx.h
index 74fcb2a7c78..045df2ebdda 100644
--- a/source/blender/blenlib/BLI_task_cxx.h
+++ b/source/blender/blenlib/BLI_task_cxx.h
@@ -44,7 +44,7 @@ static void parallel_array_elements(ArrayRef<T> array,
                                     bool use_threading = true)
 {
   if (!use_threading) {
-    for (T &element : array) {
+    for (const T &element : array) {
       process_element(element);
     }
     return;
@@ -66,70 +66,12 @@ static void parallel_array_elements(ArrayRef<T> array,
                              const int index,
                              const TaskParallelTLS *__restrict UNUSED(tls)) {
                             ParallelData &data = *(ParallelData *)userdata;
-                            T &element = data.array[index];
+                            const T &element = data.array[index];
                             data.process_element(element);
                           },
                           &settings);
 }
 
-template<typename T, typename ProcessElement, typename CreateThreadLocal, typename FreeThreadLocal>
-static void parallel_array_elements(ArrayRef<T> array,
-                                    ProcessElement process_element,
-                                    CreateThreadLocal create_thread_local,
-                                    FreeThreadLocal free_thread_local,
-                                    bool use_threading = true)
-{
-  using LocalData = decltype(create_thread_local());
-
-  if (!use_threading) {
-    LocalData local_data = create_thread_local();
-    for (const T &element : array) {
-      process_element(element, local_data);
-    }
-    free_thread_local(local_data);
-    return;
-  }
-
-  TaskParallelSettings settings;
-  BLI_parallel_range_settings_defaults(&settings);
-  settings.scheduling_mode = TASK_SCHEDULING_STATIC;
-  settings.min_iter_per_thread = 1;
-
-  struct ParallelData {
-    ArrayRef<T> array;
-    ProcessElement &process_element;
-    CreateThreadLocal &create_thread_local;
-    Map<int, LocalData> thread_locals;
-    std::mutex thread_locals_mutex;
-  } data = {array, process_element, create_thread_local, {}, {}};
-
-  BLI_task_parallel_range(
-      0,
-      array.size(),
-      (void *)&data,
-      [](void *__restrict userdata, const int index, const TaskParallelTLS *__restrict tls) {
-        ParallelData &data = *(ParallelData *)userdata;
-        int thread_id = tls->thread_id;
-
-        data.thread_locals_mutex.lock();
-        LocalData *local_data_ptr = data.thread_locals.lookup_ptr(thread_id);
-        LocalData local_data = (local_data_ptr == nullptr) ? data.create_thread_local() :
-                                                             *local_data_ptr;
-        if (local_data_ptr == nullptr) {
-          data.thread_locals.add_new(thread_id, local_data);
-        }
-        data.thread_locals_mutex.unlock();
-
-        const T &element = data.array[index];
-        data.process_element(element, local_data);
-      },
-      &settings);
-
-  for (LocalData local_data : data.thread_locals.values()) {
-    free_thread_local(local_data);
-  }
-}
-
 template<typename ProcessRange>
 static void parallel_range(IndexRange total_range,
                            uint chunk_size,
diff --git a/source/blender/simulations/bparticles/particle_allocator.cpp b/source/blender/simulations/bparticles/particle_allocator.cpp
index 45ef8c507ff..77cf965508a 100644
--- a/source/blender/simulations/bparticles/particle_allocator.cpp
+++ b/source/blender/simulations/bparticles/particle_allocator.cpp
@@ -6,83 +6,71 @@ ParticleAllocator::ParticleAllocator(ParticlesState &state) : m_state(state)
 {
 }
 
-AttributesBlock &ParticleAllocator::get_non_full_block(AttributesBlockContainer &container)
+void ParticleAllocator::allocate_buffer_ranges(AttributesBlockContainer &container,
+                                               uint size,
+                                               Vector<ArrayRef<void *>> &r_buffers,
+                                               Vector<IndexRange> &r_ranges)
 {
-  AttributesBlock *cached_block = m_non_full_cache.lookup_default(&container, nullptr);
-  if (cached_block != nullptr) {
-    if (cached_block->remaining_capacity() > 0) {
-      return *cached_block;
-    }
-
-    m_non_full_cache.remove(&container);
-  }
-
-  AttributesBlock *block = container.new_block();
-  m_non_full_cache.add_new(&container, block);
-  m_allocated_blocks.append(block);
-  return *block;
-}
-
-void ParticleAllocator::allocate_block_ranges(StringRef particle_system_name,
-                                              uint size,
-                                              Vector<AttributesBlock *> &r_blocks,
-                                              Vector<IndexRange> &r_ranges)
-{
-  AttributesBlockContainer &container = m_state.particle_container(particle_system_name);
+  std::lock_guard<std::mutex> lock(m_request_mutex);
 
   uint remaining_size = size;
   while (remaining_size > 0) {
-    AttributesBlock &block = this->get_non_full_block(container);
-
-    uint size_to_use = std::min(block.remaining_capacity(), remaining_size);
-    IndexRange range(block.size(), size_to_use);
-    block.set_size(block.size() + size_to_use);
-
-    r_blocks.append(&block);
-    r_ranges.append(range);
-
-    this->initialize_new_particles(block, container, range);
-
-    remaining_size -= size_to_use;
+    AttributesBlock *cached_block = m_non_full_cache.lookup_default(&container, nullptr);
+    if (cached_block != nullptr) {
+      uint remaining_in_block = cached_block->remaining_capacity();
+      BLI_assert(remaining_in_block > 0);
+      uint size_to_use = std::min(remaining_size, remaining_in_block);
+
+      IndexRange range(cached_block->size(), size_to_use);
+      r_buffers.append(cached_block->as_ref__all().buffers());
+      r_ranges.append(range);
+      remaining_size -= size_to_use;
+
+      cached_block->set_size(range.one_after_last());
+      if (cached_block->remaining_capacity() == 0) {
+        m_non_full_cache.remove(&container);
+      }
+      continue;
+    }
+    else {
+      AttributesBlock *new_block = container.new_block();
+      m_non_full_cache.add_new(&container, new_block);
+      m_allocated_blocks.append(new_block);
+    }
   }
 }
 
-void ParticleAllocator::initialize_new_particles(AttributesBlock &block,
-                                                 AttributesBlockContainer &container,
-                                                 IndexRange pindices)
+void ParticleAllocator::initialize_new_particles(AttributesBlockContainer &container,
+                                                 AttributesRefGroup &attributes_group)
 {
-  AttributesRef attributes = block.as_ref().slice(pindices);
-  for (uint i : attributes.info().attribute_indices()) {
-    attributes.init_default(i);
-  }
+  for (AttributesRef attributes : attributes_group) {
+    for (uint i : attributes.info().attribute_indices()) {
+      attributes.init_default(i);
+    }
 
-  MutableArrayRef<int32_t> particle_ids = block.as_ref__all().get<int32_t>("ID");
-  IndexRange new_ids = container.new_ids(pindices.size());
-  for (uint i = 0; i < pindices.size(); i++) {
-    uint pindex = pindices[i];
-    particle_ids[pindex] = new_ids[i];
+    MutableArrayRef<int32_t> particle_ids = attributes.get<int32_t>("ID");
+    IndexRange new_ids = container.new_ids(attributes.size());
+    BLI_assert(particle_ids.size() == new_ids.size());
+    for (uint i = 0; i < new_ids.size(); i++) {
+      particle_ids[i] = new_ids[i];
+    }
   }
 }
 
-const AttributesInfo &ParticleAllocator::attributes_info(StringRef particle_system_name)
-{
-  return m_state.particle_container(particle_system_name).attributes_info();
-}
-
 AttributesRefGroup ParticleAllocator::request(StringRef particle_system_name, uint size)
 {
-  Vector<AttributesBlock *> blocks;
+  AttributesBlockContainer &container = m_state.particle_container(particle_system_name);
+
+  Vector<ArrayRef<void *>> buffers;
   Vector<IndexRange> ranges;
-  this->allocate_block_ranges(particle_system_name, size, blocks, ranges);
+  this->allocate_buffer_ranges(container, size, buffers, ranges);
 
-  const AttributesInfo &attributes_info = this->attributes_info(particle_system_name);
+  const AttributesInfo &attributes_info = container.attributes_info();
+  AttributesRefGroup attributes_group(attributes_info, std::move(buffers), std::move(ranges));
 
-  Vector<ArrayRef<void *>> buffers;
-  for (uint i = 0; i < blocks.size(); i++) {
-    buffers.append(blocks[i]->as_ref().buffers());
-  }
+  this->initialize_new_particles(container, attributes_group);
 
-  return AttributesRefGroup(attributes_info, std::move(buffers), std::move(ranges));
+  return attributes_group;
 }
 
 }  // namespace BParticles
diff --git a/source/blender/simulations/bparticles/particle_allocator.hpp b/source/blender/simulations/bparticles/particle_allocator.hpp
index c63ce4bc6c7..79b41363e61 100644
--- a/source/blender/simulations/bparticles/particle_allocator.hpp
+++ b/source/blender/simulations/bparticles/particle_allocator.hpp
@@ -6,28 +6,24 @@ namespace BParticles {
 
 using BKE::AttributesRefGroup;
 
-/**
- * This class allows allocating new blocks from different particle containers.
- * A single instance is not thread safe, but multiple allocator instances can
- * be used by multiple threads at the same time.
- * It might hand out the same block more than once until it is full.
- */
-class ParticleAllocator {
+class ParticleAllocator : BLI::NonCopyable, BLI::NonMovable {
  private:
   ParticlesState &m_state;
   Map<AttributesBlockContainer *, AttributesBlock *> m_non_full_cache;
   Vector<AttributesBlock *> m_allocated_blocks;
+  std::mutex m_request_mutex;
 
  public:
   ParticleAllocator(ParticlesState &state);
-  ParticleAllocator(ParticleAllocator &other) = delete;
-  ParticleAllocator(ParticleAllocator &&other) = delete;
 
   /**
    * Access all blocks that have been allocated by this allocator.
    */
   ArrayRef<AttributesBlock *> allocated_blocks();
 
+  /**
+   * Get memory buffers for new particles.
+   */
   AttributesRefGroup request(StringRef particle_

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list