Author: Walter Erquinigo Date: 2021-07-21T09:50:15-07:00 New Revision: 345ace026b6e5cdbc38d207291e4b399d72e62ee
URL: https://github.com/llvm/llvm-project/commit/345ace026b6e5cdbc38d207291e4b399d72e62ee DIFF: https://github.com/llvm/llvm-project/commit/345ace026b6e5cdbc38d207291e4b399d72e62ee.diff LOG: [trace] [intel pt] Create a "thread trace dump stats" command When the user types that command 'thread trace dump info' and there's a running Trace session in LLDB, a raw trace in bytes should be printed; the command 'thread trace dump info all' should print the info for all the threads. Original Author: hanbingwang Reviewed By: clayborg, wallace Differential Revision: https://reviews.llvm.org/D105717 Added: lldb/test/API/commands/trace/TestTraceDumpInfo.py Modified: lldb/include/lldb/Target/Trace.h lldb/source/Commands/CommandObjectThread.cpp lldb/source/Commands/Options.td lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp lldb/source/Plugins/Trace/intel-pt/DecodedThread.h lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h lldb/test/API/commands/trace/TestTraceLoad.py Removed: ################################################################################ diff --git a/lldb/include/lldb/Target/Trace.h b/lldb/include/lldb/Target/Trace.h index c82d17b029557..f5654988b2015 100644 --- a/lldb/include/lldb/Target/Trace.h +++ b/lldb/include/lldb/Target/Trace.h @@ -140,6 +140,20 @@ class Trace : public PluginInterface, /// trace. virtual lldb::TraceCursorUP GetCursor(Thread &thread) = 0; + /// Dump general info about a given thread's trace. Each Trace plug-in + /// decides which data to show. + /// + /// \param[in] thread + /// The thread that owns the trace in question. + /// + /// \param[in] s + /// The stream object where the info will be printed printed. + /// + /// \param[in] verbose + /// If \b true, print detailed info + /// If \b false, print compact info + virtual void DumpTraceInfo(Thread &thread, Stream &s, bool verbose) = 0; + /// Check if a thread is currently traced by this object. /// /// \param[in] thread diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index 2f8772953af40..3b58d71048739 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -2138,6 +2138,83 @@ class CommandObjectTraceDumpInstructions std::map<lldb::tid_t, std::unique_ptr<TraceInstructionDumper>> m_dumpers; }; +// CommandObjectTraceDumpInfo +#define LLDB_OPTIONS_thread_trace_dump_info +#include "CommandOptions.inc" + +class CommandObjectTraceDumpInfo : public CommandObjectIterateOverThreads { +public: + class CommandOptions : public Options { + public: + CommandOptions() : Options() { OptionParsingStarting(nullptr); } + + ~CommandOptions() override = default; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'v': { + m_verbose = true; + break; + } + default: + llvm_unreachable("Unimplemented option"); + } + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_verbose = false; + } + + llvm::ArrayRef<OptionDefinition> GetDefinitions() override { + return llvm::makeArrayRef(g_thread_trace_dump_info_options); + } + + // Instance variables to hold the values for command options. + bool m_verbose; + }; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + Target &target = m_exe_ctx.GetTargetRef(); + result.GetOutputStream().Printf( + "Trace technology: %s\n", + target.GetTrace()->GetPluginName().AsCString()); + return CommandObjectIterateOverThreads::DoExecute(command, result); + } + + CommandObjectTraceDumpInfo(CommandInterpreter &interpreter) + : CommandObjectIterateOverThreads( + interpreter, "thread trace dump info", + "Dump the traced information for one or more threads. If no " + "threads are specified, show the current thread. Use the " + "thread-index \"all\" to see all threads.", + nullptr, + eCommandRequiresProcess | eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | + eCommandProcessMustBeTraced), + m_options() {} + + ~CommandObjectTraceDumpInfo() override = default; + + Options *GetOptions() override { return &m_options; } + +protected: + bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { + const TraceSP &trace_sp = m_exe_ctx.GetTargetSP()->GetTrace(); + ThreadSP thread_sp = + m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); + trace_sp->DumpTraceInfo(*thread_sp, result.GetOutputStream(), + m_options.m_verbose); + return true; + } + + CommandOptions m_options; +}; + // CommandObjectMultiwordTraceDump class CommandObjectMultiwordTraceDump : public CommandObjectMultiword { public: @@ -2150,6 +2227,8 @@ class CommandObjectMultiwordTraceDump : public CommandObjectMultiword { LoadSubCommand( "instructions", CommandObjectSP(new CommandObjectTraceDumpInstructions(interpreter))); + LoadSubCommand( + "info", CommandObjectSP(new CommandObjectTraceDumpInfo(interpreter))); } ~CommandObjectMultiwordTraceDump() override = default; }; diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index d0bc80c74d55d..9c9b7c6e9b829 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -1070,6 +1070,11 @@ let Command = "thread trace dump instructions" in { Desc<"For each instruction, print the corresponding timestamp counter if available.">; } +let Command = "thread trace dump info" in { + def thread_trace_dump_info_verbose : Option<"verbose", "v">, Group<1>, + Desc<"show verbose thread trace dump info">; +} + let Command = "type summary add" in { def type_summary_add_category : Option<"category", "w">, Arg<"Name">, Desc<"Add this to the given category instead of the default one.">; diff --git a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp index 970a7970c0fb3..4822a786c68c1 100644 --- a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp +++ b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp @@ -61,6 +61,7 @@ Error IntelPTInstruction::ToError() const { return make_error<StringError>(m_error->message(), m_error->convertToErrorCode()); } +size_t DecodedThread::GetRawTraceSize() const { return m_raw_trace_size; } TraceInstructionControlFlowType IntelPTInstruction::GetControlFlowType(lldb::addr_t next_load_address) const { @@ -103,8 +104,10 @@ DecodedThread::DecodedThread(ThreadSP thread_sp, Error error) } DecodedThread::DecodedThread(ThreadSP thread_sp, - std::vector<IntelPTInstruction> &&instructions) - : m_thread_sp(thread_sp), m_instructions(std::move(instructions)) { + std::vector<IntelPTInstruction> &&instructions, + size_t raw_trace_size) + : m_thread_sp(thread_sp), m_instructions(std::move(instructions)), + m_raw_trace_size(raw_trace_size) { if (m_instructions.empty()) m_instructions.emplace_back( createStringError(inconvertibleErrorCode(), "empty trace")); diff --git a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h index 135d938dfc57b..592c402cd0e50 100644 --- a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h +++ b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h @@ -127,7 +127,8 @@ class IntelPTInstruction { class DecodedThread : public std::enable_shared_from_this<DecodedThread> { public: DecodedThread(lldb::ThreadSP thread_sp, - std::vector<IntelPTInstruction> &&instructions); + std::vector<IntelPTInstruction> &&instructions, + size_t raw_trace_size); /// Constructor with a single error signaling a complete failure of the /// decoding process. @@ -143,9 +144,16 @@ class DecodedThread : public std::enable_shared_from_this<DecodedThread> { /// Get a new cursor for the decoded thread. lldb::TraceCursorUP GetCursor(); + /// Get the size in bytes of the corresponding Intel PT raw trace + /// + /// \return + /// The size of the trace. + size_t GetRawTraceSize() const; + private: lldb::ThreadSP m_thread_sp; std::vector<IntelPTInstruction> m_instructions; + size_t m_raw_trace_size; }; using DecodedThreadSP = std::shared_ptr<DecodedThread>; diff --git a/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp index 8c331841b54e6..aeba0081e5076 100644 --- a/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp +++ b/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp @@ -211,7 +211,7 @@ DecodeInMemoryTrace(Process &process, TraceIntelPT &trace_intel_pt, static Expected<std::vector<IntelPTInstruction>> DecodeTraceFile(Process &process, TraceIntelPT &trace_intel_pt, - const FileSpec &trace_file) { + const FileSpec &trace_file, size_t &raw_trace_size) { ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error = MemoryBuffer::getFile(trace_file.GetPath()); if (std::error_code err = trace_or_error.getError()) @@ -223,15 +223,17 @@ DecodeTraceFile(Process &process, TraceIntelPT &trace_intel_pt, // following cast is safe. reinterpret_cast<uint8_t *>(const_cast<char *>(trace.getBufferStart())), trace.getBufferSize()); + raw_trace_size = trace_data.size(); return DecodeInMemoryTrace(process, trace_intel_pt, trace_data); } static Expected<std::vector<IntelPTInstruction>> -DecodeLiveThread(Thread &thread, TraceIntelPT &trace) { +DecodeLiveThread(Thread &thread, TraceIntelPT &trace, size_t &raw_trace_size) { Expected<std::vector<uint8_t>> buffer = trace.GetLiveThreadBuffer(thread.GetID()); if (!buffer) return buffer.takeError(); + raw_trace_size = buffer->size(); if (Expected<pt_cpu> cpu_info = trace.GetCPUInfo()) return DecodeInMemoryTrace(*thread.GetProcess(), trace, MutableArrayRef<uint8_t>(*buffer)); @@ -250,11 +252,13 @@ PostMortemThreadDecoder::PostMortemThreadDecoder( : m_trace_thread(trace_thread), m_trace(trace) {} DecodedThreadSP PostMortemThreadDecoder::DoDecode() { + size_t raw_trace_size = 0; if (Expected<std::vector<IntelPTInstruction>> instructions = DecodeTraceFile(*m_trace_thread->GetProcess(), m_trace, - m_trace_thread->GetTraceFile())) + m_trace_thread->GetTraceFile(), raw_trace_size)) return std::make_shared<DecodedThread>(m_trace_thread->shared_from_this(), - std::move(*instructions)); + std::move(*instructions), + raw_trace_size); else return std::make_shared<DecodedThread>(m_trace_thread->shared_from_this(), instructions.takeError()); @@ -264,10 +268,11 @@ LiveThreadDecoder::LiveThreadDecoder(Thread &thread, TraceIntelPT &trace) : m_thread_sp(thread.shared_from_this()), m_trace(trace) {} DecodedThreadSP LiveThreadDecoder::DoDecode() { + size_t raw_trace_size = 0; if (Expected<std::vector<IntelPTInstruction>> instructions = - DecodeLiveThread(*m_thread_sp, m_trace)) - return std::make_shared<DecodedThread>(m_thread_sp, - std::move(*instructions)); + DecodeLiveThread(*m_thread_sp, m_trace, raw_trace_size)) + return std::make_shared<DecodedThread>( + m_thread_sp, std::move(*instructions), raw_trace_size); else return std::make_shared<DecodedThread>(m_thread_sp, instructions.takeError()); diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp index efbc0e2ed7f47..7588db610fafa 100644 --- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp +++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp @@ -108,6 +108,24 @@ lldb::TraceCursorUP TraceIntelPT::GetCursor(Thread &thread) { return Decode(thread)->GetCursor(); } +void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose) { + Optional<size_t> raw_size = GetRawTraceSize(thread); + s.Printf("\nthread #%u: tid = %" PRIu64, thread.GetIndexID(), thread.GetID()); + if (!raw_size) { + s.Printf(", not traced\n"); + return; + } + s.Printf("\n Raw trace size: %zu bytes\n", *raw_size); + return; +} + +Optional<size_t> TraceIntelPT::GetRawTraceSize(Thread &thread) { + if (IsTraced(thread)) + return Decode(thread)->GetRawTraceSize(); + else + return None; +} + Expected<pt_cpu> TraceIntelPT::GetCPUInfoForLiveProcess() { Expected<std::vector<uint8_t>> cpu_info = GetLiveProcessBinaryData("cpuInfo"); if (!cpu_info) diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h index cd6fedb2e1616..e3b247112ae16 100644 --- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h +++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h @@ -67,6 +67,10 @@ class TraceIntelPT : public Trace { lldb::TraceCursorUP GetCursor(Thread &thread) override; + void DumpTraceInfo(Thread &thread, Stream &s, bool verbose) override; + + llvm::Optional<size_t> GetRawTraceSize(Thread &thread); + void DoRefreshLiveProcessState( llvm::Expected<TraceGetStateResponse> state) override; diff --git a/lldb/test/API/commands/trace/TestTraceDumpInfo.py b/lldb/test/API/commands/trace/TestTraceDumpInfo.py new file mode 100644 index 0000000000000..b06840865232b --- /dev/null +++ b/lldb/test/API/commands/trace/TestTraceDumpInfo.py @@ -0,0 +1,41 @@ +import lldb +from intelpt_testcase import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +from lldbsuite.test.decorators import * + +class TestTraceDumpInfo(TraceIntelPTTestCaseBase): + mydir = TestBase.compute_mydir(__file__) + + def testErrorMessages(self): + # We first check the output when there are no targets + self.expect("thread trace dump info", + substrs=["error: invalid target, create a target using the 'target create' command"], + error=True) + + # We now check the output when there's a non-running target + self.expect("target create " + + os.path.join(self.getSourceDir(), "intelpt-trace", "a.out")) + + self.expect("thread trace dump info", + substrs=["error: invalid process"], + error=True) + + # Now we check the output when there's a running target without a trace + self.expect("b main") + self.expect("run") + + self.expect("thread trace dump info", + substrs=["error: Process is not being traced"], + error=True) + + def testDumpRawTraceSize(self): + self.expect("trace load -v " + + os.path.join(self.getSourceDir(), "intelpt-trace", "trace.json"), + substrs=["intel-pt"]) + + self.expect("thread trace dump info", + substrs=['''Trace technology: intel-pt + +thread #1: tid = 3842849 + Raw trace size: 4096 bytes''']) diff --git a/lldb/test/API/commands/trace/TestTraceLoad.py b/lldb/test/API/commands/trace/TestTraceLoad.py index 0ea414f2b0594..896f0eade663f 100644 --- a/lldb/test/API/commands/trace/TestTraceLoad.py +++ b/lldb/test/API/commands/trace/TestTraceLoad.py @@ -33,7 +33,10 @@ def testLoadTrace(self): # check that the Process and Thread objects were created correctly self.expect("thread info", substrs=["tid = 3842849"]) self.expect("thread list", substrs=["Process 1234 stopped", "tid = 3842849"]) + self.expect("thread trace dump info", substrs=['''Trace technology: intel-pt +thread #1: tid = 3842849 + Raw trace size: 4096 bytes''']) def testLoadInvalidTraces(self): src_dir = self.getSourceDir() _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits