Skip to content

Commit 27c248a

Browse files
committed
[lldb] Reduce the frequency of DWARF index progress reporting
Indexing a single DWARF unit is a relatively fast operation, particularly if it's a type unit, which can be very small. Reporting progress takes a mutex (and allocates memory, etc.), which creates a lot of contention and slows down indexing noticeably. This patch reports makes us report progress only once per 10 milliseconds (on average), which speeds up indexing by up to 55%. It achieves this by checking whether the time after indexing every unit. This creates the possibility that a particularly large unit could cause us to stop reporting progress for a while (even for units that have already been indexed), but I don't think this is likely to happen, because: - Even the largest units don't take that long to index. The largest unit in lldb (4MB of .debug_info) was indexed in "only" 200ms. - The time is being checked and reported by all worker threads, which means that in order to stall, we'd have to be very unfortunate and pick up an extremely large compile unit on all indexing threads simultaneously. Even if that does happens, the only negative consequence is some jitteriness in a progress bar, which is why I prefer this over alternative implementations which e.g. involve reporting progress from a dedicated thread.
1 parent 3740fac commit 27c248a

File tree

1 file changed

+23
-8
lines changed

1 file changed

+23
-8
lines changed

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

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/Support/FormatVariadic.h"
2525
#include "llvm/Support/ThreadPool.h"
2626
#include <atomic>
27+
#include <chrono>
2728
#include <optional>
2829

2930
using namespace lldb_private;
@@ -91,21 +92,35 @@ void ManualDWARFIndex::Index() {
9192
// are available. This is significantly faster than submiting a new task for
9293
// each unit.
9394
auto for_each_unit = [&](auto &&fn) {
94-
std::atomic<size_t> next_cu_idx = 0;
95-
auto wrapper = [&fn, &next_cu_idx, &units_to_index,
96-
&progress](size_t worker_id) {
97-
size_t cu_idx;
98-
while ((cu_idx = next_cu_idx.fetch_add(1, std::memory_order_relaxed)) <
99-
units_to_index.size()) {
100-
fn(worker_id, cu_idx, units_to_index[cu_idx]);
101-
progress.Increment();
95+
std::atomic<size_t> next_unit_idx = 0;
96+
std::atomic<size_t> units_indexed = 0;
97+
auto wrapper = [&fn, &next_unit_idx, &units_indexed, &units_to_index,
98+
&progress, num_threads](size_t worker_id) {
99+
constexpr auto progress_interval = std::chrono::milliseconds(10);
100+
101+
// Stagger the reports for different threads so we get a steady stream of
102+
// one report per ~10ms.
103+
auto next_report = std::chrono::steady_clock::now() +
104+
progress_interval * (1 + worker_id);
105+
size_t unit_idx;
106+
while ((unit_idx = next_unit_idx.fetch_add(
107+
1, std::memory_order_relaxed)) < units_to_index.size()) {
108+
fn(worker_id, unit_idx, units_to_index[unit_idx]);
109+
110+
units_indexed.fetch_add(1, std::memory_order_acq_rel);
111+
if (auto now = std::chrono::steady_clock::now(); now >= next_report) {
112+
progress.Increment(
113+
units_indexed.exchange(0, std::memory_order_acq_rel));
114+
next_report = now + num_threads * progress_interval;
115+
}
102116
}
103117
};
104118

105119
for (size_t i = 0; i < num_threads; ++i)
106120
task_group.async(wrapper, i);
107121

108122
task_group.wait();
123+
progress.Increment(units_indexed.load(std::memory_order_acquire));
109124
};
110125

111126
// Extract dies for all DWARFs unit in parallel. Figure out which units

0 commit comments

Comments
 (0)