[Bf-blender-cvs] [f9e22fd1ca7] profiler-editor: fix shutdown issues

Jacques Lucke noreply at git.blender.org
Thu Apr 29 11:30:49 CEST 2021


Commit: f9e22fd1ca7959225458864450c64dfeb5f81465
Author: Jacques Lucke
Date:   Wed Apr 28 10:13:41 2021 +0200
Branches: profiler-editor
https://developer.blender.org/rBf9e22fd1ca7959225458864450c64dfeb5f81465

fix shutdown issues

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

M	source/blender/blenlib/intern/profile.cc

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

diff --git a/source/blender/blenlib/intern/profile.cc b/source/blender/blenlib/intern/profile.cc
index 50c5e61306c..7918ab1008e 100644
--- a/source/blender/blenlib/intern/profile.cc
+++ b/source/blender/blenlib/intern/profile.cc
@@ -35,29 +35,56 @@ static uint64_t get_unique_session_id()
 
 struct ThreadLocalProfileData;
 
-static std::mutex registered_threadlocals_mutex;
-static RawVector<ThreadLocalProfileData *> registered_threadlocals;
+struct ProfileRegistry {
+  static inline std::mutex threadlocals_mutex;
+  RawVector<ThreadLocalProfileData *> threadlocals;
+
+  static inline std::mutex listeners_mutex;
+  RawVector<ProfileListener *> listeners;
+};
+
+/**
+ * All threads that record profile data register themselves here.
+ * It is a shared pointer, because the individual threadlocal variables have to own the registry as
+ * well. Otherwise there are problems at shutdown when this static variable is destructed before
+ * all other threads unregistered themselves.
+ */
+static std::shared_ptr<ProfileRegistry> registry;
+
+static std::shared_ptr<ProfileRegistry> &ensure_registry()
+{
+  static std::mutex mutex;
+  std::lock_guard lock{mutex};
+  if (!registry) {
+    registry = std::make_shared<ProfileRegistry>();
+  }
+  return registry;
+}
 
 template<typename T> using ProfileDataQueue = SingleProducerChunkConsumerQueue<T, RawAllocator>;
 
 struct ThreadLocalProfileData {
   ThreadLocalProfileData()
   {
-    std::lock_guard lock{registered_threadlocals_mutex};
-    registered_threadlocals.append(this);
+    std::lock_guard lock{ProfileRegistry::threadlocals_mutex};
+    used_registry = ensure_registry();
+    registry->threadlocals.append(this);
     thread_id = get_unique_session_id();
   }
 
   ~ThreadLocalProfileData()
   {
-    std::lock_guard lock{registered_threadlocals_mutex};
-    registered_threadlocals.remove_first_occurrence_and_reorder(this);
+    std::lock_guard lock{ProfileRegistry::threadlocals_mutex};
+    used_registry->threadlocals.remove_first_occurrence_and_reorder(this);
   }
 
   uint64_t thread_id;
   ProfileDataQueue<ProfileTaskBegin> queue_begins;
   ProfileDataQueue<ProfileTaskEnd> queue_ends;
   RawStack<uint64_t> id_stack;
+
+  /* Take ownership to make sure that the registry won't be destructed too early. */
+  std::shared_ptr<ProfileRegistry> used_registry;
 };
 
 static thread_local ThreadLocalProfileData threadlocal_profile_data;
@@ -75,23 +102,22 @@ static void stop_profiling()
   bli_profiling_is_enabled = false;
 }
 
-static std::mutex listeners_mutex;
-static RawVector<ProfileListener *> listeners;
-
 ProfileListener::ProfileListener()
 {
-  std::lock_guard lock{listeners_mutex};
-  listeners.append(this);
-  if (listeners.size() == 1) {
+  std::lock_guard lock{ProfileRegistry::listeners_mutex};
+  ensure_registry();
+  registry->listeners.append(this);
+  if (registry->listeners.size() == 1) {
     start_profiling();
   }
 }
 
 ProfileListener::~ProfileListener()
 {
-  std::lock_guard lock{listeners_mutex};
-  listeners.remove_first_occurrence_and_reorder(this);
-  if (listeners.is_empty()) {
+  std::lock_guard lock{ProfileRegistry::listeners_mutex};
+  ensure_registry();
+  registry->listeners.remove_first_occurrence_and_reorder(this);
+  if (registry->listeners.is_empty()) {
     stop_profiling();
   }
 }
@@ -99,15 +125,18 @@ ProfileListener::~ProfileListener()
 void ProfileListener::flush_to_all()
 {
   /* Todo: How to handle short lived threads? */
-  std::scoped_lock lock{listeners_mutex, registered_threadlocals_mutex};
+  std::scoped_lock lock{ProfileRegistry::threadlocals_mutex, ProfileRegistry::listeners_mutex};
+  if (!registry) {
+    return;
+  }
   RecordedProfile recorded_profile;
-  for (ThreadLocalProfileData *data : registered_threadlocals) {
+  for (ThreadLocalProfileData *data : registry->threadlocals) {
     data->queue_begins.consume(
         [&](Span<ProfileTaskBegin> data) { recorded_profile.task_begins.extend(data); });
     data->queue_ends.consume(
         [&](Span<ProfileTaskEnd> data) { recorded_profile.task_ends.extend(data); });
   }
-  for (ProfileListener *listener : listeners) {
+  for (ProfileListener *listener : registry->listeners) {
     listener->handle(recorded_profile);
   }
 }



More information about the Bf-blender-cvs mailing list