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