From 5a27b99825a5ba3a7a2eec3d35aea381a3ba9a31 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Sat, 5 Mar 2022 15:45:52 -0800 Subject: [PATCH] [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 --- lldb/include/lldb/Core/Debugger.h | 8 ++++ lldb/source/Core/CoreProperties.td | 4 ++ lldb/source/Core/Debugger.cpp | 69 +++++++++++++++++++++++++++++++++ lldb/source/Symbol/LocateSymbolFile.cpp | 5 +++ 4 files changed, 86 insertions(+) diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h index d801e2d..ec66459 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 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 m_current_event_id; + llvm::StringMap> m_log_streams; std::shared_ptr m_log_callback_stream_sp; ConstString m_instance_name; diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td index 73539db..04e2f4e 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 eb0f6b5..4df7c98 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 4a7fbaa..589908e 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(""))); + FileSpecList debug_file_search_paths = default_search_paths; // Add module directory. -- 2.7.4