1 //===-- TraceIntelPT.cpp --------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "TraceIntelPT.h"
11 #include "../common/ThreadPostMortemTrace.h"
12 #include "CommandObjectTraceStartIntelPT.h"
13 #include "DecodedThread.h"
14 #include "TraceCursorIntelPT.h"
15 #include "TraceIntelPTBundleLoader.h"
16 #include "TraceIntelPTBundleSaver.h"
17 #include "TraceIntelPTConstants.h"
18 #include "lldb/Core/PluginManager.h"
19 #include "lldb/Interpreter/OptionValueProperties.h"
20 #include "lldb/Target/Process.h"
21 #include "lldb/Target/Target.h"
25 using namespace lldb_private
;
26 using namespace lldb_private::trace_intel_pt
;
29 LLDB_PLUGIN_DEFINE(TraceIntelPT
)
32 TraceIntelPT::GetProcessTraceStartCommand(CommandInterpreter
&interpreter
) {
33 return CommandObjectSP(
34 new CommandObjectProcessTraceStartIntelPT(*this, interpreter
));
38 TraceIntelPT::GetThreadTraceStartCommand(CommandInterpreter
&interpreter
) {
39 return CommandObjectSP(
40 new CommandObjectThreadTraceStartIntelPT(*this, interpreter
));
43 #define LLDB_PROPERTIES_traceintelpt
44 #include "TraceIntelPTProperties.inc"
47 #define LLDB_PROPERTIES_traceintelpt
48 #include "TraceIntelPTPropertiesEnum.inc"
51 llvm::StringRef
TraceIntelPT::PluginProperties::GetSettingName() {
52 return TraceIntelPT::GetPluginNameStatic();
55 TraceIntelPT::PluginProperties::PluginProperties() : Properties() {
56 m_collection_sp
= std::make_shared
<OptionValueProperties
>(GetSettingName());
57 m_collection_sp
->Initialize(g_traceintelpt_properties
);
61 TraceIntelPT::PluginProperties::GetInfiniteDecodingLoopVerificationThreshold() {
62 const uint32_t idx
= ePropertyInfiniteDecodingLoopVerificationThreshold
;
63 return m_collection_sp
->GetPropertyAtIndexAsUInt64(
64 nullptr, idx
, g_traceintelpt_properties
[idx
].default_uint_value
);
67 uint64_t TraceIntelPT::PluginProperties::GetExtremelyLargeDecodingThreshold() {
68 const uint32_t idx
= ePropertyExtremelyLargeDecodingThreshold
;
69 return m_collection_sp
->GetPropertyAtIndexAsUInt64(
70 nullptr, idx
, g_traceintelpt_properties
[idx
].default_uint_value
);
73 TraceIntelPT::PluginProperties
&TraceIntelPT::GetGlobalProperties() {
74 static TraceIntelPT::PluginProperties g_settings
;
78 void TraceIntelPT::Initialize() {
79 PluginManager::RegisterPlugin(
80 GetPluginNameStatic(), "Intel Processor Trace",
81 CreateInstanceForTraceBundle
, CreateInstanceForLiveProcess
,
82 TraceIntelPTBundleLoader::GetSchema(), DebuggerInitialize
);
85 void TraceIntelPT::DebuggerInitialize(Debugger
&debugger
) {
86 if (!PluginManager::GetSettingForProcessPlugin(
87 debugger
, PluginProperties::GetSettingName())) {
88 const bool is_global_setting
= true;
89 PluginManager::CreateSettingForTracePlugin(
90 debugger
, GetGlobalProperties().GetValueProperties(),
91 "Properties for the intel-pt trace plug-in.", is_global_setting
);
95 void TraceIntelPT::Terminate() {
96 PluginManager::UnregisterPlugin(CreateInstanceForTraceBundle
);
99 StringRef
TraceIntelPT::GetSchema() {
100 return TraceIntelPTBundleLoader::GetSchema();
103 void TraceIntelPT::Dump(Stream
*s
) const {}
105 Expected
<FileSpec
> TraceIntelPT::SaveToDisk(FileSpec directory
, bool compact
) {
106 RefreshLiveProcessState();
107 return TraceIntelPTBundleSaver().SaveToDisk(*this, directory
, compact
);
110 Expected
<TraceSP
> TraceIntelPT::CreateInstanceForTraceBundle(
111 const json::Value
&bundle_description
, StringRef bundle_dir
,
112 Debugger
&debugger
) {
113 return TraceIntelPTBundleLoader(debugger
, bundle_description
, bundle_dir
)
117 Expected
<TraceSP
> TraceIntelPT::CreateInstanceForLiveProcess(Process
&process
) {
118 TraceSP
instance(new TraceIntelPT(process
));
119 process
.GetTarget().SetTrace(instance
);
123 TraceIntelPTSP
TraceIntelPT::GetSharedPtr() {
124 return std::static_pointer_cast
<TraceIntelPT
>(shared_from_this());
127 TraceIntelPT::TraceMode
TraceIntelPT::GetTraceMode() { return trace_mode
; }
129 TraceIntelPTSP
TraceIntelPT::CreateInstanceForPostmortemTrace(
130 JSONTraceBundleDescription
&bundle_description
,
131 ArrayRef
<ProcessSP
> traced_processes
,
132 ArrayRef
<ThreadPostMortemTraceSP
> traced_threads
, TraceMode trace_mode
) {
133 TraceIntelPTSP
trace_sp(
134 new TraceIntelPT(bundle_description
, traced_processes
, trace_mode
));
135 trace_sp
->m_storage
.tsc_conversion
=
136 bundle_description
.tsc_perf_zero_conversion
;
138 if (bundle_description
.cpus
) {
139 std::vector
<cpu_id_t
> cpus
;
141 for (const JSONCpu
&cpu
: *bundle_description
.cpus
) {
142 trace_sp
->SetPostMortemCpuDataFile(cpu
.id
, IntelPTDataKinds::kIptTrace
,
143 FileSpec(cpu
.ipt_trace
));
145 trace_sp
->SetPostMortemCpuDataFile(
146 cpu
.id
, IntelPTDataKinds::kPerfContextSwitchTrace
,
147 FileSpec(cpu
.context_switch_trace
));
148 cpus
.push_back(cpu
.id
);
151 if (trace_mode
== TraceMode::UserMode
) {
152 trace_sp
->m_storage
.multicpu_decoder
.emplace(trace_sp
);
156 if (!bundle_description
.cpus
|| trace_mode
== TraceMode::KernelMode
) {
157 for (const ThreadPostMortemTraceSP
&thread
: traced_threads
) {
158 trace_sp
->m_storage
.thread_decoders
.try_emplace(
159 thread
->GetID(), std::make_unique
<ThreadDecoder
>(thread
, *trace_sp
));
160 if (const std::optional
<FileSpec
> &trace_file
= thread
->GetTraceFile()) {
161 trace_sp
->SetPostMortemThreadDataFile(
162 thread
->GetID(), IntelPTDataKinds::kIptTrace
, *trace_file
);
167 for (const ProcessSP
&process_sp
: traced_processes
)
168 process_sp
->GetTarget().SetTrace(trace_sp
);
172 TraceIntelPT::TraceIntelPT(JSONTraceBundleDescription
&bundle_description
,
173 ArrayRef
<ProcessSP
> traced_processes
,
174 TraceMode trace_mode
)
175 : Trace(traced_processes
, bundle_description
.GetCpuIds()),
176 m_cpu_info(bundle_description
.cpu_info
), trace_mode(trace_mode
) {}
178 Expected
<DecodedThreadSP
> TraceIntelPT::Decode(Thread
&thread
) {
179 if (const char *error
= RefreshLiveProcessState())
180 return createStringError(inconvertibleErrorCode(), error
);
182 Storage
&storage
= GetUpdatedStorage();
183 if (storage
.multicpu_decoder
)
184 return storage
.multicpu_decoder
->Decode(thread
);
186 auto it
= storage
.thread_decoders
.find(thread
.GetID());
187 if (it
== storage
.thread_decoders
.end())
188 return createStringError(inconvertibleErrorCode(), "thread not traced");
189 return it
->second
->Decode();
192 Expected
<std::optional
<uint64_t>> TraceIntelPT::FindBeginningOfTimeNanos() {
193 Storage
&storage
= GetUpdatedStorage();
194 if (storage
.beginning_of_time_nanos_calculated
)
195 return storage
.beginning_of_time_nanos
;
196 storage
.beginning_of_time_nanos_calculated
= true;
198 if (!storage
.tsc_conversion
)
201 std::optional
<uint64_t> lowest_tsc
;
203 if (storage
.multicpu_decoder
) {
204 if (Expected
<std::optional
<uint64_t>> tsc
=
205 storage
.multicpu_decoder
->FindLowestTSC()) {
208 return tsc
.takeError();
212 for (auto &decoder
: storage
.thread_decoders
) {
213 Expected
<std::optional
<uint64_t>> tsc
= decoder
.second
->FindLowestTSC();
215 return tsc
.takeError();
217 if (*tsc
&& (!lowest_tsc
|| *lowest_tsc
> **tsc
))
222 storage
.beginning_of_time_nanos
=
223 storage
.tsc_conversion
->ToNanos(*lowest_tsc
);
225 return storage
.beginning_of_time_nanos
;
228 llvm::Expected
<lldb::TraceCursorSP
>
229 TraceIntelPT::CreateNewCursor(Thread
&thread
) {
230 if (Expected
<DecodedThreadSP
> decoded_thread
= Decode(thread
)) {
231 if (Expected
<std::optional
<uint64_t>> beginning_of_time
=
232 FindBeginningOfTimeNanos())
233 return std::make_shared
<TraceCursorIntelPT
>(
234 thread
.shared_from_this(), *decoded_thread
, m_storage
.tsc_conversion
,
237 return beginning_of_time
.takeError();
239 return decoded_thread
.takeError();
242 void TraceIntelPT::DumpTraceInfo(Thread
&thread
, Stream
&s
, bool verbose
,
244 Storage
&storage
= GetUpdatedStorage();
246 lldb::tid_t tid
= thread
.GetID();
248 DumpTraceInfoAsJson(thread
, s
, verbose
);
252 s
.Format("\nthread #{0}: tid = {1}", thread
.GetIndexID(), thread
.GetID());
253 if (!IsTraced(tid
)) {
254 s
<< ", not traced\n";
259 Expected
<DecodedThreadSP
> decoded_thread_sp_or_err
= Decode(thread
);
260 if (!decoded_thread_sp_or_err
) {
261 s
<< toString(decoded_thread_sp_or_err
.takeError()) << "\n";
265 DecodedThreadSP
&decoded_thread_sp
= *decoded_thread_sp_or_err
;
267 Expected
<std::optional
<uint64_t>> raw_size_or_error
= GetRawTraceSize(thread
);
268 if (!raw_size_or_error
) {
269 s
.Format(" {0}\n", toString(raw_size_or_error
.takeError()));
272 std::optional
<uint64_t> raw_size
= *raw_size_or_error
;
274 s
.Format("\n Trace technology: {0}\n", GetPluginName());
276 /// Instruction stats
278 uint64_t items_count
= decoded_thread_sp
->GetItemsCount();
279 uint64_t mem_used
= decoded_thread_sp
->CalculateApproximateMemoryUsage();
281 s
.Format("\n Total number of trace items: {0}\n", items_count
);
283 s
<< "\n Memory usage:\n";
285 s
.Format(" Raw trace size: {0} KiB\n", *raw_size
/ 1024);
288 " Total approximate memory usage (excluding raw trace): {0:2} KiB\n",
289 (double)mem_used
/ 1024);
290 if (items_count
!= 0)
291 s
.Format(" Average memory usage per item (excluding raw trace): "
293 (double)mem_used
/ items_count
);
298 s
<< "\n Timing for this thread:\n";
299 auto print_duration
= [&](const std::string
&name
,
300 std::chrono::milliseconds duration
) {
301 s
.Format(" {0}: {1:2}s\n", name
, duration
.count() / 1000.0);
303 GetThreadTimer(tid
).ForEachTimedTask(print_duration
);
305 s
<< "\n Timing for global tasks:\n";
306 GetGlobalTimer().ForEachTimedTask(print_duration
);
309 // Instruction events stats
311 const DecodedThread::EventsStats
&events_stats
=
312 decoded_thread_sp
->GetEventsStats();
314 s
.Format(" Number of individual events: {0}\n",
315 events_stats
.total_count
);
316 for (const auto &event_to_count
: events_stats
.events_counts
) {
317 s
.Format(" {0}: {1}\n",
318 TraceCursor::EventKindToString(event_to_count
.first
),
319 event_to_count
.second
);
324 const DecodedThread::ErrorStats
&error_stats
=
325 decoded_thread_sp
->GetErrorStats();
327 s
.Format(" Number of individual errors: {0}\n",
328 error_stats
.GetTotalCount());
329 s
.Format(" Number of fatal errors: {0}\n", error_stats
.fatal_errors
);
330 for (const auto &[kind
, count
] : error_stats
.libipt_errors
) {
331 s
.Format(" Number of libipt errors of kind [{0}]: {1}\n", kind
,
334 s
.Format(" Number of other errors: {0}\n", error_stats
.other_errors
);
337 if (storage
.multicpu_decoder
) {
338 s
<< "\n Multi-cpu decoding:\n";
339 s
.Format(" Total number of continuous executions found: {0}\n",
340 storage
.multicpu_decoder
->GetTotalContinuousExecutionsCount());
342 " Number of continuous executions for this thread: {0}\n",
343 storage
.multicpu_decoder
->GetNumContinuousExecutionsForThread(tid
));
344 s
.Format(" Total number of PSB blocks found: {0}\n",
345 storage
.multicpu_decoder
->GetTotalPSBBlocksCount());
346 s
.Format(" Number of PSB blocks for this thread: {0}\n",
347 storage
.multicpu_decoder
->GePSBBlocksCountForThread(tid
));
348 s
.Format(" Total number of unattributed PSB blocks found: {0}\n",
349 storage
.multicpu_decoder
->GetUnattributedPSBBlocksCount());
353 void TraceIntelPT::DumpTraceInfoAsJson(Thread
&thread
, Stream
&s
,
355 Storage
&storage
= GetUpdatedStorage();
357 lldb::tid_t tid
= thread
.GetID();
358 json::OStream
json_str(s
.AsRawOstream(), 2);
359 if (!IsTraced(tid
)) {
360 s
<< "error: thread not traced\n";
364 Expected
<std::optional
<uint64_t>> raw_size_or_error
= GetRawTraceSize(thread
);
365 if (!raw_size_or_error
) {
366 s
<< "error: " << toString(raw_size_or_error
.takeError()) << "\n";
370 Expected
<DecodedThreadSP
> decoded_thread_sp_or_err
= Decode(thread
);
371 if (!decoded_thread_sp_or_err
) {
372 s
<< "error: " << toString(decoded_thread_sp_or_err
.takeError()) << "\n";
375 DecodedThreadSP
&decoded_thread_sp
= *decoded_thread_sp_or_err
;
377 json_str
.object([&] {
378 json_str
.attribute("traceTechnology", "intel-pt");
379 json_str
.attributeObject("threadStats", [&] {
380 json_str
.attribute("tid", tid
);
382 uint64_t insn_len
= decoded_thread_sp
->GetItemsCount();
383 json_str
.attribute("traceItemsCount", insn_len
);
386 uint64_t mem_used
= decoded_thread_sp
->CalculateApproximateMemoryUsage();
387 json_str
.attributeObject("memoryUsage", [&] {
388 json_str
.attribute("totalInBytes", std::to_string(mem_used
));
389 std::optional
<double> avg
;
391 avg
= double(mem_used
) / insn_len
;
392 json_str
.attribute("avgPerItemInBytes", avg
);
396 json_str
.attributeObject("timingInSeconds", [&] {
397 GetTimer().ForThread(tid
).ForEachTimedTask(
398 [&](const std::string
&name
, std::chrono::milliseconds duration
) {
399 json_str
.attribute(name
, duration
.count() / 1000.0);
403 // Instruction events stats
404 const DecodedThread::EventsStats
&events_stats
=
405 decoded_thread_sp
->GetEventsStats();
406 json_str
.attributeObject("events", [&] {
407 json_str
.attribute("totalCount", events_stats
.total_count
);
408 json_str
.attributeObject("individualCounts", [&] {
409 for (const auto &event_to_count
: events_stats
.events_counts
) {
411 TraceCursor::EventKindToString(event_to_count
.first
),
412 event_to_count
.second
);
417 const DecodedThread::ErrorStats
&error_stats
=
418 decoded_thread_sp
->GetErrorStats();
419 json_str
.attributeObject("errors", [&] {
420 json_str
.attribute("totalCount", error_stats
.GetTotalCount());
421 json_str
.attributeObject("libiptErrors", [&] {
422 for (const auto &[kind
, count
] : error_stats
.libipt_errors
) {
423 json_str
.attribute(kind
, count
);
426 json_str
.attribute("fatalErrors", error_stats
.fatal_errors
);
427 json_str
.attribute("otherErrors", error_stats
.other_errors
);
430 if (storage
.multicpu_decoder
) {
432 "continuousExecutions",
433 storage
.multicpu_decoder
->GetNumContinuousExecutionsForThread(tid
));
436 storage
.multicpu_decoder
->GePSBBlocksCountForThread(tid
));
440 json_str
.attributeObject("globalStats", [&] {
441 json_str
.attributeObject("timingInSeconds", [&] {
442 GetTimer().ForGlobal().ForEachTimedTask(
443 [&](const std::string
&name
, std::chrono::milliseconds duration
) {
444 json_str
.attribute(name
, duration
.count() / 1000.0);
447 if (storage
.multicpu_decoder
) {
449 "totalUnattributedPSBBlocks",
450 storage
.multicpu_decoder
->GetUnattributedPSBBlocksCount());
452 "totalCountinuosExecutions",
453 storage
.multicpu_decoder
->GetTotalContinuousExecutionsCount());
454 json_str
.attribute("totalPSBBlocks",
455 storage
.multicpu_decoder
->GetTotalPSBBlocksCount());
457 "totalContinuousExecutions",
458 storage
.multicpu_decoder
->GetTotalContinuousExecutionsCount());
464 llvm::Expected
<std::optional
<uint64_t>>
465 TraceIntelPT::GetRawTraceSize(Thread
&thread
) {
466 if (GetUpdatedStorage().multicpu_decoder
)
467 return std::nullopt
; // TODO: calculate the amount of intel pt raw trace associated
468 // with the given thread.
469 if (GetLiveProcess())
470 return GetLiveThreadBinaryDataSize(thread
.GetID(),
471 IntelPTDataKinds::kIptTrace
);
473 auto callback
= [&](llvm::ArrayRef
<uint8_t> data
) {
475 return Error::success();
477 if (Error err
= OnThreadBufferRead(thread
.GetID(), callback
))
478 return std::move(err
);
483 Expected
<pt_cpu
> TraceIntelPT::GetCPUInfoForLiveProcess() {
484 Expected
<std::vector
<uint8_t>> cpu_info
=
485 GetLiveProcessBinaryData(IntelPTDataKinds::kProcFsCpuInfo
);
487 return cpu_info
.takeError();
489 int64_t cpu_family
= -1;
491 int64_t stepping
= -1;
492 std::string vendor_id
;
494 StringRef
rest(reinterpret_cast<const char *>(cpu_info
->data()),
496 while (!rest
.empty()) {
498 std::tie(line
, rest
) = rest
.split('\n');
500 SmallVector
<StringRef
, 2> columns
;
501 line
.split(columns
, StringRef(":"), -1, false);
503 if (columns
.size() < 2)
504 continue; // continue searching
506 columns
[1] = columns
[1].trim(" ");
507 if (columns
[0].contains("cpu family") &&
508 columns
[1].getAsInteger(10, cpu_family
))
511 else if (columns
[0].contains("model") && columns
[1].getAsInteger(10, model
))
514 else if (columns
[0].contains("stepping") &&
515 columns
[1].getAsInteger(10, stepping
))
518 else if (columns
[0].contains("vendor_id")) {
519 vendor_id
= columns
[1].str();
520 if (!vendor_id
.empty())
524 if ((cpu_family
!= -1) && (model
!= -1) && (stepping
!= -1) &&
525 (!vendor_id
.empty())) {
526 return pt_cpu
{vendor_id
== "GenuineIntel" ? pcv_intel
: pcv_unknown
,
527 static_cast<uint16_t>(cpu_family
),
528 static_cast<uint8_t>(model
),
529 static_cast<uint8_t>(stepping
)};
532 return createStringError(inconvertibleErrorCode(),
533 "Failed parsing the target's /proc/cpuinfo file");
536 Expected
<pt_cpu
> TraceIntelPT::GetCPUInfo() {
538 if (llvm::Expected
<pt_cpu
> cpu_info
= GetCPUInfoForLiveProcess())
539 m_cpu_info
= *cpu_info
;
541 return cpu_info
.takeError();
546 std::optional
<LinuxPerfZeroTscConversion
>
547 TraceIntelPT::GetPerfZeroTscConversion() {
548 return GetUpdatedStorage().tsc_conversion
;
551 TraceIntelPT::Storage
&TraceIntelPT::GetUpdatedStorage() {
552 RefreshLiveProcessState();
556 Error
TraceIntelPT::DoRefreshLiveProcessState(TraceGetStateResponse state
,
557 StringRef json_response
) {
558 m_storage
= Storage();
560 Expected
<TraceIntelPTGetStateResponse
> intelpt_state
=
561 json::parse
<TraceIntelPTGetStateResponse
>(json_response
,
562 "TraceIntelPTGetStateResponse");
564 return intelpt_state
.takeError();
566 m_storage
.tsc_conversion
= intelpt_state
->tsc_perf_zero_conversion
;
568 if (!intelpt_state
->cpus
) {
569 for (const TraceThreadState
&thread_state
: state
.traced_threads
) {
571 GetLiveProcess()->GetThreadList().FindThreadByID(thread_state
.tid
);
572 m_storage
.thread_decoders
.try_emplace(
573 thread_state
.tid
, std::make_unique
<ThreadDecoder
>(thread_sp
, *this));
576 std::vector
<cpu_id_t
> cpus
;
577 for (const TraceCpuState
&cpu
: *intelpt_state
->cpus
)
578 cpus
.push_back(cpu
.id
);
580 std::vector
<tid_t
> tids
;
581 for (const TraceThreadState
&thread
: intelpt_state
->traced_threads
)
582 tids
.push_back(thread
.tid
);
584 if (!intelpt_state
->tsc_perf_zero_conversion
)
585 return createStringError(inconvertibleErrorCode(),
586 "Missing perf time_zero conversion values");
587 m_storage
.multicpu_decoder
.emplace(GetSharedPtr());
590 if (m_storage
.tsc_conversion
) {
591 Log
*log
= GetLog(LLDBLog::Target
);
592 LLDB_LOG(log
, "TraceIntelPT found TSC conversion information");
594 return Error::success();
597 bool TraceIntelPT::IsTraced(lldb::tid_t tid
) {
598 Storage
&storage
= GetUpdatedStorage();
599 if (storage
.multicpu_decoder
)
600 return storage
.multicpu_decoder
->TracesThread(tid
);
601 return storage
.thread_decoders
.count(tid
);
604 // The information here should match the description of the intel-pt section
605 // of the jLLDBTraceStart packet in the lldb/docs/lldb-gdb-remote.txt
606 // documentation file. Similarly, it should match the CLI help messages of the
607 // TraceIntelPTOptions.td file.
608 const char *TraceIntelPT::GetStartConfigurationHelp() {
609 static std::optional
<std::string
> message
;
611 message
.emplace(formatv(R
"(Parameters:
613 See the jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt for a
614 description of each parameter below.
616 - int iptTraceSize (defaults to {0} bytes):
617 [process and thread tracing]
619 - boolean enableTsc (default to {1}):
620 [process and thread tracing]
622 - int psbPeriod (defaults to {2}):
623 [process and thread tracing]
625 - boolean perCpuTracing (default to {3}):
626 [process tracing only]
628 - int processBufferSizeLimit (defaults to {4} MiB):
629 [process tracing only]
631 - boolean disableCgroupFiltering (default to {5}):
632 [process tracing only])",
633 kDefaultIptTraceSize
, kDefaultEnableTscValue
,
634 kDefaultPsbPeriod
, kDefaultPerCpuTracing
,
635 kDefaultProcessBufferSizeLimit
/ 1024 / 1024,
636 kDefaultDisableCgroupFiltering
));
638 return message
->c_str();
641 Error
TraceIntelPT::Start(uint64_t ipt_trace_size
,
642 uint64_t total_buffer_size_limit
, bool enable_tsc
,
643 std::optional
<uint64_t> psb_period
,
644 bool per_cpu_tracing
, bool disable_cgroup_filtering
) {
645 TraceIntelPTStartRequest request
;
646 request
.ipt_trace_size
= ipt_trace_size
;
647 request
.process_buffer_size_limit
= total_buffer_size_limit
;
648 request
.enable_tsc
= enable_tsc
;
649 request
.psb_period
= psb_period
;
650 request
.type
= GetPluginName().str();
651 request
.per_cpu_tracing
= per_cpu_tracing
;
652 request
.disable_cgroup_filtering
= disable_cgroup_filtering
;
653 return Trace::Start(toJSON(request
));
656 Error
TraceIntelPT::Start(StructuredData::ObjectSP configuration
) {
657 uint64_t ipt_trace_size
= kDefaultIptTraceSize
;
658 uint64_t process_buffer_size_limit
= kDefaultProcessBufferSizeLimit
;
659 bool enable_tsc
= kDefaultEnableTscValue
;
660 std::optional
<uint64_t> psb_period
= kDefaultPsbPeriod
;
661 bool per_cpu_tracing
= kDefaultPerCpuTracing
;
662 bool disable_cgroup_filtering
= kDefaultDisableCgroupFiltering
;
665 if (StructuredData::Dictionary
*dict
= configuration
->GetAsDictionary()) {
666 dict
->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size
);
667 dict
->GetValueForKeyAsInteger("processBufferSizeLimit",
668 process_buffer_size_limit
);
669 dict
->GetValueForKeyAsBoolean("enableTsc", enable_tsc
);
670 dict
->GetValueForKeyAsInteger("psbPeriod", psb_period
);
671 dict
->GetValueForKeyAsBoolean("perCpuTracing", per_cpu_tracing
);
672 dict
->GetValueForKeyAsBoolean("disableCgroupFiltering",
673 disable_cgroup_filtering
);
675 return createStringError(inconvertibleErrorCode(),
676 "configuration object is not a dictionary");
680 return Start(ipt_trace_size
, process_buffer_size_limit
, enable_tsc
,
681 psb_period
, per_cpu_tracing
, disable_cgroup_filtering
);
684 llvm::Error
TraceIntelPT::Start(llvm::ArrayRef
<lldb::tid_t
> tids
,
685 uint64_t ipt_trace_size
, bool enable_tsc
,
686 std::optional
<uint64_t> psb_period
) {
687 TraceIntelPTStartRequest request
;
688 request
.ipt_trace_size
= ipt_trace_size
;
689 request
.enable_tsc
= enable_tsc
;
690 request
.psb_period
= psb_period
;
691 request
.type
= GetPluginName().str();
692 request
.tids
.emplace();
693 for (lldb::tid_t tid
: tids
)
694 request
.tids
->push_back(tid
);
695 return Trace::Start(toJSON(request
));
698 Error
TraceIntelPT::Start(llvm::ArrayRef
<lldb::tid_t
> tids
,
699 StructuredData::ObjectSP configuration
) {
700 uint64_t ipt_trace_size
= kDefaultIptTraceSize
;
701 bool enable_tsc
= kDefaultEnableTscValue
;
702 std::optional
<uint64_t> psb_period
= kDefaultPsbPeriod
;
705 if (StructuredData::Dictionary
*dict
= configuration
->GetAsDictionary()) {
706 llvm::StringRef ipt_trace_size_not_parsed
;
707 if (dict
->GetValueForKeyAsString("iptTraceSize",
708 ipt_trace_size_not_parsed
)) {
709 if (std::optional
<uint64_t> bytes
=
710 ParsingUtils::ParseUserFriendlySizeExpression(
711 ipt_trace_size_not_parsed
))
712 ipt_trace_size
= *bytes
;
714 return createStringError(inconvertibleErrorCode(),
715 "iptTraceSize is wrong bytes expression");
717 dict
->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size
);
720 dict
->GetValueForKeyAsBoolean("enableTsc", enable_tsc
);
721 dict
->GetValueForKeyAsInteger("psbPeriod", psb_period
);
723 return createStringError(inconvertibleErrorCode(),
724 "configuration object is not a dictionary");
728 return Start(tids
, ipt_trace_size
, enable_tsc
, psb_period
);
731 Error
TraceIntelPT::OnThreadBufferRead(lldb::tid_t tid
,
732 OnBinaryDataReadCallback callback
) {
733 return OnThreadBinaryDataRead(tid
, IntelPTDataKinds::kIptTrace
, callback
);
736 TaskTimer
&TraceIntelPT::GetTimer() { return GetUpdatedStorage().task_timer
; }
738 ScopedTaskTimer
&TraceIntelPT::GetThreadTimer(lldb::tid_t tid
) {
739 return GetTimer().ForThread(tid
);
742 ScopedTaskTimer
&TraceIntelPT::GetGlobalTimer() {
743 return GetTimer().ForGlobal();