Skip to content

Commit 5034305

Browse files
DmT021DanielCChen
authored andcommitted
DynamicLoaderDarwin load images in parallel with preload (llvm#110646)
This change enables `DynamicLoaderDarwin` to load modules in parallel using the thread pool. This new behavior is controlled by a new setting `plugin.dynamic-loader.darwin.experimental.enable-parallel-image-load`, which is enabled by default. When disabled, DynamicLoaderDarwin will load modules sequentially as before.
1 parent 35dd8b7 commit 5034305

9 files changed

+215
-43
lines changed

lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
1+
lldb_tablegen(DynamicLoaderDarwinProperties.inc -gen-lldb-property-defs
2+
SOURCE DynamicLoaderDarwinProperties.td
3+
TARGET LLDBPluginDynamicLoaderDarwinPropertiesGen)
4+
5+
lldb_tablegen(DynamicLoaderDarwinPropertiesEnum.inc -gen-lldb-property-enum-defs
6+
SOURCE DynamicLoaderDarwinProperties.td
7+
TARGET LLDBPluginDynamicLoaderDarwinPropertiesEnumGen)
8+
19
add_lldb_library(lldbPluginDynamicLoaderMacOSXDYLD PLUGIN
210
DynamicLoaderMacOSXDYLD.cpp
311
DynamicLoaderMacOS.cpp
412
DynamicLoaderDarwin.cpp
13+
DynamicLoaderDarwinProperties.cpp
514

615
LINK_LIBS
716
lldbBreakpoint
@@ -16,3 +25,7 @@ add_lldb_library(lldbPluginDynamicLoaderMacOSXDYLD PLUGIN
1625
Support
1726
TargetParser
1827
)
28+
29+
add_dependencies(lldbPluginDynamicLoaderMacOSXDYLD
30+
LLDBPluginDynamicLoaderDarwinPropertiesGen
31+
LLDBPluginDynamicLoaderDarwinPropertiesEnumGen)

lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp

Lines changed: 72 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "DynamicLoaderDarwin.h"
1010

11+
#include "DynamicLoaderDarwinProperties.h"
1112
#include "lldb/Breakpoint/StoppointCallbackContext.h"
1213
#include "lldb/Core/Debugger.h"
1314
#include "lldb/Core/Module.h"
@@ -31,6 +32,7 @@
3132
#include "lldb/Utility/LLDBLog.h"
3233
#include "lldb/Utility/Log.h"
3334
#include "lldb/Utility/State.h"
35+
#include "llvm/Support/ThreadPool.h"
3436

3537
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
3638
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
@@ -77,6 +79,17 @@ void DynamicLoaderDarwin::DidLaunch() {
7779
SetNotificationBreakpoint();
7880
}
7981

82+
void DynamicLoaderDarwin::CreateSettings(lldb_private::Debugger &debugger) {
83+
if (!PluginManager::GetSettingForDynamicLoaderPlugin(
84+
debugger, DynamicLoaderDarwinProperties::GetSettingName())) {
85+
const bool is_global_setting = true;
86+
PluginManager::CreateSettingForDynamicLoaderPlugin(
87+
debugger,
88+
DynamicLoaderDarwinProperties::GetGlobal().GetValueProperties(),
89+
"Properties for the DynamicLoaderDarwin plug-in.", is_global_setting);
90+
}
91+
}
92+
8093
// Clear out the state of this class.
8194
void DynamicLoaderDarwin::Clear(bool clear_process) {
8295
std::lock_guard<std::recursive_mutex> guard(m_mutex);
@@ -88,7 +101,7 @@ void DynamicLoaderDarwin::Clear(bool clear_process) {
88101
}
89102

90103
ModuleSP DynamicLoaderDarwin::FindTargetModuleForImageInfo(
91-
ImageInfo &image_info, bool can_create, bool *did_create_ptr) {
104+
const ImageInfo &image_info, bool can_create, bool *did_create_ptr) {
92105
if (did_create_ptr)
93106
*did_create_ptr = false;
94107

@@ -517,44 +530,43 @@ bool DynamicLoaderDarwin::JSONImageInformationIntoImageInfo(
517530
return true;
518531
}
519532

520-
void DynamicLoaderDarwin::UpdateSpecialBinariesFromNewImageInfos(
521-
ImageInfo::collection &image_infos) {
533+
void DynamicLoaderDarwin::UpdateSpecialBinariesFromPreloadedModules(
534+
std::vector<std::pair<ImageInfo, ModuleSP>> &images) {
522535
uint32_t exe_idx = UINT32_MAX;
523536
uint32_t dyld_idx = UINT32_MAX;
524537
Target &target = m_process->GetTarget();
525538
Log *log = GetLog(LLDBLog::DynamicLoader);
526539
ConstString g_dyld_sim_filename("dyld_sim");
527540

528541
ArchSpec target_arch = target.GetArchitecture();
529-
const size_t image_infos_size = image_infos.size();
530-
for (size_t i = 0; i < image_infos_size; i++) {
531-
if (image_infos[i].header.filetype == llvm::MachO::MH_DYLINKER) {
542+
const size_t images_size = images.size();
543+
for (size_t i = 0; i < images_size; i++) {
544+
const auto &image_info = images[i].first;
545+
if (image_info.header.filetype == llvm::MachO::MH_DYLINKER) {
532546
// In a "simulator" process we will have two dyld modules --
533547
// a "dyld" that we want to keep track of, and a "dyld_sim" which
534548
// we don't need to keep track of here. dyld_sim will have a non-macosx
535549
// OS.
536550
if (target_arch.GetTriple().getEnvironment() == llvm::Triple::Simulator &&
537-
image_infos[i].os_type != llvm::Triple::OSType::MacOSX) {
551+
image_info.os_type != llvm::Triple::OSType::MacOSX) {
538552
continue;
539553
}
540554

541555
dyld_idx = i;
542556
}
543-
if (image_infos[i].header.filetype == llvm::MachO::MH_EXECUTE) {
557+
if (image_info.header.filetype == llvm::MachO::MH_EXECUTE) {
544558
exe_idx = i;
545559
}
546560
}
547561

548562
// Set the target executable if we haven't found one so far.
549563
if (exe_idx != UINT32_MAX && !target.GetExecutableModule()) {
550-
const bool can_create = true;
551-
ModuleSP exe_module_sp(FindTargetModuleForImageInfo(image_infos[exe_idx],
552-
can_create, nullptr));
564+
ModuleSP exe_module_sp = images[exe_idx].second;
553565
if (exe_module_sp) {
554566
LLDB_LOGF(log, "Found executable module: %s",
555567
exe_module_sp->GetFileSpec().GetPath().c_str());
556568
target.GetImages().AppendIfNeeded(exe_module_sp);
557-
UpdateImageLoadAddress(exe_module_sp.get(), image_infos[exe_idx]);
569+
UpdateImageLoadAddress(exe_module_sp.get(), images[exe_idx].first);
558570
if (exe_module_sp.get() != target.GetExecutableModulePointer())
559571
target.SetExecutableModule(exe_module_sp, eLoadDependentsNo);
560572

@@ -581,14 +593,12 @@ void DynamicLoaderDarwin::UpdateSpecialBinariesFromNewImageInfos(
581593
}
582594

583595
if (dyld_idx != UINT32_MAX) {
584-
const bool can_create = true;
585-
ModuleSP dyld_sp = FindTargetModuleForImageInfo(image_infos[dyld_idx],
586-
can_create, nullptr);
596+
ModuleSP dyld_sp = images[dyld_idx].second;
587597
if (dyld_sp.get()) {
588598
LLDB_LOGF(log, "Found dyld module: %s",
589599
dyld_sp->GetFileSpec().GetPath().c_str());
590600
target.GetImages().AppendIfNeeded(dyld_sp);
591-
UpdateImageLoadAddress(dyld_sp.get(), image_infos[dyld_idx]);
601+
UpdateImageLoadAddress(dyld_sp.get(), images[dyld_idx].first);
592602
SetDYLDModule(dyld_sp);
593603
}
594604
}
@@ -642,26 +652,58 @@ ModuleSP DynamicLoaderDarwin::GetDYLDModule() {
642652

643653
void DynamicLoaderDarwin::ClearDYLDModule() { m_dyld_module_wp.reset(); }
644654

655+
std::vector<std::pair<DynamicLoaderDarwin::ImageInfo, ModuleSP>>
656+
DynamicLoaderDarwin::PreloadModulesFromImageInfos(
657+
const ImageInfo::collection &image_infos) {
658+
const auto size = image_infos.size();
659+
std::vector<std::pair<DynamicLoaderDarwin::ImageInfo, ModuleSP>> images(size);
660+
auto LoadImage = [&](size_t i, ImageInfo::collection::const_iterator it) {
661+
const auto &image_info = *it;
662+
images[i] = std::make_pair(
663+
image_info, FindTargetModuleForImageInfo(image_info, true, nullptr));
664+
};
665+
auto it = image_infos.begin();
666+
bool is_parallel_load =
667+
DynamicLoaderDarwinProperties::GetGlobal().GetEnableParallelImageLoad();
668+
if (is_parallel_load) {
669+
llvm::ThreadPoolTaskGroup taskGroup(Debugger::GetThreadPool());
670+
for (size_t i = 0; i < size; ++i, ++it) {
671+
taskGroup.async(LoadImage, i, it);
672+
}
673+
taskGroup.wait();
674+
} else {
675+
for (size_t i = 0; i < size; ++i, ++it) {
676+
LoadImage(i, it);
677+
}
678+
}
679+
return images;
680+
}
681+
645682
bool DynamicLoaderDarwin::AddModulesUsingImageInfos(
646683
ImageInfo::collection &image_infos) {
647684
std::lock_guard<std::recursive_mutex> guard(m_mutex);
685+
auto images = PreloadModulesFromImageInfos(image_infos);
686+
return AddModulesUsingPreloadedModules(images);
687+
}
688+
689+
bool DynamicLoaderDarwin::AddModulesUsingPreloadedModules(
690+
std::vector<std::pair<ImageInfo, ModuleSP>> &images) {
691+
std::lock_guard<std::recursive_mutex> guard(m_mutex);
648692
// Now add these images to the main list.
649693
ModuleList loaded_module_list;
650694
Log *log = GetLog(LLDBLog::DynamicLoader);
651695
Target &target = m_process->GetTarget();
652696
ModuleList &target_images = target.GetImages();
653697

654-
for (uint32_t idx = 0; idx < image_infos.size(); ++idx) {
698+
for (uint32_t idx = 0; idx < images.size(); ++idx) {
699+
auto &image_info = images[idx].first;
700+
const auto &image_module_sp = images[idx].second;
655701
if (log) {
656702
LLDB_LOGF(log, "Adding new image at address=0x%16.16" PRIx64 ".",
657-
image_infos[idx].address);
658-
image_infos[idx].PutToLog(log);
703+
image_info.address);
704+
image_info.PutToLog(log);
659705
}
660-
661-
m_dyld_image_infos.push_back(image_infos[idx]);
662-
663-
ModuleSP image_module_sp(
664-
FindTargetModuleForImageInfo(image_infos[idx], true, nullptr));
706+
m_dyld_image_infos.push_back(image_info);
665707

666708
if (image_module_sp) {
667709
ObjectFile *objfile = image_module_sp->GetObjectFile();
@@ -673,7 +715,7 @@ bool DynamicLoaderDarwin::AddModulesUsingImageInfos(
673715
sections->FindSectionByName(commpage_dbstr).get();
674716
if (commpage_section) {
675717
ModuleSpec module_spec(objfile->GetFileSpec(),
676-
image_infos[idx].GetArchitecture());
718+
image_info.GetArchitecture());
677719
module_spec.GetObjectName() = commpage_dbstr;
678720
ModuleSP commpage_image_module_sp(
679721
target_images.FindFirstModule(module_spec));
@@ -686,17 +728,17 @@ bool DynamicLoaderDarwin::AddModulesUsingImageInfos(
686728
if (!commpage_image_module_sp ||
687729
commpage_image_module_sp->GetObjectFile() == nullptr) {
688730
commpage_image_module_sp = m_process->ReadModuleFromMemory(
689-
image_infos[idx].file_spec, image_infos[idx].address);
731+
image_info.file_spec, image_info.address);
690732
// Always load a memory image right away in the target in case
691733
// we end up trying to read the symbol table from memory... The
692734
// __LINKEDIT will need to be mapped so we can figure out where
693735
// the symbol table bits are...
694736
bool changed = false;
695737
UpdateImageLoadAddress(commpage_image_module_sp.get(),
696-
image_infos[idx]);
738+
image_info);
697739
target.GetImages().Append(commpage_image_module_sp);
698740
if (changed) {
699-
image_infos[idx].load_stop_id = m_process->GetStopID();
741+
image_info.load_stop_id = m_process->GetStopID();
700742
loaded_module_list.AppendIfNeeded(commpage_image_module_sp);
701743
}
702744
}
@@ -709,14 +751,14 @@ bool DynamicLoaderDarwin::AddModulesUsingImageInfos(
709751
// address. We need to check this so we don't mention that all loaded
710752
// shared libraries are newly loaded each time we hit out dyld breakpoint
711753
// since dyld will list all shared libraries each time.
712-
if (UpdateImageLoadAddress(image_module_sp.get(), image_infos[idx])) {
754+
if (UpdateImageLoadAddress(image_module_sp.get(), image_info)) {
713755
target_images.AppendIfNeeded(image_module_sp);
714756
loaded_module_list.AppendIfNeeded(image_module_sp);
715757
}
716758

717759
// To support macCatalyst and legacy iOS simulator,
718760
// update the module's platform with the DYLD info.
719-
ArchSpec dyld_spec = image_infos[idx].GetArchitecture();
761+
ArchSpec dyld_spec = image_info.GetArchitecture();
720762
auto &dyld_triple = dyld_spec.GetTriple();
721763
if ((dyld_triple.getEnvironment() == llvm::Triple::MacABI &&
722764
dyld_triple.getOS() == llvm::Triple::IOS) ||

lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ class DynamicLoaderDarwin : public lldb_private::DynamicLoader {
5858

5959
std::optional<lldb_private::Address> GetStartAddress() override;
6060

61+
static void CreateSettings(lldb_private::Debugger &debugger);
62+
6163
protected:
6264
void PrivateInitialize(lldb_private::Process *process);
6365

@@ -174,7 +176,7 @@ class DynamicLoaderDarwin : public lldb_private::DynamicLoader {
174176

175177
bool UnloadModuleSections(lldb_private::Module *module, ImageInfo &info);
176178

177-
lldb::ModuleSP FindTargetModuleForImageInfo(ImageInfo &image_info,
179+
lldb::ModuleSP FindTargetModuleForImageInfo(const ImageInfo &image_info,
178180
bool can_create,
179181
bool *did_create_ptr);
180182

@@ -201,11 +203,18 @@ class DynamicLoaderDarwin : public lldb_private::DynamicLoader {
201203
lldb_private::StructuredData::ObjectSP image_details,
202204
ImageInfo::collection &image_infos);
203205

204-
// If image_infos contains / may contain dyld or executable image, call this
205-
// method
206-
// to keep our internal record keeping of the special binaries up-to-date.
207-
void
208-
UpdateSpecialBinariesFromNewImageInfos(ImageInfo::collection &image_infos);
206+
// Finds/loads modules for a given `image_infos` and returns pairs
207+
// (ImageInfo, ModuleSP).
208+
// Prefer using this method rather than calling `FindTargetModuleForImageInfo`
209+
// directly as this method may load the modules in parallel.
210+
std::vector<std::pair<ImageInfo, lldb::ModuleSP>>
211+
PreloadModulesFromImageInfos(const ImageInfo::collection &image_infos);
212+
213+
// If `images` contains / may contain dyld or executable image, call this
214+
// method to keep our internal record keeping of the special binaries
215+
// up-to-date.
216+
void UpdateSpecialBinariesFromPreloadedModules(
217+
std::vector<std::pair<ImageInfo, lldb::ModuleSP>> &images);
209218

210219
// if image_info is a dyld binary, call this method
211220
bool UpdateDYLDImageInfoFromNewImageInfo(ImageInfo &image_info);
@@ -215,6 +224,8 @@ class DynamicLoaderDarwin : public lldb_private::DynamicLoader {
215224
void AddExecutableModuleIfInImageInfos(ImageInfo::collection &image_infos);
216225

217226
bool AddModulesUsingImageInfos(ImageInfo::collection &image_infos);
227+
bool AddModulesUsingPreloadedModules(
228+
std::vector<std::pair<ImageInfo, lldb::ModuleSP>> &images);
218229

219230
// Whether we should use the new dyld SPI to get shared library information,
220231
// or read
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===-- DynamicLoaderDarwinProperties.cpp ---------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "DynamicLoaderDarwinProperties.h"
10+
11+
using namespace lldb_private;
12+
13+
#define LLDB_PROPERTIES_dynamicloaderdarwin_experimental
14+
#include "DynamicLoaderDarwinProperties.inc"
15+
16+
enum {
17+
#define LLDB_PROPERTIES_dynamicloaderdarwin_experimental
18+
#include "DynamicLoaderDarwinPropertiesEnum.inc"
19+
};
20+
21+
llvm::StringRef DynamicLoaderDarwinProperties::GetSettingName() {
22+
static constexpr llvm::StringLiteral g_setting_name("darwin");
23+
return g_setting_name;
24+
}
25+
26+
DynamicLoaderDarwinProperties::ExperimentalProperties::ExperimentalProperties()
27+
: Properties(std::make_shared<OptionValueProperties>(
28+
GetExperimentalSettingsName())) {
29+
m_collection_sp->Initialize(g_dynamicloaderdarwin_experimental_properties);
30+
}
31+
32+
DynamicLoaderDarwinProperties::DynamicLoaderDarwinProperties()
33+
: Properties(std::make_shared<OptionValueProperties>(GetSettingName())),
34+
m_experimental_properties(std::make_unique<ExperimentalProperties>()) {
35+
m_collection_sp->AppendProperty(
36+
Properties::GetExperimentalSettingsName(),
37+
"Experimental settings - setting these won't produce errors if the "
38+
"setting is not present.",
39+
true, m_experimental_properties->GetValueProperties());
40+
}
41+
42+
bool DynamicLoaderDarwinProperties::GetEnableParallelImageLoad() const {
43+
return m_experimental_properties->GetPropertyAtIndexAs<bool>(
44+
ePropertyEnableParallelImageLoad,
45+
g_dynamicloaderdarwin_experimental_properties
46+
[ePropertyEnableParallelImageLoad]
47+
.default_uint_value != 0);
48+
}
49+
50+
DynamicLoaderDarwinProperties &DynamicLoaderDarwinProperties::GetGlobal() {
51+
static DynamicLoaderDarwinProperties g_settings;
52+
return g_settings;
53+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===-- DynamicLoaderDarwinProperties.h -------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERDARWINPROPERTIES_H
10+
#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERDARWINPROPERTIES_H
11+
12+
#include "lldb/Core/UserSettingsController.h"
13+
14+
namespace lldb_private {
15+
16+
class DynamicLoaderDarwinProperties : public Properties {
17+
public:
18+
class ExperimentalProperties : public Properties {
19+
public:
20+
ExperimentalProperties();
21+
};
22+
static llvm::StringRef GetSettingName();
23+
static DynamicLoaderDarwinProperties &GetGlobal();
24+
DynamicLoaderDarwinProperties();
25+
~DynamicLoaderDarwinProperties() override = default;
26+
bool GetEnableParallelImageLoad() const;
27+
28+
private:
29+
std::unique_ptr<ExperimentalProperties> m_experimental_properties;
30+
};
31+
32+
} // namespace lldb_private
33+
34+
#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERDARWINPROPERTIES_H

0 commit comments

Comments
 (0)