@@ -33,118 +33,121 @@ using namespace lldb_private::plugin::dwarf;
3333using namespace llvm ::dwarf;
3434
3535void ManualDWARFIndex::Index () {
36- if (m_indexed)
37- return ;
38- m_indexed = true ;
39-
40- ElapsedTime elapsed (m_index_time);
41- LLDB_SCOPED_TIMERF (" %p" , static_cast <void *>(m_dwarf));
42- if (LoadFromCache ()) {
43- m_dwarf->SetDebugInfoIndexWasLoadedFromCache ();
44- return ;
45- }
36+ // TODO(toyang): wrapping it in the call_once isn't really thread-safe either.
37+ // Though, if index callers always call index() before any read/write
38+ // operation (and would therefore wait here), maybe it's ok?
39+ // TODO(toyang): we wrap this logic in the call_once, but maybe it's better if
40+ // it's a separate function that we call instead?
41+ std::call_once (m_indexed_flag, [this ]() {
42+ ElapsedTime elapsed (m_index_time);
43+ LLDB_SCOPED_TIMERF (" %p" , static_cast <void *>(m_dwarf));
44+ if (LoadFromCache ()) {
45+ m_dwarf->SetDebugInfoIndexWasLoadedFromCache ();
46+ return ;
47+ }
4648
47- DWARFDebugInfo &main_info = m_dwarf->DebugInfo ();
48- SymbolFileDWARFDwo *dwp_dwarf = m_dwarf->GetDwpSymbolFile ().get ();
49- DWARFDebugInfo *dwp_info = dwp_dwarf ? &dwp_dwarf->DebugInfo () : nullptr ;
50-
51- std::vector<DWARFUnit *> units_to_index;
52- units_to_index.reserve (main_info.GetNumUnits () +
53- (dwp_info ? dwp_info->GetNumUnits () : 0 ));
54-
55- // Process all units in the main file, as well as any type units in the dwp
56- // file. Type units in dwo files are handled when we reach the dwo file in
57- // IndexUnit.
58- for (size_t U = 0 ; U < main_info.GetNumUnits (); ++U) {
59- DWARFUnit *unit = main_info.GetUnitAtIndex (U);
60- if (unit && m_units_to_avoid.count (unit->GetOffset ()) == 0 )
61- units_to_index.push_back (unit);
62- }
63- if (dwp_info && dwp_info->ContainsTypeUnits ()) {
64- for (size_t U = 0 ; U < dwp_info->GetNumUnits (); ++U) {
65- if (auto *tu =
66- llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex (U))) {
67- if (!m_type_sigs_to_avoid.contains (tu->GetTypeHash ()))
68- units_to_index.push_back (tu);
49+ DWARFDebugInfo &main_info = m_dwarf->DebugInfo ();
50+ SymbolFileDWARFDwo *dwp_dwarf = m_dwarf->GetDwpSymbolFile ().get ();
51+ DWARFDebugInfo *dwp_info = dwp_dwarf ? &dwp_dwarf->DebugInfo () : nullptr ;
52+
53+ std::vector<DWARFUnit *> units_to_index;
54+ units_to_index.reserve (main_info.GetNumUnits () +
55+ (dwp_info ? dwp_info->GetNumUnits () : 0 ));
56+
57+ // Process all units in the main file, as well as any type units in the dwp
58+ // file. Type units in dwo files are handled when we reach the dwo file in
59+ // IndexUnit.
60+ for (size_t U = 0 ; U < main_info.GetNumUnits (); ++U) {
61+ DWARFUnit *unit = main_info.GetUnitAtIndex (U);
62+ if (unit && m_units_to_avoid.count (unit->GetOffset ()) == 0 )
63+ units_to_index.push_back (unit);
64+ }
65+ if (dwp_info && dwp_info->ContainsTypeUnits ()) {
66+ for (size_t U = 0 ; U < dwp_info->GetNumUnits (); ++U) {
67+ if (auto *tu =
68+ llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex (U))) {
69+ if (!m_type_sigs_to_avoid.contains (tu->GetTypeHash ()))
70+ units_to_index.push_back (tu);
71+ }
6972 }
7073 }
71- }
7274
73- if (units_to_index.empty ())
74- return ;
75-
76- StreamString module_desc;
77- m_module.GetDescription (module_desc.AsRawOstream (),
78- lldb::eDescriptionLevelBrief);
79-
80- // Include 2 passes per unit to index for extracting DIEs from the unit and
81- // indexing the unit, and then extra entries for finalizing each index in the
82- // set.
83- const auto indices = IndexSet<NameToDIE>::Indices ();
84- const uint64_t total_progress = units_to_index.size () * 2 + indices.size ();
85- Progress progress (" Manually indexing DWARF" , module_desc.GetData (),
86- total_progress, /* debugger=*/ nullptr ,
87- Progress::kDefaultHighFrequencyReportTime );
88-
89- // Share one thread pool across operations to avoid the overhead of
90- // recreating the threads.
91- llvm::ThreadPoolTaskGroup task_group (Debugger::GetThreadPool ());
92- const size_t num_threads = Debugger::GetThreadPool ().getMaxConcurrency ();
93-
94- // Run a function for each compile unit in parallel using as many threads as
95- // are available. This is significantly faster than submiting a new task for
96- // each unit.
97- auto for_each_unit = [&](auto &&fn) {
98- std::atomic<size_t > next_cu_idx = 0 ;
99- auto wrapper = [&fn, &next_cu_idx, &units_to_index,
100- &progress](size_t worker_id) {
101- size_t cu_idx;
102- while ((cu_idx = next_cu_idx.fetch_add (1 , std::memory_order_relaxed)) <
103- units_to_index.size ()) {
104- fn (worker_id, cu_idx, units_to_index[cu_idx]);
105- progress.Increment ();
106- }
107- };
75+ if (units_to_index.empty ())
76+ return ;
10877
109- for (size_t i = 0 ; i < num_threads; ++i)
110- task_group.async (wrapper, i);
78+ StreamString module_desc;
79+ m_module.GetDescription (module_desc.AsRawOstream (),
80+ lldb::eDescriptionLevelBrief);
81+
82+ // Include 2 passes per unit to index for extracting DIEs from the unit and
83+ // indexing the unit, and then extra entries for finalizing each index in
84+ // the set.
85+ const auto indices = IndexSet<NameToDIE>::Indices ();
86+ const uint64_t total_progress = units_to_index.size () * 2 + indices.size ();
87+ Progress progress (" Manually indexing DWARF" , module_desc.GetData (),
88+ total_progress, /* debugger=*/ nullptr ,
89+ Progress::kDefaultHighFrequencyReportTime );
90+
91+ // Share one thread pool across operations to avoid the overhead of
92+ // recreating the threads.
93+ llvm::ThreadPoolTaskGroup task_group (Debugger::GetThreadPool ());
94+ const size_t num_threads = Debugger::GetThreadPool ().getMaxConcurrency ();
95+
96+ // Run a function for each compile unit in parallel using as many threads as
97+ // are available. This is significantly faster than submiting a new task for
98+ // each unit.
99+ auto for_each_unit = [&](auto &&fn) {
100+ std::atomic<size_t > next_cu_idx = 0 ;
101+ auto wrapper = [&fn, &next_cu_idx, &units_to_index,
102+ &progress](size_t worker_id) {
103+ size_t cu_idx;
104+ while ((cu_idx = next_cu_idx.fetch_add (1 , std::memory_order_relaxed)) <
105+ units_to_index.size ()) {
106+ fn (worker_id, cu_idx, units_to_index[cu_idx]);
107+ progress.Increment ();
108+ }
109+ };
111110
112- task_group.wait ();
113- };
114-
115- // Extract dies for all DWARFs unit in parallel. Figure out which units
116- // didn't have their DIEs already parsed and remember this. If no DIEs were
117- // parsed prior to this index function call, we are going to want to clear the
118- // CU dies after we are done indexing to make sure we don't pull in all DWARF
119- // dies, but we need to wait until all units have been indexed in case a DIE
120- // in one unit refers to another and the indexes accesses those DIEs.
121- std::vector<std::optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies (
122- units_to_index.size ());
123- for_each_unit ([&clear_cu_dies](size_t , size_t idx, DWARFUnit *unit) {
124- clear_cu_dies[idx] = unit->ExtractDIEsScoped ();
125- });
111+ for (size_t i = 0 ; i < num_threads; ++i)
112+ task_group.async (wrapper, i);
126113
127- // Now index all DWARF unit in parallel.
128- std::vector<IndexSet<NameToDIE>> sets (num_threads);
129- for_each_unit (
130- [this , dwp_dwarf, &sets](size_t worker_id, size_t , DWARFUnit *unit) {
131- IndexUnit (*unit, dwp_dwarf, sets[worker_id]);
132- });
114+ task_group.wait ();
115+ };
133116
134- // Merge partial indexes into a single index. Process each index in a set in
135- // parallel.
136- for (NameToDIE IndexSet<NameToDIE>::*index : indices) {
137- task_group.async ([this , &sets, index, &progress]() {
138- NameToDIE &result = m_set.*index;
139- for (auto &set : sets)
140- result.Append (set.*index);
141- result.Finalize ();
142- progress.Increment ();
117+ // Extract dies for all DWARFs unit in parallel. Figure out which units
118+ // didn't have their DIEs already parsed and remember this. If no DIEs were
119+ // parsed prior to this index function call, we are going to want to clear
120+ // the CU dies after we are done indexing to make sure we don't pull in all
121+ // DWARF dies, but we need to wait until all units have been indexed in case
122+ // a DIE in one unit refers to another and the indexes accesses those DIEs.
123+ std::vector<std::optional<DWARFUnit::ScopedExtractDIEs>> clear_cu_dies (
124+ units_to_index.size ());
125+ for_each_unit ([&clear_cu_dies](size_t , size_t idx, DWARFUnit *unit) {
126+ clear_cu_dies[idx] = unit->ExtractDIEsScoped ();
143127 });
144- }
145- task_group.wait ();
146128
147- SaveToCache ();
129+ // Now index all DWARF unit in parallel.
130+ std::vector<IndexSet<NameToDIE>> sets (num_threads);
131+ for_each_unit (
132+ [this , dwp_dwarf, &sets](size_t worker_id, size_t , DWARFUnit *unit) {
133+ IndexUnit (*unit, dwp_dwarf, sets[worker_id]);
134+ });
135+
136+ // Merge partial indexes into a single index. Process each index in a set in
137+ // parallel.
138+ for (NameToDIE IndexSet<NameToDIE>::*index : indices) {
139+ task_group.async ([this , &sets, index, &progress]() {
140+ NameToDIE &result = m_set.*index;
141+ for (auto &set : sets)
142+ result.Append (set.*index);
143+ result.Finalize ();
144+ progress.Increment ();
145+ });
146+ }
147+ task_group.wait ();
148+
149+ SaveToCache ();
150+ });
148151}
149152
150153void ManualDWARFIndex::IndexUnit (DWARFUnit &unit, SymbolFileDWARFDwo *dwp,
0 commit comments