1 //===-- PerfContextSwitchDecoder.h --======----------------------*- C++ -*-===// 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 #ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_PERFCONTEXTSWITCHDECODER_H 10 #define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_PERFCONTEXTSWITCHDECODER_H 11 12 #include "lldb/Utility/TraceIntelPTGDBRemotePackets.h" 13 #include "lldb/lldb-types.h" 14 15 #include "llvm/Support/Error.h" 16 17 #include <set> 18 #include <vector> 19 20 namespace lldb_private { 21 namespace trace_intel_pt { 22 23 /// This class indicates the time interval in which a thread was running 24 /// continuously on a cpu core. 25 struct ThreadContinuousExecution { 26 27 /// In most cases both the start and end of a continuous execution can be 28 /// accurately recovered from the context switch trace, but in some cases one 29 /// of these endpoints might be guessed or not known at all, due to contention 30 /// problems in the trace or because tracing was interrupted, e.g. with ioctl 31 /// calls, which causes gaps in the trace. Because of that, we identify which 32 /// situation we fall into with the following variants. 33 enum class Variant { 34 /// Both endpoints are known. 35 Complete, 36 /// The end is known and we have a lower bound for the start, i.e. the 37 /// previous execution in the same cpu happens strictly before the hinted 38 /// start. 39 HintedStart, 40 /// The start is known and we have an upper bound for the end, i.e. the next 41 /// execution in the same cpu happens strictly after the hinted end. 42 HintedEnd, 43 /// We only know the start. This might be the last entry of a cpu trace. 44 OnlyStart, 45 /// We only know the end. This might be the first entry or a cpu trace. 46 OnlyEnd, 47 } variant; 48 49 /// \return 50 /// The lowest tsc that we are sure of, i.e. not hinted. 51 uint64_t GetLowestKnownTSC() const; 52 53 /// \return 54 /// The known or hinted start tsc, or 0 if the variant is \a OnlyEnd. 55 uint64_t GetStartTSC() const; 56 57 /// \return 58 /// The known or hinted end tsc, or max \a uint64_t if the variant is \a 59 /// OnlyStart. 60 uint64_t GetEndTSC() const; 61 62 /// Constructors for the different variants of this object 63 /// 64 /// \{ 65 static ThreadContinuousExecution 66 CreateCompleteExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid, 67 lldb::pid_t pid, uint64_t start, uint64_t end); 68 69 static ThreadContinuousExecution 70 CreateHintedStartExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid, 71 lldb::pid_t pid, uint64_t hinted_start, 72 uint64_t end); 73 74 static ThreadContinuousExecution 75 CreateHintedEndExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid, 76 lldb::pid_t pid, uint64_t start, 77 uint64_t hinted_end); 78 79 static ThreadContinuousExecution CreateOnlyEndExecution(lldb::cpu_id_t cpu_id, 80 lldb::tid_t tid, 81 lldb::pid_t pid, 82 uint64_t end); 83 84 static ThreadContinuousExecution 85 CreateOnlyStartExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid, 86 lldb::pid_t pid, uint64_t start); 87 /// \} 88 89 union { 90 struct { 91 uint64_t start; 92 uint64_t end; 93 } complete; 94 struct { 95 uint64_t start; 96 } only_start; 97 struct { 98 uint64_t end; 99 } only_end; 100 /// The following 'hinted' structures are useful when there are contention 101 /// problems in the trace 102 struct { 103 uint64_t hinted_start; 104 uint64_t end; 105 } hinted_start; 106 struct { 107 uint64_t start; 108 uint64_t hinted_end; 109 } hinted_end; 110 } tscs; 111 112 lldb::cpu_id_t cpu_id; 113 lldb::tid_t tid; 114 lldb::pid_t pid; 115 116 private: 117 /// We keep this constructor private to force the usage of the static named 118 /// constructors. 119 ThreadContinuousExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid, 120 lldb::pid_t pid) 121 : cpu_id(cpu_id), tid(tid), pid(pid) {} 122 }; 123 124 /// Decodes a context switch trace collected with perf_event_open. 125 /// 126 /// \param[in] data 127 /// The context switch trace in binary format. 128 /// 129 /// \param[i] cpu_id 130 /// The cpu_id where the trace were gotten from. 131 /// 132 /// \param[in] tsc_conversion 133 /// The conversion values used to confert nanoseconds to TSC. 134 /// 135 /// \return 136 /// A list of continuous executions recovered from the raw trace sorted by 137 /// time, or an \a llvm::Error if the data is malformed. 138 llvm::Expected<std::vector<ThreadContinuousExecution>> 139 DecodePerfContextSwitchTrace(llvm::ArrayRef<uint8_t> data, 140 lldb::cpu_id_t cpu_id, 141 const LinuxPerfZeroTscConversion &tsc_conversion); 142 143 llvm::Expected<std::vector<uint8_t>> 144 FilterProcessesFromContextSwitchTrace(llvm::ArrayRef<uint8_t> data, 145 const std::set<lldb::pid_t> &pids); 146 147 } // namespace trace_intel_pt 148 } // namespace lldb_private 149 150 #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_PERFCONTEXTSWITCHDECODER_H 151