Performance Monitoring Solution for Swift Debugging Using LLDB Plugin in the DanceCC Toolchain
This article describes a comprehensive LLDB‑plugin based monitoring framework that intercepts Xcode’s Script Bridge API to measure and report precise debugging latency for Swift projects, outlines the implementation details, timing scenarios, data reporting, and includes a recruitment notice for the ByteDance client infrastructure team.
In the article "ByteDance DanceCC Toolchain Series: Swift Debugging Performance Optimization" the authors introduce a custom toolchain that improves LLDB debugging performance for large Swift projects.
Background
To accurately measure the efficiency gain after applying the optimization, a monitoring solution that can capture the execution time of both the Xcode official toolchain and the DanceCC toolchain was required.
The built‑in LLDB timer command log timers dump only reports cumulative time for functions wrapped with LLDB_SCOPED_TIMER() and does not provide fine‑grained, automatic measurements.
Solution Overview
The proposed solution leverages an LLDB plugin, Fishhook, and the LLDB Script Bridge API to intercept calls from Xcode to LLDB, allowing precise timing of each debugging operation.
LLDB Plugin
Each plugin is a dynamic library that implements specific C/C++ entry points. The new plugin interface requires a function bool PluginInitialize(SBDebugger debugger) and is loaded with plugin load /path/to/plugin.dylib . The legacy interface uses extern "C" bool LLDBPluginInitialize(void) and extern "C" void LLDBPluginTerminate(void) . The compiled libraries are placed in /path/to/LLDB.framework/Resources/Plugins or ~/Library/Application Support/LLDB/PlugIns to be auto‑loaded.
Injecting the Dynamic Library
When Xcode starts a debug session it launches lldb‑rpc‑server , which loads the default LLDB.framework. By adding command script import ~/.dancecc/dancecc_lldb.py to lldbinit , the script loads the monitoring library plugin load ~/.dancecc/libLLDBStatistics.dylib . Fishhook then hooks the desired Script Bridge API functions.
Hooking SB API
The hook macros are defined as follows:
/// Hook a SB API using the stub method defined with the macros above
#define LLDB_HOOK_METHOD(MANGLED, CLASS, METHOD) \
Logger::Log("Hook "#CLASS"::"#METHOD" started!"); \
ptr_##MANGLED.pvoid = dlsym(RTLD_DEFAULT, #MANGLED); \
if (!ptr_##MANGLED.pvoid) { Logger::Log(dlerror()); return; } \
if (rebind_symbols((struct rebinding[1]){{#MANGLED, (void *)hook_##MANGLED, (void **)&ptr_##MANGLED.pvoid}}, 1) < 0) { Logger::Log(dlerror()); return; } \
Logger::Log("Hook "#CLASS"::"#METHOD" succeed!");Calling the original implementation is done with:
/// Call the original implementation for member function
#define LLDB_CALL_HOOKED_METHOD(MANGLED, SELF, ...) (SELF->*(ptr_##MANGLED.pmember))(__VA_ARGS__)A complete hook example:
// Assume we want to hook: char * ClassA::MethodB(int foo, double bar)
LLDB_GEN_HOOKED_METHOD(mangled, char *, ClassA, MethodB, int foo, double bar) {
return LLDB_CALL_HOOKED_METHOD(mangled, self, 1, 2.0);
}
LLDB_HOOK_METHOD(mangled, ClassA, MethodB);Timing Scenarios
Display Frame Variables
The debugger calls SBFrame::GetVariables to obtain an SBValueList , then queries each variable and finally waits on SBListener::GetNextEvent . The solution records a timestamp before SBFrame::GetVariables and after SBListener::GetNextEvent to compute the latency.
Display Child Variables
When expanding a variable, LLDB invokes SBValue::GetNumChildren followed by SBValue::GetChildAtIndex and again waits on SBListener::GetNextEvent . The same timestamp technique is applied.
Expression Command (expr/po)
Commands entered in the debug console bypass SB API, so the solution registers a callback via SBCommandInterpreter::SetCommandOverrideCallback . The callback records the start time, forwards the command to SBDebugger::HandleCommand , and uses a static bool isTrapped flag to avoid recursive interception.
Attach Process
During a real‑device attach, LLDB calls SBTarget::Attach . The wrapper records timestamps before and after the call.
Launch Process
For simulator launches, LLDB calls SBTarget::Launch . The same timing approach is used.
Reporting
The framework reports non‑sensitive metadata such as process name, bundle ID, source file, line, function, module, toolchain type (Xcode vs. DanceCC), and Swift version. Internal builds also include an app repository identifier via environment variables.
Collected data shows that DanceCC reduces variable‑display latency by nearly an order of magnitude compared with the default Xcode toolchain.
Extreme‑Latency Stack Collection
If a frame‑display or expr‑command exceeds 10 seconds, the current LLDB call stack is captured using log timers dump . The stack entries are generated by the LLDB_SCOPED_TIMER() macro, which records the function name via __PRETTY_FUNCTION__ . The top‑10 most expensive frames are sampled and uploaded for further analysis.
Conclusion
Performance optimization of both applications and toolchains requires solid data metrics. The presented monitoring solution provides precise, automated telemetry that validates the impact of debugger optimizations and guides future improvements.
References
https://mp.weixin.qq.com/s/MTt3Igy7fu7hU0ooE8vZog
https://reviews.llvm.org/rG4272cc7d4c1e1a8cb39595cfe691e2d6985f7161
https://lldb.llvm.org/design/sbapi.html
https://github.com/facebook/fishhook
https://discourse.llvm.org/t/rfc-lldb-telemetry-metrics/64588
About ByteDance Terminal Technology Team
The ByteDance Client Infrastructure team builds global front‑end infrastructure for products such as Douyin, Toutiao, Feishu, etc., covering mobile, web, and desktop platforms.
Join Us
We are hiring compiler/toolchain engineers to design and implement high‑efficiency compiler, linker, and debugger optimizations for Swift and other languages. Required skills include C++/Objective‑C/Swift, knowledge of language implementation, build systems (CMake/Bazel/Gradle/XCBuild), and experience with LLVM/GCC.
Location: Shenzhen, Beijing. Apply at https://job.toutiao.com/s/FBS9cLk
ByteDance Terminal Technology
Official account of ByteDance Terminal Technology, sharing technical insights and team updates.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.