Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
39645 views
//===-- TraceIntelPT.cpp --------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "TraceIntelPT.h"910#include "../common/ThreadPostMortemTrace.h"11#include "CommandObjectTraceStartIntelPT.h"12#include "DecodedThread.h"13#include "TraceCursorIntelPT.h"14#include "TraceIntelPTBundleLoader.h"15#include "TraceIntelPTBundleSaver.h"16#include "TraceIntelPTConstants.h"17#include "lldb/Core/PluginManager.h"18#include "lldb/Interpreter/OptionValueProperties.h"19#include "lldb/Target/Process.h"20#include "lldb/Target/Target.h"21#include <optional>2223using namespace lldb;24using namespace lldb_private;25using namespace lldb_private::trace_intel_pt;26using namespace llvm;2728LLDB_PLUGIN_DEFINE(TraceIntelPT)2930lldb::CommandObjectSP31TraceIntelPT::GetProcessTraceStartCommand(CommandInterpreter &interpreter) {32return CommandObjectSP(33new CommandObjectProcessTraceStartIntelPT(*this, interpreter));34}3536lldb::CommandObjectSP37TraceIntelPT::GetThreadTraceStartCommand(CommandInterpreter &interpreter) {38return CommandObjectSP(39new CommandObjectThreadTraceStartIntelPT(*this, interpreter));40}4142#define LLDB_PROPERTIES_traceintelpt43#include "TraceIntelPTProperties.inc"4445enum {46#define LLDB_PROPERTIES_traceintelpt47#include "TraceIntelPTPropertiesEnum.inc"48};4950llvm::StringRef TraceIntelPT::PluginProperties::GetSettingName() {51return TraceIntelPT::GetPluginNameStatic();52}5354TraceIntelPT::PluginProperties::PluginProperties() : Properties() {55m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());56m_collection_sp->Initialize(g_traceintelpt_properties);57}5859uint64_t60TraceIntelPT::PluginProperties::GetInfiniteDecodingLoopVerificationThreshold() {61const uint32_t idx = ePropertyInfiniteDecodingLoopVerificationThreshold;62return GetPropertyAtIndexAs<uint64_t>(63idx, g_traceintelpt_properties[idx].default_uint_value);64}6566uint64_t TraceIntelPT::PluginProperties::GetExtremelyLargeDecodingThreshold() {67const uint32_t idx = ePropertyExtremelyLargeDecodingThreshold;68return GetPropertyAtIndexAs<uint64_t>(69idx, g_traceintelpt_properties[idx].default_uint_value);70}7172TraceIntelPT::PluginProperties &TraceIntelPT::GetGlobalProperties() {73static TraceIntelPT::PluginProperties g_settings;74return g_settings;75}7677void TraceIntelPT::Initialize() {78PluginManager::RegisterPlugin(79GetPluginNameStatic(), "Intel Processor Trace",80CreateInstanceForTraceBundle, CreateInstanceForLiveProcess,81TraceIntelPTBundleLoader::GetSchema(), DebuggerInitialize);82}8384void TraceIntelPT::DebuggerInitialize(Debugger &debugger) {85if (!PluginManager::GetSettingForProcessPlugin(86debugger, PluginProperties::GetSettingName())) {87const bool is_global_setting = true;88PluginManager::CreateSettingForTracePlugin(89debugger, GetGlobalProperties().GetValueProperties(),90"Properties for the intel-pt trace plug-in.", is_global_setting);91}92}9394void TraceIntelPT::Terminate() {95PluginManager::UnregisterPlugin(CreateInstanceForTraceBundle);96}9798StringRef TraceIntelPT::GetSchema() {99return TraceIntelPTBundleLoader::GetSchema();100}101102void TraceIntelPT::Dump(Stream *s) const {}103104Expected<FileSpec> TraceIntelPT::SaveToDisk(FileSpec directory, bool compact) {105RefreshLiveProcessState();106return TraceIntelPTBundleSaver().SaveToDisk(*this, directory, compact);107}108109Expected<TraceSP> TraceIntelPT::CreateInstanceForTraceBundle(110const json::Value &bundle_description, StringRef bundle_dir,111Debugger &debugger) {112return TraceIntelPTBundleLoader(debugger, bundle_description, bundle_dir)113.Load();114}115116Expected<TraceSP> TraceIntelPT::CreateInstanceForLiveProcess(Process &process) {117TraceSP instance(new TraceIntelPT(process));118process.GetTarget().SetTrace(instance);119return instance;120}121122TraceIntelPTSP TraceIntelPT::GetSharedPtr() {123return std::static_pointer_cast<TraceIntelPT>(shared_from_this());124}125126TraceIntelPT::TraceMode TraceIntelPT::GetTraceMode() { return trace_mode; }127128TraceIntelPTSP TraceIntelPT::CreateInstanceForPostmortemTrace(129JSONTraceBundleDescription &bundle_description,130ArrayRef<ProcessSP> traced_processes,131ArrayRef<ThreadPostMortemTraceSP> traced_threads, TraceMode trace_mode) {132TraceIntelPTSP trace_sp(133new TraceIntelPT(bundle_description, traced_processes, trace_mode));134trace_sp->m_storage.tsc_conversion =135bundle_description.tsc_perf_zero_conversion;136137if (bundle_description.cpus) {138std::vector<cpu_id_t> cpus;139140for (const JSONCpu &cpu : *bundle_description.cpus) {141trace_sp->SetPostMortemCpuDataFile(cpu.id, IntelPTDataKinds::kIptTrace,142FileSpec(cpu.ipt_trace));143144trace_sp->SetPostMortemCpuDataFile(145cpu.id, IntelPTDataKinds::kPerfContextSwitchTrace,146FileSpec(cpu.context_switch_trace));147cpus.push_back(cpu.id);148}149150if (trace_mode == TraceMode::UserMode) {151trace_sp->m_storage.multicpu_decoder.emplace(trace_sp);152}153}154155if (!bundle_description.cpus || trace_mode == TraceMode::KernelMode) {156for (const ThreadPostMortemTraceSP &thread : traced_threads) {157trace_sp->m_storage.thread_decoders.try_emplace(158thread->GetID(), std::make_unique<ThreadDecoder>(thread, *trace_sp));159if (const std::optional<FileSpec> &trace_file = thread->GetTraceFile()) {160trace_sp->SetPostMortemThreadDataFile(161thread->GetID(), IntelPTDataKinds::kIptTrace, *trace_file);162}163}164}165166for (const ProcessSP &process_sp : traced_processes)167process_sp->GetTarget().SetTrace(trace_sp);168return trace_sp;169}170171TraceIntelPT::TraceIntelPT(JSONTraceBundleDescription &bundle_description,172ArrayRef<ProcessSP> traced_processes,173TraceMode trace_mode)174: Trace(traced_processes, bundle_description.GetCpuIds()),175m_cpu_info(bundle_description.cpu_info), trace_mode(trace_mode) {}176177Expected<DecodedThreadSP> TraceIntelPT::Decode(Thread &thread) {178if (const char *error = RefreshLiveProcessState())179return createStringError(inconvertibleErrorCode(), error);180181Storage &storage = GetUpdatedStorage();182if (storage.multicpu_decoder)183return storage.multicpu_decoder->Decode(thread);184185auto it = storage.thread_decoders.find(thread.GetID());186if (it == storage.thread_decoders.end())187return createStringError(inconvertibleErrorCode(), "thread not traced");188return it->second->Decode();189}190191Expected<std::optional<uint64_t>> TraceIntelPT::FindBeginningOfTimeNanos() {192Storage &storage = GetUpdatedStorage();193if (storage.beginning_of_time_nanos_calculated)194return storage.beginning_of_time_nanos;195storage.beginning_of_time_nanos_calculated = true;196197if (!storage.tsc_conversion)198return std::nullopt;199200std::optional<uint64_t> lowest_tsc;201202if (storage.multicpu_decoder) {203if (Expected<std::optional<uint64_t>> tsc =204storage.multicpu_decoder->FindLowestTSC()) {205lowest_tsc = *tsc;206} else {207return tsc.takeError();208}209}210211for (auto &decoder : storage.thread_decoders) {212Expected<std::optional<uint64_t>> tsc = decoder.second->FindLowestTSC();213if (!tsc)214return tsc.takeError();215216if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))217lowest_tsc = **tsc;218}219220if (lowest_tsc) {221storage.beginning_of_time_nanos =222storage.tsc_conversion->ToNanos(*lowest_tsc);223}224return storage.beginning_of_time_nanos;225}226227llvm::Expected<lldb::TraceCursorSP>228TraceIntelPT::CreateNewCursor(Thread &thread) {229if (Expected<DecodedThreadSP> decoded_thread = Decode(thread)) {230if (Expected<std::optional<uint64_t>> beginning_of_time =231FindBeginningOfTimeNanos())232return std::make_shared<TraceCursorIntelPT>(233thread.shared_from_this(), *decoded_thread, m_storage.tsc_conversion,234*beginning_of_time);235else236return beginning_of_time.takeError();237} else238return decoded_thread.takeError();239}240241void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose,242bool json) {243Storage &storage = GetUpdatedStorage();244245lldb::tid_t tid = thread.GetID();246if (json) {247DumpTraceInfoAsJson(thread, s, verbose);248return;249}250251s.Format("\nthread #{0}: tid = {1}", thread.GetIndexID(), thread.GetID());252if (!IsTraced(tid)) {253s << ", not traced\n";254return;255}256s << "\n";257258Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread);259if (!decoded_thread_sp_or_err) {260s << toString(decoded_thread_sp_or_err.takeError()) << "\n";261return;262}263264DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err;265266Expected<std::optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread);267if (!raw_size_or_error) {268s.Format(" {0}\n", toString(raw_size_or_error.takeError()));269return;270}271std::optional<uint64_t> raw_size = *raw_size_or_error;272273s.Format("\n Trace technology: {0}\n", GetPluginName());274275/// Instruction stats276{277uint64_t items_count = decoded_thread_sp->GetItemsCount();278uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage();279280s.Format("\n Total number of trace items: {0}\n", items_count);281282s << "\n Memory usage:\n";283if (raw_size)284s.Format(" Raw trace size: {0} KiB\n", *raw_size / 1024);285286s.Format(287" Total approximate memory usage (excluding raw trace): {0:2} KiB\n",288(double)mem_used / 1024);289if (items_count != 0)290s.Format(" Average memory usage per item (excluding raw trace): "291"{0:2} bytes\n",292(double)mem_used / items_count);293}294295// Timing296{297s << "\n Timing for this thread:\n";298auto print_duration = [&](const std::string &name,299std::chrono::milliseconds duration) {300s.Format(" {0}: {1:2}s\n", name, duration.count() / 1000.0);301};302GetThreadTimer(tid).ForEachTimedTask(print_duration);303304s << "\n Timing for global tasks:\n";305GetGlobalTimer().ForEachTimedTask(print_duration);306}307308// Instruction events stats309{310const DecodedThread::EventsStats &events_stats =311decoded_thread_sp->GetEventsStats();312s << "\n Events:\n";313s.Format(" Number of individual events: {0}\n",314events_stats.total_count);315for (const auto &event_to_count : events_stats.events_counts) {316s.Format(" {0}: {1}\n",317TraceCursor::EventKindToString(event_to_count.first),318event_to_count.second);319}320}321// Trace error stats322{323const DecodedThread::ErrorStats &error_stats =324decoded_thread_sp->GetErrorStats();325s << "\n Errors:\n";326s.Format(" Number of individual errors: {0}\n",327error_stats.GetTotalCount());328s.Format(" Number of fatal errors: {0}\n", error_stats.fatal_errors);329for (const auto &[kind, count] : error_stats.libipt_errors) {330s.Format(" Number of libipt errors of kind [{0}]: {1}\n", kind,331count);332}333s.Format(" Number of other errors: {0}\n", error_stats.other_errors);334}335336if (storage.multicpu_decoder) {337s << "\n Multi-cpu decoding:\n";338s.Format(" Total number of continuous executions found: {0}\n",339storage.multicpu_decoder->GetTotalContinuousExecutionsCount());340s.Format(341" Number of continuous executions for this thread: {0}\n",342storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid));343s.Format(" Total number of PSB blocks found: {0}\n",344storage.multicpu_decoder->GetTotalPSBBlocksCount());345s.Format(" Number of PSB blocks for this thread: {0}\n",346storage.multicpu_decoder->GePSBBlocksCountForThread(tid));347s.Format(" Total number of unattributed PSB blocks found: {0}\n",348storage.multicpu_decoder->GetUnattributedPSBBlocksCount());349}350}351352void TraceIntelPT::DumpTraceInfoAsJson(Thread &thread, Stream &s,353bool verbose) {354Storage &storage = GetUpdatedStorage();355356lldb::tid_t tid = thread.GetID();357json::OStream json_str(s.AsRawOstream(), 2);358if (!IsTraced(tid)) {359s << "error: thread not traced\n";360return;361}362363Expected<std::optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread);364if (!raw_size_or_error) {365s << "error: " << toString(raw_size_or_error.takeError()) << "\n";366return;367}368369Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread);370if (!decoded_thread_sp_or_err) {371s << "error: " << toString(decoded_thread_sp_or_err.takeError()) << "\n";372return;373}374DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err;375376json_str.object([&] {377json_str.attribute("traceTechnology", "intel-pt");378json_str.attributeObject("threadStats", [&] {379json_str.attribute("tid", tid);380381uint64_t insn_len = decoded_thread_sp->GetItemsCount();382json_str.attribute("traceItemsCount", insn_len);383384// Instruction stats385uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage();386json_str.attributeObject("memoryUsage", [&] {387json_str.attribute("totalInBytes", std::to_string(mem_used));388std::optional<double> avg;389if (insn_len != 0)390avg = double(mem_used) / insn_len;391json_str.attribute("avgPerItemInBytes", avg);392});393394// Timing395json_str.attributeObject("timingInSeconds", [&] {396GetTimer().ForThread(tid).ForEachTimedTask(397[&](const std::string &name, std::chrono::milliseconds duration) {398json_str.attribute(name, duration.count() / 1000.0);399});400});401402// Instruction events stats403const DecodedThread::EventsStats &events_stats =404decoded_thread_sp->GetEventsStats();405json_str.attributeObject("events", [&] {406json_str.attribute("totalCount", events_stats.total_count);407json_str.attributeObject("individualCounts", [&] {408for (const auto &event_to_count : events_stats.events_counts) {409json_str.attribute(410TraceCursor::EventKindToString(event_to_count.first),411event_to_count.second);412}413});414});415// Trace error stats416const DecodedThread::ErrorStats &error_stats =417decoded_thread_sp->GetErrorStats();418json_str.attributeObject("errors", [&] {419json_str.attribute("totalCount", error_stats.GetTotalCount());420json_str.attributeObject("libiptErrors", [&] {421for (const auto &[kind, count] : error_stats.libipt_errors) {422json_str.attribute(kind, count);423}424});425json_str.attribute("fatalErrors", error_stats.fatal_errors);426json_str.attribute("otherErrors", error_stats.other_errors);427});428429if (storage.multicpu_decoder) {430json_str.attribute(431"continuousExecutions",432storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid));433json_str.attribute(434"PSBBlocks",435storage.multicpu_decoder->GePSBBlocksCountForThread(tid));436}437});438439json_str.attributeObject("globalStats", [&] {440json_str.attributeObject("timingInSeconds", [&] {441GetTimer().ForGlobal().ForEachTimedTask(442[&](const std::string &name, std::chrono::milliseconds duration) {443json_str.attribute(name, duration.count() / 1000.0);444});445});446if (storage.multicpu_decoder) {447json_str.attribute(448"totalUnattributedPSBBlocks",449storage.multicpu_decoder->GetUnattributedPSBBlocksCount());450json_str.attribute(451"totalCountinuosExecutions",452storage.multicpu_decoder->GetTotalContinuousExecutionsCount());453json_str.attribute("totalPSBBlocks",454storage.multicpu_decoder->GetTotalPSBBlocksCount());455json_str.attribute(456"totalContinuousExecutions",457storage.multicpu_decoder->GetTotalContinuousExecutionsCount());458}459});460});461}462463llvm::Expected<std::optional<uint64_t>>464TraceIntelPT::GetRawTraceSize(Thread &thread) {465if (GetUpdatedStorage().multicpu_decoder)466return std::nullopt; // TODO: calculate the amount of intel pt raw trace associated467// with the given thread.468if (GetLiveProcess())469return GetLiveThreadBinaryDataSize(thread.GetID(),470IntelPTDataKinds::kIptTrace);471uint64_t size;472auto callback = [&](llvm::ArrayRef<uint8_t> data) {473size = data.size();474return Error::success();475};476if (Error err = OnThreadBufferRead(thread.GetID(), callback))477return std::move(err);478479return size;480}481482Expected<pt_cpu> TraceIntelPT::GetCPUInfoForLiveProcess() {483Expected<std::vector<uint8_t>> cpu_info =484GetLiveProcessBinaryData(IntelPTDataKinds::kProcFsCpuInfo);485if (!cpu_info)486return cpu_info.takeError();487488int64_t cpu_family = -1;489int64_t model = -1;490int64_t stepping = -1;491std::string vendor_id;492493StringRef rest(reinterpret_cast<const char *>(cpu_info->data()),494cpu_info->size());495while (!rest.empty()) {496StringRef line;497std::tie(line, rest) = rest.split('\n');498499SmallVector<StringRef, 2> columns;500line.split(columns, StringRef(":"), -1, false);501502if (columns.size() < 2)503continue; // continue searching504505columns[1] = columns[1].trim(" ");506if (columns[0].contains("cpu family") &&507columns[1].getAsInteger(10, cpu_family))508continue;509510else if (columns[0].contains("model") && columns[1].getAsInteger(10, model))511continue;512513else if (columns[0].contains("stepping") &&514columns[1].getAsInteger(10, stepping))515continue;516517else if (columns[0].contains("vendor_id")) {518vendor_id = columns[1].str();519if (!vendor_id.empty())520continue;521}522523if ((cpu_family != -1) && (model != -1) && (stepping != -1) &&524(!vendor_id.empty())) {525return pt_cpu{vendor_id == "GenuineIntel" ? pcv_intel : pcv_unknown,526static_cast<uint16_t>(cpu_family),527static_cast<uint8_t>(model),528static_cast<uint8_t>(stepping)};529}530}531return createStringError(inconvertibleErrorCode(),532"Failed parsing the target's /proc/cpuinfo file");533}534535Expected<pt_cpu> TraceIntelPT::GetCPUInfo() {536if (!m_cpu_info) {537if (llvm::Expected<pt_cpu> cpu_info = GetCPUInfoForLiveProcess())538m_cpu_info = *cpu_info;539else540return cpu_info.takeError();541}542return *m_cpu_info;543}544545std::optional<LinuxPerfZeroTscConversion>546TraceIntelPT::GetPerfZeroTscConversion() {547return GetUpdatedStorage().tsc_conversion;548}549550TraceIntelPT::Storage &TraceIntelPT::GetUpdatedStorage() {551RefreshLiveProcessState();552return m_storage;553}554555Error TraceIntelPT::DoRefreshLiveProcessState(TraceGetStateResponse state,556StringRef json_response) {557m_storage = Storage();558559Expected<TraceIntelPTGetStateResponse> intelpt_state =560json::parse<TraceIntelPTGetStateResponse>(json_response,561"TraceIntelPTGetStateResponse");562if (!intelpt_state)563return intelpt_state.takeError();564565m_storage.tsc_conversion = intelpt_state->tsc_perf_zero_conversion;566567if (!intelpt_state->cpus) {568for (const TraceThreadState &thread_state : state.traced_threads) {569ThreadSP thread_sp =570GetLiveProcess()->GetThreadList().FindThreadByID(thread_state.tid);571m_storage.thread_decoders.try_emplace(572thread_state.tid, std::make_unique<ThreadDecoder>(thread_sp, *this));573}574} else {575std::vector<cpu_id_t> cpus;576for (const TraceCpuState &cpu : *intelpt_state->cpus)577cpus.push_back(cpu.id);578579std::vector<tid_t> tids;580for (const TraceThreadState &thread : intelpt_state->traced_threads)581tids.push_back(thread.tid);582583if (!intelpt_state->tsc_perf_zero_conversion)584return createStringError(inconvertibleErrorCode(),585"Missing perf time_zero conversion values");586m_storage.multicpu_decoder.emplace(GetSharedPtr());587}588589if (m_storage.tsc_conversion) {590Log *log = GetLog(LLDBLog::Target);591LLDB_LOG(log, "TraceIntelPT found TSC conversion information");592}593return Error::success();594}595596bool TraceIntelPT::IsTraced(lldb::tid_t tid) {597Storage &storage = GetUpdatedStorage();598if (storage.multicpu_decoder)599return storage.multicpu_decoder->TracesThread(tid);600return storage.thread_decoders.count(tid);601}602603// The information here should match the description of the intel-pt section604// of the jLLDBTraceStart packet in the lldb/docs/lldb-gdb-remote.txt605// documentation file. Similarly, it should match the CLI help messages of the606// TraceIntelPTOptions.td file.607const char *TraceIntelPT::GetStartConfigurationHelp() {608static std::optional<std::string> message;609if (!message) {610message.emplace(formatv(R"(Parameters:611612See the jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt for a613description of each parameter below.614615- int iptTraceSize (defaults to {0} bytes):616[process and thread tracing]617618- boolean enableTsc (default to {1}):619[process and thread tracing]620621- int psbPeriod (defaults to {2}):622[process and thread tracing]623624- boolean perCpuTracing (default to {3}):625[process tracing only]626627- int processBufferSizeLimit (defaults to {4} MiB):628[process tracing only]629630- boolean disableCgroupFiltering (default to {5}):631[process tracing only])",632kDefaultIptTraceSize, kDefaultEnableTscValue,633kDefaultPsbPeriod, kDefaultPerCpuTracing,634kDefaultProcessBufferSizeLimit / 1024 / 1024,635kDefaultDisableCgroupFiltering));636}637return message->c_str();638}639640Error TraceIntelPT::Start(uint64_t ipt_trace_size,641uint64_t total_buffer_size_limit, bool enable_tsc,642std::optional<uint64_t> psb_period,643bool per_cpu_tracing, bool disable_cgroup_filtering) {644TraceIntelPTStartRequest request;645request.ipt_trace_size = ipt_trace_size;646request.process_buffer_size_limit = total_buffer_size_limit;647request.enable_tsc = enable_tsc;648request.psb_period = psb_period;649request.type = GetPluginName().str();650request.per_cpu_tracing = per_cpu_tracing;651request.disable_cgroup_filtering = disable_cgroup_filtering;652return Trace::Start(toJSON(request));653}654655Error TraceIntelPT::Start(StructuredData::ObjectSP configuration) {656uint64_t ipt_trace_size = kDefaultIptTraceSize;657uint64_t process_buffer_size_limit = kDefaultProcessBufferSizeLimit;658bool enable_tsc = kDefaultEnableTscValue;659std::optional<uint64_t> psb_period = kDefaultPsbPeriod;660bool per_cpu_tracing = kDefaultPerCpuTracing;661bool disable_cgroup_filtering = kDefaultDisableCgroupFiltering;662663if (configuration) {664if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {665dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size);666dict->GetValueForKeyAsInteger("processBufferSizeLimit",667process_buffer_size_limit);668dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);669dict->GetValueForKeyAsInteger("psbPeriod", psb_period);670dict->GetValueForKeyAsBoolean("perCpuTracing", per_cpu_tracing);671dict->GetValueForKeyAsBoolean("disableCgroupFiltering",672disable_cgroup_filtering);673} else {674return createStringError(inconvertibleErrorCode(),675"configuration object is not a dictionary");676}677}678679return Start(ipt_trace_size, process_buffer_size_limit, enable_tsc,680psb_period, per_cpu_tracing, disable_cgroup_filtering);681}682683llvm::Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,684uint64_t ipt_trace_size, bool enable_tsc,685std::optional<uint64_t> psb_period) {686TraceIntelPTStartRequest request;687request.ipt_trace_size = ipt_trace_size;688request.enable_tsc = enable_tsc;689request.psb_period = psb_period;690request.type = GetPluginName().str();691request.tids.emplace();692for (lldb::tid_t tid : tids)693request.tids->push_back(tid);694return Trace::Start(toJSON(request));695}696697Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,698StructuredData::ObjectSP configuration) {699uint64_t ipt_trace_size = kDefaultIptTraceSize;700bool enable_tsc = kDefaultEnableTscValue;701std::optional<uint64_t> psb_period = kDefaultPsbPeriod;702703if (configuration) {704if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {705llvm::StringRef ipt_trace_size_not_parsed;706if (dict->GetValueForKeyAsString("iptTraceSize",707ipt_trace_size_not_parsed)) {708if (std::optional<uint64_t> bytes =709ParsingUtils::ParseUserFriendlySizeExpression(710ipt_trace_size_not_parsed))711ipt_trace_size = *bytes;712else713return createStringError(inconvertibleErrorCode(),714"iptTraceSize is wrong bytes expression");715} else {716dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size);717}718719dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);720dict->GetValueForKeyAsInteger("psbPeriod", psb_period);721} else {722return createStringError(inconvertibleErrorCode(),723"configuration object is not a dictionary");724}725}726727return Start(tids, ipt_trace_size, enable_tsc, psb_period);728}729730Error TraceIntelPT::OnThreadBufferRead(lldb::tid_t tid,731OnBinaryDataReadCallback callback) {732return OnThreadBinaryDataRead(tid, IntelPTDataKinds::kIptTrace, callback);733}734735TaskTimer &TraceIntelPT::GetTimer() { return GetUpdatedStorage().task_timer; }736737ScopedTaskTimer &TraceIntelPT::GetThreadTimer(lldb::tid_t tid) {738return GetTimer().ForThread(tid);739}740741ScopedTaskTimer &TraceIntelPT::GetGlobalTimer() {742return GetTimer().ForGlobal();743}744745746