Skip to content

Commit 9a269fa

Browse files
committed
[lldb] Create dependent modules in parallel
Create dependent modules in parallel in Target::SetExecutableModule. This change was inspired by llvm#110646 which takes the same approach when attaching. Jason suggested we could use the same approach when you create a target in LLDB. I used Slack for benchmarking, which loads 902 images. Benchmark 1: ./bin/lldb /Applications/Slack.app/Contents/MacOS/Slack Time (mean ± σ): 1.225 s ± 0.003 s [User: 3.977 s, System: 1.521 s] Range (min … max): 1.220 s … 1.229 s 10 runs Benchmark 2: ./bin/lldb /Applications/Slack.app/Contents/MacOS/Slack Time (mean ± σ): 3.253 s ± 0.037 s [User: 3.013 s, System: 0.248 s] Range (min … max): 3.211 s … 3.310 s 10 runs We see about a 2x speedup, which matches what Jason saw for the attach scenario. I also ran this under TSan to confirm this doesn't introduce any races or deadlocks.
1 parent d1b311d commit 9a269fa

File tree

1 file changed

+28
-5
lines changed

1 file changed

+28
-5
lines changed

lldb/source/Target/Target.cpp

+28-5
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868

6969
#include "llvm/ADT/ScopeExit.h"
7070
#include "llvm/ADT/SetVector.h"
71+
#include "llvm/Support/ThreadPool.h"
7172

7273
#include <memory>
7374
#include <mutex>
@@ -1575,7 +1576,6 @@ void Target::SetExecutableModule(ModuleSP &executable_sp,
15751576
m_arch.GetSpec().GetTriple().getTriple());
15761577
}
15771578

1578-
FileSpecList dependent_files;
15791579
ObjectFile *executable_objfile = executable_sp->GetObjectFile();
15801580
bool load_dependents = true;
15811581
switch (load_dependent_files) {
@@ -1591,10 +1591,14 @@ void Target::SetExecutableModule(ModuleSP &executable_sp,
15911591
}
15921592

15931593
if (executable_objfile && load_dependents) {
1594+
// FileSpecList is not thread safe and needs to be synchronized.
1595+
FileSpecList dependent_files;
1596+
std::mutex dependent_files_mutex;
1597+
1598+
// ModuleList is thread safe.
15941599
ModuleList added_modules;
1595-
executable_objfile->GetDependentModules(dependent_files);
1596-
for (uint32_t i = 0; i < dependent_files.GetSize(); i++) {
1597-
FileSpec dependent_file_spec(dependent_files.GetFileSpecAtIndex(i));
1600+
1601+
auto GetDependentModules = [&](FileSpec dependent_file_spec) {
15981602
FileSpec platform_dependent_file_spec;
15991603
if (m_platform_sp)
16001604
m_platform_sp->GetFileWithUUID(dependent_file_spec, nullptr,
@@ -1608,9 +1612,28 @@ void Target::SetExecutableModule(ModuleSP &executable_sp,
16081612
if (image_module_sp) {
16091613
added_modules.AppendIfNeeded(image_module_sp, false);
16101614
ObjectFile *objfile = image_module_sp->GetObjectFile();
1611-
if (objfile)
1615+
if (objfile) {
1616+
std::lock_guard<std::mutex> guard(dependent_files_mutex);
16121617
objfile->GetDependentModules(dependent_files);
1618+
}
1619+
}
1620+
};
1621+
1622+
executable_objfile->GetDependentModules(dependent_files);
1623+
1624+
llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());
1625+
for (uint32_t i = 0; i < dependent_files.GetSize(); i++) {
1626+
// Process all currently known dependencies in parallel in the innermost
1627+
// loop. This may create newly discovered dependencies to be appended to
1628+
// dependent_files. We'll deal with these files during the next
1629+
// iteration of the outermost loop.
1630+
{
1631+
std::lock_guard<std::mutex> guard(dependent_files_mutex);
1632+
for (; i < dependent_files.GetSize(); i++)
1633+
task_group.async(GetDependentModules,
1634+
dependent_files.GetFileSpecAtIndex(i));
16131635
}
1636+
task_group.wait();
16141637
}
16151638
ModulesDidLoad(added_modules);
16161639
}

0 commit comments

Comments
 (0)