19#define PERF_RECORD_MISC_SWITCH_OUT (1 << 13)
21#define PERF_RECORD_LOST 2
22#define PERF_RECORD_THROTTLE 5
23#define PERF_RECORD_UNTHROTTLE 6
24#define PERF_RECORD_LOST_SAMPLES 13
25#define PERF_RECORD_SWITCH_CPU_WIDE 15
26#define PERF_RECORD_MAX 19
45 const uint64_t max_valid_size_bytes = 8000;
46 if (
size == 0 ||
size > max_valid_size_bytes)
47 return createStringError(
48 inconvertibleErrorCode(),
49 formatv(
"A record of {0} bytes was found.",
size));
54 return createStringError(
55 inconvertibleErrorCode(),
56 formatv(
"Invalid record type {0} was found.",
type));
57 return Error::success();
104 return tscs.complete.start;
106 return tscs.only_start.start;
108 return tscs.only_end.end;
110 return tscs.hinted_end.start;
112 return tscs.hinted_start.end;
119 return tscs.complete.start;
121 return tscs.only_start.start;
125 return tscs.hinted_end.start;
127 return tscs.hinted_start.hinted_start;
134 return tscs.complete.end;
136 return std::numeric_limits<uint64_t>::max();
138 return tscs.only_end.end;
140 return tscs.hinted_end.hinted_end;
142 return tscs.hinted_start.end;
158 uint64_t hinted_start, uint64_t end) {
168 uint64_t hinted_end) {
195 const std::optional<ContextSwitchRecord> &prev_record,
199 if (current_record.
IsOut()) {
201 cpu_id, current_record.
tid, current_record.
pid, current_record.
tsc));
204 return Error::success();
208 if (prev.
tsc >= current_record.
tsc)
209 return createStringError(
210 inconvertibleErrorCode(),
211 formatv(
"A context switch record doesn't happen after the previous "
212 "record. Previous TSC= {0}, current TSC = {1}.",
213 prev.
tsc, current_record.
tsc));
215 if (current_record.
IsIn() && prev.
IsIn()) {
219 cpu_id, prev.
tid, prev.
pid, prev.
tsc, current_record.
tsc - 1));
220 }
else if (current_record.
IsOut() && prev.
IsOut()) {
224 cpu_id, current_record.
tid, current_record.
pid, prev.
tsc + 1,
225 current_record.
tsc));
226 }
else if (current_record.
IsOut() && prev.
IsIn()) {
227 if (current_record.
pid == prev.
pid && current_record.
tid == prev.
tid) {
230 cpu_id, current_record.
tid, current_record.
pid, prev.
tsc,
231 current_record.
tsc));
236 cpu_id, prev.
tid, prev.
pid, prev.
tsc, current_record.
tsc - 1));
238 cpu_id, current_record.
tid, current_record.
pid, prev.
tsc + 1,
239 current_record.
tsc));
242 return Error::success();
245Expected<std::vector<ThreadContinuousExecution>>
247 ArrayRef<uint8_t> data,
cpu_id_t cpu_id,
250 std::vector<ThreadContinuousExecution> executions;
255 auto do_decode = [&]() ->
Error {
256 std::optional<ContextSwitchRecord> prev_record;
257 while (offset < data.size()) {
269 context_switch_record.
IsOut(),
274 cpu_id, tsc_conversion, record, prev_record,
276 executions.push_back(execution);
280 prev_record = record;
282 offset += perf_record.
size;
286 if (prev_record && prev_record->IsIn())
288 cpu_id, prev_record->tid, prev_record->pid, prev_record->tsc));
289 return Error::success();
292 if (
Error err = do_decode())
293 return createStringError(inconvertibleErrorCode(),
294 formatv(
"Malformed perf context switch trace for "
295 "cpu {0} at offset {1}. {2}",
296 cpu_id, offset,
toString(std::move(err))));
301Expected<std::vector<uint8_t>>
303 llvm::ArrayRef<uint8_t> data,
const std::set<lldb::pid_t> &pids) {
305 std::vector<uint8_t> out_data;
307 while (offset < data.size()) {
311 return std::move(err);
312 bool should_copy =
false;
317 if (pids.count(context_switch_record.
pid))
324 for (
size_t i = 0; i < perf_record.
size; i++) {
325 out_data.push_back(data[offset + i]);
329 offset += perf_record.
size;
#define PERF_RECORD_MISC_SWITCH_OUT
Copied from <linux/perf_event.h> to avoid depending on perf_event.h on non-linux platforms.
#define PERF_RECORD_UNTHROTTLE
#define PERF_RECORD_LOST_SAMPLES
static Error RecoverExecutionsFromConsecutiveRecords(cpu_id_t cpu_id, const LinuxPerfZeroTscConversion &tsc_conversion, const ContextSwitchRecord ¤t_record, const std::optional< ContextSwitchRecord > &prev_record, std::function< void(const ThreadContinuousExecution &execution)> on_new_execution)
#define PERF_RECORD_THROTTLE
#define PERF_RECORD_SWITCH_CPU_WIDE
llvm::Expected< std::vector< uint8_t > > FilterProcessesFromContextSwitchTrace(llvm::ArrayRef< uint8_t > data, const std::set< lldb::pid_t > &pids)
llvm::Expected< std::vector< ThreadContinuousExecution > > DecodePerfContextSwitchTrace(llvm::ArrayRef< uint8_t > data, lldb::cpu_id_t cpu_id, const LinuxPerfZeroTscConversion &tsc_conversion)
Decodes a context switch trace collected with perf_event_open.
A class that represents a running process on the host machine.
const char * toString(AppleArm64ExceptionClass EC)
Record produced after parsing the raw context switch trace produce by perf_event.
bool is_out
Whether the switch is in or out.
lldb::pid_t pid
pid = 0 and tid = 0 indicate the swapper or idle process, which normally runs after a context switch ...
Record found in the perf_event context switch traces.
struct perf_event_header header
jLLDBTraceGetState gdb-remote packet
uint64_t ToTSC(uint64_t nanos) const
This class indicates the time interval in which a thread was running continuously on a cpu core.
struct lldb_private::trace_intel_pt::ThreadContinuousExecution::@165::@167 only_start
struct lldb_private::trace_intel_pt::ThreadContinuousExecution::@165::@166 complete
uint64_t GetStartTSC() const
static ThreadContinuousExecution CreateHintedEndExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid, lldb::pid_t pid, uint64_t start, uint64_t hinted_end)
uint64_t GetEndTSC() const
uint64_t GetLowestKnownTSC() const
static ThreadContinuousExecution CreateOnlyStartExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid, lldb::pid_t pid, uint64_t start)
struct lldb_private::trace_intel_pt::ThreadContinuousExecution::@165::@168 only_end
enum lldb_private::trace_intel_pt::ThreadContinuousExecution::Variant variant
@ OnlyEnd
We only know the end. This might be the first entry or a cpu trace.
@ HintedEnd
The start is known and we have an upper bound for the end, i.e.
@ HintedStart
The end is known and we have a lower bound for the start, i.e.
@ Complete
Both endpoints are known.
@ OnlyStart
We only know the start. This might be the last entry of a cpu trace.
static ThreadContinuousExecution CreateCompleteExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid, lldb::pid_t pid, uint64_t start, uint64_t end)
Constructors for the different variants of this object.
union lldb_private::trace_intel_pt::ThreadContinuousExecution::@165 tscs
static ThreadContinuousExecution CreateHintedStartExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid, lldb::pid_t pid, uint64_t hinted_start, uint64_t end)
static ThreadContinuousExecution CreateOnlyEndExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid, lldb::pid_t pid, uint64_t end)