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" 14*bdd1243dSDimitry Andric #include "TraceCursorIntelPT.h" 1581ad6265SDimitry Andric #include "TraceIntelPTBundleLoader.h" 1681ad6265SDimitry Andric #include "TraceIntelPTBundleSaver.h" 17*bdd1243dSDimitry Andric #include "TraceIntelPTConstants.h" 18e8d8bef9SDimitry Andric #include "lldb/Core/PluginManager.h" 19*bdd1243dSDimitry Andric #include "lldb/Interpreter/OptionValueProperties.h" 20e8d8bef9SDimitry Andric #include "lldb/Target/Process.h" 21e8d8bef9SDimitry Andric #include "lldb/Target/Target.h" 22*bdd1243dSDimitry 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 29e8d8bef9SDimitry Andric LLDB_PLUGIN_DEFINE(TraceIntelPT) 30e8d8bef9SDimitry Andric 31fe6060f1SDimitry Andric lldb::CommandObjectSP 32fe6060f1SDimitry Andric TraceIntelPT::GetProcessTraceStartCommand(CommandInterpreter &interpreter) { 33fe6060f1SDimitry Andric return CommandObjectSP( 34fe6060f1SDimitry Andric new CommandObjectProcessTraceStartIntelPT(*this, interpreter)); 35fe6060f1SDimitry Andric } 36fe6060f1SDimitry Andric 37fe6060f1SDimitry Andric lldb::CommandObjectSP 38fe6060f1SDimitry Andric TraceIntelPT::GetThreadTraceStartCommand(CommandInterpreter &interpreter) { 39fe6060f1SDimitry Andric return CommandObjectSP( 40fe6060f1SDimitry Andric new CommandObjectThreadTraceStartIntelPT(*this, interpreter)); 41e8d8bef9SDimitry Andric } 42e8d8bef9SDimitry Andric 43*bdd1243dSDimitry Andric #define LLDB_PROPERTIES_traceintelpt 44*bdd1243dSDimitry Andric #include "TraceIntelPTProperties.inc" 45*bdd1243dSDimitry Andric 46*bdd1243dSDimitry Andric enum { 47*bdd1243dSDimitry Andric #define LLDB_PROPERTIES_traceintelpt 48*bdd1243dSDimitry Andric #include "TraceIntelPTPropertiesEnum.inc" 49*bdd1243dSDimitry Andric }; 50*bdd1243dSDimitry Andric 51*bdd1243dSDimitry Andric ConstString TraceIntelPT::PluginProperties::GetSettingName() { 52*bdd1243dSDimitry Andric return ConstString(TraceIntelPT::GetPluginNameStatic()); 53*bdd1243dSDimitry Andric } 54*bdd1243dSDimitry Andric 55*bdd1243dSDimitry Andric TraceIntelPT::PluginProperties::PluginProperties() : Properties() { 56*bdd1243dSDimitry Andric m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName()); 57*bdd1243dSDimitry Andric m_collection_sp->Initialize(g_traceintelpt_properties); 58*bdd1243dSDimitry Andric } 59*bdd1243dSDimitry Andric 60*bdd1243dSDimitry Andric uint64_t 61*bdd1243dSDimitry Andric TraceIntelPT::PluginProperties::GetInfiniteDecodingLoopVerificationThreshold() { 62*bdd1243dSDimitry Andric const uint32_t idx = ePropertyInfiniteDecodingLoopVerificationThreshold; 63*bdd1243dSDimitry Andric return m_collection_sp->GetPropertyAtIndexAsUInt64( 64*bdd1243dSDimitry Andric nullptr, idx, g_traceintelpt_properties[idx].default_uint_value); 65*bdd1243dSDimitry Andric } 66*bdd1243dSDimitry Andric 67*bdd1243dSDimitry Andric uint64_t TraceIntelPT::PluginProperties::GetExtremelyLargeDecodingThreshold() { 68*bdd1243dSDimitry Andric const uint32_t idx = ePropertyExtremelyLargeDecodingThreshold; 69*bdd1243dSDimitry Andric return m_collection_sp->GetPropertyAtIndexAsUInt64( 70*bdd1243dSDimitry Andric nullptr, idx, g_traceintelpt_properties[idx].default_uint_value); 71*bdd1243dSDimitry Andric } 72*bdd1243dSDimitry Andric 73*bdd1243dSDimitry Andric TraceIntelPT::PluginProperties &TraceIntelPT::GetGlobalProperties() { 74*bdd1243dSDimitry Andric static TraceIntelPT::PluginProperties g_settings; 75*bdd1243dSDimitry Andric return g_settings; 76*bdd1243dSDimitry Andric } 77*bdd1243dSDimitry Andric 78e8d8bef9SDimitry Andric void TraceIntelPT::Initialize() { 79*bdd1243dSDimitry Andric PluginManager::RegisterPlugin( 80*bdd1243dSDimitry Andric GetPluginNameStatic(), "Intel Processor Trace", 81*bdd1243dSDimitry Andric CreateInstanceForTraceBundle, CreateInstanceForLiveProcess, 82*bdd1243dSDimitry Andric TraceIntelPTBundleLoader::GetSchema(), DebuggerInitialize); 83*bdd1243dSDimitry Andric } 84*bdd1243dSDimitry Andric 85*bdd1243dSDimitry Andric void TraceIntelPT::DebuggerInitialize(Debugger &debugger) { 86*bdd1243dSDimitry Andric if (!PluginManager::GetSettingForProcessPlugin( 87*bdd1243dSDimitry Andric debugger, PluginProperties::GetSettingName())) { 88*bdd1243dSDimitry Andric const bool is_global_setting = true; 89*bdd1243dSDimitry Andric PluginManager::CreateSettingForTracePlugin( 90*bdd1243dSDimitry Andric debugger, GetGlobalProperties().GetValueProperties(), 91*bdd1243dSDimitry Andric ConstString("Properties for the intel-pt trace plug-in."), 92*bdd1243dSDimitry Andric is_global_setting); 93*bdd1243dSDimitry Andric } 94e8d8bef9SDimitry Andric } 95e8d8bef9SDimitry Andric 96e8d8bef9SDimitry Andric void TraceIntelPT::Terminate() { 9781ad6265SDimitry Andric PluginManager::UnregisterPlugin(CreateInstanceForTraceBundle); 98e8d8bef9SDimitry Andric } 99e8d8bef9SDimitry Andric 100e8d8bef9SDimitry Andric StringRef TraceIntelPT::GetSchema() { 10181ad6265SDimitry Andric return TraceIntelPTBundleLoader::GetSchema(); 102e8d8bef9SDimitry Andric } 103e8d8bef9SDimitry Andric 104e8d8bef9SDimitry Andric void TraceIntelPT::Dump(Stream *s) const {} 105e8d8bef9SDimitry Andric 106753f127fSDimitry Andric Expected<FileSpec> TraceIntelPT::SaveToDisk(FileSpec directory, bool compact) { 107349cc55cSDimitry Andric RefreshLiveProcessState(); 108753f127fSDimitry Andric return TraceIntelPTBundleSaver().SaveToDisk(*this, directory, compact); 109349cc55cSDimitry Andric } 110349cc55cSDimitry Andric 11181ad6265SDimitry Andric Expected<TraceSP> TraceIntelPT::CreateInstanceForTraceBundle( 11281ad6265SDimitry Andric const json::Value &bundle_description, StringRef bundle_dir, 113fe6060f1SDimitry Andric Debugger &debugger) { 114*bdd1243dSDimitry Andric return TraceIntelPTBundleLoader(debugger, bundle_description, bundle_dir) 11581ad6265SDimitry Andric .Load(); 116e8d8bef9SDimitry Andric } 117e8d8bef9SDimitry Andric 118fe6060f1SDimitry Andric Expected<TraceSP> TraceIntelPT::CreateInstanceForLiveProcess(Process &process) { 119fe6060f1SDimitry Andric TraceSP instance(new TraceIntelPT(process)); 120fe6060f1SDimitry Andric process.GetTarget().SetTrace(instance); 121fe6060f1SDimitry Andric return instance; 122fe6060f1SDimitry Andric } 123fe6060f1SDimitry Andric 12481ad6265SDimitry Andric TraceIntelPTSP TraceIntelPT::GetSharedPtr() { 12581ad6265SDimitry Andric return std::static_pointer_cast<TraceIntelPT>(shared_from_this()); 126e8d8bef9SDimitry Andric } 127e8d8bef9SDimitry Andric 128*bdd1243dSDimitry Andric TraceIntelPT::TraceMode TraceIntelPT::GetTraceMode() { return trace_mode; } 129*bdd1243dSDimitry Andric 13081ad6265SDimitry Andric TraceIntelPTSP TraceIntelPT::CreateInstanceForPostmortemTrace( 131*bdd1243dSDimitry Andric JSONTraceBundleDescription &bundle_description, 132*bdd1243dSDimitry Andric ArrayRef<ProcessSP> traced_processes, 133*bdd1243dSDimitry Andric ArrayRef<ThreadPostMortemTraceSP> traced_threads, TraceMode trace_mode) { 134*bdd1243dSDimitry Andric TraceIntelPTSP trace_sp( 135*bdd1243dSDimitry Andric new TraceIntelPT(bundle_description, traced_processes, trace_mode)); 136*bdd1243dSDimitry Andric trace_sp->m_storage.tsc_conversion = 137*bdd1243dSDimitry Andric bundle_description.tsc_perf_zero_conversion; 138fe6060f1SDimitry Andric 13981ad6265SDimitry Andric if (bundle_description.cpus) { 14081ad6265SDimitry Andric std::vector<cpu_id_t> cpus; 14181ad6265SDimitry Andric 14281ad6265SDimitry Andric for (const JSONCpu &cpu : *bundle_description.cpus) { 14381ad6265SDimitry Andric trace_sp->SetPostMortemCpuDataFile(cpu.id, IntelPTDataKinds::kIptTrace, 14481ad6265SDimitry Andric FileSpec(cpu.ipt_trace)); 14581ad6265SDimitry Andric 14681ad6265SDimitry Andric trace_sp->SetPostMortemCpuDataFile( 14781ad6265SDimitry Andric cpu.id, IntelPTDataKinds::kPerfContextSwitchTrace, 14881ad6265SDimitry Andric FileSpec(cpu.context_switch_trace)); 14981ad6265SDimitry Andric cpus.push_back(cpu.id); 15081ad6265SDimitry Andric } 15181ad6265SDimitry Andric 152*bdd1243dSDimitry Andric if (trace_mode == TraceMode::UserMode) { 15381ad6265SDimitry Andric trace_sp->m_storage.multicpu_decoder.emplace(trace_sp); 154*bdd1243dSDimitry Andric } 155*bdd1243dSDimitry Andric } 156*bdd1243dSDimitry Andric 157*bdd1243dSDimitry Andric if (!bundle_description.cpus || trace_mode == TraceMode::KernelMode) { 15881ad6265SDimitry Andric for (const ThreadPostMortemTraceSP &thread : traced_threads) { 15981ad6265SDimitry Andric trace_sp->m_storage.thread_decoders.try_emplace( 16081ad6265SDimitry Andric thread->GetID(), std::make_unique<ThreadDecoder>(thread, *trace_sp)); 161*bdd1243dSDimitry Andric if (const std::optional<FileSpec> &trace_file = thread->GetTraceFile()) { 16281ad6265SDimitry Andric trace_sp->SetPostMortemThreadDataFile( 16381ad6265SDimitry Andric thread->GetID(), IntelPTDataKinds::kIptTrace, *trace_file); 16481ad6265SDimitry Andric } 16581ad6265SDimitry Andric } 16681ad6265SDimitry Andric } 16781ad6265SDimitry Andric 16881ad6265SDimitry Andric for (const ProcessSP &process_sp : traced_processes) 16981ad6265SDimitry Andric process_sp->GetTarget().SetTrace(trace_sp); 17081ad6265SDimitry Andric return trace_sp; 17181ad6265SDimitry Andric } 17281ad6265SDimitry Andric 17381ad6265SDimitry Andric TraceIntelPT::TraceIntelPT(JSONTraceBundleDescription &bundle_description, 174*bdd1243dSDimitry Andric ArrayRef<ProcessSP> traced_processes, 175*bdd1243dSDimitry Andric TraceMode trace_mode) 17681ad6265SDimitry Andric : Trace(traced_processes, bundle_description.GetCpuIds()), 177*bdd1243dSDimitry Andric m_cpu_info(bundle_description.cpu_info), trace_mode(trace_mode) {} 17881ad6265SDimitry Andric 17981ad6265SDimitry Andric Expected<DecodedThreadSP> TraceIntelPT::Decode(Thread &thread) { 18081ad6265SDimitry Andric if (const char *error = RefreshLiveProcessState()) 18181ad6265SDimitry Andric return createStringError(inconvertibleErrorCode(), error); 18281ad6265SDimitry Andric 18381ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 18481ad6265SDimitry Andric if (storage.multicpu_decoder) 18581ad6265SDimitry Andric return storage.multicpu_decoder->Decode(thread); 18681ad6265SDimitry Andric 18781ad6265SDimitry Andric auto it = storage.thread_decoders.find(thread.GetID()); 18881ad6265SDimitry Andric if (it == storage.thread_decoders.end()) 18981ad6265SDimitry Andric return createStringError(inconvertibleErrorCode(), "thread not traced"); 190fe6060f1SDimitry Andric return it->second->Decode(); 191e8d8bef9SDimitry Andric } 192e8d8bef9SDimitry Andric 193*bdd1243dSDimitry Andric Expected<std::optional<uint64_t>> TraceIntelPT::FindBeginningOfTimeNanos() { 194972a253aSDimitry Andric Storage &storage = GetUpdatedStorage(); 195972a253aSDimitry Andric if (storage.beginning_of_time_nanos_calculated) 196972a253aSDimitry Andric return storage.beginning_of_time_nanos; 197972a253aSDimitry Andric storage.beginning_of_time_nanos_calculated = true; 198972a253aSDimitry Andric 199972a253aSDimitry Andric if (!storage.tsc_conversion) 200*bdd1243dSDimitry Andric return std::nullopt; 201972a253aSDimitry Andric 202*bdd1243dSDimitry Andric std::optional<uint64_t> lowest_tsc; 203972a253aSDimitry Andric 204972a253aSDimitry Andric if (storage.multicpu_decoder) { 205*bdd1243dSDimitry Andric if (Expected<std::optional<uint64_t>> tsc = 206972a253aSDimitry Andric storage.multicpu_decoder->FindLowestTSC()) { 207972a253aSDimitry Andric lowest_tsc = *tsc; 208972a253aSDimitry Andric } else { 209972a253aSDimitry Andric return tsc.takeError(); 210972a253aSDimitry Andric } 211972a253aSDimitry Andric } 212972a253aSDimitry Andric 213972a253aSDimitry Andric for (auto &decoder : storage.thread_decoders) { 214*bdd1243dSDimitry Andric Expected<std::optional<uint64_t>> tsc = decoder.second->FindLowestTSC(); 215972a253aSDimitry Andric if (!tsc) 216972a253aSDimitry Andric return tsc.takeError(); 217972a253aSDimitry Andric 218972a253aSDimitry Andric if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc)) 219972a253aSDimitry Andric lowest_tsc = **tsc; 220972a253aSDimitry Andric } 221972a253aSDimitry Andric 222972a253aSDimitry Andric if (lowest_tsc) { 223972a253aSDimitry Andric storage.beginning_of_time_nanos = 224972a253aSDimitry Andric storage.tsc_conversion->ToNanos(*lowest_tsc); 225972a253aSDimitry Andric } 226972a253aSDimitry Andric return storage.beginning_of_time_nanos; 227972a253aSDimitry Andric } 228972a253aSDimitry Andric 229*bdd1243dSDimitry Andric llvm::Expected<lldb::TraceCursorSP> 23081ad6265SDimitry Andric TraceIntelPT::CreateNewCursor(Thread &thread) { 231972a253aSDimitry Andric if (Expected<DecodedThreadSP> decoded_thread = Decode(thread)) { 232*bdd1243dSDimitry Andric if (Expected<std::optional<uint64_t>> beginning_of_time = 233972a253aSDimitry Andric FindBeginningOfTimeNanos()) 234*bdd1243dSDimitry Andric return std::make_shared<TraceCursorIntelPT>( 235972a253aSDimitry Andric thread.shared_from_this(), *decoded_thread, m_storage.tsc_conversion, 236972a253aSDimitry Andric *beginning_of_time); 23781ad6265SDimitry Andric else 238972a253aSDimitry Andric return beginning_of_time.takeError(); 239972a253aSDimitry Andric } else 24081ad6265SDimitry Andric return decoded_thread.takeError(); 241e8d8bef9SDimitry Andric } 242e8d8bef9SDimitry Andric 243753f127fSDimitry Andric void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose, 244753f127fSDimitry Andric bool json) { 24581ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 24681ad6265SDimitry Andric 24781ad6265SDimitry Andric lldb::tid_t tid = thread.GetID(); 248753f127fSDimitry Andric if (json) { 249753f127fSDimitry Andric DumpTraceInfoAsJson(thread, s, verbose); 250753f127fSDimitry Andric return; 251753f127fSDimitry Andric } 252753f127fSDimitry Andric 25381ad6265SDimitry Andric s.Format("\nthread #{0}: tid = {1}", thread.GetIndexID(), thread.GetID()); 25481ad6265SDimitry Andric if (!IsTraced(tid)) { 25581ad6265SDimitry Andric s << ", not traced\n"; 256e8d8bef9SDimitry Andric return; 257fe6060f1SDimitry Andric } 25881ad6265SDimitry Andric s << "\n"; 25981ad6265SDimitry Andric 26081ad6265SDimitry Andric Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread); 26181ad6265SDimitry Andric if (!decoded_thread_sp_or_err) { 26281ad6265SDimitry Andric s << toString(decoded_thread_sp_or_err.takeError()) << "\n"; 263fe6060f1SDimitry Andric return; 264e8d8bef9SDimitry Andric } 265e8d8bef9SDimitry Andric 26681ad6265SDimitry Andric DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err; 26781ad6265SDimitry Andric 268*bdd1243dSDimitry Andric Expected<std::optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread); 26981ad6265SDimitry Andric if (!raw_size_or_error) { 27081ad6265SDimitry Andric s.Format(" {0}\n", toString(raw_size_or_error.takeError())); 27181ad6265SDimitry Andric return; 27281ad6265SDimitry Andric } 273*bdd1243dSDimitry Andric std::optional<uint64_t> raw_size = *raw_size_or_error; 27481ad6265SDimitry Andric 275753f127fSDimitry Andric s.Format("\n Trace technology: {0}\n", GetPluginName()); 276753f127fSDimitry Andric 27781ad6265SDimitry Andric /// Instruction stats 27881ad6265SDimitry Andric { 27981ad6265SDimitry Andric uint64_t items_count = decoded_thread_sp->GetItemsCount(); 28081ad6265SDimitry Andric uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage(); 28181ad6265SDimitry Andric 282753f127fSDimitry Andric s.Format("\n Total number of trace items: {0}\n", items_count); 28381ad6265SDimitry Andric 28481ad6265SDimitry Andric s << "\n Memory usage:\n"; 28581ad6265SDimitry Andric if (raw_size) 28681ad6265SDimitry Andric s.Format(" Raw trace size: {0} KiB\n", *raw_size / 1024); 28781ad6265SDimitry Andric 28881ad6265SDimitry Andric s.Format( 28981ad6265SDimitry Andric " Total approximate memory usage (excluding raw trace): {0:2} KiB\n", 29081ad6265SDimitry Andric (double)mem_used / 1024); 29181ad6265SDimitry Andric if (items_count != 0) 29281ad6265SDimitry Andric s.Format(" Average memory usage per item (excluding raw trace): " 29381ad6265SDimitry Andric "{0:2} bytes\n", 29481ad6265SDimitry Andric (double)mem_used / items_count); 29581ad6265SDimitry Andric } 29681ad6265SDimitry Andric 29781ad6265SDimitry Andric // Timing 29881ad6265SDimitry Andric { 29981ad6265SDimitry Andric s << "\n Timing for this thread:\n"; 30081ad6265SDimitry Andric auto print_duration = [&](const std::string &name, 30181ad6265SDimitry Andric std::chrono::milliseconds duration) { 30281ad6265SDimitry Andric s.Format(" {0}: {1:2}s\n", name, duration.count() / 1000.0); 30381ad6265SDimitry Andric }; 304753f127fSDimitry Andric GetThreadTimer(tid).ForEachTimedTask(print_duration); 30581ad6265SDimitry Andric 30681ad6265SDimitry Andric s << "\n Timing for global tasks:\n"; 307753f127fSDimitry Andric GetGlobalTimer().ForEachTimedTask(print_duration); 30881ad6265SDimitry Andric } 30981ad6265SDimitry Andric 31081ad6265SDimitry Andric // Instruction events stats 31181ad6265SDimitry Andric { 31281ad6265SDimitry Andric const DecodedThread::EventsStats &events_stats = 31381ad6265SDimitry Andric decoded_thread_sp->GetEventsStats(); 31481ad6265SDimitry Andric s << "\n Events:\n"; 31581ad6265SDimitry Andric s.Format(" Number of individual events: {0}\n", 31681ad6265SDimitry Andric events_stats.total_count); 31781ad6265SDimitry Andric for (const auto &event_to_count : events_stats.events_counts) { 31881ad6265SDimitry Andric s.Format(" {0}: {1}\n", 31981ad6265SDimitry Andric TraceCursor::EventKindToString(event_to_count.first), 32081ad6265SDimitry Andric event_to_count.second); 32181ad6265SDimitry Andric } 32281ad6265SDimitry Andric } 323*bdd1243dSDimitry Andric // Trace error stats 324*bdd1243dSDimitry Andric { 325*bdd1243dSDimitry Andric const DecodedThread::ErrorStats &error_stats = 326*bdd1243dSDimitry Andric decoded_thread_sp->GetErrorStats(); 327*bdd1243dSDimitry Andric s << "\n Errors:\n"; 328*bdd1243dSDimitry Andric s.Format(" Number of individual errors: {0}\n", 329*bdd1243dSDimitry Andric error_stats.GetTotalCount()); 330*bdd1243dSDimitry Andric s.Format(" Number of fatal errors: {0}\n", error_stats.fatal_errors); 331*bdd1243dSDimitry Andric for (const auto &[kind, count] : error_stats.libipt_errors) { 332*bdd1243dSDimitry Andric s.Format(" Number of libipt errors of kind [{0}]: {1}\n", kind, 333*bdd1243dSDimitry Andric count); 334*bdd1243dSDimitry Andric } 335*bdd1243dSDimitry Andric s.Format(" Number of other errors: {0}\n", error_stats.other_errors); 336*bdd1243dSDimitry Andric } 33781ad6265SDimitry Andric 33881ad6265SDimitry Andric if (storage.multicpu_decoder) { 33981ad6265SDimitry Andric s << "\n Multi-cpu decoding:\n"; 34081ad6265SDimitry Andric s.Format(" Total number of continuous executions found: {0}\n", 34181ad6265SDimitry Andric storage.multicpu_decoder->GetTotalContinuousExecutionsCount()); 34281ad6265SDimitry Andric s.Format( 34381ad6265SDimitry Andric " Number of continuous executions for this thread: {0}\n", 34481ad6265SDimitry Andric storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid)); 345753f127fSDimitry Andric s.Format(" Total number of PSB blocks found: {0}\n", 346753f127fSDimitry Andric storage.multicpu_decoder->GetTotalPSBBlocksCount()); 347753f127fSDimitry Andric s.Format(" Number of PSB blocks for this thread: {0}\n", 348753f127fSDimitry Andric storage.multicpu_decoder->GePSBBlocksCountForThread(tid)); 349753f127fSDimitry Andric s.Format(" Total number of unattributed PSB blocks found: {0}\n", 350753f127fSDimitry Andric storage.multicpu_decoder->GetUnattributedPSBBlocksCount()); 35181ad6265SDimitry Andric } 35281ad6265SDimitry Andric } 35381ad6265SDimitry Andric 354753f127fSDimitry Andric void TraceIntelPT::DumpTraceInfoAsJson(Thread &thread, Stream &s, 355753f127fSDimitry Andric bool verbose) { 356753f127fSDimitry Andric Storage &storage = GetUpdatedStorage(); 357753f127fSDimitry Andric 358753f127fSDimitry Andric lldb::tid_t tid = thread.GetID(); 359753f127fSDimitry Andric json::OStream json_str(s.AsRawOstream(), 2); 360753f127fSDimitry Andric if (!IsTraced(tid)) { 361753f127fSDimitry Andric s << "error: thread not traced\n"; 362753f127fSDimitry Andric return; 363753f127fSDimitry Andric } 364753f127fSDimitry Andric 365*bdd1243dSDimitry Andric Expected<std::optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread); 366753f127fSDimitry Andric if (!raw_size_or_error) { 367753f127fSDimitry Andric s << "error: " << toString(raw_size_or_error.takeError()) << "\n"; 368753f127fSDimitry Andric return; 369753f127fSDimitry Andric } 370753f127fSDimitry Andric 371753f127fSDimitry Andric Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread); 372753f127fSDimitry Andric if (!decoded_thread_sp_or_err) { 373753f127fSDimitry Andric s << "error: " << toString(decoded_thread_sp_or_err.takeError()) << "\n"; 374753f127fSDimitry Andric return; 375753f127fSDimitry Andric } 376753f127fSDimitry Andric DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err; 377753f127fSDimitry Andric 378753f127fSDimitry Andric json_str.object([&] { 379753f127fSDimitry Andric json_str.attribute("traceTechnology", "intel-pt"); 380753f127fSDimitry Andric json_str.attributeObject("threadStats", [&] { 381753f127fSDimitry Andric json_str.attribute("tid", tid); 382753f127fSDimitry Andric 383753f127fSDimitry Andric uint64_t insn_len = decoded_thread_sp->GetItemsCount(); 384753f127fSDimitry Andric json_str.attribute("traceItemsCount", insn_len); 385753f127fSDimitry Andric 386753f127fSDimitry Andric // Instruction stats 387753f127fSDimitry Andric uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage(); 388753f127fSDimitry Andric json_str.attributeObject("memoryUsage", [&] { 389753f127fSDimitry Andric json_str.attribute("totalInBytes", std::to_string(mem_used)); 390*bdd1243dSDimitry Andric std::optional<double> avg; 391753f127fSDimitry Andric if (insn_len != 0) 392753f127fSDimitry Andric avg = double(mem_used) / insn_len; 393753f127fSDimitry Andric json_str.attribute("avgPerItemInBytes", avg); 394753f127fSDimitry Andric }); 395753f127fSDimitry Andric 396753f127fSDimitry Andric // Timing 397753f127fSDimitry Andric json_str.attributeObject("timingInSeconds", [&] { 398753f127fSDimitry Andric GetTimer().ForThread(tid).ForEachTimedTask( 399753f127fSDimitry Andric [&](const std::string &name, std::chrono::milliseconds duration) { 400753f127fSDimitry Andric json_str.attribute(name, duration.count() / 1000.0); 401753f127fSDimitry Andric }); 402753f127fSDimitry Andric }); 403753f127fSDimitry Andric 404753f127fSDimitry Andric // Instruction events stats 405753f127fSDimitry Andric const DecodedThread::EventsStats &events_stats = 406753f127fSDimitry Andric decoded_thread_sp->GetEventsStats(); 407753f127fSDimitry Andric json_str.attributeObject("events", [&] { 408753f127fSDimitry Andric json_str.attribute("totalCount", events_stats.total_count); 409753f127fSDimitry Andric json_str.attributeObject("individualCounts", [&] { 410753f127fSDimitry Andric for (const auto &event_to_count : events_stats.events_counts) { 411753f127fSDimitry Andric json_str.attribute( 412753f127fSDimitry Andric TraceCursor::EventKindToString(event_to_count.first), 413753f127fSDimitry Andric event_to_count.second); 414753f127fSDimitry Andric } 415753f127fSDimitry Andric }); 416753f127fSDimitry Andric }); 417*bdd1243dSDimitry Andric // Trace error stats 418*bdd1243dSDimitry Andric const DecodedThread::ErrorStats &error_stats = 419*bdd1243dSDimitry Andric decoded_thread_sp->GetErrorStats(); 420*bdd1243dSDimitry Andric json_str.attributeObject("errors", [&] { 421*bdd1243dSDimitry Andric json_str.attribute("totalCount", error_stats.GetTotalCount()); 422*bdd1243dSDimitry Andric json_str.attributeObject("libiptErrors", [&] { 423*bdd1243dSDimitry Andric for (const auto &[kind, count] : error_stats.libipt_errors) { 424*bdd1243dSDimitry Andric json_str.attribute(kind, count); 425*bdd1243dSDimitry Andric } 426*bdd1243dSDimitry Andric }); 427*bdd1243dSDimitry Andric json_str.attribute("fatalErrors", error_stats.fatal_errors); 428*bdd1243dSDimitry Andric json_str.attribute("otherErrors", error_stats.other_errors); 429*bdd1243dSDimitry Andric }); 430753f127fSDimitry Andric 431753f127fSDimitry Andric if (storage.multicpu_decoder) { 432753f127fSDimitry Andric json_str.attribute( 433753f127fSDimitry Andric "continuousExecutions", 434753f127fSDimitry Andric storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid)); 435753f127fSDimitry Andric json_str.attribute( 436753f127fSDimitry Andric "PSBBlocks", 437753f127fSDimitry Andric storage.multicpu_decoder->GePSBBlocksCountForThread(tid)); 438753f127fSDimitry Andric } 439*bdd1243dSDimitry Andric }); 440753f127fSDimitry Andric 441753f127fSDimitry Andric json_str.attributeObject("globalStats", [&] { 442753f127fSDimitry Andric json_str.attributeObject("timingInSeconds", [&] { 443753f127fSDimitry Andric GetTimer().ForGlobal().ForEachTimedTask( 444753f127fSDimitry Andric [&](const std::string &name, std::chrono::milliseconds duration) { 445753f127fSDimitry Andric json_str.attribute(name, duration.count() / 1000.0); 446753f127fSDimitry Andric }); 447753f127fSDimitry Andric }); 448753f127fSDimitry Andric if (storage.multicpu_decoder) { 449753f127fSDimitry Andric json_str.attribute( 450753f127fSDimitry Andric "totalUnattributedPSBBlocks", 451753f127fSDimitry Andric storage.multicpu_decoder->GetUnattributedPSBBlocksCount()); 452753f127fSDimitry Andric json_str.attribute( 453753f127fSDimitry Andric "totalCountinuosExecutions", 454753f127fSDimitry Andric storage.multicpu_decoder->GetTotalContinuousExecutionsCount()); 455753f127fSDimitry Andric json_str.attribute("totalPSBBlocks", 456753f127fSDimitry Andric storage.multicpu_decoder->GetTotalPSBBlocksCount()); 457753f127fSDimitry Andric json_str.attribute( 458753f127fSDimitry Andric "totalContinuousExecutions", 459753f127fSDimitry Andric storage.multicpu_decoder->GetTotalContinuousExecutionsCount()); 460753f127fSDimitry Andric } 461753f127fSDimitry Andric }); 462753f127fSDimitry Andric }); 463753f127fSDimitry Andric } 464753f127fSDimitry Andric 465*bdd1243dSDimitry Andric llvm::Expected<std::optional<uint64_t>> 46681ad6265SDimitry Andric TraceIntelPT::GetRawTraceSize(Thread &thread) { 46781ad6265SDimitry Andric if (GetUpdatedStorage().multicpu_decoder) 468*bdd1243dSDimitry Andric return std::nullopt; // TODO: calculate the amount of intel pt raw trace associated 46981ad6265SDimitry Andric // with the given thread. 47081ad6265SDimitry Andric if (GetLiveProcess()) 47181ad6265SDimitry Andric return GetLiveThreadBinaryDataSize(thread.GetID(), 47281ad6265SDimitry Andric IntelPTDataKinds::kIptTrace); 47381ad6265SDimitry Andric uint64_t size; 47481ad6265SDimitry Andric auto callback = [&](llvm::ArrayRef<uint8_t> data) { 47581ad6265SDimitry Andric size = data.size(); 47681ad6265SDimitry Andric return Error::success(); 47781ad6265SDimitry Andric }; 47881ad6265SDimitry Andric if (Error err = OnThreadBufferRead(thread.GetID(), callback)) 47981ad6265SDimitry Andric return std::move(err); 48081ad6265SDimitry Andric 48181ad6265SDimitry Andric return size; 482fe6060f1SDimitry Andric } 483fe6060f1SDimitry Andric 484fe6060f1SDimitry Andric Expected<pt_cpu> TraceIntelPT::GetCPUInfoForLiveProcess() { 48581ad6265SDimitry Andric Expected<std::vector<uint8_t>> cpu_info = 48681ad6265SDimitry Andric GetLiveProcessBinaryData(IntelPTDataKinds::kProcFsCpuInfo); 487fe6060f1SDimitry Andric if (!cpu_info) 488fe6060f1SDimitry Andric return cpu_info.takeError(); 489fe6060f1SDimitry Andric 490fe6060f1SDimitry Andric int64_t cpu_family = -1; 491fe6060f1SDimitry Andric int64_t model = -1; 492fe6060f1SDimitry Andric int64_t stepping = -1; 493fe6060f1SDimitry Andric std::string vendor_id; 494fe6060f1SDimitry Andric 495fe6060f1SDimitry Andric StringRef rest(reinterpret_cast<const char *>(cpu_info->data()), 496fe6060f1SDimitry Andric cpu_info->size()); 497fe6060f1SDimitry Andric while (!rest.empty()) { 498fe6060f1SDimitry Andric StringRef line; 499fe6060f1SDimitry Andric std::tie(line, rest) = rest.split('\n'); 500fe6060f1SDimitry Andric 501fe6060f1SDimitry Andric SmallVector<StringRef, 2> columns; 502fe6060f1SDimitry Andric line.split(columns, StringRef(":"), -1, false); 503fe6060f1SDimitry Andric 504fe6060f1SDimitry Andric if (columns.size() < 2) 505fe6060f1SDimitry Andric continue; // continue searching 506fe6060f1SDimitry Andric 507fe6060f1SDimitry Andric columns[1] = columns[1].trim(" "); 508fe6060f1SDimitry Andric if (columns[0].contains("cpu family") && 509fe6060f1SDimitry Andric columns[1].getAsInteger(10, cpu_family)) 510fe6060f1SDimitry Andric continue; 511fe6060f1SDimitry Andric 512fe6060f1SDimitry Andric else if (columns[0].contains("model") && columns[1].getAsInteger(10, model)) 513fe6060f1SDimitry Andric continue; 514fe6060f1SDimitry Andric 515fe6060f1SDimitry Andric else if (columns[0].contains("stepping") && 516fe6060f1SDimitry Andric columns[1].getAsInteger(10, stepping)) 517fe6060f1SDimitry Andric continue; 518fe6060f1SDimitry Andric 519fe6060f1SDimitry Andric else if (columns[0].contains("vendor_id")) { 520fe6060f1SDimitry Andric vendor_id = columns[1].str(); 521fe6060f1SDimitry Andric if (!vendor_id.empty()) 522fe6060f1SDimitry Andric continue; 523fe6060f1SDimitry Andric } 524fe6060f1SDimitry Andric 525fe6060f1SDimitry Andric if ((cpu_family != -1) && (model != -1) && (stepping != -1) && 526fe6060f1SDimitry Andric (!vendor_id.empty())) { 527fe6060f1SDimitry Andric return pt_cpu{vendor_id == "GenuineIntel" ? pcv_intel : pcv_unknown, 528fe6060f1SDimitry Andric static_cast<uint16_t>(cpu_family), 529fe6060f1SDimitry Andric static_cast<uint8_t>(model), 530fe6060f1SDimitry Andric static_cast<uint8_t>(stepping)}; 531fe6060f1SDimitry Andric } 532fe6060f1SDimitry Andric } 533fe6060f1SDimitry Andric return createStringError(inconvertibleErrorCode(), 534fe6060f1SDimitry Andric "Failed parsing the target's /proc/cpuinfo file"); 535fe6060f1SDimitry Andric } 536fe6060f1SDimitry Andric 537fe6060f1SDimitry Andric Expected<pt_cpu> TraceIntelPT::GetCPUInfo() { 538fe6060f1SDimitry Andric if (!m_cpu_info) { 539fe6060f1SDimitry Andric if (llvm::Expected<pt_cpu> cpu_info = GetCPUInfoForLiveProcess()) 540fe6060f1SDimitry Andric m_cpu_info = *cpu_info; 541fe6060f1SDimitry Andric else 542fe6060f1SDimitry Andric return cpu_info.takeError(); 543fe6060f1SDimitry Andric } 544fe6060f1SDimitry Andric return *m_cpu_info; 545fe6060f1SDimitry Andric } 546fe6060f1SDimitry Andric 547*bdd1243dSDimitry Andric std::optional<LinuxPerfZeroTscConversion> 54881ad6265SDimitry Andric TraceIntelPT::GetPerfZeroTscConversion() { 54981ad6265SDimitry Andric return GetUpdatedStorage().tsc_conversion; 550fe6060f1SDimitry Andric } 551fe6060f1SDimitry Andric 55281ad6265SDimitry Andric TraceIntelPT::Storage &TraceIntelPT::GetUpdatedStorage() { 55381ad6265SDimitry Andric RefreshLiveProcessState(); 55481ad6265SDimitry Andric return m_storage; 555fe6060f1SDimitry Andric } 55681ad6265SDimitry Andric 55781ad6265SDimitry Andric Error TraceIntelPT::DoRefreshLiveProcessState(TraceGetStateResponse state, 55881ad6265SDimitry Andric StringRef json_response) { 55981ad6265SDimitry Andric m_storage = Storage(); 56081ad6265SDimitry Andric 56181ad6265SDimitry Andric Expected<TraceIntelPTGetStateResponse> intelpt_state = 56281ad6265SDimitry Andric json::parse<TraceIntelPTGetStateResponse>(json_response, 56381ad6265SDimitry Andric "TraceIntelPTGetStateResponse"); 56481ad6265SDimitry Andric if (!intelpt_state) 56581ad6265SDimitry Andric return intelpt_state.takeError(); 56681ad6265SDimitry Andric 56781ad6265SDimitry Andric m_storage.tsc_conversion = intelpt_state->tsc_perf_zero_conversion; 56881ad6265SDimitry Andric 56981ad6265SDimitry Andric if (!intelpt_state->cpus) { 57081ad6265SDimitry Andric for (const TraceThreadState &thread_state : state.traced_threads) { 57181ad6265SDimitry Andric ThreadSP thread_sp = 57281ad6265SDimitry Andric GetLiveProcess()->GetThreadList().FindThreadByID(thread_state.tid); 57381ad6265SDimitry Andric m_storage.thread_decoders.try_emplace( 57481ad6265SDimitry Andric thread_state.tid, std::make_unique<ThreadDecoder>(thread_sp, *this)); 57581ad6265SDimitry Andric } 57681ad6265SDimitry Andric } else { 57781ad6265SDimitry Andric std::vector<cpu_id_t> cpus; 57881ad6265SDimitry Andric for (const TraceCpuState &cpu : *intelpt_state->cpus) 57981ad6265SDimitry Andric cpus.push_back(cpu.id); 58081ad6265SDimitry Andric 58181ad6265SDimitry Andric std::vector<tid_t> tids; 58281ad6265SDimitry Andric for (const TraceThreadState &thread : intelpt_state->traced_threads) 58381ad6265SDimitry Andric tids.push_back(thread.tid); 58481ad6265SDimitry Andric 58581ad6265SDimitry Andric if (!intelpt_state->tsc_perf_zero_conversion) 58681ad6265SDimitry Andric return createStringError(inconvertibleErrorCode(), 58781ad6265SDimitry Andric "Missing perf time_zero conversion values"); 58881ad6265SDimitry Andric m_storage.multicpu_decoder.emplace(GetSharedPtr()); 58981ad6265SDimitry Andric } 59081ad6265SDimitry Andric 59181ad6265SDimitry Andric if (m_storage.tsc_conversion) { 59281ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Target); 59381ad6265SDimitry Andric LLDB_LOG(log, "TraceIntelPT found TSC conversion information"); 59481ad6265SDimitry Andric } 59581ad6265SDimitry Andric return Error::success(); 596fe6060f1SDimitry Andric } 597fe6060f1SDimitry Andric 598349cc55cSDimitry Andric bool TraceIntelPT::IsTraced(lldb::tid_t tid) { 59981ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 60081ad6265SDimitry Andric if (storage.multicpu_decoder) 60181ad6265SDimitry Andric return storage.multicpu_decoder->TracesThread(tid); 60281ad6265SDimitry Andric return storage.thread_decoders.count(tid); 603fe6060f1SDimitry Andric } 604fe6060f1SDimitry Andric 605fe6060f1SDimitry Andric // The information here should match the description of the intel-pt section 606fe6060f1SDimitry Andric // of the jLLDBTraceStart packet in the lldb/docs/lldb-gdb-remote.txt 607fe6060f1SDimitry Andric // documentation file. Similarly, it should match the CLI help messages of the 608fe6060f1SDimitry Andric // TraceIntelPTOptions.td file. 609fe6060f1SDimitry Andric const char *TraceIntelPT::GetStartConfigurationHelp() { 610*bdd1243dSDimitry Andric static std::optional<std::string> message; 61181ad6265SDimitry Andric if (!message) { 61281ad6265SDimitry Andric message.emplace(formatv(R"(Parameters: 613fe6060f1SDimitry Andric 61481ad6265SDimitry Andric See the jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt for a 61581ad6265SDimitry Andric description of each parameter below. 616fe6060f1SDimitry Andric 61781ad6265SDimitry Andric - int iptTraceSize (defaults to {0} bytes): 618fe6060f1SDimitry Andric [process and thread tracing] 619fe6060f1SDimitry Andric 62081ad6265SDimitry Andric - boolean enableTsc (default to {1}): 621fe6060f1SDimitry Andric [process and thread tracing] 622fe6060f1SDimitry Andric 62381ad6265SDimitry Andric - int psbPeriod (defaults to {2}): 624fe6060f1SDimitry Andric [process and thread tracing] 625fe6060f1SDimitry Andric 62681ad6265SDimitry Andric - boolean perCpuTracing (default to {3}): 627fe6060f1SDimitry Andric [process tracing only] 62881ad6265SDimitry Andric 62981ad6265SDimitry Andric - int processBufferSizeLimit (defaults to {4} MiB): 630753f127fSDimitry Andric [process tracing only] 631753f127fSDimitry Andric 632753f127fSDimitry Andric - boolean disableCgroupFiltering (default to {5}): 63381ad6265SDimitry Andric [process tracing only])", 63481ad6265SDimitry Andric kDefaultIptTraceSize, kDefaultEnableTscValue, 63581ad6265SDimitry Andric kDefaultPsbPeriod, kDefaultPerCpuTracing, 636753f127fSDimitry Andric kDefaultProcessBufferSizeLimit / 1024 / 1024, 637753f127fSDimitry Andric kDefaultDisableCgroupFiltering)); 63881ad6265SDimitry Andric } 63981ad6265SDimitry Andric return message->c_str(); 640fe6060f1SDimitry Andric } 641fe6060f1SDimitry Andric 64281ad6265SDimitry Andric Error TraceIntelPT::Start(uint64_t ipt_trace_size, 64381ad6265SDimitry Andric uint64_t total_buffer_size_limit, bool enable_tsc, 644*bdd1243dSDimitry Andric std::optional<uint64_t> psb_period, 645*bdd1243dSDimitry Andric bool per_cpu_tracing, bool disable_cgroup_filtering) { 646fe6060f1SDimitry Andric TraceIntelPTStartRequest request; 64781ad6265SDimitry Andric request.ipt_trace_size = ipt_trace_size; 64881ad6265SDimitry Andric request.process_buffer_size_limit = total_buffer_size_limit; 64981ad6265SDimitry Andric request.enable_tsc = enable_tsc; 65081ad6265SDimitry Andric request.psb_period = psb_period; 651349cc55cSDimitry Andric request.type = GetPluginName().str(); 65281ad6265SDimitry Andric request.per_cpu_tracing = per_cpu_tracing; 653753f127fSDimitry Andric request.disable_cgroup_filtering = disable_cgroup_filtering; 654fe6060f1SDimitry Andric return Trace::Start(toJSON(request)); 655fe6060f1SDimitry Andric } 656fe6060f1SDimitry Andric 657fe6060f1SDimitry Andric Error TraceIntelPT::Start(StructuredData::ObjectSP configuration) { 65881ad6265SDimitry Andric uint64_t ipt_trace_size = kDefaultIptTraceSize; 65981ad6265SDimitry Andric uint64_t process_buffer_size_limit = kDefaultProcessBufferSizeLimit; 660fe6060f1SDimitry Andric bool enable_tsc = kDefaultEnableTscValue; 661*bdd1243dSDimitry Andric std::optional<uint64_t> psb_period = kDefaultPsbPeriod; 66281ad6265SDimitry Andric bool per_cpu_tracing = kDefaultPerCpuTracing; 663753f127fSDimitry Andric bool disable_cgroup_filtering = kDefaultDisableCgroupFiltering; 664fe6060f1SDimitry Andric 665fe6060f1SDimitry Andric if (configuration) { 666fe6060f1SDimitry Andric if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) { 66781ad6265SDimitry Andric dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size); 668fe6060f1SDimitry Andric dict->GetValueForKeyAsInteger("processBufferSizeLimit", 669fe6060f1SDimitry Andric process_buffer_size_limit); 670fe6060f1SDimitry Andric dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc); 671fe6060f1SDimitry Andric dict->GetValueForKeyAsInteger("psbPeriod", psb_period); 67281ad6265SDimitry Andric dict->GetValueForKeyAsBoolean("perCpuTracing", per_cpu_tracing); 673753f127fSDimitry Andric dict->GetValueForKeyAsBoolean("disableCgroupFiltering", 674753f127fSDimitry Andric disable_cgroup_filtering); 675fe6060f1SDimitry Andric } else { 676fe6060f1SDimitry Andric return createStringError(inconvertibleErrorCode(), 677fe6060f1SDimitry Andric "configuration object is not a dictionary"); 678fe6060f1SDimitry Andric } 679fe6060f1SDimitry Andric } 680fe6060f1SDimitry Andric 68181ad6265SDimitry Andric return Start(ipt_trace_size, process_buffer_size_limit, enable_tsc, 682753f127fSDimitry Andric psb_period, per_cpu_tracing, disable_cgroup_filtering); 683fe6060f1SDimitry Andric } 684fe6060f1SDimitry Andric 685fe6060f1SDimitry Andric llvm::Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids, 68681ad6265SDimitry Andric uint64_t ipt_trace_size, bool enable_tsc, 687*bdd1243dSDimitry Andric std::optional<uint64_t> psb_period) { 688fe6060f1SDimitry Andric TraceIntelPTStartRequest request; 68981ad6265SDimitry Andric request.ipt_trace_size = ipt_trace_size; 69081ad6265SDimitry Andric request.enable_tsc = enable_tsc; 69181ad6265SDimitry Andric request.psb_period = psb_period; 692349cc55cSDimitry Andric request.type = GetPluginName().str(); 693fe6060f1SDimitry Andric request.tids.emplace(); 694fe6060f1SDimitry Andric for (lldb::tid_t tid : tids) 695fe6060f1SDimitry Andric request.tids->push_back(tid); 696fe6060f1SDimitry Andric return Trace::Start(toJSON(request)); 697fe6060f1SDimitry Andric } 698fe6060f1SDimitry Andric 699fe6060f1SDimitry Andric Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids, 700fe6060f1SDimitry Andric StructuredData::ObjectSP configuration) { 70181ad6265SDimitry Andric uint64_t ipt_trace_size = kDefaultIptTraceSize; 702fe6060f1SDimitry Andric bool enable_tsc = kDefaultEnableTscValue; 703*bdd1243dSDimitry Andric std::optional<uint64_t> psb_period = kDefaultPsbPeriod; 704fe6060f1SDimitry Andric 705fe6060f1SDimitry Andric if (configuration) { 706fe6060f1SDimitry Andric if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) { 707753f127fSDimitry Andric llvm::StringRef ipt_trace_size_not_parsed; 708753f127fSDimitry Andric if (dict->GetValueForKeyAsString("iptTraceSize", 709753f127fSDimitry Andric ipt_trace_size_not_parsed)) { 710*bdd1243dSDimitry Andric if (std::optional<uint64_t> bytes = 711753f127fSDimitry Andric ParsingUtils::ParseUserFriendlySizeExpression( 712753f127fSDimitry Andric ipt_trace_size_not_parsed)) 713753f127fSDimitry Andric ipt_trace_size = *bytes; 714753f127fSDimitry Andric else 715753f127fSDimitry Andric return createStringError(inconvertibleErrorCode(), 716753f127fSDimitry Andric "iptTraceSize is wrong bytes expression"); 717753f127fSDimitry Andric } else { 71881ad6265SDimitry Andric dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size); 719753f127fSDimitry Andric } 720753f127fSDimitry Andric 721fe6060f1SDimitry Andric dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc); 722fe6060f1SDimitry Andric dict->GetValueForKeyAsInteger("psbPeriod", psb_period); 723fe6060f1SDimitry Andric } else { 724fe6060f1SDimitry Andric return createStringError(inconvertibleErrorCode(), 725fe6060f1SDimitry Andric "configuration object is not a dictionary"); 726fe6060f1SDimitry Andric } 727fe6060f1SDimitry Andric } 728fe6060f1SDimitry Andric 72981ad6265SDimitry Andric return Start(tids, ipt_trace_size, enable_tsc, psb_period); 730fe6060f1SDimitry Andric } 731fe6060f1SDimitry Andric 73281ad6265SDimitry Andric Error TraceIntelPT::OnThreadBufferRead(lldb::tid_t tid, 73381ad6265SDimitry Andric OnBinaryDataReadCallback callback) { 73481ad6265SDimitry Andric return OnThreadBinaryDataRead(tid, IntelPTDataKinds::kIptTrace, callback); 735e8d8bef9SDimitry Andric } 73681ad6265SDimitry Andric 73781ad6265SDimitry Andric TaskTimer &TraceIntelPT::GetTimer() { return GetUpdatedStorage().task_timer; } 738753f127fSDimitry Andric 739753f127fSDimitry Andric ScopedTaskTimer &TraceIntelPT::GetThreadTimer(lldb::tid_t tid) { 740753f127fSDimitry Andric return GetTimer().ForThread(tid); 741753f127fSDimitry Andric } 742753f127fSDimitry Andric 743753f127fSDimitry Andric ScopedTaskTimer &TraceIntelPT::GetGlobalTimer() { 744753f127fSDimitry Andric return GetTimer().ForGlobal(); 745753f127fSDimitry Andric } 746