[Lldb-commits] [lldb] 1f49714 - [trace][intelpt] Support system-wide tracing [4] - Support per core tracing on lldb-server

Walter Erquinigo via lldb-commits lldb-commits at lists.llvm.org
Tue May 17 12:47:01 PDT 2022


Author: Walter Erquinigo
Date: 2022-05-17T12:46:54-07:00
New Revision: 1f49714d3e19502753fcea7ad8378a194222328f

URL: https://github.com/llvm/llvm-project/commit/1f49714d3e19502753fcea7ad8378a194222328f
DIFF: https://github.com/llvm/llvm-project/commit/1f49714d3e19502753fcea7ad8378a194222328f.diff

LOG: [trace][intelpt] Support system-wide tracing [4] - Support per core tracing on lldb-server

This diffs implements per-core tracing on lldb-server. It also includes tests that ensure that tracing can be initiated from the client and that the jLLDBGetState ppacket returns the list of trace buffers per core.

This doesn't include any decoder changes.

Finally, this makes some little changes here and there improving the existing code.

A specific piece of code that can't reliably be tested is when tracing
per core fails due to permissions. In this case we add a
troubleshooting message and this is the manual test:

```
/proc/sys/kernel/perf_event_paranoid set to 1

(lldb) process trace start --per-core-tracing                                         error: perf event syscall failed: Permission denied
 You might need that /proc/sys/kernel/perf_event_paranoid has a value of 0 or -1.
``

Differential Revision: https://reviews.llvm.org/D124858

Added: 
    lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.cpp
    lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.h

Modified: 
    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/IntelPTSingleBufferTrace.cpp
    lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.h
    lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
    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
    lldb/unittests/Process/Linux/ProcfsTests.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/docs/lldb-gdb-remote.txt b/lldb/docs/lldb-gdb-remote.txt
index 17e85a6d0df3f..a7b1803a92f02 100644
--- a/lldb/docs/lldb-gdb-remote.txt
+++ b/lldb/docs/lldb-gdb-remote.txt
@@ -245,7 +245,7 @@ read packet: OK
 //  OUTPUT SCHEMA
 //   {
 //     "name": <string>,
-//         Tracing technology name, e.g. intel-pt, arm-coresight.
+//         Tracing technology name, e.g. intel-pt, arm-etm.
 //     "description": <string>,
 //         Description for this technology.
 //   }
@@ -280,7 +280,7 @@ read packet: {"name":<name>, "description":<description>}/E<error code>;AAAAAAAA
 // INPUT SCHEMA
 //  {
 //    "type": <string>,
-//        Tracing technology name, e.g. intel-pt, arm-coresight.
+//        Tracing technology name, e.g. intel-pt, arm-etm.
 //
 //    /* thread tracing only */
 //    "tids"?: [<decimal integer>],
@@ -369,8 +369,9 @@ read packet: {"name":<name>, "description":<description>}/E<error code>;AAAAAAAA
 //     /* 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 thread or 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
@@ -421,7 +422,7 @@ read packet: OK/E<error code>;AAAAAAAAA
 //
 //  {
 //    "type": <string>
-//       Tracing technology name, e.g. intel-pt, arm-coresight.
+//       Tracing technology name, e.g. intel-pt, arm-etm.
 //
 //    /* thread trace stopping only */
 //    "tids":  [<decimal integer>]
@@ -455,7 +456,7 @@ read packet: OK/E<error code>;AAAAAAAAA
 // INPUT SCHEMA
 //  {
 //     "type": <string>
-//        Tracing technology name, e.g. intel-pt, arm-coresight.
+//        Tracing technology name, e.g. intel-pt, arm-etm.
 //  }
 //
 // OUTPUT SCHEMA
@@ -481,10 +482,23 @@ read packet: OK/E<error code>;AAAAAAAAA
 //            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.
-//          They are described below.
+//          Each entry includes information related to counters associated with
+//          the trace. They are described below.
 //    }
 //  }
 //
@@ -494,6 +508,12 @@ read packet: OK/E<error code>;AAAAAAAAA
 //
 // INTEL PT
 //
+//  If per-core process tracing is enabled, "tracedThreads" will contain all
+//  the threads of the process without any trace buffers. Besides that, the
+//  "cores" field will also be returned with per core trace buffers.
+//  A side effect of per-core tracing is that all the threads of unrelated
+//  processes will also be traced, thus polluting the tracing data.
+//
 //  Binary data kinds:
 //    - traceBuffer: trace buffer for a thread or a core.
 //    - procfsCpuInfo: contents of the /proc/cpuinfo file.
@@ -536,9 +556,11 @@ read packet: {...object}/E<error code>;AAAAAAAAA
 //
 //  {
 //   "type": <string>,
-//       Tracing technology name, e.g. intel-pt, arm-coresight.
+//       Tracing technology name, e.g. intel-pt, arm-etm.
 //   "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>,

diff  --git a/lldb/include/lldb/Utility/TraceGDBRemotePackets.h b/lldb/include/lldb/Utility/TraceGDBRemotePackets.h
index 8e8919c4d8d87..2f1cc872f687d 100644
--- a/lldb/include/lldb/Utility/TraceGDBRemotePackets.h
+++ b/lldb/include/lldb/Utility/TraceGDBRemotePackets.h
@@ -109,7 +109,7 @@ llvm::json::Value toJSON(const TraceBinaryData &packet);
 struct TraceThreadState {
   lldb::tid_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 @@ bool fromJSON(const llvm::json::Value &value, TraceThreadState &packet,
 
 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 
diff erent algorithms used to convert trace
 /// counters into 
diff erent units.
 template <typename ToType> class TraceCounterConversion {
@@ -143,8 +154,9 @@ using TraceTscConversionUP =
     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,

diff  --git a/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h b/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
index cb79fb351a438..788d8c7809de4 100644
--- a/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
+++ b/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
@@ -48,6 +48,8 @@ struct TraceIntelPTStartRequest : TraceStartRequest {
 
   /// 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,

diff  --git a/lldb/include/lldb/lldb-types.h b/lldb/include/lldb/lldb-types.h
index 976da35b11dd5..e6567926909fc 100644
--- a/lldb/include/lldb/lldb-types.h
+++ b/lldb/include/lldb/lldb-types.h
@@ -89,6 +89,7 @@ typedef int32_t break_id_t;
 typedef int32_t watch_id_t;
 typedef void *opaque_compiler_type_t;
 typedef uint64_t queue_id_t;
+typedef uint32_t core_id_t; // CPU core id
 } // namespace lldb
 
 #endif // LLDB_LLDB_TYPES_H

diff  --git a/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
index 9f1b6bab2f86b..dee428993a1b4 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
@@ -33,6 +33,19 @@ def setUp(self):
         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 @@ def traceStopProcess(self):
         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 @@ def traceStopThread(self, thread=None, error=False):
             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)

diff  --git a/lldb/source/Plugins/Process/Linux/CMakeLists.txt b/lldb/source/Plugins/Process/Linux/CMakeLists.txt
index fb249008146b2..5830a40721061 100644
--- a/lldb/source/Plugins/Process/Linux/CMakeLists.txt
+++ b/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

diff  --git a/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp b/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
index a1544680043f5..f986ec459082d 100644
--- a/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
+++ b/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
@@ -92,17 +92,21 @@ void IntelPTThreadTraceCollection::Clear() {
   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))
@@ -117,13 +121,14 @@ Error IntelPTProcessTrace::TraceStart(lldb::tid_t tid) {
 }
 
 const IntelPTThreadTraceCollection &
-IntelPTProcessTrace::GetThreadTraces() const {
+IntelPTPerThreadProcessTrace::GetThreadTraces() const {
   return m_thread_traces;
 }
 
 /// IntelPTCollector
 
-IntelPTCollector::IntelPTCollector() {
+IntelPTCollector::IntelPTCollector(NativeProcessProtocol &process)
+    : m_process(process) {
   if (Expected<LinuxPerfZeroTscConversion> tsc_conversion =
           LoadPerfTscConversionParameters())
     m_tsc_conversion =
@@ -134,8 +139,13 @@ IntelPTCollector::IntelPTCollector() {
 }
 
 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);
+  else 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);
 }
 
@@ -152,26 +162,60 @@ Error IntelPTCollector::TraceStop(const TraceStopRequest &request) {
   }
 }
 
-Error IntelPTCollector::TraceStart(
-    const TraceIntelPTStartRequest &request,
-    const std::vector<lldb::tid_t> &process_threads) {
+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) {
   if (request.IsProcessTracing()) {
     if (IsProcessTracingEnabled()) {
       return createStringError(
           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 {
+      std::vector<lldb::tid_t> process_threads;
+      for (size_t i = 0; m_process.GetThreadAtIndex(i); i++)
+        process_threads.push_back(m_process.GetThreadAtIndex(i)->GetID());
+
+      // 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),
@@ -181,14 +225,16 @@ Error IntelPTCollector::TraceStart(
 }
 
 Error IntelPTCollector::OnThreadCreated(lldb::tid_t tid) {
-  if (!IsProcessTracingEnabled())
-    return Error::success();
-  return m_process_trace->TraceStart(tid);
+  if (m_per_thread_process_trace_up)
+    return m_per_thread_process_trace_up->TraceStart(tid);
+
+  return Error::success();
 }
 
 Error IntelPTCollector::OnThreadDestroyed(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);
   else if (m_thread_traces.TracesThread(tid))
     return m_thread_traces.TraceStop(tid);
   return Error::success();
@@ -200,26 +246,42 @@ Expected<json::Value> IntelPTCollector::GetState() const {
     return cpu_info.takeError();
 
   TraceGetStateResponse state;
-  state.processBinaryData.push_back(
+  state.process_binary_data.push_back(
       {IntelPTDataKinds::kProcFsCpuInfo, 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());
+  } else 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(), {}});
+
+    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,
+                                    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 (m_per_thread_process_trace_up &&
+      m_per_thread_process_trace_up->TracesThread(tid))
+    return m_per_thread_process_trace_up->GetThreadTraces().GetTracedThread(
+        tid);
   return m_thread_traces.GetTracedThread(tid);
 }
 
@@ -239,7 +301,10 @@ IntelPTCollector::GetBinaryData(const TraceGetBinaryDataRequest &request) const
                            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()) {
@@ -251,7 +316,8 @@ bool IntelPTCollector::IsSupported() {
 }
 
 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() {

diff  --git a/lldb/source/Plugins/Process/Linux/IntelPTCollector.h b/lldb/source/Plugins/Process/Linux/IntelPTCollector.h
index e78a7aa9d07b0..6125d335931b3 100644
--- a/lldb/source/Plugins/Process/Linux/IntelPTCollector.h
+++ b/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,8 +11,10 @@
 
 #include "Perf.h"
 
+#include "IntelPTMultiCoreTrace.h"
 #include "IntelPTSingleBufferTrace.h"
 
+#include "lldb/Host/common/NativeProcessProtocol.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
 #include "lldb/lldb-types.h"
@@ -47,17 +49,37 @@ class IntelPTThreadTraceCollection {
 
   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 +90,9 @@ class IntelPTProcessTrace {
   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;
@@ -76,7 +101,9 @@ class IntelPTProcessTrace {
 /// Main class that manages intel-pt process and thread tracing.
 class IntelPTCollector {
 public:
-  IntelPTCollector();
+  /// \param[in] process
+  ///     Process to be traced.
+  IntelPTCollector(NativeProcessProtocol &process);
 
   static bool IsSupported();
 
@@ -90,11 +117,7 @@ class IntelPTCollector {
   llvm::Error TraceStop(const TraceStopRequest &request);
 
   /// Implementation of the jLLDBTraceStart packet
-  ///
-  /// \param[in] process_threads
-  ///     A list of all threads owned by the process.
-  llvm::Error TraceStart(const TraceIntelPTStartRequest &request,
-                         const std::vector<lldb::tid_t> &process_threads);
+  llvm::Error TraceStart(const TraceIntelPTStartRequest &request);
 
   /// Implementation of the jLLDBTraceGetState packet
   llvm::Expected<llvm::json::Value> GetState() const;
@@ -120,11 +143,21 @@ class IntelPTCollector {
 
   void ClearProcessTracing();
 
+  NativeProcessProtocol &m_process;
   /// 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;
+
+  /// Only one of the following "process tracing" handlers can be active at a
+  /// given time.
+  ///
+  /// \{
+  /// Threads traced due to per-thread "process tracing".  This might be \b
+  /// nullptr.
+  IntelPTPerThreadProcessTraceUP m_per_thread_process_trace_up;
+  /// Cores traced due to per-core "process tracing".  This might be \b nullptr.
+  IntelPTMultiCoreTraceUP m_per_core_process_trace_up;
+  /// \}
+
   /// TSC to wall time conversion.
   TraceTscConversionUP m_tsc_conversion;
 };

diff  --git a/lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.cpp b/lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.cpp
new file mode 100644
index 0000000000000..3762179496c3a
--- /dev/null
+++ b/lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.cpp
@@ -0,0 +1,64 @@
+//===-- 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) {
+  uint64_t required = cores.size() * request.trace_buffer_size;
+  uint64_t limit = request.process_buffer_size_limit.getValueOr(
+      std::numeric_limits<uint64_t>::max());
+  return required > limit;
+}
+
+static Error IncludePerfEventParanoidMessageInError(Error &&error) {
+  return createStringError(
+      inconvertibleErrorCode(),
+      "%s\nYou might need to rerun as sudo or to set "
+      "/proc/sys/kernel/perf_event_paranoid to a value of 0 or -1.",
+      toString(std::move(error)).c_str());
+}
+
+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);
+}

diff  --git a/lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.h b/lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.h
new file mode 100644
index 0000000000000..5aaea4d0b341d
--- /dev/null
+++ b/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_

diff  --git a/lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.cpp b/lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.cpp
index 18c69d13700d5..b86c28bf10485 100644
--- a/lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.cpp
+++ b/lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.cpp
@@ -260,14 +260,16 @@ IntelPTSingleBufferTrace::GetTraceBuffer(size_t offset, size_t size) const {
 
 Expected<IntelPTSingleBufferTraceUP>
 IntelPTSingleBufferTrace::Start(const TraceIntelPTStartRequest &request,
-                                lldb::tid_t tid) {
+                                Optional<lldb::tid_t> tid,
+                                Optional<core_id_t> core_id) {
 #ifndef PERF_ATTR_SIZE_VER5
   return createStringError(inconvertibleErrorCode(),
                            "Intel PT Linux perf event not supported");
 #else
   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) {
@@ -291,13 +293,13 @@ IntelPTSingleBufferTrace::Start(const TraceIntelPTStartRequest &request,
   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();
   }

diff  --git a/lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.h b/lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.h
index ada8c3b72dea6..7613c5408ade3 100644
--- a/lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.h
+++ b/lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.h
@@ -23,10 +23,8 @@ namespace process_linux {
 
 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 @@ class IntelPTSingleBufferTrace {
   ///     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 @@ class IntelPTSingleBufferTrace {
   ///
   /// \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.

diff  --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index 78d1b3a8e835f..37da1f12421a5 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -312,7 +312,7 @@ NativeProcessLinux::NativeProcessLinux(::pid_t pid, int terminal_fd,
                                        const ArchSpec &arch, MainLoop &mainloop,
                                        llvm::ArrayRef<::pid_t> tids)
     : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch),
-      m_main_loop(mainloop) {
+      m_main_loop(mainloop), m_intel_pt_collector(*this) {
   if (m_terminal_fd != -1) {
     Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
     assert(status.Success());
@@ -1967,10 +1967,7 @@ Error NativeProcessLinux::TraceStart(StringRef json_request, StringRef type) {
     if (Expected<TraceIntelPTStartRequest> request =
             json::parse<TraceIntelPTStartRequest>(json_request,
                                                   "TraceIntelPTStartRequest")) {
-      std::vector<lldb::tid_t> process_threads;
-      for (auto &thread : m_threads)
-        process_threads.push_back(thread->GetID());
-      return m_intel_pt_collector.TraceStart(*request, process_threads);
+      return m_intel_pt_collector.TraceStart(*request);
     } else
       return request.takeError();
   }

diff  --git a/lldb/source/Plugins/Process/Linux/Perf.cpp b/lldb/source/Plugins/Process/Linux/Perf.cpp
index d1691a9d7d228..89f14a5bb41da 100644
--- a/lldb/source/Plugins/Process/Linux/Perf.cpp
+++ b/lldb/source/Plugins/Process/Linux/Perf.cpp
@@ -117,10 +117,13 @@ void resource_handle::FileDescriptorDeleter::operator()(long *ptr) {
 }
 
 llvm::Expected<PerfEvent> PerfEvent::Init(perf_event_attr &attr,
-                                          lldb::pid_t pid, int cpu,
-                                          int group_fd, unsigned long flags) {
+                                          Optional<lldb::pid_t> pid,
+                                          Optional<lldb::core_id_t> cpu,
+                                          Optional<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.getValueOr(-1), flags);
   if (fd == -1) {
     std::string err_msg =
         llvm::formatv("perf event syscall failed: {0}", std::strerror(errno));
@@ -130,8 +133,9 @@ llvm::Expected<PerfEvent> PerfEvent::Init(perf_event_attr &attr,
 }
 
 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>

diff  --git a/lldb/source/Plugins/Process/Linux/Perf.h b/lldb/source/Plugins/Process/Linux/Perf.h
index d8fab93995c6e..ea7bea5277ff7 100644
--- a/lldb/source/Plugins/Process/Linux/Perf.h
+++ b/lldb/source/Plugins/Process/Linux/Perf.h
@@ -109,13 +109,16 @@ class PerfEvent {
   ///     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. If \b None, then
+  ///     all processes and threads are monitored.
   ///
   /// \param[in] cpu
-  ///     The cpu to be monitored by the event.
+  ///     The cpu to be monitored by the event. If \b None, then all cpus are
+  ///     monitored.
   ///
   /// \param[in] group_fd
-  ///     File descriptor of the group leader.
+  ///     File descriptor of the group leader. If \b None, then this perf_event
+  ///     doesn't belong to a preexisting group.
   ///
   /// \param[in] flags
   ///     Bitmask of additional configuration flags.
@@ -123,8 +126,10 @@ class PerfEvent {
   /// \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,
+  static llvm::Expected<PerfEvent> Init(perf_event_attr &attr,
+                                        llvm::Optional<lldb::pid_t> pid,
+                                        llvm::Optional<lldb::core_id_t> cpu,
+                                        llvm::Optional<int> group_fd,
                                         unsigned long flags);
 
   /// Create a new performance monitoring event via the perf_event_open syscall
@@ -137,8 +142,11 @@ class PerfEvent {
   ///     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. If \b None, then
+  ///     all threads and processes are monitored.
+  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

diff  --git a/lldb/source/Plugins/Process/Linux/Procfs.cpp b/lldb/source/Plugins/Process/Linux/Procfs.cpp
index 756749e0a7e32..bca0f1070f839 100644
--- a/lldb/source/Plugins/Process/Linux/Procfs.cpp
+++ b/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 @@ Expected<ArrayRef<uint8_t>> lldb_private::process_linux::GetProcfsCpuInfo() {
   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,17 +52,17 @@ lldb_private::process_linux::GetAvailableLogicalCoreIDs(StringRef cpuinfo) {
   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(StringRef(
-        reinterpret_cast<const char *>(cpuinfo->data()), cpuinfo->size()));
+    Expected<std::vector<core_id_t>> core_ids = GetAvailableLogicalCoreIDs(
+        StringRef(reinterpret_cast<const char *>(cpuinfo->data())));
     if (!core_ids)
       return core_ids.takeError();
 

diff  --git a/lldb/source/Plugins/Process/Linux/Procfs.h b/lldb/source/Plugins/Process/Linux/Procfs.h
index 297fafe7ccd5e..ee45b25a5529e 100644
--- a/lldb/source/Plugins/Process/Linux/Procfs.h
+++ b/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,13 +45,13 @@ llvm::Expected<llvm::ArrayRef<uint8_t>> GetProcfsCpuInfo();
 /// \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
 ///     A list with all the logical cores available in the system and cache it
 ///     if errors didn't happen.
-llvm::Expected<llvm::ArrayRef<int>> GetAvailableLogicalCoreIDs();
+llvm::Expected<llvm::ArrayRef<lldb::core_id_t>> GetAvailableLogicalCoreIDs();
 
 } // namespace process_linux
 } // namespace lldb_private

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
index 9c1412c16acd9..036333ddd859c 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -252,7 +252,7 @@ void TraceIntelPT::DoRefreshLiveProcessState(
     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(
@@ -354,9 +354,9 @@ llvm::Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
 
 Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
                           StructuredData::ObjectSP configuration) {
-  size_t trace_buffer_size = kDefaultTraceBufferSize;
+  uint64_t trace_buffer_size = kDefaultTraceBufferSize;
   bool enable_tsc = kDefaultEnableTscValue;
-  Optional<size_t> psb_period = kDefaultPsbPeriod;
+  Optional<uint64_t> psb_period = kDefaultPsbPeriod;
 
   if (configuration) {
     if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
index 2583f8f4b2f4a..1cc41ac9198c9 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
@@ -57,8 +57,8 @@ let Command = "process trace start intel pt" in {
     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 "

diff  --git a/lldb/source/Target/Trace.cpp b/lldb/source/Target/Trace.cpp
index fba1b94a03014..5d0920420cf7b 100644
--- a/lldb/source/Target/Trace.cpp
+++ b/lldb/source/Target/Trace.cpp
@@ -199,12 +199,12 @@ void Trace::RefreshLiveProcessState() {
   }
 
   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));

diff  --git a/lldb/source/Utility/TraceGDBRemotePackets.cpp b/lldb/source/Utility/TraceGDBRemotePackets.cpp
index b8ac71be51357..9f92da34f7e69 100644
--- a/lldb/source/Utility/TraceGDBRemotePackets.cpp
+++ b/lldb/source/Utility/TraceGDBRemotePackets.cpp
@@ -87,24 +87,42 @@ json::Value toJSON(const TraceBinaryData &packet) {
 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", packet.core_id}, {"binaryData", packet.binary_data}});
 }
 /// \}
 

diff  --git a/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp b/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
index 27f1d4c6229b7..aff77fddc4242 100644
--- a/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
+++ b/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
@@ -16,6 +16,10 @@ namespace lldb_private {
 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);

diff  --git a/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py b/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py
index 6bfe83192bd58..33177ca5ff01f 100644
--- a/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py
+++ b/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py
@@ -30,6 +30,8 @@ def testStartMultipleLiveThreads(self):
         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 @@ def testStartMultipleLiveThreadsWithStops(self):
 
         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 @@ def testStartMultipleLiveThreadsWithStops(self):
         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 @@ def testStartMultipleLiveThreadsWithSmallTotalLimit(self):
     @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 @@ def testStartPerCoreSession(self):
         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 and at least one traced thread
+        self.expect("""process plugin packet send 'jLLDBTraceGetState:{"type":"intel-pt"}]'""",
+            substrs=['''[{"kind":"traceBuffer","size":4096}],"coreId":''', '"tid":'])
+
+        self.traceStopProcess()

diff  --git a/lldb/unittests/Process/Linux/ProcfsTests.cpp b/lldb/unittests/Process/Linux/ProcfsTests.cpp
index f619234ea5bb0..e11ef728449d9 100644
--- a/lldb/unittests/Process/Linux/ProcfsTests.cpp
+++ b/lldb/unittests/Process/Linux/ProcfsTests.cpp
@@ -18,7 +18,7 @@ using namespace process_linux;
 using namespace llvm;
 
 TEST(Perf, HardcodedLogicalCoreIDs) {
-  Expected<std::vector<int>> core_ids =
+  Expected<std::vector<lldb::core_id_t>> core_ids =
       GetAvailableLogicalCoreIDs(R"(processor       : 13
 vendor_id       : GenuineIntel
 cpu family      : 6
@@ -98,7 +98,7 @@ TEST(Perf, RealLogicalCoreIDs) {
     GTEST_SKIP() << toString(buffer_or_error.takeError());
 
   // At this point we shouldn't fail parsing the core ids
-  Expected<ArrayRef<int>> core_ids = GetAvailableLogicalCoreIDs();
+  Expected<ArrayRef<lldb::core_id_t>> core_ids = GetAvailableLogicalCoreIDs();
   ASSERT_TRUE((bool)core_ids);
   ASSERT_GT((int)core_ids->size(), 0) << "We must see at least one core";
 }


        


More information about the lldb-commits mailing list