• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef INCLUDE_PERFETTO_TRACING_TRACING_H_
18 #define INCLUDE_PERFETTO_TRACING_TRACING_H_
19 
20 #include <stddef.h>
21 #include <stdint.h>
22 
23 #include <functional>
24 #include <memory>
25 #include <string>
26 #include <vector>
27 
28 #include "perfetto/base/compiler.h"
29 #include "perfetto/base/export.h"
30 #include "perfetto/base/logging.h"
31 #include "perfetto/tracing/backend_type.h"
32 #include "perfetto/tracing/core/forward_decls.h"
33 #include "perfetto/tracing/internal/in_process_tracing_backend.h"
34 #include "perfetto/tracing/internal/system_tracing_backend.h"
35 #include "perfetto/tracing/tracing_policy.h"
36 
37 namespace perfetto {
38 
39 namespace internal {
40 class TracingMuxerImpl;
41 }
42 
43 class TracingBackend;
44 class Platform;
45 class TracingSession;  // Declared below.
46 
47 struct TracingError {
48   enum ErrorCode : uint32_t {
49     // Peer disconnection.
50     kDisconnected = 1,
51 
52     // The Start() method failed. This is typically because errors in the passed
53     // TraceConfig. More details are available in |message|.
54     kTracingFailed = 2,
55   };
56 
57   ErrorCode code;
58   std::string message;
59 
TracingErrorTracingError60   TracingError(ErrorCode cd, std::string msg)
61       : code(cd), message(std::move(msg)) {
62     PERFETTO_CHECK(!message.empty());
63   }
64 };
65 
66 using LogLev = ::perfetto::base::LogLev;
67 using LogMessageCallbackArgs = ::perfetto::base::LogMessageCallbackArgs;
68 using LogMessageCallback = ::perfetto::base::LogMessageCallback;
69 
70 struct TracingInitArgs {
71   uint32_t backends = 0;                     // One or more BackendTypes.
72   TracingBackend* custom_backend = nullptr;  // [Optional].
73 
74   // [Optional] Platform implementation. It allows the embedder to take control
75   // of platform-specific bits like thread creation and TLS slot handling. If
76   // not set it will use Platform::GetDefaultPlatform().
77   Platform* platform = nullptr;
78 
79   // [Optional] Tune the size of the shared memory buffer between the current
80   // process and the service backend(s). This is a trade-off between memory
81   // footprint and the ability to sustain bursts of trace writes (see comments
82   // in shared_memory_abi.h).
83   // If set, the value must be a multiple of 4KB. The value can be ignored if
84   // larger than kMaxShmSize (32MB) or not a multiple of 4KB.
85   uint32_t shmem_size_hint_kb = 0;
86 
87   // [Optional] Specifies the preferred size of each page in the shmem buffer.
88   // This is a trade-off between IPC overhead and fragmentation/efficiency of
89   // the shmem buffer in presence of multiple writer threads.
90   // Must be one of [4, 8, 16, 32].
91   uint32_t shmem_page_size_hint_kb = 0;
92 
93   // [Optional] The length of the period during which shared-memory-buffer
94   // chunks that have been filled with data are accumulated (batched) on the
95   // producer side, before the service is notified of them over an out-of-band
96   // IPC call. If, while this period lasts, the shared memory buffer gets too
97   // full, the IPC call will be sent immediately. The value of this parameter is
98   // a trade-off between IPC traffic overhead and the ability to sustain bursts
99   // of trace writes. The higher the value, the more chunks will be batched and
100   // the less buffer space will be available to hide the latency of the service,
101   // and vice versa. For more details, see the SetBatchCommitsDuration method in
102   // shared_memory_arbiter.h.
103   //
104   // Note: With the default value of 0ms, batching still happens but with a zero
105   // delay, i.e. commits will be sent to the service at the next opportunity.
106   uint32_t shmem_batch_commits_duration_ms = 0;
107 
108   // [Optional] If set, the policy object is notified when certain SDK events
109   // occur and may apply policy decisions, such as denying connections. The
110   // embedder is responsible for ensuring the object remains alive for the
111   // lifetime of the process.
112   TracingPolicy* tracing_policy = nullptr;
113 
114   // [Optional] If set, log messages generated by perfetto are passed to this
115   // callback instead of being logged directly.
116   LogMessageCallback log_message_callback = nullptr;
117 
118  protected:
119   friend class Tracing;
120   friend class internal::TracingMuxerImpl;
121 
122   // Used only by the DCHECK in tracing.cc, to check that the config is the
123   // same in case of re-initialization.
124   bool operator==(const TracingInitArgs& other) const {
125     return std::tie(backends, custom_backend, platform, shmem_size_hint_kb,
126                     shmem_page_size_hint_kb, in_process_backend_factory_,
127                     system_backend_factory_, dcheck_is_on_) ==
128            std::tie(other.backends, other.custom_backend, other.platform,
129                     other.shmem_size_hint_kb, other.shmem_page_size_hint_kb,
130                     other.in_process_backend_factory_,
131                     other.system_backend_factory_, other.dcheck_is_on_);
132   }
133 
134   using BackendFactoryFunction = TracingBackend* (*)();
135   BackendFactoryFunction in_process_backend_factory_ = nullptr;
136   BackendFactoryFunction system_backend_factory_ = nullptr;
137   bool dcheck_is_on_ = PERFETTO_DCHECK_IS_ON();
138 };
139 
140 // The entry-point for using perfetto.
141 class PERFETTO_EXPORT Tracing {
142  public:
143   // Initializes Perfetto with the given backends in the calling process and/or
144   // with a user-provided backend. No-op if called more than once.
Initialize(const TracingInitArgs & args)145   static inline void Initialize(const TracingInitArgs& args)
146       PERFETTO_ALWAYS_INLINE {
147     TracingInitArgs args_copy(args);
148     // This code is inlined to allow dead-code elimination for unused backends.
149     // This saves ~200 KB when not using the in-process backend (b/148198993).
150     // The logic behind it is the following:
151     // Nothing other than the code below references the two GetInstance()
152     // methods. From a linker-graph viewpoint, those GetInstance() pull in many
153     // other pieces of the codebase (e.g. InProcessTracingBackend pulls the
154     // whole TracingServiceImpl, SystemTracingBackend pulls the whole //ipc
155     // layer). Due to the inline, the compiler can see through the code and
156     // realize that some branches are always not taken. When that happens, no
157     // reference to the backends' GetInstance() is emitted and that allows the
158     // linker GC to get rid of the entire set of dependencies.
159     if (args.backends & kInProcessBackend) {
160       args_copy.in_process_backend_factory_ =
161           &internal::InProcessTracingBackend::GetInstance;
162     }
163     if (args.backends & kSystemBackend) {
164       args_copy.system_backend_factory_ =
165           &internal::SystemTracingBackend::GetInstance;
166     }
167     InitializeInternal(args_copy);
168   }
169 
170   // Checks if tracing has been initialized by calling |Initialize|.
171   static bool IsInitialized();
172 
173   // Start a new tracing session using the given tracing backend. Use
174   // |kUnspecifiedBackend| to select an available backend automatically.
175   // For the moment this can be used only when initializing tracing in
176   // kInProcess mode. For the system mode use the 'bin/perfetto' cmdline client.
177   static std::unique_ptr<TracingSession> NewTrace(
178       BackendType = kUnspecifiedBackend);
179 
180   // Uninitialize Perfetto. Only exposed for testing scenarios where it can be
181   // guaranteed that no tracing sessions or other operations are happening when
182   // this call is made.
183   static void ResetForTesting();
184 
185  private:
186   static void InitializeInternal(const TracingInitArgs&);
187 
188   Tracing() = delete;
189 };
190 
191 class PERFETTO_EXPORT TracingSession {
192  public:
193   virtual ~TracingSession();
194 
195   // Configure the session passing the trace config.
196   // If a writable file handle is given through |fd|, the trace will
197   // automatically written to that file. Otherwise you should call ReadTrace()
198   // to retrieve the trace data. This call does not take ownership of |fd|.
199   // TODO(primiano): add an error callback.
200   virtual void Setup(const TraceConfig&, int fd = -1) = 0;
201 
202   // Enable tracing asynchronously. Use SetOnStartCallback() to get a
203   // notification when the session has fully started.
204   virtual void Start() = 0;
205 
206   // Enable tracing and block until tracing has started. Note that if data
207   // sources are registered after this call was initiated, the call may return
208   // before the additional data sources have started. Also, if other producers
209   // (e.g., with system-wide tracing) have registered data sources without start
210   // notification support, this call may return before those data sources have
211   // started.
212   virtual void StartBlocking() = 0;
213 
214   // This callback will be invoked when all data sources have acknowledged that
215   // tracing has started. This callback will be invoked on an internal perfetto
216   // thread.
217   virtual void SetOnStartCallback(std::function<void()>) = 0;
218 
219   // This callback can be used to get a notification when some error occured
220   // (e.g., peer disconnection). Error type will be passed as an argument. This
221   // callback will be invoked on an internal perfetto thread.
222   virtual void SetOnErrorCallback(std::function<void(TracingError)>) = 0;
223 
224   // Issues a flush request, asking all data sources to ack the request, within
225   // the specified timeout. A "flush" is a fence to ensure visibility of data in
226   // the async tracing pipeline. It guarantees that all data written before the
227   // Flush() call will be visible in the trace buffer and hence by the
228   // ReadTrace() / ReadTraceBlocking() methods.
229   // Args:
230   //  callback: will be invoked on an internal perfetto thread when all data
231   //    sources have acked, or the timeout is reached. The bool argument
232   //    will be true if all data sources acked within the timeout, false if
233   //    the timeout was hit or some other error occurred (e.g. the tracing
234   //    session wasn't started or ended).
235   //  timeout_ms: how much time the service will wait for data source acks. If
236   //    0, the global timeout specified in the TraceConfig (flush_timeout_ms)
237   //    will be used. If flush_timeout_ms is also unspecified, a default value
238   //    of 5s will be used.
239   // Known issues:
240   //    Because flushing is still based on service-side scraping, the very last
241   //    trace packet for each data source thread will not be visible. Fixing
242   //    this requires either propagating the Flush() to the data sources or
243   //    changing the order of atomic operations in the service (b/162206162).
244   //    Until then, a workaround is to make sure to call
245   //    DataSource::Trace([](TraceContext ctx) { ctx.Flush(); }) just before
246   //    stopping, on each thread where DataSource::Trace has been previously
247   //    called.
248   virtual void Flush(std::function<void(bool)>, uint32_t timeout_ms = 0) = 0;
249 
250   // Blocking version of Flush(). Waits until all data sources have acked and
251   // returns the success/failure status.
252   bool FlushBlocking(uint32_t timeout_ms = 0);
253 
254   // Disable tracing asynchronously.
255   // Use SetOnStopCallback() to get a notification when the tracing session is
256   // fully stopped and all data sources have acked.
257   virtual void Stop() = 0;
258 
259   // Disable tracing and block until tracing has stopped.
260   virtual void StopBlocking() = 0;
261 
262   // This callback will be invoked when tracing is disabled.
263   // This can happen either when explicitly calling TracingSession.Stop() or
264   // when the trace reaches its |duration_ms| time limit.
265   // This callback will be invoked on an internal perfetto thread.
266   virtual void SetOnStopCallback(std::function<void()>) = 0;
267 
268   // Changes the TraceConfig for an active tracing session. The session must
269   // have been configured and started before. Note that the tracing service
270   // only supports changing a subset of TraceConfig fields,
271   // see ConsumerEndpoint::ChangeTraceConfig().
272   virtual void ChangeTraceConfig(const TraceConfig&) = 0;
273 
274   // Struct passed as argument to the callback passed to ReadTrace().
275   // [data, size] is guaranteed to contain 1 or more full trace packets, which
276   // can be decoded using trace.proto. No partial or truncated packets are
277   // exposed. If the trace is empty this returns a zero-sized nullptr with
278   // |has_more| == true to signal EOF.
279   // This callback will be invoked on an internal perfetto thread.
280   struct ReadTraceCallbackArgs {
281     const char* data = nullptr;
282     size_t size = 0;
283 
284     // When false, this will be the last invocation of the callback for this
285     // read cycle.
286     bool has_more = false;
287   };
288 
289   // Reads back the trace data (raw protobuf-encoded bytes) asynchronously.
290   // Can be called at any point during the trace, typically but not necessarily,
291   // after stopping. If this is called before the end of the trace (i.e. before
292   // Stop() / StopBlocking()), in almost all cases you need to call
293   // Flush() / FlushBlocking() before Read(). This is to guarantee that tracing
294   // data in-flight in the data sources is committed into the tracing buffers
295   // before reading them.
296   // Reading the trace data is a destructive operation w.r.t. contents of the
297   // trace buffer and is not idempotent.
298   // A single ReadTrace() call can yield >1 callback invocations, until
299   // |has_more| is false.
300   using ReadTraceCallback = std::function<void(ReadTraceCallbackArgs)>;
301   virtual void ReadTrace(ReadTraceCallback) = 0;
302 
303   // Synchronous version of ReadTrace(). It blocks the calling thread until all
304   // the trace contents are read. This is slow and inefficient (involves more
305   // copies) and is mainly intended for testing.
306   std::vector<char> ReadTraceBlocking();
307 
308   // Struct passed as an argument to the callback for GetTraceStats(). Contains
309   // statistics about the tracing session.
310   struct GetTraceStatsCallbackArgs {
311     // Whether or not querying statistics succeeded.
312     bool success = false;
313     // Serialized TraceStats protobuf message. To decode:
314     //
315     //   perfetto::protos::gen::TraceStats trace_stats;
316     //   trace_stats.ParseFromArray(args.trace_stats_data.data(),
317     //                              args.trace_stats_data.size());
318     //
319     std::vector<uint8_t> trace_stats_data;
320   };
321 
322   // Requests a snapshot of statistical data for this tracing session. Only one
323   // query may be active at a time. This callback will be invoked on an internal
324   // perfetto thread.
325   using GetTraceStatsCallback = std::function<void(GetTraceStatsCallbackArgs)>;
326   virtual void GetTraceStats(GetTraceStatsCallback) = 0;
327 
328   // Synchronous version of GetTraceStats() for convenience.
329   GetTraceStatsCallbackArgs GetTraceStatsBlocking();
330 
331   // Struct passed as an argument to the callback for QueryServiceState().
332   // Contains information about registered data sources.
333   struct QueryServiceStateCallbackArgs {
334     // Whether or not getting the service state succeeded.
335     bool success = false;
336     // Serialized TracingServiceState protobuf message. To decode:
337     //
338     //   perfetto::protos::gen::TracingServiceState state;
339     //   state.ParseFromArray(args.service_state_data.data(),
340     //                        args.service_state_data.size());
341     //
342     std::vector<uint8_t> service_state_data;
343   };
344 
345   // Requests a snapshot of the tracing service state for this session. Only one
346   // request per session may be active at a time. This callback will be invoked
347   // on an internal perfetto thread.
348   using QueryServiceStateCallback =
349       std::function<void(QueryServiceStateCallbackArgs)>;
350   virtual void QueryServiceState(QueryServiceStateCallback) = 0;
351 
352   // Synchronous version of QueryServiceState() for convenience.
353   QueryServiceStateCallbackArgs QueryServiceStateBlocking();
354 };
355 
356 }  // namespace perfetto
357 
358 #endif  // INCLUDE_PERFETTO_TRACING_TRACING_H_
359