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