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 private: 181 static void InitializeInternal(const TracingInitArgs&); 182 183 Tracing() = delete; 184 }; 185 186 class PERFETTO_EXPORT TracingSession { 187 public: 188 virtual ~TracingSession(); 189 190 // Configure the session passing the trace config. 191 // If a writable file handle is given through |fd|, the trace will 192 // automatically written to that file. Otherwise you should call ReadTrace() 193 // to retrieve the trace data. This call does not take ownership of |fd|. 194 // TODO(primiano): add an error callback. 195 virtual void Setup(const TraceConfig&, int fd = -1) = 0; 196 197 // Enable tracing asynchronously. Use SetOnStartCallback() to get a 198 // notification when the session has fully started. 199 virtual void Start() = 0; 200 201 // Enable tracing and block until tracing has started. Note that if data 202 // sources are registered after this call was initiated, the call may return 203 // before the additional data sources have started. Also, if other producers 204 // (e.g., with system-wide tracing) have registered data sources without start 205 // notification support, this call may return before those data sources have 206 // started. 207 virtual void StartBlocking() = 0; 208 209 // This callback will be invoked when all data sources have acknowledged that 210 // tracing has started. This callback will be invoked on an internal perfetto 211 // thread. 212 virtual void SetOnStartCallback(std::function<void()>) = 0; 213 214 // This callback can be used to get a notification when some error occured 215 // (e.g., peer disconnection). Error type will be passed as an argument. This 216 // callback will be invoked on an internal perfetto thread. 217 virtual void SetOnErrorCallback(std::function<void(TracingError)>) = 0; 218 219 // Issues a flush request, asking all data sources to ack the request, within 220 // the specified timeout. A "flush" is a fence to ensure visibility of data in 221 // the async tracing pipeline. It guarantees that all data written before the 222 // Flush() call will be visible in the trace buffer and hence by the 223 // ReadTrace() / ReadTraceBlocking() methods. 224 // Args: 225 // callback: will be invoked on an internal perfetto thread when all data 226 // sources have acked, or the timeout is reached. The bool argument 227 // will be true if all data sources acked within the timeout, false if 228 // the timeout was hit or some other error occurred (e.g. the tracing 229 // session wasn't started or ended). 230 // timeout_ms: how much time the service will wait for data source acks. If 231 // 0, the global timeout specified in the TraceConfig (flush_timeout_ms) 232 // will be used. If flush_timeout_ms is also unspecified, a default value 233 // of 5s will be used. 234 // Known issues: 235 // Because flushing is still based on service-side scraping, the very last 236 // trace packet for each data source thread will not be visible. Fixing 237 // this requires either propagating the Flush() to the data sources or 238 // changing the order of atomic operations in the service (b/162206162). 239 // Until then, a workaround is to make sure to call 240 // DataSource::Trace([](TraceContext ctx) { ctx.Flush(); }) just before 241 // stopping, on each thread where DataSource::Trace has been previously 242 // called. 243 virtual void Flush(std::function<void(bool)>, uint32_t timeout_ms = 0) = 0; 244 245 // Blocking version of Flush(). Waits until all data sources have acked and 246 // returns the success/failure status. 247 bool FlushBlocking(uint32_t timeout_ms = 0); 248 249 // Disable tracing asynchronously. 250 // Use SetOnStopCallback() to get a notification when the tracing session is 251 // fully stopped and all data sources have acked. 252 virtual void Stop() = 0; 253 254 // Disable tracing and block until tracing has stopped. 255 virtual void StopBlocking() = 0; 256 257 // This callback will be invoked when tracing is disabled. 258 // This can happen either when explicitly calling TracingSession.Stop() or 259 // when the trace reaches its |duration_ms| time limit. 260 // This callback will be invoked on an internal perfetto thread. 261 virtual void SetOnStopCallback(std::function<void()>) = 0; 262 263 // Changes the TraceConfig for an active tracing session. The session must 264 // have been configured and started before. Note that the tracing service 265 // only supports changing a subset of TraceConfig fields, 266 // see ConsumerEndpoint::ChangeTraceConfig(). 267 virtual void ChangeTraceConfig(const TraceConfig&) = 0; 268 269 // Struct passed as argument to the callback passed to ReadTrace(). 270 // [data, size] is guaranteed to contain 1 or more full trace packets, which 271 // can be decoded using trace.proto. No partial or truncated packets are 272 // exposed. If the trace is empty this returns a zero-sized nullptr with 273 // |has_more| == true to signal EOF. 274 // This callback will be invoked on an internal perfetto thread. 275 struct ReadTraceCallbackArgs { 276 const char* data = nullptr; 277 size_t size = 0; 278 279 // When false, this will be the last invocation of the callback for this 280 // read cycle. 281 bool has_more = false; 282 }; 283 284 // Reads back the trace data (raw protobuf-encoded bytes) asynchronously. 285 // Can be called at any point during the trace, typically but not necessarily, 286 // after stopping. If this is called before the end of the trace (i.e. before 287 // Stop() / StopBlocking()), in almost all cases you need to call 288 // Flush() / FlushBlocking() before Read(). This is to guarantee that tracing 289 // data in-flight in the data sources is committed into the tracing buffers 290 // before reading them. 291 // Reading the trace data is a destructive operation w.r.t. contents of the 292 // trace buffer and is not idempotent. 293 // A single ReadTrace() call can yield >1 callback invocations, until 294 // |has_more| is false. 295 using ReadTraceCallback = std::function<void(ReadTraceCallbackArgs)>; 296 virtual void ReadTrace(ReadTraceCallback) = 0; 297 298 // Synchronous version of ReadTrace(). It blocks the calling thread until all 299 // the trace contents are read. This is slow and inefficient (involves more 300 // copies) and is mainly intended for testing. 301 std::vector<char> ReadTraceBlocking(); 302 303 // Struct passed as an argument to the callback for GetTraceStats(). Contains 304 // statistics about the tracing session. 305 struct GetTraceStatsCallbackArgs { 306 // Whether or not querying statistics succeeded. 307 bool success = false; 308 // Serialized TraceStats protobuf message. To decode: 309 // 310 // perfetto::protos::gen::TraceStats trace_stats; 311 // trace_stats.ParseFromArray(args.trace_stats_data.data(), 312 // args.trace_stats_data.size()); 313 // 314 std::vector<uint8_t> trace_stats_data; 315 }; 316 317 // Requests a snapshot of statistical data for this tracing session. Only one 318 // query may be active at a time. This callback will be invoked on an internal 319 // perfetto thread. 320 using GetTraceStatsCallback = std::function<void(GetTraceStatsCallbackArgs)>; 321 virtual void GetTraceStats(GetTraceStatsCallback) = 0; 322 323 // Synchronous version of GetTraceStats() for convenience. 324 GetTraceStatsCallbackArgs GetTraceStatsBlocking(); 325 326 // Struct passed as an argument to the callback for QueryServiceState(). 327 // Contains information about registered data sources. 328 struct QueryServiceStateCallbackArgs { 329 // Whether or not getting the service state succeeded. 330 bool success = false; 331 // Serialized TracingServiceState protobuf message. To decode: 332 // 333 // perfetto::protos::gen::TracingServiceState state; 334 // state.ParseFromArray(args.service_state_data.data(), 335 // args.service_state_data.size()); 336 // 337 std::vector<uint8_t> service_state_data; 338 }; 339 340 // Requests a snapshot of the tracing service state for this session. Only one 341 // request per session may be active at a time. This callback will be invoked 342 // on an internal perfetto thread. 343 using QueryServiceStateCallback = 344 std::function<void(QueryServiceStateCallbackArgs)>; 345 virtual void QueryServiceState(QueryServiceStateCallback) = 0; 346 347 // Synchronous version of QueryServiceState() for convenience. 348 QueryServiceStateCallbackArgs QueryServiceStateBlocking(); 349 }; 350 351 } // namespace perfetto 352 353 #endif // INCLUDE_PERFETTO_TRACING_TRACING_H_ 354