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