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