forked from OSchip/llvm-project
[trace][intelpt] Support system-wide tracing [6] - Break IntelPTCollector into smaller files and minor refactor
IntelPTCollector is very big and has 3 classes in it. It's actually cleaner if each one has its own file. This also gives more visibility to the developer about the different kinds of "tracers" that we have. Besides that, I'm now restricting the creation of the BinaryData chunks to GetState() instead of having it in different places, which is not very clean, because the gdb-remote protocol should be as restricted as possible. Differential Revision: https://reviews.llvm.org/D125047
This commit is contained in:
parent
1637545f68
commit
1188faa7ab
|
@ -10,6 +10,7 @@
|
|||
#define LLDB_UTILITY_TRACEGDBREMOTEPACKETS_H
|
||||
|
||||
#include "llvm/Support/JSON.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "lldb/lldb-defines.h"
|
||||
|
|
|
@ -2,6 +2,8 @@ add_lldb_library(lldbPluginProcessLinux
|
|||
IntelPTCollector.cpp
|
||||
IntelPTSingleBufferTrace.cpp
|
||||
IntelPTMultiCoreTrace.cpp
|
||||
IntelPTPerThreadProcessTrace.cpp
|
||||
IntelPTThreadTraceCollection.cpp
|
||||
NativeProcessLinux.cpp
|
||||
NativeRegisterContextLinux.cpp
|
||||
NativeRegisterContextLinux_arm.cpp
|
||||
|
|
|
@ -32,101 +32,6 @@ using namespace lldb_private;
|
|||
using namespace process_linux;
|
||||
using namespace llvm;
|
||||
|
||||
/// IntelPTThreadTraceCollection
|
||||
|
||||
bool IntelPTThreadTraceCollection::TracesThread(lldb::tid_t tid) const {
|
||||
return m_thread_traces.count(tid);
|
||||
}
|
||||
|
||||
Error IntelPTThreadTraceCollection::TraceStop(lldb::tid_t tid) {
|
||||
auto it = m_thread_traces.find(tid);
|
||||
if (it == m_thread_traces.end())
|
||||
return createStringError(inconvertibleErrorCode(),
|
||||
"Thread %" PRIu64 " not currently traced", tid);
|
||||
m_total_buffer_size -= it->second->GetTraceBufferSize();
|
||||
m_thread_traces.erase(tid);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error IntelPTThreadTraceCollection::TraceStart(
|
||||
lldb::tid_t tid, const TraceIntelPTStartRequest &request) {
|
||||
if (TracesThread(tid))
|
||||
return createStringError(inconvertibleErrorCode(),
|
||||
"Thread %" PRIu64 " already traced", tid);
|
||||
|
||||
Expected<IntelPTSingleBufferTraceUP> trace_up =
|
||||
IntelPTSingleBufferTrace::Start(request, tid, /*core_id=*/None,
|
||||
TraceCollectionState::Running);
|
||||
if (!trace_up)
|
||||
return trace_up.takeError();
|
||||
|
||||
m_total_buffer_size += (*trace_up)->GetTraceBufferSize();
|
||||
m_thread_traces.try_emplace(tid, std::move(*trace_up));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
size_t IntelPTThreadTraceCollection::GetTotalBufferSize() const {
|
||||
return m_total_buffer_size;
|
||||
}
|
||||
|
||||
std::vector<TraceThreadState>
|
||||
IntelPTThreadTraceCollection::GetThreadStates() const {
|
||||
std::vector<TraceThreadState> states;
|
||||
for (const auto &it : m_thread_traces)
|
||||
states.push_back({it.first,
|
||||
{TraceBinaryData{IntelPTDataKinds::kTraceBuffer,
|
||||
it.second->GetTraceBufferSize()}}});
|
||||
return states;
|
||||
}
|
||||
|
||||
Expected<IntelPTSingleBufferTrace &>
|
||||
IntelPTThreadTraceCollection::GetTracedThread(lldb::tid_t tid) {
|
||||
auto it = m_thread_traces.find(tid);
|
||||
if (it == m_thread_traces.end())
|
||||
return createStringError(inconvertibleErrorCode(),
|
||||
"Thread %" PRIu64 " not currently traced", tid);
|
||||
return *it->second.get();
|
||||
}
|
||||
|
||||
void IntelPTThreadTraceCollection::Clear() {
|
||||
m_thread_traces.clear();
|
||||
m_total_buffer_size = 0;
|
||||
}
|
||||
|
||||
size_t IntelPTThreadTraceCollection::GetTracedThreadsCount() const {
|
||||
return m_thread_traces.size();
|
||||
}
|
||||
|
||||
/// IntelPTPerThreadProcessTrace
|
||||
|
||||
bool IntelPTPerThreadProcessTrace::TracesThread(lldb::tid_t tid) const {
|
||||
return m_thread_traces.TracesThread(tid);
|
||||
}
|
||||
|
||||
Error IntelPTPerThreadProcessTrace::TraceStop(lldb::tid_t tid) {
|
||||
return m_thread_traces.TraceStop(tid);
|
||||
}
|
||||
|
||||
Error IntelPTPerThreadProcessTrace::TraceStart(lldb::tid_t tid) {
|
||||
if (m_thread_traces.GetTotalBufferSize() +
|
||||
m_tracing_params.trace_buffer_size >
|
||||
static_cast<size_t>(*m_tracing_params.process_buffer_size_limit))
|
||||
return createStringError(
|
||||
inconvertibleErrorCode(),
|
||||
"Thread %" PRIu64 " can't be traced as the process trace size limit "
|
||||
"has been reached. Consider retracing with a higher "
|
||||
"limit.",
|
||||
tid);
|
||||
|
||||
return m_thread_traces.TraceStart(tid, m_tracing_params);
|
||||
}
|
||||
|
||||
IntelPTThreadTraceCollection &IntelPTPerThreadProcessTrace::GetThreadTraces() {
|
||||
return m_thread_traces;
|
||||
}
|
||||
|
||||
/// IntelPTCollector
|
||||
|
||||
IntelPTCollector::IntelPTCollector(NativeProcessProtocol &process)
|
||||
: m_process(process) {
|
||||
if (Expected<LinuxPerfZeroTscConversion> tsc_conversion =
|
||||
|
@ -245,7 +150,7 @@ Error IntelPTCollector::OnThreadDestroyed(lldb::tid_t tid) {
|
|||
return Error::success();
|
||||
}
|
||||
|
||||
Expected<json::Value> IntelPTCollector::GetState() const {
|
||||
Expected<json::Value> IntelPTCollector::GetState() {
|
||||
Expected<ArrayRef<uint8_t>> cpu_info = GetProcfsCpuInfo();
|
||||
if (!cpu_info)
|
||||
return cpu_info.takeError();
|
||||
|
@ -254,17 +159,24 @@ Expected<json::Value> IntelPTCollector::GetState() const {
|
|||
state.process_binary_data.push_back(
|
||||
{IntelPTDataKinds::kProcFsCpuInfo, cpu_info->size()});
|
||||
|
||||
std::vector<TraceThreadState> thread_states =
|
||||
m_thread_traces.GetThreadStates();
|
||||
state.traced_threads.insert(state.traced_threads.end(), thread_states.begin(),
|
||||
thread_states.end());
|
||||
m_thread_traces.ForEachThread(
|
||||
[&](lldb::tid_t tid, const IntelPTSingleBufferTrace &thread_trace) {
|
||||
state.traced_threads.push_back({tid,
|
||||
{{IntelPTDataKinds::kTraceBuffer,
|
||||
thread_trace.GetTraceBufferSize()}}});
|
||||
});
|
||||
|
||||
if (m_per_thread_process_trace_up) {
|
||||
thread_states =
|
||||
m_per_thread_process_trace_up->GetThreadTraces().GetThreadStates();
|
||||
state.traced_threads.insert(state.traced_threads.end(),
|
||||
thread_states.begin(), thread_states.end());
|
||||
} else if (m_per_core_process_trace_up) {
|
||||
m_per_thread_process_trace_up->GetThreadTraces().ForEachThread(
|
||||
[&](lldb::tid_t tid, const IntelPTSingleBufferTrace &thread_trace) {
|
||||
state.traced_threads.push_back(
|
||||
{tid,
|
||||
{{IntelPTDataKinds::kTraceBuffer,
|
||||
thread_trace.GetTraceBufferSize()}}});
|
||||
});
|
||||
}
|
||||
|
||||
if (m_per_core_process_trace_up) {
|
||||
for (size_t i = 0; m_process.GetThreadAtIndex(i); i++)
|
||||
state.traced_threads.push_back(
|
||||
TraceThreadState{m_process.GetThreadAtIndex(i)->GetID(), {}});
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "Perf.h"
|
||||
|
||||
#include "IntelPTMultiCoreTrace.h"
|
||||
#include "IntelPTPerThreadProcessTrace.h"
|
||||
#include "IntelPTSingleBufferTrace.h"
|
||||
|
||||
#include "lldb/Host/common/NativeProcessProtocol.h"
|
||||
|
@ -27,76 +28,6 @@ namespace lldb_private {
|
|||
|
||||
namespace process_linux {
|
||||
|
||||
/// Manages a list of thread traces.
|
||||
class IntelPTThreadTraceCollection {
|
||||
public:
|
||||
IntelPTThreadTraceCollection() {}
|
||||
|
||||
/// Dispose of all traces
|
||||
void Clear();
|
||||
|
||||
bool TracesThread(lldb::tid_t tid) const;
|
||||
|
||||
size_t GetTotalBufferSize() const;
|
||||
|
||||
std::vector<TraceThreadState> GetThreadStates() const;
|
||||
|
||||
llvm::Expected<IntelPTSingleBufferTrace &> GetTracedThread(lldb::tid_t tid);
|
||||
|
||||
llvm::Error TraceStart(lldb::tid_t tid,
|
||||
const TraceIntelPTStartRequest &request);
|
||||
|
||||
llvm::Error TraceStop(lldb::tid_t tid);
|
||||
|
||||
size_t GetTracedThreadsCount() const;
|
||||
|
||||
private:
|
||||
llvm::DenseMap<lldb::tid_t, IntelPTSingleBufferTraceUP> m_thread_traces;
|
||||
/// Total actual thread buffer size in bytes
|
||||
size_t m_total_buffer_size = 0;
|
||||
};
|
||||
|
||||
class IntelPTPerThreadProcessTrace;
|
||||
using IntelPTPerThreadProcessTraceUP =
|
||||
std::unique_ptr<IntelPTPerThreadProcessTrace>;
|
||||
|
||||
/// Manages a "process trace" instance by tracing each thread individually.
|
||||
class IntelPTPerThreadProcessTrace {
|
||||
public:
|
||||
/// Start tracing the current process by tracing each of its tids
|
||||
/// individually.
|
||||
///
|
||||
/// \param[in] request
|
||||
/// Intel PT configuration parameters.
|
||||
///
|
||||
/// \param[in] current_tids
|
||||
/// List of tids currently alive. In the future, whenever a new thread is
|
||||
/// spawned, they should be traced by calling the \a TraceStart(tid) method.
|
||||
///
|
||||
/// \return
|
||||
/// An \a IntelPTMultiCoreTrace instance if tracing was successful, or
|
||||
/// an \a llvm::Error otherwise.
|
||||
static llvm::Expected<IntelPTPerThreadProcessTraceUP>
|
||||
Start(const TraceIntelPTStartRequest &request,
|
||||
llvm::ArrayRef<lldb::tid_t> current_tids);
|
||||
|
||||
bool TracesThread(lldb::tid_t tid) const;
|
||||
|
||||
IntelPTThreadTraceCollection &GetThreadTraces();
|
||||
|
||||
llvm::Error TraceStart(lldb::tid_t tid);
|
||||
|
||||
llvm::Error TraceStop(lldb::tid_t tid);
|
||||
|
||||
private:
|
||||
IntelPTPerThreadProcessTrace(const TraceIntelPTStartRequest &request)
|
||||
: m_tracing_params(request) {}
|
||||
|
||||
IntelPTThreadTraceCollection m_thread_traces;
|
||||
/// Params used to trace threads when the user started "process tracing".
|
||||
TraceIntelPTStartRequest m_tracing_params;
|
||||
};
|
||||
|
||||
/// Main class that manages intel-pt process and thread tracing.
|
||||
class IntelPTCollector {
|
||||
public:
|
||||
|
@ -122,7 +53,7 @@ public:
|
|||
llvm::Error TraceStart(const TraceIntelPTStartRequest &request);
|
||||
|
||||
/// Implementation of the jLLDBTraceGetState packet
|
||||
llvm::Expected<llvm::json::Value> GetState() const;
|
||||
llvm::Expected<llvm::json::Value> GetState();
|
||||
|
||||
/// Implementation of the jLLDBTraceGetBinaryData packet
|
||||
llvm::Expected<std::vector<uint8_t>>
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
//===-- IntelPTPerThreadProcessTrace.cpp ----------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "IntelPTPerThreadProcessTrace.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
using namespace process_linux;
|
||||
using namespace llvm;
|
||||
|
||||
bool IntelPTPerThreadProcessTrace::TracesThread(lldb::tid_t tid) const {
|
||||
return m_thread_traces.TracesThread(tid);
|
||||
}
|
||||
|
||||
Error IntelPTPerThreadProcessTrace::TraceStop(lldb::tid_t tid) {
|
||||
return m_thread_traces.TraceStop(tid);
|
||||
}
|
||||
|
||||
Error IntelPTPerThreadProcessTrace::TraceStart(lldb::tid_t tid) {
|
||||
if (m_thread_traces.GetTotalBufferSize() +
|
||||
m_tracing_params.trace_buffer_size >
|
||||
static_cast<size_t>(*m_tracing_params.process_buffer_size_limit))
|
||||
return createStringError(
|
||||
inconvertibleErrorCode(),
|
||||
"Thread %" PRIu64 " can't be traced as the process trace size limit "
|
||||
"has been reached. Consider retracing with a higher "
|
||||
"limit.",
|
||||
tid);
|
||||
|
||||
return m_thread_traces.TraceStart(tid, m_tracing_params);
|
||||
}
|
||||
|
||||
IntelPTThreadTraceCollection &IntelPTPerThreadProcessTrace::GetThreadTraces() {
|
||||
return m_thread_traces;
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
//===-- IntelPTPerThreadProcessTrace.h ------------------------ -*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_IntelPTPerThreadProcessTrace_H_
|
||||
#define liblldb_IntelPTPerThreadProcessTrace_H_
|
||||
|
||||
#include "IntelPTSingleBufferTrace.h"
|
||||
#include "IntelPTThreadTraceCollection.h"
|
||||
|
||||
namespace lldb_private {
|
||||
namespace process_linux {
|
||||
|
||||
class IntelPTPerThreadProcessTrace;
|
||||
using IntelPTPerThreadProcessTraceUP =
|
||||
std::unique_ptr<IntelPTPerThreadProcessTrace>;
|
||||
|
||||
/// Manages a "process trace" instance by tracing each thread individually.
|
||||
class IntelPTPerThreadProcessTrace {
|
||||
public:
|
||||
/// Start tracing the current process by tracing each of its tids
|
||||
/// individually.
|
||||
///
|
||||
/// \param[in] request
|
||||
/// Intel PT configuration parameters.
|
||||
///
|
||||
/// \param[in] current_tids
|
||||
/// List of tids currently alive. In the future, whenever a new thread is
|
||||
/// spawned, they should be traced by calling the \a TraceStart(tid) method.
|
||||
///
|
||||
/// \return
|
||||
/// An \a IntelPTMultiCoreTrace instance if tracing was successful, or
|
||||
/// an \a llvm::Error otherwise.
|
||||
static llvm::Expected<IntelPTPerThreadProcessTraceUP>
|
||||
Start(const TraceIntelPTStartRequest &request,
|
||||
llvm::ArrayRef<lldb::tid_t> current_tids);
|
||||
|
||||
bool TracesThread(lldb::tid_t tid) const;
|
||||
|
||||
IntelPTThreadTraceCollection &GetThreadTraces();
|
||||
|
||||
/// \copydoc IntelPTThreadTraceCollection::TraceStart()
|
||||
llvm::Error TraceStart(lldb::tid_t tid);
|
||||
|
||||
/// \copydoc IntelPTThreadTraceCollection::TraceStop()
|
||||
llvm::Error TraceStop(lldb::tid_t tid);
|
||||
|
||||
private:
|
||||
IntelPTPerThreadProcessTrace(const TraceIntelPTStartRequest &request)
|
||||
: m_tracing_params(request) {}
|
||||
|
||||
IntelPTThreadTraceCollection m_thread_traces;
|
||||
/// Params used to trace threads when the user started "process tracing".
|
||||
TraceIntelPTStartRequest m_tracing_params;
|
||||
};
|
||||
|
||||
} // namespace process_linux
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // liblldb_IntelPTPerThreadProcessTrace_H_
|
|
@ -0,0 +1,74 @@
|
|||
//===-- IntelPTThreadTraceCollection.cpp ----------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "IntelPTThreadTraceCollection.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
using namespace process_linux;
|
||||
using namespace llvm;
|
||||
|
||||
bool IntelPTThreadTraceCollection::TracesThread(lldb::tid_t tid) const {
|
||||
return m_thread_traces.count(tid);
|
||||
}
|
||||
|
||||
Error IntelPTThreadTraceCollection::TraceStop(lldb::tid_t tid) {
|
||||
auto it = m_thread_traces.find(tid);
|
||||
if (it == m_thread_traces.end())
|
||||
return createStringError(inconvertibleErrorCode(),
|
||||
"Thread %" PRIu64 " not currently traced", tid);
|
||||
m_total_buffer_size -= it->second->GetTraceBufferSize();
|
||||
m_thread_traces.erase(tid);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error IntelPTThreadTraceCollection::TraceStart(
|
||||
lldb::tid_t tid, const TraceIntelPTStartRequest &request) {
|
||||
if (TracesThread(tid))
|
||||
return createStringError(inconvertibleErrorCode(),
|
||||
"Thread %" PRIu64 " already traced", tid);
|
||||
|
||||
Expected<IntelPTSingleBufferTraceUP> trace_up =
|
||||
IntelPTSingleBufferTrace::Start(request, tid, /*core_id=*/None,
|
||||
TraceCollectionState::Running);
|
||||
if (!trace_up)
|
||||
return trace_up.takeError();
|
||||
|
||||
m_total_buffer_size += (*trace_up)->GetTraceBufferSize();
|
||||
m_thread_traces.try_emplace(tid, std::move(*trace_up));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
size_t IntelPTThreadTraceCollection::GetTotalBufferSize() const {
|
||||
return m_total_buffer_size;
|
||||
}
|
||||
|
||||
void IntelPTThreadTraceCollection::ForEachThread(
|
||||
std::function<void(lldb::tid_t tid, IntelPTSingleBufferTrace &thread_trace)>
|
||||
callback) {
|
||||
for (auto &it : m_thread_traces)
|
||||
callback(it.first, *it.second);
|
||||
}
|
||||
|
||||
Expected<IntelPTSingleBufferTrace &>
|
||||
IntelPTThreadTraceCollection::GetTracedThread(lldb::tid_t tid) {
|
||||
auto it = m_thread_traces.find(tid);
|
||||
if (it == m_thread_traces.end())
|
||||
return createStringError(inconvertibleErrorCode(),
|
||||
"Thread %" PRIu64 " not currently traced", tid);
|
||||
return *it->second.get();
|
||||
}
|
||||
|
||||
void IntelPTThreadTraceCollection::Clear() {
|
||||
m_thread_traces.clear();
|
||||
m_total_buffer_size = 0;
|
||||
}
|
||||
|
||||
size_t IntelPTThreadTraceCollection::GetTracedThreadsCount() const {
|
||||
return m_thread_traces.size();
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
//===-- IntelPTThreadTraceCollection.h ------------------------ -*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_IntelPTPerThreadTraceCollection_H_
|
||||
#define liblldb_IntelPTPerThreadTraceCollection_H_
|
||||
|
||||
#include "IntelPTSingleBufferTrace.h"
|
||||
|
||||
namespace lldb_private {
|
||||
namespace process_linux {
|
||||
|
||||
/// Manages a list of thread traces.
|
||||
class IntelPTThreadTraceCollection {
|
||||
public:
|
||||
IntelPTThreadTraceCollection() {}
|
||||
|
||||
/// Dispose of all traces
|
||||
void Clear();
|
||||
|
||||
/// \return
|
||||
/// \b true if and only if this instance of tracing the provided \p tid.
|
||||
bool TracesThread(lldb::tid_t tid) const;
|
||||
|
||||
/// \return
|
||||
/// The total sum of the trace buffer sizes used by this collection.
|
||||
size_t GetTotalBufferSize() const;
|
||||
|
||||
/// Execute the provided callback on each thread that is being traced.
|
||||
///
|
||||
/// \param[in] callback.tid
|
||||
/// The id of the thread that is being traced.
|
||||
///
|
||||
/// \param[in] callback.core_trace
|
||||
/// The single-buffer trace instance for the given core.
|
||||
void ForEachThread(std::function<void(lldb::tid_t tid,
|
||||
IntelPTSingleBufferTrace &thread_trace)>
|
||||
callback);
|
||||
|
||||
llvm::Expected<IntelPTSingleBufferTrace &> GetTracedThread(lldb::tid_t tid);
|
||||
|
||||
/// Start tracing the thread given by its \p tid.
|
||||
///
|
||||
/// \return
|
||||
/// An error if the operation failed.
|
||||
llvm::Error TraceStart(lldb::tid_t tid,
|
||||
const TraceIntelPTStartRequest &request);
|
||||
|
||||
/// Stop tracing the thread given by its \p tid.
|
||||
///
|
||||
/// \return
|
||||
/// An error if the given thread is not being traced or tracing couldn't be
|
||||
/// stopped.
|
||||
llvm::Error TraceStop(lldb::tid_t tid);
|
||||
|
||||
size_t GetTracedThreadsCount() const;
|
||||
|
||||
private:
|
||||
llvm::DenseMap<lldb::tid_t, IntelPTSingleBufferTraceUP> m_thread_traces;
|
||||
/// Total actual thread buffer size in bytes
|
||||
size_t m_total_buffer_size = 0;
|
||||
};
|
||||
|
||||
} // namespace process_linux
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // liblldb_IntelPTPerThreadTraceCollection_H_
|
Loading…
Reference in New Issue