Skip to content

Commit b360dfd

Browse files
authored
[lldb] Create dependent modules in parallel (#114507)
Create dependent modules in parallel in Target::SetExecutableModule. This change was inspired by #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 fcd51de commit b360dfd

File tree

1 file changed

+49
-6
lines changed

1 file changed

+49
-6
lines changed

lldb/source/Target/Target.cpp

+49-6
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,48 @@ 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)
1612-
objfile->GetDependentModules(dependent_files);
1615+
if (objfile) {
1616+
// Create a local copy of the dependent file list so we don't have
1617+
// to lock for the whole duration of GetDependentModules.
1618+
FileSpecList dependent_files_copy;
1619+
{
1620+
std::lock_guard<std::mutex> guard(dependent_files_mutex);
1621+
dependent_files_copy = dependent_files;
1622+
}
1623+
1624+
// Remember the size of the local copy so we can append only the
1625+
// modules that have been added by GetDependentModules.
1626+
const size_t previous_dependent_files =
1627+
dependent_files_copy.GetSize();
1628+
1629+
objfile->GetDependentModules(dependent_files_copy);
1630+
1631+
{
1632+
std::lock_guard<std::mutex> guard(dependent_files_mutex);
1633+
for (size_t i = previous_dependent_files;
1634+
i < dependent_files_copy.GetSize(); ++i)
1635+
dependent_files.AppendIfUnique(
1636+
dependent_files_copy.GetFileSpecAtIndex(i));
1637+
}
1638+
}
1639+
}
1640+
};
1641+
1642+
executable_objfile->GetDependentModules(dependent_files);
1643+
1644+
llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());
1645+
for (uint32_t i = 0; i < dependent_files.GetSize(); i++) {
1646+
// Process all currently known dependencies in parallel in the innermost
1647+
// loop. This may create newly discovered dependencies to be appended to
1648+
// dependent_files. We'll deal with these files during the next
1649+
// iteration of the outermost loop.
1650+
{
1651+
std::lock_guard<std::mutex> guard(dependent_files_mutex);
1652+
for (; i < dependent_files.GetSize(); i++)
1653+
task_group.async(GetDependentModules,
1654+
dependent_files.GetFileSpecAtIndex(i));
16131655
}
1656+
task_group.wait();
16141657
}
16151658
ModulesDidLoad(added_modules);
16161659
}

0 commit comments

Comments
 (0)