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