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