xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1be691f3bSpatrick //===-- TraceIntelPT.cpp --------------------------------------------------===//
2be691f3bSpatrick //
3be691f3bSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4be691f3bSpatrick // See https://llvm.org/LICENSE.txt for license information.
5be691f3bSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6be691f3bSpatrick //
7be691f3bSpatrick //===----------------------------------------------------------------------===//
8be691f3bSpatrick 
9be691f3bSpatrick #include "TraceIntelPT.h"
10be691f3bSpatrick 
11be691f3bSpatrick #include "../common/ThreadPostMortemTrace.h"
12be691f3bSpatrick #include "CommandObjectTraceStartIntelPT.h"
13be691f3bSpatrick #include "DecodedThread.h"
14*f6aab3d8Srobert #include "TraceCursorIntelPT.h"
15*f6aab3d8Srobert #include "TraceIntelPTBundleLoader.h"
16*f6aab3d8Srobert #include "TraceIntelPTBundleSaver.h"
17be691f3bSpatrick #include "TraceIntelPTConstants.h"
18be691f3bSpatrick #include "lldb/Core/PluginManager.h"
19*f6aab3d8Srobert #include "lldb/Interpreter/OptionValueProperties.h"
20be691f3bSpatrick #include "lldb/Target/Process.h"
21be691f3bSpatrick #include "lldb/Target/Target.h"
22*f6aab3d8Srobert #include <optional>
23be691f3bSpatrick 
24be691f3bSpatrick using namespace lldb;
25be691f3bSpatrick using namespace lldb_private;
26be691f3bSpatrick using namespace lldb_private::trace_intel_pt;
27be691f3bSpatrick using namespace llvm;
28be691f3bSpatrick 
LLDB_PLUGIN_DEFINE(TraceIntelPT)29be691f3bSpatrick LLDB_PLUGIN_DEFINE(TraceIntelPT)
30be691f3bSpatrick 
31be691f3bSpatrick lldb::CommandObjectSP
32be691f3bSpatrick TraceIntelPT::GetProcessTraceStartCommand(CommandInterpreter &interpreter) {
33be691f3bSpatrick   return CommandObjectSP(
34be691f3bSpatrick       new CommandObjectProcessTraceStartIntelPT(*this, interpreter));
35be691f3bSpatrick }
36be691f3bSpatrick 
37be691f3bSpatrick lldb::CommandObjectSP
GetThreadTraceStartCommand(CommandInterpreter & interpreter)38be691f3bSpatrick TraceIntelPT::GetThreadTraceStartCommand(CommandInterpreter &interpreter) {
39be691f3bSpatrick   return CommandObjectSP(
40be691f3bSpatrick       new CommandObjectThreadTraceStartIntelPT(*this, interpreter));
41be691f3bSpatrick }
42be691f3bSpatrick 
43*f6aab3d8Srobert #define LLDB_PROPERTIES_traceintelpt
44*f6aab3d8Srobert #include "TraceIntelPTProperties.inc"
45*f6aab3d8Srobert 
46*f6aab3d8Srobert enum {
47*f6aab3d8Srobert #define LLDB_PROPERTIES_traceintelpt
48*f6aab3d8Srobert #include "TraceIntelPTPropertiesEnum.inc"
49*f6aab3d8Srobert };
50*f6aab3d8Srobert 
GetSettingName()51*f6aab3d8Srobert ConstString TraceIntelPT::PluginProperties::GetSettingName() {
52*f6aab3d8Srobert   return ConstString(TraceIntelPT::GetPluginNameStatic());
53*f6aab3d8Srobert }
54*f6aab3d8Srobert 
PluginProperties()55*f6aab3d8Srobert TraceIntelPT::PluginProperties::PluginProperties() : Properties() {
56*f6aab3d8Srobert   m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
57*f6aab3d8Srobert   m_collection_sp->Initialize(g_traceintelpt_properties);
58*f6aab3d8Srobert }
59*f6aab3d8Srobert 
60*f6aab3d8Srobert uint64_t
GetInfiniteDecodingLoopVerificationThreshold()61*f6aab3d8Srobert TraceIntelPT::PluginProperties::GetInfiniteDecodingLoopVerificationThreshold() {
62*f6aab3d8Srobert   const uint32_t idx = ePropertyInfiniteDecodingLoopVerificationThreshold;
63*f6aab3d8Srobert   return m_collection_sp->GetPropertyAtIndexAsUInt64(
64*f6aab3d8Srobert       nullptr, idx, g_traceintelpt_properties[idx].default_uint_value);
65*f6aab3d8Srobert }
66*f6aab3d8Srobert 
GetExtremelyLargeDecodingThreshold()67*f6aab3d8Srobert uint64_t TraceIntelPT::PluginProperties::GetExtremelyLargeDecodingThreshold() {
68*f6aab3d8Srobert   const uint32_t idx = ePropertyExtremelyLargeDecodingThreshold;
69*f6aab3d8Srobert   return m_collection_sp->GetPropertyAtIndexAsUInt64(
70*f6aab3d8Srobert       nullptr, idx, g_traceintelpt_properties[idx].default_uint_value);
71*f6aab3d8Srobert }
72*f6aab3d8Srobert 
GetGlobalProperties()73*f6aab3d8Srobert TraceIntelPT::PluginProperties &TraceIntelPT::GetGlobalProperties() {
74*f6aab3d8Srobert   static TraceIntelPT::PluginProperties g_settings;
75*f6aab3d8Srobert   return g_settings;
76*f6aab3d8Srobert }
77*f6aab3d8Srobert 
Initialize()78be691f3bSpatrick void TraceIntelPT::Initialize() {
79*f6aab3d8Srobert   PluginManager::RegisterPlugin(
80*f6aab3d8Srobert       GetPluginNameStatic(), "Intel Processor Trace",
81*f6aab3d8Srobert       CreateInstanceForTraceBundle, CreateInstanceForLiveProcess,
82*f6aab3d8Srobert       TraceIntelPTBundleLoader::GetSchema(), DebuggerInitialize);
83*f6aab3d8Srobert }
84*f6aab3d8Srobert 
DebuggerInitialize(Debugger & debugger)85*f6aab3d8Srobert void TraceIntelPT::DebuggerInitialize(Debugger &debugger) {
86*f6aab3d8Srobert   if (!PluginManager::GetSettingForProcessPlugin(
87*f6aab3d8Srobert           debugger, PluginProperties::GetSettingName())) {
88*f6aab3d8Srobert     const bool is_global_setting = true;
89*f6aab3d8Srobert     PluginManager::CreateSettingForTracePlugin(
90*f6aab3d8Srobert         debugger, GetGlobalProperties().GetValueProperties(),
91*f6aab3d8Srobert         ConstString("Properties for the intel-pt trace plug-in."),
92*f6aab3d8Srobert         is_global_setting);
93*f6aab3d8Srobert   }
94be691f3bSpatrick }
95be691f3bSpatrick 
Terminate()96be691f3bSpatrick void TraceIntelPT::Terminate() {
97*f6aab3d8Srobert   PluginManager::UnregisterPlugin(CreateInstanceForTraceBundle);
98be691f3bSpatrick }
99be691f3bSpatrick 
GetSchema()100be691f3bSpatrick StringRef TraceIntelPT::GetSchema() {
101*f6aab3d8Srobert   return TraceIntelPTBundleLoader::GetSchema();
102be691f3bSpatrick }
103be691f3bSpatrick 
Dump(Stream * s) const104be691f3bSpatrick void TraceIntelPT::Dump(Stream *s) const {}
105be691f3bSpatrick 
SaveToDisk(FileSpec directory,bool compact)106*f6aab3d8Srobert Expected<FileSpec> TraceIntelPT::SaveToDisk(FileSpec directory, bool compact) {
107*f6aab3d8Srobert   RefreshLiveProcessState();
108*f6aab3d8Srobert   return TraceIntelPTBundleSaver().SaveToDisk(*this, directory, compact);
109*f6aab3d8Srobert }
110*f6aab3d8Srobert 
CreateInstanceForTraceBundle(const json::Value & bundle_description,StringRef bundle_dir,Debugger & debugger)111*f6aab3d8Srobert Expected<TraceSP> TraceIntelPT::CreateInstanceForTraceBundle(
112*f6aab3d8Srobert     const json::Value &bundle_description, StringRef bundle_dir,
113be691f3bSpatrick     Debugger &debugger) {
114*f6aab3d8Srobert   return TraceIntelPTBundleLoader(debugger, bundle_description, bundle_dir)
115*f6aab3d8Srobert       .Load();
116be691f3bSpatrick }
117be691f3bSpatrick 
CreateInstanceForLiveProcess(Process & process)118be691f3bSpatrick Expected<TraceSP> TraceIntelPT::CreateInstanceForLiveProcess(Process &process) {
119be691f3bSpatrick   TraceSP instance(new TraceIntelPT(process));
120be691f3bSpatrick   process.GetTarget().SetTrace(instance);
121be691f3bSpatrick   return instance;
122be691f3bSpatrick }
123be691f3bSpatrick 
GetSharedPtr()124*f6aab3d8Srobert TraceIntelPTSP TraceIntelPT::GetSharedPtr() {
125*f6aab3d8Srobert   return std::static_pointer_cast<TraceIntelPT>(shared_from_this());
126be691f3bSpatrick }
127be691f3bSpatrick 
GetTraceMode()128*f6aab3d8Srobert TraceIntelPT::TraceMode TraceIntelPT::GetTraceMode() { return trace_mode; }
129be691f3bSpatrick 
CreateInstanceForPostmortemTrace(JSONTraceBundleDescription & bundle_description,ArrayRef<ProcessSP> traced_processes,ArrayRef<ThreadPostMortemTraceSP> traced_threads,TraceMode trace_mode)130*f6aab3d8Srobert TraceIntelPTSP TraceIntelPT::CreateInstanceForPostmortemTrace(
131*f6aab3d8Srobert     JSONTraceBundleDescription &bundle_description,
132*f6aab3d8Srobert     ArrayRef<ProcessSP> traced_processes,
133*f6aab3d8Srobert     ArrayRef<ThreadPostMortemTraceSP> traced_threads, TraceMode trace_mode) {
134*f6aab3d8Srobert   TraceIntelPTSP trace_sp(
135*f6aab3d8Srobert       new TraceIntelPT(bundle_description, traced_processes, trace_mode));
136*f6aab3d8Srobert   trace_sp->m_storage.tsc_conversion =
137*f6aab3d8Srobert       bundle_description.tsc_perf_zero_conversion;
138*f6aab3d8Srobert 
139*f6aab3d8Srobert   if (bundle_description.cpus) {
140*f6aab3d8Srobert     std::vector<cpu_id_t> cpus;
141*f6aab3d8Srobert 
142*f6aab3d8Srobert     for (const JSONCpu &cpu : *bundle_description.cpus) {
143*f6aab3d8Srobert       trace_sp->SetPostMortemCpuDataFile(cpu.id, IntelPTDataKinds::kIptTrace,
144*f6aab3d8Srobert                                          FileSpec(cpu.ipt_trace));
145*f6aab3d8Srobert 
146*f6aab3d8Srobert       trace_sp->SetPostMortemCpuDataFile(
147*f6aab3d8Srobert           cpu.id, IntelPTDataKinds::kPerfContextSwitchTrace,
148*f6aab3d8Srobert           FileSpec(cpu.context_switch_trace));
149*f6aab3d8Srobert       cpus.push_back(cpu.id);
150*f6aab3d8Srobert     }
151*f6aab3d8Srobert 
152*f6aab3d8Srobert     if (trace_mode == TraceMode::UserMode) {
153*f6aab3d8Srobert       trace_sp->m_storage.multicpu_decoder.emplace(trace_sp);
154*f6aab3d8Srobert     }
155*f6aab3d8Srobert   }
156*f6aab3d8Srobert 
157*f6aab3d8Srobert   if (!bundle_description.cpus || trace_mode == TraceMode::KernelMode) {
158*f6aab3d8Srobert     for (const ThreadPostMortemTraceSP &thread : traced_threads) {
159*f6aab3d8Srobert       trace_sp->m_storage.thread_decoders.try_emplace(
160*f6aab3d8Srobert           thread->GetID(), std::make_unique<ThreadDecoder>(thread, *trace_sp));
161*f6aab3d8Srobert       if (const std::optional<FileSpec> &trace_file = thread->GetTraceFile()) {
162*f6aab3d8Srobert         trace_sp->SetPostMortemThreadDataFile(
163*f6aab3d8Srobert             thread->GetID(), IntelPTDataKinds::kIptTrace, *trace_file);
164*f6aab3d8Srobert       }
165*f6aab3d8Srobert     }
166*f6aab3d8Srobert   }
167*f6aab3d8Srobert 
168*f6aab3d8Srobert   for (const ProcessSP &process_sp : traced_processes)
169*f6aab3d8Srobert     process_sp->GetTarget().SetTrace(trace_sp);
170*f6aab3d8Srobert   return trace_sp;
171*f6aab3d8Srobert }
172*f6aab3d8Srobert 
TraceIntelPT(JSONTraceBundleDescription & bundle_description,ArrayRef<ProcessSP> traced_processes,TraceMode trace_mode)173*f6aab3d8Srobert TraceIntelPT::TraceIntelPT(JSONTraceBundleDescription &bundle_description,
174*f6aab3d8Srobert                            ArrayRef<ProcessSP> traced_processes,
175*f6aab3d8Srobert                            TraceMode trace_mode)
176*f6aab3d8Srobert     : Trace(traced_processes, bundle_description.GetCpuIds()),
177*f6aab3d8Srobert       m_cpu_info(bundle_description.cpu_info), trace_mode(trace_mode) {}
178*f6aab3d8Srobert 
Decode(Thread & thread)179*f6aab3d8Srobert Expected<DecodedThreadSP> TraceIntelPT::Decode(Thread &thread) {
180*f6aab3d8Srobert   if (const char *error = RefreshLiveProcessState())
181*f6aab3d8Srobert     return createStringError(inconvertibleErrorCode(), error);
182*f6aab3d8Srobert 
183*f6aab3d8Srobert   Storage &storage = GetUpdatedStorage();
184*f6aab3d8Srobert   if (storage.multicpu_decoder)
185*f6aab3d8Srobert     return storage.multicpu_decoder->Decode(thread);
186*f6aab3d8Srobert 
187*f6aab3d8Srobert   auto it = storage.thread_decoders.find(thread.GetID());
188*f6aab3d8Srobert   if (it == storage.thread_decoders.end())
189*f6aab3d8Srobert     return createStringError(inconvertibleErrorCode(), "thread not traced");
190be691f3bSpatrick   return it->second->Decode();
191be691f3bSpatrick }
192be691f3bSpatrick 
FindBeginningOfTimeNanos()193*f6aab3d8Srobert Expected<std::optional<uint64_t>> TraceIntelPT::FindBeginningOfTimeNanos() {
194*f6aab3d8Srobert   Storage &storage = GetUpdatedStorage();
195*f6aab3d8Srobert   if (storage.beginning_of_time_nanos_calculated)
196*f6aab3d8Srobert     return storage.beginning_of_time_nanos;
197*f6aab3d8Srobert   storage.beginning_of_time_nanos_calculated = true;
198*f6aab3d8Srobert 
199*f6aab3d8Srobert   if (!storage.tsc_conversion)
200*f6aab3d8Srobert     return std::nullopt;
201*f6aab3d8Srobert 
202*f6aab3d8Srobert   std::optional<uint64_t> lowest_tsc;
203*f6aab3d8Srobert 
204*f6aab3d8Srobert   if (storage.multicpu_decoder) {
205*f6aab3d8Srobert     if (Expected<std::optional<uint64_t>> tsc =
206*f6aab3d8Srobert             storage.multicpu_decoder->FindLowestTSC()) {
207*f6aab3d8Srobert       lowest_tsc = *tsc;
208*f6aab3d8Srobert     } else {
209*f6aab3d8Srobert       return tsc.takeError();
210*f6aab3d8Srobert     }
211be691f3bSpatrick   }
212be691f3bSpatrick 
213*f6aab3d8Srobert   for (auto &decoder : storage.thread_decoders) {
214*f6aab3d8Srobert     Expected<std::optional<uint64_t>> tsc = decoder.second->FindLowestTSC();
215*f6aab3d8Srobert     if (!tsc)
216*f6aab3d8Srobert       return tsc.takeError();
217*f6aab3d8Srobert 
218*f6aab3d8Srobert     if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))
219*f6aab3d8Srobert       lowest_tsc = **tsc;
220be691f3bSpatrick   }
221be691f3bSpatrick 
222*f6aab3d8Srobert   if (lowest_tsc) {
223*f6aab3d8Srobert     storage.beginning_of_time_nanos =
224*f6aab3d8Srobert         storage.tsc_conversion->ToNanos(*lowest_tsc);
225*f6aab3d8Srobert   }
226*f6aab3d8Srobert   return storage.beginning_of_time_nanos;
227*f6aab3d8Srobert }
228*f6aab3d8Srobert 
229*f6aab3d8Srobert llvm::Expected<lldb::TraceCursorSP>
CreateNewCursor(Thread & thread)230*f6aab3d8Srobert TraceIntelPT::CreateNewCursor(Thread &thread) {
231*f6aab3d8Srobert   if (Expected<DecodedThreadSP> decoded_thread = Decode(thread)) {
232*f6aab3d8Srobert     if (Expected<std::optional<uint64_t>> beginning_of_time =
233*f6aab3d8Srobert             FindBeginningOfTimeNanos())
234*f6aab3d8Srobert       return std::make_shared<TraceCursorIntelPT>(
235*f6aab3d8Srobert           thread.shared_from_this(), *decoded_thread, m_storage.tsc_conversion,
236*f6aab3d8Srobert           *beginning_of_time);
237be691f3bSpatrick     else
238*f6aab3d8Srobert       return beginning_of_time.takeError();
239*f6aab3d8Srobert   } else
240*f6aab3d8Srobert     return decoded_thread.takeError();
241*f6aab3d8Srobert }
242*f6aab3d8Srobert 
DumpTraceInfo(Thread & thread,Stream & s,bool verbose,bool json)243*f6aab3d8Srobert void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose,
244*f6aab3d8Srobert                                  bool json) {
245*f6aab3d8Srobert   Storage &storage = GetUpdatedStorage();
246*f6aab3d8Srobert 
247*f6aab3d8Srobert   lldb::tid_t tid = thread.GetID();
248*f6aab3d8Srobert   if (json) {
249*f6aab3d8Srobert     DumpTraceInfoAsJson(thread, s, verbose);
250*f6aab3d8Srobert     return;
251*f6aab3d8Srobert   }
252*f6aab3d8Srobert 
253*f6aab3d8Srobert   s.Format("\nthread #{0}: tid = {1}", thread.GetIndexID(), thread.GetID());
254*f6aab3d8Srobert   if (!IsTraced(tid)) {
255*f6aab3d8Srobert     s << ", not traced\n";
256*f6aab3d8Srobert     return;
257*f6aab3d8Srobert   }
258*f6aab3d8Srobert   s << "\n";
259*f6aab3d8Srobert 
260*f6aab3d8Srobert   Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread);
261*f6aab3d8Srobert   if (!decoded_thread_sp_or_err) {
262*f6aab3d8Srobert     s << toString(decoded_thread_sp_or_err.takeError()) << "\n";
263*f6aab3d8Srobert     return;
264*f6aab3d8Srobert   }
265*f6aab3d8Srobert 
266*f6aab3d8Srobert   DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err;
267*f6aab3d8Srobert 
268*f6aab3d8Srobert   Expected<std::optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread);
269*f6aab3d8Srobert   if (!raw_size_or_error) {
270*f6aab3d8Srobert     s.Format("  {0}\n", toString(raw_size_or_error.takeError()));
271*f6aab3d8Srobert     return;
272*f6aab3d8Srobert   }
273*f6aab3d8Srobert   std::optional<uint64_t> raw_size = *raw_size_or_error;
274*f6aab3d8Srobert 
275*f6aab3d8Srobert   s.Format("\n  Trace technology: {0}\n", GetPluginName());
276*f6aab3d8Srobert 
277*f6aab3d8Srobert   /// Instruction stats
278*f6aab3d8Srobert   {
279*f6aab3d8Srobert     uint64_t items_count = decoded_thread_sp->GetItemsCount();
280*f6aab3d8Srobert     uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage();
281*f6aab3d8Srobert 
282*f6aab3d8Srobert     s.Format("\n  Total number of trace items: {0}\n", items_count);
283*f6aab3d8Srobert 
284*f6aab3d8Srobert     s << "\n  Memory usage:\n";
285*f6aab3d8Srobert     if (raw_size)
286*f6aab3d8Srobert       s.Format("    Raw trace size: {0} KiB\n", *raw_size / 1024);
287*f6aab3d8Srobert 
288*f6aab3d8Srobert     s.Format(
289*f6aab3d8Srobert         "    Total approximate memory usage (excluding raw trace): {0:2} KiB\n",
290*f6aab3d8Srobert         (double)mem_used / 1024);
291*f6aab3d8Srobert     if (items_count != 0)
292*f6aab3d8Srobert       s.Format("    Average memory usage per item (excluding raw trace): "
293*f6aab3d8Srobert                "{0:2} bytes\n",
294*f6aab3d8Srobert                (double)mem_used / items_count);
295*f6aab3d8Srobert   }
296*f6aab3d8Srobert 
297*f6aab3d8Srobert   // Timing
298*f6aab3d8Srobert   {
299*f6aab3d8Srobert     s << "\n  Timing for this thread:\n";
300*f6aab3d8Srobert     auto print_duration = [&](const std::string &name,
301*f6aab3d8Srobert                               std::chrono::milliseconds duration) {
302*f6aab3d8Srobert       s.Format("    {0}: {1:2}s\n", name, duration.count() / 1000.0);
303*f6aab3d8Srobert     };
304*f6aab3d8Srobert     GetThreadTimer(tid).ForEachTimedTask(print_duration);
305*f6aab3d8Srobert 
306*f6aab3d8Srobert     s << "\n  Timing for global tasks:\n";
307*f6aab3d8Srobert     GetGlobalTimer().ForEachTimedTask(print_duration);
308*f6aab3d8Srobert   }
309*f6aab3d8Srobert 
310*f6aab3d8Srobert   // Instruction events stats
311*f6aab3d8Srobert   {
312*f6aab3d8Srobert     const DecodedThread::EventsStats &events_stats =
313*f6aab3d8Srobert         decoded_thread_sp->GetEventsStats();
314*f6aab3d8Srobert     s << "\n  Events:\n";
315*f6aab3d8Srobert     s.Format("    Number of individual events: {0}\n",
316*f6aab3d8Srobert              events_stats.total_count);
317*f6aab3d8Srobert     for (const auto &event_to_count : events_stats.events_counts) {
318*f6aab3d8Srobert       s.Format("      {0}: {1}\n",
319*f6aab3d8Srobert                TraceCursor::EventKindToString(event_to_count.first),
320*f6aab3d8Srobert                event_to_count.second);
321*f6aab3d8Srobert     }
322*f6aab3d8Srobert   }
323*f6aab3d8Srobert   // Trace error stats
324*f6aab3d8Srobert   {
325*f6aab3d8Srobert     const DecodedThread::ErrorStats &error_stats =
326*f6aab3d8Srobert         decoded_thread_sp->GetErrorStats();
327*f6aab3d8Srobert     s << "\n  Errors:\n";
328*f6aab3d8Srobert     s.Format("    Number of individual errors: {0}\n",
329*f6aab3d8Srobert              error_stats.GetTotalCount());
330*f6aab3d8Srobert     s.Format("      Number of fatal errors: {0}\n", error_stats.fatal_errors);
331*f6aab3d8Srobert     for (const auto &[kind, count] : error_stats.libipt_errors) {
332*f6aab3d8Srobert       s.Format("     Number of libipt errors of kind [{0}]: {1}\n", kind,
333*f6aab3d8Srobert                count);
334*f6aab3d8Srobert     }
335*f6aab3d8Srobert     s.Format("      Number of other errors: {0}\n", error_stats.other_errors);
336*f6aab3d8Srobert   }
337*f6aab3d8Srobert 
338*f6aab3d8Srobert   if (storage.multicpu_decoder) {
339*f6aab3d8Srobert     s << "\n  Multi-cpu decoding:\n";
340*f6aab3d8Srobert     s.Format("    Total number of continuous executions found: {0}\n",
341*f6aab3d8Srobert              storage.multicpu_decoder->GetTotalContinuousExecutionsCount());
342*f6aab3d8Srobert     s.Format(
343*f6aab3d8Srobert         "    Number of continuous executions for this thread: {0}\n",
344*f6aab3d8Srobert         storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid));
345*f6aab3d8Srobert     s.Format("    Total number of PSB blocks found: {0}\n",
346*f6aab3d8Srobert              storage.multicpu_decoder->GetTotalPSBBlocksCount());
347*f6aab3d8Srobert     s.Format("    Number of PSB blocks for this thread: {0}\n",
348*f6aab3d8Srobert              storage.multicpu_decoder->GePSBBlocksCountForThread(tid));
349*f6aab3d8Srobert     s.Format("    Total number of unattributed PSB blocks found: {0}\n",
350*f6aab3d8Srobert              storage.multicpu_decoder->GetUnattributedPSBBlocksCount());
351*f6aab3d8Srobert   }
352*f6aab3d8Srobert }
353*f6aab3d8Srobert 
DumpTraceInfoAsJson(Thread & thread,Stream & s,bool verbose)354*f6aab3d8Srobert void TraceIntelPT::DumpTraceInfoAsJson(Thread &thread, Stream &s,
355*f6aab3d8Srobert                                        bool verbose) {
356*f6aab3d8Srobert   Storage &storage = GetUpdatedStorage();
357*f6aab3d8Srobert 
358*f6aab3d8Srobert   lldb::tid_t tid = thread.GetID();
359*f6aab3d8Srobert   json::OStream json_str(s.AsRawOstream(), 2);
360*f6aab3d8Srobert   if (!IsTraced(tid)) {
361*f6aab3d8Srobert     s << "error: thread not traced\n";
362*f6aab3d8Srobert     return;
363*f6aab3d8Srobert   }
364*f6aab3d8Srobert 
365*f6aab3d8Srobert   Expected<std::optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread);
366*f6aab3d8Srobert   if (!raw_size_or_error) {
367*f6aab3d8Srobert     s << "error: " << toString(raw_size_or_error.takeError()) << "\n";
368*f6aab3d8Srobert     return;
369*f6aab3d8Srobert   }
370*f6aab3d8Srobert 
371*f6aab3d8Srobert   Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread);
372*f6aab3d8Srobert   if (!decoded_thread_sp_or_err) {
373*f6aab3d8Srobert     s << "error: " << toString(decoded_thread_sp_or_err.takeError()) << "\n";
374*f6aab3d8Srobert     return;
375*f6aab3d8Srobert   }
376*f6aab3d8Srobert   DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err;
377*f6aab3d8Srobert 
378*f6aab3d8Srobert   json_str.object([&] {
379*f6aab3d8Srobert     json_str.attribute("traceTechnology", "intel-pt");
380*f6aab3d8Srobert     json_str.attributeObject("threadStats", [&] {
381*f6aab3d8Srobert       json_str.attribute("tid", tid);
382*f6aab3d8Srobert 
383*f6aab3d8Srobert       uint64_t insn_len = decoded_thread_sp->GetItemsCount();
384*f6aab3d8Srobert       json_str.attribute("traceItemsCount", insn_len);
385*f6aab3d8Srobert 
386*f6aab3d8Srobert       // Instruction stats
387*f6aab3d8Srobert       uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage();
388*f6aab3d8Srobert       json_str.attributeObject("memoryUsage", [&] {
389*f6aab3d8Srobert         json_str.attribute("totalInBytes", std::to_string(mem_used));
390*f6aab3d8Srobert         std::optional<double> avg;
391*f6aab3d8Srobert         if (insn_len != 0)
392*f6aab3d8Srobert           avg = double(mem_used) / insn_len;
393*f6aab3d8Srobert         json_str.attribute("avgPerItemInBytes", avg);
394*f6aab3d8Srobert       });
395*f6aab3d8Srobert 
396*f6aab3d8Srobert       // Timing
397*f6aab3d8Srobert       json_str.attributeObject("timingInSeconds", [&] {
398*f6aab3d8Srobert         GetTimer().ForThread(tid).ForEachTimedTask(
399*f6aab3d8Srobert             [&](const std::string &name, std::chrono::milliseconds duration) {
400*f6aab3d8Srobert               json_str.attribute(name, duration.count() / 1000.0);
401*f6aab3d8Srobert             });
402*f6aab3d8Srobert       });
403*f6aab3d8Srobert 
404*f6aab3d8Srobert       // Instruction events stats
405*f6aab3d8Srobert       const DecodedThread::EventsStats &events_stats =
406*f6aab3d8Srobert           decoded_thread_sp->GetEventsStats();
407*f6aab3d8Srobert       json_str.attributeObject("events", [&] {
408*f6aab3d8Srobert         json_str.attribute("totalCount", events_stats.total_count);
409*f6aab3d8Srobert         json_str.attributeObject("individualCounts", [&] {
410*f6aab3d8Srobert           for (const auto &event_to_count : events_stats.events_counts) {
411*f6aab3d8Srobert             json_str.attribute(
412*f6aab3d8Srobert                 TraceCursor::EventKindToString(event_to_count.first),
413*f6aab3d8Srobert                 event_to_count.second);
414*f6aab3d8Srobert           }
415*f6aab3d8Srobert         });
416*f6aab3d8Srobert       });
417*f6aab3d8Srobert       // Trace error stats
418*f6aab3d8Srobert       const DecodedThread::ErrorStats &error_stats =
419*f6aab3d8Srobert           decoded_thread_sp->GetErrorStats();
420*f6aab3d8Srobert       json_str.attributeObject("errors", [&] {
421*f6aab3d8Srobert         json_str.attribute("totalCount", error_stats.GetTotalCount());
422*f6aab3d8Srobert         json_str.attributeObject("libiptErrors", [&] {
423*f6aab3d8Srobert           for (const auto &[kind, count] : error_stats.libipt_errors) {
424*f6aab3d8Srobert             json_str.attribute(kind, count);
425*f6aab3d8Srobert           }
426*f6aab3d8Srobert         });
427*f6aab3d8Srobert         json_str.attribute("fatalErrors", error_stats.fatal_errors);
428*f6aab3d8Srobert         json_str.attribute("otherErrors", error_stats.other_errors);
429*f6aab3d8Srobert       });
430*f6aab3d8Srobert 
431*f6aab3d8Srobert       if (storage.multicpu_decoder) {
432*f6aab3d8Srobert         json_str.attribute(
433*f6aab3d8Srobert             "continuousExecutions",
434*f6aab3d8Srobert             storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid));
435*f6aab3d8Srobert         json_str.attribute(
436*f6aab3d8Srobert             "PSBBlocks",
437*f6aab3d8Srobert             storage.multicpu_decoder->GePSBBlocksCountForThread(tid));
438*f6aab3d8Srobert       }
439*f6aab3d8Srobert     });
440*f6aab3d8Srobert 
441*f6aab3d8Srobert     json_str.attributeObject("globalStats", [&] {
442*f6aab3d8Srobert       json_str.attributeObject("timingInSeconds", [&] {
443*f6aab3d8Srobert         GetTimer().ForGlobal().ForEachTimedTask(
444*f6aab3d8Srobert             [&](const std::string &name, std::chrono::milliseconds duration) {
445*f6aab3d8Srobert               json_str.attribute(name, duration.count() / 1000.0);
446*f6aab3d8Srobert             });
447*f6aab3d8Srobert       });
448*f6aab3d8Srobert       if (storage.multicpu_decoder) {
449*f6aab3d8Srobert         json_str.attribute(
450*f6aab3d8Srobert             "totalUnattributedPSBBlocks",
451*f6aab3d8Srobert             storage.multicpu_decoder->GetUnattributedPSBBlocksCount());
452*f6aab3d8Srobert         json_str.attribute(
453*f6aab3d8Srobert             "totalCountinuosExecutions",
454*f6aab3d8Srobert             storage.multicpu_decoder->GetTotalContinuousExecutionsCount());
455*f6aab3d8Srobert         json_str.attribute("totalPSBBlocks",
456*f6aab3d8Srobert                            storage.multicpu_decoder->GetTotalPSBBlocksCount());
457*f6aab3d8Srobert         json_str.attribute(
458*f6aab3d8Srobert             "totalContinuousExecutions",
459*f6aab3d8Srobert             storage.multicpu_decoder->GetTotalContinuousExecutionsCount());
460*f6aab3d8Srobert       }
461*f6aab3d8Srobert     });
462*f6aab3d8Srobert   });
463*f6aab3d8Srobert }
464*f6aab3d8Srobert 
465*f6aab3d8Srobert llvm::Expected<std::optional<uint64_t>>
GetRawTraceSize(Thread & thread)466*f6aab3d8Srobert TraceIntelPT::GetRawTraceSize(Thread &thread) {
467*f6aab3d8Srobert   if (GetUpdatedStorage().multicpu_decoder)
468*f6aab3d8Srobert     return std::nullopt; // TODO: calculate the amount of intel pt raw trace associated
469*f6aab3d8Srobert                  // with the given thread.
470*f6aab3d8Srobert   if (GetLiveProcess())
471*f6aab3d8Srobert     return GetLiveThreadBinaryDataSize(thread.GetID(),
472*f6aab3d8Srobert                                        IntelPTDataKinds::kIptTrace);
473*f6aab3d8Srobert   uint64_t size;
474*f6aab3d8Srobert   auto callback = [&](llvm::ArrayRef<uint8_t> data) {
475*f6aab3d8Srobert     size = data.size();
476*f6aab3d8Srobert     return Error::success();
477*f6aab3d8Srobert   };
478*f6aab3d8Srobert   if (Error err = OnThreadBufferRead(thread.GetID(), callback))
479*f6aab3d8Srobert     return std::move(err);
480*f6aab3d8Srobert 
481*f6aab3d8Srobert   return size;
482be691f3bSpatrick }
483be691f3bSpatrick 
GetCPUInfoForLiveProcess()484be691f3bSpatrick Expected<pt_cpu> TraceIntelPT::GetCPUInfoForLiveProcess() {
485*f6aab3d8Srobert   Expected<std::vector<uint8_t>> cpu_info =
486*f6aab3d8Srobert       GetLiveProcessBinaryData(IntelPTDataKinds::kProcFsCpuInfo);
487be691f3bSpatrick   if (!cpu_info)
488be691f3bSpatrick     return cpu_info.takeError();
489be691f3bSpatrick 
490be691f3bSpatrick   int64_t cpu_family = -1;
491be691f3bSpatrick   int64_t model = -1;
492be691f3bSpatrick   int64_t stepping = -1;
493be691f3bSpatrick   std::string vendor_id;
494be691f3bSpatrick 
495be691f3bSpatrick   StringRef rest(reinterpret_cast<const char *>(cpu_info->data()),
496be691f3bSpatrick                  cpu_info->size());
497be691f3bSpatrick   while (!rest.empty()) {
498be691f3bSpatrick     StringRef line;
499be691f3bSpatrick     std::tie(line, rest) = rest.split('\n');
500be691f3bSpatrick 
501be691f3bSpatrick     SmallVector<StringRef, 2> columns;
502be691f3bSpatrick     line.split(columns, StringRef(":"), -1, false);
503be691f3bSpatrick 
504be691f3bSpatrick     if (columns.size() < 2)
505be691f3bSpatrick       continue; // continue searching
506be691f3bSpatrick 
507be691f3bSpatrick     columns[1] = columns[1].trim(" ");
508be691f3bSpatrick     if (columns[0].contains("cpu family") &&
509be691f3bSpatrick         columns[1].getAsInteger(10, cpu_family))
510be691f3bSpatrick       continue;
511be691f3bSpatrick 
512be691f3bSpatrick     else if (columns[0].contains("model") && columns[1].getAsInteger(10, model))
513be691f3bSpatrick       continue;
514be691f3bSpatrick 
515be691f3bSpatrick     else if (columns[0].contains("stepping") &&
516be691f3bSpatrick              columns[1].getAsInteger(10, stepping))
517be691f3bSpatrick       continue;
518be691f3bSpatrick 
519be691f3bSpatrick     else if (columns[0].contains("vendor_id")) {
520be691f3bSpatrick       vendor_id = columns[1].str();
521be691f3bSpatrick       if (!vendor_id.empty())
522be691f3bSpatrick         continue;
523be691f3bSpatrick     }
524be691f3bSpatrick 
525be691f3bSpatrick     if ((cpu_family != -1) && (model != -1) && (stepping != -1) &&
526be691f3bSpatrick         (!vendor_id.empty())) {
527be691f3bSpatrick       return pt_cpu{vendor_id == "GenuineIntel" ? pcv_intel : pcv_unknown,
528be691f3bSpatrick                     static_cast<uint16_t>(cpu_family),
529be691f3bSpatrick                     static_cast<uint8_t>(model),
530be691f3bSpatrick                     static_cast<uint8_t>(stepping)};
531be691f3bSpatrick     }
532be691f3bSpatrick   }
533be691f3bSpatrick   return createStringError(inconvertibleErrorCode(),
534be691f3bSpatrick                            "Failed parsing the target's /proc/cpuinfo file");
535be691f3bSpatrick }
536be691f3bSpatrick 
GetCPUInfo()537be691f3bSpatrick Expected<pt_cpu> TraceIntelPT::GetCPUInfo() {
538be691f3bSpatrick   if (!m_cpu_info) {
539be691f3bSpatrick     if (llvm::Expected<pt_cpu> cpu_info = GetCPUInfoForLiveProcess())
540be691f3bSpatrick       m_cpu_info = *cpu_info;
541be691f3bSpatrick     else
542be691f3bSpatrick       return cpu_info.takeError();
543be691f3bSpatrick   }
544be691f3bSpatrick   return *m_cpu_info;
545be691f3bSpatrick }
546be691f3bSpatrick 
547*f6aab3d8Srobert std::optional<LinuxPerfZeroTscConversion>
GetPerfZeroTscConversion()548*f6aab3d8Srobert TraceIntelPT::GetPerfZeroTscConversion() {
549*f6aab3d8Srobert   return GetUpdatedStorage().tsc_conversion;
550be691f3bSpatrick }
551be691f3bSpatrick 
GetUpdatedStorage()552*f6aab3d8Srobert TraceIntelPT::Storage &TraceIntelPT::GetUpdatedStorage() {
553be691f3bSpatrick   RefreshLiveProcessState();
554*f6aab3d8Srobert   return m_storage;
555*f6aab3d8Srobert }
556*f6aab3d8Srobert 
DoRefreshLiveProcessState(TraceGetStateResponse state,StringRef json_response)557*f6aab3d8Srobert Error TraceIntelPT::DoRefreshLiveProcessState(TraceGetStateResponse state,
558*f6aab3d8Srobert                                               StringRef json_response) {
559*f6aab3d8Srobert   m_storage = Storage();
560*f6aab3d8Srobert 
561*f6aab3d8Srobert   Expected<TraceIntelPTGetStateResponse> intelpt_state =
562*f6aab3d8Srobert       json::parse<TraceIntelPTGetStateResponse>(json_response,
563*f6aab3d8Srobert                                                 "TraceIntelPTGetStateResponse");
564*f6aab3d8Srobert   if (!intelpt_state)
565*f6aab3d8Srobert     return intelpt_state.takeError();
566*f6aab3d8Srobert 
567*f6aab3d8Srobert   m_storage.tsc_conversion = intelpt_state->tsc_perf_zero_conversion;
568*f6aab3d8Srobert 
569*f6aab3d8Srobert   if (!intelpt_state->cpus) {
570*f6aab3d8Srobert     for (const TraceThreadState &thread_state : state.traced_threads) {
571*f6aab3d8Srobert       ThreadSP thread_sp =
572*f6aab3d8Srobert           GetLiveProcess()->GetThreadList().FindThreadByID(thread_state.tid);
573*f6aab3d8Srobert       m_storage.thread_decoders.try_emplace(
574*f6aab3d8Srobert           thread_state.tid, std::make_unique<ThreadDecoder>(thread_sp, *this));
575*f6aab3d8Srobert     }
576*f6aab3d8Srobert   } else {
577*f6aab3d8Srobert     std::vector<cpu_id_t> cpus;
578*f6aab3d8Srobert     for (const TraceCpuState &cpu : *intelpt_state->cpus)
579*f6aab3d8Srobert       cpus.push_back(cpu.id);
580*f6aab3d8Srobert 
581*f6aab3d8Srobert     std::vector<tid_t> tids;
582*f6aab3d8Srobert     for (const TraceThreadState &thread : intelpt_state->traced_threads)
583*f6aab3d8Srobert       tids.push_back(thread.tid);
584*f6aab3d8Srobert 
585*f6aab3d8Srobert     if (!intelpt_state->tsc_perf_zero_conversion)
586*f6aab3d8Srobert       return createStringError(inconvertibleErrorCode(),
587*f6aab3d8Srobert                                "Missing perf time_zero conversion values");
588*f6aab3d8Srobert     m_storage.multicpu_decoder.emplace(GetSharedPtr());
589*f6aab3d8Srobert   }
590*f6aab3d8Srobert 
591*f6aab3d8Srobert   if (m_storage.tsc_conversion) {
592*f6aab3d8Srobert     Log *log = GetLog(LLDBLog::Target);
593*f6aab3d8Srobert     LLDB_LOG(log, "TraceIntelPT found TSC conversion information");
594*f6aab3d8Srobert   }
595*f6aab3d8Srobert   return Error::success();
596*f6aab3d8Srobert }
597*f6aab3d8Srobert 
IsTraced(lldb::tid_t tid)598*f6aab3d8Srobert bool TraceIntelPT::IsTraced(lldb::tid_t tid) {
599*f6aab3d8Srobert   Storage &storage = GetUpdatedStorage();
600*f6aab3d8Srobert   if (storage.multicpu_decoder)
601*f6aab3d8Srobert     return storage.multicpu_decoder->TracesThread(tid);
602*f6aab3d8Srobert   return storage.thread_decoders.count(tid);
603be691f3bSpatrick }
604be691f3bSpatrick 
605be691f3bSpatrick // The information here should match the description of the intel-pt section
606be691f3bSpatrick // of the jLLDBTraceStart packet in the lldb/docs/lldb-gdb-remote.txt
607be691f3bSpatrick // documentation file. Similarly, it should match the CLI help messages of the
608be691f3bSpatrick // TraceIntelPTOptions.td file.
GetStartConfigurationHelp()609be691f3bSpatrick const char *TraceIntelPT::GetStartConfigurationHelp() {
610*f6aab3d8Srobert   static std::optional<std::string> message;
611*f6aab3d8Srobert   if (!message) {
612*f6aab3d8Srobert     message.emplace(formatv(R"(Parameters:
613be691f3bSpatrick 
614*f6aab3d8Srobert   See the jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt for a
615*f6aab3d8Srobert   description of each parameter below.
616be691f3bSpatrick 
617*f6aab3d8Srobert   - int iptTraceSize (defaults to {0} bytes):
618be691f3bSpatrick     [process and thread tracing]
619be691f3bSpatrick 
620*f6aab3d8Srobert   - boolean enableTsc (default to {1}):
621be691f3bSpatrick     [process and thread tracing]
622be691f3bSpatrick 
623*f6aab3d8Srobert   - int psbPeriod (defaults to {2}):
624be691f3bSpatrick     [process and thread tracing]
625be691f3bSpatrick 
626*f6aab3d8Srobert   - boolean perCpuTracing (default to {3}):
627be691f3bSpatrick     [process tracing only]
628*f6aab3d8Srobert 
629*f6aab3d8Srobert   - int processBufferSizeLimit (defaults to {4} MiB):
630*f6aab3d8Srobert     [process tracing only]
631*f6aab3d8Srobert 
632*f6aab3d8Srobert   - boolean disableCgroupFiltering (default to {5}):
633*f6aab3d8Srobert     [process tracing only])",
634*f6aab3d8Srobert                             kDefaultIptTraceSize, kDefaultEnableTscValue,
635*f6aab3d8Srobert                             kDefaultPsbPeriod, kDefaultPerCpuTracing,
636*f6aab3d8Srobert                             kDefaultProcessBufferSizeLimit / 1024 / 1024,
637*f6aab3d8Srobert                             kDefaultDisableCgroupFiltering));
638*f6aab3d8Srobert   }
639*f6aab3d8Srobert   return message->c_str();
640be691f3bSpatrick }
641be691f3bSpatrick 
Start(uint64_t ipt_trace_size,uint64_t total_buffer_size_limit,bool enable_tsc,std::optional<uint64_t> psb_period,bool per_cpu_tracing,bool disable_cgroup_filtering)642*f6aab3d8Srobert Error TraceIntelPT::Start(uint64_t ipt_trace_size,
643*f6aab3d8Srobert                           uint64_t total_buffer_size_limit, bool enable_tsc,
644*f6aab3d8Srobert                           std::optional<uint64_t> psb_period,
645*f6aab3d8Srobert                           bool per_cpu_tracing, bool disable_cgroup_filtering) {
646be691f3bSpatrick   TraceIntelPTStartRequest request;
647*f6aab3d8Srobert   request.ipt_trace_size = ipt_trace_size;
648*f6aab3d8Srobert   request.process_buffer_size_limit = total_buffer_size_limit;
649*f6aab3d8Srobert   request.enable_tsc = enable_tsc;
650*f6aab3d8Srobert   request.psb_period = psb_period;
651*f6aab3d8Srobert   request.type = GetPluginName().str();
652*f6aab3d8Srobert   request.per_cpu_tracing = per_cpu_tracing;
653*f6aab3d8Srobert   request.disable_cgroup_filtering = disable_cgroup_filtering;
654be691f3bSpatrick   return Trace::Start(toJSON(request));
655be691f3bSpatrick }
656be691f3bSpatrick 
Start(StructuredData::ObjectSP configuration)657be691f3bSpatrick Error TraceIntelPT::Start(StructuredData::ObjectSP configuration) {
658*f6aab3d8Srobert   uint64_t ipt_trace_size = kDefaultIptTraceSize;
659*f6aab3d8Srobert   uint64_t process_buffer_size_limit = kDefaultProcessBufferSizeLimit;
660be691f3bSpatrick   bool enable_tsc = kDefaultEnableTscValue;
661*f6aab3d8Srobert   std::optional<uint64_t> psb_period = kDefaultPsbPeriod;
662*f6aab3d8Srobert   bool per_cpu_tracing = kDefaultPerCpuTracing;
663*f6aab3d8Srobert   bool disable_cgroup_filtering = kDefaultDisableCgroupFiltering;
664be691f3bSpatrick 
665be691f3bSpatrick   if (configuration) {
666be691f3bSpatrick     if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
667*f6aab3d8Srobert       dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size);
668be691f3bSpatrick       dict->GetValueForKeyAsInteger("processBufferSizeLimit",
669be691f3bSpatrick                                     process_buffer_size_limit);
670be691f3bSpatrick       dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
671be691f3bSpatrick       dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
672*f6aab3d8Srobert       dict->GetValueForKeyAsBoolean("perCpuTracing", per_cpu_tracing);
673*f6aab3d8Srobert       dict->GetValueForKeyAsBoolean("disableCgroupFiltering",
674*f6aab3d8Srobert                                     disable_cgroup_filtering);
675be691f3bSpatrick     } else {
676be691f3bSpatrick       return createStringError(inconvertibleErrorCode(),
677be691f3bSpatrick                                "configuration object is not a dictionary");
678be691f3bSpatrick     }
679be691f3bSpatrick   }
680be691f3bSpatrick 
681*f6aab3d8Srobert   return Start(ipt_trace_size, process_buffer_size_limit, enable_tsc,
682*f6aab3d8Srobert                psb_period, per_cpu_tracing, disable_cgroup_filtering);
683be691f3bSpatrick }
684be691f3bSpatrick 
Start(llvm::ArrayRef<lldb::tid_t> tids,uint64_t ipt_trace_size,bool enable_tsc,std::optional<uint64_t> psb_period)685be691f3bSpatrick llvm::Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
686*f6aab3d8Srobert                                 uint64_t ipt_trace_size, bool enable_tsc,
687*f6aab3d8Srobert                                 std::optional<uint64_t> psb_period) {
688be691f3bSpatrick   TraceIntelPTStartRequest request;
689*f6aab3d8Srobert   request.ipt_trace_size = ipt_trace_size;
690*f6aab3d8Srobert   request.enable_tsc = enable_tsc;
691*f6aab3d8Srobert   request.psb_period = psb_period;
692*f6aab3d8Srobert   request.type = GetPluginName().str();
693be691f3bSpatrick   request.tids.emplace();
694be691f3bSpatrick   for (lldb::tid_t tid : tids)
695be691f3bSpatrick     request.tids->push_back(tid);
696be691f3bSpatrick   return Trace::Start(toJSON(request));
697be691f3bSpatrick }
698be691f3bSpatrick 
Start(llvm::ArrayRef<lldb::tid_t> tids,StructuredData::ObjectSP configuration)699be691f3bSpatrick Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
700be691f3bSpatrick                           StructuredData::ObjectSP configuration) {
701*f6aab3d8Srobert   uint64_t ipt_trace_size = kDefaultIptTraceSize;
702be691f3bSpatrick   bool enable_tsc = kDefaultEnableTscValue;
703*f6aab3d8Srobert   std::optional<uint64_t> psb_period = kDefaultPsbPeriod;
704be691f3bSpatrick 
705be691f3bSpatrick   if (configuration) {
706be691f3bSpatrick     if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
707*f6aab3d8Srobert       llvm::StringRef ipt_trace_size_not_parsed;
708*f6aab3d8Srobert       if (dict->GetValueForKeyAsString("iptTraceSize",
709*f6aab3d8Srobert                                        ipt_trace_size_not_parsed)) {
710*f6aab3d8Srobert         if (std::optional<uint64_t> bytes =
711*f6aab3d8Srobert                 ParsingUtils::ParseUserFriendlySizeExpression(
712*f6aab3d8Srobert                     ipt_trace_size_not_parsed))
713*f6aab3d8Srobert           ipt_trace_size = *bytes;
714*f6aab3d8Srobert         else
715*f6aab3d8Srobert           return createStringError(inconvertibleErrorCode(),
716*f6aab3d8Srobert                                    "iptTraceSize is wrong bytes expression");
717*f6aab3d8Srobert       } else {
718*f6aab3d8Srobert         dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size);
719*f6aab3d8Srobert       }
720*f6aab3d8Srobert 
721be691f3bSpatrick       dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
722be691f3bSpatrick       dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
723be691f3bSpatrick     } else {
724be691f3bSpatrick       return createStringError(inconvertibleErrorCode(),
725be691f3bSpatrick                                "configuration object is not a dictionary");
726be691f3bSpatrick     }
727be691f3bSpatrick   }
728be691f3bSpatrick 
729*f6aab3d8Srobert   return Start(tids, ipt_trace_size, enable_tsc, psb_period);
730be691f3bSpatrick }
731be691f3bSpatrick 
OnThreadBufferRead(lldb::tid_t tid,OnBinaryDataReadCallback callback)732*f6aab3d8Srobert Error TraceIntelPT::OnThreadBufferRead(lldb::tid_t tid,
733*f6aab3d8Srobert                                        OnBinaryDataReadCallback callback) {
734*f6aab3d8Srobert   return OnThreadBinaryDataRead(tid, IntelPTDataKinds::kIptTrace, callback);
735*f6aab3d8Srobert }
736*f6aab3d8Srobert 
GetTimer()737*f6aab3d8Srobert TaskTimer &TraceIntelPT::GetTimer() { return GetUpdatedStorage().task_timer; }
738*f6aab3d8Srobert 
GetThreadTimer(lldb::tid_t tid)739*f6aab3d8Srobert ScopedTaskTimer &TraceIntelPT::GetThreadTimer(lldb::tid_t tid) {
740*f6aab3d8Srobert   return GetTimer().ForThread(tid);
741*f6aab3d8Srobert }
742*f6aab3d8Srobert 
GetGlobalTimer()743*f6aab3d8Srobert ScopedTaskTimer &TraceIntelPT::GetGlobalTimer() {
744*f6aab3d8Srobert   return GetTimer().ForGlobal();
745be691f3bSpatrick }
746