From 377e888cbe9f5ac3f4a6e88ee5601a3facc88e9f Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 13 Oct 2025 15:58:58 -0700 Subject: [PATCH] [LLDB] Add progress updates for reflection metadata loading When debugging locally, parsing reflection metadata is instant. But when debugging over a slow network connection the amount of memory read packets being sent back and forth can indtroduce significan delays. To meake is easier to diagnose why an operation is stalling and to provide users with feedback about what LDB is doing this patch introduces a progress update in GetSwiftRuntimTypeInfo(). LLDB only publishes at meast 1 progress event every 20ms, so this is (visually) and performance-wise a noop wehen debugging locally. --- .../Swift/LLDBMemoryReader.cpp | 32 +++++++++++++------ .../LanguageRuntime/Swift/LLDBMemoryReader.h | 8 +++++ ...ftLanguageRuntimeDynamicTypeResolution.cpp | 24 ++++++++++++++ .../TestSwiftProgressReporting.py | 1 + 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp index 6b3e8ec652a91..2ee3f25efc1ab 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp +++ b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp @@ -18,6 +18,7 @@ #include "swift/Demangling/Demangle.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" using namespace lldb; using namespace lldb_private; @@ -416,16 +417,27 @@ bool LLDBMemoryReader::readString(swift::remote::RemoteAddress address, Log *log = GetLog(LLDBLog::Types); auto format_string = [](const std::string &dest) { - StreamString stream; - for (auto c : dest) { - if (c >= 32 && c <= 127) { - stream << c; - } else { - stream << "\\0"; - stream.PutHex8(c); - } + std::string result; + llvm::raw_string_ostream s(result); + llvm::printEscapedString(dest, s); + return result; + }; + /// Very quickly (this is a high-firing event), copy a few + /// human-readable bytes usable as detail in the progress update. + auto short_string = [](const std::string &dest) { + std::string result; + result.reserve(24); + size_t end = std::min(dest.size(), 24); + for (size_t i = 0; i < end; ++i) { + signed char c = dest[i]; + result.append(1, c > 32 ? c : '.'); } - return std::string(stream.GetData()); + if (end < dest.size()) { + result[21] = '.'; + result[22] = '.'; + result[23] = '.'; + } + return result; }; LLDB_LOGV(log, "[MemoryReader] asked to read string data at address {0:x}", address.getRawAddress()); @@ -463,6 +475,8 @@ bool LLDBMemoryReader::readString(swift::remote::RemoteAddress address, !readMetadataFromFileCacheEnabled() || !addr.IsSectionOffset(); target.ReadCStringFromMemory(addr, dest, error, force_live_memory); if (error.Success()) { + if (m_progress_callback) + m_progress_callback(short_string(dest)); LLDB_LOGV(log, "[MemoryReader] memory read returned string: \"{0}\"", format_string(dest)); return true; diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h index a42f503ad07cc..6d37b7f18c820 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h +++ b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h @@ -105,6 +105,12 @@ class LLDBMemoryReader : public swift::remote::MemoryReader { /// Returns whether the filecache optimization is enabled or not. bool readMetadataFromFileCacheEnabled() const; + /// Set or clear the progress callback. + void SetProgressCallback( + std::function progress_callback = {}) { + m_progress_callback = progress_callback; + } + protected: bool readRemoteAddressImpl(swift::remote::RemoteAddress address, swift::remote::RemoteAddress &out, @@ -166,6 +172,8 @@ class LLDBMemoryReader : public swift::remote::MemoryReader { /// The set of modules where we should read memory from the symbol file's /// object file instead of the main object file. llvm::SmallSet m_modules_with_metadata_in_symbol_obj_file; + /// A callback to update a progress event. + std::function m_progress_callback; }; } // namespace lldb_private #endif diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp b/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp index d89b3821a5225..f3ad5a2008c61 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp +++ b/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntimeDynamicTypeResolution.cpp @@ -608,6 +608,22 @@ std::optional SwiftLanguageRuntime::GetMemberVariableOffset( namespace { +class ProgressRAII { + Progress m_progress; + LLDBMemoryReader &m_memory_reader; +public: + ProgressRAII(std::string title, Debugger *debugger, + LLDBMemoryReader &memory_reader) + : m_progress(title, {}, {}, debugger, + Progress::kDefaultHighFrequencyReportTime), + m_memory_reader(memory_reader) { + m_memory_reader.SetProgressCallback([&](StringRef message) { + m_progress.Increment(1, message.str()); + }); + } + ~ProgressRAII() { m_memory_reader.SetProgressCallback(); }; +}; + CompilerType GetTypeFromTypeRef(TypeSystemSwiftTypeRef &ts, const swift::reflection::TypeRef *type_ref, swift::Mangle::ManglingFlavor flavor) { @@ -3480,6 +3496,14 @@ SwiftLanguageRuntime::GetSwiftRuntimeTypeInfo( if (!reflection_ctx) return llvm::createStringError("no reflection context"); + // On remove connections downloading reflection metadata can be a bottleneck. + auto flavor = GetManglingFlavor(type.GetMangledTypeName()); + static std::string g_debuginfo = "Loading debug info"; + static std::string g_reflection = "Loading reflection metadata"; + ProgressRAII progress( + flavor == swift::Mangle::ManglingFlavor::Embedded ? g_debuginfo + : g_reflection, + &GetProcess().GetTarget().GetDebugger(), *GetMemoryReader()); LLDBTypeInfoProvider provider(*this, ts); return reflection_ctx->GetTypeInfo(*type_ref_or_err, &provider, ts.GetDescriptorFinder()); diff --git a/lldb/test/API/functionalities/progress_reporting/swift_progress_reporting/TestSwiftProgressReporting.py b/lldb/test/API/functionalities/progress_reporting/swift_progress_reporting/TestSwiftProgressReporting.py index 1cca761bf5a14..3ab9abcf135c0 100644 --- a/lldb/test/API/functionalities/progress_reporting/swift_progress_reporting/TestSwiftProgressReporting.py +++ b/lldb/test/API/functionalities/progress_reporting/swift_progress_reporting/TestSwiftProgressReporting.py @@ -41,6 +41,7 @@ def test_swift_progress_report(self): "Importing dependencies for main.swift", "Importing dependencies for main.swift: Foundation", "Importing Swift standard library", + "Loading reflection metadata", ] importing_swift_reports = []