[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:
parent
67d0bc27c0
commit
b8d1776fc5
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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">,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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']))
|
||||
|
|
|
@ -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"])
|
||||
|
|
Loading…
Reference in New Issue