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