• 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 <tuple>
27 #include <utility>
28 #include <vector>
29 
30 #include "perfetto/base/compiler.h"
31 #include "perfetto/base/export.h"
32 #include "perfetto/base/logging.h"
33 #include "perfetto/tracing/backend_type.h"
34 #include "perfetto/tracing/core/forward_decls.h"
35 #include "perfetto/tracing/internal/in_process_tracing_backend.h"
36 #include "perfetto/tracing/internal/system_tracing_backend.h"
37 #include "perfetto/tracing/tracing_policy.h"
38 
39 namespace perfetto {
40 
41 namespace internal {
42 class TracingMuxerImpl;
43 }
44 
45 class TracingBackend;
46 class Platform;
47 class StartupTracingSession;  // Declared below.
48 class TracingSession;         // Declared below.
49 
50 struct TracingError {
51   enum ErrorCode : uint32_t {
52     // Peer disconnection.
53     kDisconnected = 1,
54 
55     // The Start() method failed. This is typically because errors in the passed
56     // TraceConfig. More details are available in |message|.
57     kTracingFailed = 2,
58   };
59 
60   ErrorCode code;
61   std::string message;
62 
TracingErrorTracingError63   TracingError(ErrorCode cd, std::string msg)
64       : code(cd), message(std::move(msg)) {
65     PERFETTO_CHECK(!message.empty());
66   }
67 };
68 
69 using LogLev = ::perfetto::base::LogLev;
70 using LogMessageCallbackArgs = ::perfetto::base::LogMessageCallbackArgs;
71 using LogMessageCallback = ::perfetto::base::LogMessageCallback;
72 
73 struct TracingInitArgs {
74   uint32_t backends = 0;                     // One or more BackendTypes.
75   TracingBackend* custom_backend = nullptr;  // [Optional].
76 
77   // [Optional] Platform implementation. It allows the embedder to take control
78   // of platform-specific bits like thread creation and TLS slot handling. If
79   // not set it will use Platform::GetDefaultPlatform().
80   Platform* platform = nullptr;
81 
82   // [Optional] Tune the size of the shared memory buffer between the current
83   // process and the service backend(s). This is a trade-off between memory
84   // footprint and the ability to sustain bursts of trace writes (see comments
85   // in shared_memory_abi.h).
86   // If set, the value must be a multiple of 4KB. The value can be ignored if
87   // larger than kMaxShmSize (32MB) or not a multiple of 4KB.
88   uint32_t shmem_size_hint_kb = 0;
89 
90   // [Optional] Specifies the preferred size of each page in the shmem buffer.
91   // This is a trade-off between IPC overhead and fragmentation/efficiency of
92   // the shmem buffer in presence of multiple writer threads.
93   // Must be one of [4, 8, 16, 32].
94   uint32_t shmem_page_size_hint_kb = 0;
95 
96   // [Optional] The length of the period during which shared-memory-buffer
97   // chunks that have been filled with data are accumulated (batched) on the
98   // producer side, before the service is notified of them over an out-of-band
99   // IPC call. If, while this period lasts, the shared memory buffer gets too
100   // full, the IPC call will be sent immediately. The value of this parameter is
101   // a trade-off between IPC traffic overhead and the ability to sustain bursts
102   // of trace writes. The higher the value, the more chunks will be batched and
103   // the less buffer space will be available to hide the latency of the service,
104   // and vice versa. For more details, see the SetBatchCommitsDuration method in
105   // shared_memory_arbiter.h.
106   //
107   // Note: With the default value of 0ms, batching still happens but with a zero
108   // delay, i.e. commits will be sent to the service at the next opportunity.
109   uint32_t shmem_batch_commits_duration_ms = 0;
110 
111   // [Optional] If set, the policy object is notified when certain SDK events
112   // occur and may apply policy decisions, such as denying connections. The
113   // embedder is responsible for ensuring the object remains alive for the
114   // lifetime of the process.
115   TracingPolicy* tracing_policy = nullptr;
116 
117   // [Optional] If set, log messages generated by perfetto are passed to this
118   // callback instead of being logged directly.
119   LogMessageCallback log_message_callback = nullptr;
120 
121   // When this flag is set to false, it overrides
122   // `DataSource::kSupportsMultipleInstances` for all the data sources.
123   // As a result when a tracing session is already running and if we attempt to
124   // start another session, it will fail to start the data source which were
125   // already active.
126   bool supports_multiple_data_source_instances = true;
127 
128   // If this flag is set the default clock for taking timestamps is overridden
129   // with CLOCK_MONOTONIC (for use in Chrome).
130   bool use_monotonic_clock = false;
131 
132   // If this flag is set the default clock for taking timestamps is overridden
133   // with CLOCK_MONOTONIC_RAW on platforms that support it.
134   bool use_monotonic_raw_clock = false;
135 
136   // This flag can be set to false in order to avoid enabling the system
137   // consumer in Tracing::Initialize(), so that the linker can remove the unused
138   // consumer IPC implementation to reduce binary size. This setting only has an
139   // effect if kSystemBackend is specified in |backends|. When this option is
140   // false, Tracing::NewTrace() will instatiate the system backend only if
141   // explicitly specified as kSystemBackend: kUndefinedBackend will consider
142   // only already instantiated backends.
143   bool enable_system_consumer = true;
144 
145   // When true, sets disallow_merging_with_system_tracks in TrackDescriptor,
146   // making sure that Trace Processor doesn't merge track event and system
147   // event tracks for the same thread.
148   bool disallow_merging_with_system_tracks = false;
149 
150  protected:
151   friend class Tracing;
152   friend class internal::TracingMuxerImpl;
153 
154   using BackendFactoryFunction = TracingBackend* (*)();
155   using ProducerBackendFactoryFunction = TracingProducerBackend* (*)();
156   using ConsumerBackendFactoryFunction = TracingConsumerBackend* (*)();
157 
158   BackendFactoryFunction in_process_backend_factory_ = nullptr;
159   ProducerBackendFactoryFunction system_producer_backend_factory_ = nullptr;
160   ConsumerBackendFactoryFunction system_consumer_backend_factory_ = nullptr;
161   bool dcheck_is_on_ = PERFETTO_DCHECK_IS_ON();
162 };
163 
164 // The entry-point for using perfetto.
165 class PERFETTO_EXPORT_COMPONENT Tracing {
166  public:
167   // Initializes Perfetto with the given backends in the calling process and/or
168   // with a user-provided backend. It's possible to call this function more than
169   // once to initialize different backends. If a backend was already initialized
170   // the call will have no effect on it. All the members of `args` will be
171   // ignored in subsequent calls, except those require to initialize new
172   // backends (`backends`, `enable_system_consumer`, `shmem_size_hint_kb`,
173   // `shmem_page_size_hint_kb` and `shmem_batch_commits_duration_ms`).
Initialize(const TracingInitArgs & args)174   static inline void Initialize(const TracingInitArgs& args)
175       PERFETTO_ALWAYS_INLINE {
176     TracingInitArgs args_copy(args);
177     // This code is inlined to allow dead-code elimination for unused backends.
178     // This saves ~200 KB when not using the in-process backend (b/148198993).
179     // The logic behind it is the following:
180     // Nothing other than the code below references the two GetInstance()
181     // methods. From a linker-graph viewpoint, those GetInstance() pull in many
182     // other pieces of the codebase (e.g. InProcessTracingBackend pulls the
183     // whole TracingServiceImpl, SystemTracingBackend pulls the whole //ipc
184     // layer). Due to the inline, the compiler can see through the code and
185     // realize that some branches are always not taken. When that happens, no
186     // reference to the backends' GetInstance() is emitted and that allows the
187     // linker GC to get rid of the entire set of dependencies.
188     if (args.backends & kInProcessBackend) {
189       args_copy.in_process_backend_factory_ =
190           &internal::InProcessTracingBackend::GetInstance;
191     }
192     if (args.backends & kSystemBackend) {
193       args_copy.system_producer_backend_factory_ =
194           &internal::SystemProducerTracingBackend::GetInstance;
195       if (args.enable_system_consumer) {
196         args_copy.system_consumer_backend_factory_ =
197             &internal::SystemConsumerTracingBackend::GetInstance;
198       }
199     }
200     InitializeInternal(args_copy);
201   }
202 
203   // Checks if tracing has been initialized by calling |Initialize|.
204   static bool IsInitialized();
205 
206   // Start a new tracing session using the given tracing backend. Use
207   // |kUnspecifiedBackend| to select an available backend automatically.
208   static inline std::unique_ptr<TracingSession> NewTrace(
209       BackendType backend = kUnspecifiedBackend) PERFETTO_ALWAYS_INLINE {
210     // This code is inlined to allow dead-code elimination for unused consumer
211     // implementation. The logic behind it is the following:
212     // Nothing other than the code below references the GetInstance() method
213     // below. From a linker-graph viewpoint, those GetInstance() pull in many
214     // other pieces of the codebase (ConsumerOnlySystemTracingBackend pulls
215     // ConsumerIPCClient). Due to the inline, the compiler can see through the
216     // code and realize that some branches are always not taken. When that
217     // happens, no reference to the backends' GetInstance() is emitted and that
218     // allows the linker GC to get rid of the entire set of dependencies.
219     TracingConsumerBackend* (*system_backend_factory)();
220     system_backend_factory = nullptr;
221     // In case PERFETTO_IPC is disabled, a fake system backend is used, which
222     // always panics. NewTrace(kSystemBackend) should fail if PERFETTO_IPC is
223     // diabled, not panic.
224 #if PERFETTO_BUILDFLAG(PERFETTO_IPC)
225     if (backend & kSystemBackend) {
226       system_backend_factory =
227           &internal::SystemConsumerTracingBackend::GetInstance;
228     }
229 #endif
230     return NewTraceInternal(backend, system_backend_factory);
231   }
232 
233   // Shut down Perfetto, releasing any allocated OS resources (threads, files,
234   // sockets, etc.). Note that Perfetto cannot be reinitialized again in the
235   // same process[1]. Instead, this function is meant for shutting down all
236   // Perfetto-related code so that it can be safely unloaded, e.g., with
237   // dlclose().
238   //
239   // It is only safe to call this function when all threads recording trace
240   // events have been terminated or otherwise guaranteed to not make any further
241   // calls into Perfetto.
242   //
243   // [1] Unless static data is also cleared through other means.
244   static void Shutdown();
245 
246   // Uninitialize Perfetto. Only exposed for testing scenarios where it can be
247   // guaranteed that no tracing sessions or other operations are happening when
248   // this call is made.
249   static void ResetForTesting();
250 
251   // Start a new startup tracing session in the current process. Startup tracing
252   // can be used in anticipation of a session that will be started by the
253   // specified backend in the near future. The data source configs in the
254   // supplied TraceConfig have to (mostly) match those in the config that will
255   // later be provided by the backend.
256   // Learn more about config matching at ComputeStartupConfigHash.
257   //
258   // Note that startup tracing requires that either:
259   //  (a) the service backend already has an SMB set up, or
260   //  (b) the service backend to support producer-provided SMBs if the backend
261   //      is not yet connected or no SMB has been set up yet
262   //      (See `use_producer_provided_smb`). If necessary, the
263   //      client library will briefly disconnect and reconnect the backend to
264   //      supply an SMB to the backend. If the service does not accept the SMB,
265   //      startup tracing will be aborted, but the service may still start the
266   //      corresponding tracing session later.
267   //
268   // Startup tracing is NOT supported with the in-process backend. For this
269   // backend, you can just start a regular tracing session and block until it is
270   // set up instead.
271   //
272   // The client library will start the data sources instances specified in the
273   // config with a placeholder target buffer. Once the backend starts a matching
274   // tracing session, the session will resume as normal. If no matching session
275   // is started after a timeout (or the backend doesn't accept the
276   // producer-provided SMB), the startup tracing session will be aborted
277   // and the data source instances stopped.
278   struct OnStartupTracingSetupCallbackArgs {
279     int num_data_sources_started;
280   };
281   struct SetupStartupTracingOpts {
282     BackendType backend = kUnspecifiedBackend;
283     uint32_t timeout_ms = 10000;
284 
285     // If set, this callback is executed (on an internal Perfetto thread) when
286     // startup tracing was set up.
287     std::function<void(OnStartupTracingSetupCallbackArgs)> on_setup;
288 
289     // If set, this callback is executed (on an internal Perfetto thread) if any
290     // data sources were aborted, e.g. due to exceeding the timeout or as a
291     // response to Abort().
292     std::function<void()> on_aborted;
293 
294     // If set, this callback is executed (on an internal Perfetto thread) after
295     // all data sources were adopted by a tracing session initiated by the
296     // backend.
297     std::function<void()> on_adopted;
298   };
299 
300   static std::unique_ptr<StartupTracingSession> SetupStartupTracing(
301       const TraceConfig& config,
302       SetupStartupTracingOpts);
303 
304   // Blocking version of above method, so callers can ensure that tracing is
305   // active before proceeding with app startup. Calls into
306   // DataSource::Trace() or trace macros right after this method are written
307   // into the startup session.
308   static std::unique_ptr<StartupTracingSession> SetupStartupTracingBlocking(
309       const TraceConfig& config,
310       SetupStartupTracingOpts);
311 
312   // Informs the tracing services to activate any of these triggers if any
313   // tracing session was waiting for them.
314   //
315   // Sends the trigger signal to all the initialized backends that are currently
316   // connected and that connect in the next `ttl_ms` milliseconds (but
317   // returns immediately anyway).
318   static void ActivateTriggers(const std::vector<std::string>& triggers,
319                                uint32_t ttl_ms);
320 
321  private:
322   static void InitializeInternal(const TracingInitArgs&);
323   static std::unique_ptr<TracingSession> NewTraceInternal(
324       BackendType,
325       TracingConsumerBackend* (*system_backend_factory)());
326 
327   Tracing() = delete;
328 };
329 
330 class PERFETTO_EXPORT_COMPONENT TracingSession {
331  public:
332   virtual ~TracingSession();
333 
334   // Configure the session passing the trace config.
335   // If a writable file handle is given through |fd|, the trace will
336   // automatically written to that file. Otherwise you should call ReadTrace()
337   // to retrieve the trace data. This call does not take ownership of |fd|.
338   // TODO(primiano): add an error callback.
339   virtual void Setup(const TraceConfig&, int fd = -1) = 0;
340 
341   // Enable tracing asynchronously. Use SetOnStartCallback() to get a
342   // notification when the session has fully started.
343   virtual void Start() = 0;
344 
345   // Enable tracing and block until tracing has started. Note that if data
346   // sources are registered after this call was initiated, the call may return
347   // before the additional data sources have started. Also, if other producers
348   // (e.g., with system-wide tracing) have registered data sources without start
349   // notification support, this call may return before those data sources have
350   // started.
351   virtual void StartBlocking() = 0;
352 
353   // This callback will be invoked when all data sources have acknowledged that
354   // tracing has started. This callback will be invoked on an internal perfetto
355   // thread.
356   virtual void SetOnStartCallback(std::function<void()>) = 0;
357 
358   // This callback can be used to get a notification when some error occured
359   // (e.g., peer disconnection). Error type will be passed as an argument. This
360   // callback will be invoked on an internal perfetto thread.
361   virtual void SetOnErrorCallback(std::function<void(TracingError)>) = 0;
362 
363   // Issues a flush request, asking all data sources to ack the request, within
364   // the specified timeout. A "flush" is a fence to ensure visibility of data in
365   // the async tracing pipeline. It guarantees that all data written before the
366   // Flush() call will be visible in the trace buffer and hence by the
367   // ReadTrace() / ReadTraceBlocking() methods.
368   // Args:
369   //  callback: will be invoked on an internal perfetto thread when all data
370   //    sources have acked, or the timeout is reached. The bool argument
371   //    will be true if all data sources acked within the timeout, false if
372   //    the timeout was hit or some other error occurred (e.g. the tracing
373   //    session wasn't started or ended).
374   //  timeout_ms: how much time the service will wait for data source acks. If
375   //    0, the global timeout specified in the TraceConfig (flush_timeout_ms)
376   //    will be used. If flush_timeout_ms is also unspecified, a default value
377   //    of 5s will be used.
378   // Known issues:
379   //    Because flushing is still based on service-side scraping, the very last
380   //    trace packet for each data source thread will not be visible. Fixing
381   //    this requires either propagating the Flush() to the data sources or
382   //    changing the order of atomic operations in the service (b/162206162).
383   //    Until then, a workaround is to make sure to call
384   //    DataSource::Trace([](TraceContext ctx) { ctx.Flush(); }) just before
385   //    stopping, on each thread where DataSource::Trace has been previously
386   //    called.
387   virtual void Flush(std::function<void(bool)>, uint32_t timeout_ms = 0) = 0;
388 
389   // Blocking version of Flush(). Waits until all data sources have acked and
390   // returns the success/failure status.
391   bool FlushBlocking(uint32_t timeout_ms = 0);
392 
393   // Disable tracing asynchronously.
394   // Use SetOnStopCallback() to get a notification when the tracing session is
395   // fully stopped and all data sources have acked.
396   virtual void Stop() = 0;
397 
398   // Disable tracing and block until tracing has stopped.
399   virtual void StopBlocking() = 0;
400 
401   // This callback will be invoked when tracing is disabled.
402   // This can happen either when explicitly calling TracingSession.Stop() or
403   // when the trace reaches its |duration_ms| time limit.
404   // This callback will be invoked on an internal perfetto thread.
405   virtual void SetOnStopCallback(std::function<void()>) = 0;
406 
407   // Changes the TraceConfig for an active tracing session. The session must
408   // have been configured and started before. Note that the tracing service
409   // only supports changing a subset of TraceConfig fields,
410   // see ConsumerEndpoint::ChangeTraceConfig().
411   virtual void ChangeTraceConfig(const TraceConfig&) = 0;
412 
413   // Struct passed as argument to the callback passed to ReadTrace().
414   // [data, size] is guaranteed to contain 1 or more full trace packets, which
415   // can be decoded using trace.proto. No partial or truncated packets are
416   // exposed. If the trace is empty this returns a zero-sized nullptr with
417   // |has_more| == true to signal EOF.
418   // This callback will be invoked on an internal perfetto thread.
419   struct ReadTraceCallbackArgs {
420     const char* data = nullptr;
421     size_t size = 0;
422 
423     // When false, this will be the last invocation of the callback for this
424     // read cycle.
425     bool has_more = false;
426   };
427 
428   // Reads back the trace data (raw protobuf-encoded bytes) asynchronously.
429   // Can be called at any point during the trace, typically but not necessarily,
430   // after stopping. If this is called before the end of the trace (i.e. before
431   // Stop() / StopBlocking()), in almost all cases you need to call
432   // Flush() / FlushBlocking() before Read(). This is to guarantee that tracing
433   // data in-flight in the data sources is committed into the tracing buffers
434   // before reading them.
435   // Reading the trace data is a destructive operation w.r.t. contents of the
436   // trace buffer and is not idempotent.
437   // A single ReadTrace() call can yield >1 callback invocations, until
438   // |has_more| is false.
439   using ReadTraceCallback = std::function<void(ReadTraceCallbackArgs)>;
440   virtual void ReadTrace(ReadTraceCallback) = 0;
441 
442   // Synchronous version of ReadTrace(). It blocks the calling thread until all
443   // the trace contents are read. This is slow and inefficient (involves more
444   // copies) and is mainly intended for testing.
445   std::vector<char> ReadTraceBlocking();
446 
447   // Struct passed as an argument to the callback for GetTraceStats(). Contains
448   // statistics about the tracing session.
449   struct GetTraceStatsCallbackArgs {
450     // Whether or not querying statistics succeeded.
451     bool success = false;
452     // Serialized TraceStats protobuf message. To decode:
453     //
454     //   perfetto::protos::gen::TraceStats trace_stats;
455     //   trace_stats.ParseFromArray(args.trace_stats_data.data(),
456     //                              args.trace_stats_data.size());
457     //
458     std::vector<uint8_t> trace_stats_data;
459   };
460 
461   // Requests a snapshot of statistical data for this tracing session. Only one
462   // query may be active at a time. This callback will be invoked on an internal
463   // perfetto thread.
464   using GetTraceStatsCallback = std::function<void(GetTraceStatsCallbackArgs)>;
465   virtual void GetTraceStats(GetTraceStatsCallback) = 0;
466 
467   // Synchronous version of GetTraceStats() for convenience.
468   GetTraceStatsCallbackArgs GetTraceStatsBlocking();
469 
470   // Struct passed as an argument to the callback for QueryServiceState().
471   // Contains information about registered data sources.
472   struct QueryServiceStateCallbackArgs {
473     // Whether or not getting the service state succeeded.
474     bool success = false;
475     // Serialized TracingServiceState protobuf message. To decode:
476     //
477     //   perfetto::protos::gen::TracingServiceState state;
478     //   state.ParseFromArray(args.service_state_data.data(),
479     //                        args.service_state_data.size());
480     //
481     std::vector<uint8_t> service_state_data;
482   };
483 
484   // Requests a snapshot of the tracing service state for this session. Only one
485   // request per session may be active at a time. This callback will be invoked
486   // on an internal perfetto thread.
487   using QueryServiceStateCallback =
488       std::function<void(QueryServiceStateCallbackArgs)>;
489   virtual void QueryServiceState(QueryServiceStateCallback) = 0;
490 
491   // Synchronous version of QueryServiceState() for convenience.
492   QueryServiceStateCallbackArgs QueryServiceStateBlocking();
493 };
494 
495 class PERFETTO_EXPORT_COMPONENT StartupTracingSession {
496  public:
497   // Note that destroying the StartupTracingSession object will not abort the
498   // startup session automatically. Call Abort() explicitly to do so.
499   virtual ~StartupTracingSession();
500 
501   // Abort any active but still unbound data source instances that belong to
502   // this startup tracing session. Does not affect data source instances that
503   // were already bound to a service-controlled session.
504   virtual void Abort() = 0;
505 
506   // Same as above, but blocks the current thread until aborted.
507   // Note some of the internal (non observable from public APIs) cleanup might
508   // be done even after this method returns.
509   virtual void AbortBlocking() = 0;
510 };
511 
512 }  // namespace perfetto
513 
514 #endif  // INCLUDE_PERFETTO_TRACING_TRACING_H_
515