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