wallace updated this revision to Diff 426742.
wallace added a comment.
add one test
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D124858/new/
https://reviews.llvm.org/D124858
Files:
lldb/docs/lldb-gdb-remote.txt
lldb/include/lldb/Utility/TraceGDBRemotePackets.h
lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
lldb/include/lldb/lldb-types.h
lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
lldb/source/Plugins/Process/Linux/CMakeLists.txt
lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
lldb/source/Plugins/Process/Linux/IntelPTCollector.h
lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.cpp
lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.h
lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.cpp
lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.h
lldb/source/Plugins/Process/Linux/Perf.cpp
lldb/source/Plugins/Process/Linux/Perf.h
lldb/source/Plugins/Process/Linux/Procfs.cpp
lldb/source/Plugins/Process/Linux/Procfs.h
lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
lldb/source/Target/Trace.cpp
lldb/source/Utility/TraceGDBRemotePackets.cpp
lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py
Index: lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py
===================================================================
--- lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py
+++ lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py
@@ -30,6 +30,8 @@
self.expect("continue")
self.expect("thread trace dump instructions", substrs=['main.cpp:4'])
+ self.traceStopProcess()
+
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
@testSBAPIAndCommands
def testStartMultipleLiveThreadsWithStops(self):
@@ -65,6 +67,8 @@
self.expect("thread trace dump instructions 2", substrs=['not traced'])
+ self.traceStopProcess()
+
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
@testSBAPIAndCommands
def testStartMultipleLiveThreadsWithStops(self):
@@ -100,6 +104,8 @@
self.expect("thread trace dump instructions 1", substrs=['not traced'])
self.expect("thread trace dump instructions 2", substrs=['not traced'])
+ self.traceStopProcess()
+
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
def testStartMultipleLiveThreadsWithThreadStartAll(self):
self.build()
@@ -156,6 +162,8 @@
@skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
@testSBAPIAndCommands
def testStartPerCoreSession(self):
+ self.skipIfPerCoreTracingIsNotSupported()
+
self.build()
exe = self.getBuildArtifact("a.out")
self.dbg.CreateTarget(exe)
@@ -163,6 +171,32 @@
self.expect("b main")
self.expect("r")
- self.traceStartProcess(
- error=True, perCoreTracing=True,
- substrs=["Per-core tracing is not supported"])
+ # We should fail if we hit the total buffer limit. Useful if the number
+ # of cores is huge.
+ self.traceStartProcess(error="True", processBufferSizeLimit=100,
+ perCoreTracing=True,
+ substrs=["The process can't be traced because the process trace size "
+ "limit has been reached. Consider retracing with a higher limit."])
+
+ self.traceStartProcess(perCoreTracing=True)
+ self.traceStopProcess()
+
+ self.traceStartProcess(perCoreTracing=True)
+ # We can't support multiple per-core tracing sessions.
+ self.traceStartProcess(error=True, perCoreTracing=True,
+ substrs=["Process currently traced. Stop process tracing first"])
+
+ # We can't support tracing per thread is per core is enabled.
+ self.traceStartThread(
+ error="True",
+ substrs=["Process currently traced with per-core tracing. Stop process tracing first"])
+
+ # We can't stop individual thread when per core is enabled.
+ self.traceStopThread(error="True",
+ substrs=["Can't stop tracing an individual thread when per-core process tracing is enabled"])
+
+ # The GetState packet should return trace buffers per core
+ self.expect("""process plugin packet send 'jLLDBTraceGetState:{"type":"intel-pt"}]'""",
+ substrs=['''[{"kind":"traceBuffer","size":4096}],"coreId":'''])
+
+ self.traceStopProcess()
Index: lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
===================================================================
--- lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
+++ lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
@@ -16,6 +16,10 @@
const char *IntelPTDataKinds::kProcFsCpuInfo = "procfsCpuInfo";
const char *IntelPTDataKinds::kTraceBuffer = "traceBuffer";
+bool TraceIntelPTStartRequest::IsPerCoreTracing() const {
+ return per_core_tracing.getValueOr(false);
+}
+
bool fromJSON(const json::Value &value, TraceIntelPTStartRequest &packet,
Path path) {
ObjectMapper o(value, path);
Index: lldb/source/Utility/TraceGDBRemotePackets.cpp
===================================================================
--- lldb/source/Utility/TraceGDBRemotePackets.cpp
+++ lldb/source/Utility/TraceGDBRemotePackets.cpp
@@ -87,24 +87,42 @@
bool fromJSON(const json::Value &value, TraceThreadState &packet, Path path) {
ObjectMapper o(value, path);
return o && o.map("tid", packet.tid) &&
- o.map("binaryData", packet.binaryData);
+ o.map("binaryData", packet.binary_data);
}
json::Value toJSON(const TraceThreadState &packet) {
return json::Value(
- Object{{"tid", packet.tid}, {"binaryData", packet.binaryData}});
+ Object{{"tid", packet.tid}, {"binaryData", packet.binary_data}});
}
bool fromJSON(const json::Value &value, TraceGetStateResponse &packet,
Path path) {
ObjectMapper o(value, path);
- return o && o.map("tracedThreads", packet.tracedThreads) &&
- o.map("processBinaryData", packet.processBinaryData);
+ return o && o.map("tracedThreads", packet.traced_threads) &&
+ o.map("processBinaryData", packet.process_binary_data) &&
+ o.map("cores", packet.cores);
}
json::Value toJSON(const TraceGetStateResponse &packet) {
- return json::Value(Object{{"tracedThreads", packet.tracedThreads},
- {"processBinaryData", packet.processBinaryData}});
+ return json::Value(Object{{"tracedThreads", packet.traced_threads},
+ {"processBinaryData", packet.process_binary_data},
+ {"cores", packet.cores}});
+}
+
+bool fromJSON(const json::Value &value, TraceCoreState &packet,
+ json::Path path) {
+ ObjectMapper o(value, path);
+ int64_t core_id;
+ if (!o || !o.map("coreId", core_id) ||
+ !o.map("binaryData", packet.binary_data))
+ return false;
+ packet.core_id = static_cast<lldb::core_id_t>(core_id);
+ return true;
+}
+
+json::Value toJSON(const TraceCoreState &packet) {
+ return json::Value(Object{{"coreId", static_cast<int64_t>(packet.core_id)},
+ {"binaryData", packet.binary_data}});
}
/// \}
Index: lldb/source/Target/Trace.cpp
===================================================================
--- lldb/source/Target/Trace.cpp
+++ lldb/source/Target/Trace.cpp
@@ -200,12 +200,12 @@
}
for (const TraceThreadState &thread_state :
- live_process_state->tracedThreads) {
- for (const TraceBinaryData &item : thread_state.binaryData)
+ live_process_state->traced_threads) {
+ for (const TraceBinaryData &item : thread_state.binary_data)
m_live_thread_data[thread_state.tid][item.kind] = item.size;
}
- for (const TraceBinaryData &item : live_process_state->processBinaryData)
+ for (const TraceBinaryData &item : live_process_state->process_binary_data)
m_live_process_data[item.kind] = item.size;
DoRefreshLiveProcessState(std::move(live_process_state));
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
@@ -57,8 +57,8 @@
Group<1>,
Arg<"Value">,
Desc<"Maximum total trace size per process in bytes. This limit applies to "
- "the sum of the sizes of all thread traces of this process, excluding "
- "the ones created with the \"thread trace start\" command. "
+ "the sum of the sizes of all thread and core traces of this process, "
+ "excluding the ones created with the \"thread trace start\" command. "
"Whenever a thread is attempted to be traced due to this command and "
"the limit would be reached, the process is stopped with a "
"\"processor trace\" reason, so that the user can retrace the process "
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -252,7 +252,7 @@
return;
}
- for (const TraceThreadState &thread_state : state->tracedThreads) {
+ for (const TraceThreadState &thread_state : state->traced_threads) {
ThreadSP thread_sp =
m_live_process->GetThreadList().FindThreadByID(thread_state.tid);
m_thread_decoders.emplace(
Index: lldb/source/Plugins/Process/Linux/Procfs.h
===================================================================
--- lldb/source/Plugins/Process/Linux/Procfs.h
+++ lldb/source/Plugins/Process/Linux/Procfs.h
@@ -11,6 +11,8 @@
#include <sys/ptrace.h>
+#include "lldb/lldb-types.h"
+
#include "llvm/Support/Error.h"
#include <vector>
@@ -43,7 +45,7 @@
/// \return
/// A list of available logical core ids given the contents of
/// /proc/cpuinfo.
-llvm::Expected<std::vector<int>>
+llvm::Expected<std::vector<lldb::core_id_t>>
GetAvailableLogicalCoreIDs(llvm::StringRef cpuinfo);
/// \return
Index: lldb/source/Plugins/Process/Linux/Procfs.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/Procfs.cpp
+++ lldb/source/Plugins/Process/Linux/Procfs.cpp
@@ -11,6 +11,7 @@
#include "lldb/Host/linux/Support.h"
#include "llvm/Support/MemoryBuffer.h"
+using namespace lldb;
using namespace lldb_private;
using namespace process_linux;
using namespace llvm;
@@ -29,18 +30,18 @@
return *cpu_info;
}
-Expected<std::vector<int>>
+Expected<std::vector<core_id_t>>
lldb_private::process_linux::GetAvailableLogicalCoreIDs(StringRef cpuinfo) {
SmallVector<StringRef, 8> lines;
cpuinfo.split(lines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
- std::vector<int> logical_cores;
+ std::vector<core_id_t> logical_cores;
for (StringRef line : lines) {
std::pair<StringRef, StringRef> key_value = line.split(':');
auto key = key_value.first.trim();
auto val = key_value.second.trim();
if (key == "processor") {
- int processor;
+ core_id_t processor;
if (val.getAsInteger(10, processor))
return createStringError(
inconvertibleErrorCode(),
@@ -51,16 +52,16 @@
return logical_cores;
}
-llvm::Expected<llvm::ArrayRef<int>>
+llvm::Expected<llvm::ArrayRef<core_id_t>>
lldb_private::process_linux::GetAvailableLogicalCoreIDs() {
- static Optional<std::vector<int>> logical_cores_ids;
+ static Optional<std::vector<core_id_t>> logical_cores_ids;
if (!logical_cores_ids) {
// We find the actual list of core ids by parsing /proc/cpuinfo
Expected<ArrayRef<uint8_t>> cpuinfo = GetProcfsCpuInfo();
if (!cpuinfo)
return cpuinfo.takeError();
- Expected<std::vector<int>> core_ids = GetAvailableLogicalCoreIDs(
+ Expected<std::vector<core_id_t>> core_ids = GetAvailableLogicalCoreIDs(
StringRef(reinterpret_cast<const char *>(cpuinfo->data())));
if (!core_ids)
return core_ids.takeError();
Index: lldb/source/Plugins/Process/Linux/Perf.h
===================================================================
--- lldb/source/Plugins/Process/Linux/Perf.h
+++ lldb/source/Plugins/Process/Linux/Perf.h
@@ -109,7 +109,7 @@
/// Configuration information for the event.
///
/// \param[in] pid
- /// The process to be monitored by the event.
+ /// The process or thread to be monitored by the event.
///
/// \param[in] cpu
/// The cpu to be monitored by the event.
@@ -123,9 +123,10 @@
/// \return
/// If the perf_event_open syscall was successful, a minimal \a PerfEvent
/// instance, or an \a llvm::Error otherwise.
- static llvm::Expected<PerfEvent> Init(perf_event_attr &attr, lldb::pid_t pid,
- int cpu, int group_fd,
- unsigned long flags);
+ static llvm::Expected<PerfEvent> Init(perf_event_attr &attr,
+ llvm::Optional<lldb::pid_t> pid,
+ llvm::Optional<lldb::core_id_t> cpu,
+ int group_fd, unsigned long flags);
/// Create a new performance monitoring event via the perf_event_open syscall
/// with "default" values for the cpu, group_fd and flags arguments.
@@ -137,8 +138,10 @@
/// Configuration information for the event.
///
/// \param[in] pid
- /// The process to be monitored by the event.
- static llvm::Expected<PerfEvent> Init(perf_event_attr &attr, lldb::pid_t pid);
+ /// The process or thread to be monitored by the event.
+ static llvm::Expected<PerfEvent>
+ Init(perf_event_attr &attr, llvm::Optional<lldb::pid_t> pid,
+ llvm::Optional<lldb::core_id_t> core = llvm::None);
/// Mmap the metadata page and the data and aux buffers of the perf event and
/// expose them through \a PerfEvent::GetMetadataPage() , \a
Index: lldb/source/Plugins/Process/Linux/Perf.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/Perf.cpp
+++ lldb/source/Plugins/Process/Linux/Perf.cpp
@@ -117,10 +117,12 @@
}
llvm::Expected<PerfEvent> PerfEvent::Init(perf_event_attr &attr,
- lldb::pid_t pid, int cpu,
+ Optional<lldb::pid_t> pid,
+ Optional<lldb::core_id_t> cpu,
int group_fd, unsigned long flags) {
errno = 0;
- long fd = syscall(SYS_perf_event_open, &attr, pid, cpu, group_fd, flags);
+ long fd = syscall(SYS_perf_event_open, &attr, pid.getValueOr(-1),
+ cpu.getValueOr(-1), group_fd, flags);
if (fd == -1) {
std::string err_msg =
llvm::formatv("perf event syscall failed: {0}", std::strerror(errno));
@@ -130,8 +132,9 @@
}
llvm::Expected<PerfEvent> PerfEvent::Init(perf_event_attr &attr,
- lldb::pid_t pid) {
- return Init(attr, pid, -1, -1, 0);
+ Optional<lldb::pid_t> pid,
+ Optional<lldb::core_id_t> cpu) {
+ return Init(attr, pid, cpu, -1, 0);
}
llvm::Expected<resource_handle::MmapUP>
Index: lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.h
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.h
+++ lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.h
@@ -23,10 +23,8 @@
llvm::Expected<uint32_t> GetIntelPTOSEventType();
-class IntelPTTrace;
class IntelPTSingleBufferTrace;
-using IntelPTThreadTraceUP = std::unique_ptr<IntelPTTrace>;
using IntelPTSingleBufferTraceUP = std::unique_ptr<IntelPTSingleBufferTrace>;
/// This class wraps a single perf event collecting intel pt data in a single
@@ -39,13 +37,19 @@
/// Intel PT configuration parameters.
///
/// \param[in] tid
- /// The tid of the thread to be traced.
+ /// The tid of the thread to be traced. If \b None, then this traces all
+ /// threads of all processes.
+ ///
+ /// \param[in] core_id
+ /// The CPU core id where to trace. If \b None, then this traces all CPUs.
///
/// \return
/// A \a IntelPTSingleBufferTrace instance if tracing was successful, or
/// an \a llvm::Error otherwise.
static llvm::Expected<IntelPTSingleBufferTraceUP>
- Start(const TraceIntelPTStartRequest &request, lldb::tid_t tid);
+ Start(const TraceIntelPTStartRequest &request,
+ llvm::Optional<lldb::tid_t> tid,
+ llvm::Optional<lldb::core_id_t> core_id = llvm::None);
/// \return
/// The bytes requested by a jLLDBTraceGetBinaryData packet that was routed
@@ -80,10 +84,7 @@
///
/// \param[in] perf_event
/// perf event configured for IntelPT.
- ///
- /// \param[in] tid
- /// The thread being traced.
- IntelPTSingleBufferTrace(PerfEvent &&perf_event, lldb::tid_t tid)
+ IntelPTSingleBufferTrace(PerfEvent &&perf_event)
: m_perf_event(std::move(perf_event)) {}
/// perf event configured for IntelPT.
Index: lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.cpp
+++ lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.cpp
@@ -262,10 +262,12 @@
Expected<IntelPTSingleBufferTraceUP>
IntelPTSingleBufferTrace::Start(const TraceIntelPTStartRequest &request,
- lldb::tid_t tid) {
+ Optional<lldb::tid_t> tid,
+ Optional<core_id_t> core_id) {
Log *log = GetLog(POSIXLog::Trace);
- LLDB_LOG(log, "Will start tracing thread id {0}", tid);
+ LLDB_LOG(log, "Will start tracing thread id {0} and cpu id {1}", tid,
+ core_id);
if (__builtin_popcount(request.trace_buffer_size) != 1 ||
request.trace_buffer_size < 4096) {
@@ -289,13 +291,13 @@
LLDB_LOG(log, "Will create trace buffer of size {0}",
request.trace_buffer_size);
- if (Expected<PerfEvent> perf_event = PerfEvent::Init(*attr, tid)) {
+ if (Expected<PerfEvent> perf_event = PerfEvent::Init(*attr, tid, core_id)) {
if (Error mmap_err = perf_event->MmapMetadataAndBuffers(buffer_numpages,
buffer_numpages)) {
return std::move(mmap_err);
}
return IntelPTSingleBufferTraceUP(
- new IntelPTSingleBufferTrace(std::move(*perf_event), tid));
+ new IntelPTSingleBufferTrace(std::move(*perf_event)));
} else {
return perf_event.takeError();
}
Index: lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.h
@@ -0,0 +1,64 @@
+//===-- IntelPTMultiCoreTrace.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_IntelPTMultiCoreTrace_H_
+#define liblldb_IntelPTMultiCoreTrace_H_
+
+#include "IntelPTSingleBufferTrace.h"
+
+#include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
+#include "lldb/lldb-types.h"
+
+#include "llvm/Support/Error.h"
+
+#include <memory>
+
+namespace lldb_private {
+namespace process_linux {
+
+class IntelPTMultiCoreTrace;
+using IntelPTMultiCoreTraceUP = std::unique_ptr<IntelPTMultiCoreTrace>;
+
+class IntelPTMultiCoreTrace {
+public:
+ /// Start tracing all CPU cores.
+ ///
+ /// \param[in] request
+ /// Intel PT configuration parameters.
+ ///
+ /// \return
+ /// An \a IntelPTMultiCoreTrace instance if tracing was successful, or
+ /// an \a llvm::Error otherwise.
+ static llvm::Expected<IntelPTMultiCoreTraceUP>
+ StartOnAllCores(const TraceIntelPTStartRequest &request);
+
+ /// Execute the provided callback on each core that is being traced.
+ ///
+ /// \param[in] callback.core_id
+ /// The core id that is being traced.
+ ///
+ /// \param[in] callback.core_trace
+ /// The single-buffer trace instance for the given core.
+ void
+ ForEachCore(std::function<void(lldb::core_id_t core_id,
+ const IntelPTSingleBufferTrace &core_trace)>
+ callback);
+
+private:
+ IntelPTMultiCoreTrace(
+ llvm::DenseMap<lldb::core_id_t, IntelPTSingleBufferTraceUP>
+ &&traces_per_core)
+ : m_traces_per_core(std::move(traces_per_core)) {}
+
+ llvm::DenseMap<lldb::core_id_t, IntelPTSingleBufferTraceUP> m_traces_per_core;
+};
+
+} // namespace process_linux
+} // namespace lldb_private
+
+#endif // liblldb_IntelPTMultiCoreTrace_H_
Index: lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.cpp
@@ -0,0 +1,63 @@
+//===-- IntelPTMultiCoreTrace.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 "IntelPTMultiCoreTrace.h"
+
+#include "Procfs.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace process_linux;
+using namespace llvm;
+
+static bool IsTotalBufferLimitReached(ArrayRef<core_id_t> cores,
+ const TraceIntelPTStartRequest &request) {
+ int64_t required = cores.size() * request.trace_buffer_size;
+ int64_t limit = request.process_buffer_size_limit.getValueOr(
+ std::numeric_limits<int64_t>::max());
+ return required > limit;
+}
+
+static Error IncludePerfEventParanoidMessageInError(Error &&error) {
+ return createStringError(
+ inconvertibleErrorCode(),
+ "%s\n You might need that /proc/sys/kernel/perf_event_paranoid has a "
+ "value of 0 or -1.");
+}
+
+Expected<IntelPTMultiCoreTraceUP> IntelPTMultiCoreTrace::StartOnAllCores(
+ const TraceIntelPTStartRequest &request) {
+ Expected<ArrayRef<core_id_t>> core_ids = GetAvailableLogicalCoreIDs();
+ if (!core_ids)
+ return core_ids.takeError();
+
+ if (IsTotalBufferLimitReached(*core_ids, request))
+ return createStringError(
+ inconvertibleErrorCode(),
+ "The process can't be traced because the process trace size limit "
+ "has been reached. Consider retracing with a higher limit.");
+
+ llvm::DenseMap<core_id_t, IntelPTSingleBufferTraceUP> buffers;
+ for (core_id_t core_id : *core_ids) {
+ if (Expected<IntelPTSingleBufferTraceUP> core_trace =
+ IntelPTSingleBufferTrace::Start(request, /*tid=*/None, core_id))
+ buffers.try_emplace(core_id, std::move(*core_trace));
+ else
+ return IncludePerfEventParanoidMessageInError(core_trace.takeError());
+ }
+
+ return IntelPTMultiCoreTraceUP(new IntelPTMultiCoreTrace(std::move(buffers)));
+}
+
+void IntelPTMultiCoreTrace::ForEachCore(
+ std::function<void(core_id_t core_id,
+ const IntelPTSingleBufferTrace &core_trace)>
+ callback) {
+ for (auto &it : m_traces_per_core)
+ callback(it.first, *it.second);
+}
Index: lldb/source/Plugins/Process/Linux/IntelPTCollector.h
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTCollector.h
+++ lldb/source/Plugins/Process/Linux/IntelPTCollector.h
@@ -1,4 +1,4 @@
-//===-- IntelPTCollector.h -------------------------------------- -*- C++ -*-===//
+//===-- IntelPTCollector.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.
@@ -11,6 +11,7 @@
#include "Perf.h"
+#include "IntelPTMultiCoreTrace.h"
#include "IntelPTSingleBufferTrace.h"
#include "lldb/Utility/Status.h"
@@ -47,17 +48,37 @@
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;
};
-/// Manages a "process trace" instance.
-class IntelPTProcessTrace {
+class IntelPTPerThreadProcessTrace;
+using IntelPTPerThreadProcessTraceUP =
+ std::unique_ptr<IntelPTPerThreadProcessTrace>;
+
+/// Manages a "process trace" instance by tracing each thread individually.
+class IntelPTPerThreadProcessTrace {
public:
- IntelPTProcessTrace(const TraceIntelPTStartRequest &request)
- : m_tracing_params(request) {}
+ /// 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;
@@ -68,6 +89,9 @@
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;
@@ -122,9 +146,14 @@
/// Threads traced due to "thread tracing"
IntelPTThreadTraceCollection m_thread_traces;
- /// Threads traced due to "process tracing". Only one active "process tracing"
- /// instance is assumed for a single process.
- llvm::Optional<IntelPTProcessTrace> m_process_trace;
+ /// Threads traced due to per-thread "process tracing". Only one active
+ /// "process tracing" instance is allowed for a single process.
+ /// This might be \b nullptr.
+ IntelPTPerThreadProcessTraceUP m_per_thread_process_trace_up;
+ /// Cores traced due to per-core "process tracing". Only one active
+ /// "process tracing" instance is allowed for a single process.
+ /// This might be \b nullptr.
+ IntelPTMultiCoreTraceUP m_per_core_process_trace_up;
/// TSC to wall time conversion.
TraceTscConversionUP m_tsc_conversion;
};
Index: lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
+++ lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
@@ -93,17 +93,21 @@
m_total_buffer_size = 0;
}
-/// IntelPTProcessTrace
+size_t IntelPTThreadTraceCollection::GetTracedThreadsCount() const {
+ return m_thread_traces.size();
+}
+
+/// IntelPTPerThreadProcessTrace
-bool IntelPTProcessTrace::TracesThread(lldb::tid_t tid) const {
+bool IntelPTPerThreadProcessTrace::TracesThread(lldb::tid_t tid) const {
return m_thread_traces.TracesThread(tid);
}
-Error IntelPTProcessTrace::TraceStop(lldb::tid_t tid) {
+Error IntelPTPerThreadProcessTrace::TraceStop(lldb::tid_t tid) {
return m_thread_traces.TraceStop(tid);
}
-Error IntelPTProcessTrace::TraceStart(lldb::tid_t 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))
@@ -118,7 +122,7 @@
}
const IntelPTThreadTraceCollection &
-IntelPTProcessTrace::GetThreadTraces() const {
+IntelPTPerThreadProcessTrace::GetThreadTraces() const {
return m_thread_traces;
}
@@ -135,8 +139,13 @@
}
Error IntelPTCollector::TraceStop(lldb::tid_t tid) {
- if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid))
- return m_process_trace->TraceStop(tid);
+ if (m_per_thread_process_trace_up &&
+ m_per_thread_process_trace_up->TracesThread(tid))
+ return m_per_thread_process_trace_up->TraceStop(tid);
+ if (m_per_core_process_trace_up)
+ return createStringError(inconvertibleErrorCode(),
+ "Can't stop tracing an individual thread when "
+ "per-core process tracing is enabled.");
return m_thread_traces.TraceStop(tid);
}
@@ -153,6 +162,20 @@
}
}
+Expected<IntelPTPerThreadProcessTraceUP>
+IntelPTPerThreadProcessTrace::Start(const TraceIntelPTStartRequest &request,
+ ArrayRef<lldb::tid_t> current_tids) {
+ IntelPTPerThreadProcessTraceUP trace(
+ new IntelPTPerThreadProcessTrace(request));
+
+ Error error = Error::success();
+ for (lldb::tid_t tid : current_tids)
+ error = joinErrors(std::move(error), trace->TraceStart(tid));
+ if (error)
+ return std::move(error);
+ return trace;
+}
+
Error IntelPTCollector::TraceStart(
const TraceIntelPTStartRequest &request,
const std::vector<lldb::tid_t> &process_threads) {
@@ -162,17 +185,35 @@
inconvertibleErrorCode(),
"Process currently traced. Stop process tracing first");
}
- if (request.per_core_tracing.getValueOr(false)) {
- return createStringError(inconvertibleErrorCode(),
- "Per-core tracing is not supported.");
+ if (request.IsPerCoreTracing()) {
+ if (m_thread_traces.GetTracedThreadsCount() > 0)
+ return createStringError(
+ inconvertibleErrorCode(),
+ "Threads currently traced. Stop tracing them first.");
+ if (Expected<IntelPTMultiCoreTraceUP> trace =
+ IntelPTMultiCoreTrace::StartOnAllCores(request)) {
+ m_per_core_process_trace_up = std::move(*trace);
+ return Error::success();
+ } else {
+ return trace.takeError();
+ }
+ } else {
+ // per-thread process tracing
+ if (Expected<IntelPTPerThreadProcessTraceUP> trace =
+ IntelPTPerThreadProcessTrace::Start(request, process_threads)) {
+ m_per_thread_process_trace_up = std::move(trace.get());
+ return Error::success();
+ } else {
+ return trace.takeError();
+ }
}
- m_process_trace = IntelPTProcessTrace(request);
-
- Error error = Error::success();
- for (lldb::tid_t tid : process_threads)
- error = joinErrors(std::move(error), m_process_trace->TraceStart(tid));
- return error;
} else {
+ // individual thread tracing
+ if (m_per_core_process_trace_up)
+ return createStringError(inconvertibleErrorCode(),
+ "Process currently traced with per-core "
+ "tracing. Stop process tracing first");
+
Error error = Error::success();
for (int64_t tid : *request.tids)
error = joinErrors(std::move(error),
@@ -184,12 +225,13 @@
Error IntelPTCollector::OnThreadCreated(lldb::tid_t tid) {
if (!IsProcessTracingEnabled())
return Error::success();
- return m_process_trace->TraceStart(tid);
+ return m_per_thread_process_trace_up->TraceStart(tid);
}
Error IntelPTCollector::OnThreadDestroyed(lldb::tid_t tid) {
- if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid))
- return m_process_trace->TraceStop(tid);
+ if (IsProcessTracingEnabled() &&
+ m_per_thread_process_trace_up->TracesThread(tid))
+ return m_per_thread_process_trace_up->TraceStop(tid);
else if (m_thread_traces.TracesThread(tid))
return m_thread_traces.TraceStop(tid);
return Error::success();
@@ -201,26 +243,40 @@
return cpu_info.takeError();
TraceGetStateResponse state;
- state.processBinaryData.push_back({IntelPTDataKinds::kProcFsCpuInfo,
- static_cast<int64_t>(cpu_info->size())});
+ state.process_binary_data.push_back({IntelPTDataKinds::kProcFsCpuInfo,
+ static_cast<int64_t>(cpu_info->size())});
std::vector<TraceThreadState> thread_states =
m_thread_traces.GetThreadStates();
- state.tracedThreads.insert(state.tracedThreads.end(), thread_states.begin(),
- thread_states.end());
-
- if (IsProcessTracingEnabled()) {
- thread_states = m_process_trace->GetThreadTraces().GetThreadStates();
- state.tracedThreads.insert(state.tracedThreads.end(), thread_states.begin(),
- thread_states.end());
+ state.traced_threads.insert(state.traced_threads.end(), thread_states.begin(),
+ thread_states.end());
+
+ 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());
+ }
+ if (m_per_core_process_trace_up) {
+ state.cores.emplace();
+ m_per_core_process_trace_up->ForEachCore(
+ [&](lldb::core_id_t core_id,
+ const IntelPTSingleBufferTrace &core_trace) {
+ state.cores->push_back(
+ {core_id,
+ {{IntelPTDataKinds::kTraceBuffer,
+ static_cast<int64_t>(core_trace.GetTraceBufferSize())}}});
+ });
}
return toJSON(state);
}
Expected<const IntelPTSingleBufferTrace &>
IntelPTCollector::GetTracedThread(lldb::tid_t tid) const {
- if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid))
- return m_process_trace->GetThreadTraces().GetTracedThread(tid);
+ if (IsProcessTracingEnabled() &&
+ m_per_thread_process_trace_up->TracesThread(tid))
+ return m_per_thread_process_trace_up->GetThreadTraces().GetTracedThread(
+ tid);
return m_thread_traces.GetTracedThread(tid);
}
@@ -240,7 +296,10 @@
request.kind.c_str());
}
-void IntelPTCollector::ClearProcessTracing() { m_process_trace = None; }
+void IntelPTCollector::ClearProcessTracing() {
+ m_per_thread_process_trace_up.reset();
+ m_per_core_process_trace_up.reset();
+}
bool IntelPTCollector::IsSupported() {
if (Expected<uint32_t> intel_pt_type = GetIntelPTOSEventType()) {
@@ -252,7 +311,8 @@
}
bool IntelPTCollector::IsProcessTracingEnabled() const {
- return (bool)m_process_trace;
+ return (bool)m_per_thread_process_trace_up ||
+ (bool)m_per_core_process_trace_up;
}
void IntelPTCollector::Clear() {
Index: lldb/source/Plugins/Process/Linux/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/Process/Linux/CMakeLists.txt
+++ lldb/source/Plugins/Process/Linux/CMakeLists.txt
@@ -1,6 +1,7 @@
add_lldb_library(lldbPluginProcessLinux
IntelPTCollector.cpp
IntelPTSingleBufferTrace.cpp
+ IntelPTMultiCoreTrace.cpp
NativeProcessLinux.cpp
NativeRegisterContextLinux.cpp
NativeRegisterContextLinux_arm.cpp
Index: lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
+++ lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
@@ -33,6 +33,19 @@
if 'intel-pt' not in configuration.enabled_plugins:
self.skipTest("The intel-pt test plugin is not enabled")
+ def skipIfPerCoreTracingIsNotSupported(self):
+ def is_supported():
+ try:
+ with open("/proc/sys/kernel/perf_event_paranoid", "r") as permissions:
+ value = int(permissions.readlines()[0])
+ if value <= 0:
+ return True
+ except:
+ return False
+ if not is_supported():
+ self.skipTest("Per core tracing is not supported. You need "
+ "/proc/sys/kernel/perf_event_paranoid to be 0 or -1.")
+
def getTraceOrCreate(self):
if not self.target().GetTrace().IsValid():
error = lldb.SBError()
@@ -110,7 +123,7 @@
else:
self.expect("process trace stop")
- def traceStopThread(self, thread=None, error=False):
+ def traceStopThread(self, thread=None, error=False, substrs=None):
if self.USE_SB_API:
thread = thread if thread is not None else self.thread()
self.assertSBError(self.target().GetTrace().Stop(thread), error)
@@ -119,4 +132,4 @@
command = "thread trace stop"
if thread is not None:
command += " " + str(thread.GetIndexID())
- self.expect(command, error=error)
+ self.expect(command, error=error, substrs=substrs)
Index: lldb/include/lldb/lldb-types.h
===================================================================
--- lldb/include/lldb/lldb-types.h
+++ lldb/include/lldb/lldb-types.h
@@ -89,6 +89,7 @@
typedef int32_t watch_id_t;
typedef void *opaque_compiler_type_t;
typedef uint64_t queue_id_t;
+typedef int core_id_t; // CPU core id
} // namespace lldb
#endif // LLDB_LLDB_TYPES_H
Index: lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
===================================================================
--- lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
+++ lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
@@ -45,6 +45,8 @@
/// Whether to have a trace buffer per thread or per cpu core.
llvm::Optional<bool> per_core_tracing;
+
+ bool IsPerCoreTracing() const;
};
bool fromJSON(const llvm::json::Value &value, TraceIntelPTStartRequest &packet,
Index: lldb/include/lldb/Utility/TraceGDBRemotePackets.h
===================================================================
--- lldb/include/lldb/Utility/TraceGDBRemotePackets.h
+++ lldb/include/lldb/Utility/TraceGDBRemotePackets.h
@@ -109,7 +109,7 @@
struct TraceThreadState {
int64_t tid;
/// List of binary data objects for this thread.
- std::vector<TraceBinaryData> binaryData;
+ std::vector<TraceBinaryData> binary_data;
};
bool fromJSON(const llvm::json::Value &value, TraceThreadState &packet,
@@ -117,6 +117,17 @@
llvm::json::Value toJSON(const TraceThreadState &packet);
+struct TraceCoreState {
+ lldb::core_id_t core_id;
+ /// List of binary data objects for this core.
+ std::vector<TraceBinaryData> binary_data;
+};
+
+bool fromJSON(const llvm::json::Value &value, TraceCoreState &packet,
+ llvm::json::Path path);
+
+llvm::json::Value toJSON(const TraceCoreState &packet);
+
/// Interface for different algorithms used to convert trace
/// counters into different units.
template <typename ToType> class TraceCounterConversion {
@@ -143,8 +154,9 @@
std::unique_ptr<TraceCounterConversion<std::chrono::nanoseconds>>;
struct TraceGetStateResponse {
- std::vector<TraceThreadState> tracedThreads;
- std::vector<TraceBinaryData> processBinaryData;
+ std::vector<TraceThreadState> traced_threads;
+ std::vector<TraceBinaryData> process_binary_data;
+ llvm::Optional<std::vector<TraceCoreState>> cores;
};
bool fromJSON(const llvm::json::Value &value, TraceGetStateResponse &packet,
Index: lldb/docs/lldb-gdb-remote.txt
===================================================================
--- lldb/docs/lldb-gdb-remote.txt
+++ lldb/docs/lldb-gdb-remote.txt
@@ -369,8 +369,9 @@
// /* process tracing only */
// "processBufferSizeLimit": <decimal integer>,
// Maximum total buffer size per process in bytes.
-// This limit applies to the sum of the sizes of all trace buffers for
-// the current process, excluding the ones started with "thread tracing".
+// This limit applies to the sum of the sizes of all trace and core
+// buffers for the current process, excluding the ones started with
+// "thread tracing".
//
// If "perCoreTracing" is false, whenever a thread is attempted to be
// traced due to "process tracing" and the limit would be reached, the
@@ -481,6 +482,19 @@
// Size in bytes of this thread data.
// },
// ],
+// "cores"?: [
+// "id": <decimal integer>,
+// Identifier for this CPU logical core.
+// "binaryData": [
+// {
+// "kind": <string>,
+// Identifier for some binary data related to this thread to
+// fetch with the jLLDBTraceGetBinaryData packet.
+// "size": <decimal integer>,
+// Size in bytes of this cpu core data.
+// },
+// ]
+// ],
// "counters"?: {
// "info_kind": {...parameters specific to the provided counter info kind},
// Each entry includes information related to counters associated with the trace.
@@ -539,6 +553,8 @@
// Tracing technology name, e.g. intel-pt, arm-coresight.
// "kind": <string>,
// Identifier for the data.
+// "coreId": <Optional decimal>,
+// Core id in decimal if the data belongs to a CPU core.
// "tid"?: <Optional decimal>,
// Tid in decimal if the data belongs to a thread.
// "offset": <decimal>,
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits