diff --git a/lldb/docs/lldb-gdb-remote.txt b/lldb/docs/lldb-gdb-remote.txt --- a/lldb/docs/lldb-gdb-remote.txt +++ b/lldb/docs/lldb-gdb-remote.txt @@ -283,7 +283,7 @@ // Tracing technology name, e.g. intel-pt, arm-coresight. // // /* thread tracing only */ -// "tids": [], +// "tids"?: [], // Individual threads to trace. // // ... other parameters specific to the provided tracing type @@ -298,16 +298,25 @@ // 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 different 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": , -// Trace buffer size per thread in bytes. It must be a power of 2 -// greater than or equal to 4096 (2^12) bytes. +// "traceBufferSize": , +// 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": , // Whether to enable TSC timestamps or not. This is supported on @@ -342,15 +351,35 @@ // 0 if supported. // // /* process tracing only */ +// "perCoreTracing": +// 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": , // 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 --- a/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h +++ b/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h @@ -28,20 +28,23 @@ /// \{ 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 psbPeriod; + llvm::Optional 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 processBufferSizeLimit; + llvm::Optional process_buffer_size_limit; + + /// Whether to have a trace buffer per thread or per cpu core. + llvm::Optional 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 --- 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 @@ 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 @@ 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 @@ 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 --- a/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp +++ b/lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp @@ -443,8 +443,8 @@ "Thread %" PRIu64 " already traced", tid); Expected 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::TraceStart(lldb::tid_t tid) { - if (m_thread_traces.GetTotalBufferSize() + m_tracing_params.threadBufferSize > - static_cast(*m_tracing_params.processBufferSizeLimit)) + if (m_thread_traces.GetTotalBufferSize() + + m_tracing_params.trace_buffer_size > + static_cast(*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 @@ 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.h b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h --- a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h +++ b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h @@ -31,7 +31,7 @@ llvm::ArrayRef GetDefinitions() override; - size_t m_thread_buffer_size; + size_t m_trace_buffer_size; bool m_enable_tsc; llvm::Optional m_psb_period; }; @@ -74,10 +74,11 @@ llvm::ArrayRef 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 m_psb_period; + bool m_per_core_tracing; }; CommandObjectProcessTraceStartIntelPT(TraceIntelPT &trace, @@ -85,10 +86,14 @@ : 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 []", lldb::eCommandRequiresProcess | lldb::eCommandTryTargetAPILock | lldb::eCommandProcessMustBeLaunched | diff --git a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp --- a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp +++ b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp @@ -32,13 +32,13 @@ 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 @@ 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 @@ bool CommandObjectThreadTraceStartIntelPT::DoExecuteOnThreads( Args &command, CommandReturnObject &result, llvm::ArrayRef 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 @@ 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 @@ 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 @@ 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 @@ -153,9 +158,10 @@ 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/TraceIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h --- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h +++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h @@ -84,27 +84,31 @@ /// 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 psb_period); + llvm::Error Start(size_t trace_buffer_size, size_t total_buffer_size_limit, + bool enable_tsc, llvm::Optional psb_period, + bool m_per_core_tracing); /// \copydoc Trace::Start llvm::Error Start(StructuredData::ObjectSP configuration = @@ -112,25 +116,25 @@ /// 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 tids, size_t thread_buffer_size, + llvm::Error Start(llvm::ArrayRef tids, size_t trace_buffer_size, bool enable_tsc, llvm::Optional psb_period); /// \copydoc Trace::Start diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp --- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp +++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp @@ -271,101 +271,79 @@ // documentation file. Similarly, it should match the CLI help messages of the // TraceIntelPTOptions.td file. const char *TraceIntelPT::GetStartConfigurationHelp() { - return R"(Parameters: + static Optional 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 psb_period) { + Optional 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 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 tids, - size_t thread_buffer_size, bool enable_tsc, + size_t trace_buffer_size, bool enable_tsc, Optional 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 @@ Error TraceIntelPT::Start(llvm::ArrayRef tids, StructuredData::ObjectSP configuration) { - size_t thread_buffer_size = kDefaultThreadBufferSize; + size_t trace_buffer_size = kDefaultTraceBufferSize; bool enable_tsc = kDefaultEnableTscValue; Optional 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 @@ } } - 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/TraceIntelPTConstants.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h --- 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 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 --- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td +++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td @@ -35,12 +35,24 @@ } 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 --- a/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp +++ b/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp @@ -20,29 +20,27 @@ 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 --- a/lldb/test/API/commands/trace/TestTraceStartStop.py +++ b/lldb/test/API/commands/trace/TestTraceStartStop.py @@ -35,18 +35,18 @@ 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 @@ 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 --- a/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py +++ b/lldb/test/API/commands/trace/multiple-threads/TestTraceStartStopMultipleThreads.py @@ -152,3 +152,17 @@ 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"])