Skip to content

Commit fa605ef

Browse files
author
Tom Yang
committed
update ManualDWARFIndex::Index to use std::once
Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags:
1 parent e5f3d7f commit fa605ef

File tree

2 files changed

+106
-103
lines changed

2 files changed

+106
-103
lines changed

lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp

Lines changed: 105 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -33,118 +33,121 @@ using namespace lldb_private::plugin::dwarf;
3333
using namespace llvm::dwarf;
3434

3535
void 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

150153
void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, SymbolFileDWARFDwo *dwp,

lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ class ManualDWARFIndex : public DWARFIndex {
170170
llvm::DenseSet<uint64_t> m_type_sigs_to_avoid;
171171

172172
IndexSet<NameToDIE> m_set;
173-
bool m_indexed = false;
173+
std::once_flag m_indexed_flag;
174174
};
175175
} // namespace dwarf
176176
} // namespace lldb_private::plugin

0 commit comments

Comments
 (0)