brintos

brintos / llvm-project-archived public Read only

0
0
Text · 26.0 KiB · 72e9948 Raw
745 lines · cpp
1//===-- TraceIntelPT.cpp --------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "TraceIntelPT.h"10 11#include "../common/ThreadPostMortemTrace.h"12#include "CommandObjectTraceStartIntelPT.h"13#include "DecodedThread.h"14#include "TraceCursorIntelPT.h"15#include "TraceIntelPTBundleLoader.h"16#include "TraceIntelPTBundleSaver.h"17#include "TraceIntelPTConstants.h"18#include "lldb/Core/PluginManager.h"19#include "lldb/Interpreter/OptionValueProperties.h"20#include "lldb/Target/Process.h"21#include "lldb/Target/Target.h"22#include <optional>23 24using namespace lldb;25using namespace lldb_private;26using namespace lldb_private::trace_intel_pt;27using namespace llvm;28 29LLDB_PLUGIN_DEFINE(TraceIntelPT)30 31lldb::CommandObjectSP32TraceIntelPT::GetProcessTraceStartCommand(CommandInterpreter &interpreter) {33  return CommandObjectSP(34      new CommandObjectProcessTraceStartIntelPT(*this, interpreter));35}36 37lldb::CommandObjectSP38TraceIntelPT::GetThreadTraceStartCommand(CommandInterpreter &interpreter) {39  return CommandObjectSP(40      new CommandObjectThreadTraceStartIntelPT(*this, interpreter));41}42 43#define LLDB_PROPERTIES_traceintelpt44#include "TraceIntelPTProperties.inc"45 46enum {47#define LLDB_PROPERTIES_traceintelpt48#include "TraceIntelPTPropertiesEnum.inc"49};50 51llvm::StringRef TraceIntelPT::PluginProperties::GetSettingName() {52  return TraceIntelPT::GetPluginNameStatic();53}54 55TraceIntelPT::PluginProperties::PluginProperties() : Properties() {56  m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());57  m_collection_sp->Initialize(g_traceintelpt_properties);58}59 60uint64_t61TraceIntelPT::PluginProperties::GetInfiniteDecodingLoopVerificationThreshold() {62  const uint32_t idx = ePropertyInfiniteDecodingLoopVerificationThreshold;63  return GetPropertyAtIndexAs<uint64_t>(64      idx, g_traceintelpt_properties[idx].default_uint_value);65}66 67uint64_t TraceIntelPT::PluginProperties::GetExtremelyLargeDecodingThreshold() {68  const uint32_t idx = ePropertyExtremelyLargeDecodingThreshold;69  return GetPropertyAtIndexAs<uint64_t>(70      idx, g_traceintelpt_properties[idx].default_uint_value);71}72 73TraceIntelPT::PluginProperties &TraceIntelPT::GetGlobalProperties() {74  static TraceIntelPT::PluginProperties g_settings;75  return g_settings;76}77 78void TraceIntelPT::Initialize() {79  PluginManager::RegisterPlugin(80      GetPluginNameStatic(), "Intel Processor Trace",81      CreateInstanceForTraceBundle, CreateInstanceForLiveProcess,82      TraceIntelPTBundleLoader::GetSchema(), DebuggerInitialize);83}84 85void TraceIntelPT::DebuggerInitialize(Debugger &debugger) {86  if (!PluginManager::GetSettingForProcessPlugin(87          debugger, PluginProperties::GetSettingName())) {88    const bool is_global_setting = true;89    PluginManager::CreateSettingForTracePlugin(90        debugger, GetGlobalProperties().GetValueProperties(),91        "Properties for the intel-pt trace plug-in.", is_global_setting);92  }93}94 95void TraceIntelPT::Terminate() {96  PluginManager::UnregisterPlugin(CreateInstanceForTraceBundle);97}98 99StringRef TraceIntelPT::GetSchema() {100  return TraceIntelPTBundleLoader::GetSchema();101}102 103void TraceIntelPT::Dump(Stream *s) const {}104 105Expected<FileSpec> TraceIntelPT::SaveToDisk(FileSpec directory, bool compact) {106  RefreshLiveProcessState();107  return TraceIntelPTBundleSaver().SaveToDisk(*this, directory, compact);108}109 110Expected<TraceSP> TraceIntelPT::CreateInstanceForTraceBundle(111    const json::Value &bundle_description, StringRef bundle_dir,112    Debugger &debugger) {113  return TraceIntelPTBundleLoader(debugger, bundle_description, bundle_dir)114      .Load();115}116 117Expected<TraceSP> TraceIntelPT::CreateInstanceForLiveProcess(Process &process) {118  TraceSP instance(new TraceIntelPT(process));119  process.GetTarget().SetTrace(instance);120  return instance;121}122 123TraceIntelPTSP TraceIntelPT::GetSharedPtr() {124  return std::static_pointer_cast<TraceIntelPT>(shared_from_this());125}126 127TraceIntelPT::TraceMode TraceIntelPT::GetTraceMode() { return trace_mode; }128 129TraceIntelPTSP TraceIntelPT::CreateInstanceForPostmortemTrace(130    JSONTraceBundleDescription &bundle_description,131    ArrayRef<ProcessSP> traced_processes,132    ArrayRef<ThreadPostMortemTraceSP> traced_threads, TraceMode trace_mode) {133  TraceIntelPTSP trace_sp(134      new TraceIntelPT(bundle_description, traced_processes, trace_mode));135  trace_sp->m_storage.tsc_conversion =136      bundle_description.tsc_perf_zero_conversion;137 138  if (bundle_description.cpus) {139    std::vector<cpu_id_t> cpus;140 141    for (const JSONCpu &cpu : *bundle_description.cpus) {142      trace_sp->SetPostMortemCpuDataFile(cpu.id, IntelPTDataKinds::kIptTrace,143                                         FileSpec(cpu.ipt_trace));144 145      trace_sp->SetPostMortemCpuDataFile(146          cpu.id, IntelPTDataKinds::kPerfContextSwitchTrace,147          FileSpec(cpu.context_switch_trace));148      cpus.push_back(cpu.id);149    }150 151    if (trace_mode == TraceMode::UserMode) {152      trace_sp->m_storage.multicpu_decoder.emplace(trace_sp);153    }154  }155 156  if (!bundle_description.cpus || trace_mode == TraceMode::KernelMode) {157    for (const ThreadPostMortemTraceSP &thread : traced_threads) {158      trace_sp->m_storage.thread_decoders.try_emplace(159          thread->GetID(), std::make_unique<ThreadDecoder>(thread, *trace_sp));160      if (const std::optional<FileSpec> &trace_file = thread->GetTraceFile()) {161        trace_sp->SetPostMortemThreadDataFile(162            thread->GetID(), IntelPTDataKinds::kIptTrace, *trace_file);163      }164    }165  }166 167  for (const ProcessSP &process_sp : traced_processes)168    process_sp->GetTarget().SetTrace(trace_sp);169  return trace_sp;170}171 172TraceIntelPT::TraceIntelPT(JSONTraceBundleDescription &bundle_description,173                           ArrayRef<ProcessSP> traced_processes,174                           TraceMode trace_mode)175    : Trace(traced_processes, bundle_description.GetCpuIds()),176      m_cpu_info(bundle_description.cpu_info), trace_mode(trace_mode) {}177 178Expected<DecodedThreadSP> TraceIntelPT::Decode(Thread &thread) {179  if (const char *error = RefreshLiveProcessState())180    return createStringError(inconvertibleErrorCode(), error);181 182  Storage &storage = GetUpdatedStorage();183  if (storage.multicpu_decoder)184    return storage.multicpu_decoder->Decode(thread);185 186  auto it = storage.thread_decoders.find(thread.GetID());187  if (it == storage.thread_decoders.end())188    return createStringError(inconvertibleErrorCode(), "thread not traced");189  return it->second->Decode();190}191 192Expected<std::optional<uint64_t>> TraceIntelPT::FindBeginningOfTimeNanos() {193  Storage &storage = GetUpdatedStorage();194  if (storage.beginning_of_time_nanos_calculated)195    return storage.beginning_of_time_nanos;196  storage.beginning_of_time_nanos_calculated = true;197 198  if (!storage.tsc_conversion)199    return std::nullopt;200 201  std::optional<uint64_t> lowest_tsc;202 203  if (storage.multicpu_decoder) {204    if (Expected<std::optional<uint64_t>> tsc =205            storage.multicpu_decoder->FindLowestTSC()) {206      lowest_tsc = *tsc;207    } else {208      return tsc.takeError();209    }210  }211 212  for (auto &decoder : storage.thread_decoders) {213    Expected<std::optional<uint64_t>> tsc = decoder.second->FindLowestTSC();214    if (!tsc)215      return tsc.takeError();216 217    if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))218      lowest_tsc = **tsc;219  }220 221  if (lowest_tsc) {222    storage.beginning_of_time_nanos =223        storage.tsc_conversion->ToNanos(*lowest_tsc);224  }225  return storage.beginning_of_time_nanos;226}227 228llvm::Expected<lldb::TraceCursorSP>229TraceIntelPT::CreateNewCursor(Thread &thread) {230  if (Expected<DecodedThreadSP> decoded_thread = Decode(thread)) {231    if (Expected<std::optional<uint64_t>> beginning_of_time =232            FindBeginningOfTimeNanos())233      return std::make_shared<TraceCursorIntelPT>(234          thread.shared_from_this(), *decoded_thread, m_storage.tsc_conversion,235          *beginning_of_time);236    else237      return beginning_of_time.takeError();238  } else239    return decoded_thread.takeError();240}241 242void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose,243                                 bool json) {244  Storage &storage = GetUpdatedStorage();245 246  lldb::tid_t tid = thread.GetID();247  if (json) {248    DumpTraceInfoAsJson(thread, s, verbose);249    return;250  }251 252  s.Format("\nthread #{0}: tid = {1}", thread.GetIndexID(), thread.GetID());253  if (!IsTraced(tid)) {254    s << ", not traced\n";255    return;256  }257  s << "\n";258 259  Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread);260  if (!decoded_thread_sp_or_err) {261    s << toString(decoded_thread_sp_or_err.takeError()) << "\n";262    return;263  }264 265  DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err;266 267  Expected<std::optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread);268  if (!raw_size_or_error) {269    s.Format("  {0}\n", toString(raw_size_or_error.takeError()));270    return;271  }272  std::optional<uint64_t> raw_size = *raw_size_or_error;273 274  s.Format("\n  Trace technology: {0}\n", GetPluginName());275 276  /// Instruction stats277  {278    uint64_t items_count = decoded_thread_sp->GetItemsCount();279    uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage();280 281    s.Format("\n  Total number of trace items: {0}\n", items_count);282 283    s << "\n  Memory usage:\n";284    if (raw_size)285      s.Format("    Raw trace size: {0} KiB\n", *raw_size / 1024);286 287    s.Format(288        "    Total approximate memory usage (excluding raw trace): {0:2} KiB\n",289        (double)mem_used / 1024);290    if (items_count != 0)291      s.Format("    Average memory usage per item (excluding raw trace): "292               "{0:2} bytes\n",293               (double)mem_used / items_count);294  }295 296  // Timing297  {298    s << "\n  Timing for this thread:\n";299    auto print_duration = [&](const std::string &name,300                              std::chrono::milliseconds duration) {301      s.Format("    {0}: {1:2}s\n", name, duration.count() / 1000.0);302    };303    GetThreadTimer(tid).ForEachTimedTask(print_duration);304 305    s << "\n  Timing for global tasks:\n";306    GetGlobalTimer().ForEachTimedTask(print_duration);307  }308 309  // Instruction events stats310  {311    const DecodedThread::EventsStats &events_stats =312        decoded_thread_sp->GetEventsStats();313    s << "\n  Events:\n";314    s.Format("    Number of individual events: {0}\n",315             events_stats.total_count);316    for (const auto &event_to_count : events_stats.events_counts) {317      s.Format("      {0}: {1}\n",318               TraceCursor::EventKindToString(event_to_count.first),319               event_to_count.second);320    }321  }322  // Trace error stats323  {324    const DecodedThread::ErrorStats &error_stats =325        decoded_thread_sp->GetErrorStats();326    s << "\n  Errors:\n";327    s.Format("    Number of individual errors: {0}\n",328             error_stats.GetTotalCount());329    s.Format("      Number of fatal errors: {0}\n", error_stats.fatal_errors);330    for (const auto &[kind, count] : error_stats.libipt_errors) {331      s.Format("     Number of libipt errors of kind [{0}]: {1}\n", kind,332               count);333    }334    s.Format("      Number of other errors: {0}\n", error_stats.other_errors);335  }336 337  if (storage.multicpu_decoder) {338    s << "\n  Multi-cpu decoding:\n";339    s.Format("    Total number of continuous executions found: {0}\n",340             storage.multicpu_decoder->GetTotalContinuousExecutionsCount());341    s.Format(342        "    Number of continuous executions for this thread: {0}\n",343        storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid));344    s.Format("    Total number of PSB blocks found: {0}\n",345             storage.multicpu_decoder->GetTotalPSBBlocksCount());346    s.Format("    Number of PSB blocks for this thread: {0}\n",347             storage.multicpu_decoder->GePSBBlocksCountForThread(tid));348    s.Format("    Total number of unattributed PSB blocks found: {0}\n",349             storage.multicpu_decoder->GetUnattributedPSBBlocksCount());350  }351}352 353void TraceIntelPT::DumpTraceInfoAsJson(Thread &thread, Stream &s,354                                       bool verbose) {355  Storage &storage = GetUpdatedStorage();356 357  lldb::tid_t tid = thread.GetID();358  json::OStream json_str(s.AsRawOstream(), 2);359  if (!IsTraced(tid)) {360    s << "error: thread not traced\n";361    return;362  }363 364  Expected<std::optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread);365  if (!raw_size_or_error) {366    s << "error: " << toString(raw_size_or_error.takeError()) << "\n";367    return;368  }369 370  Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread);371  if (!decoded_thread_sp_or_err) {372    s << "error: " << toString(decoded_thread_sp_or_err.takeError()) << "\n";373    return;374  }375  DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err;376 377  json_str.object([&] {378    json_str.attribute("traceTechnology", "intel-pt");379    json_str.attributeObject("threadStats", [&] {380      json_str.attribute("tid", tid);381 382      uint64_t insn_len = decoded_thread_sp->GetItemsCount();383      json_str.attribute("traceItemsCount", insn_len);384 385      // Instruction stats386      uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage();387      json_str.attributeObject("memoryUsage", [&] {388        json_str.attribute("totalInBytes", std::to_string(mem_used));389        std::optional<double> avg;390        if (insn_len != 0)391          avg = double(mem_used) / insn_len;392        json_str.attribute("avgPerItemInBytes", avg);393      });394 395      // Timing396      json_str.attributeObject("timingInSeconds", [&] {397        GetTimer().ForThread(tid).ForEachTimedTask(398            [&](const std::string &name, std::chrono::milliseconds duration) {399              json_str.attribute(name, duration.count() / 1000.0);400            });401      });402 403      // Instruction events stats404      const DecodedThread::EventsStats &events_stats =405          decoded_thread_sp->GetEventsStats();406      json_str.attributeObject("events", [&] {407        json_str.attribute("totalCount", events_stats.total_count);408        json_str.attributeObject("individualCounts", [&] {409          for (const auto &event_to_count : events_stats.events_counts) {410            json_str.attribute(411                TraceCursor::EventKindToString(event_to_count.first),412                event_to_count.second);413          }414        });415      });416      // Trace error stats417      const DecodedThread::ErrorStats &error_stats =418          decoded_thread_sp->GetErrorStats();419      json_str.attributeObject("errors", [&] {420        json_str.attribute("totalCount", error_stats.GetTotalCount());421        json_str.attributeObject("libiptErrors", [&] {422          for (const auto &[kind, count] : error_stats.libipt_errors) {423            json_str.attribute(kind, count);424          }425        });426        json_str.attribute("fatalErrors", error_stats.fatal_errors);427        json_str.attribute("otherErrors", error_stats.other_errors);428      });429 430      if (storage.multicpu_decoder) {431        json_str.attribute(432            "continuousExecutions",433            storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid));434        json_str.attribute(435            "PSBBlocks",436            storage.multicpu_decoder->GePSBBlocksCountForThread(tid));437      }438    });439 440    json_str.attributeObject("globalStats", [&] {441      json_str.attributeObject("timingInSeconds", [&] {442        GetTimer().ForGlobal().ForEachTimedTask(443            [&](const std::string &name, std::chrono::milliseconds duration) {444              json_str.attribute(name, duration.count() / 1000.0);445            });446      });447      if (storage.multicpu_decoder) {448        json_str.attribute(449            "totalUnattributedPSBBlocks",450            storage.multicpu_decoder->GetUnattributedPSBBlocksCount());451        json_str.attribute(452            "totalCountinuosExecutions",453            storage.multicpu_decoder->GetTotalContinuousExecutionsCount());454        json_str.attribute("totalPSBBlocks",455                           storage.multicpu_decoder->GetTotalPSBBlocksCount());456        json_str.attribute(457            "totalContinuousExecutions",458            storage.multicpu_decoder->GetTotalContinuousExecutionsCount());459      }460    });461  });462}463 464llvm::Expected<std::optional<uint64_t>>465TraceIntelPT::GetRawTraceSize(Thread &thread) {466  if (GetUpdatedStorage().multicpu_decoder)467    return std::nullopt; // TODO: calculate the amount of intel pt raw trace associated468                 // with the given thread.469  if (GetLiveProcess())470    return GetLiveThreadBinaryDataSize(thread.GetID(),471                                       IntelPTDataKinds::kIptTrace);472  uint64_t size;473  auto callback = [&](llvm::ArrayRef<uint8_t> data) {474    size = data.size();475    return Error::success();476  };477  if (Error err = OnThreadBufferRead(thread.GetID(), callback))478    return std::move(err);479 480  return size;481}482 483Expected<pt_cpu> TraceIntelPT::GetCPUInfoForLiveProcess() {484  Expected<std::vector<uint8_t>> cpu_info =485      GetLiveProcessBinaryData(IntelPTDataKinds::kProcFsCpuInfo);486  if (!cpu_info)487    return cpu_info.takeError();488 489  int64_t cpu_family = -1;490  int64_t model = -1;491  int64_t stepping = -1;492  std::string vendor_id;493 494  StringRef rest(reinterpret_cast<const char *>(cpu_info->data()),495                 cpu_info->size());496  while (!rest.empty()) {497    StringRef line;498    std::tie(line, rest) = rest.split('\n');499 500    SmallVector<StringRef, 2> columns;501    line.split(columns, StringRef(":"), -1, false);502 503    if (columns.size() < 2)504      continue; // continue searching505 506    columns[1] = columns[1].trim(" ");507    if (columns[0].contains("cpu family") &&508        columns[1].getAsInteger(10, cpu_family))509      continue;510 511    else if (columns[0].contains("model") && columns[1].getAsInteger(10, model))512      continue;513 514    else if (columns[0].contains("stepping") &&515             columns[1].getAsInteger(10, stepping))516      continue;517 518    else if (columns[0].contains("vendor_id")) {519      vendor_id = columns[1].str();520      if (!vendor_id.empty())521        continue;522    }523 524    if ((cpu_family != -1) && (model != -1) && (stepping != -1) &&525        (!vendor_id.empty())) {526      return pt_cpu{vendor_id == "GenuineIntel" ? pcv_intel : pcv_unknown,527                    static_cast<uint16_t>(cpu_family),528                    static_cast<uint8_t>(model),529                    static_cast<uint8_t>(stepping)};530    }531  }532  return createStringError(inconvertibleErrorCode(),533                           "Failed parsing the target's /proc/cpuinfo file");534}535 536Expected<pt_cpu> TraceIntelPT::GetCPUInfo() {537  if (!m_cpu_info) {538    if (llvm::Expected<pt_cpu> cpu_info = GetCPUInfoForLiveProcess())539      m_cpu_info = *cpu_info;540    else541      return cpu_info.takeError();542  }543  return *m_cpu_info;544}545 546std::optional<LinuxPerfZeroTscConversion>547TraceIntelPT::GetPerfZeroTscConversion() {548  return GetUpdatedStorage().tsc_conversion;549}550 551TraceIntelPT::Storage &TraceIntelPT::GetUpdatedStorage() {552  RefreshLiveProcessState();553  return m_storage;554}555 556Error TraceIntelPT::DoRefreshLiveProcessState(TraceGetStateResponse state,557                                              StringRef json_response) {558  m_storage = Storage();559 560  Expected<TraceIntelPTGetStateResponse> intelpt_state =561      json::parse<TraceIntelPTGetStateResponse>(json_response,562                                                "TraceIntelPTGetStateResponse");563  if (!intelpt_state)564    return intelpt_state.takeError();565 566  m_storage.tsc_conversion = intelpt_state->tsc_perf_zero_conversion;567 568  if (!intelpt_state->cpus) {569    for (const TraceThreadState &thread_state : state.traced_threads) {570      ThreadSP thread_sp =571          GetLiveProcess()->GetThreadList().FindThreadByID(thread_state.tid);572      m_storage.thread_decoders.try_emplace(573          thread_state.tid, std::make_unique<ThreadDecoder>(thread_sp, *this));574    }575  } else {576    std::vector<cpu_id_t> cpus;577    for (const TraceCpuState &cpu : *intelpt_state->cpus)578      cpus.push_back(cpu.id);579 580    std::vector<tid_t> tids;581    for (const TraceThreadState &thread : intelpt_state->traced_threads)582      tids.push_back(thread.tid);583 584    if (!intelpt_state->tsc_perf_zero_conversion)585      return createStringError(inconvertibleErrorCode(),586                               "Missing perf time_zero conversion values");587    m_storage.multicpu_decoder.emplace(GetSharedPtr());588  }589 590  if (m_storage.tsc_conversion) {591    Log *log = GetLog(LLDBLog::Target);592    LLDB_LOG(log, "TraceIntelPT found TSC conversion information");593  }594  return Error::success();595}596 597bool TraceIntelPT::IsTraced(lldb::tid_t tid) {598  Storage &storage = GetUpdatedStorage();599  if (storage.multicpu_decoder)600    return storage.multicpu_decoder->TracesThread(tid);601  return storage.thread_decoders.count(tid);602}603 604// The information here should match the description of the intel-pt section605// of the jLLDBTraceStart packet in the lldb/docs/lldb-gdb-remote.txt606// documentation file. Similarly, it should match the CLI help messages of the607// TraceIntelPTOptions.td file.608const char *TraceIntelPT::GetStartConfigurationHelp() {609  static std::optional<std::string> message;610  if (!message) {611    message.emplace(formatv(R"(Parameters:612 613  See the jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt for a614  description of each parameter below.615 616  - int iptTraceSize (defaults to {0} bytes):617    [process and thread tracing]618 619  - boolean enableTsc (default to {1}):620    [process and thread tracing]621 622  - int psbPeriod (defaults to {2}):623    [process and thread tracing]624 625  - boolean perCpuTracing (default to {3}):626    [process tracing only]627 628  - int processBufferSizeLimit (defaults to {4} MiB):629    [process tracing only]630 631  - boolean disableCgroupFiltering (default to {5}):632    [process tracing only])",633                            kDefaultIptTraceSize, kDefaultEnableTscValue,634                            kDefaultPsbPeriod, kDefaultPerCpuTracing,635                            kDefaultProcessBufferSizeLimit / 1024 / 1024,636                            kDefaultDisableCgroupFiltering));637  }638  return message->c_str();639}640 641Error TraceIntelPT::Start(uint64_t ipt_trace_size,642                          uint64_t total_buffer_size_limit, bool enable_tsc,643                          std::optional<uint64_t> psb_period,644                          bool per_cpu_tracing, bool disable_cgroup_filtering) {645  TraceIntelPTStartRequest request;646  request.ipt_trace_size = ipt_trace_size;647  request.process_buffer_size_limit = total_buffer_size_limit;648  request.enable_tsc = enable_tsc;649  request.psb_period = psb_period;650  request.type = GetPluginName().str();651  request.per_cpu_tracing = per_cpu_tracing;652  request.disable_cgroup_filtering = disable_cgroup_filtering;653  return Trace::Start(toJSON(request));654}655 656Error TraceIntelPT::Start(StructuredData::ObjectSP configuration) {657  uint64_t ipt_trace_size = kDefaultIptTraceSize;658  uint64_t process_buffer_size_limit = kDefaultProcessBufferSizeLimit;659  bool enable_tsc = kDefaultEnableTscValue;660  std::optional<uint64_t> psb_period = kDefaultPsbPeriod;661  bool per_cpu_tracing = kDefaultPerCpuTracing;662  bool disable_cgroup_filtering = kDefaultDisableCgroupFiltering;663 664  if (configuration) {665    if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {666      dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size);667      dict->GetValueForKeyAsInteger("processBufferSizeLimit",668                                    process_buffer_size_limit);669      dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);670      dict->GetValueForKeyAsInteger("psbPeriod", psb_period);671      dict->GetValueForKeyAsBoolean("perCpuTracing", per_cpu_tracing);672      dict->GetValueForKeyAsBoolean("disableCgroupFiltering",673                                    disable_cgroup_filtering);674    } else {675      return createStringError(inconvertibleErrorCode(),676                               "configuration object is not a dictionary");677    }678  }679 680  return Start(ipt_trace_size, process_buffer_size_limit, enable_tsc,681               psb_period, per_cpu_tracing, disable_cgroup_filtering);682}683 684llvm::Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,685                                uint64_t ipt_trace_size, bool enable_tsc,686                                std::optional<uint64_t> psb_period) {687  TraceIntelPTStartRequest request;688  request.ipt_trace_size = ipt_trace_size;689  request.enable_tsc = enable_tsc;690  request.psb_period = psb_period;691  request.type = GetPluginName().str();692  request.tids.emplace();693  for (lldb::tid_t tid : tids)694    request.tids->push_back(tid);695  return Trace::Start(toJSON(request));696}697 698Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,699                          StructuredData::ObjectSP configuration) {700  uint64_t ipt_trace_size = kDefaultIptTraceSize;701  bool enable_tsc = kDefaultEnableTscValue;702  std::optional<uint64_t> psb_period = kDefaultPsbPeriod;703 704  if (configuration) {705    if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {706      llvm::StringRef ipt_trace_size_not_parsed;707      if (dict->GetValueForKeyAsString("iptTraceSize",708                                       ipt_trace_size_not_parsed)) {709        if (std::optional<uint64_t> bytes =710                ParsingUtils::ParseUserFriendlySizeExpression(711                    ipt_trace_size_not_parsed))712          ipt_trace_size = *bytes;713        else714          return createStringError(inconvertibleErrorCode(),715                                   "iptTraceSize is wrong bytes expression");716      } else {717        dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size);718      }719 720      dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);721      dict->GetValueForKeyAsInteger("psbPeriod", psb_period);722    } else {723      return createStringError(inconvertibleErrorCode(),724                               "configuration object is not a dictionary");725    }726  }727 728  return Start(tids, ipt_trace_size, enable_tsc, psb_period);729}730 731Error TraceIntelPT::OnThreadBufferRead(lldb::tid_t tid,732                                       OnBinaryDataReadCallback callback) {733  return OnThreadBinaryDataRead(tid, IntelPTDataKinds::kIptTrace, callback);734}735 736TaskTimer &TraceIntelPT::GetTimer() { return GetUpdatedStorage().task_timer; }737 738ScopedTaskTimer &TraceIntelPT::GetThreadTimer(lldb::tid_t tid) {739  return GetTimer().ForThread(tid);740}741 742ScopedTaskTimer &TraceIntelPT::GetGlobalTimer() {743  return GetTimer().ForGlobal();744}745