xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1e8d8bef9SDimitry Andric //===-- TraceIntelPT.cpp --------------------------------------------------===//
2e8d8bef9SDimitry Andric //
3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e8d8bef9SDimitry Andric //
7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8e8d8bef9SDimitry Andric 
9e8d8bef9SDimitry Andric #include "TraceIntelPT.h"
10e8d8bef9SDimitry Andric 
11fe6060f1SDimitry Andric #include "../common/ThreadPostMortemTrace.h"
12e8d8bef9SDimitry Andric #include "CommandObjectTraceStartIntelPT.h"
13fe6060f1SDimitry Andric #include "DecodedThread.h"
14*bdd1243dSDimitry Andric #include "TraceCursorIntelPT.h"
1581ad6265SDimitry Andric #include "TraceIntelPTBundleLoader.h"
1681ad6265SDimitry Andric #include "TraceIntelPTBundleSaver.h"
17*bdd1243dSDimitry Andric #include "TraceIntelPTConstants.h"
18e8d8bef9SDimitry Andric #include "lldb/Core/PluginManager.h"
19*bdd1243dSDimitry Andric #include "lldb/Interpreter/OptionValueProperties.h"
20e8d8bef9SDimitry Andric #include "lldb/Target/Process.h"
21e8d8bef9SDimitry Andric #include "lldb/Target/Target.h"
22*bdd1243dSDimitry Andric #include <optional>
23e8d8bef9SDimitry Andric 
24e8d8bef9SDimitry Andric using namespace lldb;
25e8d8bef9SDimitry Andric using namespace lldb_private;
26e8d8bef9SDimitry Andric using namespace lldb_private::trace_intel_pt;
27e8d8bef9SDimitry Andric using namespace llvm;
28e8d8bef9SDimitry Andric 
29e8d8bef9SDimitry Andric LLDB_PLUGIN_DEFINE(TraceIntelPT)
30e8d8bef9SDimitry Andric 
31fe6060f1SDimitry Andric lldb::CommandObjectSP
32fe6060f1SDimitry Andric TraceIntelPT::GetProcessTraceStartCommand(CommandInterpreter &interpreter) {
33fe6060f1SDimitry Andric   return CommandObjectSP(
34fe6060f1SDimitry Andric       new CommandObjectProcessTraceStartIntelPT(*this, interpreter));
35fe6060f1SDimitry Andric }
36fe6060f1SDimitry Andric 
37fe6060f1SDimitry Andric lldb::CommandObjectSP
38fe6060f1SDimitry Andric TraceIntelPT::GetThreadTraceStartCommand(CommandInterpreter &interpreter) {
39fe6060f1SDimitry Andric   return CommandObjectSP(
40fe6060f1SDimitry Andric       new CommandObjectThreadTraceStartIntelPT(*this, interpreter));
41e8d8bef9SDimitry Andric }
42e8d8bef9SDimitry Andric 
43*bdd1243dSDimitry Andric #define LLDB_PROPERTIES_traceintelpt
44*bdd1243dSDimitry Andric #include "TraceIntelPTProperties.inc"
45*bdd1243dSDimitry Andric 
46*bdd1243dSDimitry Andric enum {
47*bdd1243dSDimitry Andric #define LLDB_PROPERTIES_traceintelpt
48*bdd1243dSDimitry Andric #include "TraceIntelPTPropertiesEnum.inc"
49*bdd1243dSDimitry Andric };
50*bdd1243dSDimitry Andric 
51*bdd1243dSDimitry Andric ConstString TraceIntelPT::PluginProperties::GetSettingName() {
52*bdd1243dSDimitry Andric   return ConstString(TraceIntelPT::GetPluginNameStatic());
53*bdd1243dSDimitry Andric }
54*bdd1243dSDimitry Andric 
55*bdd1243dSDimitry Andric TraceIntelPT::PluginProperties::PluginProperties() : Properties() {
56*bdd1243dSDimitry Andric   m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
57*bdd1243dSDimitry Andric   m_collection_sp->Initialize(g_traceintelpt_properties);
58*bdd1243dSDimitry Andric }
59*bdd1243dSDimitry Andric 
60*bdd1243dSDimitry Andric uint64_t
61*bdd1243dSDimitry Andric TraceIntelPT::PluginProperties::GetInfiniteDecodingLoopVerificationThreshold() {
62*bdd1243dSDimitry Andric   const uint32_t idx = ePropertyInfiniteDecodingLoopVerificationThreshold;
63*bdd1243dSDimitry Andric   return m_collection_sp->GetPropertyAtIndexAsUInt64(
64*bdd1243dSDimitry Andric       nullptr, idx, g_traceintelpt_properties[idx].default_uint_value);
65*bdd1243dSDimitry Andric }
66*bdd1243dSDimitry Andric 
67*bdd1243dSDimitry Andric uint64_t TraceIntelPT::PluginProperties::GetExtremelyLargeDecodingThreshold() {
68*bdd1243dSDimitry Andric   const uint32_t idx = ePropertyExtremelyLargeDecodingThreshold;
69*bdd1243dSDimitry Andric   return m_collection_sp->GetPropertyAtIndexAsUInt64(
70*bdd1243dSDimitry Andric       nullptr, idx, g_traceintelpt_properties[idx].default_uint_value);
71*bdd1243dSDimitry Andric }
72*bdd1243dSDimitry Andric 
73*bdd1243dSDimitry Andric TraceIntelPT::PluginProperties &TraceIntelPT::GetGlobalProperties() {
74*bdd1243dSDimitry Andric   static TraceIntelPT::PluginProperties g_settings;
75*bdd1243dSDimitry Andric   return g_settings;
76*bdd1243dSDimitry Andric }
77*bdd1243dSDimitry Andric 
78e8d8bef9SDimitry Andric void TraceIntelPT::Initialize() {
79*bdd1243dSDimitry Andric   PluginManager::RegisterPlugin(
80*bdd1243dSDimitry Andric       GetPluginNameStatic(), "Intel Processor Trace",
81*bdd1243dSDimitry Andric       CreateInstanceForTraceBundle, CreateInstanceForLiveProcess,
82*bdd1243dSDimitry Andric       TraceIntelPTBundleLoader::GetSchema(), DebuggerInitialize);
83*bdd1243dSDimitry Andric }
84*bdd1243dSDimitry Andric 
85*bdd1243dSDimitry Andric void TraceIntelPT::DebuggerInitialize(Debugger &debugger) {
86*bdd1243dSDimitry Andric   if (!PluginManager::GetSettingForProcessPlugin(
87*bdd1243dSDimitry Andric           debugger, PluginProperties::GetSettingName())) {
88*bdd1243dSDimitry Andric     const bool is_global_setting = true;
89*bdd1243dSDimitry Andric     PluginManager::CreateSettingForTracePlugin(
90*bdd1243dSDimitry Andric         debugger, GetGlobalProperties().GetValueProperties(),
91*bdd1243dSDimitry Andric         ConstString("Properties for the intel-pt trace plug-in."),
92*bdd1243dSDimitry Andric         is_global_setting);
93*bdd1243dSDimitry Andric   }
94e8d8bef9SDimitry Andric }
95e8d8bef9SDimitry Andric 
96e8d8bef9SDimitry Andric void TraceIntelPT::Terminate() {
9781ad6265SDimitry Andric   PluginManager::UnregisterPlugin(CreateInstanceForTraceBundle);
98e8d8bef9SDimitry Andric }
99e8d8bef9SDimitry Andric 
100e8d8bef9SDimitry Andric StringRef TraceIntelPT::GetSchema() {
10181ad6265SDimitry Andric   return TraceIntelPTBundleLoader::GetSchema();
102e8d8bef9SDimitry Andric }
103e8d8bef9SDimitry Andric 
104e8d8bef9SDimitry Andric void TraceIntelPT::Dump(Stream *s) const {}
105e8d8bef9SDimitry Andric 
106753f127fSDimitry Andric Expected<FileSpec> TraceIntelPT::SaveToDisk(FileSpec directory, bool compact) {
107349cc55cSDimitry Andric   RefreshLiveProcessState();
108753f127fSDimitry Andric   return TraceIntelPTBundleSaver().SaveToDisk(*this, directory, compact);
109349cc55cSDimitry Andric }
110349cc55cSDimitry Andric 
11181ad6265SDimitry Andric Expected<TraceSP> TraceIntelPT::CreateInstanceForTraceBundle(
11281ad6265SDimitry Andric     const json::Value &bundle_description, StringRef bundle_dir,
113fe6060f1SDimitry Andric     Debugger &debugger) {
114*bdd1243dSDimitry Andric   return TraceIntelPTBundleLoader(debugger, bundle_description, bundle_dir)
11581ad6265SDimitry Andric       .Load();
116e8d8bef9SDimitry Andric }
117e8d8bef9SDimitry Andric 
118fe6060f1SDimitry Andric Expected<TraceSP> TraceIntelPT::CreateInstanceForLiveProcess(Process &process) {
119fe6060f1SDimitry Andric   TraceSP instance(new TraceIntelPT(process));
120fe6060f1SDimitry Andric   process.GetTarget().SetTrace(instance);
121fe6060f1SDimitry Andric   return instance;
122fe6060f1SDimitry Andric }
123fe6060f1SDimitry Andric 
12481ad6265SDimitry Andric TraceIntelPTSP TraceIntelPT::GetSharedPtr() {
12581ad6265SDimitry Andric   return std::static_pointer_cast<TraceIntelPT>(shared_from_this());
126e8d8bef9SDimitry Andric }
127e8d8bef9SDimitry Andric 
128*bdd1243dSDimitry Andric TraceIntelPT::TraceMode TraceIntelPT::GetTraceMode() { return trace_mode; }
129*bdd1243dSDimitry Andric 
13081ad6265SDimitry Andric TraceIntelPTSP TraceIntelPT::CreateInstanceForPostmortemTrace(
131*bdd1243dSDimitry Andric     JSONTraceBundleDescription &bundle_description,
132*bdd1243dSDimitry Andric     ArrayRef<ProcessSP> traced_processes,
133*bdd1243dSDimitry Andric     ArrayRef<ThreadPostMortemTraceSP> traced_threads, TraceMode trace_mode) {
134*bdd1243dSDimitry Andric   TraceIntelPTSP trace_sp(
135*bdd1243dSDimitry Andric       new TraceIntelPT(bundle_description, traced_processes, trace_mode));
136*bdd1243dSDimitry Andric   trace_sp->m_storage.tsc_conversion =
137*bdd1243dSDimitry Andric       bundle_description.tsc_perf_zero_conversion;
138fe6060f1SDimitry Andric 
13981ad6265SDimitry Andric   if (bundle_description.cpus) {
14081ad6265SDimitry Andric     std::vector<cpu_id_t> cpus;
14181ad6265SDimitry Andric 
14281ad6265SDimitry Andric     for (const JSONCpu &cpu : *bundle_description.cpus) {
14381ad6265SDimitry Andric       trace_sp->SetPostMortemCpuDataFile(cpu.id, IntelPTDataKinds::kIptTrace,
14481ad6265SDimitry Andric                                          FileSpec(cpu.ipt_trace));
14581ad6265SDimitry Andric 
14681ad6265SDimitry Andric       trace_sp->SetPostMortemCpuDataFile(
14781ad6265SDimitry Andric           cpu.id, IntelPTDataKinds::kPerfContextSwitchTrace,
14881ad6265SDimitry Andric           FileSpec(cpu.context_switch_trace));
14981ad6265SDimitry Andric       cpus.push_back(cpu.id);
15081ad6265SDimitry Andric     }
15181ad6265SDimitry Andric 
152*bdd1243dSDimitry Andric     if (trace_mode == TraceMode::UserMode) {
15381ad6265SDimitry Andric       trace_sp->m_storage.multicpu_decoder.emplace(trace_sp);
154*bdd1243dSDimitry Andric     }
155*bdd1243dSDimitry Andric   }
156*bdd1243dSDimitry Andric 
157*bdd1243dSDimitry Andric   if (!bundle_description.cpus || trace_mode == TraceMode::KernelMode) {
15881ad6265SDimitry Andric     for (const ThreadPostMortemTraceSP &thread : traced_threads) {
15981ad6265SDimitry Andric       trace_sp->m_storage.thread_decoders.try_emplace(
16081ad6265SDimitry Andric           thread->GetID(), std::make_unique<ThreadDecoder>(thread, *trace_sp));
161*bdd1243dSDimitry Andric       if (const std::optional<FileSpec> &trace_file = thread->GetTraceFile()) {
16281ad6265SDimitry Andric         trace_sp->SetPostMortemThreadDataFile(
16381ad6265SDimitry Andric             thread->GetID(), IntelPTDataKinds::kIptTrace, *trace_file);
16481ad6265SDimitry Andric       }
16581ad6265SDimitry Andric     }
16681ad6265SDimitry Andric   }
16781ad6265SDimitry Andric 
16881ad6265SDimitry Andric   for (const ProcessSP &process_sp : traced_processes)
16981ad6265SDimitry Andric     process_sp->GetTarget().SetTrace(trace_sp);
17081ad6265SDimitry Andric   return trace_sp;
17181ad6265SDimitry Andric }
17281ad6265SDimitry Andric 
17381ad6265SDimitry Andric TraceIntelPT::TraceIntelPT(JSONTraceBundleDescription &bundle_description,
174*bdd1243dSDimitry Andric                            ArrayRef<ProcessSP> traced_processes,
175*bdd1243dSDimitry Andric                            TraceMode trace_mode)
17681ad6265SDimitry Andric     : Trace(traced_processes, bundle_description.GetCpuIds()),
177*bdd1243dSDimitry Andric       m_cpu_info(bundle_description.cpu_info), trace_mode(trace_mode) {}
17881ad6265SDimitry Andric 
17981ad6265SDimitry Andric Expected<DecodedThreadSP> TraceIntelPT::Decode(Thread &thread) {
18081ad6265SDimitry Andric   if (const char *error = RefreshLiveProcessState())
18181ad6265SDimitry Andric     return createStringError(inconvertibleErrorCode(), error);
18281ad6265SDimitry Andric 
18381ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
18481ad6265SDimitry Andric   if (storage.multicpu_decoder)
18581ad6265SDimitry Andric     return storage.multicpu_decoder->Decode(thread);
18681ad6265SDimitry Andric 
18781ad6265SDimitry Andric   auto it = storage.thread_decoders.find(thread.GetID());
18881ad6265SDimitry Andric   if (it == storage.thread_decoders.end())
18981ad6265SDimitry Andric     return createStringError(inconvertibleErrorCode(), "thread not traced");
190fe6060f1SDimitry Andric   return it->second->Decode();
191e8d8bef9SDimitry Andric }
192e8d8bef9SDimitry Andric 
193*bdd1243dSDimitry Andric Expected<std::optional<uint64_t>> TraceIntelPT::FindBeginningOfTimeNanos() {
194972a253aSDimitry Andric   Storage &storage = GetUpdatedStorage();
195972a253aSDimitry Andric   if (storage.beginning_of_time_nanos_calculated)
196972a253aSDimitry Andric     return storage.beginning_of_time_nanos;
197972a253aSDimitry Andric   storage.beginning_of_time_nanos_calculated = true;
198972a253aSDimitry Andric 
199972a253aSDimitry Andric   if (!storage.tsc_conversion)
200*bdd1243dSDimitry Andric     return std::nullopt;
201972a253aSDimitry Andric 
202*bdd1243dSDimitry Andric   std::optional<uint64_t> lowest_tsc;
203972a253aSDimitry Andric 
204972a253aSDimitry Andric   if (storage.multicpu_decoder) {
205*bdd1243dSDimitry Andric     if (Expected<std::optional<uint64_t>> tsc =
206972a253aSDimitry Andric             storage.multicpu_decoder->FindLowestTSC()) {
207972a253aSDimitry Andric       lowest_tsc = *tsc;
208972a253aSDimitry Andric     } else {
209972a253aSDimitry Andric       return tsc.takeError();
210972a253aSDimitry Andric     }
211972a253aSDimitry Andric   }
212972a253aSDimitry Andric 
213972a253aSDimitry Andric   for (auto &decoder : storage.thread_decoders) {
214*bdd1243dSDimitry Andric     Expected<std::optional<uint64_t>> tsc = decoder.second->FindLowestTSC();
215972a253aSDimitry Andric     if (!tsc)
216972a253aSDimitry Andric       return tsc.takeError();
217972a253aSDimitry Andric 
218972a253aSDimitry Andric     if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))
219972a253aSDimitry Andric       lowest_tsc = **tsc;
220972a253aSDimitry Andric   }
221972a253aSDimitry Andric 
222972a253aSDimitry Andric   if (lowest_tsc) {
223972a253aSDimitry Andric     storage.beginning_of_time_nanos =
224972a253aSDimitry Andric         storage.tsc_conversion->ToNanos(*lowest_tsc);
225972a253aSDimitry Andric   }
226972a253aSDimitry Andric   return storage.beginning_of_time_nanos;
227972a253aSDimitry Andric }
228972a253aSDimitry Andric 
229*bdd1243dSDimitry Andric llvm::Expected<lldb::TraceCursorSP>
23081ad6265SDimitry Andric TraceIntelPT::CreateNewCursor(Thread &thread) {
231972a253aSDimitry Andric   if (Expected<DecodedThreadSP> decoded_thread = Decode(thread)) {
232*bdd1243dSDimitry Andric     if (Expected<std::optional<uint64_t>> beginning_of_time =
233972a253aSDimitry Andric             FindBeginningOfTimeNanos())
234*bdd1243dSDimitry Andric       return std::make_shared<TraceCursorIntelPT>(
235972a253aSDimitry Andric           thread.shared_from_this(), *decoded_thread, m_storage.tsc_conversion,
236972a253aSDimitry Andric           *beginning_of_time);
23781ad6265SDimitry Andric     else
238972a253aSDimitry Andric       return beginning_of_time.takeError();
239972a253aSDimitry Andric   } else
24081ad6265SDimitry Andric     return decoded_thread.takeError();
241e8d8bef9SDimitry Andric }
242e8d8bef9SDimitry Andric 
243753f127fSDimitry Andric void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose,
244753f127fSDimitry Andric                                  bool json) {
24581ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
24681ad6265SDimitry Andric 
24781ad6265SDimitry Andric   lldb::tid_t tid = thread.GetID();
248753f127fSDimitry Andric   if (json) {
249753f127fSDimitry Andric     DumpTraceInfoAsJson(thread, s, verbose);
250753f127fSDimitry Andric     return;
251753f127fSDimitry Andric   }
252753f127fSDimitry Andric 
25381ad6265SDimitry Andric   s.Format("\nthread #{0}: tid = {1}", thread.GetIndexID(), thread.GetID());
25481ad6265SDimitry Andric   if (!IsTraced(tid)) {
25581ad6265SDimitry Andric     s << ", not traced\n";
256e8d8bef9SDimitry Andric     return;
257fe6060f1SDimitry Andric   }
25881ad6265SDimitry Andric   s << "\n";
25981ad6265SDimitry Andric 
26081ad6265SDimitry Andric   Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread);
26181ad6265SDimitry Andric   if (!decoded_thread_sp_or_err) {
26281ad6265SDimitry Andric     s << toString(decoded_thread_sp_or_err.takeError()) << "\n";
263fe6060f1SDimitry Andric     return;
264e8d8bef9SDimitry Andric   }
265e8d8bef9SDimitry Andric 
26681ad6265SDimitry Andric   DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err;
26781ad6265SDimitry Andric 
268*bdd1243dSDimitry Andric   Expected<std::optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread);
26981ad6265SDimitry Andric   if (!raw_size_or_error) {
27081ad6265SDimitry Andric     s.Format("  {0}\n", toString(raw_size_or_error.takeError()));
27181ad6265SDimitry Andric     return;
27281ad6265SDimitry Andric   }
273*bdd1243dSDimitry Andric   std::optional<uint64_t> raw_size = *raw_size_or_error;
27481ad6265SDimitry Andric 
275753f127fSDimitry Andric   s.Format("\n  Trace technology: {0}\n", GetPluginName());
276753f127fSDimitry Andric 
27781ad6265SDimitry Andric   /// Instruction stats
27881ad6265SDimitry Andric   {
27981ad6265SDimitry Andric     uint64_t items_count = decoded_thread_sp->GetItemsCount();
28081ad6265SDimitry Andric     uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage();
28181ad6265SDimitry Andric 
282753f127fSDimitry Andric     s.Format("\n  Total number of trace items: {0}\n", items_count);
28381ad6265SDimitry Andric 
28481ad6265SDimitry Andric     s << "\n  Memory usage:\n";
28581ad6265SDimitry Andric     if (raw_size)
28681ad6265SDimitry Andric       s.Format("    Raw trace size: {0} KiB\n", *raw_size / 1024);
28781ad6265SDimitry Andric 
28881ad6265SDimitry Andric     s.Format(
28981ad6265SDimitry Andric         "    Total approximate memory usage (excluding raw trace): {0:2} KiB\n",
29081ad6265SDimitry Andric         (double)mem_used / 1024);
29181ad6265SDimitry Andric     if (items_count != 0)
29281ad6265SDimitry Andric       s.Format("    Average memory usage per item (excluding raw trace): "
29381ad6265SDimitry Andric                "{0:2} bytes\n",
29481ad6265SDimitry Andric                (double)mem_used / items_count);
29581ad6265SDimitry Andric   }
29681ad6265SDimitry Andric 
29781ad6265SDimitry Andric   // Timing
29881ad6265SDimitry Andric   {
29981ad6265SDimitry Andric     s << "\n  Timing for this thread:\n";
30081ad6265SDimitry Andric     auto print_duration = [&](const std::string &name,
30181ad6265SDimitry Andric                               std::chrono::milliseconds duration) {
30281ad6265SDimitry Andric       s.Format("    {0}: {1:2}s\n", name, duration.count() / 1000.0);
30381ad6265SDimitry Andric     };
304753f127fSDimitry Andric     GetThreadTimer(tid).ForEachTimedTask(print_duration);
30581ad6265SDimitry Andric 
30681ad6265SDimitry Andric     s << "\n  Timing for global tasks:\n";
307753f127fSDimitry Andric     GetGlobalTimer().ForEachTimedTask(print_duration);
30881ad6265SDimitry Andric   }
30981ad6265SDimitry Andric 
31081ad6265SDimitry Andric   // Instruction events stats
31181ad6265SDimitry Andric   {
31281ad6265SDimitry Andric     const DecodedThread::EventsStats &events_stats =
31381ad6265SDimitry Andric         decoded_thread_sp->GetEventsStats();
31481ad6265SDimitry Andric     s << "\n  Events:\n";
31581ad6265SDimitry Andric     s.Format("    Number of individual events: {0}\n",
31681ad6265SDimitry Andric              events_stats.total_count);
31781ad6265SDimitry Andric     for (const auto &event_to_count : events_stats.events_counts) {
31881ad6265SDimitry Andric       s.Format("      {0}: {1}\n",
31981ad6265SDimitry Andric                TraceCursor::EventKindToString(event_to_count.first),
32081ad6265SDimitry Andric                event_to_count.second);
32181ad6265SDimitry Andric     }
32281ad6265SDimitry Andric   }
323*bdd1243dSDimitry Andric   // Trace error stats
324*bdd1243dSDimitry Andric   {
325*bdd1243dSDimitry Andric     const DecodedThread::ErrorStats &error_stats =
326*bdd1243dSDimitry Andric         decoded_thread_sp->GetErrorStats();
327*bdd1243dSDimitry Andric     s << "\n  Errors:\n";
328*bdd1243dSDimitry Andric     s.Format("    Number of individual errors: {0}\n",
329*bdd1243dSDimitry Andric              error_stats.GetTotalCount());
330*bdd1243dSDimitry Andric     s.Format("      Number of fatal errors: {0}\n", error_stats.fatal_errors);
331*bdd1243dSDimitry Andric     for (const auto &[kind, count] : error_stats.libipt_errors) {
332*bdd1243dSDimitry Andric       s.Format("     Number of libipt errors of kind [{0}]: {1}\n", kind,
333*bdd1243dSDimitry Andric                count);
334*bdd1243dSDimitry Andric     }
335*bdd1243dSDimitry Andric     s.Format("      Number of other errors: {0}\n", error_stats.other_errors);
336*bdd1243dSDimitry Andric   }
33781ad6265SDimitry Andric 
33881ad6265SDimitry Andric   if (storage.multicpu_decoder) {
33981ad6265SDimitry Andric     s << "\n  Multi-cpu decoding:\n";
34081ad6265SDimitry Andric     s.Format("    Total number of continuous executions found: {0}\n",
34181ad6265SDimitry Andric              storage.multicpu_decoder->GetTotalContinuousExecutionsCount());
34281ad6265SDimitry Andric     s.Format(
34381ad6265SDimitry Andric         "    Number of continuous executions for this thread: {0}\n",
34481ad6265SDimitry Andric         storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid));
345753f127fSDimitry Andric     s.Format("    Total number of PSB blocks found: {0}\n",
346753f127fSDimitry Andric              storage.multicpu_decoder->GetTotalPSBBlocksCount());
347753f127fSDimitry Andric     s.Format("    Number of PSB blocks for this thread: {0}\n",
348753f127fSDimitry Andric              storage.multicpu_decoder->GePSBBlocksCountForThread(tid));
349753f127fSDimitry Andric     s.Format("    Total number of unattributed PSB blocks found: {0}\n",
350753f127fSDimitry Andric              storage.multicpu_decoder->GetUnattributedPSBBlocksCount());
35181ad6265SDimitry Andric   }
35281ad6265SDimitry Andric }
35381ad6265SDimitry Andric 
354753f127fSDimitry Andric void TraceIntelPT::DumpTraceInfoAsJson(Thread &thread, Stream &s,
355753f127fSDimitry Andric                                        bool verbose) {
356753f127fSDimitry Andric   Storage &storage = GetUpdatedStorage();
357753f127fSDimitry Andric 
358753f127fSDimitry Andric   lldb::tid_t tid = thread.GetID();
359753f127fSDimitry Andric   json::OStream json_str(s.AsRawOstream(), 2);
360753f127fSDimitry Andric   if (!IsTraced(tid)) {
361753f127fSDimitry Andric     s << "error: thread not traced\n";
362753f127fSDimitry Andric     return;
363753f127fSDimitry Andric   }
364753f127fSDimitry Andric 
365*bdd1243dSDimitry Andric   Expected<std::optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread);
366753f127fSDimitry Andric   if (!raw_size_or_error) {
367753f127fSDimitry Andric     s << "error: " << toString(raw_size_or_error.takeError()) << "\n";
368753f127fSDimitry Andric     return;
369753f127fSDimitry Andric   }
370753f127fSDimitry Andric 
371753f127fSDimitry Andric   Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread);
372753f127fSDimitry Andric   if (!decoded_thread_sp_or_err) {
373753f127fSDimitry Andric     s << "error: " << toString(decoded_thread_sp_or_err.takeError()) << "\n";
374753f127fSDimitry Andric     return;
375753f127fSDimitry Andric   }
376753f127fSDimitry Andric   DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err;
377753f127fSDimitry Andric 
378753f127fSDimitry Andric   json_str.object([&] {
379753f127fSDimitry Andric     json_str.attribute("traceTechnology", "intel-pt");
380753f127fSDimitry Andric     json_str.attributeObject("threadStats", [&] {
381753f127fSDimitry Andric       json_str.attribute("tid", tid);
382753f127fSDimitry Andric 
383753f127fSDimitry Andric       uint64_t insn_len = decoded_thread_sp->GetItemsCount();
384753f127fSDimitry Andric       json_str.attribute("traceItemsCount", insn_len);
385753f127fSDimitry Andric 
386753f127fSDimitry Andric       // Instruction stats
387753f127fSDimitry Andric       uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage();
388753f127fSDimitry Andric       json_str.attributeObject("memoryUsage", [&] {
389753f127fSDimitry Andric         json_str.attribute("totalInBytes", std::to_string(mem_used));
390*bdd1243dSDimitry Andric         std::optional<double> avg;
391753f127fSDimitry Andric         if (insn_len != 0)
392753f127fSDimitry Andric           avg = double(mem_used) / insn_len;
393753f127fSDimitry Andric         json_str.attribute("avgPerItemInBytes", avg);
394753f127fSDimitry Andric       });
395753f127fSDimitry Andric 
396753f127fSDimitry Andric       // Timing
397753f127fSDimitry Andric       json_str.attributeObject("timingInSeconds", [&] {
398753f127fSDimitry Andric         GetTimer().ForThread(tid).ForEachTimedTask(
399753f127fSDimitry Andric             [&](const std::string &name, std::chrono::milliseconds duration) {
400753f127fSDimitry Andric               json_str.attribute(name, duration.count() / 1000.0);
401753f127fSDimitry Andric             });
402753f127fSDimitry Andric       });
403753f127fSDimitry Andric 
404753f127fSDimitry Andric       // Instruction events stats
405753f127fSDimitry Andric       const DecodedThread::EventsStats &events_stats =
406753f127fSDimitry Andric           decoded_thread_sp->GetEventsStats();
407753f127fSDimitry Andric       json_str.attributeObject("events", [&] {
408753f127fSDimitry Andric         json_str.attribute("totalCount", events_stats.total_count);
409753f127fSDimitry Andric         json_str.attributeObject("individualCounts", [&] {
410753f127fSDimitry Andric           for (const auto &event_to_count : events_stats.events_counts) {
411753f127fSDimitry Andric             json_str.attribute(
412753f127fSDimitry Andric                 TraceCursor::EventKindToString(event_to_count.first),
413753f127fSDimitry Andric                 event_to_count.second);
414753f127fSDimitry Andric           }
415753f127fSDimitry Andric         });
416753f127fSDimitry Andric       });
417*bdd1243dSDimitry Andric       // Trace error stats
418*bdd1243dSDimitry Andric       const DecodedThread::ErrorStats &error_stats =
419*bdd1243dSDimitry Andric           decoded_thread_sp->GetErrorStats();
420*bdd1243dSDimitry Andric       json_str.attributeObject("errors", [&] {
421*bdd1243dSDimitry Andric         json_str.attribute("totalCount", error_stats.GetTotalCount());
422*bdd1243dSDimitry Andric         json_str.attributeObject("libiptErrors", [&] {
423*bdd1243dSDimitry Andric           for (const auto &[kind, count] : error_stats.libipt_errors) {
424*bdd1243dSDimitry Andric             json_str.attribute(kind, count);
425*bdd1243dSDimitry Andric           }
426*bdd1243dSDimitry Andric         });
427*bdd1243dSDimitry Andric         json_str.attribute("fatalErrors", error_stats.fatal_errors);
428*bdd1243dSDimitry Andric         json_str.attribute("otherErrors", error_stats.other_errors);
429*bdd1243dSDimitry Andric       });
430753f127fSDimitry Andric 
431753f127fSDimitry Andric       if (storage.multicpu_decoder) {
432753f127fSDimitry Andric         json_str.attribute(
433753f127fSDimitry Andric             "continuousExecutions",
434753f127fSDimitry Andric             storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid));
435753f127fSDimitry Andric         json_str.attribute(
436753f127fSDimitry Andric             "PSBBlocks",
437753f127fSDimitry Andric             storage.multicpu_decoder->GePSBBlocksCountForThread(tid));
438753f127fSDimitry Andric       }
439*bdd1243dSDimitry Andric     });
440753f127fSDimitry Andric 
441753f127fSDimitry Andric     json_str.attributeObject("globalStats", [&] {
442753f127fSDimitry Andric       json_str.attributeObject("timingInSeconds", [&] {
443753f127fSDimitry Andric         GetTimer().ForGlobal().ForEachTimedTask(
444753f127fSDimitry Andric             [&](const std::string &name, std::chrono::milliseconds duration) {
445753f127fSDimitry Andric               json_str.attribute(name, duration.count() / 1000.0);
446753f127fSDimitry Andric             });
447753f127fSDimitry Andric       });
448753f127fSDimitry Andric       if (storage.multicpu_decoder) {
449753f127fSDimitry Andric         json_str.attribute(
450753f127fSDimitry Andric             "totalUnattributedPSBBlocks",
451753f127fSDimitry Andric             storage.multicpu_decoder->GetUnattributedPSBBlocksCount());
452753f127fSDimitry Andric         json_str.attribute(
453753f127fSDimitry Andric             "totalCountinuosExecutions",
454753f127fSDimitry Andric             storage.multicpu_decoder->GetTotalContinuousExecutionsCount());
455753f127fSDimitry Andric         json_str.attribute("totalPSBBlocks",
456753f127fSDimitry Andric                            storage.multicpu_decoder->GetTotalPSBBlocksCount());
457753f127fSDimitry Andric         json_str.attribute(
458753f127fSDimitry Andric             "totalContinuousExecutions",
459753f127fSDimitry Andric             storage.multicpu_decoder->GetTotalContinuousExecutionsCount());
460753f127fSDimitry Andric       }
461753f127fSDimitry Andric     });
462753f127fSDimitry Andric   });
463753f127fSDimitry Andric }
464753f127fSDimitry Andric 
465*bdd1243dSDimitry Andric llvm::Expected<std::optional<uint64_t>>
46681ad6265SDimitry Andric TraceIntelPT::GetRawTraceSize(Thread &thread) {
46781ad6265SDimitry Andric   if (GetUpdatedStorage().multicpu_decoder)
468*bdd1243dSDimitry Andric     return std::nullopt; // TODO: calculate the amount of intel pt raw trace associated
46981ad6265SDimitry Andric                  // with the given thread.
47081ad6265SDimitry Andric   if (GetLiveProcess())
47181ad6265SDimitry Andric     return GetLiveThreadBinaryDataSize(thread.GetID(),
47281ad6265SDimitry Andric                                        IntelPTDataKinds::kIptTrace);
47381ad6265SDimitry Andric   uint64_t size;
47481ad6265SDimitry Andric   auto callback = [&](llvm::ArrayRef<uint8_t> data) {
47581ad6265SDimitry Andric     size = data.size();
47681ad6265SDimitry Andric     return Error::success();
47781ad6265SDimitry Andric   };
47881ad6265SDimitry Andric   if (Error err = OnThreadBufferRead(thread.GetID(), callback))
47981ad6265SDimitry Andric     return std::move(err);
48081ad6265SDimitry Andric 
48181ad6265SDimitry Andric   return size;
482fe6060f1SDimitry Andric }
483fe6060f1SDimitry Andric 
484fe6060f1SDimitry Andric Expected<pt_cpu> TraceIntelPT::GetCPUInfoForLiveProcess() {
48581ad6265SDimitry Andric   Expected<std::vector<uint8_t>> cpu_info =
48681ad6265SDimitry Andric       GetLiveProcessBinaryData(IntelPTDataKinds::kProcFsCpuInfo);
487fe6060f1SDimitry Andric   if (!cpu_info)
488fe6060f1SDimitry Andric     return cpu_info.takeError();
489fe6060f1SDimitry Andric 
490fe6060f1SDimitry Andric   int64_t cpu_family = -1;
491fe6060f1SDimitry Andric   int64_t model = -1;
492fe6060f1SDimitry Andric   int64_t stepping = -1;
493fe6060f1SDimitry Andric   std::string vendor_id;
494fe6060f1SDimitry Andric 
495fe6060f1SDimitry Andric   StringRef rest(reinterpret_cast<const char *>(cpu_info->data()),
496fe6060f1SDimitry Andric                  cpu_info->size());
497fe6060f1SDimitry Andric   while (!rest.empty()) {
498fe6060f1SDimitry Andric     StringRef line;
499fe6060f1SDimitry Andric     std::tie(line, rest) = rest.split('\n');
500fe6060f1SDimitry Andric 
501fe6060f1SDimitry Andric     SmallVector<StringRef, 2> columns;
502fe6060f1SDimitry Andric     line.split(columns, StringRef(":"), -1, false);
503fe6060f1SDimitry Andric 
504fe6060f1SDimitry Andric     if (columns.size() < 2)
505fe6060f1SDimitry Andric       continue; // continue searching
506fe6060f1SDimitry Andric 
507fe6060f1SDimitry Andric     columns[1] = columns[1].trim(" ");
508fe6060f1SDimitry Andric     if (columns[0].contains("cpu family") &&
509fe6060f1SDimitry Andric         columns[1].getAsInteger(10, cpu_family))
510fe6060f1SDimitry Andric       continue;
511fe6060f1SDimitry Andric 
512fe6060f1SDimitry Andric     else if (columns[0].contains("model") && columns[1].getAsInteger(10, model))
513fe6060f1SDimitry Andric       continue;
514fe6060f1SDimitry Andric 
515fe6060f1SDimitry Andric     else if (columns[0].contains("stepping") &&
516fe6060f1SDimitry Andric              columns[1].getAsInteger(10, stepping))
517fe6060f1SDimitry Andric       continue;
518fe6060f1SDimitry Andric 
519fe6060f1SDimitry Andric     else if (columns[0].contains("vendor_id")) {
520fe6060f1SDimitry Andric       vendor_id = columns[1].str();
521fe6060f1SDimitry Andric       if (!vendor_id.empty())
522fe6060f1SDimitry Andric         continue;
523fe6060f1SDimitry Andric     }
524fe6060f1SDimitry Andric 
525fe6060f1SDimitry Andric     if ((cpu_family != -1) && (model != -1) && (stepping != -1) &&
526fe6060f1SDimitry Andric         (!vendor_id.empty())) {
527fe6060f1SDimitry Andric       return pt_cpu{vendor_id == "GenuineIntel" ? pcv_intel : pcv_unknown,
528fe6060f1SDimitry Andric                     static_cast<uint16_t>(cpu_family),
529fe6060f1SDimitry Andric                     static_cast<uint8_t>(model),
530fe6060f1SDimitry Andric                     static_cast<uint8_t>(stepping)};
531fe6060f1SDimitry Andric     }
532fe6060f1SDimitry Andric   }
533fe6060f1SDimitry Andric   return createStringError(inconvertibleErrorCode(),
534fe6060f1SDimitry Andric                            "Failed parsing the target's /proc/cpuinfo file");
535fe6060f1SDimitry Andric }
536fe6060f1SDimitry Andric 
537fe6060f1SDimitry Andric Expected<pt_cpu> TraceIntelPT::GetCPUInfo() {
538fe6060f1SDimitry Andric   if (!m_cpu_info) {
539fe6060f1SDimitry Andric     if (llvm::Expected<pt_cpu> cpu_info = GetCPUInfoForLiveProcess())
540fe6060f1SDimitry Andric       m_cpu_info = *cpu_info;
541fe6060f1SDimitry Andric     else
542fe6060f1SDimitry Andric       return cpu_info.takeError();
543fe6060f1SDimitry Andric   }
544fe6060f1SDimitry Andric   return *m_cpu_info;
545fe6060f1SDimitry Andric }
546fe6060f1SDimitry Andric 
547*bdd1243dSDimitry Andric std::optional<LinuxPerfZeroTscConversion>
54881ad6265SDimitry Andric TraceIntelPT::GetPerfZeroTscConversion() {
54981ad6265SDimitry Andric   return GetUpdatedStorage().tsc_conversion;
550fe6060f1SDimitry Andric }
551fe6060f1SDimitry Andric 
55281ad6265SDimitry Andric TraceIntelPT::Storage &TraceIntelPT::GetUpdatedStorage() {
55381ad6265SDimitry Andric   RefreshLiveProcessState();
55481ad6265SDimitry Andric   return m_storage;
555fe6060f1SDimitry Andric }
55681ad6265SDimitry Andric 
55781ad6265SDimitry Andric Error TraceIntelPT::DoRefreshLiveProcessState(TraceGetStateResponse state,
55881ad6265SDimitry Andric                                               StringRef json_response) {
55981ad6265SDimitry Andric   m_storage = Storage();
56081ad6265SDimitry Andric 
56181ad6265SDimitry Andric   Expected<TraceIntelPTGetStateResponse> intelpt_state =
56281ad6265SDimitry Andric       json::parse<TraceIntelPTGetStateResponse>(json_response,
56381ad6265SDimitry Andric                                                 "TraceIntelPTGetStateResponse");
56481ad6265SDimitry Andric   if (!intelpt_state)
56581ad6265SDimitry Andric     return intelpt_state.takeError();
56681ad6265SDimitry Andric 
56781ad6265SDimitry Andric   m_storage.tsc_conversion = intelpt_state->tsc_perf_zero_conversion;
56881ad6265SDimitry Andric 
56981ad6265SDimitry Andric   if (!intelpt_state->cpus) {
57081ad6265SDimitry Andric     for (const TraceThreadState &thread_state : state.traced_threads) {
57181ad6265SDimitry Andric       ThreadSP thread_sp =
57281ad6265SDimitry Andric           GetLiveProcess()->GetThreadList().FindThreadByID(thread_state.tid);
57381ad6265SDimitry Andric       m_storage.thread_decoders.try_emplace(
57481ad6265SDimitry Andric           thread_state.tid, std::make_unique<ThreadDecoder>(thread_sp, *this));
57581ad6265SDimitry Andric     }
57681ad6265SDimitry Andric   } else {
57781ad6265SDimitry Andric     std::vector<cpu_id_t> cpus;
57881ad6265SDimitry Andric     for (const TraceCpuState &cpu : *intelpt_state->cpus)
57981ad6265SDimitry Andric       cpus.push_back(cpu.id);
58081ad6265SDimitry Andric 
58181ad6265SDimitry Andric     std::vector<tid_t> tids;
58281ad6265SDimitry Andric     for (const TraceThreadState &thread : intelpt_state->traced_threads)
58381ad6265SDimitry Andric       tids.push_back(thread.tid);
58481ad6265SDimitry Andric 
58581ad6265SDimitry Andric     if (!intelpt_state->tsc_perf_zero_conversion)
58681ad6265SDimitry Andric       return createStringError(inconvertibleErrorCode(),
58781ad6265SDimitry Andric                                "Missing perf time_zero conversion values");
58881ad6265SDimitry Andric     m_storage.multicpu_decoder.emplace(GetSharedPtr());
58981ad6265SDimitry Andric   }
59081ad6265SDimitry Andric 
59181ad6265SDimitry Andric   if (m_storage.tsc_conversion) {
59281ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Target);
59381ad6265SDimitry Andric     LLDB_LOG(log, "TraceIntelPT found TSC conversion information");
59481ad6265SDimitry Andric   }
59581ad6265SDimitry Andric   return Error::success();
596fe6060f1SDimitry Andric }
597fe6060f1SDimitry Andric 
598349cc55cSDimitry Andric bool TraceIntelPT::IsTraced(lldb::tid_t tid) {
59981ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
60081ad6265SDimitry Andric   if (storage.multicpu_decoder)
60181ad6265SDimitry Andric     return storage.multicpu_decoder->TracesThread(tid);
60281ad6265SDimitry Andric   return storage.thread_decoders.count(tid);
603fe6060f1SDimitry Andric }
604fe6060f1SDimitry Andric 
605fe6060f1SDimitry Andric // The information here should match the description of the intel-pt section
606fe6060f1SDimitry Andric // of the jLLDBTraceStart packet in the lldb/docs/lldb-gdb-remote.txt
607fe6060f1SDimitry Andric // documentation file. Similarly, it should match the CLI help messages of the
608fe6060f1SDimitry Andric // TraceIntelPTOptions.td file.
609fe6060f1SDimitry Andric const char *TraceIntelPT::GetStartConfigurationHelp() {
610*bdd1243dSDimitry Andric   static std::optional<std::string> message;
61181ad6265SDimitry Andric   if (!message) {
61281ad6265SDimitry Andric     message.emplace(formatv(R"(Parameters:
613fe6060f1SDimitry Andric 
61481ad6265SDimitry Andric   See the jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt for a
61581ad6265SDimitry Andric   description of each parameter below.
616fe6060f1SDimitry Andric 
61781ad6265SDimitry Andric   - int iptTraceSize (defaults to {0} bytes):
618fe6060f1SDimitry Andric     [process and thread tracing]
619fe6060f1SDimitry Andric 
62081ad6265SDimitry Andric   - boolean enableTsc (default to {1}):
621fe6060f1SDimitry Andric     [process and thread tracing]
622fe6060f1SDimitry Andric 
62381ad6265SDimitry Andric   - int psbPeriod (defaults to {2}):
624fe6060f1SDimitry Andric     [process and thread tracing]
625fe6060f1SDimitry Andric 
62681ad6265SDimitry Andric   - boolean perCpuTracing (default to {3}):
627fe6060f1SDimitry Andric     [process tracing only]
62881ad6265SDimitry Andric 
62981ad6265SDimitry Andric   - int processBufferSizeLimit (defaults to {4} MiB):
630753f127fSDimitry Andric     [process tracing only]
631753f127fSDimitry Andric 
632753f127fSDimitry Andric   - boolean disableCgroupFiltering (default to {5}):
63381ad6265SDimitry Andric     [process tracing only])",
63481ad6265SDimitry Andric                             kDefaultIptTraceSize, kDefaultEnableTscValue,
63581ad6265SDimitry Andric                             kDefaultPsbPeriod, kDefaultPerCpuTracing,
636753f127fSDimitry Andric                             kDefaultProcessBufferSizeLimit / 1024 / 1024,
637753f127fSDimitry Andric                             kDefaultDisableCgroupFiltering));
63881ad6265SDimitry Andric   }
63981ad6265SDimitry Andric   return message->c_str();
640fe6060f1SDimitry Andric }
641fe6060f1SDimitry Andric 
64281ad6265SDimitry Andric Error TraceIntelPT::Start(uint64_t ipt_trace_size,
64381ad6265SDimitry Andric                           uint64_t total_buffer_size_limit, bool enable_tsc,
644*bdd1243dSDimitry Andric                           std::optional<uint64_t> psb_period,
645*bdd1243dSDimitry Andric                           bool per_cpu_tracing, bool disable_cgroup_filtering) {
646fe6060f1SDimitry Andric   TraceIntelPTStartRequest request;
64781ad6265SDimitry Andric   request.ipt_trace_size = ipt_trace_size;
64881ad6265SDimitry Andric   request.process_buffer_size_limit = total_buffer_size_limit;
64981ad6265SDimitry Andric   request.enable_tsc = enable_tsc;
65081ad6265SDimitry Andric   request.psb_period = psb_period;
651349cc55cSDimitry Andric   request.type = GetPluginName().str();
65281ad6265SDimitry Andric   request.per_cpu_tracing = per_cpu_tracing;
653753f127fSDimitry Andric   request.disable_cgroup_filtering = disable_cgroup_filtering;
654fe6060f1SDimitry Andric   return Trace::Start(toJSON(request));
655fe6060f1SDimitry Andric }
656fe6060f1SDimitry Andric 
657fe6060f1SDimitry Andric Error TraceIntelPT::Start(StructuredData::ObjectSP configuration) {
65881ad6265SDimitry Andric   uint64_t ipt_trace_size = kDefaultIptTraceSize;
65981ad6265SDimitry Andric   uint64_t process_buffer_size_limit = kDefaultProcessBufferSizeLimit;
660fe6060f1SDimitry Andric   bool enable_tsc = kDefaultEnableTscValue;
661*bdd1243dSDimitry Andric   std::optional<uint64_t> psb_period = kDefaultPsbPeriod;
66281ad6265SDimitry Andric   bool per_cpu_tracing = kDefaultPerCpuTracing;
663753f127fSDimitry Andric   bool disable_cgroup_filtering = kDefaultDisableCgroupFiltering;
664fe6060f1SDimitry Andric 
665fe6060f1SDimitry Andric   if (configuration) {
666fe6060f1SDimitry Andric     if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
66781ad6265SDimitry Andric       dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size);
668fe6060f1SDimitry Andric       dict->GetValueForKeyAsInteger("processBufferSizeLimit",
669fe6060f1SDimitry Andric                                     process_buffer_size_limit);
670fe6060f1SDimitry Andric       dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
671fe6060f1SDimitry Andric       dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
67281ad6265SDimitry Andric       dict->GetValueForKeyAsBoolean("perCpuTracing", per_cpu_tracing);
673753f127fSDimitry Andric       dict->GetValueForKeyAsBoolean("disableCgroupFiltering",
674753f127fSDimitry Andric                                     disable_cgroup_filtering);
675fe6060f1SDimitry Andric     } else {
676fe6060f1SDimitry Andric       return createStringError(inconvertibleErrorCode(),
677fe6060f1SDimitry Andric                                "configuration object is not a dictionary");
678fe6060f1SDimitry Andric     }
679fe6060f1SDimitry Andric   }
680fe6060f1SDimitry Andric 
68181ad6265SDimitry Andric   return Start(ipt_trace_size, process_buffer_size_limit, enable_tsc,
682753f127fSDimitry Andric                psb_period, per_cpu_tracing, disable_cgroup_filtering);
683fe6060f1SDimitry Andric }
684fe6060f1SDimitry Andric 
685fe6060f1SDimitry Andric llvm::Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
68681ad6265SDimitry Andric                                 uint64_t ipt_trace_size, bool enable_tsc,
687*bdd1243dSDimitry Andric                                 std::optional<uint64_t> psb_period) {
688fe6060f1SDimitry Andric   TraceIntelPTStartRequest request;
68981ad6265SDimitry Andric   request.ipt_trace_size = ipt_trace_size;
69081ad6265SDimitry Andric   request.enable_tsc = enable_tsc;
69181ad6265SDimitry Andric   request.psb_period = psb_period;
692349cc55cSDimitry Andric   request.type = GetPluginName().str();
693fe6060f1SDimitry Andric   request.tids.emplace();
694fe6060f1SDimitry Andric   for (lldb::tid_t tid : tids)
695fe6060f1SDimitry Andric     request.tids->push_back(tid);
696fe6060f1SDimitry Andric   return Trace::Start(toJSON(request));
697fe6060f1SDimitry Andric }
698fe6060f1SDimitry Andric 
699fe6060f1SDimitry Andric Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
700fe6060f1SDimitry Andric                           StructuredData::ObjectSP configuration) {
70181ad6265SDimitry Andric   uint64_t ipt_trace_size = kDefaultIptTraceSize;
702fe6060f1SDimitry Andric   bool enable_tsc = kDefaultEnableTscValue;
703*bdd1243dSDimitry Andric   std::optional<uint64_t> psb_period = kDefaultPsbPeriod;
704fe6060f1SDimitry Andric 
705fe6060f1SDimitry Andric   if (configuration) {
706fe6060f1SDimitry Andric     if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
707753f127fSDimitry Andric       llvm::StringRef ipt_trace_size_not_parsed;
708753f127fSDimitry Andric       if (dict->GetValueForKeyAsString("iptTraceSize",
709753f127fSDimitry Andric                                        ipt_trace_size_not_parsed)) {
710*bdd1243dSDimitry Andric         if (std::optional<uint64_t> bytes =
711753f127fSDimitry Andric                 ParsingUtils::ParseUserFriendlySizeExpression(
712753f127fSDimitry Andric                     ipt_trace_size_not_parsed))
713753f127fSDimitry Andric           ipt_trace_size = *bytes;
714753f127fSDimitry Andric         else
715753f127fSDimitry Andric           return createStringError(inconvertibleErrorCode(),
716753f127fSDimitry Andric                                    "iptTraceSize is wrong bytes expression");
717753f127fSDimitry Andric       } else {
71881ad6265SDimitry Andric         dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size);
719753f127fSDimitry Andric       }
720753f127fSDimitry Andric 
721fe6060f1SDimitry Andric       dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
722fe6060f1SDimitry Andric       dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
723fe6060f1SDimitry Andric     } else {
724fe6060f1SDimitry Andric       return createStringError(inconvertibleErrorCode(),
725fe6060f1SDimitry Andric                                "configuration object is not a dictionary");
726fe6060f1SDimitry Andric     }
727fe6060f1SDimitry Andric   }
728fe6060f1SDimitry Andric 
72981ad6265SDimitry Andric   return Start(tids, ipt_trace_size, enable_tsc, psb_period);
730fe6060f1SDimitry Andric }
731fe6060f1SDimitry Andric 
73281ad6265SDimitry Andric Error TraceIntelPT::OnThreadBufferRead(lldb::tid_t tid,
73381ad6265SDimitry Andric                                        OnBinaryDataReadCallback callback) {
73481ad6265SDimitry Andric   return OnThreadBinaryDataRead(tid, IntelPTDataKinds::kIptTrace, callback);
735e8d8bef9SDimitry Andric }
73681ad6265SDimitry Andric 
73781ad6265SDimitry Andric TaskTimer &TraceIntelPT::GetTimer() { return GetUpdatedStorage().task_timer; }
738753f127fSDimitry Andric 
739753f127fSDimitry Andric ScopedTaskTimer &TraceIntelPT::GetThreadTimer(lldb::tid_t tid) {
740753f127fSDimitry Andric   return GetTimer().ForThread(tid);
741753f127fSDimitry Andric }
742753f127fSDimitry Andric 
743753f127fSDimitry Andric ScopedTaskTimer &TraceIntelPT::GetGlobalTimer() {
744753f127fSDimitry Andric   return GetTimer().ForGlobal();
745753f127fSDimitry Andric }
746