[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:
Walter Erquinigo 2022-05-05 14:42:54 -07:00
parent 1637545f68
commit 1188faa7ab
8 changed files with 271 additions and 176 deletions

View File

@ -10,6 +10,7 @@
#define LLDB_UTILITY_TRACEGDBREMOTEPACKETS_H
#include "llvm/Support/JSON.h"
#include <chrono>
#include "lldb/lldb-defines.h"

View File

@ -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

View File

@ -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(), {}});

View File

@ -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>>

View File

@ -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;
}

View File

@ -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_

View File

@ -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();
}

View File

@ -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_