[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
This commit is contained in:
Walter Erquinigo 2022-04-28 14:00:44 -07:00
parent 67d0bc27c0
commit b8d1776fc5
13 changed files with 204 additions and 145 deletions

View File

@ -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 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": <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:

View File

@ -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,

View File

@ -45,37 +45,38 @@ class TraceIntelPTTestCaseBase(TestBase):
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 @@ class TraceIntelPTTestCaseBase(TestBase):
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 @@ class TraceIntelPTTestCaseBase(TestBase):
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):

View File

@ -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();

View File

@ -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);

View File

@ -31,7 +31,7 @@ public:
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 @@ public:
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 @@ public:
: 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 |

View File

@ -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,

View File

@ -84,27 +84,31 @@ public:
/// 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 @@ public:
/// 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

View File

@ -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

View File

@ -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">,

View File

@ -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;
}

View File

@ -35,18 +35,18 @@ class TestTraceStartStop(TraceIntelPTTestCaseBase):
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 @@ class TestTraceStartStop(TraceIntelPTTestCaseBase):
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']))

View File

@ -152,3 +152,17 @@ class TestTraceStartStopMultipleThreads(TraceIntelPTTestCaseBase):
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"])