Author: Walter Erquinigo Date: 2022-06-15T12:08:00-07:00 New Revision: a0a46473c3df488c9ea63988595cea0bd0521fb4
URL: https://github.com/llvm/llvm-project/commit/a0a46473c3df488c9ea63988595cea0bd0521fb4 DIFF: https://github.com/llvm/llvm-project/commit/a0a46473c3df488c9ea63988595cea0bd0521fb4.diff LOG: [trace][intelpt] Support system-wide tracing [11] - Read warnings and perf conversion in the client - Add logging for when the live state of the process is refreshed - Move error handling of the live state refreshing to Trace from TraceIntelPT. This allows refreshing to fail either at the plug-in level or at the base class level. The error is cached and it can be gotten every time RefreshLiveProcessState is invoked. - Allow DoRefreshLiveProcessState to handle plugin-specific parameters. - Add some encapsulation to prevent TraceIntelPT from accessing variables belonging to Trace. Test done via logging: ``` (lldb) b main Breakpoint 1: where = a.out`main + 20 at main.cpp:27:20, address = 0x00000000004023d9 (lldb) r Process 2359706 launched: '/home/wallace/a.out' (x86_64) Process 2359706 stopped * thread #1, name = 'a.out', stop reason = breakpoint 1.1 frame #0: 0x00000000004023d9 a.out`main at main.cpp:27:20 24 }; 25 26 int main() { -> 27 std::vector<int> vvv; 28 for (int i = 0; i < 100000; i++) 29 vvv.push_back(i); 30 (lldb) process trace start (lldb) log enable lldb target -F(lldb) n Process 2359706 stopped * thread #1, name = 'a.out', stop reason = step over frame #0: 0x00000000004023e8 a.out`main at main.cpp:28:12 25 26 int main() { 27 std::vector<int> vvv; -> 28 for (int i = 0; i < 100000; i++) 29 vvv.push_back(i); 30 31 std::deque<int> dq1 = {1, 2, 3}; (lldb) thread trace dump instructions -c 2 -t Trace.cpp:RefreshLiveProcessState Trace::RefreshLiveProcessState invoked TraceIntelPT.cpp:DoRefreshLiveProcessState TraceIntelPT found tsc conversion information thread #1: tid = 2359706 a.out`std::vector<int, std::allocator<int>>::vector() + 26 at stl_vector.h:395:19 54: [tsc=unavailable] 0x0000000000403a7c retq ``` See the logging lines at the end of the dump. They indicate that refreshing happened and that perf conversion information was found. Differential Revision: https://reviews.llvm.org/D125943 Added: Modified: lldb/include/lldb/Target/Trace.h lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h lldb/source/Target/Trace.cpp Removed: ################################################################################ diff --git a/lldb/include/lldb/Target/Trace.h b/lldb/include/lldb/Target/Trace.h index 78575119b680b..88af9d3b221dc 100644 --- a/lldb/include/lldb/Target/Trace.h +++ b/lldb/include/lldb/Target/Trace.h @@ -265,6 +265,13 @@ class Trace : public PluginInterface, llvm::Error OnThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, OnBinaryDataReadCallback callback); + /// Get the current traced live process. + /// + /// \return + /// The current traced live process. If it's not a live process, + /// return \a nullptr. + Process *GetLiveProcess(); + protected: /// Implementation of \a OnThreadBinaryDataRead() for live threads. llvm::Error OnLiveThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind, @@ -365,14 +372,30 @@ class Trace : public PluginInterface, /// /// \param[in] state /// The jLLDBTraceGetState response. - virtual void - DoRefreshLiveProcessState(llvm::Expected<TraceGetStateResponse> state) = 0; + /// + /// \param[in] json_response + /// The original JSON response as a string. It might be useful to redecode + /// it if it contains custom data for a specific trace plug-in. + /// + /// \return + /// \b Error::success() if this operation succeedes, or an actual error + /// otherwise. + virtual llvm::Error + DoRefreshLiveProcessState(TraceGetStateResponse state, + llvm::StringRef json_response) = 0; - /// Method to be invoked by the plug-in to refresh the live process state. + /// Method to be invoked by the plug-in to refresh the live process state. It + /// will invoked DoRefreshLiveProcessState at some point, which should be + /// implemented by the plug-in for custom state handling. + /// + /// The result is cached through the same process stop. Even in the case of + /// errors, it caches the error. /// - /// The result is cached through the same process stop. - void RefreshLiveProcessState(); + /// \return + /// An error message if this operation failed, or \b nullptr otherwise. + const char *RefreshLiveProcessState(); +private: uint32_t m_stop_id = LLDB_INVALID_STOP_ID; /// Process traced by this object if doing live tracing. Otherwise it's null. Process *m_live_process = nullptr; @@ -395,6 +418,8 @@ class Trace : public PluginInterface, /// tid -> data kind -> file llvm::DenseMap<lldb::tid_t, std::unordered_map<std::string, FileSpec>> m_postmortem_thread_data; + + llvm::Optional<std::string> m_live_refresh_error; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp index 036333ddd859c..df3192a8bd9bf 100644 --- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp +++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp @@ -87,11 +87,10 @@ TraceIntelPT::TraceIntelPT( } DecodedThreadSP TraceIntelPT::Decode(Thread &thread) { - RefreshLiveProcessState(); - if (m_live_refresh_error.hasValue()) + if (const char *error = RefreshLiveProcessState()) return std::make_shared<DecodedThread>( thread.shared_from_this(), - createStringError(inconvertibleErrorCode(), *m_live_refresh_error)); + createStringError(inconvertibleErrorCode(), error)); auto it = m_thread_decoders.find(thread.GetID()); if (it == m_thread_decoders.end()) @@ -241,23 +240,29 @@ Expected<pt_cpu> TraceIntelPT::GetCPUInfo() { return *m_cpu_info; } -Process *TraceIntelPT::GetLiveProcess() { return m_live_process; } - -void TraceIntelPT::DoRefreshLiveProcessState( - Expected<TraceGetStateResponse> state) { +Error TraceIntelPT::DoRefreshLiveProcessState(TraceGetStateResponse state, + StringRef json_response) { m_thread_decoders.clear(); - if (!state) { - m_live_refresh_error = toString(state.takeError()); - return; - } - - for (const TraceThreadState &thread_state : state->traced_threads) { + for (const TraceThreadState &thread_state : state.traced_threads) { ThreadSP thread_sp = - m_live_process->GetThreadList().FindThreadByID(thread_state.tid); + GetLiveProcess()->GetThreadList().FindThreadByID(thread_state.tid); m_thread_decoders.emplace( thread_state.tid, std::make_unique<ThreadDecoder>(thread_sp, *this)); } + + Expected<TraceIntelPTGetStateResponse> intelpt_state = + json::parse<TraceIntelPTGetStateResponse>(json_response, + "TraceIntelPTGetStateResponse"); + if (!intelpt_state) + return intelpt_state.takeError(); + + m_tsc_conversion = intelpt_state->tsc_perf_zero_conversion; + if (m_tsc_conversion) { + Log *log = GetLog(LLDBLog::Target); + LLDB_LOG(log, "TraceIntelPT found TSC conversion information"); + } + return Error::success(); } bool TraceIntelPT::IsTraced(lldb::tid_t tid) { diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h index d5e8c93c2ba39..dd4f3e8430445 100644 --- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h +++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h @@ -75,8 +75,8 @@ class TraceIntelPT : public Trace { llvm::Expected<size_t> GetRawTraceSize(Thread &thread); - void DoRefreshLiveProcessState( - llvm::Expected<TraceGetStateResponse> state) override; + llvm::Error DoRefreshLiveProcessState(TraceGetStateResponse state, + llvm::StringRef json_response) override; bool IsTraced(lldb::tid_t tid) override; @@ -148,12 +148,6 @@ class TraceIntelPT : public Trace { llvm::Expected<pt_cpu> GetCPUInfo(); - /// Get the current traced live process. - /// - /// \return - /// The current traced live process. If it's not a live process, - /// return \a nullptr. - Process *GetLiveProcess(); /// \return /// The timer object for this trace. @@ -191,9 +185,11 @@ class TraceIntelPT : public Trace { /// binary data. llvm::Optional<pt_cpu> m_cpu_info; std::map<lldb::tid_t, std::unique_ptr<ThreadDecoder>> m_thread_decoders; - /// Error gotten after a failed live process update, if any. - llvm::Optional<std::string> m_live_refresh_error; + /// Helper variable used to track long running operations for telemetry. TaskTimer m_task_timer; + /// It is provided by either a session file or a live process to convert TSC + /// counters to and from nanos. It might not be available on all hosts. + llvm::Optional<LinuxPerfZeroTscConversion> m_tsc_conversion; }; } // namespace trace_intel_pt diff --git a/lldb/source/Target/Trace.cpp b/lldb/source/Target/Trace.cpp index 5d0920420cf7b..16d816e640181 100644 --- a/lldb/source/Target/Trace.cpp +++ b/lldb/source/Target/Trace.cpp @@ -17,6 +17,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Stream.h" using namespace lldb; @@ -175,28 +176,37 @@ Trace::GetLiveProcessBinaryData(llvm::StringRef kind) { return m_live_process->TraceGetBinaryData(request); } -void Trace::RefreshLiveProcessState() { +const char *Trace::RefreshLiveProcessState() { if (!m_live_process) - return; + return nullptr; uint32_t new_stop_id = m_live_process->GetStopID(); if (new_stop_id == m_stop_id) - return; + return nullptr; + + Log *log = GetLog(LLDBLog::Target); + LLDB_LOG(log, "Trace::RefreshLiveProcessState invoked"); m_stop_id = new_stop_id; m_live_thread_data.clear(); + m_live_refresh_error.reset(); + + auto HandleError = [&](Error &&err) -> const char * { + m_live_refresh_error = toString(std::move(err)); + return m_live_refresh_error->c_str(); + }; Expected<std::string> json_string = GetLiveProcessState(); - if (!json_string) { - DoRefreshLiveProcessState(json_string.takeError()); - return; - } + if (!json_string) + return HandleError(json_string.takeError()); + Expected<TraceGetStateResponse> live_process_state = json::parse<TraceGetStateResponse>(*json_string, "TraceGetStateResponse"); - if (!live_process_state) { - DoRefreshLiveProcessState(live_process_state.takeError()); - return; - } + if (!live_process_state) + return HandleError(live_process_state.takeError()); + + for (std::string &warning : live_process_state->warnings) + LLDB_LOG(log, "Warning when fetching the trace state: {0}", warning); for (const TraceThreadState &thread_state : live_process_state->traced_threads) { @@ -207,9 +217,15 @@ void Trace::RefreshLiveProcessState() { for (const TraceBinaryData &item : live_process_state->process_binary_data) m_live_process_data[item.kind] = item.size; - DoRefreshLiveProcessState(std::move(live_process_state)); + if (Error err = DoRefreshLiveProcessState(std::move(*live_process_state), + *json_string)) + return HandleError(std::move(err)); + + return nullptr; } +Process *Trace::GetLiveProcess() { return m_live_process; } + uint32_t Trace::GetStopID() { RefreshLiveProcessState(); return m_stop_id; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits