11 #include "../common/ThreadPostMortemTrace.h"
20 #include "llvm/ADT/None.h"
31 return CommandObjectSP(
37 return CommandObjectSP(
41 void TraceIntelPT::Initialize() {
42 PluginManager::RegisterPlugin(GetPluginNameStatic(),
"Intel Processor Trace",
43 CreateInstanceForTraceBundle,
44 CreateInstanceForLiveProcess,
45 TraceIntelPTBundleLoader::GetSchema());
48 void TraceIntelPT::Terminate() {
49 PluginManager::UnregisterPlugin(CreateInstanceForTraceBundle);
52 StringRef TraceIntelPT::GetSchema() {
53 return TraceIntelPTBundleLoader::GetSchema();
56 void TraceIntelPT::Dump(
Stream *s)
const {}
59 RefreshLiveProcessState();
63 Expected<TraceSP> TraceIntelPT::CreateInstanceForTraceBundle(
64 const json::Value &bundle_description, StringRef bundle_dir,
71 Expected<TraceSP> TraceIntelPT::CreateInstanceForLiveProcess(
Process &process) {
78 return std::static_pointer_cast<TraceIntelPT>(shared_from_this());
83 ArrayRef<ThreadPostMortemTraceSP> traced_threads) {
87 if (bundle_description.
cpus) {
88 std::vector<cpu_id_t> cpus;
90 for (
const JSONCpu &cpu : *bundle_description.
cpus) {
91 trace_sp->SetPostMortemCpuDataFile(cpu.
id, IntelPTDataKinds::kIptTrace,
94 trace_sp->SetPostMortemCpuDataFile(
95 cpu.
id, IntelPTDataKinds::kPerfContextSwitchTrace,
97 cpus.push_back(cpu.
id);
100 std::vector<tid_t> tids;
103 tids.push_back(thread.
tid);
105 trace_sp->m_storage.multicpu_decoder.emplace(trace_sp);
107 for (
const ThreadPostMortemTraceSP &thread : traced_threads) {
108 trace_sp->m_storage.thread_decoders.try_emplace(
109 thread->GetID(), std::make_unique<ThreadDecoder>(thread, *trace_sp));
110 if (
const Optional<FileSpec> &trace_file = thread->GetTraceFile()) {
111 trace_sp->SetPostMortemThreadDataFile(
112 thread->GetID(), IntelPTDataKinds::kIptTrace, *trace_file);
117 for (
const ProcessSP &process_sp : traced_processes)
118 process_sp->GetTarget().SetTrace(trace_sp);
123 ArrayRef<ProcessSP> traced_processes)
124 :
Trace(traced_processes, bundle_description.GetCpuIds()),
125 m_cpu_info(bundle_description.cpu_info) {}
129 return createStringError(inconvertibleErrorCode(),
error);
137 return createStringError(inconvertibleErrorCode(),
"thread not traced");
138 return it->second->Decode();
141 llvm::Expected<lldb::TraceCursorUP>
143 if (Expected<DecodedThreadSP> decoded_thread =
Decode(thread))
144 return decoded_thread.get()->CreateNewCursor();
146 return decoded_thread.takeError();
155 s <<
", not traced\n";
160 Expected<DecodedThreadSP> decoded_thread_sp_or_err =
Decode(thread);
161 if (!decoded_thread_sp_or_err) {
162 s <<
toString(decoded_thread_sp_or_err.takeError()) <<
"\n";
168 Expected<Optional<uint64_t>> raw_size_or_error =
GetRawTraceSize(thread);
169 if (!raw_size_or_error) {
173 Optional<uint64_t> raw_size = *raw_size_or_error;
177 uint64_t items_count = decoded_thread_sp->GetItemsCount();
178 uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage();
180 s.
Format(
" Total number of trace items: {0}\n", items_count);
182 s <<
"\n Memory usage:\n";
184 s.
Format(
" Raw trace size: {0} KiB\n", *raw_size / 1024);
187 " Total approximate memory usage (excluding raw trace): {0:2} KiB\n",
188 (
double)mem_used / 1024);
189 if (items_count != 0)
190 s.
Format(
" Average memory usage per item (excluding raw trace): "
192 (
double)mem_used / items_count);
197 s <<
"\n Timing for this thread:\n";
199 std::chrono::milliseconds duration) {
200 s.
Format(
" {0}: {1:2}s\n", name, duration.count() / 1000.0);
204 s <<
"\n Timing for global tasks:\n";
211 decoded_thread_sp->GetEventsStats();
213 s.
Format(
" Number of individual events: {0}\n",
215 for (
const auto &event_to_count : events_stats.
events_counts) {
218 event_to_count.second);
223 s <<
"\n Multi-cpu decoding:\n";
224 s.
Format(
" Total number of continuous executions found: {0}\n",
227 " Number of continuous executions for this thread: {0}\n",
235 decoded_thread_sp->GetTscErrorsStats();
236 s.
Format(
" Number of TSC decoding errors: {0}\n",
238 for (
const auto &error_message_to_count :
240 s.
Format(
" {0}: {1}\n", error_message_to_count.first,
241 error_message_to_count.second);
246 llvm::Expected<Optional<uint64_t>>
255 auto callback = [&](llvm::ArrayRef<uint8_t> data) {
257 return Error::success();
260 return std::move(err);
266 Expected<std::vector<uint8_t>> cpu_info =
269 return cpu_info.takeError();
271 int64_t cpu_family = -1;
273 int64_t stepping = -1;
276 StringRef rest(
reinterpret_cast<const char *
>(cpu_info->data()),
278 while (!rest.empty()) {
280 std::tie(line, rest) = rest.split(
'\n');
282 SmallVector<StringRef, 2> columns;
283 line.split(columns, StringRef(
":"), -1,
false);
285 if (columns.size() < 2)
288 columns[1] = columns[1].trim(
" ");
289 if (columns[0].contains(
"cpu family") &&
290 columns[1].getAsInteger(10, cpu_family))
293 else if (columns[0].contains(
"model") && columns[1].getAsInteger(10, model))
296 else if (columns[0].contains(
"stepping") &&
297 columns[1].getAsInteger(10, stepping))
300 else if (columns[0].contains(
"vendor_id")) {
301 vendor_id = columns[1].str();
302 if (!vendor_id.empty())
306 if ((cpu_family != -1) && (model != -1) && (stepping != -1) &&
307 (!vendor_id.empty())) {
308 return pt_cpu{vendor_id ==
"GenuineIntel" ? pcv_intel : pcv_unknown,
310 static_cast<uint8_t
>(model),
311 static_cast<uint8_t
>(stepping)};
314 return createStringError(inconvertibleErrorCode(),
315 "Failed parsing the target's /proc/cpuinfo file");
323 return cpu_info.takeError();
328 llvm::Optional<LinuxPerfZeroTscConversion>
339 StringRef json_response) {
342 Expected<TraceIntelPTGetStateResponse> intelpt_state =
343 json::parse<TraceIntelPTGetStateResponse>(json_response,
344 "TraceIntelPTGetStateResponse");
346 return intelpt_state.takeError();
350 if (!intelpt_state->cpus) {
355 thread_state.
tid, std::make_unique<ThreadDecoder>(thread_sp, *
this));
358 std::vector<cpu_id_t> cpus;
360 cpus.push_back(cpu.
id);
362 std::vector<tid_t> tids;
364 tids.push_back(thread.
tid);
366 if (!intelpt_state->tsc_perf_zero_conversion)
367 return createStringError(inconvertibleErrorCode(),
368 "Missing perf time_zero conversion values");
374 LLDB_LOG(log,
"TraceIntelPT found TSC conversion information");
376 return Error::success();
391 static Optional<std::string>
message;
393 message.emplace(formatv(R
"(Parameters:
395 See the jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt for a
396 description of each parameter below.
398 - int iptTraceSize (defaults to {0} bytes):
399 [process and thread tracing]
401 - boolean enableTsc (default to {1}):
402 [process and thread tracing]
404 - int psbPeriod (defaults to {2}):
405 [process and thread tracing]
407 - boolean perCpuTracing (default to {3}):
408 [process tracing only]
410 - int processBufferSizeLimit (defaults to {4} MiB):
411 [process tracing only])",
420 uint64_t total_buffer_size_limit,
bool enable_tsc,
421 Optional<uint64_t> psb_period,
bool per_cpu_tracing) {
441 dict->GetValueForKeyAsInteger(
"iptTraceSize", ipt_trace_size);
442 dict->GetValueForKeyAsInteger(
"processBufferSizeLimit",
443 process_buffer_size_limit);
444 dict->GetValueForKeyAsBoolean(
"enableTsc", enable_tsc);
445 dict->GetValueForKeyAsInteger(
"psbPeriod", psb_period);
446 dict->GetValueForKeyAsBoolean(
"perCpuTracing", per_cpu_tracing);
448 return createStringError(inconvertibleErrorCode(),
449 "configuration object is not a dictionary");
453 return Start(ipt_trace_size, process_buffer_size_limit, enable_tsc,
454 psb_period, per_cpu_tracing);
458 uint64_t ipt_trace_size,
bool enable_tsc,
459 Optional<uint64_t> psb_period) {
465 request.
tids.emplace();
467 request.
tids->push_back(tid);
479 dict->GetValueForKeyAsInteger(
"iptTraceSize", ipt_trace_size);
480 dict->GetValueForKeyAsBoolean(
"enableTsc", enable_tsc);
481 dict->GetValueForKeyAsInteger(
"psbPeriod", psb_period);
483 return createStringError(inconvertibleErrorCode(),
484 "configuration object is not a dictionary");
488 return Start(tids, ipt_trace_size, enable_tsc, psb_period);