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