wallace updated this revision to Diff 426737.
wallace added a comment.

nits


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,28 @@
         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"])
+
+        # 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,9 @@
 }
 
 Error IntelPTCollector::TraceStop(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);
   return m_thread_traces.TraceStop(tid);
 }
 
@@ -153,6 +158,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 +181,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 +221,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 +239,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 +292,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 +307,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()
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
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to