Skip to content

Commit 9360e52

Browse files
author
George Hu
committed
Implement parallel module loading for ModuleList DYLD
Summary: In H1, parallel module loading was introduced to PosixDYLD. https://github.com/llvm/llvm-project/pull/130912/files#diff-a697476e39fd57edf84295d97876820763cd80570d0a64f7f0145c5e24442cbf However for coredump debugging, we are using this ModuleList DYLD internally. We want to implement similar approach for ModuleList DYLD, to speed up core file loading. Test Plan: Found a big hhvm core oelpwa5ueda300nh: lldb -c oelpwa5ueda300nh -O symrv Before this change: first run: P1879168794 -> 143s to load core second run: P1879180294 -> 21s to load core After this change: first run P1879227037 -> 54s to load core second run P1879228346 -> 16s to load core Rollback Plan: Reviewers: jalalonde, #lldb_team, gclayton, toyang Reviewed By: jalalonde Subscribers: #lldb_team Differential Revision: https://phabricator.intern.facebook.com/D77804090
1 parent c14b17f commit 9360e52

File tree

2 files changed

+72
-5
lines changed

2 files changed

+72
-5
lines changed

lldb/source/Plugins/DynamicLoader/ModuleList-DYLD/DynamicLoaderDumpWithModuleList.cpp

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@
99
// Main header include
1010
#include "DynamicLoaderDumpWithModuleList.h"
1111

12+
#include "lldb/Core/Debugger.h"
1213
#include "lldb/Core/Module.h"
1314
#include "lldb/Core/PluginManager.h"
1415
#include "lldb/Target/Process.h"
1516
#include "lldb/Utility/LLDBLog.h"
1617
#include "lldb/Utility/Log.h"
18+
#include "llvm/Support/ThreadPool.h"
1719

1820
#include "Plugins/ObjectFile/Placeholder/ObjectFilePlaceholder.h"
21+
#include <mutex>
1922
#include <regex>
2023

2124
using namespace lldb;
@@ -53,6 +56,26 @@ DynamicLoaderDumpWithModuleList::DynamicLoaderDumpWithModuleList(
5356

5457
DynamicLoaderDumpWithModuleList::~DynamicLoaderDumpWithModuleList() {}
5558

59+
void DynamicLoaderDumpWithModuleList::SetLoadedModule(const ModuleSP &module_sp,
60+
addr_t link_map_addr) {
61+
llvm::sys::ScopedWriter lock(m_loaded_modules_rw_mutex);
62+
m_loaded_modules[module_sp] = link_map_addr;
63+
}
64+
65+
void DynamicLoaderDumpWithModuleList::UnloadModule(const ModuleSP &module_sp) {
66+
llvm::sys::ScopedWriter lock(m_loaded_modules_rw_mutex);
67+
m_loaded_modules.erase(module_sp);
68+
}
69+
70+
std::optional<lldb::addr_t>
71+
DynamicLoaderDumpWithModuleList::GetLoadedModuleLinkAddr(const ModuleSP &module_sp) {
72+
llvm::sys::ScopedReader lock(m_loaded_modules_rw_mutex);
73+
auto it = m_loaded_modules.find(module_sp);
74+
if (it != m_loaded_modules.end())
75+
return it->second;
76+
return std::nullopt;
77+
}
78+
5679
std::optional<const LoadedModuleInfoList::LoadedModuleInfo>
5780
DynamicLoaderDumpWithModuleList::GetModuleInfo(lldb::addr_t module_base_addr) {
5881
if (m_module_addr_to_info_map.empty()) {
@@ -201,11 +224,23 @@ void DynamicLoaderDumpWithModuleList::DidAttach() {
201224
LoadVDSO();
202225

203226
ModuleList module_list;
227+
228+
// Collect module information first
229+
std::vector<ModuleInfo> module_info_list;
204230
LoadAllModules([&](const std::string &name, addr_t base_addr,
205231
addr_t module_size, addr_t link_map_addr) {
206232
// vdso module has already been loaded.
207233
if (base_addr == m_vdso_base)
208234
return;
235+
module_info_list.emplace_back(ModuleInfo{name, base_addr, module_size, link_map_addr});
236+
});
237+
238+
// Load modules in parallel or sequentially based on target setting
239+
auto load_module_fn = [this, &module_list, &log](const ModuleInfo &module_info) {
240+
const std::string &name = module_info.name;
241+
addr_t base_addr = module_info.base_addr;
242+
addr_t module_size = module_info.module_size;
243+
addr_t link_map_addr = module_info.link_map_addr;
209244

210245
FileSpec file(name, m_process->GetTarget().GetArchitecture().GetTriple());
211246
const bool base_addr_is_offset = false;
@@ -214,6 +249,10 @@ void DynamicLoaderDumpWithModuleList::DidAttach() {
214249
if (module_sp.get()) {
215250
LLDB_LOGF(log, "LoadAllCurrentModules loading module at 0x%lX: %s",
216251
base_addr, name.c_str());
252+
// Note: in a multi-threaded environment, these module lists may be
253+
// appended to out-of-order. This is fine, since there's no
254+
// expectation for `module_list` to be in any particular order, and
255+
// appending to the module list is thread-safe.
217256
module_list.Append(module_sp);
218257
} else {
219258
LLDB_LOGF(
@@ -229,8 +268,18 @@ void DynamicLoaderDumpWithModuleList::DidAttach() {
229268
base_addr_is_offset);
230269
m_process->GetTarget().GetImages().Append(module_sp, /*notify*/ true);
231270
}
232-
m_loaded_modules[module_sp] = link_map_addr;
233-
});
271+
SetLoadedModule(module_sp, link_map_addr);
272+
};
273+
274+
if (m_process->GetTarget().GetParallelModuleLoad()) {
275+
llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());
276+
for (const auto &module_info : module_info_list)
277+
task_group.async(load_module_fn, module_info);
278+
task_group.wait();
279+
} else {
280+
for (const auto &module_info : module_info_list)
281+
load_module_fn(module_info);
282+
}
234283

235284
m_process->GetTarget().ModulesDidLoad(module_list);
236285
}
@@ -273,15 +322,15 @@ lldb::addr_t DynamicLoaderDumpWithModuleList::GetThreadLocalData(
273322
const lldb::ModuleSP module_sp, const lldb::ThreadSP thread,
274323
lldb::addr_t tls_file_addr) {
275324
Log *log = GetLog(LLDBLog::DynamicLoader);
276-
auto it = m_loaded_modules.find(module_sp);
277-
if (it == m_loaded_modules.end()) {
325+
std::optional<addr_t> link_map_addr_opt = GetLoadedModuleLinkAddr(module_sp);
326+
if (!link_map_addr_opt.has_value()) {
278327
LLDB_LOGF(
279328
log, "GetThreadLocalData error: module(%s) not found in loaded modules",
280329
module_sp->GetObjectName().AsCString());
281330
return LLDB_INVALID_ADDRESS;
282331
}
283332

284-
addr_t link_map = it->second;
333+
addr_t link_map = link_map_addr_opt.value();
285334
if (link_map == LLDB_INVALID_ADDRESS || link_map == 0) {
286335
LLDB_LOGF(log,
287336
"GetThreadLocalData error: invalid link map address=0x%" PRIx64,

lldb/source/Plugins/DynamicLoader/ModuleList-DYLD/DynamicLoaderDumpWithModuleList.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "Plugins/Process/Utility/AuxVector.h"
1515
#include "lldb/Core/ModuleList.h"
1616
#include "lldb/Target/DynamicLoader.h"
17+
#include "llvm/Support/RWMutex.h"
1718

1819
/**
1920
* Dynamic loader for dump process with module list available.
@@ -70,6 +71,14 @@ class DynamicLoaderDumpWithModuleList : public lldb_private::DynamicLoader {
7071
const DynamicLoaderDumpWithModuleList &
7172
operator=(const DynamicLoaderDumpWithModuleList &) = delete;
7273

74+
// Structure to hold module information
75+
struct ModuleInfo {
76+
std::string name;
77+
lldb::addr_t base_addr;
78+
lldb::addr_t module_size;
79+
lldb::addr_t link_map_addr;
80+
};
81+
7382
typedef std::function<void(const std::string &, lldb::addr_t, lldb::addr_t,
7483
lldb::addr_t)>
7584
LoadModuleCallback;
@@ -109,8 +118,17 @@ class DynamicLoaderDumpWithModuleList : public lldb_private::DynamicLoader {
109118
// TODO: merge with DynamicLoaderPOSIXDYLD::m_loaded_modules
110119
// The same as DynamicLoaderPOSIXDYLD::m_loaded_modules to track all loaded
111120
// module's link map addresses. It is used by TLS to get DTV data structure.
121+
/// This may be accessed in a multi-threaded context. Use the accessor methods
122+
/// to access `m_loaded_modules` safely.
112123
std::map<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>>
113124
m_loaded_modules;
125+
mutable llvm::sys::RWMutex m_loaded_modules_rw_mutex;
126+
127+
void SetLoadedModule(const lldb::ModuleSP &module_sp,
128+
lldb::addr_t link_map_addr);
129+
void UnloadModule(const lldb::ModuleSP &module_sp);
130+
std::optional<lldb::addr_t>
131+
GetLoadedModuleLinkAddr(const lldb::ModuleSP &module_sp);
114132
};
115133

116134
#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MODULELIST_DYLD_DYNAMICLOADERDUMPWITHMODULELIST_H

0 commit comments

Comments
 (0)