• 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/core/forward_decls.h"
32 #include "perfetto/tracing/internal/in_process_tracing_backend.h"
33 #include "perfetto/tracing/internal/system_tracing_backend.h"
34 
35 namespace perfetto {
36 
37 namespace internal {
38 class TracingMuxerImpl;
39 }
40 
41 class TracingBackend;
42 class Platform;
43 class TracingSession;  // Declared below.
44 
45 enum BackendType : uint32_t {
46   kUnspecifiedBackend = 0,
47 
48   // Connects to a previously-initialized perfetto tracing backend for
49   // in-process. If the in-process backend has not been previously initialized
50   // it will do so and create the tracing service on a dedicated thread.
51   kInProcessBackend = 1 << 0,
52 
53   // Connects to the system tracing service (e.g. on Linux/Android/Mac uses a
54   // named UNIX socket).
55   kSystemBackend = 1 << 1,
56 
57   // Used to provide a custom IPC transport to connect to the service.
58   // TracingInitArgs::custom_backend must be non-null and point to an
59   // indefinitely lived instance.
60   kCustomBackend = 1 << 2,
61 };
62 
63 struct TracingInitArgs {
64   uint32_t backends = 0;                     // One or more BackendFlags.
65   TracingBackend* custom_backend = nullptr;  // [Optional].
66 
67   // [Optional] Platform implementation. It allows the embedder to take control
68   // of platform-specific bits like thread creation and TLS slot handling. If
69   // not set it will use Platform::GetDefaultPlatform().
70   Platform* platform = nullptr;
71 
72   // [Optional] Tune the size of the shared memory buffer between the current
73   // process and the service backend(s). This is a trade-off between memory
74   // footprint and the ability to sustain bursts of trace writes (see comments
75   // in shared_memory_abi.h).
76   // If set, the value must be a multiple of 4KB. The value can be ignored if
77   // larger than kMaxShmSize (32MB) or not a multiple of 4KB.
78   uint32_t shmem_size_hint_kb = 0;
79 
80   // [Optional] Specifies the preferred size of each page in the shmem buffer.
81   // This is a trade-off between IPC overhead and fragmentation/efficiency of
82   // the shmem buffer in presence of multiple writer threads.
83   // Must be one of [4, 8, 16, 32].
84   uint32_t shmem_page_size_hint_kb = 0;
85 
86  protected:
87   friend class Tracing;
88   friend class internal::TracingMuxerImpl;
89 
90   // Used only by the DCHECK in tracing.cc, to check that the config is the
91   // same in case of re-initialization.
92   bool operator==(const TracingInitArgs& other) const {
93     return std::tie(backends, custom_backend, platform, shmem_size_hint_kb,
94                     shmem_page_size_hint_kb, in_process_backend_factory_,
95                     system_backend_factory_, dcheck_is_on_) ==
96            std::tie(other.backends, other.custom_backend, other.platform,
97                     other.shmem_size_hint_kb, other.shmem_page_size_hint_kb,
98                     other.in_process_backend_factory_,
99                     other.system_backend_factory_, other.dcheck_is_on_);
100   }
101 
102   using BackendFactoryFunction = TracingBackend* (*)();
103   BackendFactoryFunction in_process_backend_factory_ = nullptr;
104   BackendFactoryFunction system_backend_factory_ = nullptr;
105   bool dcheck_is_on_ = PERFETTO_DCHECK_IS_ON();
106 };
107 
108 // The entry-point for using perfetto.
109 class PERFETTO_EXPORT Tracing {
110  public:
111   // Initializes Perfetto with the given backends in the calling process and/or
112   // with a user-provided backend. No-op if called more than once.
Initialize(const TracingInitArgs & args)113   static inline void Initialize(const TracingInitArgs& args)
114       PERFETTO_ALWAYS_INLINE {
115     TracingInitArgs args_copy(args);
116     // This code is inlined to allow dead-code elimination for unused backends.
117     // This saves ~200 KB when not using the in-process backend (b/148198993).
118     // The logic behind it is the following:
119     // Nothing other than the code below references the two GetInstance()
120     // methods. From a linker-graph viewpoint, those GetInstance() pull in many
121     // other pieces of the codebase (e.g. InProcessTracingBackend pulls the
122     // whole TracingServiceImpl, SystemTracingBackend pulls the whole //ipc
123     // layer). Due to the inline, the compiler can see through the code and
124     // realize that some branches are always not taken. When that happens, no
125     // reference to the backends' GetInstance() is emitted and that allows the
126     // linker GC to get rid of the entire set of dependencies.
127     if (args.backends & kInProcessBackend) {
128       args_copy.in_process_backend_factory_ =
129           &internal::InProcessTracingBackend::GetInstance;
130     }
131     if (args.backends & kSystemBackend) {
132       args_copy.system_backend_factory_ =
133           &internal::SystemTracingBackend::GetInstance;
134     }
135     InitializeInternal(args_copy);
136   }
137 
138   // Start a new tracing session using the given tracing backend. Use
139   // |kUnspecifiedBackend| to select an available backend automatically.
140   // For the moment this can be used only when initializing tracing in
141   // kInProcess mode. For the system mode use the 'bin/perfetto' cmdline client.
142   static std::unique_ptr<TracingSession> NewTrace(
143       BackendType = kUnspecifiedBackend);
144 
145  private:
146   static void InitializeInternal(const TracingInitArgs&);
147 
148   Tracing() = delete;
149 };
150 
151 class PERFETTO_EXPORT TracingSession {
152  public:
153   virtual ~TracingSession();
154 
155   // Configure the session passing the trace config.
156   // If a writable file handle is given through |fd|, the trace will
157   // automatically written to that file. Otherwise you should call ReadTrace()
158   // to retrieve the trace data. This call does not take ownership of |fd|.
159   // TODO(primiano): add an error callback.
160   virtual void Setup(const TraceConfig&, int fd = -1) = 0;
161 
162   // Enable tracing asynchronously.
163   virtual void Start() = 0;
164 
165   // Enable tracing and block until tracing has started. Note that if data
166   // sources are registered after this call was initiated, the call may return
167   // before the additional data sources have started. Also, if other producers
168   // (e.g., with system-wide tracing) have registered data sources without start
169   // notification support, this call may return before those data sources have
170   // started.
171   virtual void StartBlocking() = 0;
172 
173   // Disable tracing asynchronously.
174   // Use SetOnStopCallback() to get a notification when the tracing session is
175   // fully stopped and all data sources have acked.
176   virtual void Stop() = 0;
177 
178   // Disable tracing and block until tracing has stopped.
179   virtual void StopBlocking() = 0;
180 
181   // This callback will be invoked when tracing is disabled.
182   // This can happen either when explicitly calling TracingSession.Stop() or
183   // when the trace reaches its |duration_ms| time limit.
184   // This callback will be invoked on an internal perfetto thread.
185   virtual void SetOnStopCallback(std::function<void()>) = 0;
186 
187   // Struct passed as argument to the callback passed to ReadTrace().
188   // [data, size] is guaranteed to contain 1 or more full trace packets, which
189   // can be decoded using trace.proto. No partial or truncated packets are
190   // exposed. If the trace is empty this returns a zero-sized nullptr with
191   // |has_more| == true to signal EOF.
192   // This callback will be invoked on an internal perfetto thread.
193   struct ReadTraceCallbackArgs {
194     const char* data = nullptr;
195     size_t size = 0;
196 
197     // When false, this will be the last invocation of the callback for this
198     // read cycle.
199     bool has_more = false;
200   };
201 
202   // Reads back the trace data (raw protobuf-encoded bytes) asynchronously.
203   // Can be called at any point during the trace, typically but not necessarily,
204   // after stopping. Reading the trace data is a destructive operation w.r.t.
205   // contents of the trace buffer and is not idempotent.
206   // A single ReadTrace() call can yield >1 callback invocations, until
207   // |has_more| is false.
208   using ReadTraceCallback = std::function<void(ReadTraceCallbackArgs)>;
209   virtual void ReadTrace(ReadTraceCallback) = 0;
210 
211   // Synchronous version of ReadTrace(). It blocks the calling thread until all
212   // the trace contents are read. This is slow and inefficient (involves more
213   // copies) and is mainly intended for testing.
214   std::vector<char> ReadTraceBlocking();
215 };
216 
217 }  // namespace perfetto
218 
219 #endif  // INCLUDE_PERFETTO_TRACING_TRACING_H_
220