Skip to content

Commit af9459b

Browse files
committed
[lldb] Create dependent modules in parallel (llvm#114507)
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. (cherry picked from commit a57296a)
1 parent 987402a commit af9459b

File tree

1 file changed

+49
-6
lines changed

1 file changed

+49
-6
lines changed

lldb/source/Target/Target.cpp

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969

7070
#include "llvm/ADT/ScopeExit.h"
7171
#include "llvm/ADT/SetVector.h"
72+
#include "llvm/Support/ThreadPool.h"
7273

7374
#include <memory>
7475
#include <mutex>
@@ -1611,7 +1612,6 @@ void Target::SetExecutableModule(ModuleSP &executable_sp,
16111612
m_arch.GetSpec().GetTriple().getTriple());
16121613
}
16131614

1614-
FileSpecList dependent_files;
16151615
ObjectFile *executable_objfile = executable_sp->GetObjectFile();
16161616
bool load_dependents = true;
16171617
switch (load_dependent_files) {
@@ -1627,10 +1627,14 @@ void Target::SetExecutableModule(ModuleSP &executable_sp,
16271627
}
16281628

16291629
if (executable_objfile && load_dependents) {
1630+
// FileSpecList is not thread safe and needs to be synchronized.
1631+
FileSpecList dependent_files;
1632+
std::mutex dependent_files_mutex;
1633+
1634+
// ModuleList is thread safe.
16301635
ModuleList added_modules;
1631-
executable_objfile->GetDependentModules(dependent_files);
1632-
for (uint32_t i = 0; i < dependent_files.GetSize(); i++) {
1633-
FileSpec dependent_file_spec(dependent_files.GetFileSpecAtIndex(i));
1636+
1637+
auto GetDependentModules = [&](FileSpec dependent_file_spec) {
16341638
FileSpec platform_dependent_file_spec;
16351639
if (m_platform_sp)
16361640
m_platform_sp->GetFileWithUUID(dependent_file_spec, nullptr,
@@ -1644,9 +1648,48 @@ void Target::SetExecutableModule(ModuleSP &executable_sp,
16441648
if (image_module_sp) {
16451649
added_modules.AppendIfNeeded(image_module_sp, false);
16461650
ObjectFile *objfile = image_module_sp->GetObjectFile();
1647-
if (objfile)
1648-
objfile->GetDependentModules(dependent_files);
1651+
if (objfile) {
1652+
// Create a local copy of the dependent file list so we don't have
1653+
// to lock for the whole duration of GetDependentModules.
1654+
FileSpecList dependent_files_copy;
1655+
{
1656+
std::lock_guard<std::mutex> guard(dependent_files_mutex);
1657+
dependent_files_copy = dependent_files;
1658+
}
1659+
1660+
// Remember the size of the local copy so we can append only the
1661+
// modules that have been added by GetDependentModules.
1662+
const size_t previous_dependent_files =
1663+
dependent_files_copy.GetSize();
1664+
1665+
objfile->GetDependentModules(dependent_files_copy);
1666+
1667+
{
1668+
std::lock_guard<std::mutex> guard(dependent_files_mutex);
1669+
for (size_t i = previous_dependent_files;
1670+
i < dependent_files_copy.GetSize(); ++i)
1671+
dependent_files.AppendIfUnique(
1672+
dependent_files_copy.GetFileSpecAtIndex(i));
1673+
}
1674+
}
1675+
}
1676+
};
1677+
1678+
executable_objfile->GetDependentModules(dependent_files);
1679+
1680+
llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());
1681+
for (uint32_t i = 0; i < dependent_files.GetSize(); i++) {
1682+
// Process all currently known dependencies in parallel in the innermost
1683+
// loop. This may create newly discovered dependencies to be appended to
1684+
// dependent_files. We'll deal with these files during the next
1685+
// iteration of the outermost loop.
1686+
{
1687+
std::lock_guard<std::mutex> guard(dependent_files_mutex);
1688+
for (; i < dependent_files.GetSize(); i++)
1689+
task_group.async(GetDependentModules,
1690+
dependent_files.GetFileSpecAtIndex(i));
16491691
}
1692+
task_group.wait();
16501693
}
16511694
ModulesDidLoad(added_modules);
16521695
}

0 commit comments

Comments
 (0)