diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h --- a/lldb/include/lldb/Core/Debugger.h +++ b/lldb/include/lldb/Core/Debugger.h @@ -307,6 +307,10 @@ bool SetShowProgress(bool show_progress); + uint64_t GetRateLimitProgress() const; + + bool SetRateLimitProgress(uint64_t rate_limit); + llvm::StringRef GetShowProgressAnsiPrefix() const; llvm::StringRef GetShowProgressAnsiSuffix() const; @@ -668,6 +672,9 @@ eBroadcastBitEventThreadIsListening = (1 << 0), }; + // Used to rate-limit progress reports; + double m_next_report_time = 0.0; + private: // Use Debugger::CreateInstance() to get a shared pointer to a new debugger // object diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td --- a/lldb/source/Core/CoreProperties.td +++ b/lldb/source/Core/CoreProperties.td @@ -147,6 +147,10 @@ Global, DefaultTrue, Desc<"Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.">; + def RateLimitProgress: Property<"rate-limit-progress", "UInt64">, + Global, + DefaultUnsignedValue<1>, + Desc<"Seconds to wait between progress reports.">; def ShowProgressAnsiPrefix: Property<"show-progress-ansi-prefix", "String">, Global, DefaultStringValue<"${ansi.faint}">, diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -66,6 +66,7 @@ #include "llvm/Support/Process.h" #include "llvm/Support/ThreadPool.h" #include "llvm/Support/Threading.h" +#include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include @@ -403,6 +404,17 @@ return SetPropertyAtIndex(idx, show_progress); } +uint64_t Debugger::GetRateLimitProgress() const { + const uint32_t idx = ePropertyRateLimitProgress; + return GetPropertyAtIndexAs( + idx, g_debugger_properties[idx].default_uint_value != 0); +} + +bool Debugger::SetRateLimitProgress(uint64_t rate_limit) { + const uint32_t idx = ePropertyShowProgress; + return SetPropertyAtIndex(idx, rate_limit); +} + llvm::StringRef Debugger::GetShowProgressAnsiPrefix() const { const uint32_t idx = ePropertyShowProgressAnsiPrefix; return GetPropertyAtIndexAs( @@ -1934,6 +1946,16 @@ return {}; } +// Rate-limit calculations should be fast. TimePoints collect memory and +// instruction counts, which is slow. +static double getCurrentTime() { + using Seconds = std::chrono::duration>; + llvm::sys::TimePoint<> now; + std::chrono::nanoseconds user, sys; + llvm::sys::Process::GetTimeUsage(now, user, sys); + return Seconds(now.time_since_epoch()).count(); +} + void Debugger::HandleProgressEvent(const lldb::EventSP &event_sp) { auto *data = ProgressEventData::GetEventDataFromEvent(event_sp.get()); if (!data) @@ -1976,6 +1998,13 @@ StreamSP output = GetAsyncOutputStream(); + // Rate limit progress messages, but always show the last event. + double current_time = getCurrentTime(); + if (current_time < m_next_report_time && + data->GetCompleted() != data->GetTotal()) + return; + m_next_report_time = current_time + GetRateLimitProgress(); + // Print over previous line, if any. output->Printf("\r"); @@ -1983,6 +2012,9 @@ // Clear the current line. output->Printf("\x1B[2K"); output->Flush(); + // This set of progress reports is complete. Reset to show the first + // progress report of the next set. + m_next_report_time = 0.0; return; }