1 | //===-- TraceIntelPT.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_TRACEINTELPT_H |
10 | #define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPT_H |
11 | |
12 | #include "TaskTimer.h" |
13 | #include "ThreadDecoder.h" |
14 | #include "TraceIntelPTBundleLoader.h" |
15 | #include "TraceIntelPTMultiCpuDecoder.h" |
16 | #include "lldb/Utility/FileSpec.h" |
17 | #include "lldb/lldb-types.h" |
18 | #include "llvm/Support/raw_ostream.h" |
19 | #include <optional> |
20 | |
21 | namespace lldb_private { |
22 | namespace trace_intel_pt { |
23 | |
24 | class TraceIntelPT : public Trace { |
25 | public: |
26 | /// Properties to be used with the `settings` command. |
27 | class PluginProperties : public Properties { |
28 | public: |
29 | static llvm::StringRef GetSettingName(); |
30 | |
31 | PluginProperties(); |
32 | |
33 | ~PluginProperties() override = default; |
34 | |
35 | uint64_t GetInfiniteDecodingLoopVerificationThreshold(); |
36 | |
37 | uint64_t GetExtremelyLargeDecodingThreshold(); |
38 | }; |
39 | |
40 | /// Return the global properties for this trace plug-in. |
41 | static PluginProperties &GetGlobalProperties(); |
42 | |
43 | void Dump(Stream *s) const override; |
44 | |
45 | llvm::Expected<FileSpec> SaveToDisk(FileSpec directory, |
46 | bool compact) override; |
47 | |
48 | ~TraceIntelPT() override = default; |
49 | |
50 | /// PluginInterface protocol |
51 | /// \{ |
52 | llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } |
53 | |
54 | static void Initialize(); |
55 | |
56 | static void Terminate(); |
57 | |
58 | /// Create an instance of this class from a trace bundle. |
59 | /// |
60 | /// \param[in] trace_bundle_description |
61 | /// The description of the trace bundle. See \a Trace::FindPlugin. |
62 | /// |
63 | /// \param[in] bundle_dir |
64 | /// The path to the directory that contains the trace bundle. |
65 | /// |
66 | /// \param[in] debugger |
67 | /// The debugger instance where new Targets will be created as part of the |
68 | /// JSON data parsing. |
69 | /// |
70 | /// \return |
71 | /// A trace instance or an error in case of failures. |
72 | static llvm::Expected<lldb::TraceSP> CreateInstanceForTraceBundle( |
73 | const llvm::json::Value &trace_bundle_description, |
74 | llvm::StringRef bundle_dir, Debugger &debugger); |
75 | |
76 | static llvm::Expected<lldb::TraceSP> |
77 | CreateInstanceForLiveProcess(Process &process); |
78 | |
79 | static llvm::StringRef GetPluginNameStatic() { return "intel-pt" ; } |
80 | |
81 | static void DebuggerInitialize(Debugger &debugger); |
82 | /// \} |
83 | |
84 | lldb::CommandObjectSP |
85 | GetProcessTraceStartCommand(CommandInterpreter &interpreter) override; |
86 | |
87 | lldb::CommandObjectSP |
88 | GetThreadTraceStartCommand(CommandInterpreter &interpreter) override; |
89 | |
90 | llvm::StringRef GetSchema() override; |
91 | |
92 | llvm::Expected<lldb::TraceCursorSP> CreateNewCursor(Thread &thread) override; |
93 | |
94 | void DumpTraceInfo(Thread &thread, Stream &s, bool verbose, |
95 | bool json) override; |
96 | |
97 | llvm::Expected<std::optional<uint64_t>> GetRawTraceSize(Thread &thread); |
98 | |
99 | llvm::Error DoRefreshLiveProcessState(TraceGetStateResponse state, |
100 | llvm::StringRef json_response) override; |
101 | |
102 | bool IsTraced(lldb::tid_t tid) override; |
103 | |
104 | const char *GetStartConfigurationHelp() override; |
105 | |
106 | /// Start tracing a live process. |
107 | /// |
108 | /// More information on the parameters below can be found in the |
109 | /// jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt. |
110 | /// |
111 | /// \param[in] ipt_trace_size |
112 | /// Trace size per thread in bytes. |
113 | /// |
114 | /// \param[in] total_buffer_size_limit |
115 | /// Maximum total trace size per process in bytes. |
116 | /// |
117 | /// \param[in] enable_tsc |
118 | /// Whether to use enable TSC timestamps or not. |
119 | /// |
120 | /// \param[in] psb_period |
121 | /// This value defines the period in which PSB packets will be generated. |
122 | /// |
123 | /// \param[in] per_cpu_tracing |
124 | /// This value defines whether to have an intel pt trace buffer per thread |
125 | /// or per cpu core. |
126 | /// |
127 | /// \param[in] disable_cgroup_filtering |
128 | /// Disable the cgroup filtering that is automatically applied when doing |
129 | /// per cpu tracing. |
130 | /// |
131 | /// \return |
132 | /// \a llvm::Error::success if the operation was successful, or |
133 | /// \a llvm::Error otherwise. |
134 | llvm::Error Start(uint64_t ipt_trace_size, uint64_t total_buffer_size_limit, |
135 | bool enable_tsc, std::optional<uint64_t> psb_period, |
136 | bool m_per_cpu_tracing, bool disable_cgroup_filtering); |
137 | |
138 | /// \copydoc Trace::Start |
139 | llvm::Error Start(StructuredData::ObjectSP configuration = |
140 | StructuredData::ObjectSP()) override; |
141 | |
142 | /// Start tracing live threads. |
143 | /// |
144 | /// More information on the parameters below can be found in the |
145 | /// jLLDBTraceStart section in lldb/docs/lldb-gdb-remote.txt. |
146 | /// |
147 | /// \param[in] tids |
148 | /// Threads to trace. |
149 | /// |
150 | /// \param[in] ipt_trace_size |
151 | /// Trace size per thread or per cpu core in bytes. |
152 | /// |
153 | /// \param[in] enable_tsc |
154 | /// Whether to use enable TSC timestamps or not. |
155 | /// |
156 | /// \param[in] psb_period |
157 | /// This value defines the period in which PSB packets will be generated. |
158 | /// |
159 | /// \return |
160 | /// \a llvm::Error::success if the operation was successful, or |
161 | /// \a llvm::Error otherwise. |
162 | llvm::Error Start(llvm::ArrayRef<lldb::tid_t> tids, uint64_t ipt_trace_size, |
163 | bool enable_tsc, std::optional<uint64_t> psb_period); |
164 | |
165 | /// \copydoc Trace::Start |
166 | llvm::Error Start(llvm::ArrayRef<lldb::tid_t> tids, |
167 | StructuredData::ObjectSP configuration = |
168 | StructuredData::ObjectSP()) override; |
169 | |
170 | /// See \a Trace::OnThreadBinaryDataRead(). |
171 | llvm::Error OnThreadBufferRead(lldb::tid_t tid, |
172 | OnBinaryDataReadCallback callback); |
173 | |
174 | /// Get or fetch the cpu information from, for example, /proc/cpuinfo. |
175 | llvm::Expected<pt_cpu> GetCPUInfo(); |
176 | |
177 | /// Get or fetch the values used to convert to and from TSCs and nanos. |
178 | std::optional<LinuxPerfZeroTscConversion> GetPerfZeroTscConversion(); |
179 | |
180 | /// \return |
181 | /// The timer object for this trace. |
182 | TaskTimer &GetTimer(); |
183 | |
184 | /// \return |
185 | /// The ScopedTaskTimer object for the given thread in this trace. |
186 | ScopedTaskTimer &GetThreadTimer(lldb::tid_t tid); |
187 | |
188 | /// \return |
189 | /// The global copedTaskTimer object for this trace. |
190 | ScopedTaskTimer &GetGlobalTimer(); |
191 | |
192 | TraceIntelPTSP GetSharedPtr(); |
193 | |
194 | enum class TraceMode { UserMode, KernelMode }; |
195 | |
196 | TraceMode GetTraceMode(); |
197 | |
198 | private: |
199 | friend class TraceIntelPTBundleLoader; |
200 | |
201 | llvm::Expected<pt_cpu> GetCPUInfoForLiveProcess(); |
202 | |
203 | /// Postmortem trace constructor |
204 | /// |
205 | /// \param[in] bundle_description |
206 | /// The definition file for the postmortem bundle. |
207 | /// |
208 | /// \param[in] traced_processes |
209 | /// The processes traced in the postmortem session. |
210 | /// |
211 | /// \param[in] trace_threads |
212 | /// The threads traced in the postmortem session. They must belong to the |
213 | /// processes mentioned above. |
214 | /// |
215 | /// \param[in] trace_mode |
216 | /// The tracing mode of the postmortem session. |
217 | /// |
218 | /// \return |
219 | /// A TraceIntelPT shared pointer instance. |
220 | /// \{ |
221 | static TraceIntelPTSP CreateInstanceForPostmortemTrace( |
222 | JSONTraceBundleDescription &bundle_description, |
223 | llvm::ArrayRef<lldb::ProcessSP> traced_processes, |
224 | llvm::ArrayRef<lldb::ThreadPostMortemTraceSP> traced_threads, |
225 | TraceMode trace_mode); |
226 | |
227 | /// This constructor is used by CreateInstanceForPostmortemTrace to get the |
228 | /// instance ready before using shared pointers, which is a limitation of C++. |
229 | TraceIntelPT(JSONTraceBundleDescription &bundle_description, |
230 | llvm::ArrayRef<lldb::ProcessSP> traced_processes, |
231 | TraceMode trace_mode); |
232 | /// \} |
233 | |
234 | /// Constructor for live processes |
235 | TraceIntelPT(Process &live_process) |
236 | : Trace(live_process), trace_mode(TraceMode::UserMode){}; |
237 | |
238 | /// Decode the trace of the given thread that, i.e. recontruct the traced |
239 | /// instructions. |
240 | /// |
241 | /// \param[in] thread |
242 | /// If \a thread is a \a ThreadTrace, then its internal trace file will be |
243 | /// decoded. Live threads are not currently supported. |
244 | /// |
245 | /// \return |
246 | /// A \a DecodedThread shared pointer with the decoded instructions. Any |
247 | /// errors are embedded in the instruction list. An \a llvm::Error is |
248 | /// returned if the decoder couldn't be properly set up. |
249 | llvm::Expected<DecodedThreadSP> Decode(Thread &thread); |
250 | |
251 | /// \return |
252 | /// The lowest timestamp in nanoseconds in all traces if available, \a |
253 | /// std::nullopt if all the traces were empty or no trace contained no |
254 | /// timing information, or an \a llvm::Error if it was not possible to set |
255 | /// up the decoder for some trace. |
256 | llvm::Expected<std::optional<uint64_t>> FindBeginningOfTimeNanos(); |
257 | |
258 | // Dump out trace info in JSON format |
259 | void DumpTraceInfoAsJson(Thread &thread, Stream &s, bool verbose); |
260 | |
261 | /// We package all the data that can change upon process stops to make sure |
262 | /// this contract is very visible. |
263 | /// This variable should only be accessed directly by constructores or live |
264 | /// process data refreshers. |
265 | struct Storage { |
266 | std::optional<TraceIntelPTMultiCpuDecoder> multicpu_decoder; |
267 | /// These decoders are used for the non-per-cpu case |
268 | llvm::DenseMap<lldb::tid_t, std::unique_ptr<ThreadDecoder>> thread_decoders; |
269 | /// Helper variable used to track long running operations for telemetry. |
270 | TaskTimer task_timer; |
271 | /// It is provided by either a trace bundle or a live process to convert TSC |
272 | /// counters to and from nanos. It might not be available on all hosts. |
273 | std::optional<LinuxPerfZeroTscConversion> tsc_conversion; |
274 | std::optional<uint64_t> beginning_of_time_nanos; |
275 | bool beginning_of_time_nanos_calculated = false; |
276 | } m_storage; |
277 | |
278 | /// It is provided by either a trace bundle or a live process' "cpuInfo" |
279 | /// binary data. We don't put it in the Storage because this variable doesn't |
280 | /// change. |
281 | std::optional<pt_cpu> m_cpu_info; |
282 | |
283 | /// Get the storage after refreshing the data in the case of a live process. |
284 | Storage &GetUpdatedStorage(); |
285 | |
286 | /// The tracing mode of post mortem trace. |
287 | TraceMode trace_mode; |
288 | }; |
289 | |
290 | } // namespace trace_intel_pt |
291 | } // namespace lldb_private |
292 | |
293 | #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPT_H |
294 | |