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 11*972a253aSDimitry Andric #include "TraceCursorIntelPT.h" 12*972a253aSDimitry Andric 13fe6060f1SDimitry Andric #include "../common/ThreadPostMortemTrace.h" 14e8d8bef9SDimitry Andric #include "CommandObjectTraceStartIntelPT.h" 15fe6060f1SDimitry Andric #include "DecodedThread.h" 16fe6060f1SDimitry Andric #include "TraceIntelPTConstants.h" 1781ad6265SDimitry Andric #include "TraceIntelPTBundleLoader.h" 1881ad6265SDimitry Andric #include "TraceIntelPTBundleSaver.h" 19e8d8bef9SDimitry Andric #include "lldb/Core/PluginManager.h" 20e8d8bef9SDimitry Andric #include "lldb/Target/Process.h" 21e8d8bef9SDimitry Andric #include "lldb/Target/Target.h" 22349cc55cSDimitry Andric #include "llvm/ADT/None.h" 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 43e8d8bef9SDimitry Andric void TraceIntelPT::Initialize() { 44fe6060f1SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(), "Intel Processor Trace", 4581ad6265SDimitry Andric CreateInstanceForTraceBundle, 46fe6060f1SDimitry Andric CreateInstanceForLiveProcess, 4781ad6265SDimitry Andric TraceIntelPTBundleLoader::GetSchema()); 48e8d8bef9SDimitry Andric } 49e8d8bef9SDimitry Andric 50e8d8bef9SDimitry Andric void TraceIntelPT::Terminate() { 5181ad6265SDimitry Andric PluginManager::UnregisterPlugin(CreateInstanceForTraceBundle); 52e8d8bef9SDimitry Andric } 53e8d8bef9SDimitry Andric 54e8d8bef9SDimitry Andric StringRef TraceIntelPT::GetSchema() { 5581ad6265SDimitry Andric return TraceIntelPTBundleLoader::GetSchema(); 56e8d8bef9SDimitry Andric } 57e8d8bef9SDimitry Andric 58e8d8bef9SDimitry Andric void TraceIntelPT::Dump(Stream *s) const {} 59e8d8bef9SDimitry Andric 60753f127fSDimitry Andric Expected<FileSpec> TraceIntelPT::SaveToDisk(FileSpec directory, bool compact) { 61349cc55cSDimitry Andric RefreshLiveProcessState(); 62753f127fSDimitry Andric return TraceIntelPTBundleSaver().SaveToDisk(*this, directory, compact); 63349cc55cSDimitry Andric } 64349cc55cSDimitry Andric 6581ad6265SDimitry Andric Expected<TraceSP> TraceIntelPT::CreateInstanceForTraceBundle( 6681ad6265SDimitry Andric const json::Value &bundle_description, StringRef bundle_dir, 67fe6060f1SDimitry Andric Debugger &debugger) { 6881ad6265SDimitry Andric return TraceIntelPTBundleLoader(debugger, bundle_description, 6981ad6265SDimitry Andric bundle_dir) 7081ad6265SDimitry Andric .Load(); 71e8d8bef9SDimitry Andric } 72e8d8bef9SDimitry Andric 73fe6060f1SDimitry Andric Expected<TraceSP> TraceIntelPT::CreateInstanceForLiveProcess(Process &process) { 74fe6060f1SDimitry Andric TraceSP instance(new TraceIntelPT(process)); 75fe6060f1SDimitry Andric process.GetTarget().SetTrace(instance); 76fe6060f1SDimitry Andric return instance; 77fe6060f1SDimitry Andric } 78fe6060f1SDimitry Andric 7981ad6265SDimitry Andric TraceIntelPTSP TraceIntelPT::GetSharedPtr() { 8081ad6265SDimitry Andric return std::static_pointer_cast<TraceIntelPT>(shared_from_this()); 81e8d8bef9SDimitry Andric } 82e8d8bef9SDimitry Andric 8381ad6265SDimitry Andric TraceIntelPTSP TraceIntelPT::CreateInstanceForPostmortemTrace( 8481ad6265SDimitry Andric JSONTraceBundleDescription &bundle_description, ArrayRef<ProcessSP> traced_processes, 8581ad6265SDimitry Andric ArrayRef<ThreadPostMortemTraceSP> traced_threads) { 8681ad6265SDimitry Andric TraceIntelPTSP trace_sp(new TraceIntelPT(bundle_description, traced_processes)); 8781ad6265SDimitry Andric trace_sp->m_storage.tsc_conversion = bundle_description.tsc_perf_zero_conversion; 88fe6060f1SDimitry Andric 8981ad6265SDimitry Andric if (bundle_description.cpus) { 9081ad6265SDimitry Andric std::vector<cpu_id_t> cpus; 9181ad6265SDimitry Andric 9281ad6265SDimitry Andric for (const JSONCpu &cpu : *bundle_description.cpus) { 9381ad6265SDimitry Andric trace_sp->SetPostMortemCpuDataFile(cpu.id, IntelPTDataKinds::kIptTrace, 9481ad6265SDimitry Andric FileSpec(cpu.ipt_trace)); 9581ad6265SDimitry Andric 9681ad6265SDimitry Andric trace_sp->SetPostMortemCpuDataFile( 9781ad6265SDimitry Andric cpu.id, IntelPTDataKinds::kPerfContextSwitchTrace, 9881ad6265SDimitry Andric FileSpec(cpu.context_switch_trace)); 9981ad6265SDimitry Andric cpus.push_back(cpu.id); 10081ad6265SDimitry Andric } 10181ad6265SDimitry Andric 10281ad6265SDimitry Andric std::vector<tid_t> tids; 10381ad6265SDimitry Andric for (const JSONProcess &process : bundle_description.processes) 10481ad6265SDimitry Andric for (const JSONThread &thread : process.threads) 10581ad6265SDimitry Andric tids.push_back(thread.tid); 10681ad6265SDimitry Andric 10781ad6265SDimitry Andric trace_sp->m_storage.multicpu_decoder.emplace(trace_sp); 10881ad6265SDimitry Andric } else { 10981ad6265SDimitry Andric for (const ThreadPostMortemTraceSP &thread : traced_threads) { 11081ad6265SDimitry Andric trace_sp->m_storage.thread_decoders.try_emplace( 11181ad6265SDimitry Andric thread->GetID(), std::make_unique<ThreadDecoder>(thread, *trace_sp)); 11281ad6265SDimitry Andric if (const Optional<FileSpec> &trace_file = thread->GetTraceFile()) { 11381ad6265SDimitry Andric trace_sp->SetPostMortemThreadDataFile( 11481ad6265SDimitry Andric thread->GetID(), IntelPTDataKinds::kIptTrace, *trace_file); 11581ad6265SDimitry Andric } 11681ad6265SDimitry Andric } 11781ad6265SDimitry Andric } 11881ad6265SDimitry Andric 11981ad6265SDimitry Andric for (const ProcessSP &process_sp : traced_processes) 12081ad6265SDimitry Andric process_sp->GetTarget().SetTrace(trace_sp); 12181ad6265SDimitry Andric return trace_sp; 12281ad6265SDimitry Andric } 12381ad6265SDimitry Andric 12481ad6265SDimitry Andric TraceIntelPT::TraceIntelPT(JSONTraceBundleDescription &bundle_description, 12581ad6265SDimitry Andric ArrayRef<ProcessSP> traced_processes) 12681ad6265SDimitry Andric : Trace(traced_processes, bundle_description.GetCpuIds()), 12781ad6265SDimitry Andric m_cpu_info(bundle_description.cpu_info) {} 12881ad6265SDimitry Andric 12981ad6265SDimitry Andric Expected<DecodedThreadSP> TraceIntelPT::Decode(Thread &thread) { 13081ad6265SDimitry Andric if (const char *error = RefreshLiveProcessState()) 13181ad6265SDimitry Andric return createStringError(inconvertibleErrorCode(), error); 13281ad6265SDimitry Andric 13381ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 13481ad6265SDimitry Andric if (storage.multicpu_decoder) 13581ad6265SDimitry Andric return storage.multicpu_decoder->Decode(thread); 13681ad6265SDimitry Andric 13781ad6265SDimitry Andric auto it = storage.thread_decoders.find(thread.GetID()); 13881ad6265SDimitry Andric if (it == storage.thread_decoders.end()) 13981ad6265SDimitry Andric return createStringError(inconvertibleErrorCode(), "thread not traced"); 140fe6060f1SDimitry Andric return it->second->Decode(); 141e8d8bef9SDimitry Andric } 142e8d8bef9SDimitry Andric 143*972a253aSDimitry Andric Expected<Optional<uint64_t>> TraceIntelPT::FindBeginningOfTimeNanos() { 144*972a253aSDimitry Andric Storage &storage = GetUpdatedStorage(); 145*972a253aSDimitry Andric if (storage.beginning_of_time_nanos_calculated) 146*972a253aSDimitry Andric return storage.beginning_of_time_nanos; 147*972a253aSDimitry Andric storage.beginning_of_time_nanos_calculated = true; 148*972a253aSDimitry Andric 149*972a253aSDimitry Andric if (!storage.tsc_conversion) 150*972a253aSDimitry Andric return None; 151*972a253aSDimitry Andric 152*972a253aSDimitry Andric Optional<uint64_t> lowest_tsc; 153*972a253aSDimitry Andric 154*972a253aSDimitry Andric if (storage.multicpu_decoder) { 155*972a253aSDimitry Andric if (Expected<Optional<uint64_t>> tsc = 156*972a253aSDimitry Andric storage.multicpu_decoder->FindLowestTSC()) { 157*972a253aSDimitry Andric lowest_tsc = *tsc; 158*972a253aSDimitry Andric } else { 159*972a253aSDimitry Andric return tsc.takeError(); 160*972a253aSDimitry Andric } 161*972a253aSDimitry Andric } 162*972a253aSDimitry Andric 163*972a253aSDimitry Andric for (auto &decoder : storage.thread_decoders) { 164*972a253aSDimitry Andric Expected<Optional<uint64_t>> tsc = decoder.second->FindLowestTSC(); 165*972a253aSDimitry Andric if (!tsc) 166*972a253aSDimitry Andric return tsc.takeError(); 167*972a253aSDimitry Andric 168*972a253aSDimitry Andric if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc)) 169*972a253aSDimitry Andric lowest_tsc = **tsc; 170*972a253aSDimitry Andric } 171*972a253aSDimitry Andric 172*972a253aSDimitry Andric if (lowest_tsc) { 173*972a253aSDimitry Andric storage.beginning_of_time_nanos = 174*972a253aSDimitry Andric storage.tsc_conversion->ToNanos(*lowest_tsc); 175*972a253aSDimitry Andric } 176*972a253aSDimitry Andric return storage.beginning_of_time_nanos; 177*972a253aSDimitry Andric } 178*972a253aSDimitry Andric 17981ad6265SDimitry Andric llvm::Expected<lldb::TraceCursorUP> 18081ad6265SDimitry Andric TraceIntelPT::CreateNewCursor(Thread &thread) { 181*972a253aSDimitry Andric if (Expected<DecodedThreadSP> decoded_thread = Decode(thread)) { 182*972a253aSDimitry Andric if (Expected<Optional<uint64_t>> beginning_of_time = 183*972a253aSDimitry Andric FindBeginningOfTimeNanos()) 184*972a253aSDimitry Andric return std::make_unique<TraceCursorIntelPT>( 185*972a253aSDimitry Andric thread.shared_from_this(), *decoded_thread, m_storage.tsc_conversion, 186*972a253aSDimitry Andric *beginning_of_time); 18781ad6265SDimitry Andric else 188*972a253aSDimitry Andric return beginning_of_time.takeError(); 189*972a253aSDimitry Andric } else 19081ad6265SDimitry Andric return decoded_thread.takeError(); 191e8d8bef9SDimitry Andric } 192e8d8bef9SDimitry Andric 193753f127fSDimitry Andric void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose, 194753f127fSDimitry Andric bool json) { 19581ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 19681ad6265SDimitry Andric 19781ad6265SDimitry Andric lldb::tid_t tid = thread.GetID(); 198753f127fSDimitry Andric if (json) { 199753f127fSDimitry Andric DumpTraceInfoAsJson(thread, s, verbose); 200753f127fSDimitry Andric return; 201753f127fSDimitry Andric } 202753f127fSDimitry Andric 20381ad6265SDimitry Andric s.Format("\nthread #{0}: tid = {1}", thread.GetIndexID(), thread.GetID()); 20481ad6265SDimitry Andric if (!IsTraced(tid)) { 20581ad6265SDimitry Andric s << ", not traced\n"; 206e8d8bef9SDimitry Andric return; 207fe6060f1SDimitry Andric } 20881ad6265SDimitry Andric s << "\n"; 20981ad6265SDimitry Andric 21081ad6265SDimitry Andric Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread); 21181ad6265SDimitry Andric if (!decoded_thread_sp_or_err) { 21281ad6265SDimitry Andric s << toString(decoded_thread_sp_or_err.takeError()) << "\n"; 213fe6060f1SDimitry Andric return; 214e8d8bef9SDimitry Andric } 215e8d8bef9SDimitry Andric 21681ad6265SDimitry Andric DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err; 21781ad6265SDimitry Andric 21881ad6265SDimitry Andric Expected<Optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread); 21981ad6265SDimitry Andric if (!raw_size_or_error) { 22081ad6265SDimitry Andric s.Format(" {0}\n", toString(raw_size_or_error.takeError())); 22181ad6265SDimitry Andric return; 22281ad6265SDimitry Andric } 22381ad6265SDimitry Andric Optional<uint64_t> raw_size = *raw_size_or_error; 22481ad6265SDimitry Andric 225753f127fSDimitry Andric s.Format("\n Trace technology: {0}\n", GetPluginName()); 226753f127fSDimitry Andric 22781ad6265SDimitry Andric /// Instruction stats 22881ad6265SDimitry Andric { 22981ad6265SDimitry Andric uint64_t items_count = decoded_thread_sp->GetItemsCount(); 23081ad6265SDimitry Andric uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage(); 23181ad6265SDimitry Andric 232753f127fSDimitry Andric s.Format("\n Total number of trace items: {0}\n", items_count); 23381ad6265SDimitry Andric 23481ad6265SDimitry Andric s << "\n Memory usage:\n"; 23581ad6265SDimitry Andric if (raw_size) 23681ad6265SDimitry Andric s.Format(" Raw trace size: {0} KiB\n", *raw_size / 1024); 23781ad6265SDimitry Andric 23881ad6265SDimitry Andric s.Format( 23981ad6265SDimitry Andric " Total approximate memory usage (excluding raw trace): {0:2} KiB\n", 24081ad6265SDimitry Andric (double)mem_used / 1024); 24181ad6265SDimitry Andric if (items_count != 0) 24281ad6265SDimitry Andric s.Format(" Average memory usage per item (excluding raw trace): " 24381ad6265SDimitry Andric "{0:2} bytes\n", 24481ad6265SDimitry Andric (double)mem_used / items_count); 24581ad6265SDimitry Andric } 24681ad6265SDimitry Andric 24781ad6265SDimitry Andric // Timing 24881ad6265SDimitry Andric { 24981ad6265SDimitry Andric s << "\n Timing for this thread:\n"; 25081ad6265SDimitry Andric auto print_duration = [&](const std::string &name, 25181ad6265SDimitry Andric std::chrono::milliseconds duration) { 25281ad6265SDimitry Andric s.Format(" {0}: {1:2}s\n", name, duration.count() / 1000.0); 25381ad6265SDimitry Andric }; 254753f127fSDimitry Andric GetThreadTimer(tid).ForEachTimedTask(print_duration); 25581ad6265SDimitry Andric 25681ad6265SDimitry Andric s << "\n Timing for global tasks:\n"; 257753f127fSDimitry Andric GetGlobalTimer().ForEachTimedTask(print_duration); 25881ad6265SDimitry Andric } 25981ad6265SDimitry Andric 26081ad6265SDimitry Andric // Instruction events stats 26181ad6265SDimitry Andric { 26281ad6265SDimitry Andric const DecodedThread::EventsStats &events_stats = 26381ad6265SDimitry Andric decoded_thread_sp->GetEventsStats(); 26481ad6265SDimitry Andric s << "\n Events:\n"; 26581ad6265SDimitry Andric s.Format(" Number of individual events: {0}\n", 26681ad6265SDimitry Andric events_stats.total_count); 26781ad6265SDimitry Andric for (const auto &event_to_count : events_stats.events_counts) { 26881ad6265SDimitry Andric s.Format(" {0}: {1}\n", 26981ad6265SDimitry Andric TraceCursor::EventKindToString(event_to_count.first), 27081ad6265SDimitry Andric event_to_count.second); 27181ad6265SDimitry Andric } 27281ad6265SDimitry Andric } 27381ad6265SDimitry Andric 27481ad6265SDimitry Andric if (storage.multicpu_decoder) { 27581ad6265SDimitry Andric s << "\n Multi-cpu decoding:\n"; 27681ad6265SDimitry Andric s.Format(" Total number of continuous executions found: {0}\n", 27781ad6265SDimitry Andric storage.multicpu_decoder->GetTotalContinuousExecutionsCount()); 27881ad6265SDimitry Andric s.Format( 27981ad6265SDimitry Andric " Number of continuous executions for this thread: {0}\n", 28081ad6265SDimitry Andric storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid)); 281753f127fSDimitry Andric s.Format(" Total number of PSB blocks found: {0}\n", 282753f127fSDimitry Andric storage.multicpu_decoder->GetTotalPSBBlocksCount()); 283753f127fSDimitry Andric s.Format(" Number of PSB blocks for this thread: {0}\n", 284753f127fSDimitry Andric storage.multicpu_decoder->GePSBBlocksCountForThread(tid)); 285753f127fSDimitry Andric s.Format(" Total number of unattributed PSB blocks found: {0}\n", 286753f127fSDimitry Andric storage.multicpu_decoder->GetUnattributedPSBBlocksCount()); 28781ad6265SDimitry Andric } 28881ad6265SDimitry Andric 28981ad6265SDimitry Andric // Errors 29081ad6265SDimitry Andric { 29181ad6265SDimitry Andric s << "\n Errors:\n"; 29281ad6265SDimitry Andric const DecodedThread::LibiptErrorsStats &tsc_errors_stats = 29381ad6265SDimitry Andric decoded_thread_sp->GetTscErrorsStats(); 29481ad6265SDimitry Andric s.Format(" Number of TSC decoding errors: {0}\n", 29581ad6265SDimitry Andric tsc_errors_stats.total_count); 29681ad6265SDimitry Andric for (const auto &error_message_to_count : 29781ad6265SDimitry Andric tsc_errors_stats.libipt_errors_counts) { 29881ad6265SDimitry Andric s.Format(" {0}: {1}\n", error_message_to_count.first, 29981ad6265SDimitry Andric error_message_to_count.second); 30081ad6265SDimitry Andric } 30181ad6265SDimitry Andric } 30281ad6265SDimitry Andric } 30381ad6265SDimitry Andric 304753f127fSDimitry Andric void TraceIntelPT::DumpTraceInfoAsJson(Thread &thread, Stream &s, 305753f127fSDimitry Andric bool verbose) { 306753f127fSDimitry Andric Storage &storage = GetUpdatedStorage(); 307753f127fSDimitry Andric 308753f127fSDimitry Andric lldb::tid_t tid = thread.GetID(); 309753f127fSDimitry Andric json::OStream json_str(s.AsRawOstream(), 2); 310753f127fSDimitry Andric if (!IsTraced(tid)) { 311753f127fSDimitry Andric s << "error: thread not traced\n"; 312753f127fSDimitry Andric return; 313753f127fSDimitry Andric } 314753f127fSDimitry Andric 315753f127fSDimitry Andric Expected<Optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread); 316753f127fSDimitry Andric if (!raw_size_or_error) { 317753f127fSDimitry Andric s << "error: " << toString(raw_size_or_error.takeError()) << "\n"; 318753f127fSDimitry Andric return; 319753f127fSDimitry Andric } 320753f127fSDimitry Andric 321753f127fSDimitry Andric Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread); 322753f127fSDimitry Andric if (!decoded_thread_sp_or_err) { 323753f127fSDimitry Andric s << "error: " << toString(decoded_thread_sp_or_err.takeError()) << "\n"; 324753f127fSDimitry Andric return; 325753f127fSDimitry Andric } 326753f127fSDimitry Andric DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err; 327753f127fSDimitry Andric 328753f127fSDimitry Andric json_str.object([&] { 329753f127fSDimitry Andric json_str.attribute("traceTechnology", "intel-pt"); 330753f127fSDimitry Andric json_str.attributeObject("threadStats", [&] { 331753f127fSDimitry Andric json_str.attribute("tid", tid); 332753f127fSDimitry Andric 333753f127fSDimitry Andric uint64_t insn_len = decoded_thread_sp->GetItemsCount(); 334753f127fSDimitry Andric json_str.attribute("traceItemsCount", insn_len); 335753f127fSDimitry Andric 336753f127fSDimitry Andric // Instruction stats 337753f127fSDimitry Andric uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage(); 338753f127fSDimitry Andric json_str.attributeObject("memoryUsage", [&] { 339753f127fSDimitry Andric json_str.attribute("totalInBytes", std::to_string(mem_used)); 340753f127fSDimitry Andric Optional<double> avg; 341753f127fSDimitry Andric if (insn_len != 0) 342753f127fSDimitry Andric avg = double(mem_used) / insn_len; 343753f127fSDimitry Andric json_str.attribute("avgPerItemInBytes", avg); 344753f127fSDimitry Andric }); 345753f127fSDimitry Andric 346753f127fSDimitry Andric // Timing 347753f127fSDimitry Andric json_str.attributeObject("timingInSeconds", [&] { 348753f127fSDimitry Andric GetTimer().ForThread(tid).ForEachTimedTask( 349753f127fSDimitry Andric [&](const std::string &name, std::chrono::milliseconds duration) { 350753f127fSDimitry Andric json_str.attribute(name, duration.count() / 1000.0); 351753f127fSDimitry Andric }); 352753f127fSDimitry Andric }); 353753f127fSDimitry Andric 354753f127fSDimitry Andric // Instruction events stats 355753f127fSDimitry Andric const DecodedThread::EventsStats &events_stats = 356753f127fSDimitry Andric decoded_thread_sp->GetEventsStats(); 357753f127fSDimitry Andric json_str.attributeObject("events", [&] { 358753f127fSDimitry Andric json_str.attribute("totalCount", events_stats.total_count); 359753f127fSDimitry Andric json_str.attributeObject("individualCounts", [&] { 360753f127fSDimitry Andric for (const auto &event_to_count : events_stats.events_counts) { 361753f127fSDimitry Andric json_str.attribute( 362753f127fSDimitry Andric TraceCursor::EventKindToString(event_to_count.first), 363753f127fSDimitry Andric event_to_count.second); 364753f127fSDimitry Andric } 365753f127fSDimitry Andric }); 366753f127fSDimitry Andric }); 367753f127fSDimitry Andric 368753f127fSDimitry Andric if (storage.multicpu_decoder) { 369753f127fSDimitry Andric json_str.attribute( 370753f127fSDimitry Andric "continuousExecutions", 371753f127fSDimitry Andric storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid)); 372753f127fSDimitry Andric json_str.attribute( 373753f127fSDimitry Andric "PSBBlocks", 374753f127fSDimitry Andric storage.multicpu_decoder->GePSBBlocksCountForThread(tid)); 375753f127fSDimitry Andric } 376753f127fSDimitry Andric 377753f127fSDimitry Andric // Errors 378753f127fSDimitry Andric const DecodedThread::LibiptErrorsStats &tsc_errors_stats = 379753f127fSDimitry Andric decoded_thread_sp->GetTscErrorsStats(); 380753f127fSDimitry Andric json_str.attributeObject("errorItems", [&] { 381753f127fSDimitry Andric json_str.attribute("total", tsc_errors_stats.total_count); 382753f127fSDimitry Andric json_str.attributeObject("individualErrors", [&] { 383753f127fSDimitry Andric for (const auto &error_message_to_count : 384753f127fSDimitry Andric tsc_errors_stats.libipt_errors_counts) { 385753f127fSDimitry Andric json_str.attribute(error_message_to_count.first, 386753f127fSDimitry Andric error_message_to_count.second); 387753f127fSDimitry Andric } 388753f127fSDimitry Andric }); 389753f127fSDimitry Andric }); 390753f127fSDimitry Andric }); 391753f127fSDimitry Andric json_str.attributeObject("globalStats", [&] { 392753f127fSDimitry Andric json_str.attributeObject("timingInSeconds", [&] { 393753f127fSDimitry Andric GetTimer().ForGlobal().ForEachTimedTask( 394753f127fSDimitry Andric [&](const std::string &name, std::chrono::milliseconds duration) { 395753f127fSDimitry Andric json_str.attribute(name, duration.count() / 1000.0); 396753f127fSDimitry Andric }); 397753f127fSDimitry Andric }); 398753f127fSDimitry Andric if (storage.multicpu_decoder) { 399753f127fSDimitry Andric json_str.attribute( 400753f127fSDimitry Andric "totalUnattributedPSBBlocks", 401753f127fSDimitry Andric storage.multicpu_decoder->GetUnattributedPSBBlocksCount()); 402753f127fSDimitry Andric json_str.attribute( 403753f127fSDimitry Andric "totalCountinuosExecutions", 404753f127fSDimitry Andric storage.multicpu_decoder->GetTotalContinuousExecutionsCount()); 405753f127fSDimitry Andric json_str.attribute("totalPSBBlocks", 406753f127fSDimitry Andric storage.multicpu_decoder->GetTotalPSBBlocksCount()); 407753f127fSDimitry Andric json_str.attribute( 408753f127fSDimitry Andric "totalContinuousExecutions", 409753f127fSDimitry Andric storage.multicpu_decoder->GetTotalContinuousExecutionsCount()); 410753f127fSDimitry Andric } 411753f127fSDimitry Andric }); 412753f127fSDimitry Andric }); 413753f127fSDimitry Andric } 414753f127fSDimitry Andric 41581ad6265SDimitry Andric llvm::Expected<Optional<uint64_t>> 41681ad6265SDimitry Andric TraceIntelPT::GetRawTraceSize(Thread &thread) { 41781ad6265SDimitry Andric if (GetUpdatedStorage().multicpu_decoder) 41881ad6265SDimitry Andric return None; // TODO: calculate the amount of intel pt raw trace associated 41981ad6265SDimitry Andric // with the given thread. 42081ad6265SDimitry Andric if (GetLiveProcess()) 42181ad6265SDimitry Andric return GetLiveThreadBinaryDataSize(thread.GetID(), 42281ad6265SDimitry Andric IntelPTDataKinds::kIptTrace); 42381ad6265SDimitry Andric uint64_t size; 42481ad6265SDimitry Andric auto callback = [&](llvm::ArrayRef<uint8_t> data) { 42581ad6265SDimitry Andric size = data.size(); 42681ad6265SDimitry Andric return Error::success(); 42781ad6265SDimitry Andric }; 42881ad6265SDimitry Andric if (Error err = OnThreadBufferRead(thread.GetID(), callback)) 42981ad6265SDimitry Andric return std::move(err); 43081ad6265SDimitry Andric 43181ad6265SDimitry Andric return size; 432fe6060f1SDimitry Andric } 433fe6060f1SDimitry Andric 434fe6060f1SDimitry Andric Expected<pt_cpu> TraceIntelPT::GetCPUInfoForLiveProcess() { 43581ad6265SDimitry Andric Expected<std::vector<uint8_t>> cpu_info = 43681ad6265SDimitry Andric GetLiveProcessBinaryData(IntelPTDataKinds::kProcFsCpuInfo); 437fe6060f1SDimitry Andric if (!cpu_info) 438fe6060f1SDimitry Andric return cpu_info.takeError(); 439fe6060f1SDimitry Andric 440fe6060f1SDimitry Andric int64_t cpu_family = -1; 441fe6060f1SDimitry Andric int64_t model = -1; 442fe6060f1SDimitry Andric int64_t stepping = -1; 443fe6060f1SDimitry Andric std::string vendor_id; 444fe6060f1SDimitry Andric 445fe6060f1SDimitry Andric StringRef rest(reinterpret_cast<const char *>(cpu_info->data()), 446fe6060f1SDimitry Andric cpu_info->size()); 447fe6060f1SDimitry Andric while (!rest.empty()) { 448fe6060f1SDimitry Andric StringRef line; 449fe6060f1SDimitry Andric std::tie(line, rest) = rest.split('\n'); 450fe6060f1SDimitry Andric 451fe6060f1SDimitry Andric SmallVector<StringRef, 2> columns; 452fe6060f1SDimitry Andric line.split(columns, StringRef(":"), -1, false); 453fe6060f1SDimitry Andric 454fe6060f1SDimitry Andric if (columns.size() < 2) 455fe6060f1SDimitry Andric continue; // continue searching 456fe6060f1SDimitry Andric 457fe6060f1SDimitry Andric columns[1] = columns[1].trim(" "); 458fe6060f1SDimitry Andric if (columns[0].contains("cpu family") && 459fe6060f1SDimitry Andric columns[1].getAsInteger(10, cpu_family)) 460fe6060f1SDimitry Andric continue; 461fe6060f1SDimitry Andric 462fe6060f1SDimitry Andric else if (columns[0].contains("model") && columns[1].getAsInteger(10, model)) 463fe6060f1SDimitry Andric continue; 464fe6060f1SDimitry Andric 465fe6060f1SDimitry Andric else if (columns[0].contains("stepping") && 466fe6060f1SDimitry Andric columns[1].getAsInteger(10, stepping)) 467fe6060f1SDimitry Andric continue; 468fe6060f1SDimitry Andric 469fe6060f1SDimitry Andric else if (columns[0].contains("vendor_id")) { 470fe6060f1SDimitry Andric vendor_id = columns[1].str(); 471fe6060f1SDimitry Andric if (!vendor_id.empty()) 472fe6060f1SDimitry Andric continue; 473fe6060f1SDimitry Andric } 474fe6060f1SDimitry Andric 475fe6060f1SDimitry Andric if ((cpu_family != -1) && (model != -1) && (stepping != -1) && 476fe6060f1SDimitry Andric (!vendor_id.empty())) { 477fe6060f1SDimitry Andric return pt_cpu{vendor_id == "GenuineIntel" ? pcv_intel : pcv_unknown, 478fe6060f1SDimitry Andric static_cast<uint16_t>(cpu_family), 479fe6060f1SDimitry Andric static_cast<uint8_t>(model), 480fe6060f1SDimitry Andric static_cast<uint8_t>(stepping)}; 481fe6060f1SDimitry Andric } 482fe6060f1SDimitry Andric } 483fe6060f1SDimitry Andric return createStringError(inconvertibleErrorCode(), 484fe6060f1SDimitry Andric "Failed parsing the target's /proc/cpuinfo file"); 485fe6060f1SDimitry Andric } 486fe6060f1SDimitry Andric 487fe6060f1SDimitry Andric Expected<pt_cpu> TraceIntelPT::GetCPUInfo() { 488fe6060f1SDimitry Andric if (!m_cpu_info) { 489fe6060f1SDimitry Andric if (llvm::Expected<pt_cpu> cpu_info = GetCPUInfoForLiveProcess()) 490fe6060f1SDimitry Andric m_cpu_info = *cpu_info; 491fe6060f1SDimitry Andric else 492fe6060f1SDimitry Andric return cpu_info.takeError(); 493fe6060f1SDimitry Andric } 494fe6060f1SDimitry Andric return *m_cpu_info; 495fe6060f1SDimitry Andric } 496fe6060f1SDimitry Andric 49781ad6265SDimitry Andric llvm::Optional<LinuxPerfZeroTscConversion> 49881ad6265SDimitry Andric TraceIntelPT::GetPerfZeroTscConversion() { 49981ad6265SDimitry Andric return GetUpdatedStorage().tsc_conversion; 500fe6060f1SDimitry Andric } 501fe6060f1SDimitry Andric 50281ad6265SDimitry Andric TraceIntelPT::Storage &TraceIntelPT::GetUpdatedStorage() { 50381ad6265SDimitry Andric RefreshLiveProcessState(); 50481ad6265SDimitry Andric return m_storage; 505fe6060f1SDimitry Andric } 50681ad6265SDimitry Andric 50781ad6265SDimitry Andric Error TraceIntelPT::DoRefreshLiveProcessState(TraceGetStateResponse state, 50881ad6265SDimitry Andric StringRef json_response) { 50981ad6265SDimitry Andric m_storage = Storage(); 51081ad6265SDimitry Andric 51181ad6265SDimitry Andric Expected<TraceIntelPTGetStateResponse> intelpt_state = 51281ad6265SDimitry Andric json::parse<TraceIntelPTGetStateResponse>(json_response, 51381ad6265SDimitry Andric "TraceIntelPTGetStateResponse"); 51481ad6265SDimitry Andric if (!intelpt_state) 51581ad6265SDimitry Andric return intelpt_state.takeError(); 51681ad6265SDimitry Andric 51781ad6265SDimitry Andric m_storage.tsc_conversion = intelpt_state->tsc_perf_zero_conversion; 51881ad6265SDimitry Andric 51981ad6265SDimitry Andric if (!intelpt_state->cpus) { 52081ad6265SDimitry Andric for (const TraceThreadState &thread_state : state.traced_threads) { 52181ad6265SDimitry Andric ThreadSP thread_sp = 52281ad6265SDimitry Andric GetLiveProcess()->GetThreadList().FindThreadByID(thread_state.tid); 52381ad6265SDimitry Andric m_storage.thread_decoders.try_emplace( 52481ad6265SDimitry Andric thread_state.tid, std::make_unique<ThreadDecoder>(thread_sp, *this)); 52581ad6265SDimitry Andric } 52681ad6265SDimitry Andric } else { 52781ad6265SDimitry Andric std::vector<cpu_id_t> cpus; 52881ad6265SDimitry Andric for (const TraceCpuState &cpu : *intelpt_state->cpus) 52981ad6265SDimitry Andric cpus.push_back(cpu.id); 53081ad6265SDimitry Andric 53181ad6265SDimitry Andric std::vector<tid_t> tids; 53281ad6265SDimitry Andric for (const TraceThreadState &thread : intelpt_state->traced_threads) 53381ad6265SDimitry Andric tids.push_back(thread.tid); 53481ad6265SDimitry Andric 53581ad6265SDimitry Andric if (!intelpt_state->tsc_perf_zero_conversion) 53681ad6265SDimitry Andric return createStringError(inconvertibleErrorCode(), 53781ad6265SDimitry Andric "Missing perf time_zero conversion values"); 53881ad6265SDimitry Andric m_storage.multicpu_decoder.emplace(GetSharedPtr()); 53981ad6265SDimitry Andric } 54081ad6265SDimitry Andric 54181ad6265SDimitry Andric if (m_storage.tsc_conversion) { 54281ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Target); 54381ad6265SDimitry Andric LLDB_LOG(log, "TraceIntelPT found TSC conversion information"); 54481ad6265SDimitry Andric } 54581ad6265SDimitry Andric return Error::success(); 546fe6060f1SDimitry Andric } 547fe6060f1SDimitry Andric 548349cc55cSDimitry Andric bool TraceIntelPT::IsTraced(lldb::tid_t tid) { 54981ad6265SDimitry Andric Storage &storage = GetUpdatedStorage(); 55081ad6265SDimitry Andric if (storage.multicpu_decoder) 55181ad6265SDimitry Andric return storage.multicpu_decoder->TracesThread(tid); 55281ad6265SDimitry Andric return storage.thread_decoders.count(tid); 553fe6060f1SDimitry Andric } 554fe6060f1SDimitry Andric 555fe6060f1SDimitry Andric // The information here should match the description of the intel-pt section 556fe6060f1SDimitry Andric // of the jLLDBTraceStart packet in the lldb/docs/lldb-gdb-remote.txt 557fe6060f1SDimitry Andric // documentation file. Similarly, it should match the CLI help messages of the 558fe6060f1SDimitry Andric // TraceIntelPTOptions.td file. 559fe6060f1SDimitry Andric const char *TraceIntelPT::GetStartConfigurationHelp() { 56081ad6265SDimitry Andric static Optional<std::string> message; 56181ad6265SDimitry Andric if (!message) { 56281ad6265SDimitry Andric message.emplace(formatv(R"(Parameters: 563fe6060f1SDimitry Andric 56481ad6265SDimitry Andric See the jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt for a 56581ad6265SDimitry Andric description of each parameter below. 566fe6060f1SDimitry Andric 56781ad6265SDimitry Andric - int iptTraceSize (defaults to {0} bytes): 568fe6060f1SDimitry Andric [process and thread tracing] 569fe6060f1SDimitry Andric 57081ad6265SDimitry Andric - boolean enableTsc (default to {1}): 571fe6060f1SDimitry Andric [process and thread tracing] 572fe6060f1SDimitry Andric 57381ad6265SDimitry Andric - int psbPeriod (defaults to {2}): 574fe6060f1SDimitry Andric [process and thread tracing] 575fe6060f1SDimitry Andric 57681ad6265SDimitry Andric - boolean perCpuTracing (default to {3}): 577fe6060f1SDimitry Andric [process tracing only] 57881ad6265SDimitry Andric 57981ad6265SDimitry Andric - int processBufferSizeLimit (defaults to {4} MiB): 580753f127fSDimitry Andric [process tracing only] 581753f127fSDimitry Andric 582753f127fSDimitry Andric - boolean disableCgroupFiltering (default to {5}): 58381ad6265SDimitry Andric [process tracing only])", 58481ad6265SDimitry Andric kDefaultIptTraceSize, kDefaultEnableTscValue, 58581ad6265SDimitry Andric kDefaultPsbPeriod, kDefaultPerCpuTracing, 586753f127fSDimitry Andric kDefaultProcessBufferSizeLimit / 1024 / 1024, 587753f127fSDimitry Andric kDefaultDisableCgroupFiltering)); 58881ad6265SDimitry Andric } 58981ad6265SDimitry Andric return message->c_str(); 590fe6060f1SDimitry Andric } 591fe6060f1SDimitry Andric 59281ad6265SDimitry Andric Error TraceIntelPT::Start(uint64_t ipt_trace_size, 59381ad6265SDimitry Andric uint64_t total_buffer_size_limit, bool enable_tsc, 594753f127fSDimitry Andric Optional<uint64_t> psb_period, bool per_cpu_tracing, 595753f127fSDimitry Andric bool disable_cgroup_filtering) { 596fe6060f1SDimitry Andric TraceIntelPTStartRequest request; 59781ad6265SDimitry Andric request.ipt_trace_size = ipt_trace_size; 59881ad6265SDimitry Andric request.process_buffer_size_limit = total_buffer_size_limit; 59981ad6265SDimitry Andric request.enable_tsc = enable_tsc; 60081ad6265SDimitry Andric request.psb_period = psb_period; 601349cc55cSDimitry Andric request.type = GetPluginName().str(); 60281ad6265SDimitry Andric request.per_cpu_tracing = per_cpu_tracing; 603753f127fSDimitry Andric request.disable_cgroup_filtering = disable_cgroup_filtering; 604fe6060f1SDimitry Andric return Trace::Start(toJSON(request)); 605fe6060f1SDimitry Andric } 606fe6060f1SDimitry Andric 607fe6060f1SDimitry Andric Error TraceIntelPT::Start(StructuredData::ObjectSP configuration) { 60881ad6265SDimitry Andric uint64_t ipt_trace_size = kDefaultIptTraceSize; 60981ad6265SDimitry Andric uint64_t process_buffer_size_limit = kDefaultProcessBufferSizeLimit; 610fe6060f1SDimitry Andric bool enable_tsc = kDefaultEnableTscValue; 61181ad6265SDimitry Andric Optional<uint64_t> psb_period = kDefaultPsbPeriod; 61281ad6265SDimitry Andric bool per_cpu_tracing = kDefaultPerCpuTracing; 613753f127fSDimitry Andric bool disable_cgroup_filtering = kDefaultDisableCgroupFiltering; 614fe6060f1SDimitry Andric 615fe6060f1SDimitry Andric if (configuration) { 616fe6060f1SDimitry Andric if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) { 61781ad6265SDimitry Andric dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size); 618fe6060f1SDimitry Andric dict->GetValueForKeyAsInteger("processBufferSizeLimit", 619fe6060f1SDimitry Andric process_buffer_size_limit); 620fe6060f1SDimitry Andric dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc); 621fe6060f1SDimitry Andric dict->GetValueForKeyAsInteger("psbPeriod", psb_period); 62281ad6265SDimitry Andric dict->GetValueForKeyAsBoolean("perCpuTracing", per_cpu_tracing); 623753f127fSDimitry Andric dict->GetValueForKeyAsBoolean("disableCgroupFiltering", 624753f127fSDimitry Andric disable_cgroup_filtering); 625fe6060f1SDimitry Andric } else { 626fe6060f1SDimitry Andric return createStringError(inconvertibleErrorCode(), 627fe6060f1SDimitry Andric "configuration object is not a dictionary"); 628fe6060f1SDimitry Andric } 629fe6060f1SDimitry Andric } 630fe6060f1SDimitry Andric 63181ad6265SDimitry Andric return Start(ipt_trace_size, process_buffer_size_limit, enable_tsc, 632753f127fSDimitry Andric psb_period, per_cpu_tracing, disable_cgroup_filtering); 633fe6060f1SDimitry Andric } 634fe6060f1SDimitry Andric 635fe6060f1SDimitry Andric llvm::Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids, 63681ad6265SDimitry Andric uint64_t ipt_trace_size, bool enable_tsc, 63781ad6265SDimitry Andric Optional<uint64_t> psb_period) { 638fe6060f1SDimitry Andric TraceIntelPTStartRequest request; 63981ad6265SDimitry Andric request.ipt_trace_size = ipt_trace_size; 64081ad6265SDimitry Andric request.enable_tsc = enable_tsc; 64181ad6265SDimitry Andric request.psb_period = psb_period; 642349cc55cSDimitry Andric request.type = GetPluginName().str(); 643fe6060f1SDimitry Andric request.tids.emplace(); 644fe6060f1SDimitry Andric for (lldb::tid_t tid : tids) 645fe6060f1SDimitry Andric request.tids->push_back(tid); 646fe6060f1SDimitry Andric return Trace::Start(toJSON(request)); 647fe6060f1SDimitry Andric } 648fe6060f1SDimitry Andric 649fe6060f1SDimitry Andric Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids, 650fe6060f1SDimitry Andric StructuredData::ObjectSP configuration) { 65181ad6265SDimitry Andric uint64_t ipt_trace_size = kDefaultIptTraceSize; 652fe6060f1SDimitry Andric bool enable_tsc = kDefaultEnableTscValue; 65381ad6265SDimitry Andric Optional<uint64_t> psb_period = kDefaultPsbPeriod; 654fe6060f1SDimitry Andric 655fe6060f1SDimitry Andric if (configuration) { 656fe6060f1SDimitry Andric if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) { 657753f127fSDimitry Andric llvm::StringRef ipt_trace_size_not_parsed; 658753f127fSDimitry Andric if (dict->GetValueForKeyAsString("iptTraceSize", 659753f127fSDimitry Andric ipt_trace_size_not_parsed)) { 660753f127fSDimitry Andric if (Optional<uint64_t> bytes = 661753f127fSDimitry Andric ParsingUtils::ParseUserFriendlySizeExpression( 662753f127fSDimitry Andric ipt_trace_size_not_parsed)) 663753f127fSDimitry Andric ipt_trace_size = *bytes; 664753f127fSDimitry Andric else 665753f127fSDimitry Andric return createStringError(inconvertibleErrorCode(), 666753f127fSDimitry Andric "iptTraceSize is wrong bytes expression"); 667753f127fSDimitry Andric } else { 66881ad6265SDimitry Andric dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size); 669753f127fSDimitry Andric } 670753f127fSDimitry Andric 671fe6060f1SDimitry Andric dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc); 672fe6060f1SDimitry Andric dict->GetValueForKeyAsInteger("psbPeriod", psb_period); 673fe6060f1SDimitry Andric } else { 674fe6060f1SDimitry Andric return createStringError(inconvertibleErrorCode(), 675fe6060f1SDimitry Andric "configuration object is not a dictionary"); 676fe6060f1SDimitry Andric } 677fe6060f1SDimitry Andric } 678fe6060f1SDimitry Andric 67981ad6265SDimitry Andric return Start(tids, ipt_trace_size, enable_tsc, psb_period); 680fe6060f1SDimitry Andric } 681fe6060f1SDimitry Andric 68281ad6265SDimitry Andric Error TraceIntelPT::OnThreadBufferRead(lldb::tid_t tid, 68381ad6265SDimitry Andric OnBinaryDataReadCallback callback) { 68481ad6265SDimitry Andric return OnThreadBinaryDataRead(tid, IntelPTDataKinds::kIptTrace, callback); 685e8d8bef9SDimitry Andric } 68681ad6265SDimitry Andric 68781ad6265SDimitry Andric TaskTimer &TraceIntelPT::GetTimer() { return GetUpdatedStorage().task_timer; } 688753f127fSDimitry Andric 689753f127fSDimitry Andric ScopedTaskTimer &TraceIntelPT::GetThreadTimer(lldb::tid_t tid) { 690753f127fSDimitry Andric return GetTimer().ForThread(tid); 691753f127fSDimitry Andric } 692753f127fSDimitry Andric 693753f127fSDimitry Andric ScopedTaskTimer &TraceIntelPT::GetGlobalTimer() { 694753f127fSDimitry Andric return GetTimer().ForGlobal(); 695753f127fSDimitry Andric } 696