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