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"
14bdd1243dSDimitry Andric #include "TraceCursorIntelPT.h"
1581ad6265SDimitry Andric #include "TraceIntelPTBundleLoader.h"
1681ad6265SDimitry Andric #include "TraceIntelPTBundleSaver.h"
17bdd1243dSDimitry Andric #include "TraceIntelPTConstants.h"
18e8d8bef9SDimitry Andric #include "lldb/Core/PluginManager.h"
19bdd1243dSDimitry Andric #include "lldb/Interpreter/OptionValueProperties.h"
20e8d8bef9SDimitry Andric #include "lldb/Target/Process.h"
21e8d8bef9SDimitry Andric #include "lldb/Target/Target.h"
22bdd1243dSDimitry 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 
LLDB_PLUGIN_DEFINE(TraceIntelPT)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
GetThreadTraceStartCommand(CommandInterpreter & interpreter)38fe6060f1SDimitry Andric TraceIntelPT::GetThreadTraceStartCommand(CommandInterpreter &interpreter) {
39fe6060f1SDimitry Andric   return CommandObjectSP(
40fe6060f1SDimitry Andric       new CommandObjectThreadTraceStartIntelPT(*this, interpreter));
41e8d8bef9SDimitry Andric }
42e8d8bef9SDimitry Andric 
43bdd1243dSDimitry Andric #define LLDB_PROPERTIES_traceintelpt
44bdd1243dSDimitry Andric #include "TraceIntelPTProperties.inc"
45bdd1243dSDimitry Andric 
46bdd1243dSDimitry Andric enum {
47bdd1243dSDimitry Andric #define LLDB_PROPERTIES_traceintelpt
48bdd1243dSDimitry Andric #include "TraceIntelPTPropertiesEnum.inc"
49bdd1243dSDimitry Andric };
50bdd1243dSDimitry Andric 
GetSettingName()51*5f757f3fSDimitry Andric llvm::StringRef TraceIntelPT::PluginProperties::GetSettingName() {
52*5f757f3fSDimitry Andric   return TraceIntelPT::GetPluginNameStatic();
53bdd1243dSDimitry Andric }
54bdd1243dSDimitry Andric 
PluginProperties()55bdd1243dSDimitry Andric TraceIntelPT::PluginProperties::PluginProperties() : Properties() {
56bdd1243dSDimitry Andric   m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
57bdd1243dSDimitry Andric   m_collection_sp->Initialize(g_traceintelpt_properties);
58bdd1243dSDimitry Andric }
59bdd1243dSDimitry Andric 
60bdd1243dSDimitry Andric uint64_t
GetInfiniteDecodingLoopVerificationThreshold()61bdd1243dSDimitry Andric TraceIntelPT::PluginProperties::GetInfiniteDecodingLoopVerificationThreshold() {
62bdd1243dSDimitry Andric   const uint32_t idx = ePropertyInfiniteDecodingLoopVerificationThreshold;
63*5f757f3fSDimitry Andric   return GetPropertyAtIndexAs<uint64_t>(
64*5f757f3fSDimitry Andric       idx, g_traceintelpt_properties[idx].default_uint_value);
65bdd1243dSDimitry Andric }
66bdd1243dSDimitry Andric 
GetExtremelyLargeDecodingThreshold()67bdd1243dSDimitry Andric uint64_t TraceIntelPT::PluginProperties::GetExtremelyLargeDecodingThreshold() {
68bdd1243dSDimitry Andric   const uint32_t idx = ePropertyExtremelyLargeDecodingThreshold;
69*5f757f3fSDimitry Andric   return GetPropertyAtIndexAs<uint64_t>(
70*5f757f3fSDimitry Andric       idx, g_traceintelpt_properties[idx].default_uint_value);
71bdd1243dSDimitry Andric }
72bdd1243dSDimitry Andric 
GetGlobalProperties()73bdd1243dSDimitry Andric TraceIntelPT::PluginProperties &TraceIntelPT::GetGlobalProperties() {
74bdd1243dSDimitry Andric   static TraceIntelPT::PluginProperties g_settings;
75bdd1243dSDimitry Andric   return g_settings;
76bdd1243dSDimitry Andric }
77bdd1243dSDimitry Andric 
Initialize()78e8d8bef9SDimitry Andric void TraceIntelPT::Initialize() {
79bdd1243dSDimitry Andric   PluginManager::RegisterPlugin(
80bdd1243dSDimitry Andric       GetPluginNameStatic(), "Intel Processor Trace",
81bdd1243dSDimitry Andric       CreateInstanceForTraceBundle, CreateInstanceForLiveProcess,
82bdd1243dSDimitry Andric       TraceIntelPTBundleLoader::GetSchema(), DebuggerInitialize);
83bdd1243dSDimitry Andric }
84bdd1243dSDimitry Andric 
DebuggerInitialize(Debugger & debugger)85bdd1243dSDimitry Andric void TraceIntelPT::DebuggerInitialize(Debugger &debugger) {
86bdd1243dSDimitry Andric   if (!PluginManager::GetSettingForProcessPlugin(
87bdd1243dSDimitry Andric           debugger, PluginProperties::GetSettingName())) {
88bdd1243dSDimitry Andric     const bool is_global_setting = true;
89bdd1243dSDimitry Andric     PluginManager::CreateSettingForTracePlugin(
90bdd1243dSDimitry Andric         debugger, GetGlobalProperties().GetValueProperties(),
9106c3fb27SDimitry Andric         "Properties for the intel-pt trace plug-in.", is_global_setting);
92bdd1243dSDimitry Andric   }
93e8d8bef9SDimitry Andric }
94e8d8bef9SDimitry Andric 
Terminate()95e8d8bef9SDimitry Andric void TraceIntelPT::Terminate() {
9681ad6265SDimitry Andric   PluginManager::UnregisterPlugin(CreateInstanceForTraceBundle);
97e8d8bef9SDimitry Andric }
98e8d8bef9SDimitry Andric 
GetSchema()99e8d8bef9SDimitry Andric StringRef TraceIntelPT::GetSchema() {
10081ad6265SDimitry Andric   return TraceIntelPTBundleLoader::GetSchema();
101e8d8bef9SDimitry Andric }
102e8d8bef9SDimitry Andric 
Dump(Stream * s) const103e8d8bef9SDimitry Andric void TraceIntelPT::Dump(Stream *s) const {}
104e8d8bef9SDimitry Andric 
SaveToDisk(FileSpec directory,bool compact)105753f127fSDimitry Andric Expected<FileSpec> TraceIntelPT::SaveToDisk(FileSpec directory, bool compact) {
106349cc55cSDimitry Andric   RefreshLiveProcessState();
107753f127fSDimitry Andric   return TraceIntelPTBundleSaver().SaveToDisk(*this, directory, compact);
108349cc55cSDimitry Andric }
109349cc55cSDimitry Andric 
CreateInstanceForTraceBundle(const json::Value & bundle_description,StringRef bundle_dir,Debugger & debugger)11081ad6265SDimitry Andric Expected<TraceSP> TraceIntelPT::CreateInstanceForTraceBundle(
11181ad6265SDimitry Andric     const json::Value &bundle_description, StringRef bundle_dir,
112fe6060f1SDimitry Andric     Debugger &debugger) {
113bdd1243dSDimitry Andric   return TraceIntelPTBundleLoader(debugger, bundle_description, bundle_dir)
11481ad6265SDimitry Andric       .Load();
115e8d8bef9SDimitry Andric }
116e8d8bef9SDimitry Andric 
CreateInstanceForLiveProcess(Process & process)117fe6060f1SDimitry Andric Expected<TraceSP> TraceIntelPT::CreateInstanceForLiveProcess(Process &process) {
118fe6060f1SDimitry Andric   TraceSP instance(new TraceIntelPT(process));
119fe6060f1SDimitry Andric   process.GetTarget().SetTrace(instance);
120fe6060f1SDimitry Andric   return instance;
121fe6060f1SDimitry Andric }
122fe6060f1SDimitry Andric 
GetSharedPtr()12381ad6265SDimitry Andric TraceIntelPTSP TraceIntelPT::GetSharedPtr() {
12481ad6265SDimitry Andric   return std::static_pointer_cast<TraceIntelPT>(shared_from_this());
125e8d8bef9SDimitry Andric }
126e8d8bef9SDimitry Andric 
GetTraceMode()127bdd1243dSDimitry Andric TraceIntelPT::TraceMode TraceIntelPT::GetTraceMode() { return trace_mode; }
128bdd1243dSDimitry Andric 
CreateInstanceForPostmortemTrace(JSONTraceBundleDescription & bundle_description,ArrayRef<ProcessSP> traced_processes,ArrayRef<ThreadPostMortemTraceSP> traced_threads,TraceMode trace_mode)12981ad6265SDimitry Andric TraceIntelPTSP TraceIntelPT::CreateInstanceForPostmortemTrace(
130bdd1243dSDimitry Andric     JSONTraceBundleDescription &bundle_description,
131bdd1243dSDimitry Andric     ArrayRef<ProcessSP> traced_processes,
132bdd1243dSDimitry Andric     ArrayRef<ThreadPostMortemTraceSP> traced_threads, TraceMode trace_mode) {
133bdd1243dSDimitry Andric   TraceIntelPTSP trace_sp(
134bdd1243dSDimitry Andric       new TraceIntelPT(bundle_description, traced_processes, trace_mode));
135bdd1243dSDimitry Andric   trace_sp->m_storage.tsc_conversion =
136bdd1243dSDimitry Andric       bundle_description.tsc_perf_zero_conversion;
137fe6060f1SDimitry Andric 
13881ad6265SDimitry Andric   if (bundle_description.cpus) {
13981ad6265SDimitry Andric     std::vector<cpu_id_t> cpus;
14081ad6265SDimitry Andric 
14181ad6265SDimitry Andric     for (const JSONCpu &cpu : *bundle_description.cpus) {
14281ad6265SDimitry Andric       trace_sp->SetPostMortemCpuDataFile(cpu.id, IntelPTDataKinds::kIptTrace,
14381ad6265SDimitry Andric                                          FileSpec(cpu.ipt_trace));
14481ad6265SDimitry Andric 
14581ad6265SDimitry Andric       trace_sp->SetPostMortemCpuDataFile(
14681ad6265SDimitry Andric           cpu.id, IntelPTDataKinds::kPerfContextSwitchTrace,
14781ad6265SDimitry Andric           FileSpec(cpu.context_switch_trace));
14881ad6265SDimitry Andric       cpus.push_back(cpu.id);
14981ad6265SDimitry Andric     }
15081ad6265SDimitry Andric 
151bdd1243dSDimitry Andric     if (trace_mode == TraceMode::UserMode) {
15281ad6265SDimitry Andric       trace_sp->m_storage.multicpu_decoder.emplace(trace_sp);
153bdd1243dSDimitry Andric     }
154bdd1243dSDimitry Andric   }
155bdd1243dSDimitry Andric 
156bdd1243dSDimitry Andric   if (!bundle_description.cpus || trace_mode == TraceMode::KernelMode) {
15781ad6265SDimitry Andric     for (const ThreadPostMortemTraceSP &thread : traced_threads) {
15881ad6265SDimitry Andric       trace_sp->m_storage.thread_decoders.try_emplace(
15981ad6265SDimitry Andric           thread->GetID(), std::make_unique<ThreadDecoder>(thread, *trace_sp));
160bdd1243dSDimitry Andric       if (const std::optional<FileSpec> &trace_file = thread->GetTraceFile()) {
16181ad6265SDimitry Andric         trace_sp->SetPostMortemThreadDataFile(
16281ad6265SDimitry Andric             thread->GetID(), IntelPTDataKinds::kIptTrace, *trace_file);
16381ad6265SDimitry Andric       }
16481ad6265SDimitry Andric     }
16581ad6265SDimitry Andric   }
16681ad6265SDimitry Andric 
16781ad6265SDimitry Andric   for (const ProcessSP &process_sp : traced_processes)
16881ad6265SDimitry Andric     process_sp->GetTarget().SetTrace(trace_sp);
16981ad6265SDimitry Andric   return trace_sp;
17081ad6265SDimitry Andric }
17181ad6265SDimitry Andric 
TraceIntelPT(JSONTraceBundleDescription & bundle_description,ArrayRef<ProcessSP> traced_processes,TraceMode trace_mode)17281ad6265SDimitry Andric TraceIntelPT::TraceIntelPT(JSONTraceBundleDescription &bundle_description,
173bdd1243dSDimitry Andric                            ArrayRef<ProcessSP> traced_processes,
174bdd1243dSDimitry Andric                            TraceMode trace_mode)
17581ad6265SDimitry Andric     : Trace(traced_processes, bundle_description.GetCpuIds()),
176bdd1243dSDimitry Andric       m_cpu_info(bundle_description.cpu_info), trace_mode(trace_mode) {}
17781ad6265SDimitry Andric 
Decode(Thread & thread)17881ad6265SDimitry Andric Expected<DecodedThreadSP> TraceIntelPT::Decode(Thread &thread) {
17981ad6265SDimitry Andric   if (const char *error = RefreshLiveProcessState())
18081ad6265SDimitry Andric     return createStringError(inconvertibleErrorCode(), error);
18181ad6265SDimitry Andric 
18281ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
18381ad6265SDimitry Andric   if (storage.multicpu_decoder)
18481ad6265SDimitry Andric     return storage.multicpu_decoder->Decode(thread);
18581ad6265SDimitry Andric 
18681ad6265SDimitry Andric   auto it = storage.thread_decoders.find(thread.GetID());
18781ad6265SDimitry Andric   if (it == storage.thread_decoders.end())
18881ad6265SDimitry Andric     return createStringError(inconvertibleErrorCode(), "thread not traced");
189fe6060f1SDimitry Andric   return it->second->Decode();
190e8d8bef9SDimitry Andric }
191e8d8bef9SDimitry Andric 
FindBeginningOfTimeNanos()192bdd1243dSDimitry Andric Expected<std::optional<uint64_t>> TraceIntelPT::FindBeginningOfTimeNanos() {
193972a253aSDimitry Andric   Storage &storage = GetUpdatedStorage();
194972a253aSDimitry Andric   if (storage.beginning_of_time_nanos_calculated)
195972a253aSDimitry Andric     return storage.beginning_of_time_nanos;
196972a253aSDimitry Andric   storage.beginning_of_time_nanos_calculated = true;
197972a253aSDimitry Andric 
198972a253aSDimitry Andric   if (!storage.tsc_conversion)
199bdd1243dSDimitry Andric     return std::nullopt;
200972a253aSDimitry Andric 
201bdd1243dSDimitry Andric   std::optional<uint64_t> lowest_tsc;
202972a253aSDimitry Andric 
203972a253aSDimitry Andric   if (storage.multicpu_decoder) {
204bdd1243dSDimitry Andric     if (Expected<std::optional<uint64_t>> tsc =
205972a253aSDimitry Andric             storage.multicpu_decoder->FindLowestTSC()) {
206972a253aSDimitry Andric       lowest_tsc = *tsc;
207972a253aSDimitry Andric     } else {
208972a253aSDimitry Andric       return tsc.takeError();
209972a253aSDimitry Andric     }
210972a253aSDimitry Andric   }
211972a253aSDimitry Andric 
212972a253aSDimitry Andric   for (auto &decoder : storage.thread_decoders) {
213bdd1243dSDimitry Andric     Expected<std::optional<uint64_t>> tsc = decoder.second->FindLowestTSC();
214972a253aSDimitry Andric     if (!tsc)
215972a253aSDimitry Andric       return tsc.takeError();
216972a253aSDimitry Andric 
217972a253aSDimitry Andric     if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))
218972a253aSDimitry Andric       lowest_tsc = **tsc;
219972a253aSDimitry Andric   }
220972a253aSDimitry Andric 
221972a253aSDimitry Andric   if (lowest_tsc) {
222972a253aSDimitry Andric     storage.beginning_of_time_nanos =
223972a253aSDimitry Andric         storage.tsc_conversion->ToNanos(*lowest_tsc);
224972a253aSDimitry Andric   }
225972a253aSDimitry Andric   return storage.beginning_of_time_nanos;
226972a253aSDimitry Andric }
227972a253aSDimitry Andric 
228bdd1243dSDimitry Andric llvm::Expected<lldb::TraceCursorSP>
CreateNewCursor(Thread & thread)22981ad6265SDimitry Andric TraceIntelPT::CreateNewCursor(Thread &thread) {
230972a253aSDimitry Andric   if (Expected<DecodedThreadSP> decoded_thread = Decode(thread)) {
231bdd1243dSDimitry Andric     if (Expected<std::optional<uint64_t>> beginning_of_time =
232972a253aSDimitry Andric             FindBeginningOfTimeNanos())
233bdd1243dSDimitry Andric       return std::make_shared<TraceCursorIntelPT>(
234972a253aSDimitry Andric           thread.shared_from_this(), *decoded_thread, m_storage.tsc_conversion,
235972a253aSDimitry Andric           *beginning_of_time);
23681ad6265SDimitry Andric     else
237972a253aSDimitry Andric       return beginning_of_time.takeError();
238972a253aSDimitry Andric   } else
23981ad6265SDimitry Andric     return decoded_thread.takeError();
240e8d8bef9SDimitry Andric }
241e8d8bef9SDimitry Andric 
DumpTraceInfo(Thread & thread,Stream & s,bool verbose,bool json)242753f127fSDimitry Andric void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose,
243753f127fSDimitry Andric                                  bool json) {
24481ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
24581ad6265SDimitry Andric 
24681ad6265SDimitry Andric   lldb::tid_t tid = thread.GetID();
247753f127fSDimitry Andric   if (json) {
248753f127fSDimitry Andric     DumpTraceInfoAsJson(thread, s, verbose);
249753f127fSDimitry Andric     return;
250753f127fSDimitry Andric   }
251753f127fSDimitry Andric 
25281ad6265SDimitry Andric   s.Format("\nthread #{0}: tid = {1}", thread.GetIndexID(), thread.GetID());
25381ad6265SDimitry Andric   if (!IsTraced(tid)) {
25481ad6265SDimitry Andric     s << ", not traced\n";
255e8d8bef9SDimitry Andric     return;
256fe6060f1SDimitry Andric   }
25781ad6265SDimitry Andric   s << "\n";
25881ad6265SDimitry Andric 
25981ad6265SDimitry Andric   Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread);
26081ad6265SDimitry Andric   if (!decoded_thread_sp_or_err) {
26181ad6265SDimitry Andric     s << toString(decoded_thread_sp_or_err.takeError()) << "\n";
262fe6060f1SDimitry Andric     return;
263e8d8bef9SDimitry Andric   }
264e8d8bef9SDimitry Andric 
26581ad6265SDimitry Andric   DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err;
26681ad6265SDimitry Andric 
267bdd1243dSDimitry Andric   Expected<std::optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread);
26881ad6265SDimitry Andric   if (!raw_size_or_error) {
26981ad6265SDimitry Andric     s.Format("  {0}\n", toString(raw_size_or_error.takeError()));
27081ad6265SDimitry Andric     return;
27181ad6265SDimitry Andric   }
272bdd1243dSDimitry Andric   std::optional<uint64_t> raw_size = *raw_size_or_error;
27381ad6265SDimitry Andric 
274753f127fSDimitry Andric   s.Format("\n  Trace technology: {0}\n", GetPluginName());
275753f127fSDimitry Andric 
27681ad6265SDimitry Andric   /// Instruction stats
27781ad6265SDimitry Andric   {
27881ad6265SDimitry Andric     uint64_t items_count = decoded_thread_sp->GetItemsCount();
27981ad6265SDimitry Andric     uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage();
28081ad6265SDimitry Andric 
281753f127fSDimitry Andric     s.Format("\n  Total number of trace items: {0}\n", items_count);
28281ad6265SDimitry Andric 
28381ad6265SDimitry Andric     s << "\n  Memory usage:\n";
28481ad6265SDimitry Andric     if (raw_size)
28581ad6265SDimitry Andric       s.Format("    Raw trace size: {0} KiB\n", *raw_size / 1024);
28681ad6265SDimitry Andric 
28781ad6265SDimitry Andric     s.Format(
28881ad6265SDimitry Andric         "    Total approximate memory usage (excluding raw trace): {0:2} KiB\n",
28981ad6265SDimitry Andric         (double)mem_used / 1024);
29081ad6265SDimitry Andric     if (items_count != 0)
29181ad6265SDimitry Andric       s.Format("    Average memory usage per item (excluding raw trace): "
29281ad6265SDimitry Andric                "{0:2} bytes\n",
29381ad6265SDimitry Andric                (double)mem_used / items_count);
29481ad6265SDimitry Andric   }
29581ad6265SDimitry Andric 
29681ad6265SDimitry Andric   // Timing
29781ad6265SDimitry Andric   {
29881ad6265SDimitry Andric     s << "\n  Timing for this thread:\n";
29981ad6265SDimitry Andric     auto print_duration = [&](const std::string &name,
30081ad6265SDimitry Andric                               std::chrono::milliseconds duration) {
30181ad6265SDimitry Andric       s.Format("    {0}: {1:2}s\n", name, duration.count() / 1000.0);
30281ad6265SDimitry Andric     };
303753f127fSDimitry Andric     GetThreadTimer(tid).ForEachTimedTask(print_duration);
30481ad6265SDimitry Andric 
30581ad6265SDimitry Andric     s << "\n  Timing for global tasks:\n";
306753f127fSDimitry Andric     GetGlobalTimer().ForEachTimedTask(print_duration);
30781ad6265SDimitry Andric   }
30881ad6265SDimitry Andric 
30981ad6265SDimitry Andric   // Instruction events stats
31081ad6265SDimitry Andric   {
31181ad6265SDimitry Andric     const DecodedThread::EventsStats &events_stats =
31281ad6265SDimitry Andric         decoded_thread_sp->GetEventsStats();
31381ad6265SDimitry Andric     s << "\n  Events:\n";
31481ad6265SDimitry Andric     s.Format("    Number of individual events: {0}\n",
31581ad6265SDimitry Andric              events_stats.total_count);
31681ad6265SDimitry Andric     for (const auto &event_to_count : events_stats.events_counts) {
31781ad6265SDimitry Andric       s.Format("      {0}: {1}\n",
31881ad6265SDimitry Andric                TraceCursor::EventKindToString(event_to_count.first),
31981ad6265SDimitry Andric                event_to_count.second);
32081ad6265SDimitry Andric     }
32181ad6265SDimitry Andric   }
322bdd1243dSDimitry Andric   // Trace error stats
323bdd1243dSDimitry Andric   {
324bdd1243dSDimitry Andric     const DecodedThread::ErrorStats &error_stats =
325bdd1243dSDimitry Andric         decoded_thread_sp->GetErrorStats();
326bdd1243dSDimitry Andric     s << "\n  Errors:\n";
327bdd1243dSDimitry Andric     s.Format("    Number of individual errors: {0}\n",
328bdd1243dSDimitry Andric              error_stats.GetTotalCount());
329bdd1243dSDimitry Andric     s.Format("      Number of fatal errors: {0}\n", error_stats.fatal_errors);
330bdd1243dSDimitry Andric     for (const auto &[kind, count] : error_stats.libipt_errors) {
331bdd1243dSDimitry Andric       s.Format("     Number of libipt errors of kind [{0}]: {1}\n", kind,
332bdd1243dSDimitry Andric                count);
333bdd1243dSDimitry Andric     }
334bdd1243dSDimitry Andric     s.Format("      Number of other errors: {0}\n", error_stats.other_errors);
335bdd1243dSDimitry Andric   }
33681ad6265SDimitry Andric 
33781ad6265SDimitry Andric   if (storage.multicpu_decoder) {
33881ad6265SDimitry Andric     s << "\n  Multi-cpu decoding:\n";
33981ad6265SDimitry Andric     s.Format("    Total number of continuous executions found: {0}\n",
34081ad6265SDimitry Andric              storage.multicpu_decoder->GetTotalContinuousExecutionsCount());
34181ad6265SDimitry Andric     s.Format(
34281ad6265SDimitry Andric         "    Number of continuous executions for this thread: {0}\n",
34381ad6265SDimitry Andric         storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid));
344753f127fSDimitry Andric     s.Format("    Total number of PSB blocks found: {0}\n",
345753f127fSDimitry Andric              storage.multicpu_decoder->GetTotalPSBBlocksCount());
346753f127fSDimitry Andric     s.Format("    Number of PSB blocks for this thread: {0}\n",
347753f127fSDimitry Andric              storage.multicpu_decoder->GePSBBlocksCountForThread(tid));
348753f127fSDimitry Andric     s.Format("    Total number of unattributed PSB blocks found: {0}\n",
349753f127fSDimitry Andric              storage.multicpu_decoder->GetUnattributedPSBBlocksCount());
35081ad6265SDimitry Andric   }
35181ad6265SDimitry Andric }
35281ad6265SDimitry Andric 
DumpTraceInfoAsJson(Thread & thread,Stream & s,bool verbose)353753f127fSDimitry Andric void TraceIntelPT::DumpTraceInfoAsJson(Thread &thread, Stream &s,
354753f127fSDimitry Andric                                        bool verbose) {
355753f127fSDimitry Andric   Storage &storage = GetUpdatedStorage();
356753f127fSDimitry Andric 
357753f127fSDimitry Andric   lldb::tid_t tid = thread.GetID();
358753f127fSDimitry Andric   json::OStream json_str(s.AsRawOstream(), 2);
359753f127fSDimitry Andric   if (!IsTraced(tid)) {
360753f127fSDimitry Andric     s << "error: thread not traced\n";
361753f127fSDimitry Andric     return;
362753f127fSDimitry Andric   }
363753f127fSDimitry Andric 
364bdd1243dSDimitry Andric   Expected<std::optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread);
365753f127fSDimitry Andric   if (!raw_size_or_error) {
366753f127fSDimitry Andric     s << "error: " << toString(raw_size_or_error.takeError()) << "\n";
367753f127fSDimitry Andric     return;
368753f127fSDimitry Andric   }
369753f127fSDimitry Andric 
370753f127fSDimitry Andric   Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread);
371753f127fSDimitry Andric   if (!decoded_thread_sp_or_err) {
372753f127fSDimitry Andric     s << "error: " << toString(decoded_thread_sp_or_err.takeError()) << "\n";
373753f127fSDimitry Andric     return;
374753f127fSDimitry Andric   }
375753f127fSDimitry Andric   DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err;
376753f127fSDimitry Andric 
377753f127fSDimitry Andric   json_str.object([&] {
378753f127fSDimitry Andric     json_str.attribute("traceTechnology", "intel-pt");
379753f127fSDimitry Andric     json_str.attributeObject("threadStats", [&] {
380753f127fSDimitry Andric       json_str.attribute("tid", tid);
381753f127fSDimitry Andric 
382753f127fSDimitry Andric       uint64_t insn_len = decoded_thread_sp->GetItemsCount();
383753f127fSDimitry Andric       json_str.attribute("traceItemsCount", insn_len);
384753f127fSDimitry Andric 
385753f127fSDimitry Andric       // Instruction stats
386753f127fSDimitry Andric       uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage();
387753f127fSDimitry Andric       json_str.attributeObject("memoryUsage", [&] {
388753f127fSDimitry Andric         json_str.attribute("totalInBytes", std::to_string(mem_used));
389bdd1243dSDimitry Andric         std::optional<double> avg;
390753f127fSDimitry Andric         if (insn_len != 0)
391753f127fSDimitry Andric           avg = double(mem_used) / insn_len;
392753f127fSDimitry Andric         json_str.attribute("avgPerItemInBytes", avg);
393753f127fSDimitry Andric       });
394753f127fSDimitry Andric 
395753f127fSDimitry Andric       // Timing
396753f127fSDimitry Andric       json_str.attributeObject("timingInSeconds", [&] {
397753f127fSDimitry Andric         GetTimer().ForThread(tid).ForEachTimedTask(
398753f127fSDimitry Andric             [&](const std::string &name, std::chrono::milliseconds duration) {
399753f127fSDimitry Andric               json_str.attribute(name, duration.count() / 1000.0);
400753f127fSDimitry Andric             });
401753f127fSDimitry Andric       });
402753f127fSDimitry Andric 
403753f127fSDimitry Andric       // Instruction events stats
404753f127fSDimitry Andric       const DecodedThread::EventsStats &events_stats =
405753f127fSDimitry Andric           decoded_thread_sp->GetEventsStats();
406753f127fSDimitry Andric       json_str.attributeObject("events", [&] {
407753f127fSDimitry Andric         json_str.attribute("totalCount", events_stats.total_count);
408753f127fSDimitry Andric         json_str.attributeObject("individualCounts", [&] {
409753f127fSDimitry Andric           for (const auto &event_to_count : events_stats.events_counts) {
410753f127fSDimitry Andric             json_str.attribute(
411753f127fSDimitry Andric                 TraceCursor::EventKindToString(event_to_count.first),
412753f127fSDimitry Andric                 event_to_count.second);
413753f127fSDimitry Andric           }
414753f127fSDimitry Andric         });
415753f127fSDimitry Andric       });
416bdd1243dSDimitry Andric       // Trace error stats
417bdd1243dSDimitry Andric       const DecodedThread::ErrorStats &error_stats =
418bdd1243dSDimitry Andric           decoded_thread_sp->GetErrorStats();
419bdd1243dSDimitry Andric       json_str.attributeObject("errors", [&] {
420bdd1243dSDimitry Andric         json_str.attribute("totalCount", error_stats.GetTotalCount());
421bdd1243dSDimitry Andric         json_str.attributeObject("libiptErrors", [&] {
422bdd1243dSDimitry Andric           for (const auto &[kind, count] : error_stats.libipt_errors) {
423bdd1243dSDimitry Andric             json_str.attribute(kind, count);
424bdd1243dSDimitry Andric           }
425bdd1243dSDimitry Andric         });
426bdd1243dSDimitry Andric         json_str.attribute("fatalErrors", error_stats.fatal_errors);
427bdd1243dSDimitry Andric         json_str.attribute("otherErrors", error_stats.other_errors);
428bdd1243dSDimitry Andric       });
429753f127fSDimitry Andric 
430753f127fSDimitry Andric       if (storage.multicpu_decoder) {
431753f127fSDimitry Andric         json_str.attribute(
432753f127fSDimitry Andric             "continuousExecutions",
433753f127fSDimitry Andric             storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid));
434753f127fSDimitry Andric         json_str.attribute(
435753f127fSDimitry Andric             "PSBBlocks",
436753f127fSDimitry Andric             storage.multicpu_decoder->GePSBBlocksCountForThread(tid));
437753f127fSDimitry Andric       }
438bdd1243dSDimitry Andric     });
439753f127fSDimitry Andric 
440753f127fSDimitry Andric     json_str.attributeObject("globalStats", [&] {
441753f127fSDimitry Andric       json_str.attributeObject("timingInSeconds", [&] {
442753f127fSDimitry Andric         GetTimer().ForGlobal().ForEachTimedTask(
443753f127fSDimitry Andric             [&](const std::string &name, std::chrono::milliseconds duration) {
444753f127fSDimitry Andric               json_str.attribute(name, duration.count() / 1000.0);
445753f127fSDimitry Andric             });
446753f127fSDimitry Andric       });
447753f127fSDimitry Andric       if (storage.multicpu_decoder) {
448753f127fSDimitry Andric         json_str.attribute(
449753f127fSDimitry Andric             "totalUnattributedPSBBlocks",
450753f127fSDimitry Andric             storage.multicpu_decoder->GetUnattributedPSBBlocksCount());
451753f127fSDimitry Andric         json_str.attribute(
452753f127fSDimitry Andric             "totalCountinuosExecutions",
453753f127fSDimitry Andric             storage.multicpu_decoder->GetTotalContinuousExecutionsCount());
454753f127fSDimitry Andric         json_str.attribute("totalPSBBlocks",
455753f127fSDimitry Andric                            storage.multicpu_decoder->GetTotalPSBBlocksCount());
456753f127fSDimitry Andric         json_str.attribute(
457753f127fSDimitry Andric             "totalContinuousExecutions",
458753f127fSDimitry Andric             storage.multicpu_decoder->GetTotalContinuousExecutionsCount());
459753f127fSDimitry Andric       }
460753f127fSDimitry Andric     });
461753f127fSDimitry Andric   });
462753f127fSDimitry Andric }
463753f127fSDimitry Andric 
464bdd1243dSDimitry Andric llvm::Expected<std::optional<uint64_t>>
GetRawTraceSize(Thread & thread)46581ad6265SDimitry Andric TraceIntelPT::GetRawTraceSize(Thread &thread) {
46681ad6265SDimitry Andric   if (GetUpdatedStorage().multicpu_decoder)
467bdd1243dSDimitry Andric     return std::nullopt; // TODO: calculate the amount of intel pt raw trace associated
46881ad6265SDimitry Andric                  // with the given thread.
46981ad6265SDimitry Andric   if (GetLiveProcess())
47081ad6265SDimitry Andric     return GetLiveThreadBinaryDataSize(thread.GetID(),
47181ad6265SDimitry Andric                                        IntelPTDataKinds::kIptTrace);
47281ad6265SDimitry Andric   uint64_t size;
47381ad6265SDimitry Andric   auto callback = [&](llvm::ArrayRef<uint8_t> data) {
47481ad6265SDimitry Andric     size = data.size();
47581ad6265SDimitry Andric     return Error::success();
47681ad6265SDimitry Andric   };
47781ad6265SDimitry Andric   if (Error err = OnThreadBufferRead(thread.GetID(), callback))
47881ad6265SDimitry Andric     return std::move(err);
47981ad6265SDimitry Andric 
48081ad6265SDimitry Andric   return size;
481fe6060f1SDimitry Andric }
482fe6060f1SDimitry Andric 
GetCPUInfoForLiveProcess()483fe6060f1SDimitry Andric Expected<pt_cpu> TraceIntelPT::GetCPUInfoForLiveProcess() {
48481ad6265SDimitry Andric   Expected<std::vector<uint8_t>> cpu_info =
48581ad6265SDimitry Andric       GetLiveProcessBinaryData(IntelPTDataKinds::kProcFsCpuInfo);
486fe6060f1SDimitry Andric   if (!cpu_info)
487fe6060f1SDimitry Andric     return cpu_info.takeError();
488fe6060f1SDimitry Andric 
489fe6060f1SDimitry Andric   int64_t cpu_family = -1;
490fe6060f1SDimitry Andric   int64_t model = -1;
491fe6060f1SDimitry Andric   int64_t stepping = -1;
492fe6060f1SDimitry Andric   std::string vendor_id;
493fe6060f1SDimitry Andric 
494fe6060f1SDimitry Andric   StringRef rest(reinterpret_cast<const char *>(cpu_info->data()),
495fe6060f1SDimitry Andric                  cpu_info->size());
496fe6060f1SDimitry Andric   while (!rest.empty()) {
497fe6060f1SDimitry Andric     StringRef line;
498fe6060f1SDimitry Andric     std::tie(line, rest) = rest.split('\n');
499fe6060f1SDimitry Andric 
500fe6060f1SDimitry Andric     SmallVector<StringRef, 2> columns;
501fe6060f1SDimitry Andric     line.split(columns, StringRef(":"), -1, false);
502fe6060f1SDimitry Andric 
503fe6060f1SDimitry Andric     if (columns.size() < 2)
504fe6060f1SDimitry Andric       continue; // continue searching
505fe6060f1SDimitry Andric 
506fe6060f1SDimitry Andric     columns[1] = columns[1].trim(" ");
507fe6060f1SDimitry Andric     if (columns[0].contains("cpu family") &&
508fe6060f1SDimitry Andric         columns[1].getAsInteger(10, cpu_family))
509fe6060f1SDimitry Andric       continue;
510fe6060f1SDimitry Andric 
511fe6060f1SDimitry Andric     else if (columns[0].contains("model") && columns[1].getAsInteger(10, model))
512fe6060f1SDimitry Andric       continue;
513fe6060f1SDimitry Andric 
514fe6060f1SDimitry Andric     else if (columns[0].contains("stepping") &&
515fe6060f1SDimitry Andric              columns[1].getAsInteger(10, stepping))
516fe6060f1SDimitry Andric       continue;
517fe6060f1SDimitry Andric 
518fe6060f1SDimitry Andric     else if (columns[0].contains("vendor_id")) {
519fe6060f1SDimitry Andric       vendor_id = columns[1].str();
520fe6060f1SDimitry Andric       if (!vendor_id.empty())
521fe6060f1SDimitry Andric         continue;
522fe6060f1SDimitry Andric     }
523fe6060f1SDimitry Andric 
524fe6060f1SDimitry Andric     if ((cpu_family != -1) && (model != -1) && (stepping != -1) &&
525fe6060f1SDimitry Andric         (!vendor_id.empty())) {
526fe6060f1SDimitry Andric       return pt_cpu{vendor_id == "GenuineIntel" ? pcv_intel : pcv_unknown,
527fe6060f1SDimitry Andric                     static_cast<uint16_t>(cpu_family),
528fe6060f1SDimitry Andric                     static_cast<uint8_t>(model),
529fe6060f1SDimitry Andric                     static_cast<uint8_t>(stepping)};
530fe6060f1SDimitry Andric     }
531fe6060f1SDimitry Andric   }
532fe6060f1SDimitry Andric   return createStringError(inconvertibleErrorCode(),
533fe6060f1SDimitry Andric                            "Failed parsing the target's /proc/cpuinfo file");
534fe6060f1SDimitry Andric }
535fe6060f1SDimitry Andric 
GetCPUInfo()536fe6060f1SDimitry Andric Expected<pt_cpu> TraceIntelPT::GetCPUInfo() {
537fe6060f1SDimitry Andric   if (!m_cpu_info) {
538fe6060f1SDimitry Andric     if (llvm::Expected<pt_cpu> cpu_info = GetCPUInfoForLiveProcess())
539fe6060f1SDimitry Andric       m_cpu_info = *cpu_info;
540fe6060f1SDimitry Andric     else
541fe6060f1SDimitry Andric       return cpu_info.takeError();
542fe6060f1SDimitry Andric   }
543fe6060f1SDimitry Andric   return *m_cpu_info;
544fe6060f1SDimitry Andric }
545fe6060f1SDimitry Andric 
546bdd1243dSDimitry Andric std::optional<LinuxPerfZeroTscConversion>
GetPerfZeroTscConversion()54781ad6265SDimitry Andric TraceIntelPT::GetPerfZeroTscConversion() {
54881ad6265SDimitry Andric   return GetUpdatedStorage().tsc_conversion;
549fe6060f1SDimitry Andric }
550fe6060f1SDimitry Andric 
GetUpdatedStorage()55181ad6265SDimitry Andric TraceIntelPT::Storage &TraceIntelPT::GetUpdatedStorage() {
55281ad6265SDimitry Andric   RefreshLiveProcessState();
55381ad6265SDimitry Andric   return m_storage;
554fe6060f1SDimitry Andric }
55581ad6265SDimitry Andric 
DoRefreshLiveProcessState(TraceGetStateResponse state,StringRef json_response)55681ad6265SDimitry Andric Error TraceIntelPT::DoRefreshLiveProcessState(TraceGetStateResponse state,
55781ad6265SDimitry Andric                                               StringRef json_response) {
55881ad6265SDimitry Andric   m_storage = Storage();
55981ad6265SDimitry Andric 
56081ad6265SDimitry Andric   Expected<TraceIntelPTGetStateResponse> intelpt_state =
56181ad6265SDimitry Andric       json::parse<TraceIntelPTGetStateResponse>(json_response,
56281ad6265SDimitry Andric                                                 "TraceIntelPTGetStateResponse");
56381ad6265SDimitry Andric   if (!intelpt_state)
56481ad6265SDimitry Andric     return intelpt_state.takeError();
56581ad6265SDimitry Andric 
56681ad6265SDimitry Andric   m_storage.tsc_conversion = intelpt_state->tsc_perf_zero_conversion;
56781ad6265SDimitry Andric 
56881ad6265SDimitry Andric   if (!intelpt_state->cpus) {
56981ad6265SDimitry Andric     for (const TraceThreadState &thread_state : state.traced_threads) {
57081ad6265SDimitry Andric       ThreadSP thread_sp =
57181ad6265SDimitry Andric           GetLiveProcess()->GetThreadList().FindThreadByID(thread_state.tid);
57281ad6265SDimitry Andric       m_storage.thread_decoders.try_emplace(
57381ad6265SDimitry Andric           thread_state.tid, std::make_unique<ThreadDecoder>(thread_sp, *this));
57481ad6265SDimitry Andric     }
57581ad6265SDimitry Andric   } else {
57681ad6265SDimitry Andric     std::vector<cpu_id_t> cpus;
57781ad6265SDimitry Andric     for (const TraceCpuState &cpu : *intelpt_state->cpus)
57881ad6265SDimitry Andric       cpus.push_back(cpu.id);
57981ad6265SDimitry Andric 
58081ad6265SDimitry Andric     std::vector<tid_t> tids;
58181ad6265SDimitry Andric     for (const TraceThreadState &thread : intelpt_state->traced_threads)
58281ad6265SDimitry Andric       tids.push_back(thread.tid);
58381ad6265SDimitry Andric 
58481ad6265SDimitry Andric     if (!intelpt_state->tsc_perf_zero_conversion)
58581ad6265SDimitry Andric       return createStringError(inconvertibleErrorCode(),
58681ad6265SDimitry Andric                                "Missing perf time_zero conversion values");
58781ad6265SDimitry Andric     m_storage.multicpu_decoder.emplace(GetSharedPtr());
58881ad6265SDimitry Andric   }
58981ad6265SDimitry Andric 
59081ad6265SDimitry Andric   if (m_storage.tsc_conversion) {
59181ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Target);
59281ad6265SDimitry Andric     LLDB_LOG(log, "TraceIntelPT found TSC conversion information");
59381ad6265SDimitry Andric   }
59481ad6265SDimitry Andric   return Error::success();
595fe6060f1SDimitry Andric }
596fe6060f1SDimitry Andric 
IsTraced(lldb::tid_t tid)597349cc55cSDimitry Andric bool TraceIntelPT::IsTraced(lldb::tid_t tid) {
59881ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
59981ad6265SDimitry Andric   if (storage.multicpu_decoder)
60081ad6265SDimitry Andric     return storage.multicpu_decoder->TracesThread(tid);
60181ad6265SDimitry Andric   return storage.thread_decoders.count(tid);
602fe6060f1SDimitry Andric }
603fe6060f1SDimitry Andric 
604fe6060f1SDimitry Andric // The information here should match the description of the intel-pt section
605fe6060f1SDimitry Andric // of the jLLDBTraceStart packet in the lldb/docs/lldb-gdb-remote.txt
606fe6060f1SDimitry Andric // documentation file. Similarly, it should match the CLI help messages of the
607fe6060f1SDimitry Andric // TraceIntelPTOptions.td file.
GetStartConfigurationHelp()608fe6060f1SDimitry Andric const char *TraceIntelPT::GetStartConfigurationHelp() {
609bdd1243dSDimitry Andric   static std::optional<std::string> message;
61081ad6265SDimitry Andric   if (!message) {
61181ad6265SDimitry Andric     message.emplace(formatv(R"(Parameters:
612fe6060f1SDimitry Andric 
61381ad6265SDimitry Andric   See the jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt for a
61481ad6265SDimitry Andric   description of each parameter below.
615fe6060f1SDimitry Andric 
61681ad6265SDimitry Andric   - int iptTraceSize (defaults to {0} bytes):
617fe6060f1SDimitry Andric     [process and thread tracing]
618fe6060f1SDimitry Andric 
61981ad6265SDimitry Andric   - boolean enableTsc (default to {1}):
620fe6060f1SDimitry Andric     [process and thread tracing]
621fe6060f1SDimitry Andric 
62281ad6265SDimitry Andric   - int psbPeriod (defaults to {2}):
623fe6060f1SDimitry Andric     [process and thread tracing]
624fe6060f1SDimitry Andric 
62581ad6265SDimitry Andric   - boolean perCpuTracing (default to {3}):
626fe6060f1SDimitry Andric     [process tracing only]
62781ad6265SDimitry Andric 
62881ad6265SDimitry Andric   - int processBufferSizeLimit (defaults to {4} MiB):
629753f127fSDimitry Andric     [process tracing only]
630753f127fSDimitry Andric 
631753f127fSDimitry Andric   - boolean disableCgroupFiltering (default to {5}):
63281ad6265SDimitry Andric     [process tracing only])",
63381ad6265SDimitry Andric                             kDefaultIptTraceSize, kDefaultEnableTscValue,
63481ad6265SDimitry Andric                             kDefaultPsbPeriod, kDefaultPerCpuTracing,
635753f127fSDimitry Andric                             kDefaultProcessBufferSizeLimit / 1024 / 1024,
636753f127fSDimitry Andric                             kDefaultDisableCgroupFiltering));
63781ad6265SDimitry Andric   }
63881ad6265SDimitry Andric   return message->c_str();
639fe6060f1SDimitry Andric }
640fe6060f1SDimitry Andric 
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)64181ad6265SDimitry Andric Error TraceIntelPT::Start(uint64_t ipt_trace_size,
64281ad6265SDimitry Andric                           uint64_t total_buffer_size_limit, bool enable_tsc,
643bdd1243dSDimitry Andric                           std::optional<uint64_t> psb_period,
644bdd1243dSDimitry Andric                           bool per_cpu_tracing, bool disable_cgroup_filtering) {
645fe6060f1SDimitry Andric   TraceIntelPTStartRequest request;
64681ad6265SDimitry Andric   request.ipt_trace_size = ipt_trace_size;
64781ad6265SDimitry Andric   request.process_buffer_size_limit = total_buffer_size_limit;
64881ad6265SDimitry Andric   request.enable_tsc = enable_tsc;
64981ad6265SDimitry Andric   request.psb_period = psb_period;
650349cc55cSDimitry Andric   request.type = GetPluginName().str();
65181ad6265SDimitry Andric   request.per_cpu_tracing = per_cpu_tracing;
652753f127fSDimitry Andric   request.disable_cgroup_filtering = disable_cgroup_filtering;
653fe6060f1SDimitry Andric   return Trace::Start(toJSON(request));
654fe6060f1SDimitry Andric }
655fe6060f1SDimitry Andric 
Start(StructuredData::ObjectSP configuration)656fe6060f1SDimitry Andric Error TraceIntelPT::Start(StructuredData::ObjectSP configuration) {
65781ad6265SDimitry Andric   uint64_t ipt_trace_size = kDefaultIptTraceSize;
65881ad6265SDimitry Andric   uint64_t process_buffer_size_limit = kDefaultProcessBufferSizeLimit;
659fe6060f1SDimitry Andric   bool enable_tsc = kDefaultEnableTscValue;
660bdd1243dSDimitry Andric   std::optional<uint64_t> psb_period = kDefaultPsbPeriod;
66181ad6265SDimitry Andric   bool per_cpu_tracing = kDefaultPerCpuTracing;
662753f127fSDimitry Andric   bool disable_cgroup_filtering = kDefaultDisableCgroupFiltering;
663fe6060f1SDimitry Andric 
664fe6060f1SDimitry Andric   if (configuration) {
665fe6060f1SDimitry Andric     if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
66681ad6265SDimitry Andric       dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size);
667fe6060f1SDimitry Andric       dict->GetValueForKeyAsInteger("processBufferSizeLimit",
668fe6060f1SDimitry Andric                                     process_buffer_size_limit);
669fe6060f1SDimitry Andric       dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
670fe6060f1SDimitry Andric       dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
67181ad6265SDimitry Andric       dict->GetValueForKeyAsBoolean("perCpuTracing", per_cpu_tracing);
672753f127fSDimitry Andric       dict->GetValueForKeyAsBoolean("disableCgroupFiltering",
673753f127fSDimitry Andric                                     disable_cgroup_filtering);
674fe6060f1SDimitry Andric     } else {
675fe6060f1SDimitry Andric       return createStringError(inconvertibleErrorCode(),
676fe6060f1SDimitry Andric                                "configuration object is not a dictionary");
677fe6060f1SDimitry Andric     }
678fe6060f1SDimitry Andric   }
679fe6060f1SDimitry Andric 
68081ad6265SDimitry Andric   return Start(ipt_trace_size, process_buffer_size_limit, enable_tsc,
681753f127fSDimitry Andric                psb_period, per_cpu_tracing, disable_cgroup_filtering);
682fe6060f1SDimitry Andric }
683fe6060f1SDimitry Andric 
Start(llvm::ArrayRef<lldb::tid_t> tids,uint64_t ipt_trace_size,bool enable_tsc,std::optional<uint64_t> psb_period)684fe6060f1SDimitry Andric llvm::Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
68581ad6265SDimitry Andric                                 uint64_t ipt_trace_size, bool enable_tsc,
686bdd1243dSDimitry Andric                                 std::optional<uint64_t> psb_period) {
687fe6060f1SDimitry Andric   TraceIntelPTStartRequest request;
68881ad6265SDimitry Andric   request.ipt_trace_size = ipt_trace_size;
68981ad6265SDimitry Andric   request.enable_tsc = enable_tsc;
69081ad6265SDimitry Andric   request.psb_period = psb_period;
691349cc55cSDimitry Andric   request.type = GetPluginName().str();
692fe6060f1SDimitry Andric   request.tids.emplace();
693fe6060f1SDimitry Andric   for (lldb::tid_t tid : tids)
694fe6060f1SDimitry Andric     request.tids->push_back(tid);
695fe6060f1SDimitry Andric   return Trace::Start(toJSON(request));
696fe6060f1SDimitry Andric }
697fe6060f1SDimitry Andric 
Start(llvm::ArrayRef<lldb::tid_t> tids,StructuredData::ObjectSP configuration)698fe6060f1SDimitry Andric Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
699fe6060f1SDimitry Andric                           StructuredData::ObjectSP configuration) {
70081ad6265SDimitry Andric   uint64_t ipt_trace_size = kDefaultIptTraceSize;
701fe6060f1SDimitry Andric   bool enable_tsc = kDefaultEnableTscValue;
702bdd1243dSDimitry Andric   std::optional<uint64_t> psb_period = kDefaultPsbPeriod;
703fe6060f1SDimitry Andric 
704fe6060f1SDimitry Andric   if (configuration) {
705fe6060f1SDimitry Andric     if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
706753f127fSDimitry Andric       llvm::StringRef ipt_trace_size_not_parsed;
707753f127fSDimitry Andric       if (dict->GetValueForKeyAsString("iptTraceSize",
708753f127fSDimitry Andric                                        ipt_trace_size_not_parsed)) {
709bdd1243dSDimitry Andric         if (std::optional<uint64_t> bytes =
710753f127fSDimitry Andric                 ParsingUtils::ParseUserFriendlySizeExpression(
711753f127fSDimitry Andric                     ipt_trace_size_not_parsed))
712753f127fSDimitry Andric           ipt_trace_size = *bytes;
713753f127fSDimitry Andric         else
714753f127fSDimitry Andric           return createStringError(inconvertibleErrorCode(),
715753f127fSDimitry Andric                                    "iptTraceSize is wrong bytes expression");
716753f127fSDimitry Andric       } else {
71781ad6265SDimitry Andric         dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size);
718753f127fSDimitry Andric       }
719753f127fSDimitry Andric 
720fe6060f1SDimitry Andric       dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
721fe6060f1SDimitry Andric       dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
722fe6060f1SDimitry Andric     } else {
723fe6060f1SDimitry Andric       return createStringError(inconvertibleErrorCode(),
724fe6060f1SDimitry Andric                                "configuration object is not a dictionary");
725fe6060f1SDimitry Andric     }
726fe6060f1SDimitry Andric   }
727fe6060f1SDimitry Andric 
72881ad6265SDimitry Andric   return Start(tids, ipt_trace_size, enable_tsc, psb_period);
729fe6060f1SDimitry Andric }
730fe6060f1SDimitry Andric 
OnThreadBufferRead(lldb::tid_t tid,OnBinaryDataReadCallback callback)73181ad6265SDimitry Andric Error TraceIntelPT::OnThreadBufferRead(lldb::tid_t tid,
73281ad6265SDimitry Andric                                        OnBinaryDataReadCallback callback) {
73381ad6265SDimitry Andric   return OnThreadBinaryDataRead(tid, IntelPTDataKinds::kIptTrace, callback);
734e8d8bef9SDimitry Andric }
73581ad6265SDimitry Andric 
GetTimer()73681ad6265SDimitry Andric TaskTimer &TraceIntelPT::GetTimer() { return GetUpdatedStorage().task_timer; }
737753f127fSDimitry Andric 
GetThreadTimer(lldb::tid_t tid)738753f127fSDimitry Andric ScopedTaskTimer &TraceIntelPT::GetThreadTimer(lldb::tid_t tid) {
739753f127fSDimitry Andric   return GetTimer().ForThread(tid);
740753f127fSDimitry Andric }
741753f127fSDimitry Andric 
GetGlobalTimer()742753f127fSDimitry Andric ScopedTaskTimer &TraceIntelPT::GetGlobalTimer() {
743753f127fSDimitry Andric   return GetTimer().ForGlobal();
744753f127fSDimitry Andric }
745