Skip to content

Commit

Permalink
[lldb] Create dependent modules in parallel (llvm#114507)
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
JDevlieghere committed Nov 4, 2024
1 parent 987402a commit af9459b
Showing 1 changed file with 49 additions and 6 deletions.
55 changes: 49 additions & 6 deletions lldb/source/Target/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@

#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/Support/ThreadPool.h"

#include <memory>
#include <mutex>
Expand Down Expand Up @@ -1611,7 +1612,6 @@ void Target::SetExecutableModule(ModuleSP &executable_sp,
m_arch.GetSpec().GetTriple().getTriple());
}

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

if (executable_objfile && load_dependents) {
// FileSpecList is not thread safe and needs to be synchronized.
FileSpecList dependent_files;
std::mutex dependent_files_mutex;

// ModuleList is thread safe.
ModuleList added_modules;
executable_objfile->GetDependentModules(dependent_files);
for (uint32_t i = 0; i < dependent_files.GetSize(); i++) {
FileSpec dependent_file_spec(dependent_files.GetFileSpecAtIndex(i));

auto GetDependentModules = [&](FileSpec dependent_file_spec) {
FileSpec platform_dependent_file_spec;
if (m_platform_sp)
m_platform_sp->GetFileWithUUID(dependent_file_spec, nullptr,
Expand All @@ -1644,9 +1648,48 @@ void Target::SetExecutableModule(ModuleSP &executable_sp,
if (image_module_sp) {
added_modules.AppendIfNeeded(image_module_sp, false);
ObjectFile *objfile = image_module_sp->GetObjectFile();
if (objfile)
objfile->GetDependentModules(dependent_files);
if (objfile) {
// Create a local copy of the dependent file list so we don't have
// to lock for the whole duration of GetDependentModules.
FileSpecList dependent_files_copy;
{
std::lock_guard<std::mutex> guard(dependent_files_mutex);
dependent_files_copy = dependent_files;
}

// Remember the size of the local copy so we can append only the
// modules that have been added by GetDependentModules.
const size_t previous_dependent_files =
dependent_files_copy.GetSize();

objfile->GetDependentModules(dependent_files_copy);

{
std::lock_guard<std::mutex> guard(dependent_files_mutex);
for (size_t i = previous_dependent_files;
i < dependent_files_copy.GetSize(); ++i)
dependent_files.AppendIfUnique(
dependent_files_copy.GetFileSpecAtIndex(i));
}
}
}
};

executable_objfile->GetDependentModules(dependent_files);

llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());
for (uint32_t i = 0; i < dependent_files.GetSize(); i++) {
// Process all currently known dependencies in parallel in the innermost
// loop. This may create newly discovered dependencies to be appended to
// dependent_files. We'll deal with these files during the next
// iteration of the outermost loop.
{
std::lock_guard<std::mutex> guard(dependent_files_mutex);
for (; i < dependent_files.GetSize(); i++)
task_group.async(GetDependentModules,
dependent_files.GetFileSpecAtIndex(i));
}
task_group.wait();
}
ModulesDidLoad(added_modules);
}
Expand Down

0 comments on commit af9459b

Please sign in to comment.