diff options
author | Jonas Devlieghere <jonas@devlieghere.com> | 2022-03-06 02:45:52 +0300 |
---|---|---|
committer | Jonas Devlieghere <jonas@devlieghere.com> | 2022-03-09 05:24:26 +0300 |
commit | 5a27b99825a5ba3a7a2eec3d35aea381a3ba9a31 (patch) | |
tree | c6c47951412fd05f3a33b207a870ab508487fe75 /lldb | |
parent | bfab18d86b2784364227631f51735fe17ee82b40 (diff) |
[lldb] Show progress events in the command line driver
This patch adds support for showing progress events when using lldb on
the command line. It spawns a separate thread that listens for progress
events and prints them to the debugger's output stream.
It's nothing fancy (yet), for now it just prints the progress message.
If we know the total number of items being processed, we prefix the
message with something like [1/100], similar to ninja's output.
This patch doesn't use any fancy terminal manipulation: it uses a simple
carriage return (\r) to bring the cursor to the front of the line and
vt100 escape codes to clear the (rest) of the line.
Differential revision: https://reviews.llvm.org/D120972
Diffstat (limited to 'lldb')
-rw-r--r-- | lldb/include/lldb/Core/Debugger.h | 8 | ||||
-rw-r--r-- | lldb/source/Core/CoreProperties.td | 4 | ||||
-rw-r--r-- | lldb/source/Core/Debugger.cpp | 69 | ||||
-rw-r--r-- | lldb/source/Symbol/LocateSymbolFile.cpp | 5 |
4 files changed, 86 insertions, 0 deletions
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h index d801e2d874df..ec6645986310 100644 --- a/lldb/include/lldb/Core/Debugger.h +++ b/lldb/include/lldb/Core/Debugger.h @@ -329,6 +329,8 @@ public: bool SetUseColor(bool use_color); + bool GetShowProgress() const; + bool GetUseAutosuggestion() const; llvm::StringRef GetAutosuggestionAnsiPrefix() const; @@ -439,6 +441,8 @@ protected: uint64_t completed, uint64_t total, llvm::Optional<lldb::user_id_t> debugger_id); + void PrintProgress(const Debugger::ProgressEventData &data); + bool StartEventHandlerThread(); void StopEventHandlerThread(); @@ -466,6 +470,8 @@ protected: void HandleThreadEvent(const lldb::EventSP &event_sp); + void HandleProgressEvent(const lldb::EventSP &event_sp); + // Ensures two threads don't attempt to flush process output in parallel. std::mutex m_output_flush_mutex; void FlushProcessOutput(Process &process, bool flush_stdout, @@ -514,6 +520,8 @@ protected: IOHandlerStack m_io_handler_stack; std::recursive_mutex m_io_handler_synchronous_mutex; + llvm::Optional<uint64_t> m_current_event_id; + llvm::StringMap<std::weak_ptr<llvm::raw_ostream>> m_log_streams; std::shared_ptr<llvm::raw_ostream> m_log_callback_stream_sp; ConstString m_instance_name; diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td index 73539dbafae1..04e2f4e1060d 100644 --- a/lldb/source/Core/CoreProperties.td +++ b/lldb/source/Core/CoreProperties.td @@ -131,6 +131,10 @@ let Definition = "debugger" in { Global, DefaultTrue, Desc<"Whether to use Ansi color codes or not.">; + def ShowProgress: Property<"show-progress", "Boolean">, + Global, + DefaultTrue, + Desc<"Whether to show progress or not if the debugger's output is an interactive color-enabled terminal.">; def UseSourceCache: Property<"use-source-cache", "Boolean">, Global, DefaultTrue, diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index eb0f6b5371d6..4df7c9800d75 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -378,6 +378,12 @@ bool Debugger::SetUseColor(bool b) { return ret; } +bool Debugger::GetShowProgress() const { + const uint32_t idx = ePropertyShowProgress; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_debugger_properties[idx].default_uint_value != 0); +} + bool Debugger::GetUseAutosuggestion() const { const uint32_t idx = ePropertyShowAutosuggestion; return m_collection_sp->GetPropertyAtIndexAsBoolean( @@ -1615,6 +1621,11 @@ lldb::thread_result_t Debugger::DefaultEventHandler() { CommandInterpreter::eBroadcastBitAsynchronousOutputData | CommandInterpreter::eBroadcastBitAsynchronousErrorData); + if (!m_broadcaster.EventTypeHasListeners(Debugger::eBroadcastBitProgress)) { + listener_sp->StartListeningForEvents(&m_broadcaster, + Debugger::eBroadcastBitProgress); + } + // Let the thread that spawned us know that we have started up and that we // are now listening to all required events so no events get missed m_sync_broadcaster.BroadcastEvent(eBroadcastBitEventThreadIsListening); @@ -1664,6 +1675,9 @@ lldb::thread_result_t Debugger::DefaultEventHandler() { } } } + } else if (broadcaster == &m_broadcaster) { + if (event_type & Debugger::eBroadcastBitProgress) + HandleProgressEvent(event_sp); } } @@ -1729,6 +1743,61 @@ lldb::thread_result_t Debugger::IOHandlerThread() { return {}; } +void Debugger::HandleProgressEvent(const lldb::EventSP &event_sp) { + auto *data = + Debugger::ProgressEventData::GetEventDataFromEvent(event_sp.get()); + if (!data) + return; + + // Do some bookkeeping for the current event, regardless of whether we're + // going to show the progress. + const uint64_t id = data->GetID(); + if (m_current_event_id) { + if (id != *m_current_event_id) + return; + if (data->GetCompleted()) + m_current_event_id.reset(); + } else { + m_current_event_id = id; + } + + // Decide whether we actually are going to show the progress. This decision + // can change between iterations so check it inside the loop. + if (!GetShowProgress()) + return; + + // Determine whether the current output file is an interactive terminal with + // color support. We assume that if we support ANSI escape codes we support + // vt100 escape codes. + File &output = GetOutputFile(); + if (!output.GetIsInteractive() || !output.GetIsTerminalWithColors()) + return; + + if (data->GetCompleted()) { + // Clear the current line. + output.Printf("\33[2K\r"); + return; + } + + // Print over previous line, if any. + output.Printf("\r"); + + // Print the progress message. + std::string message = data->GetMessage(); + if (data->GetTotal() != UINT64_MAX) { + output.Printf("[%llu/%llu] %s...", data->GetCompleted(), data->GetTotal(), + message.c_str()); + } else { + output.Printf("%s...", message.c_str()); + } + + // Clear until the end of the line. + output.Printf("\x1B[K"); + + // Flush the output. + output.Flush(); +} + bool Debugger::HasIOHandlerThread() { return m_io_handler_thread.IsJoinable(); } bool Debugger::StartIOHandlerThread() { diff --git a/lldb/source/Symbol/LocateSymbolFile.cpp b/lldb/source/Symbol/LocateSymbolFile.cpp index 4a7fbaae401a..589908e4c0dc 100644 --- a/lldb/source/Symbol/LocateSymbolFile.cpp +++ b/lldb/source/Symbol/LocateSymbolFile.cpp @@ -10,6 +10,7 @@ #include "lldb/Core/ModuleList.h" #include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/Progress.h" #include "lldb/Host/FileSystem.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/ArchSpec.h" @@ -262,6 +263,10 @@ Symbols::LocateExecutableSymbolFile(const ModuleSpec &module_spec, FileSystem::Instance().Exists(symbol_file_spec)) return symbol_file_spec; + Progress progress(llvm::formatv( + "Locating external symbol file for {0}", + module_spec.GetFileSpec().GetFilename().AsCString("<Unknown>"))); + FileSpecList debug_file_search_paths = default_search_paths; // Add module directory. |