[Lldb-commits] [lldb] update ManualDWARFIndex::Index to use std::once (PR #165896)

Tom Yang via lldb-commits lldb-commits at lists.llvm.org
Fri Oct 31 14:08:21 PDT 2025


https://github.com/zhyty updated https://github.com/llvm/llvm-project/pull/165896

>From fa605ef0b0d1a5c2e3fb232b740311dddf5ee226 Mon Sep 17 00:00:00 2001
From: Tom Yang <toyang at fb.com>
Date: Tue, 14 Oct 2025 00:09:38 -0700
Subject: [PATCH 1/4] update ManualDWARFIndex::Index to use std::once

Summary:

Test Plan:

Reviewers:

Subscribers:

Tasks:

Tags:
---
 .../SymbolFile/DWARF/ManualDWARFIndex.cpp     | 207 +++++++++---------
 .../SymbolFile/DWARF/ManualDWARFIndex.h       |   2 +-
 2 files changed, 106 insertions(+), 103 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
index d90108f687f84..ec225f446c45c 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
@@ -33,118 +33,121 @@ using namespace lldb_private::plugin::dwarf;
 using namespace llvm::dwarf;
 
 void ManualDWARFIndex::Index() {
-  if (m_indexed)
-    return;
-  m_indexed = true;
-
-  ElapsedTime elapsed(m_index_time);
-  LLDB_SCOPED_TIMERF("%p", static_cast<void *>(m_dwarf));
-  if (LoadFromCache()) {
-    m_dwarf->SetDebugInfoIndexWasLoadedFromCache();
-    return;
-  }
+  // TODO(toyang): wrapping it in the call_once isn't really thread-safe either.
+  // Though, if index callers always call index() before any read/write
+  // operation (and would therefore wait here), maybe it's ok?
+  // TODO(toyang): we wrap this logic in the call_once, but maybe it's better if
+  // it's a separate function that we call instead?
+  std::call_once(m_indexed_flag, [this]() {
+    ElapsedTime elapsed(m_index_time);
+    LLDB_SCOPED_TIMERF("%p", static_cast<void *>(m_dwarf));
+    if (LoadFromCache()) {
+      m_dwarf->SetDebugInfoIndexWasLoadedFromCache();
+      return;
+    }
 
-  DWARFDebugInfo &main_info = m_dwarf->DebugInfo();
-  SymbolFileDWARFDwo *dwp_dwarf = m_dwarf->GetDwpSymbolFile().get();
-  DWARFDebugInfo *dwp_info = dwp_dwarf ? &dwp_dwarf->DebugInfo() : nullptr;
-
-  std::vector<DWARFUnit *> units_to_index;
-  units_to_index.reserve(main_info.GetNumUnits() +
-                         (dwp_info ? dwp_info->GetNumUnits() : 0));
-
-  // Process all units in the main file, as well as any type units in the dwp
-  // file. Type units in dwo files are handled when we reach the dwo file in
-  // IndexUnit.
-  for (size_t U = 0; U < main_info.GetNumUnits(); ++U) {
-    DWARFUnit *unit = main_info.GetUnitAtIndex(U);
-    if (unit && m_units_to_avoid.count(unit->GetOffset()) == 0)
-      units_to_index.push_back(unit);
-  }
-  if (dwp_info && dwp_info->ContainsTypeUnits()) {
-    for (size_t U = 0; U < dwp_info->GetNumUnits(); ++U) {
-      if (auto *tu =
-              llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) {
-        if (!m_type_sigs_to_avoid.contains(tu->GetTypeHash()))
-          units_to_index.push_back(tu);
+    DWARFDebugInfo &main_info = m_dwarf->DebugInfo();
+    SymbolFileDWARFDwo *dwp_dwarf = m_dwarf->GetDwpSymbolFile().get();
+    DWARFDebugInfo *dwp_info = dwp_dwarf ? &dwp_dwarf->DebugInfo() : nullptr;
+
+    std::vector<DWARFUnit *> units_to_index;
+    units_to_index.reserve(main_info.GetNumUnits() +
+                           (dwp_info ? dwp_info->GetNumUnits() : 0));
+
+    // Process all units in the main file, as well as any type units in the dwp
+    // file. Type units in dwo files are handled when we reach the dwo file in
+    // IndexUnit.
+    for (size_t U = 0; U < main_info.GetNumUnits(); ++U) {
+      DWARFUnit *unit = main_info.GetUnitAtIndex(U);
+      if (unit && m_units_to_avoid.count(unit->GetOffset()) == 0)
+        units_to_index.push_back(unit);
+    }
+    if (dwp_info && dwp_info->ContainsTypeUnits()) {
+      for (size_t U = 0; U < dwp_info->GetNumUnits(); ++U) {
+        if (auto *tu =
+                llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) {
+          if (!m_type_sigs_to_avoid.contains(tu->GetTypeHash()))
+            units_to_index.push_back(tu);
+        }
       }
     }
-  }
 
-  if (units_to_index.empty())
-    return;
-
-  StreamString module_desc;
-  m_module.GetDescription(module_desc.AsRawOstream(),
-                          lldb::eDescriptionLevelBrief);
-
-  // Include 2 passes per unit to index for extracting DIEs from the unit and
-  // indexing the unit, and then extra entries for finalizing each index in the
-  // set.
-  const auto indices = IndexSet<NameToDIE>::Indices();
-  const uint64_t total_progress = units_to_index.size() * 2 + indices.size();
-  Progress progress("Manually indexing DWARF", module_desc.GetData(),
-                    total_progress, /*debugger=*/nullptr,
-                    Progress::kDefaultHighFrequencyReportTime);
-
-  // Share one thread pool across operations to avoid the overhead of
-  // recreating the threads.
-  llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());
-  const size_t num_threads = Debugger::GetThreadPool().getMaxConcurrency();
-
-  // Run a function for each compile unit in parallel using as many threads as
-  // are available. This is significantly faster than submiting a new task for
-  // each unit.
-  auto for_each_unit = [&](auto &&fn) {
-    std::atomic<size_t> next_cu_idx = 0;
-    auto wrapper = [&fn, &next_cu_idx, &units_to_index,
-                    &progress](size_t worker_id) {
-      size_t cu_idx;
-      while ((cu_idx = next_cu_idx.fetch_add(1, std::memory_order_relaxed)) <
-             units_to_index.size()) {
-        fn(worker_id, cu_idx, units_to_index[cu_idx]);
-        progress.Increment();
-      }
-    };
+    if (units_to_index.empty())
+      return;
 
-    for (size_t i = 0; i < num_threads; ++i)
-      task_group.async(wrapper, i);
+    StreamString module_desc;
+    m_module.GetDescription(module_desc.AsRawOstream(),
+                            lldb::eDescriptionLevelBrief);
+
+    // Include 2 passes per unit to index for extracting DIEs from the unit and
+    // indexing the unit, and then extra entries for finalizing each index in
+    // the set.
+    const auto indices = IndexSet<NameToDIE>::Indices();
+    const uint64_t total_progress = units_to_index.size() * 2 + indices.size();
+    Progress progress("Manually indexing DWARF", module_desc.GetData(),
+                      total_progress, /*debugger=*/nullptr,
+                      Progress::kDefaultHighFrequencyReportTime);
+
+    // Share one thread pool across operations to avoid the overhead of
+    // recreating the threads.
+    llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());
+    const size_t num_threads = Debugger::GetThreadPool().getMaxConcurrency();
+
+    // Run a function for each compile unit in parallel using as many threads as
+    // are available. This is significantly faster than submiting a new task for
+    // each unit.
+    auto for_each_unit = [&](auto &&fn) {
+      std::atomic<size_t> next_cu_idx = 0;
+      auto wrapper = [&fn, &next_cu_idx, &units_to_index,
+                      &progress](size_t worker_id) {
+        size_t cu_idx;
+        while ((cu_idx = next_cu_idx.fetch_add(1, std::memory_order_relaxed)) <
+               units_to_index.size()) {
+          fn(worker_id, cu_idx, units_to_index[cu_idx]);
+          progress.Increment();
+        }
+      };
 
-    task_group.wait();
-  };
-
-  // Extract dies for all DWARFs unit in parallel.  Figure out which units
-  // didn't have their DIEs already parsed and remember this.  If no DIEs were
-  // parsed prior to this index function call, we are going to want to clear the
-  // CU dies after we are done indexing to make sure we don't pull in all DWARF
-  // dies, but we need to wait until all units have been indexed in case a DIE
-  // in one unit refers to another and the indexes accesses those DIEs.
-  std::vector<std::optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies(
-      units_to_index.size());
-  for_each_unit([&clear_cu_dies](size_t, size_t idx, DWARFUnit *unit) {
-    clear_cu_dies[idx] = unit->ExtractDIEsScoped();
-  });
+      for (size_t i = 0; i < num_threads; ++i)
+        task_group.async(wrapper, i);
 
-  // Now index all DWARF unit in parallel.
-  std::vector<IndexSet<NameToDIE>> sets(num_threads);
-  for_each_unit(
-      [this, dwp_dwarf, &sets](size_t worker_id, size_t, DWARFUnit *unit) {
-        IndexUnit(*unit, dwp_dwarf, sets[worker_id]);
-      });
+      task_group.wait();
+    };
 
-  // Merge partial indexes into a single index. Process each index in a set in
-  // parallel.
-  for (NameToDIE IndexSet<NameToDIE>::*index : indices) {
-    task_group.async([this, &sets, index, &progress]() {
-      NameToDIE &result = m_set.*index;
-      for (auto &set : sets)
-        result.Append(set.*index);
-      result.Finalize();
-      progress.Increment();
+    // Extract dies for all DWARFs unit in parallel.  Figure out which units
+    // didn't have their DIEs already parsed and remember this.  If no DIEs were
+    // parsed prior to this index function call, we are going to want to clear
+    // the CU dies after we are done indexing to make sure we don't pull in all
+    // DWARF dies, but we need to wait until all units have been indexed in case
+    // a DIE in one unit refers to another and the indexes accesses those DIEs.
+    std::vector<std::optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies(
+        units_to_index.size());
+    for_each_unit([&clear_cu_dies](size_t, size_t idx, DWARFUnit *unit) {
+      clear_cu_dies[idx] = unit->ExtractDIEsScoped();
     });
-  }
-  task_group.wait();
 
-  SaveToCache();
+    // Now index all DWARF unit in parallel.
+    std::vector<IndexSet<NameToDIE>> sets(num_threads);
+    for_each_unit(
+        [this, dwp_dwarf, &sets](size_t worker_id, size_t, DWARFUnit *unit) {
+          IndexUnit(*unit, dwp_dwarf, sets[worker_id]);
+        });
+
+    // Merge partial indexes into a single index. Process each index in a set in
+    // parallel.
+    for (NameToDIE IndexSet<NameToDIE>::*index : indices) {
+      task_group.async([this, &sets, index, &progress]() {
+        NameToDIE &result = m_set.*index;
+        for (auto &set : sets)
+          result.Append(set.*index);
+        result.Finalize();
+        progress.Increment();
+      });
+    }
+    task_group.wait();
+
+    SaveToCache();
+  });
 }
 
 void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, SymbolFileDWARFDwo *dwp,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
index 0b5b2f3e84309..f7d45b5a24990 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
@@ -170,7 +170,7 @@ class ManualDWARFIndex : public DWARFIndex {
   llvm::DenseSet<uint64_t> m_type_sigs_to_avoid;
 
   IndexSet<NameToDIE> m_set;
-  bool m_indexed = false;
+  std::once_flag m_indexed_flag;
 };
 } // namespace dwarf
 } // namespace lldb_private::plugin

>From bf2c75613fc6b62d6ca064d7604eeae20f18a6ec Mon Sep 17 00:00:00 2001
From: Tom Yang <toyang at fb.com>
Date: Fri, 31 Oct 2025 10:59:21 -0700
Subject: [PATCH 2/4] remove TODO comment

Summary:

Test Plan:

Reviewers:

Subscribers:

Tasks:

Tags:
---
 lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
index ec225f446c45c..aa30682faed90 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
@@ -22,7 +22,6 @@
 #include "lldb/Utility/Stream.h"
 #include "lldb/Utility/Timer.h"
 #include "lldb/lldb-private-enumerations.h"
-#include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/ThreadPool.h"
 #include <atomic>
 #include <optional>
@@ -33,11 +32,6 @@ using namespace lldb_private::plugin::dwarf;
 using namespace llvm::dwarf;
 
 void ManualDWARFIndex::Index() {
-  // TODO(toyang): wrapping it in the call_once isn't really thread-safe either.
-  // Though, if index callers always call index() before any read/write
-  // operation (and would therefore wait here), maybe it's ok?
-  // TODO(toyang): we wrap this logic in the call_once, but maybe it's better if
-  // it's a separate function that we call instead?
   std::call_once(m_indexed_flag, [this]() {
     ElapsedTime elapsed(m_index_time);
     LLDB_SCOPED_TIMERF("%p", static_cast<void *>(m_dwarf));

>From 7348607ec95614054625e4de33fe54194dbbc0fc Mon Sep 17 00:00:00 2001
From: Tom Yang <toyang at fb.com>
Date: Fri, 31 Oct 2025 14:05:24 -0700
Subject: [PATCH 3/4] reduce indentation by moving body of call_once into
 IndexImpl

Summary:

Test Plan:

Reviewers:

Subscribers:

Tasks:

Tags:
---
 .../SymbolFile/DWARF/ManualDWARFIndex.cpp     | 202 +++++++++---------
 .../SymbolFile/DWARF/ManualDWARFIndex.h       |   6 +
 2 files changed, 108 insertions(+), 100 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
index aa30682faed90..33769c756c5cc 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
@@ -32,116 +32,118 @@ using namespace lldb_private::plugin::dwarf;
 using namespace llvm::dwarf;
 
 void ManualDWARFIndex::Index() {
-  std::call_once(m_indexed_flag, [this]() {
-    ElapsedTime elapsed(m_index_time);
-    LLDB_SCOPED_TIMERF("%p", static_cast<void *>(m_dwarf));
-    if (LoadFromCache()) {
-      m_dwarf->SetDebugInfoIndexWasLoadedFromCache();
-      return;
-    }
+  std::call_once(m_indexed_flag, [this]() { IndexImpl(); });
+}
 
-    DWARFDebugInfo &main_info = m_dwarf->DebugInfo();
-    SymbolFileDWARFDwo *dwp_dwarf = m_dwarf->GetDwpSymbolFile().get();
-    DWARFDebugInfo *dwp_info = dwp_dwarf ? &dwp_dwarf->DebugInfo() : nullptr;
-
-    std::vector<DWARFUnit *> units_to_index;
-    units_to_index.reserve(main_info.GetNumUnits() +
-                           (dwp_info ? dwp_info->GetNumUnits() : 0));
-
-    // Process all units in the main file, as well as any type units in the dwp
-    // file. Type units in dwo files are handled when we reach the dwo file in
-    // IndexUnit.
-    for (size_t U = 0; U < main_info.GetNumUnits(); ++U) {
-      DWARFUnit *unit = main_info.GetUnitAtIndex(U);
-      if (unit && m_units_to_avoid.count(unit->GetOffset()) == 0)
-        units_to_index.push_back(unit);
-    }
-    if (dwp_info && dwp_info->ContainsTypeUnits()) {
-      for (size_t U = 0; U < dwp_info->GetNumUnits(); ++U) {
-        if (auto *tu =
-                llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) {
-          if (!m_type_sigs_to_avoid.contains(tu->GetTypeHash()))
-            units_to_index.push_back(tu);
-        }
+void ManualDWARFIndex::IndexImpl() {
+  ElapsedTime elapsed(m_index_time);
+  LLDB_SCOPED_TIMERF("%p", static_cast<void *>(m_dwarf));
+  if (LoadFromCache()) {
+    m_dwarf->SetDebugInfoIndexWasLoadedFromCache();
+    return;
+  }
+
+  DWARFDebugInfo &main_info = m_dwarf->DebugInfo();
+  SymbolFileDWARFDwo *dwp_dwarf = m_dwarf->GetDwpSymbolFile().get();
+  DWARFDebugInfo *dwp_info = dwp_dwarf ? &dwp_dwarf->DebugInfo() : nullptr;
+
+  std::vector<DWARFUnit *> units_to_index;
+  units_to_index.reserve(main_info.GetNumUnits() +
+                         (dwp_info ? dwp_info->GetNumUnits() : 0));
+
+  // Process all units in the main file, as well as any type units in the dwp
+  // file. Type units in dwo files are handled when we reach the dwo file in
+  // IndexUnit.
+  for (size_t U = 0; U < main_info.GetNumUnits(); ++U) {
+    DWARFUnit *unit = main_info.GetUnitAtIndex(U);
+    if (unit && m_units_to_avoid.count(unit->GetOffset()) == 0)
+      units_to_index.push_back(unit);
+  }
+  if (dwp_info && dwp_info->ContainsTypeUnits()) {
+    for (size_t U = 0; U < dwp_info->GetNumUnits(); ++U) {
+      if (auto *tu =
+              llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) {
+        if (!m_type_sigs_to_avoid.contains(tu->GetTypeHash()))
+          units_to_index.push_back(tu);
       }
     }
+  }
 
-    if (units_to_index.empty())
-      return;
-
-    StreamString module_desc;
-    m_module.GetDescription(module_desc.AsRawOstream(),
-                            lldb::eDescriptionLevelBrief);
-
-    // Include 2 passes per unit to index for extracting DIEs from the unit and
-    // indexing the unit, and then extra entries for finalizing each index in
-    // the set.
-    const auto indices = IndexSet<NameToDIE>::Indices();
-    const uint64_t total_progress = units_to_index.size() * 2 + indices.size();
-    Progress progress("Manually indexing DWARF", module_desc.GetData(),
-                      total_progress, /*debugger=*/nullptr,
-                      Progress::kDefaultHighFrequencyReportTime);
-
-    // Share one thread pool across operations to avoid the overhead of
-    // recreating the threads.
-    llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());
-    const size_t num_threads = Debugger::GetThreadPool().getMaxConcurrency();
-
-    // Run a function for each compile unit in parallel using as many threads as
-    // are available. This is significantly faster than submiting a new task for
-    // each unit.
-    auto for_each_unit = [&](auto &&fn) {
-      std::atomic<size_t> next_cu_idx = 0;
-      auto wrapper = [&fn, &next_cu_idx, &units_to_index,
-                      &progress](size_t worker_id) {
-        size_t cu_idx;
-        while ((cu_idx = next_cu_idx.fetch_add(1, std::memory_order_relaxed)) <
-               units_to_index.size()) {
-          fn(worker_id, cu_idx, units_to_index[cu_idx]);
-          progress.Increment();
-        }
-      };
-
-      for (size_t i = 0; i < num_threads; ++i)
-        task_group.async(wrapper, i);
+  if (units_to_index.empty())
+    return;
 
-      task_group.wait();
+  StreamString module_desc;
+  m_module.GetDescription(module_desc.AsRawOstream(),
+                          lldb::eDescriptionLevelBrief);
+
+  // Include 2 passes per unit to index for extracting DIEs from the unit and
+  // indexing the unit, and then extra entries for finalizing each index in
+  // the set.
+  const auto indices = IndexSet<NameToDIE>::Indices();
+  const uint64_t total_progress = units_to_index.size() * 2 + indices.size();
+  Progress progress("Manually indexing DWARF", module_desc.GetData(),
+                    total_progress, /*debugger=*/nullptr,
+                    Progress::kDefaultHighFrequencyReportTime);
+
+  // Share one thread pool across operations to avoid the overhead of
+  // recreating the threads.
+  llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());
+  const size_t num_threads = Debugger::GetThreadPool().getMaxConcurrency();
+
+  // Run a function for each compile unit in parallel using as many threads as
+  // are available. This is significantly faster than submiting a new task for
+  // each unit.
+  auto for_each_unit = [&](auto &&fn) {
+    std::atomic<size_t> next_cu_idx = 0;
+    auto wrapper = [&fn, &next_cu_idx, &units_to_index,
+                    &progress](size_t worker_id) {
+      size_t cu_idx;
+      while ((cu_idx = next_cu_idx.fetch_add(1, std::memory_order_relaxed)) <
+             units_to_index.size()) {
+        fn(worker_id, cu_idx, units_to_index[cu_idx]);
+        progress.Increment();
+      }
     };
 
-    // Extract dies for all DWARFs unit in parallel.  Figure out which units
-    // didn't have their DIEs already parsed and remember this.  If no DIEs were
-    // parsed prior to this index function call, we are going to want to clear
-    // the CU dies after we are done indexing to make sure we don't pull in all
-    // DWARF dies, but we need to wait until all units have been indexed in case
-    // a DIE in one unit refers to another and the indexes accesses those DIEs.
-    std::vector<std::optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies(
-        units_to_index.size());
-    for_each_unit([&clear_cu_dies](size_t, size_t idx, DWARFUnit *unit) {
-      clear_cu_dies[idx] = unit->ExtractDIEsScoped();
-    });
+    for (size_t i = 0; i < num_threads; ++i)
+      task_group.async(wrapper, i);
 
-    // Now index all DWARF unit in parallel.
-    std::vector<IndexSet<NameToDIE>> sets(num_threads);
-    for_each_unit(
-        [this, dwp_dwarf, &sets](size_t worker_id, size_t, DWARFUnit *unit) {
-          IndexUnit(*unit, dwp_dwarf, sets[worker_id]);
-        });
-
-    // Merge partial indexes into a single index. Process each index in a set in
-    // parallel.
-    for (NameToDIE IndexSet<NameToDIE>::*index : indices) {
-      task_group.async([this, &sets, index, &progress]() {
-        NameToDIE &result = m_set.*index;
-        for (auto &set : sets)
-          result.Append(set.*index);
-        result.Finalize();
-        progress.Increment();
-      });
-    }
     task_group.wait();
-
-    SaveToCache();
+  };
+
+  // Extract dies for all DWARFs unit in parallel.  Figure out which units
+  // didn't have their DIEs already parsed and remember this.  If no DIEs were
+  // parsed prior to this index function call, we are going to want to clear
+  // the CU dies after we are done indexing to make sure we don't pull in all
+  // DWARF dies, but we need to wait until all units have been indexed in case
+  // a DIE in one unit refers to another and the indexes accesses those DIEs.
+  std::vector<std::optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies(
+      units_to_index.size());
+  for_each_unit([&clear_cu_dies](size_t, size_t idx, DWARFUnit *unit) {
+    clear_cu_dies[idx] = unit->ExtractDIEsScoped();
   });
+
+  // Now index all DWARF unit in parallel.
+  std::vector<IndexSet<NameToDIE>> sets(num_threads);
+  for_each_unit(
+      [this, dwp_dwarf, &sets](size_t worker_id, size_t, DWARFUnit *unit) {
+        IndexUnit(*unit, dwp_dwarf, sets[worker_id]);
+      });
+
+  // Merge partial indexes into a single index. Process each index in a set in
+  // parallel.
+  for (NameToDIE IndexSet<NameToDIE>::*index : indices) {
+    task_group.async([this, &sets, index, &progress]() {
+      NameToDIE &result = m_set.*index;
+      for (auto &set : sets)
+        result.Append(set.*index);
+      result.Finalize();
+      progress.Increment();
+    });
+  }
+  task_group.wait();
+
+  SaveToCache();
 }
 
 void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, SymbolFileDWARFDwo *dwp,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
index f7d45b5a24990..41e0e620a4896 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h
@@ -66,8 +66,14 @@ class ManualDWARFIndex : public DWARFIndex {
   void Dump(Stream &s) override;
 
 private:
+  /// Reads the DWARF debug info to build the index once.
+  ///
+  /// Should be called before attempting to retrieve symbols.
   void Index();
 
+  /// Call `ManualDWARFIndex::Index()` instead.
+  void IndexImpl();
+
   /// Decode a serialized version of this object from data.
   ///
   /// \param data

>From 48d9eeb2023ddb7693192329f8420a4d6f6b9684 Mon Sep 17 00:00:00 2001
From: Tom Yang <toyang at fb.com>
Date: Fri, 31 Oct 2025 14:07:31 -0700
Subject: [PATCH 4/4] undo some comment formatting changes

Summary:

Test Plan:

Reviewers:

Subscribers:

Tasks:

Tags:
---
 .../Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp    | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
index 33769c756c5cc..36dee1470e0a2 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
@@ -77,8 +77,8 @@ void ManualDWARFIndex::IndexImpl() {
                           lldb::eDescriptionLevelBrief);
 
   // Include 2 passes per unit to index for extracting DIEs from the unit and
-  // indexing the unit, and then extra entries for finalizing each index in
-  // the set.
+  // indexing the unit, and then extra entries for finalizing each index in the
+  // set.
   const auto indices = IndexSet<NameToDIE>::Indices();
   const uint64_t total_progress = units_to_index.size() * 2 + indices.size();
   Progress progress("Manually indexing DWARF", module_desc.GetData(),
@@ -113,10 +113,10 @@ void ManualDWARFIndex::IndexImpl() {
 
   // Extract dies for all DWARFs unit in parallel.  Figure out which units
   // didn't have their DIEs already parsed and remember this.  If no DIEs were
-  // parsed prior to this index function call, we are going to want to clear
-  // the CU dies after we are done indexing to make sure we don't pull in all
-  // DWARF dies, but we need to wait until all units have been indexed in case
-  // a DIE in one unit refers to another and the indexes accesses those DIEs.
+  // parsed prior to this index function call, we are going to want to clear the
+  // CU dies after we are done indexing to make sure we don't pull in all DWARF
+  // dies, but we need to wait until all units have been indexed in case a DIE
+  // in one unit refers to another and the indexes accesses those DIEs.
   std::vector<std::optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies(
       units_to_index.size());
   for_each_unit([&clear_cu_dies](size_t, size_t idx, DWARFUnit *unit) {



More information about the lldb-commits mailing list