[Lldb-commits] [lldb] [lldb] Implement coalescing of disjoint progress events (PR #84854)

Greg Clayton via lldb-commits lldb-commits at lists.llvm.org
Tue Mar 12 13:11:24 PDT 2024


================
@@ -75,45 +81,86 @@ void Progress::ReportProgress() {
   }
 }
 
-ProgressManager::ProgressManager() : m_progress_category_map() {}
+ProgressManager::ProgressManager()
+    : m_alarm(std::chrono::milliseconds(100)), m_entries() {}
 
 ProgressManager::~ProgressManager() {}
 
+void ProgressManager::Initialize() {
+  assert(!InstanceImpl() && "Already initialized.");
+  InstanceImpl().emplace();
+}
+
+void ProgressManager::Terminate() {
+  assert(InstanceImpl() && "Already terminated.");
+  InstanceImpl().reset();
+}
+
+bool ProgressManager::Enabled() { return InstanceImpl().operator bool(); }
+
 ProgressManager &ProgressManager::Instance() {
-  static std::once_flag g_once_flag;
-  static ProgressManager *g_progress_manager = nullptr;
-  std::call_once(g_once_flag, []() {
-    // NOTE: known leak to avoid global destructor chain issues.
-    g_progress_manager = new ProgressManager();
-  });
-  return *g_progress_manager;
+  assert(InstanceImpl() && "ProgressManager must be initialized");
+  return *InstanceImpl();
+}
+
+std::optional<ProgressManager> &ProgressManager::InstanceImpl() {
+  static std::optional<ProgressManager> g_progress_manager;
+  return g_progress_manager;
 }
 
 void ProgressManager::Increment(const Progress::ProgressData &progress_data) {
-  std::lock_guard<std::mutex> lock(m_progress_map_mutex);
-  // If the current category exists in the map then it is not an initial report,
-  // therefore don't broadcast to the category bit. Also, store the current
-  // progress data in the map so that we have a note of the ID used for the
-  // initial progress report.
-  if (!m_progress_category_map.contains(progress_data.title)) {
-    m_progress_category_map[progress_data.title].second = progress_data;
+  std::lock_guard<std::mutex> lock(m_entries_mutex);
+  llvm::StringRef key = progress_data.title;
+
+  // This is a new progress event.
+  if (!m_entries.contains(key)) {
     ReportProgress(progress_data, EventType::Begin);
+    Entry &entry = m_entries[key];
+    entry.data = progress_data;
+    entry.refcount = 1;
+    return;
+  }
+
+  // This is an existing progress event.
+  Entry &entry = m_entries[key];
+
+  // The progress event was scheduled to be deleted but a new one came in before
+  // the timer expired.
+  if (entry.refcount == 0) {
+    assert(entry.handle != Alarm::INVALID_HANDLE);
+
+    if (!m_alarm.Cancel(entry.handle)) {
+      // The timer expired before we had a chance to cancel it. We have to treat
+      // this as an entirely new progress event.
+      ReportProgress(progress_data, EventType::Begin);
+    }
+    entry.refcount = 1;
+    entry.handle = Alarm::INVALID_HANDLE;
+  } else {
+    entry.refcount++;
   }
----------------
clayborg wrote:

One idea for this code could be:
```
if (entry.refcount++ == 1) {
  // This entry was scheduled to be expired, but no longer is.
  assert(entry.handle != Alarm::INVALID_HANDLE);

  if (!m_alarm.Cancel(entry.handle)) {
    // The timer expired before we had a chance to cancel it. We have to treat
    // this as an entirely new progress event.
    ReportProgress(progress_data, EventType::Begin);
  }
  entry.handle = Alarm::INVALID_HANDLE;
}
```
This just removes the need to manually set `entry.refcount = 1;` or to separately increment refcount in the else body

https://github.com/llvm/llvm-project/pull/84854


More information about the lldb-commits mailing list