[Lldb-commits] [lldb] b8d1776 - [trace][intelpt] Support system-wide tracing [2] - Add a dummy --per-core-tracing option

Walter Erquinigo via lldb-commits lldb-commits at lists.llvm.org
Mon May 9 16:05:34 PDT 2022


Author: Walter Erquinigo
Date: 2022-05-09T16:05:26-07:00
New Revision: b8d1776fc58d56af30d446386788e377d25dd512

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

LOG: [trace][intelpt] Support system-wide tracing [2] - Add a dummy --per-core-tracing option

This updates the documentation of the gdb-remote protocol, as well as the help messages, to include the new --per-core-tracing option.

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

Added: 
    

Modified: 
    lldb/docs/lldb-gdb-remote.txt
    lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
    lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
    lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
    lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp
    lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
    lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
    lldb/test/API/commands/trace/TestTraceStartStop.py
    lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py

Removed: 
    


################################################################################
diff  --git a/lldb/docs/lldb-gdb-remote.txt b/lldb/docs/lldb-gdb-remote.txt
index 545fbb46ae242..50a47ccf50bfb 100644
--- a/lldb/docs/lldb-gdb-remote.txt
+++ b/lldb/docs/lldb-gdb-remote.txt
@@ -283,7 +283,7 @@ read packet: {"name":<name>, "description":<description>}/E<error code>;AAAAAAAA
 //        Tracing technology name, e.g. intel-pt, arm-coresight.
 //
 //    /* thread tracing only */
-//    "tids": [<decimal integer>],
+//    "tids"?: [<decimal integer>],
 //        Individual threads to trace.
 //
 //    ... other parameters specific to the provided tracing type
@@ -298,16 +298,25 @@ read packet: {"name":<name>, "description":<description>}/E<error code>;AAAAAAAA
 // INTEL-PT
 //  intel-pt supports both "thread tracing" and "process tracing".
 //
-//  "Process tracing" is implemented by tracing each thread individually, but
-//  managed by the same "process trace" instance.
-//  Each actual thread trace, either from "process tracing" or "thread tracing",
+//  "Process tracing" is implemented in two 
diff erent ways. If the
+//  "perCoreTracing" option is false, then each thread is traced individually
+//  but managed by the same "process trace" instance. This means that the
+//  amount of trace buffers used is proportional to the number of running
+//  threads. This is the recommended option unless the number of threads is
+//  huge. If "perCoreTracing" is true, then each cpu core is traced invidually
+//  instead of each thread, which uses a fixed number of trace buffers, but
+//  might result in less data available for less frequent threads. See
+//  "perCoreTracing" below for more information.
+//
+//  Each actual trace buffer, either from "process tracing" or "thread tracing",
 //  is stored in an in-memory circular buffer, which keeps the most recent data.
 //
 //  Additional params in the input schema:
 //   {
-//     "threadBufferSize": <decimal integer>,
-//         Trace buffer size per thread in bytes. It must be a power of 2
-//         greater than or equal to 4096 (2^12) bytes.
+//     "traceBufferSize": <decimal integer>,
+//         Size in bytes used by each individual per-thread or per-core trace
+//         buffer. It must be a power of 2 greater than or equal to 4096 (2^12)
+//         bytes.
 //
 //     "enableTsc": <boolean>,
 //         Whether to enable TSC timestamps or not. This is supported on
@@ -342,15 +351,35 @@ read packet: {"name":<name>, "description":<description>}/E<error code>;AAAAAAAA
 //          0 if supported.
 //
 //     /* process tracing only */
+//     "perCoreTracing": <boolean>
+//         Instead of having an individual trace buffer per thread, this option
+//         triggers the collection on a per cpu core basis. This effectively
+//         traces the entire activity on all cores. At decoding time, in order
+//         to correctly associate a decoded instruction with a thread, the
+//         context switch trace of each core is needed, as well as a record per
+//         cpu indicating which thread was running on each core when tracing
+//         started. These secondary traces are correlated with the intel-pt
+//         trace by comparing TSC timestamps.
+//
+//         This option forces the capture of TSC timestamps (see "enableTsc").
+//
+//         Note: This option can't be used simulatenously with any other trace
+//         sessions because of its system-wide nature.
+//
+//     /* 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".
 //
-//         Whenever a thread is attempted to be traced due to "process tracing"
-//         and the limit would be reached, the process is stopped with a
-//         "tracing" reason along with a meaningful description, so that the
-//         user can retrace the process if needed.
+//         If "perCoreTracing" is false, whenever a thread is attempted to be
+//         traced due to "process tracing" and the limit would be reached, the
+//         process is stopped with a "tracing" reason along with a meaningful
+//         description, so that the user can retrace the process if needed.
+//
+//         If "perCoreTracing" is true, then starting the system-wide trace
+//         session fails if all the individual per-core trace buffers require
+//         in total more memory that the limit impossed by this parameter.
 //   }
 //
 //  Notes:

diff  --git a/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h b/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
index 294b0205af452..d331b18c4ae70 100644
--- a/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
+++ b/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
@@ -28,20 +28,23 @@ struct IntelPTDataKinds {
 /// \{
 struct TraceIntelPTStartRequest : TraceStartRequest {
   /// Size in bytes to use for each thread's trace buffer.
-  int64_t threadBufferSize;
+  int64_t trace_buffer_size;
 
   /// Whether to enable TSC
-  bool enableTsc;
+  bool enable_tsc;
 
   /// PSB packet period
-  llvm::Optional<int64_t> psbPeriod;
+  llvm::Optional<int64_t> psb_period;
 
   /// Required when doing "process tracing".
   ///
   /// Limit in bytes on all the thread traces started by this "process trace"
   /// instance. When a thread is about to be traced and the limit would be hit,
   /// then a "tracing" stop event is triggered.
-  llvm::Optional<int64_t> processBufferSizeLimit;
+  llvm::Optional<int64_t> process_buffer_size_limit;
+
+  /// Whether to have a trace buffer per thread or per cpu core.
+  llvm::Optional<bool> per_core_tracing;
 };
 
 bool fromJSON(const llvm::json::Value &value, TraceIntelPTStartRequest &packet,

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 a2f63bc88bd10..9f1b6bab2f86b 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py
@@ -45,37 +45,38 @@ def assertSBError(self, sberror, error=False):
         else:
             self.assertSuccess(sberror)
 
-    def createConfiguration(self, threadBufferSize=None,
+    def createConfiguration(self, traceBufferSize=None,
                             processBufferSizeLimit=None, enableTsc=False,
-                            psbPeriod=None):
+                            psbPeriod=None, perCoreTracing=False):
         obj = {}
         if processBufferSizeLimit is not None:
             obj["processBufferSizeLimit"] = processBufferSizeLimit
-        if threadBufferSize is not None:
-            obj["threadBufferSize"] = threadBufferSize
+        if traceBufferSize is not None:
+            obj["traceBufferSize"] = traceBufferSize
         if psbPeriod is not None:
             obj["psbPeriod"] = psbPeriod
         obj["enableTsc"] = enableTsc
+        obj["perCoreTracing"] = perCoreTracing
 
         configuration = lldb.SBStructuredData()
         configuration.SetFromJSON(json.dumps(obj))
         return configuration
 
     def traceStartThread(self, thread=None, error=False, substrs=None,
-                         threadBufferSize=None, enableTsc=False, psbPeriod=None):
+                         traceBufferSize=None, enableTsc=False, psbPeriod=None):
         if self.USE_SB_API:
             trace = self.getTraceOrCreate()
             thread = thread if thread is not None else self.thread()
             configuration = self.createConfiguration(
-                threadBufferSize=threadBufferSize, enableTsc=enableTsc,
+                traceBufferSize=traceBufferSize, enableTsc=enableTsc,
                 psbPeriod=psbPeriod)
             self.assertSBError(trace.Start(thread, configuration), error)
         else:
             command = "thread trace start"
             if thread is not None:
                 command += " " + str(thread.GetIndexID())
-            if threadBufferSize is not None:
-                command += " -s " + str(threadBufferSize)
+            if traceBufferSize is not None:
+                command += " -s " + str(traceBufferSize)
             if enableTsc:
                 command += " --tsc"
             if psbPeriod is not None:
@@ -83,12 +84,13 @@ def traceStartThread(self, thread=None, error=False, substrs=None,
             self.expect(command, error=error, substrs=substrs)
 
     def traceStartProcess(self, processBufferSizeLimit=None, error=False,
-                          substrs=None, enableTsc=False, psbPeriod=None):
+                          substrs=None, enableTsc=False, psbPeriod=None,
+                          perCoreTracing=False):
         if self.USE_SB_API:
             trace = self.getTraceOrCreate()
             configuration = self.createConfiguration(
                 processBufferSizeLimit=processBufferSizeLimit, enableTsc=enableTsc,
-                psbPeriod=psbPeriod)
+                psbPeriod=psbPeriod, perCoreTracing=perCoreTracing)
             self.assertSBError(trace.Start(configuration), error=error)
         else:
             command = "process trace start"
@@ -98,6 +100,8 @@ def traceStartProcess(self, processBufferSizeLimit=None, error=False,
                 command += " --tsc"
             if psbPeriod is not None:
                 command += " --psb-period " + str(psbPeriod)
+            if perCoreTracing:
+                command += " --per-core-tracing"
             self.expect(command, error=error, substrs=substrs)
 
     def traceStopProcess(self):

diff  --git a/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp b/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
index e2303b37eb883..bcb270c9fae74 100644
--- a/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
+++ b/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
@@ -443,8 +443,8 @@ Error IntelPTThreadTraceCollection::TraceStart(
                              "Thread %" PRIu64 " already traced", tid);
 
   Expected<IntelPTThreadTraceUP> trace_up = IntelPTThreadTrace::Create(
-      m_pid, tid, request.threadBufferSize, request.enableTsc,
-      request.psbPeriod.map([](int64_t period) { return (size_t)period; }));
+      m_pid, tid, request.trace_buffer_size, request.enable_tsc,
+      request.psb_period.map([](int64_t period) { return (size_t)period; }));
   if (!trace_up)
     return trace_up.takeError();
 
@@ -490,8 +490,9 @@ Error IntelPTProcessTrace::TraceStop(lldb::tid_t tid) {
 }
 
 Error IntelPTProcessTrace::TraceStart(lldb::tid_t tid) {
-  if (m_thread_traces.GetTotalBufferSize() + m_tracing_params.threadBufferSize >
-      static_cast<size_t>(*m_tracing_params.processBufferSizeLimit))
+  if (m_thread_traces.GetTotalBufferSize() +
+          m_tracing_params.trace_buffer_size >
+      static_cast<size_t>(*m_tracing_params.process_buffer_size_limit))
     return createStringError(
         inconvertibleErrorCode(),
         "Thread %" PRIu64 " can't be traced as the process trace size limit "
@@ -548,6 +549,10 @@ Error IntelPTCollector::TraceStart(
           inconvertibleErrorCode(),
           "Process currently traced. Stop process tracing first");
     }
+    if (request.per_core_tracing.getValueOr(false)) {
+      return createStringError(inconvertibleErrorCode(),
+                               "Per-core tracing is not supported.");
+    }
     m_process_trace = IntelPTProcessTrace(m_pid, request);
 
     Error error = Error::success();

diff  --git a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp
index 5650af657c5e4..bd3017f8f09be 100644
--- a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp
@@ -32,13 +32,13 @@ Status CommandObjectThreadTraceStartIntelPT::CommandOptions::SetOptionValue(
 
   switch (short_option) {
   case 's': {
-    int64_t thread_buffer_size;
-    if (option_arg.empty() || option_arg.getAsInteger(0, thread_buffer_size) ||
-        thread_buffer_size < 0)
+    int64_t trace_buffer_size;
+    if (option_arg.empty() || option_arg.getAsInteger(0, trace_buffer_size) ||
+        trace_buffer_size < 0)
       error.SetErrorStringWithFormat("invalid integer value for option '%s'",
                                      option_arg.str().c_str());
     else
-      m_thread_buffer_size = thread_buffer_size;
+      m_trace_buffer_size = trace_buffer_size;
     break;
   }
   case 't': {
@@ -63,7 +63,7 @@ Status CommandObjectThreadTraceStartIntelPT::CommandOptions::SetOptionValue(
 
 void CommandObjectThreadTraceStartIntelPT::CommandOptions::
     OptionParsingStarting(ExecutionContext *execution_context) {
-  m_thread_buffer_size = kDefaultThreadBufferSize;
+  m_trace_buffer_size = kDefaultTraceBufferSize;
   m_enable_tsc = kDefaultEnableTscValue;
   m_psb_period = kDefaultPsbPeriod;
 }
@@ -76,7 +76,7 @@ CommandObjectThreadTraceStartIntelPT::CommandOptions::GetDefinitions() {
 bool CommandObjectThreadTraceStartIntelPT::DoExecuteOnThreads(
     Args &command, CommandReturnObject &result,
     llvm::ArrayRef<lldb::tid_t> tids) {
-  if (Error err = m_trace.Start(tids, m_options.m_thread_buffer_size,
+  if (Error err = m_trace.Start(tids, m_options.m_trace_buffer_size,
                                 m_options.m_enable_tsc, m_options.m_psb_period))
     result.SetError(Status(std::move(err)));
   else
@@ -98,13 +98,13 @@ Status CommandObjectProcessTraceStartIntelPT::CommandOptions::SetOptionValue(
 
   switch (short_option) {
   case 's': {
-    int64_t thread_buffer_size;
-    if (option_arg.empty() || option_arg.getAsInteger(0, thread_buffer_size) ||
-        thread_buffer_size < 0)
+    int64_t trace_buffer_size;
+    if (option_arg.empty() || option_arg.getAsInteger(0, trace_buffer_size) ||
+        trace_buffer_size < 0)
       error.SetErrorStringWithFormat("invalid integer value for option '%s'",
                                      option_arg.str().c_str());
     else
-      m_thread_buffer_size = thread_buffer_size;
+      m_trace_buffer_size = trace_buffer_size;
     break;
   }
   case 'l': {
@@ -122,6 +122,10 @@ Status CommandObjectProcessTraceStartIntelPT::CommandOptions::SetOptionValue(
     m_enable_tsc = true;
     break;
   }
+  case 'c': {
+    m_per_core_tracing = true;
+    break;
+  }
   case 'p': {
     int64_t psb_period;
     if (option_arg.empty() || option_arg.getAsInteger(0, psb_period) ||
@@ -140,10 +144,11 @@ Status CommandObjectProcessTraceStartIntelPT::CommandOptions::SetOptionValue(
 
 void CommandObjectProcessTraceStartIntelPT::CommandOptions::
     OptionParsingStarting(ExecutionContext *execution_context) {
-  m_thread_buffer_size = kDefaultThreadBufferSize;
+  m_trace_buffer_size = kDefaultTraceBufferSize;
   m_process_buffer_size_limit = kDefaultProcessBufferSizeLimit;
   m_enable_tsc = kDefaultEnableTscValue;
   m_psb_period = kDefaultPsbPeriod;
+  m_per_core_tracing = kDefaultPerCoreTracing;
 }
 
 llvm::ArrayRef<OptionDefinition>
@@ -153,9 +158,10 @@ CommandObjectProcessTraceStartIntelPT::CommandOptions::GetDefinitions() {
 
 bool CommandObjectProcessTraceStartIntelPT::DoExecute(
     Args &command, CommandReturnObject &result) {
-  if (Error err = m_trace.Start(m_options.m_thread_buffer_size,
+  if (Error err = m_trace.Start(m_options.m_trace_buffer_size,
                                 m_options.m_process_buffer_size_limit,
-                                m_options.m_enable_tsc, m_options.m_psb_period))
+                                m_options.m_enable_tsc, m_options.m_psb_period,
+                                m_options.m_per_core_tracing))
     result.SetError(Status(std::move(err)));
   else
     result.SetStatus(eReturnStatusSuccessFinishResult);

diff  --git a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h
index 2f3d53a864067..bb505905e1548 100644
--- a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h
+++ b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h
@@ -31,7 +31,7 @@ class CommandObjectThreadTraceStartIntelPT
 
     llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
 
-    size_t m_thread_buffer_size;
+    size_t m_trace_buffer_size;
     bool m_enable_tsc;
     llvm::Optional<size_t> m_psb_period;
   };
@@ -74,10 +74,11 @@ class CommandObjectProcessTraceStartIntelPT : public CommandObjectParsed {
 
     llvm::ArrayRef<OptionDefinition> GetDefinitions() override;
 
-    size_t m_thread_buffer_size;
+    size_t m_trace_buffer_size;
     size_t m_process_buffer_size_limit;
     bool m_enable_tsc;
     llvm::Optional<size_t> m_psb_period;
+    bool m_per_core_tracing;
   };
 
   CommandObjectProcessTraceStartIntelPT(TraceIntelPT &trace,
@@ -85,10 +86,14 @@ class CommandObjectProcessTraceStartIntelPT : public CommandObjectParsed {
       : CommandObjectParsed(
             interpreter, "process trace start",
             "Start tracing this process with intel-pt, including future "
-            "threads. "
-            "This is implemented by tracing each thread independently. "
+            "threads. If --per-core-tracing is not provided, this traces each "
+            "thread independently, thus using a trace buffer per thread. "
             "Threads traced with the \"thread trace start\" command are left "
-            "unaffected ant not retraced.",
+            "unaffected ant not retraced. This is the recommended option "
+            "unless the number of threads is huge. If --per-core-tracing is "
+            "passed, each cpu core is traced instead of each thread, which "
+            "uses a fixed number of trace buffers, but might result in less "
+            "data available for less frequent threads.",
             "process trace start [<intel-pt-options>]",
             lldb::eCommandRequiresProcess | lldb::eCommandTryTargetAPILock |
                 lldb::eCommandProcessMustBeLaunched |

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
index 394963a263084..9bd1e3c605a17 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -271,101 +271,79 @@ bool TraceIntelPT::IsTraced(lldb::tid_t tid) {
 // documentation file. Similarly, it should match the CLI help messages of the
 // TraceIntelPTOptions.td file.
 const char *TraceIntelPT::GetStartConfigurationHelp() {
-  return R"(Parameters:
+  static Optional<std::string> message;
+  if (!message) {
+    message.emplace(formatv(R"(Parameters:
 
-  Note: If a parameter is not specified, a default value will be used.
+  See the jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt for a
+  description of each parameter below.
 
-  - int threadBufferSize (defaults to 4096 bytes):
+  - int traceBufferSize (defaults to {0} bytes):
     [process and thread tracing]
-    Trace size in bytes per thread. It must be a power of 2 greater
-    than or equal to 4096 (2^12). The trace is circular keeping the
-    the most recent data.
 
-  - boolean enableTsc (default to false):
+  - boolean enableTsc (default to {1}):
     [process and thread tracing]
-    Whether to use enable TSC timestamps or not. This is supported on
-    all devices that support intel-pt.
 
-  - psbPeriod (defaults to null):
+  - int psbPeriod (defaults to {2}):
     [process and thread tracing]
-    This value defines the period in which PSB packets will be generated.
-    A PSB packet is a synchronization packet that contains a TSC
-    timestamp and the current absolute instruction pointer.
 
-    This parameter can only be used if
-
-        /sys/bus/event_source/devices/intel_pt/caps/psb_cyc
-
-    is 1. Otherwise, the PSB period will be defined by the processor.
-
-    If supported, valid values for this period can be found in
-
-        /sys/bus/event_source/devices/intel_pt/caps/psb_periods
-
-    which contains a hexadecimal number, whose bits represent
-    valid values e.g. if bit 2 is set, then value 2 is valid.
-
-    The psb_period value is converted to the approximate number of
-    raw trace bytes between PSB packets as:
-
-        2 ^ (value + 11)
-
-    e.g. value 3 means 16KiB between PSB packets. Defaults to 0 if
-    supported.
-
-  - int processBufferSizeLimit (defaults to 500 MB):
+  - boolean perCoreTracing (default to {3}):
     [process tracing only]
-    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 explicitly with "thread tracing".
-    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
-    if needed.)";
+
+  - int processBufferSizeLimit (defaults to {4} MiB):
+    [process tracing only])",
+                            kDefaultTraceBufferSize, kDefaultEnableTscValue,
+                            kDefaultPsbPeriod, kDefaultPerCoreTracing,
+                            kDefaultProcessBufferSizeLimit / 1024 / 1024));
+  }
+  return message->c_str();
 }
 
-Error TraceIntelPT::Start(size_t thread_buffer_size,
+Error TraceIntelPT::Start(size_t trace_buffer_size,
                           size_t total_buffer_size_limit, bool enable_tsc,
-                          Optional<size_t> psb_period) {
+                          Optional<size_t> psb_period, bool per_core_tracing) {
   TraceIntelPTStartRequest request;
-  request.threadBufferSize = thread_buffer_size;
-  request.processBufferSizeLimit = total_buffer_size_limit;
-  request.enableTsc = enable_tsc;
-  request.psbPeriod = psb_period.map([](size_t val) { return (int64_t)val; });
+  request.trace_buffer_size = trace_buffer_size;
+  request.process_buffer_size_limit = total_buffer_size_limit;
+  request.enable_tsc = enable_tsc;
+  request.psb_period = psb_period.map([](size_t val) { return (int64_t)val; });
   request.type = GetPluginName().str();
+  request.per_core_tracing = per_core_tracing;
   return Trace::Start(toJSON(request));
 }
 
 Error TraceIntelPT::Start(StructuredData::ObjectSP configuration) {
-  size_t thread_buffer_size = kDefaultThreadBufferSize;
+  size_t trace_buffer_size = kDefaultTraceBufferSize;
   size_t process_buffer_size_limit = kDefaultProcessBufferSizeLimit;
   bool enable_tsc = kDefaultEnableTscValue;
   Optional<size_t> psb_period = kDefaultPsbPeriod;
+  bool per_core_tracing = kDefaultPerCoreTracing;
 
   if (configuration) {
     if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
-      dict->GetValueForKeyAsInteger("threadBufferSize", thread_buffer_size);
+      dict->GetValueForKeyAsInteger("traceBufferSize", trace_buffer_size);
       dict->GetValueForKeyAsInteger("processBufferSizeLimit",
                                     process_buffer_size_limit);
       dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
       dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
+      dict->GetValueForKeyAsBoolean("perCoreTracing", per_core_tracing);
     } else {
       return createStringError(inconvertibleErrorCode(),
                                "configuration object is not a dictionary");
     }
   }
 
-  return Start(thread_buffer_size, process_buffer_size_limit, enable_tsc,
-               psb_period);
+  return Start(trace_buffer_size, process_buffer_size_limit, enable_tsc,
+               psb_period, per_core_tracing);
 }
 
 llvm::Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
-                                size_t thread_buffer_size, bool enable_tsc,
+                                size_t trace_buffer_size, bool enable_tsc,
                                 Optional<size_t> psb_period) {
   TraceIntelPTStartRequest request;
-  request.threadBufferSize = thread_buffer_size;
-  request.enableTsc = enable_tsc;
-  request.psbPeriod = psb_period.map([](size_t val) { return (int64_t)val; });
+  request.trace_buffer_size = trace_buffer_size;
+  request.enable_tsc = enable_tsc;
+  request.psb_period = psb_period.map([](size_t val) { return (int64_t)val; });
   request.type = GetPluginName().str();
   request.tids.emplace();
   for (lldb::tid_t tid : tids)
@@ -375,13 +353,13 @@ llvm::Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
 
 Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
                           StructuredData::ObjectSP configuration) {
-  size_t thread_buffer_size = kDefaultThreadBufferSize;
+  size_t trace_buffer_size = kDefaultTraceBufferSize;
   bool enable_tsc = kDefaultEnableTscValue;
   Optional<size_t> psb_period = kDefaultPsbPeriod;
 
   if (configuration) {
     if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
-      dict->GetValueForKeyAsInteger("threadBufferSize", thread_buffer_size);
+      dict->GetValueForKeyAsInteger("traceBufferSize", trace_buffer_size);
       dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
       dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
     } else {
@@ -390,7 +368,7 @@ Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
     }
   }
 
-  return Start(tids, thread_buffer_size, enable_tsc, psb_period);
+  return Start(tids, trace_buffer_size, enable_tsc, psb_period);
 }
 
 Error TraceIntelPT::OnThreadBufferRead(lldb::tid_t tid,

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
index f8f60da7f52ce..d5e8c93c2ba39 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
@@ -84,27 +84,31 @@ class TraceIntelPT : public Trace {
 
   /// Start tracing a live process.
   ///
-  /// \param[in] thread_buffer_size
+  /// More information on the parameters below can be found in the
+  /// jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt.
+  ///
+  /// \param[in] trace_buffer_size
   ///     Trace size per thread in bytes.
   ///
   /// \param[in] total_buffer_size_limit
   ///     Maximum total trace size per process in bytes.
-  ///     More information in TraceIntelPT::GetStartConfigurationHelp().
   ///
   /// \param[in] enable_tsc
   ///     Whether to use enable TSC timestamps or not.
-  ///     More information in TraceIntelPT::GetStartConfigurationHelp().
   ///
   /// \param[in] psb_period
-  ///
   ///     This value defines the period in which PSB packets will be generated.
-  ///     More information in TraceIntelPT::GetStartConfigurationHelp();
+  ///
+  /// \param[in] per_core_tracing
+  ///     This value defines whether to have a trace buffer per thread or per
+  ///     cpu core.
   ///
   /// \return
   ///     \a llvm::Error::success if the operation was successful, or
   ///     \a llvm::Error otherwise.
-  llvm::Error Start(size_t thread_buffer_size, size_t total_buffer_size_limit,
-                    bool enable_tsc, llvm::Optional<size_t> psb_period);
+  llvm::Error Start(size_t trace_buffer_size, size_t total_buffer_size_limit,
+                    bool enable_tsc, llvm::Optional<size_t> psb_period,
+                    bool m_per_core_tracing);
 
   /// \copydoc Trace::Start
   llvm::Error Start(StructuredData::ObjectSP configuration =
@@ -112,25 +116,25 @@ class TraceIntelPT : public Trace {
 
   /// Start tracing live threads.
   ///
+  /// More information on the parameters below can be found in the
+  /// jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt.
+  ///
   /// \param[in] tids
   ///     Threads to trace.
   ///
-  /// \param[in] thread_buffer_size
-  ///     Trace size per thread in bytes.
+  /// \param[in] trace_buffer_size
+  ///     Trace size per thread or per core in bytes.
   ///
   /// \param[in] enable_tsc
   ///     Whether to use enable TSC timestamps or not.
-  ///     More information in TraceIntelPT::GetStartConfigurationHelp().
   ///
   /// \param[in] psb_period
-  ///
   ///     This value defines the period in which PSB packets will be generated.
-  ///     More information in TraceIntelPT::GetStartConfigurationHelp().
   ///
   /// \return
   ///     \a llvm::Error::success if the operation was successful, or
   ///     \a llvm::Error otherwise.
-  llvm::Error Start(llvm::ArrayRef<lldb::tid_t> tids, size_t thread_buffer_size,
+  llvm::Error Start(llvm::ArrayRef<lldb::tid_t> tids, size_t trace_buffer_size,
                     bool enable_tsc, llvm::Optional<size_t> psb_period);
 
   /// \copydoc Trace::Start

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h
index c2bc1b57b2bd2..501fc3013f60c 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h
@@ -16,10 +16,11 @@
 namespace lldb_private {
 namespace trace_intel_pt {
 
-const size_t kDefaultThreadBufferSize = 4 * 1024;              // 4KB
+const size_t kDefaultTraceBufferSize = 4 * 1024;               // 4KB
 const size_t kDefaultProcessBufferSizeLimit = 5 * 1024 * 1024; // 500MB
 const bool kDefaultEnableTscValue = false;
 const llvm::Optional<size_t> kDefaultPsbPeriod = llvm::None;
+const bool kDefaultPerCoreTracing = false;
 
 } // namespace trace_intel_pt
 } // namespace lldb_private

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
index 714a13b6e5e02..2583f8f4b2f4a 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
@@ -35,12 +35,24 @@ let Command = "thread trace start intel pt" in {
 }
 
 let Command = "process trace start intel pt" in {
-  def process_trace_start_intel_pt_thread_size: Option<"thread-size", "s">,
+  def process_trace_start_intel_pt_buffer_size: Option<"buffer-size", "s">,
     Group<1>,
     Arg<"Value">,
-    Desc<"Trace size in bytes per thread. It must be a power of 2 greater "
-         "than or equal to 4096 (2^12). The trace is circular keeping "
-         "the most recent data. Defaults to 4096 bytes.">;
+    Desc<"Size in bytes used by each individual per-thread or per-core trace "
+         "buffer. It must be a power of 2 greater than or equal to 4096 (2^12) "
+         "bytes.">;
+  def process_trace_start_intel_pt_per_core_tracing:
+    Option<"per-core-tracing", "c">,
+    Group<1>,
+    Desc<"Instead of having an individual trace buffer per thread, which uses "
+         "a number trace buffers proportional to the number of running "
+         "threads, this option triggers the collection on a per cpu core "
+         "basis. This effectively traces the entire activity on all cores "
+         "using a limited amount of trace buffers regardless of the number of "
+         "threads. This might cause data loss for less frequent threads. This "
+         "option forces the capture of TSC timestamps (see --tsc). Also, this "
+         "option can't be used simulatenously with any other trace sessions "
+         "because of its system-wide nature.">;
   def process_trace_start_intel_pt_process_size_limit: Option<"total-size-limit", "l">,
     Group<1>,
     Arg<"Value">,

diff  --git a/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp b/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
index bd450bb0721c9..746e034e88de7 100644
--- a/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
+++ b/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
@@ -20,29 +20,27 @@ bool fromJSON(const json::Value &value, TraceIntelPTStartRequest &packet,
               Path path) {
   ObjectMapper o(value, path);
   if (!o || !fromJSON(value, (TraceStartRequest &)packet, path) ||
-      !o.map("enableTsc", packet.enableTsc) ||
-      !o.map("psbPeriod", packet.psbPeriod) ||
-      !o.map("threadBufferSize", packet.threadBufferSize) ||
-      !o.map("processBufferSizeLimit", packet.processBufferSizeLimit))
-    return false;
-  if (packet.tids && packet.processBufferSizeLimit) {
-    path.report("processBufferSizeLimit must be provided");
-    return false;
-  }
-  if (!packet.tids && !packet.processBufferSizeLimit) {
-    path.report("processBufferSizeLimit must not be provided");
+      !o.map("enableTsc", packet.enable_tsc) ||
+      !o.map("psbPeriod", packet.psb_period) ||
+      !o.map("traceBufferSize", packet.trace_buffer_size))
     return false;
+
+  if (packet.IsProcessTracing()) {
+    if (!o.map("processBufferSizeLimit", packet.process_buffer_size_limit) ||
+        !o.map("perCoreTracing", packet.per_core_tracing))
+      return false;
   }
   return true;
 }
 
 json::Value toJSON(const TraceIntelPTStartRequest &packet) {
   json::Value base = toJSON((const TraceStartRequest &)packet);
-  base.getAsObject()->try_emplace("threadBufferSize", packet.threadBufferSize);
-  base.getAsObject()->try_emplace("processBufferSizeLimit",
-                                  packet.processBufferSizeLimit);
-  base.getAsObject()->try_emplace("psbPeriod", packet.psbPeriod);
-  base.getAsObject()->try_emplace("enableTsc", packet.enableTsc);
+  json::Object &obj = *base.getAsObject();
+  obj.try_emplace("traceBufferSize", packet.trace_buffer_size);
+  obj.try_emplace("processBufferSizeLimit", packet.process_buffer_size_limit);
+  obj.try_emplace("psbPeriod", packet.psb_period);
+  obj.try_emplace("enableTsc", packet.enable_tsc);
+  obj.try_emplace("perCoreTracing", packet.per_core_tracing);
   return base;
 }
 

diff  --git a/lldb/test/API/commands/trace/TestTraceStartStop.py b/lldb/test/API/commands/trace/TestTraceStartStop.py
index 765e3e829f1c5..294ba96cf013e 100644
--- a/lldb/test/API/commands/trace/TestTraceStartStop.py
+++ b/lldb/test/API/commands/trace/TestTraceStartStop.py
@@ -35,18 +35,18 @@ def testStartSessionWithWrongSize(self):
         self.expect("r")
 
         self.traceStartThread(
-            error=True, threadBufferSize=2000,
+            error=True, traceBufferSize=2000,
             substrs=["The trace buffer size must be a power of 2", "It was 2000"])
 
         self.traceStartThread(
-            error=True, threadBufferSize=5000,
+            error=True, traceBufferSize=5000,
             substrs=["The trace buffer size must be a power of 2", "It was 5000"])
 
         self.traceStartThread(
-            error=True, threadBufferSize=0,
+            error=True, traceBufferSize=0,
             substrs=["The trace buffer size must be a power of 2", "It was 0"])
 
-        self.traceStartThread(threadBufferSize=1048576)
+        self.traceStartThread(traceBufferSize=1048576)
 
     @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
     def testSBAPIHelp(self):
@@ -55,7 +55,7 @@ def testSBAPIHelp(self):
         self.expect("r")
 
         help = self.getTraceOrCreate().GetStartConfigurationHelp()
-        self.assertIn("threadBufferSize", help)
+        self.assertIn("traceBufferSize", help)
         self.assertIn("processBufferSizeLimit", help)
 
     @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))

diff  --git a/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py b/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py
index 4b7fbc9f388de..6bfe83192bd58 100644
--- a/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py
+++ b/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py
@@ -152,3 +152,17 @@ def testStartMultipleLiveThreadsWithSmallTotalLimit(self):
         self.expect("c", substrs=['Thread', "can't be traced"])
 
         self.traceStopProcess()
+
+    @skipIf(oslist=no_match(['linux']), archs=no_match(['i386', 'x86_64']))
+    @testSBAPIAndCommands
+    def testStartPerCoreSession(self):
+        self.build()
+        exe = self.getBuildArtifact("a.out")
+        self.dbg.CreateTarget(exe)
+
+        self.expect("b main")
+        self.expect("r")
+
+        self.traceStartProcess(
+            error=True, perCoreTracing=True,
+            substrs=["Per-core tracing is not supported"])


        


More information about the lldb-commits mailing list