xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp (revision 972a253a57b6f144b0e4a3e2080a2a0076ec55a0)
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 
11*972a253aSDimitry Andric #include "TraceCursorIntelPT.h"
12*972a253aSDimitry Andric 
13fe6060f1SDimitry Andric #include "../common/ThreadPostMortemTrace.h"
14e8d8bef9SDimitry Andric #include "CommandObjectTraceStartIntelPT.h"
15fe6060f1SDimitry Andric #include "DecodedThread.h"
16fe6060f1SDimitry Andric #include "TraceIntelPTConstants.h"
1781ad6265SDimitry Andric #include "TraceIntelPTBundleLoader.h"
1881ad6265SDimitry Andric #include "TraceIntelPTBundleSaver.h"
19e8d8bef9SDimitry Andric #include "lldb/Core/PluginManager.h"
20e8d8bef9SDimitry Andric #include "lldb/Target/Process.h"
21e8d8bef9SDimitry Andric #include "lldb/Target/Target.h"
22349cc55cSDimitry Andric #include "llvm/ADT/None.h"
23e8d8bef9SDimitry Andric 
24e8d8bef9SDimitry Andric using namespace lldb;
25e8d8bef9SDimitry Andric using namespace lldb_private;
26e8d8bef9SDimitry Andric using namespace lldb_private::trace_intel_pt;
27e8d8bef9SDimitry Andric using namespace llvm;
28e8d8bef9SDimitry Andric 
29e8d8bef9SDimitry Andric LLDB_PLUGIN_DEFINE(TraceIntelPT)
30e8d8bef9SDimitry Andric 
31fe6060f1SDimitry Andric lldb::CommandObjectSP
32fe6060f1SDimitry Andric TraceIntelPT::GetProcessTraceStartCommand(CommandInterpreter &interpreter) {
33fe6060f1SDimitry Andric   return CommandObjectSP(
34fe6060f1SDimitry Andric       new CommandObjectProcessTraceStartIntelPT(*this, interpreter));
35fe6060f1SDimitry Andric }
36fe6060f1SDimitry Andric 
37fe6060f1SDimitry Andric lldb::CommandObjectSP
38fe6060f1SDimitry Andric TraceIntelPT::GetThreadTraceStartCommand(CommandInterpreter &interpreter) {
39fe6060f1SDimitry Andric   return CommandObjectSP(
40fe6060f1SDimitry Andric       new CommandObjectThreadTraceStartIntelPT(*this, interpreter));
41e8d8bef9SDimitry Andric }
42e8d8bef9SDimitry Andric 
43e8d8bef9SDimitry Andric void TraceIntelPT::Initialize() {
44fe6060f1SDimitry Andric   PluginManager::RegisterPlugin(GetPluginNameStatic(), "Intel Processor Trace",
4581ad6265SDimitry Andric                                 CreateInstanceForTraceBundle,
46fe6060f1SDimitry Andric                                 CreateInstanceForLiveProcess,
4781ad6265SDimitry Andric                                 TraceIntelPTBundleLoader::GetSchema());
48e8d8bef9SDimitry Andric }
49e8d8bef9SDimitry Andric 
50e8d8bef9SDimitry Andric void TraceIntelPT::Terminate() {
5181ad6265SDimitry Andric   PluginManager::UnregisterPlugin(CreateInstanceForTraceBundle);
52e8d8bef9SDimitry Andric }
53e8d8bef9SDimitry Andric 
54e8d8bef9SDimitry Andric StringRef TraceIntelPT::GetSchema() {
5581ad6265SDimitry Andric   return TraceIntelPTBundleLoader::GetSchema();
56e8d8bef9SDimitry Andric }
57e8d8bef9SDimitry Andric 
58e8d8bef9SDimitry Andric void TraceIntelPT::Dump(Stream *s) const {}
59e8d8bef9SDimitry Andric 
60753f127fSDimitry Andric Expected<FileSpec> TraceIntelPT::SaveToDisk(FileSpec directory, bool compact) {
61349cc55cSDimitry Andric   RefreshLiveProcessState();
62753f127fSDimitry Andric   return TraceIntelPTBundleSaver().SaveToDisk(*this, directory, compact);
63349cc55cSDimitry Andric }
64349cc55cSDimitry Andric 
6581ad6265SDimitry Andric Expected<TraceSP> TraceIntelPT::CreateInstanceForTraceBundle(
6681ad6265SDimitry Andric     const json::Value &bundle_description, StringRef bundle_dir,
67fe6060f1SDimitry Andric     Debugger &debugger) {
6881ad6265SDimitry Andric   return TraceIntelPTBundleLoader(debugger, bundle_description,
6981ad6265SDimitry Andric                                        bundle_dir)
7081ad6265SDimitry Andric       .Load();
71e8d8bef9SDimitry Andric }
72e8d8bef9SDimitry Andric 
73fe6060f1SDimitry Andric Expected<TraceSP> TraceIntelPT::CreateInstanceForLiveProcess(Process &process) {
74fe6060f1SDimitry Andric   TraceSP instance(new TraceIntelPT(process));
75fe6060f1SDimitry Andric   process.GetTarget().SetTrace(instance);
76fe6060f1SDimitry Andric   return instance;
77fe6060f1SDimitry Andric }
78fe6060f1SDimitry Andric 
7981ad6265SDimitry Andric TraceIntelPTSP TraceIntelPT::GetSharedPtr() {
8081ad6265SDimitry Andric   return std::static_pointer_cast<TraceIntelPT>(shared_from_this());
81e8d8bef9SDimitry Andric }
82e8d8bef9SDimitry Andric 
8381ad6265SDimitry Andric TraceIntelPTSP TraceIntelPT::CreateInstanceForPostmortemTrace(
8481ad6265SDimitry Andric     JSONTraceBundleDescription &bundle_description, ArrayRef<ProcessSP> traced_processes,
8581ad6265SDimitry Andric     ArrayRef<ThreadPostMortemTraceSP> traced_threads) {
8681ad6265SDimitry Andric   TraceIntelPTSP trace_sp(new TraceIntelPT(bundle_description, traced_processes));
8781ad6265SDimitry Andric   trace_sp->m_storage.tsc_conversion = bundle_description.tsc_perf_zero_conversion;
88fe6060f1SDimitry Andric 
8981ad6265SDimitry Andric   if (bundle_description.cpus) {
9081ad6265SDimitry Andric     std::vector<cpu_id_t> cpus;
9181ad6265SDimitry Andric 
9281ad6265SDimitry Andric     for (const JSONCpu &cpu : *bundle_description.cpus) {
9381ad6265SDimitry Andric       trace_sp->SetPostMortemCpuDataFile(cpu.id, IntelPTDataKinds::kIptTrace,
9481ad6265SDimitry Andric                                          FileSpec(cpu.ipt_trace));
9581ad6265SDimitry Andric 
9681ad6265SDimitry Andric       trace_sp->SetPostMortemCpuDataFile(
9781ad6265SDimitry Andric           cpu.id, IntelPTDataKinds::kPerfContextSwitchTrace,
9881ad6265SDimitry Andric           FileSpec(cpu.context_switch_trace));
9981ad6265SDimitry Andric       cpus.push_back(cpu.id);
10081ad6265SDimitry Andric     }
10181ad6265SDimitry Andric 
10281ad6265SDimitry Andric     std::vector<tid_t> tids;
10381ad6265SDimitry Andric     for (const JSONProcess &process : bundle_description.processes)
10481ad6265SDimitry Andric       for (const JSONThread &thread : process.threads)
10581ad6265SDimitry Andric         tids.push_back(thread.tid);
10681ad6265SDimitry Andric 
10781ad6265SDimitry Andric     trace_sp->m_storage.multicpu_decoder.emplace(trace_sp);
10881ad6265SDimitry Andric   } else {
10981ad6265SDimitry Andric     for (const ThreadPostMortemTraceSP &thread : traced_threads) {
11081ad6265SDimitry Andric       trace_sp->m_storage.thread_decoders.try_emplace(
11181ad6265SDimitry Andric           thread->GetID(), std::make_unique<ThreadDecoder>(thread, *trace_sp));
11281ad6265SDimitry Andric       if (const Optional<FileSpec> &trace_file = thread->GetTraceFile()) {
11381ad6265SDimitry Andric         trace_sp->SetPostMortemThreadDataFile(
11481ad6265SDimitry Andric             thread->GetID(), IntelPTDataKinds::kIptTrace, *trace_file);
11581ad6265SDimitry Andric       }
11681ad6265SDimitry Andric     }
11781ad6265SDimitry Andric   }
11881ad6265SDimitry Andric 
11981ad6265SDimitry Andric   for (const ProcessSP &process_sp : traced_processes)
12081ad6265SDimitry Andric     process_sp->GetTarget().SetTrace(trace_sp);
12181ad6265SDimitry Andric   return trace_sp;
12281ad6265SDimitry Andric }
12381ad6265SDimitry Andric 
12481ad6265SDimitry Andric TraceIntelPT::TraceIntelPT(JSONTraceBundleDescription &bundle_description,
12581ad6265SDimitry Andric                            ArrayRef<ProcessSP> traced_processes)
12681ad6265SDimitry Andric     : Trace(traced_processes, bundle_description.GetCpuIds()),
12781ad6265SDimitry Andric       m_cpu_info(bundle_description.cpu_info) {}
12881ad6265SDimitry Andric 
12981ad6265SDimitry Andric Expected<DecodedThreadSP> TraceIntelPT::Decode(Thread &thread) {
13081ad6265SDimitry Andric   if (const char *error = RefreshLiveProcessState())
13181ad6265SDimitry Andric     return createStringError(inconvertibleErrorCode(), error);
13281ad6265SDimitry Andric 
13381ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
13481ad6265SDimitry Andric   if (storage.multicpu_decoder)
13581ad6265SDimitry Andric     return storage.multicpu_decoder->Decode(thread);
13681ad6265SDimitry Andric 
13781ad6265SDimitry Andric   auto it = storage.thread_decoders.find(thread.GetID());
13881ad6265SDimitry Andric   if (it == storage.thread_decoders.end())
13981ad6265SDimitry Andric     return createStringError(inconvertibleErrorCode(), "thread not traced");
140fe6060f1SDimitry Andric   return it->second->Decode();
141e8d8bef9SDimitry Andric }
142e8d8bef9SDimitry Andric 
143*972a253aSDimitry Andric Expected<Optional<uint64_t>> TraceIntelPT::FindBeginningOfTimeNanos() {
144*972a253aSDimitry Andric   Storage &storage = GetUpdatedStorage();
145*972a253aSDimitry Andric   if (storage.beginning_of_time_nanos_calculated)
146*972a253aSDimitry Andric     return storage.beginning_of_time_nanos;
147*972a253aSDimitry Andric   storage.beginning_of_time_nanos_calculated = true;
148*972a253aSDimitry Andric 
149*972a253aSDimitry Andric   if (!storage.tsc_conversion)
150*972a253aSDimitry Andric     return None;
151*972a253aSDimitry Andric 
152*972a253aSDimitry Andric   Optional<uint64_t> lowest_tsc;
153*972a253aSDimitry Andric 
154*972a253aSDimitry Andric   if (storage.multicpu_decoder) {
155*972a253aSDimitry Andric     if (Expected<Optional<uint64_t>> tsc =
156*972a253aSDimitry Andric             storage.multicpu_decoder->FindLowestTSC()) {
157*972a253aSDimitry Andric       lowest_tsc = *tsc;
158*972a253aSDimitry Andric     } else {
159*972a253aSDimitry Andric       return tsc.takeError();
160*972a253aSDimitry Andric     }
161*972a253aSDimitry Andric   }
162*972a253aSDimitry Andric 
163*972a253aSDimitry Andric   for (auto &decoder : storage.thread_decoders) {
164*972a253aSDimitry Andric     Expected<Optional<uint64_t>> tsc = decoder.second->FindLowestTSC();
165*972a253aSDimitry Andric     if (!tsc)
166*972a253aSDimitry Andric       return tsc.takeError();
167*972a253aSDimitry Andric 
168*972a253aSDimitry Andric     if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))
169*972a253aSDimitry Andric       lowest_tsc = **tsc;
170*972a253aSDimitry Andric   }
171*972a253aSDimitry Andric 
172*972a253aSDimitry Andric   if (lowest_tsc) {
173*972a253aSDimitry Andric     storage.beginning_of_time_nanos =
174*972a253aSDimitry Andric         storage.tsc_conversion->ToNanos(*lowest_tsc);
175*972a253aSDimitry Andric   }
176*972a253aSDimitry Andric   return storage.beginning_of_time_nanos;
177*972a253aSDimitry Andric }
178*972a253aSDimitry Andric 
17981ad6265SDimitry Andric llvm::Expected<lldb::TraceCursorUP>
18081ad6265SDimitry Andric TraceIntelPT::CreateNewCursor(Thread &thread) {
181*972a253aSDimitry Andric   if (Expected<DecodedThreadSP> decoded_thread = Decode(thread)) {
182*972a253aSDimitry Andric     if (Expected<Optional<uint64_t>> beginning_of_time =
183*972a253aSDimitry Andric             FindBeginningOfTimeNanos())
184*972a253aSDimitry Andric       return std::make_unique<TraceCursorIntelPT>(
185*972a253aSDimitry Andric           thread.shared_from_this(), *decoded_thread, m_storage.tsc_conversion,
186*972a253aSDimitry Andric           *beginning_of_time);
18781ad6265SDimitry Andric     else
188*972a253aSDimitry Andric       return beginning_of_time.takeError();
189*972a253aSDimitry Andric   } else
19081ad6265SDimitry Andric     return decoded_thread.takeError();
191e8d8bef9SDimitry Andric }
192e8d8bef9SDimitry Andric 
193753f127fSDimitry Andric void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose,
194753f127fSDimitry Andric                                  bool json) {
19581ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
19681ad6265SDimitry Andric 
19781ad6265SDimitry Andric   lldb::tid_t tid = thread.GetID();
198753f127fSDimitry Andric   if (json) {
199753f127fSDimitry Andric     DumpTraceInfoAsJson(thread, s, verbose);
200753f127fSDimitry Andric     return;
201753f127fSDimitry Andric   }
202753f127fSDimitry Andric 
20381ad6265SDimitry Andric   s.Format("\nthread #{0}: tid = {1}", thread.GetIndexID(), thread.GetID());
20481ad6265SDimitry Andric   if (!IsTraced(tid)) {
20581ad6265SDimitry Andric     s << ", not traced\n";
206e8d8bef9SDimitry Andric     return;
207fe6060f1SDimitry Andric   }
20881ad6265SDimitry Andric   s << "\n";
20981ad6265SDimitry Andric 
21081ad6265SDimitry Andric   Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread);
21181ad6265SDimitry Andric   if (!decoded_thread_sp_or_err) {
21281ad6265SDimitry Andric     s << toString(decoded_thread_sp_or_err.takeError()) << "\n";
213fe6060f1SDimitry Andric     return;
214e8d8bef9SDimitry Andric   }
215e8d8bef9SDimitry Andric 
21681ad6265SDimitry Andric   DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err;
21781ad6265SDimitry Andric 
21881ad6265SDimitry Andric   Expected<Optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread);
21981ad6265SDimitry Andric   if (!raw_size_or_error) {
22081ad6265SDimitry Andric     s.Format("  {0}\n", toString(raw_size_or_error.takeError()));
22181ad6265SDimitry Andric     return;
22281ad6265SDimitry Andric   }
22381ad6265SDimitry Andric   Optional<uint64_t> raw_size = *raw_size_or_error;
22481ad6265SDimitry Andric 
225753f127fSDimitry Andric   s.Format("\n  Trace technology: {0}\n", GetPluginName());
226753f127fSDimitry Andric 
22781ad6265SDimitry Andric   /// Instruction stats
22881ad6265SDimitry Andric   {
22981ad6265SDimitry Andric     uint64_t items_count = decoded_thread_sp->GetItemsCount();
23081ad6265SDimitry Andric     uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage();
23181ad6265SDimitry Andric 
232753f127fSDimitry Andric     s.Format("\n  Total number of trace items: {0}\n", items_count);
23381ad6265SDimitry Andric 
23481ad6265SDimitry Andric     s << "\n  Memory usage:\n";
23581ad6265SDimitry Andric     if (raw_size)
23681ad6265SDimitry Andric       s.Format("    Raw trace size: {0} KiB\n", *raw_size / 1024);
23781ad6265SDimitry Andric 
23881ad6265SDimitry Andric     s.Format(
23981ad6265SDimitry Andric         "    Total approximate memory usage (excluding raw trace): {0:2} KiB\n",
24081ad6265SDimitry Andric         (double)mem_used / 1024);
24181ad6265SDimitry Andric     if (items_count != 0)
24281ad6265SDimitry Andric       s.Format("    Average memory usage per item (excluding raw trace): "
24381ad6265SDimitry Andric                "{0:2} bytes\n",
24481ad6265SDimitry Andric                (double)mem_used / items_count);
24581ad6265SDimitry Andric   }
24681ad6265SDimitry Andric 
24781ad6265SDimitry Andric   // Timing
24881ad6265SDimitry Andric   {
24981ad6265SDimitry Andric     s << "\n  Timing for this thread:\n";
25081ad6265SDimitry Andric     auto print_duration = [&](const std::string &name,
25181ad6265SDimitry Andric                               std::chrono::milliseconds duration) {
25281ad6265SDimitry Andric       s.Format("    {0}: {1:2}s\n", name, duration.count() / 1000.0);
25381ad6265SDimitry Andric     };
254753f127fSDimitry Andric     GetThreadTimer(tid).ForEachTimedTask(print_duration);
25581ad6265SDimitry Andric 
25681ad6265SDimitry Andric     s << "\n  Timing for global tasks:\n";
257753f127fSDimitry Andric     GetGlobalTimer().ForEachTimedTask(print_duration);
25881ad6265SDimitry Andric   }
25981ad6265SDimitry Andric 
26081ad6265SDimitry Andric   // Instruction events stats
26181ad6265SDimitry Andric   {
26281ad6265SDimitry Andric     const DecodedThread::EventsStats &events_stats =
26381ad6265SDimitry Andric         decoded_thread_sp->GetEventsStats();
26481ad6265SDimitry Andric     s << "\n  Events:\n";
26581ad6265SDimitry Andric     s.Format("    Number of individual events: {0}\n",
26681ad6265SDimitry Andric              events_stats.total_count);
26781ad6265SDimitry Andric     for (const auto &event_to_count : events_stats.events_counts) {
26881ad6265SDimitry Andric       s.Format("      {0}: {1}\n",
26981ad6265SDimitry Andric                TraceCursor::EventKindToString(event_to_count.first),
27081ad6265SDimitry Andric                event_to_count.second);
27181ad6265SDimitry Andric     }
27281ad6265SDimitry Andric   }
27381ad6265SDimitry Andric 
27481ad6265SDimitry Andric   if (storage.multicpu_decoder) {
27581ad6265SDimitry Andric     s << "\n  Multi-cpu decoding:\n";
27681ad6265SDimitry Andric     s.Format("    Total number of continuous executions found: {0}\n",
27781ad6265SDimitry Andric              storage.multicpu_decoder->GetTotalContinuousExecutionsCount());
27881ad6265SDimitry Andric     s.Format(
27981ad6265SDimitry Andric         "    Number of continuous executions for this thread: {0}\n",
28081ad6265SDimitry Andric         storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid));
281753f127fSDimitry Andric     s.Format("    Total number of PSB blocks found: {0}\n",
282753f127fSDimitry Andric              storage.multicpu_decoder->GetTotalPSBBlocksCount());
283753f127fSDimitry Andric     s.Format("    Number of PSB blocks for this thread: {0}\n",
284753f127fSDimitry Andric              storage.multicpu_decoder->GePSBBlocksCountForThread(tid));
285753f127fSDimitry Andric     s.Format("    Total number of unattributed PSB blocks found: {0}\n",
286753f127fSDimitry Andric              storage.multicpu_decoder->GetUnattributedPSBBlocksCount());
28781ad6265SDimitry Andric   }
28881ad6265SDimitry Andric 
28981ad6265SDimitry Andric   // Errors
29081ad6265SDimitry Andric   {
29181ad6265SDimitry Andric     s << "\n  Errors:\n";
29281ad6265SDimitry Andric     const DecodedThread::LibiptErrorsStats &tsc_errors_stats =
29381ad6265SDimitry Andric         decoded_thread_sp->GetTscErrorsStats();
29481ad6265SDimitry Andric     s.Format("    Number of TSC decoding errors: {0}\n",
29581ad6265SDimitry Andric              tsc_errors_stats.total_count);
29681ad6265SDimitry Andric     for (const auto &error_message_to_count :
29781ad6265SDimitry Andric          tsc_errors_stats.libipt_errors_counts) {
29881ad6265SDimitry Andric       s.Format("      {0}: {1}\n", error_message_to_count.first,
29981ad6265SDimitry Andric                error_message_to_count.second);
30081ad6265SDimitry Andric     }
30181ad6265SDimitry Andric   }
30281ad6265SDimitry Andric }
30381ad6265SDimitry Andric 
304753f127fSDimitry Andric void TraceIntelPT::DumpTraceInfoAsJson(Thread &thread, Stream &s,
305753f127fSDimitry Andric                                        bool verbose) {
306753f127fSDimitry Andric   Storage &storage = GetUpdatedStorage();
307753f127fSDimitry Andric 
308753f127fSDimitry Andric   lldb::tid_t tid = thread.GetID();
309753f127fSDimitry Andric   json::OStream json_str(s.AsRawOstream(), 2);
310753f127fSDimitry Andric   if (!IsTraced(tid)) {
311753f127fSDimitry Andric     s << "error: thread not traced\n";
312753f127fSDimitry Andric     return;
313753f127fSDimitry Andric   }
314753f127fSDimitry Andric 
315753f127fSDimitry Andric   Expected<Optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread);
316753f127fSDimitry Andric   if (!raw_size_or_error) {
317753f127fSDimitry Andric     s << "error: " << toString(raw_size_or_error.takeError()) << "\n";
318753f127fSDimitry Andric     return;
319753f127fSDimitry Andric   }
320753f127fSDimitry Andric 
321753f127fSDimitry Andric   Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread);
322753f127fSDimitry Andric   if (!decoded_thread_sp_or_err) {
323753f127fSDimitry Andric     s << "error: " << toString(decoded_thread_sp_or_err.takeError()) << "\n";
324753f127fSDimitry Andric     return;
325753f127fSDimitry Andric   }
326753f127fSDimitry Andric   DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err;
327753f127fSDimitry Andric 
328753f127fSDimitry Andric   json_str.object([&] {
329753f127fSDimitry Andric     json_str.attribute("traceTechnology", "intel-pt");
330753f127fSDimitry Andric     json_str.attributeObject("threadStats", [&] {
331753f127fSDimitry Andric       json_str.attribute("tid", tid);
332753f127fSDimitry Andric 
333753f127fSDimitry Andric       uint64_t insn_len = decoded_thread_sp->GetItemsCount();
334753f127fSDimitry Andric       json_str.attribute("traceItemsCount", insn_len);
335753f127fSDimitry Andric 
336753f127fSDimitry Andric       // Instruction stats
337753f127fSDimitry Andric       uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage();
338753f127fSDimitry Andric       json_str.attributeObject("memoryUsage", [&] {
339753f127fSDimitry Andric         json_str.attribute("totalInBytes", std::to_string(mem_used));
340753f127fSDimitry Andric         Optional<double> avg;
341753f127fSDimitry Andric         if (insn_len != 0)
342753f127fSDimitry Andric           avg = double(mem_used) / insn_len;
343753f127fSDimitry Andric         json_str.attribute("avgPerItemInBytes", avg);
344753f127fSDimitry Andric       });
345753f127fSDimitry Andric 
346753f127fSDimitry Andric       // Timing
347753f127fSDimitry Andric       json_str.attributeObject("timingInSeconds", [&] {
348753f127fSDimitry Andric         GetTimer().ForThread(tid).ForEachTimedTask(
349753f127fSDimitry Andric             [&](const std::string &name, std::chrono::milliseconds duration) {
350753f127fSDimitry Andric               json_str.attribute(name, duration.count() / 1000.0);
351753f127fSDimitry Andric             });
352753f127fSDimitry Andric       });
353753f127fSDimitry Andric 
354753f127fSDimitry Andric       // Instruction events stats
355753f127fSDimitry Andric       const DecodedThread::EventsStats &events_stats =
356753f127fSDimitry Andric           decoded_thread_sp->GetEventsStats();
357753f127fSDimitry Andric       json_str.attributeObject("events", [&] {
358753f127fSDimitry Andric         json_str.attribute("totalCount", events_stats.total_count);
359753f127fSDimitry Andric         json_str.attributeObject("individualCounts", [&] {
360753f127fSDimitry Andric           for (const auto &event_to_count : events_stats.events_counts) {
361753f127fSDimitry Andric             json_str.attribute(
362753f127fSDimitry Andric                 TraceCursor::EventKindToString(event_to_count.first),
363753f127fSDimitry Andric                 event_to_count.second);
364753f127fSDimitry Andric           }
365753f127fSDimitry Andric         });
366753f127fSDimitry Andric       });
367753f127fSDimitry Andric 
368753f127fSDimitry Andric       if (storage.multicpu_decoder) {
369753f127fSDimitry Andric         json_str.attribute(
370753f127fSDimitry Andric             "continuousExecutions",
371753f127fSDimitry Andric             storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid));
372753f127fSDimitry Andric         json_str.attribute(
373753f127fSDimitry Andric             "PSBBlocks",
374753f127fSDimitry Andric             storage.multicpu_decoder->GePSBBlocksCountForThread(tid));
375753f127fSDimitry Andric       }
376753f127fSDimitry Andric 
377753f127fSDimitry Andric       // Errors
378753f127fSDimitry Andric       const DecodedThread::LibiptErrorsStats &tsc_errors_stats =
379753f127fSDimitry Andric           decoded_thread_sp->GetTscErrorsStats();
380753f127fSDimitry Andric       json_str.attributeObject("errorItems", [&] {
381753f127fSDimitry Andric         json_str.attribute("total", tsc_errors_stats.total_count);
382753f127fSDimitry Andric         json_str.attributeObject("individualErrors", [&] {
383753f127fSDimitry Andric           for (const auto &error_message_to_count :
384753f127fSDimitry Andric                tsc_errors_stats.libipt_errors_counts) {
385753f127fSDimitry Andric             json_str.attribute(error_message_to_count.first,
386753f127fSDimitry Andric                                error_message_to_count.second);
387753f127fSDimitry Andric           }
388753f127fSDimitry Andric         });
389753f127fSDimitry Andric       });
390753f127fSDimitry Andric     });
391753f127fSDimitry Andric     json_str.attributeObject("globalStats", [&] {
392753f127fSDimitry Andric       json_str.attributeObject("timingInSeconds", [&] {
393753f127fSDimitry Andric         GetTimer().ForGlobal().ForEachTimedTask(
394753f127fSDimitry Andric             [&](const std::string &name, std::chrono::milliseconds duration) {
395753f127fSDimitry Andric               json_str.attribute(name, duration.count() / 1000.0);
396753f127fSDimitry Andric             });
397753f127fSDimitry Andric       });
398753f127fSDimitry Andric       if (storage.multicpu_decoder) {
399753f127fSDimitry Andric         json_str.attribute(
400753f127fSDimitry Andric             "totalUnattributedPSBBlocks",
401753f127fSDimitry Andric             storage.multicpu_decoder->GetUnattributedPSBBlocksCount());
402753f127fSDimitry Andric         json_str.attribute(
403753f127fSDimitry Andric             "totalCountinuosExecutions",
404753f127fSDimitry Andric             storage.multicpu_decoder->GetTotalContinuousExecutionsCount());
405753f127fSDimitry Andric         json_str.attribute("totalPSBBlocks",
406753f127fSDimitry Andric                            storage.multicpu_decoder->GetTotalPSBBlocksCount());
407753f127fSDimitry Andric         json_str.attribute(
408753f127fSDimitry Andric             "totalContinuousExecutions",
409753f127fSDimitry Andric             storage.multicpu_decoder->GetTotalContinuousExecutionsCount());
410753f127fSDimitry Andric       }
411753f127fSDimitry Andric     });
412753f127fSDimitry Andric   });
413753f127fSDimitry Andric }
414753f127fSDimitry Andric 
41581ad6265SDimitry Andric llvm::Expected<Optional<uint64_t>>
41681ad6265SDimitry Andric TraceIntelPT::GetRawTraceSize(Thread &thread) {
41781ad6265SDimitry Andric   if (GetUpdatedStorage().multicpu_decoder)
41881ad6265SDimitry Andric     return None; // TODO: calculate the amount of intel pt raw trace associated
41981ad6265SDimitry Andric                  // with the given thread.
42081ad6265SDimitry Andric   if (GetLiveProcess())
42181ad6265SDimitry Andric     return GetLiveThreadBinaryDataSize(thread.GetID(),
42281ad6265SDimitry Andric                                        IntelPTDataKinds::kIptTrace);
42381ad6265SDimitry Andric   uint64_t size;
42481ad6265SDimitry Andric   auto callback = [&](llvm::ArrayRef<uint8_t> data) {
42581ad6265SDimitry Andric     size = data.size();
42681ad6265SDimitry Andric     return Error::success();
42781ad6265SDimitry Andric   };
42881ad6265SDimitry Andric   if (Error err = OnThreadBufferRead(thread.GetID(), callback))
42981ad6265SDimitry Andric     return std::move(err);
43081ad6265SDimitry Andric 
43181ad6265SDimitry Andric   return size;
432fe6060f1SDimitry Andric }
433fe6060f1SDimitry Andric 
434fe6060f1SDimitry Andric Expected<pt_cpu> TraceIntelPT::GetCPUInfoForLiveProcess() {
43581ad6265SDimitry Andric   Expected<std::vector<uint8_t>> cpu_info =
43681ad6265SDimitry Andric       GetLiveProcessBinaryData(IntelPTDataKinds::kProcFsCpuInfo);
437fe6060f1SDimitry Andric   if (!cpu_info)
438fe6060f1SDimitry Andric     return cpu_info.takeError();
439fe6060f1SDimitry Andric 
440fe6060f1SDimitry Andric   int64_t cpu_family = -1;
441fe6060f1SDimitry Andric   int64_t model = -1;
442fe6060f1SDimitry Andric   int64_t stepping = -1;
443fe6060f1SDimitry Andric   std::string vendor_id;
444fe6060f1SDimitry Andric 
445fe6060f1SDimitry Andric   StringRef rest(reinterpret_cast<const char *>(cpu_info->data()),
446fe6060f1SDimitry Andric                  cpu_info->size());
447fe6060f1SDimitry Andric   while (!rest.empty()) {
448fe6060f1SDimitry Andric     StringRef line;
449fe6060f1SDimitry Andric     std::tie(line, rest) = rest.split('\n');
450fe6060f1SDimitry Andric 
451fe6060f1SDimitry Andric     SmallVector<StringRef, 2> columns;
452fe6060f1SDimitry Andric     line.split(columns, StringRef(":"), -1, false);
453fe6060f1SDimitry Andric 
454fe6060f1SDimitry Andric     if (columns.size() < 2)
455fe6060f1SDimitry Andric       continue; // continue searching
456fe6060f1SDimitry Andric 
457fe6060f1SDimitry Andric     columns[1] = columns[1].trim(" ");
458fe6060f1SDimitry Andric     if (columns[0].contains("cpu family") &&
459fe6060f1SDimitry Andric         columns[1].getAsInteger(10, cpu_family))
460fe6060f1SDimitry Andric       continue;
461fe6060f1SDimitry Andric 
462fe6060f1SDimitry Andric     else if (columns[0].contains("model") && columns[1].getAsInteger(10, model))
463fe6060f1SDimitry Andric       continue;
464fe6060f1SDimitry Andric 
465fe6060f1SDimitry Andric     else if (columns[0].contains("stepping") &&
466fe6060f1SDimitry Andric              columns[1].getAsInteger(10, stepping))
467fe6060f1SDimitry Andric       continue;
468fe6060f1SDimitry Andric 
469fe6060f1SDimitry Andric     else if (columns[0].contains("vendor_id")) {
470fe6060f1SDimitry Andric       vendor_id = columns[1].str();
471fe6060f1SDimitry Andric       if (!vendor_id.empty())
472fe6060f1SDimitry Andric         continue;
473fe6060f1SDimitry Andric     }
474fe6060f1SDimitry Andric 
475fe6060f1SDimitry Andric     if ((cpu_family != -1) && (model != -1) && (stepping != -1) &&
476fe6060f1SDimitry Andric         (!vendor_id.empty())) {
477fe6060f1SDimitry Andric       return pt_cpu{vendor_id == "GenuineIntel" ? pcv_intel : pcv_unknown,
478fe6060f1SDimitry Andric                     static_cast<uint16_t>(cpu_family),
479fe6060f1SDimitry Andric                     static_cast<uint8_t>(model),
480fe6060f1SDimitry Andric                     static_cast<uint8_t>(stepping)};
481fe6060f1SDimitry Andric     }
482fe6060f1SDimitry Andric   }
483fe6060f1SDimitry Andric   return createStringError(inconvertibleErrorCode(),
484fe6060f1SDimitry Andric                            "Failed parsing the target's /proc/cpuinfo file");
485fe6060f1SDimitry Andric }
486fe6060f1SDimitry Andric 
487fe6060f1SDimitry Andric Expected<pt_cpu> TraceIntelPT::GetCPUInfo() {
488fe6060f1SDimitry Andric   if (!m_cpu_info) {
489fe6060f1SDimitry Andric     if (llvm::Expected<pt_cpu> cpu_info = GetCPUInfoForLiveProcess())
490fe6060f1SDimitry Andric       m_cpu_info = *cpu_info;
491fe6060f1SDimitry Andric     else
492fe6060f1SDimitry Andric       return cpu_info.takeError();
493fe6060f1SDimitry Andric   }
494fe6060f1SDimitry Andric   return *m_cpu_info;
495fe6060f1SDimitry Andric }
496fe6060f1SDimitry Andric 
49781ad6265SDimitry Andric llvm::Optional<LinuxPerfZeroTscConversion>
49881ad6265SDimitry Andric TraceIntelPT::GetPerfZeroTscConversion() {
49981ad6265SDimitry Andric   return GetUpdatedStorage().tsc_conversion;
500fe6060f1SDimitry Andric }
501fe6060f1SDimitry Andric 
50281ad6265SDimitry Andric TraceIntelPT::Storage &TraceIntelPT::GetUpdatedStorage() {
50381ad6265SDimitry Andric   RefreshLiveProcessState();
50481ad6265SDimitry Andric   return m_storage;
505fe6060f1SDimitry Andric }
50681ad6265SDimitry Andric 
50781ad6265SDimitry Andric Error TraceIntelPT::DoRefreshLiveProcessState(TraceGetStateResponse state,
50881ad6265SDimitry Andric                                               StringRef json_response) {
50981ad6265SDimitry Andric   m_storage = Storage();
51081ad6265SDimitry Andric 
51181ad6265SDimitry Andric   Expected<TraceIntelPTGetStateResponse> intelpt_state =
51281ad6265SDimitry Andric       json::parse<TraceIntelPTGetStateResponse>(json_response,
51381ad6265SDimitry Andric                                                 "TraceIntelPTGetStateResponse");
51481ad6265SDimitry Andric   if (!intelpt_state)
51581ad6265SDimitry Andric     return intelpt_state.takeError();
51681ad6265SDimitry Andric 
51781ad6265SDimitry Andric   m_storage.tsc_conversion = intelpt_state->tsc_perf_zero_conversion;
51881ad6265SDimitry Andric 
51981ad6265SDimitry Andric   if (!intelpt_state->cpus) {
52081ad6265SDimitry Andric     for (const TraceThreadState &thread_state : state.traced_threads) {
52181ad6265SDimitry Andric       ThreadSP thread_sp =
52281ad6265SDimitry Andric           GetLiveProcess()->GetThreadList().FindThreadByID(thread_state.tid);
52381ad6265SDimitry Andric       m_storage.thread_decoders.try_emplace(
52481ad6265SDimitry Andric           thread_state.tid, std::make_unique<ThreadDecoder>(thread_sp, *this));
52581ad6265SDimitry Andric     }
52681ad6265SDimitry Andric   } else {
52781ad6265SDimitry Andric     std::vector<cpu_id_t> cpus;
52881ad6265SDimitry Andric     for (const TraceCpuState &cpu : *intelpt_state->cpus)
52981ad6265SDimitry Andric       cpus.push_back(cpu.id);
53081ad6265SDimitry Andric 
53181ad6265SDimitry Andric     std::vector<tid_t> tids;
53281ad6265SDimitry Andric     for (const TraceThreadState &thread : intelpt_state->traced_threads)
53381ad6265SDimitry Andric       tids.push_back(thread.tid);
53481ad6265SDimitry Andric 
53581ad6265SDimitry Andric     if (!intelpt_state->tsc_perf_zero_conversion)
53681ad6265SDimitry Andric       return createStringError(inconvertibleErrorCode(),
53781ad6265SDimitry Andric                                "Missing perf time_zero conversion values");
53881ad6265SDimitry Andric     m_storage.multicpu_decoder.emplace(GetSharedPtr());
53981ad6265SDimitry Andric   }
54081ad6265SDimitry Andric 
54181ad6265SDimitry Andric   if (m_storage.tsc_conversion) {
54281ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Target);
54381ad6265SDimitry Andric     LLDB_LOG(log, "TraceIntelPT found TSC conversion information");
54481ad6265SDimitry Andric   }
54581ad6265SDimitry Andric   return Error::success();
546fe6060f1SDimitry Andric }
547fe6060f1SDimitry Andric 
548349cc55cSDimitry Andric bool TraceIntelPT::IsTraced(lldb::tid_t tid) {
54981ad6265SDimitry Andric   Storage &storage = GetUpdatedStorage();
55081ad6265SDimitry Andric   if (storage.multicpu_decoder)
55181ad6265SDimitry Andric     return storage.multicpu_decoder->TracesThread(tid);
55281ad6265SDimitry Andric   return storage.thread_decoders.count(tid);
553fe6060f1SDimitry Andric }
554fe6060f1SDimitry Andric 
555fe6060f1SDimitry Andric // The information here should match the description of the intel-pt section
556fe6060f1SDimitry Andric // of the jLLDBTraceStart packet in the lldb/docs/lldb-gdb-remote.txt
557fe6060f1SDimitry Andric // documentation file. Similarly, it should match the CLI help messages of the
558fe6060f1SDimitry Andric // TraceIntelPTOptions.td file.
559fe6060f1SDimitry Andric const char *TraceIntelPT::GetStartConfigurationHelp() {
56081ad6265SDimitry Andric   static Optional<std::string> message;
56181ad6265SDimitry Andric   if (!message) {
56281ad6265SDimitry Andric     message.emplace(formatv(R"(Parameters:
563fe6060f1SDimitry Andric 
56481ad6265SDimitry Andric   See the jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt for a
56581ad6265SDimitry Andric   description of each parameter below.
566fe6060f1SDimitry Andric 
56781ad6265SDimitry Andric   - int iptTraceSize (defaults to {0} bytes):
568fe6060f1SDimitry Andric     [process and thread tracing]
569fe6060f1SDimitry Andric 
57081ad6265SDimitry Andric   - boolean enableTsc (default to {1}):
571fe6060f1SDimitry Andric     [process and thread tracing]
572fe6060f1SDimitry Andric 
57381ad6265SDimitry Andric   - int psbPeriod (defaults to {2}):
574fe6060f1SDimitry Andric     [process and thread tracing]
575fe6060f1SDimitry Andric 
57681ad6265SDimitry Andric   - boolean perCpuTracing (default to {3}):
577fe6060f1SDimitry Andric     [process tracing only]
57881ad6265SDimitry Andric 
57981ad6265SDimitry Andric   - int processBufferSizeLimit (defaults to {4} MiB):
580753f127fSDimitry Andric     [process tracing only]
581753f127fSDimitry Andric 
582753f127fSDimitry Andric   - boolean disableCgroupFiltering (default to {5}):
58381ad6265SDimitry Andric     [process tracing only])",
58481ad6265SDimitry Andric                             kDefaultIptTraceSize, kDefaultEnableTscValue,
58581ad6265SDimitry Andric                             kDefaultPsbPeriod, kDefaultPerCpuTracing,
586753f127fSDimitry Andric                             kDefaultProcessBufferSizeLimit / 1024 / 1024,
587753f127fSDimitry Andric                             kDefaultDisableCgroupFiltering));
58881ad6265SDimitry Andric   }
58981ad6265SDimitry Andric   return message->c_str();
590fe6060f1SDimitry Andric }
591fe6060f1SDimitry Andric 
59281ad6265SDimitry Andric Error TraceIntelPT::Start(uint64_t ipt_trace_size,
59381ad6265SDimitry Andric                           uint64_t total_buffer_size_limit, bool enable_tsc,
594753f127fSDimitry Andric                           Optional<uint64_t> psb_period, bool per_cpu_tracing,
595753f127fSDimitry Andric                           bool disable_cgroup_filtering) {
596fe6060f1SDimitry Andric   TraceIntelPTStartRequest request;
59781ad6265SDimitry Andric   request.ipt_trace_size = ipt_trace_size;
59881ad6265SDimitry Andric   request.process_buffer_size_limit = total_buffer_size_limit;
59981ad6265SDimitry Andric   request.enable_tsc = enable_tsc;
60081ad6265SDimitry Andric   request.psb_period = psb_period;
601349cc55cSDimitry Andric   request.type = GetPluginName().str();
60281ad6265SDimitry Andric   request.per_cpu_tracing = per_cpu_tracing;
603753f127fSDimitry Andric   request.disable_cgroup_filtering = disable_cgroup_filtering;
604fe6060f1SDimitry Andric   return Trace::Start(toJSON(request));
605fe6060f1SDimitry Andric }
606fe6060f1SDimitry Andric 
607fe6060f1SDimitry Andric Error TraceIntelPT::Start(StructuredData::ObjectSP configuration) {
60881ad6265SDimitry Andric   uint64_t ipt_trace_size = kDefaultIptTraceSize;
60981ad6265SDimitry Andric   uint64_t process_buffer_size_limit = kDefaultProcessBufferSizeLimit;
610fe6060f1SDimitry Andric   bool enable_tsc = kDefaultEnableTscValue;
61181ad6265SDimitry Andric   Optional<uint64_t> psb_period = kDefaultPsbPeriod;
61281ad6265SDimitry Andric   bool per_cpu_tracing = kDefaultPerCpuTracing;
613753f127fSDimitry Andric   bool disable_cgroup_filtering = kDefaultDisableCgroupFiltering;
614fe6060f1SDimitry Andric 
615fe6060f1SDimitry Andric   if (configuration) {
616fe6060f1SDimitry Andric     if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
61781ad6265SDimitry Andric       dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size);
618fe6060f1SDimitry Andric       dict->GetValueForKeyAsInteger("processBufferSizeLimit",
619fe6060f1SDimitry Andric                                     process_buffer_size_limit);
620fe6060f1SDimitry Andric       dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
621fe6060f1SDimitry Andric       dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
62281ad6265SDimitry Andric       dict->GetValueForKeyAsBoolean("perCpuTracing", per_cpu_tracing);
623753f127fSDimitry Andric       dict->GetValueForKeyAsBoolean("disableCgroupFiltering",
624753f127fSDimitry Andric                                     disable_cgroup_filtering);
625fe6060f1SDimitry Andric     } else {
626fe6060f1SDimitry Andric       return createStringError(inconvertibleErrorCode(),
627fe6060f1SDimitry Andric                                "configuration object is not a dictionary");
628fe6060f1SDimitry Andric     }
629fe6060f1SDimitry Andric   }
630fe6060f1SDimitry Andric 
63181ad6265SDimitry Andric   return Start(ipt_trace_size, process_buffer_size_limit, enable_tsc,
632753f127fSDimitry Andric                psb_period, per_cpu_tracing, disable_cgroup_filtering);
633fe6060f1SDimitry Andric }
634fe6060f1SDimitry Andric 
635fe6060f1SDimitry Andric llvm::Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
63681ad6265SDimitry Andric                                 uint64_t ipt_trace_size, bool enable_tsc,
63781ad6265SDimitry Andric                                 Optional<uint64_t> psb_period) {
638fe6060f1SDimitry Andric   TraceIntelPTStartRequest request;
63981ad6265SDimitry Andric   request.ipt_trace_size = ipt_trace_size;
64081ad6265SDimitry Andric   request.enable_tsc = enable_tsc;
64181ad6265SDimitry Andric   request.psb_period = psb_period;
642349cc55cSDimitry Andric   request.type = GetPluginName().str();
643fe6060f1SDimitry Andric   request.tids.emplace();
644fe6060f1SDimitry Andric   for (lldb::tid_t tid : tids)
645fe6060f1SDimitry Andric     request.tids->push_back(tid);
646fe6060f1SDimitry Andric   return Trace::Start(toJSON(request));
647fe6060f1SDimitry Andric }
648fe6060f1SDimitry Andric 
649fe6060f1SDimitry Andric Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
650fe6060f1SDimitry Andric                           StructuredData::ObjectSP configuration) {
65181ad6265SDimitry Andric   uint64_t ipt_trace_size = kDefaultIptTraceSize;
652fe6060f1SDimitry Andric   bool enable_tsc = kDefaultEnableTscValue;
65381ad6265SDimitry Andric   Optional<uint64_t> psb_period = kDefaultPsbPeriod;
654fe6060f1SDimitry Andric 
655fe6060f1SDimitry Andric   if (configuration) {
656fe6060f1SDimitry Andric     if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
657753f127fSDimitry Andric       llvm::StringRef ipt_trace_size_not_parsed;
658753f127fSDimitry Andric       if (dict->GetValueForKeyAsString("iptTraceSize",
659753f127fSDimitry Andric                                        ipt_trace_size_not_parsed)) {
660753f127fSDimitry Andric         if (Optional<uint64_t> bytes =
661753f127fSDimitry Andric                 ParsingUtils::ParseUserFriendlySizeExpression(
662753f127fSDimitry Andric                     ipt_trace_size_not_parsed))
663753f127fSDimitry Andric           ipt_trace_size = *bytes;
664753f127fSDimitry Andric         else
665753f127fSDimitry Andric           return createStringError(inconvertibleErrorCode(),
666753f127fSDimitry Andric                                    "iptTraceSize is wrong bytes expression");
667753f127fSDimitry Andric       } else {
66881ad6265SDimitry Andric         dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size);
669753f127fSDimitry Andric       }
670753f127fSDimitry Andric 
671fe6060f1SDimitry Andric       dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
672fe6060f1SDimitry Andric       dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
673fe6060f1SDimitry Andric     } else {
674fe6060f1SDimitry Andric       return createStringError(inconvertibleErrorCode(),
675fe6060f1SDimitry Andric                                "configuration object is not a dictionary");
676fe6060f1SDimitry Andric     }
677fe6060f1SDimitry Andric   }
678fe6060f1SDimitry Andric 
67981ad6265SDimitry Andric   return Start(tids, ipt_trace_size, enable_tsc, psb_period);
680fe6060f1SDimitry Andric }
681fe6060f1SDimitry Andric 
68281ad6265SDimitry Andric Error TraceIntelPT::OnThreadBufferRead(lldb::tid_t tid,
68381ad6265SDimitry Andric                                        OnBinaryDataReadCallback callback) {
68481ad6265SDimitry Andric   return OnThreadBinaryDataRead(tid, IntelPTDataKinds::kIptTrace, callback);
685e8d8bef9SDimitry Andric }
68681ad6265SDimitry Andric 
68781ad6265SDimitry Andric TaskTimer &TraceIntelPT::GetTimer() { return GetUpdatedStorage().task_timer; }
688753f127fSDimitry Andric 
689753f127fSDimitry Andric ScopedTaskTimer &TraceIntelPT::GetThreadTimer(lldb::tid_t tid) {
690753f127fSDimitry Andric   return GetTimer().ForThread(tid);
691753f127fSDimitry Andric }
692753f127fSDimitry Andric 
693753f127fSDimitry Andric ScopedTaskTimer &TraceIntelPT::GetGlobalTimer() {
694753f127fSDimitry Andric   return GetTimer().ForGlobal();
695753f127fSDimitry Andric }
696