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/TraceIntelPTMultiCpuDecoder.cpp
39648 views
1
//===-- TraceIntelPTMultiCpuDecoder.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 "TraceIntelPTMultiCpuDecoder.h"
10
#include "TraceIntelPT.h"
11
#include "llvm/Support/Error.h"
12
#include <optional>
13
14
using namespace lldb;
15
using namespace lldb_private;
16
using namespace lldb_private::trace_intel_pt;
17
using namespace llvm;
18
19
TraceIntelPTMultiCpuDecoder::TraceIntelPTMultiCpuDecoder(
20
TraceIntelPTSP trace_sp)
21
: m_trace_wp(trace_sp) {
22
for (Process *proc : trace_sp->GetAllProcesses()) {
23
for (ThreadSP thread_sp : proc->GetThreadList().Threads()) {
24
m_tids.insert(thread_sp->GetID());
25
}
26
}
27
}
28
29
TraceIntelPTSP TraceIntelPTMultiCpuDecoder::GetTrace() {
30
return m_trace_wp.lock();
31
}
32
33
bool TraceIntelPTMultiCpuDecoder::TracesThread(lldb::tid_t tid) const {
34
return m_tids.count(tid);
35
}
36
37
Expected<std::optional<uint64_t>> TraceIntelPTMultiCpuDecoder::FindLowestTSC() {
38
std::optional<uint64_t> lowest_tsc;
39
TraceIntelPTSP trace_sp = GetTrace();
40
41
Error err = GetTrace()->OnAllCpusBinaryDataRead(
42
IntelPTDataKinds::kIptTrace,
43
[&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {
44
for (auto &cpu_id_to_buffer : buffers) {
45
Expected<std::optional<uint64_t>> tsc =
46
FindLowestTSCInTrace(*trace_sp, cpu_id_to_buffer.second);
47
if (!tsc)
48
return tsc.takeError();
49
if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc))
50
lowest_tsc = **tsc;
51
}
52
return Error::success();
53
});
54
if (err)
55
return std::move(err);
56
return lowest_tsc;
57
}
58
59
Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) {
60
if (Error err = CorrelateContextSwitchesAndIntelPtTraces())
61
return std::move(err);
62
63
TraceIntelPTSP trace_sp = GetTrace();
64
65
return trace_sp->GetThreadTimer(thread.GetID())
66
.TimeTask("Decoding instructions", [&]() -> Expected<DecodedThreadSP> {
67
auto it = m_decoded_threads.find(thread.GetID());
68
if (it != m_decoded_threads.end())
69
return it->second;
70
71
DecodedThreadSP decoded_thread_sp = std::make_shared<DecodedThread>(
72
thread.shared_from_this(), trace_sp->GetPerfZeroTscConversion());
73
74
Error err = trace_sp->OnAllCpusBinaryDataRead(
75
IntelPTDataKinds::kIptTrace,
76
[&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {
77
auto it =
78
m_continuous_executions_per_thread->find(thread.GetID());
79
if (it != m_continuous_executions_per_thread->end())
80
return DecodeSystemWideTraceForThread(
81
*decoded_thread_sp, *trace_sp, buffers, it->second);
82
83
return Error::success();
84
});
85
if (err)
86
return std::move(err);
87
88
m_decoded_threads.try_emplace(thread.GetID(), decoded_thread_sp);
89
return decoded_thread_sp;
90
});
91
}
92
93
static Expected<std::vector<PSBBlock>> GetPSBBlocksForCPU(TraceIntelPT &trace,
94
cpu_id_t cpu_id) {
95
std::vector<PSBBlock> psb_blocks;
96
Error err = trace.OnCpuBinaryDataRead(
97
cpu_id, IntelPTDataKinds::kIptTrace,
98
[&](ArrayRef<uint8_t> data) -> Error {
99
Expected<std::vector<PSBBlock>> split_trace =
100
SplitTraceIntoPSBBlock(trace, data, /*expect_tscs=*/true);
101
if (!split_trace)
102
return split_trace.takeError();
103
104
psb_blocks = std::move(*split_trace);
105
return Error::success();
106
});
107
if (err)
108
return std::move(err);
109
return psb_blocks;
110
}
111
112
Expected<DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>>
113
TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() {
114
DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>
115
continuous_executions_per_thread;
116
TraceIntelPTSP trace_sp = GetTrace();
117
118
std::optional<LinuxPerfZeroTscConversion> conv_opt =
119
trace_sp->GetPerfZeroTscConversion();
120
if (!conv_opt)
121
return createStringError(
122
inconvertibleErrorCode(),
123
"TSC to nanoseconds conversion values were not found");
124
125
LinuxPerfZeroTscConversion tsc_conversion = *conv_opt;
126
127
for (cpu_id_t cpu_id : trace_sp->GetTracedCpus()) {
128
Expected<std::vector<PSBBlock>> psb_blocks =
129
GetPSBBlocksForCPU(*trace_sp, cpu_id);
130
if (!psb_blocks)
131
return psb_blocks.takeError();
132
133
m_total_psb_blocks += psb_blocks->size();
134
// We'll be iterating through the thread continuous executions and the intel
135
// pt subtraces sorted by time.
136
auto it = psb_blocks->begin();
137
auto on_new_thread_execution =
138
[&](const ThreadContinuousExecution &thread_execution) {
139
IntelPTThreadContinousExecution execution(thread_execution);
140
141
for (; it != psb_blocks->end() &&
142
*it->tsc < thread_execution.GetEndTSC();
143
it++) {
144
if (*it->tsc > thread_execution.GetStartTSC()) {
145
execution.psb_blocks.push_back(*it);
146
} else {
147
m_unattributed_psb_blocks++;
148
}
149
}
150
continuous_executions_per_thread[thread_execution.tid].push_back(
151
execution);
152
};
153
Error err = trace_sp->OnCpuBinaryDataRead(
154
cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace,
155
[&](ArrayRef<uint8_t> data) -> Error {
156
Expected<std::vector<ThreadContinuousExecution>> executions =
157
DecodePerfContextSwitchTrace(data, cpu_id, tsc_conversion);
158
if (!executions)
159
return executions.takeError();
160
for (const ThreadContinuousExecution &exec : *executions)
161
on_new_thread_execution(exec);
162
return Error::success();
163
});
164
if (err)
165
return std::move(err);
166
167
m_unattributed_psb_blocks += psb_blocks->end() - it;
168
}
169
// We now sort the executions of each thread to have them ready for
170
// instruction decoding
171
for (auto &tid_executions : continuous_executions_per_thread)
172
std::sort(tid_executions.second.begin(), tid_executions.second.end());
173
174
return continuous_executions_per_thread;
175
}
176
177
Error TraceIntelPTMultiCpuDecoder::CorrelateContextSwitchesAndIntelPtTraces() {
178
if (m_setup_error)
179
return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());
180
181
if (m_continuous_executions_per_thread)
182
return Error::success();
183
184
Error err = GetTrace()->GetGlobalTimer().TimeTask(
185
"Context switch and Intel PT traces correlation", [&]() -> Error {
186
if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) {
187
m_continuous_executions_per_thread.emplace(std::move(*correlation));
188
return Error::success();
189
} else {
190
return correlation.takeError();
191
}
192
});
193
if (err) {
194
m_setup_error = toString(std::move(err));
195
return createStringError(inconvertibleErrorCode(), m_setup_error->c_str());
196
}
197
return Error::success();
198
}
199
200
size_t TraceIntelPTMultiCpuDecoder::GetNumContinuousExecutionsForThread(
201
lldb::tid_t tid) const {
202
if (!m_continuous_executions_per_thread)
203
return 0;
204
auto it = m_continuous_executions_per_thread->find(tid);
205
if (it == m_continuous_executions_per_thread->end())
206
return 0;
207
return it->second.size();
208
}
209
210
size_t TraceIntelPTMultiCpuDecoder::GetTotalContinuousExecutionsCount() const {
211
if (!m_continuous_executions_per_thread)
212
return 0;
213
size_t count = 0;
214
for (const auto &kv : *m_continuous_executions_per_thread)
215
count += kv.second.size();
216
return count;
217
}
218
219
size_t
220
TraceIntelPTMultiCpuDecoder::GePSBBlocksCountForThread(lldb::tid_t tid) const {
221
if (!m_continuous_executions_per_thread)
222
return 0;
223
size_t count = 0;
224
auto it = m_continuous_executions_per_thread->find(tid);
225
if (it == m_continuous_executions_per_thread->end())
226
return 0;
227
for (const IntelPTThreadContinousExecution &execution : it->second)
228
count += execution.psb_blocks.size();
229
return count;
230
}
231
232
size_t TraceIntelPTMultiCpuDecoder::GetUnattributedPSBBlocksCount() const {
233
return m_unattributed_psb_blocks;
234
}
235
236
size_t TraceIntelPTMultiCpuDecoder::GetTotalPSBBlocksCount() const {
237
return m_total_psb_blocks;
238
}
239
240