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_INTERNAL_TRACK_EVENT_DATA_SOURCE_H_ 18 #define INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_DATA_SOURCE_H_ 19 20 #include "perfetto/base/compiler.h" 21 #include "perfetto/base/template_util.h" 22 #include "perfetto/protozero/message_handle.h" 23 #include "perfetto/tracing/core/data_source_config.h" 24 #include "perfetto/tracing/data_source.h" 25 #include "perfetto/tracing/event_context.h" 26 #include "perfetto/tracing/internal/track_event_internal.h" 27 #include "perfetto/tracing/internal/track_event_legacy.h" 28 #include "perfetto/tracing/internal/write_track_event_args.h" 29 #include "perfetto/tracing/track.h" 30 #include "perfetto/tracing/track_event_category_registry.h" 31 #include "protos/perfetto/common/builtin_clock.pbzero.h" 32 #include "protos/perfetto/config/track_event/track_event_config.gen.h" 33 #include "protos/perfetto/trace/track_event/track_event.pbzero.h" 34 35 #include <type_traits> 36 37 namespace perfetto { 38 39 namespace { 40 41 class StopArgsImpl : public DataSourceBase::StopArgs { 42 public: 43 // HandleAsynchronously() can optionally be called to defer the tracing 44 // session stop and write track events just before stopping. This function 45 // returns a closure that must be invoked after the last track events have 46 // been emitted. The caller also needs to explicitly call 47 // TrackEvent::Flush() because no other implicit flushes will happen after 48 // the stop signal. 49 // See the comment in include/perfetto/tracing/data_source.h for more info. HandleStopAsynchronously()50 std::function<void()> HandleStopAsynchronously() const override { 51 auto closure = std::move(async_stop_closure); 52 async_stop_closure = std::function<void()>(); 53 return closure; 54 } 55 56 mutable std::function<void()> async_stop_closure; 57 }; 58 59 } // namespace 60 61 // A function for converting an abstract timestamp into a 62 // perfetto::TraceTimestamp struct. By specialising this template and defining 63 // static ConvertTimestampToTraceTimeNs function in it the user can register 64 // additional timestamp types. The return value should specify the 65 // clock domain used by the timestamp as well as its value. 66 // 67 // The supported clock domains are the ones described in 68 // perfetto.protos.ClockSnapshot. However, custom clock IDs (>=64) are 69 // reserved for internal use by the SDK for the time being. 70 // The timestamp value should be in nanoseconds regardless of the clock domain. 71 template <typename T> 72 struct TraceTimestampTraits; 73 74 // A pass-through implementation for raw uint64_t nanosecond timestamps. 75 template <> 76 struct TraceTimestampTraits<uint64_t> { 77 static inline TraceTimestamp ConvertTimestampToTraceTimeNs( 78 const uint64_t& timestamp) { 79 return {static_cast<uint32_t>(internal::TrackEventInternal::GetClockId()), timestamp}; 80 } 81 }; 82 83 // A pass-through implementation for the trace timestamp structure. 84 template <> 85 struct TraceTimestampTraits<TraceTimestamp> { 86 static inline TraceTimestamp ConvertTimestampToTraceTimeNs( 87 const TraceTimestamp& timestamp) { 88 return timestamp; 89 } 90 }; 91 92 namespace internal { 93 namespace { 94 95 // Checks if |T| is a valid track. 96 template <typename T> 97 static constexpr bool IsValidTrack() { 98 return std::is_convertible<T, Track>::value; 99 } 100 101 // Checks if |T| is a valid non-counter track. 102 template <typename T> 103 static constexpr bool IsValidNormalTrack() { 104 return std::is_convertible<T, Track>::value && 105 !std::is_convertible<T, CounterTrack>::value; 106 } 107 108 // Because the user can use arbitrary timestamp types, we can't compare against 109 // any known base type here. Instead, we check that a track or a trace lambda 110 // isn't being interpreted as a timestamp. 111 template <typename T, 112 typename CanBeConvertedToNsCheck = decltype( 113 ::perfetto::TraceTimestampTraits<typename base::remove_cvref_t< 114 T>>::ConvertTimestampToTraceTimeNs(std::declval<T>())), 115 typename NotTrackCheck = 116 typename std::enable_if<!IsValidNormalTrack<T>()>::type, 117 typename NotLambdaCheck = 118 typename std::enable_if<!IsValidTraceLambda<T>()>::type> 119 static constexpr bool IsValidTimestamp() { 120 return true; 121 } 122 123 // Taken from C++17 124 template <typename...> 125 using void_t = void; 126 127 // Returns true iff `GetStaticString(T)` is defined OR T == DynamicString. 128 template <typename T, typename = void> 129 struct IsValidEventNameType 130 : std::is_same<perfetto::DynamicString, typename std::decay<T>::type> {}; 131 132 template <typename T> 133 struct IsValidEventNameType< 134 T, 135 void_t<decltype(GetStaticString(std::declval<T>()))>> : std::true_type {}; 136 137 template <typename T> 138 inline void ValidateEventNameType() { 139 static_assert( 140 IsValidEventNameType<T>::value, 141 "Event names must be static strings. To use dynamic event names, see " 142 "https://perfetto.dev/docs/instrumentation/" 143 "track-events#dynamic-event-names"); 144 } 145 146 } // namespace 147 148 inline ::perfetto::DynamicString DecayEventNameType( 149 ::perfetto::DynamicString name) { 150 return name; 151 } 152 153 inline ::perfetto::StaticString DecayEventNameType( 154 ::perfetto::StaticString name) { 155 return name; 156 } 157 158 // Convert all static strings of different length to StaticString to avoid 159 // unnecessary template instantiations. 160 inline ::perfetto::StaticString DecayEventNameType(const char* name) { 161 return ::perfetto::StaticString{name}; 162 } 163 164 // Traits for dynamic categories. 165 template <typename CategoryType> 166 struct CategoryTraits { 167 static constexpr bool kIsDynamic = true; 168 static constexpr const Category* GetStaticCategory( 169 const TrackEventCategoryRegistry*, 170 const CategoryType&) { 171 return nullptr; 172 } 173 static size_t GetStaticIndex(const CategoryType&) { 174 PERFETTO_DCHECK(false); // Not reached. 175 return TrackEventCategoryRegistry::kDynamicCategoryIndex; 176 } 177 static DynamicCategory GetDynamicCategory(const CategoryType& category) { 178 return DynamicCategory{category}; 179 } 180 }; 181 182 // Traits for static categories. 183 template <> 184 struct CategoryTraits<size_t> { 185 static constexpr bool kIsDynamic = false; 186 static const Category* GetStaticCategory( 187 const TrackEventCategoryRegistry* registry, 188 size_t category_index) { 189 return registry->GetCategory(category_index); 190 } 191 static constexpr size_t GetStaticIndex(size_t category_index) { 192 return category_index; 193 } 194 static DynamicCategory GetDynamicCategory(size_t) { 195 PERFETTO_DCHECK(false); // Not reached. 196 return DynamicCategory(); 197 } 198 }; 199 200 struct TrackEventDataSourceTraits : public perfetto::DefaultDataSourceTraits { 201 using IncrementalStateType = TrackEventIncrementalState; 202 using TlsStateType = TrackEventTlsState; 203 204 // Use a one shared TLS slot so that all track event data sources write into 205 // the same sequence and share interning dictionaries. 206 static DataSourceThreadLocalState* GetDataSourceTLS(DataSourceStaticState*, 207 TracingTLS* root_tls) { 208 return &root_tls->track_event_tls; 209 } 210 }; 211 212 // A generic track event data source which is instantiated once per track event 213 // category namespace. 214 template <typename DerivedDataSource, 215 const TrackEventCategoryRegistry* Registry> 216 class TrackEventDataSource 217 : public DataSource<DerivedDataSource, TrackEventDataSourceTraits> { 218 using Base = DataSource<DerivedDataSource, TrackEventDataSourceTraits>; 219 220 public: 221 static constexpr bool kRequiresCallbacksUnderLock = false; 222 223 // Add or remove a session observer for this track event data source. The 224 // observer will be notified about started and stopped tracing sessions. 225 // Returns |true| if the observer was successfully added (i.e., the maximum 226 // number of observers wasn't exceeded). 227 static bool AddSessionObserver(TrackEventSessionObserver* observer) { 228 return TrackEventInternal::AddSessionObserver(*Registry, observer); 229 } 230 231 static void RemoveSessionObserver(TrackEventSessionObserver* observer) { 232 TrackEventInternal::RemoveSessionObserver(*Registry, observer); 233 } 234 235 // DataSource implementation. 236 void OnSetup(const DataSourceBase::SetupArgs& args) override { 237 auto config_raw = args.config->track_event_config_raw(); 238 bool ok = config_.ParseFromArray(config_raw.data(), config_raw.size()); 239 PERFETTO_DCHECK(ok); 240 TrackEventInternal::EnableTracing(*Registry, config_, args); 241 } 242 243 void OnStart(const DataSourceBase::StartArgs& args) override { 244 TrackEventInternal::OnStart(*Registry, args); 245 } 246 247 void OnStop(const DataSourceBase::StopArgs& args) override { 248 auto outer_stop_closure = args.HandleStopAsynchronously(); 249 StopArgsImpl inner_stop_args{}; 250 uint32_t internal_instance_index = args.internal_instance_index; 251 inner_stop_args.internal_instance_index = internal_instance_index; 252 inner_stop_args.async_stop_closure = [internal_instance_index, 253 outer_stop_closure] { 254 TrackEventInternal::DisableTracing(*Registry, internal_instance_index); 255 outer_stop_closure(); 256 }; 257 258 TrackEventInternal::OnStop(*Registry, inner_stop_args); 259 260 // If inner_stop_args.HandleStopAsynchronously() hasn't been called, 261 // run the async closure here. 262 if (inner_stop_args.async_stop_closure) 263 std::move(inner_stop_args.async_stop_closure)(); 264 } 265 266 void WillClearIncrementalState( 267 const DataSourceBase::ClearIncrementalStateArgs& args) override { 268 TrackEventInternal::WillClearIncrementalState(*Registry, args); 269 } 270 271 static void Flush() { 272 Base::template Trace([](typename Base::TraceContext ctx) { ctx.Flush(); }); 273 } 274 275 // Determine if *any* tracing category is enabled. 276 static bool IsEnabled() { 277 bool enabled = false; 278 Base::template CallIfEnabled( 279 [&](uint32_t /*instances*/) { enabled = true; }); 280 return enabled; 281 } 282 283 // Determine if tracing for the given static category is enabled. 284 static bool IsCategoryEnabled(size_t category_index) { 285 return Registry->GetCategoryState(category_index) 286 ->load(std::memory_order_relaxed); 287 } 288 289 // Determine if tracing for the given dynamic category is enabled. 290 static bool IsDynamicCategoryEnabled( 291 const DynamicCategory& dynamic_category) { 292 bool enabled = false; 293 Base::template Trace([&](typename Base::TraceContext ctx) { 294 enabled = enabled || IsDynamicCategoryEnabled(&ctx, dynamic_category); 295 }); 296 return enabled; 297 } 298 299 // This is the inlined entrypoint for all track event trace points. It tries 300 // to be as lightweight as possible in terms of instructions and aims to 301 // compile down to an unlikely conditional jump to the actual trace writing 302 // function. 303 template <typename Callback> 304 static void CallIfCategoryEnabled(size_t category_index, 305 Callback callback) PERFETTO_ALWAYS_INLINE { 306 Base::template CallIfEnabled<CategoryTracePointTraits>( 307 [&callback](uint32_t instances) { callback(instances); }, 308 {category_index}); 309 } 310 311 // Once we've determined tracing to be enabled for this category, actually 312 // write a trace event onto this thread's default track. Outlined to avoid 313 // bloating code (mostly stack depth) at the actual trace point. 314 // 315 // The following combination of parameters is supported (in the given order): 316 // - Zero or one track, 317 // - Zero or one custom timestamp, 318 // - Arbitrary number of debug annotations. 319 // - Zero or one lambda. 320 321 // Trace point which does not take a track or timestamp. 322 template <typename CategoryType, 323 typename EventNameType, 324 typename... Arguments> 325 static void TraceForCategory(uint32_t instances, 326 const CategoryType& category, 327 const EventNameType& event_name, 328 perfetto::protos::pbzero::TrackEvent::Type type, 329 Arguments&&... args) PERFETTO_NO_INLINE { 330 TraceForCategoryImpl(instances, category, event_name, type, 331 TrackEventInternal::kDefaultTrack, 332 TrackEventInternal::GetTraceTime(), 333 std::forward<Arguments>(args)...); 334 } 335 336 // Trace point which takes a track, but not timestamp. 337 // NOTE: Here track should be captured using universal reference (TrackType&&) 338 // instead of const TrackType& to ensure that the proper overload is selected 339 // (otherwise the compiler will fail to disambiguate between adding const& and 340 // parsing track as a part of Arguments...). 341 template <typename TrackType, 342 typename CategoryType, 343 typename EventNameType, 344 typename... Arguments, 345 typename TrackTypeCheck = typename std::enable_if< 346 std::is_convertible<TrackType, Track>::value>::type> 347 static void TraceForCategory(uint32_t instances, 348 const CategoryType& category, 349 const EventNameType& event_name, 350 perfetto::protos::pbzero::TrackEvent::Type type, 351 TrackType&& track, 352 Arguments&&... args) PERFETTO_NO_INLINE { 353 TraceForCategoryImpl( 354 instances, category, event_name, type, std::forward<TrackType>(track), 355 TrackEventInternal::GetTraceTime(), std::forward<Arguments>(args)...); 356 } 357 358 // Trace point which takes a timestamp, but not track. 359 template <typename CategoryType, 360 typename EventNameType, 361 typename TimestampType = uint64_t, 362 typename... Arguments, 363 typename TimestampTypeCheck = typename std::enable_if< 364 IsValidTimestamp<TimestampType>()>::type> 365 static void TraceForCategory(uint32_t instances, 366 const CategoryType& category, 367 const EventNameType& event_name, 368 perfetto::protos::pbzero::TrackEvent::Type type, 369 TimestampType&& timestamp, 370 Arguments&&... args) PERFETTO_NO_INLINE { 371 TraceForCategoryImpl(instances, category, event_name, type, 372 TrackEventInternal::kDefaultTrack, 373 std::forward<TimestampType>(timestamp), 374 std::forward<Arguments>(args)...); 375 } 376 377 // Trace point which takes a timestamp and a track. 378 template <typename TrackType, 379 typename CategoryType, 380 typename EventNameType, 381 typename TimestampType = uint64_t, 382 typename... Arguments, 383 typename TrackTypeCheck = typename std::enable_if< 384 std::is_convertible<TrackType, Track>::value>::type, 385 typename TimestampTypeCheck = typename std::enable_if< 386 IsValidTimestamp<TimestampType>()>::type> 387 static void TraceForCategory(uint32_t instances, 388 const CategoryType& category, 389 const EventNameType& event_name, 390 perfetto::protos::pbzero::TrackEvent::Type type, 391 TrackType&& track, 392 TimestampType&& timestamp, 393 Arguments&&... args) PERFETTO_NO_INLINE { 394 TraceForCategoryImpl(instances, category, event_name, type, 395 std::forward<TrackType>(track), 396 std::forward<TimestampType>(timestamp), 397 std::forward<Arguments>(args)...); 398 } 399 400 // Trace point with with a counter sample. 401 template <typename CategoryType, typename EventNameType, typename ValueType> 402 static void TraceForCategory(uint32_t instances, 403 const CategoryType& category, 404 const EventNameType&, 405 perfetto::protos::pbzero::TrackEvent::Type type, 406 CounterTrack track, 407 ValueType value) PERFETTO_ALWAYS_INLINE { 408 PERFETTO_DCHECK(type == perfetto::protos::pbzero::TrackEvent::TYPE_COUNTER); 409 TraceForCategory(instances, category, /*name=*/nullptr, type, track, 410 TrackEventInternal::GetTraceTime(), value); 411 } 412 413 // Trace point with with a timestamp and a counter sample. 414 template <typename CategoryType, 415 typename EventNameType, 416 typename TimestampType = uint64_t, 417 typename TimestampTypeCheck = typename std::enable_if< 418 IsValidTimestamp<TimestampType>()>::type, 419 typename ValueType> 420 static void TraceForCategory(uint32_t instances, 421 const CategoryType& category, 422 const EventNameType&, 423 perfetto::protos::pbzero::TrackEvent::Type type, 424 CounterTrack track, 425 TimestampType timestamp, 426 ValueType value) PERFETTO_ALWAYS_INLINE { 427 PERFETTO_DCHECK(type == perfetto::protos::pbzero::TrackEvent::TYPE_COUNTER); 428 TraceForCategoryImpl( 429 instances, category, /*name=*/nullptr, type, track, timestamp, 430 [&](EventContext event_ctx) { 431 if (std::is_integral<ValueType>::value) { 432 int64_t value_int64 = static_cast<int64_t>(value); 433 if (track.is_incremental()) { 434 TrackEventIncrementalState* incr_state = 435 event_ctx.GetIncrementalState(); 436 PERFETTO_DCHECK(incr_state != nullptr); 437 auto prv_value = 438 incr_state->last_counter_value_per_track[track.uuid]; 439 event_ctx.event()->set_counter_value(value_int64 - prv_value); 440 prv_value = value_int64; 441 incr_state->last_counter_value_per_track[track.uuid] = prv_value; 442 } else { 443 event_ctx.event()->set_counter_value(value_int64); 444 } 445 } else { 446 event_ctx.event()->set_double_counter_value( 447 static_cast<double>(value)); 448 } 449 }); 450 } 451 452 // Additional trace points used in legacy macros. 453 // It's possible to implement legacy macros using a common TraceForCategory, 454 // by supplying a lambda that sets all necessary legacy fields. But this 455 // results in a binary size bloat because every trace point generates its own 456 // template instantiation with its own lambda. ICF can't eliminate those as 457 // each lambda captures different variables and so the code is not completely 458 // identical. 459 // What we do instead is define additional TraceForCategoryLegacy templates 460 // that take legacy arguments directly. Their instantiations can have the same 461 // binary code for at least some macro invocations and so can be successfully 462 // folded by the linker. 463 #if PERFETTO_ENABLE_LEGACY_TRACE_EVENTS 464 template <typename TrackType, 465 typename CategoryType, 466 typename EventNameType, 467 typename... Arguments, 468 typename TrackTypeCheck = typename std::enable_if< 469 std::is_convertible<TrackType, Track>::value>::type> 470 static void TraceForCategoryLegacy( 471 uint32_t instances, 472 const CategoryType& category, 473 const EventNameType& event_name, 474 perfetto::protos::pbzero::TrackEvent::Type type, 475 TrackType&& track, 476 char phase, 477 uint32_t flags, 478 Arguments&&... args) PERFETTO_NO_INLINE { 479 TraceForCategoryImpl(instances, category, event_name, type, track, 480 TrackEventInternal::GetTraceTime(), 481 [&](perfetto::EventContext ctx) 482 PERFETTO_NO_THREAD_SAFETY_ANALYSIS { 483 using ::perfetto::internal::TrackEventLegacy; 484 TrackEventLegacy::WriteLegacyEvent( 485 std::move(ctx), phase, flags, args...); 486 }); 487 } 488 489 template <typename TrackType, 490 typename CategoryType, 491 typename EventNameType, 492 typename TimestampType = uint64_t, 493 typename... Arguments, 494 typename TrackTypeCheck = typename std::enable_if< 495 std::is_convertible<TrackType, Track>::value>::type, 496 typename TimestampTypeCheck = typename std::enable_if< 497 IsValidTimestamp<TimestampType>()>::type> 498 static void TraceForCategoryLegacy( 499 uint32_t instances, 500 const CategoryType& category, 501 const EventNameType& event_name, 502 perfetto::protos::pbzero::TrackEvent::Type type, 503 TrackType&& track, 504 char phase, 505 uint32_t flags, 506 TimestampType&& timestamp, 507 Arguments&&... args) PERFETTO_NO_INLINE { 508 TraceForCategoryImpl( 509 instances, category, event_name, type, track, timestamp, 510 [&](perfetto::EventContext ctx) PERFETTO_NO_THREAD_SAFETY_ANALYSIS { 511 using ::perfetto::internal::TrackEventLegacy; 512 TrackEventLegacy::WriteLegacyEvent(std::move(ctx), phase, flags, 513 args...); 514 }); 515 } 516 517 template <typename TrackType, 518 typename CategoryType, 519 typename EventNameType, 520 typename ThreadIdType, 521 typename LegacyIdType, 522 typename... Arguments, 523 typename TrackTypeCheck = typename std::enable_if< 524 std::is_convertible<TrackType, Track>::value>::type> 525 static void TraceForCategoryLegacyWithId( 526 uint32_t instances, 527 const CategoryType& category, 528 const EventNameType& event_name, 529 perfetto::protos::pbzero::TrackEvent::Type type, 530 TrackType&& track, 531 char phase, 532 uint32_t flags, 533 ThreadIdType thread_id, 534 LegacyIdType legacy_id, 535 Arguments&&... args) PERFETTO_NO_INLINE { 536 TraceForCategoryImpl( 537 instances, category, event_name, type, track, 538 TrackEventInternal::GetTraceTime(), 539 [&](perfetto::EventContext ctx) PERFETTO_NO_THREAD_SAFETY_ANALYSIS { 540 using ::perfetto::internal::TrackEventLegacy; 541 ::perfetto::internal::LegacyTraceId trace_id{legacy_id}; 542 TrackEventLegacy::WriteLegacyEventWithIdAndTid( 543 std::move(ctx), phase, flags, trace_id, thread_id, args...); 544 }); 545 } 546 547 template <typename TrackType, 548 typename CategoryType, 549 typename EventNameType, 550 typename ThreadIdType, 551 typename LegacyIdType, 552 typename TimestampType = uint64_t, 553 typename... Arguments, 554 typename TrackTypeCheck = typename std::enable_if< 555 std::is_convertible<TrackType, Track>::value>::type, 556 typename TimestampTypeCheck = typename std::enable_if< 557 IsValidTimestamp<TimestampType>()>::type> 558 static void TraceForCategoryLegacyWithId( 559 uint32_t instances, 560 const CategoryType& category, 561 const EventNameType& event_name, 562 perfetto::protos::pbzero::TrackEvent::Type type, 563 TrackType&& track, 564 char phase, 565 uint32_t flags, 566 ThreadIdType thread_id, 567 LegacyIdType legacy_id, 568 TimestampType&& timestamp, 569 Arguments&&... args) PERFETTO_NO_INLINE { 570 TraceForCategoryImpl( 571 instances, category, event_name, type, track, timestamp, 572 [&](perfetto::EventContext ctx) PERFETTO_NO_THREAD_SAFETY_ANALYSIS { 573 using ::perfetto::internal::TrackEventLegacy; 574 ::perfetto::internal::LegacyTraceId trace_id{legacy_id}; 575 TrackEventLegacy::WriteLegacyEventWithIdAndTid( 576 std::move(ctx), phase, flags, trace_id, thread_id, args...); 577 }); 578 } 579 #endif // PERFETTO_ENABLE_LEGACY_TRACE_EVENTS 580 581 // Initialize the track event library. Should be called before tracing is 582 // enabled. 583 static bool Register() { 584 // Registration is performed out-of-line so users don't need to depend on 585 // DataSourceDescriptor C++ bindings. 586 return TrackEventInternal::Initialize( 587 *Registry, 588 [](const DataSourceDescriptor& dsd) { return Base::Register(dsd); }); 589 } 590 591 // Record metadata about different types of timeline tracks. See Track. 592 static void SetTrackDescriptor(const Track& track, 593 const protos::gen::TrackDescriptor& desc) { 594 PERFETTO_DCHECK(track.uuid == desc.uuid()); 595 TrackRegistry::Get()->UpdateTrack(track, desc.SerializeAsString()); 596 Base::template Trace([&](typename Base::TraceContext ctx) { 597 TrackEventInternal::WriteTrackDescriptor( 598 track, ctx.tls_inst_->trace_writer.get(), ctx.GetIncrementalState(), 599 *ctx.GetCustomTlsState(), TrackEventInternal::GetTraceTime()); 600 }); 601 } 602 603 // DEPRECATED. Only kept for backwards compatibility. 604 static void SetTrackDescriptor( 605 const Track& track, 606 std::function<void(protos::pbzero::TrackDescriptor*)> callback) { 607 SetTrackDescriptorImpl(track, std::move(callback)); 608 } 609 610 // DEPRECATED. Only kept for backwards compatibility. 611 static void SetProcessDescriptor( 612 std::function<void(protos::pbzero::TrackDescriptor*)> callback, 613 const ProcessTrack& track = ProcessTrack::Current()) { 614 SetTrackDescriptorImpl(std::move(track), std::move(callback)); 615 } 616 617 // DEPRECATED. Only kept for backwards compatibility. 618 static void SetThreadDescriptor( 619 std::function<void(protos::pbzero::TrackDescriptor*)> callback, 620 const ThreadTrack& track = ThreadTrack::Current()) { 621 SetTrackDescriptorImpl(std::move(track), std::move(callback)); 622 } 623 624 static void EraseTrackDescriptor(const Track& track) { 625 TrackRegistry::Get()->EraseTrack(track); 626 } 627 628 // Returns the current trace timestamp in nanoseconds. Note the returned 629 // timebase may vary depending on the platform, but will always match the 630 // timestamps recorded by track events (see GetTraceClockId). 631 static uint64_t GetTraceTimeNs() { return TrackEventInternal::GetTimeNs(); } 632 633 // Returns the type of clock used by GetTraceTimeNs(). 634 static constexpr protos::pbzero::BuiltinClock GetTraceClockId() { 635 return TrackEventInternal::GetClockId(); 636 } 637 638 const protos::gen::TrackEventConfig& GetConfig() const { return config_; } 639 640 private: 641 // Each category has its own enabled/disabled state, stored in the category 642 // registry. 643 struct CategoryTracePointTraits { 644 // Each trace point with a static category has an associated category index. 645 struct TracePointData { 646 size_t category_index; 647 }; 648 // Called to get the enabled state bitmap of a given category. 649 // |data| is the trace point data structure given to 650 // DataSource::TraceWithInstances. 651 static constexpr std::atomic<uint8_t>* GetActiveInstances( 652 TracePointData data) { 653 return Registry->GetCategoryState(data.category_index); 654 } 655 }; 656 657 template <typename CategoryType, 658 typename EventNameType, 659 typename TrackType = Track, 660 typename TimestampType = uint64_t, 661 typename TimestampTypeCheck = typename std::enable_if< 662 IsValidTimestamp<TimestampType>()>::type, 663 typename TrackTypeCheck = 664 typename std::enable_if<IsValidTrack<TrackType>()>::type> 665 static perfetto::EventContext WriteTrackEvent( 666 typename Base::TraceContext& ctx, 667 const CategoryType& category, 668 const EventNameType& event_name, 669 perfetto::protos::pbzero::TrackEvent::Type type, 670 const TrackType& track, 671 const TimestampType& timestamp) PERFETTO_NO_INLINE { 672 using CatTraits = CategoryTraits<CategoryType>; 673 const Category* static_category = 674 CatTraits::GetStaticCategory(Registry, category); 675 676 const TrackEventTlsState& tls_state = *ctx.GetCustomTlsState(); 677 TraceTimestamp trace_timestamp = ::perfetto::TraceTimestampTraits< 678 TimestampType>::ConvertTimestampToTraceTimeNs(timestamp); 679 680 TraceWriterBase* trace_writer = ctx.tls_inst_->trace_writer.get(); 681 // Make sure incremental state is valid. 682 TrackEventIncrementalState* incr_state = ctx.GetIncrementalState(); 683 TrackEventInternal::ResetIncrementalStateIfRequired( 684 trace_writer, incr_state, tls_state, trace_timestamp); 685 686 // Write the track descriptor before any event on the track. 687 if (track) { 688 TrackEventInternal::WriteTrackDescriptorIfNeeded( 689 track, trace_writer, incr_state, tls_state, trace_timestamp); 690 } 691 692 // Write the event itself. 693 bool on_current_thread_track = 694 (&track == &TrackEventInternal::kDefaultTrack); 695 auto event_ctx = TrackEventInternal::WriteEvent( 696 trace_writer, incr_state, tls_state, static_category, type, 697 trace_timestamp, on_current_thread_track); 698 // event name should be emitted with `TRACE_EVENT_BEGIN` macros 699 // but not with `TRACE_EVENT_END`. 700 if (type != protos::pbzero::TrackEvent::TYPE_SLICE_END) { 701 TrackEventInternal::WriteEventName(event_name, event_ctx, tls_state); 702 } 703 // Write dynamic categories (except for events that don't require 704 // categories). For counter events, the counter name (and optional 705 // category) is stored as part of the track descriptor instead being 706 // recorded with individual events. 707 if (CatTraits::kIsDynamic && 708 type != protos::pbzero::TrackEvent::TYPE_SLICE_END && 709 type != protos::pbzero::TrackEvent::TYPE_COUNTER) { 710 DynamicCategory dynamic_category = 711 CatTraits::GetDynamicCategory(category); 712 Category cat = Category::FromDynamicCategory(dynamic_category); 713 cat.ForEachGroupMember([&](const char* member_name, size_t name_size) { 714 event_ctx.event()->add_categories(member_name, name_size); 715 return true; 716 }); 717 } 718 if (type == protos::pbzero::TrackEvent::TYPE_UNSPECIFIED) { 719 // Explicitly clear the track, so that the event is not associated 720 // with the default track, but instead uses the legacy mechanism 721 // based on the phase and pid/tid override. 722 event_ctx.event()->set_track_uuid(0); 723 } else if (!on_current_thread_track) { 724 // We emit these events using TrackDescriptors, and we cannot emit 725 // events on behalf of other processes using the TrackDescriptor 726 // format. Chrome is the only user of events with explicit process 727 // ids and currently only Chrome emits PHASE_MEMORY_DUMP events 728 // with an explicit process id, so we should be fine here. 729 // TODO(mohitms): Get rid of events with explicit process ids 730 // entirely. 731 event_ctx.event()->set_track_uuid(track.uuid); 732 } 733 734 return event_ctx; 735 } 736 737 template <typename CategoryType, 738 typename EventNameType, 739 typename TrackType = Track, 740 typename TimestampType = uint64_t, 741 typename TimestampTypeCheck = typename std::enable_if< 742 IsValidTimestamp<TimestampType>()>::type, 743 typename TrackTypeCheck = 744 typename std::enable_if<IsValidTrack<TrackType>()>::type, 745 typename... Arguments> 746 static void TraceForCategoryImpl( 747 uint32_t instances, 748 const CategoryType& category, 749 const EventNameType& event_name, 750 perfetto::protos::pbzero::TrackEvent::Type type, 751 const TrackType& track, 752 const TimestampType& timestamp, 753 Arguments&&... args) PERFETTO_ALWAYS_INLINE { 754 using CatTraits = CategoryTraits<CategoryType>; 755 TraceWithInstances( 756 instances, category, [&](typename Base::TraceContext ctx) { 757 // If this category is dynamic, first check whether it's enabled. 758 if (CatTraits::kIsDynamic && 759 !IsDynamicCategoryEnabled( 760 &ctx, CatTraits::GetDynamicCategory(category))) { 761 return; 762 } 763 764 auto event_ctx = WriteTrackEvent(ctx, category, event_name, type, 765 track, timestamp); 766 WriteTrackEventArgs(std::move(event_ctx), 767 std::forward<Arguments>(args)...); 768 }); 769 } 770 771 template <typename CategoryType, typename Lambda> 772 static void TraceWithInstances(uint32_t instances, 773 const CategoryType& category, 774 Lambda lambda) PERFETTO_ALWAYS_INLINE { 775 using CatTraits = CategoryTraits<CategoryType>; 776 if (CatTraits::kIsDynamic) { 777 Base::template TraceWithInstances(instances, std::move(lambda)); 778 } else { 779 Base::template TraceWithInstances<CategoryTracePointTraits>( 780 instances, std::move(lambda), {CatTraits::GetStaticIndex(category)}); 781 } 782 } 783 784 // Records a track descriptor into the track descriptor registry and, if we 785 // are tracing, also mirrors the descriptor into the trace. 786 template <typename TrackType> 787 static void SetTrackDescriptorImpl( 788 const TrackType& track, 789 std::function<void(protos::pbzero::TrackDescriptor*)> callback) { 790 TrackRegistry::Get()->UpdateTrack(track, std::move(callback)); 791 Base::template Trace([&](typename Base::TraceContext ctx) { 792 TrackEventInternal::WriteTrackDescriptor( 793 track, ctx.tls_inst_->trace_writer.get(), ctx.GetIncrementalState(), 794 *ctx.GetCustomTlsState(), TrackEventInternal::GetTraceTime()); 795 }); 796 } 797 798 // Determines if the given dynamic category is enabled, first by checking the 799 // per-trace writer cache or by falling back to computing it based on the 800 // trace config for the given session. 801 static bool IsDynamicCategoryEnabled( 802 typename Base::TraceContext* ctx, 803 const DynamicCategory& dynamic_category) { 804 auto incr_state = ctx->GetIncrementalState(); 805 auto it = incr_state->dynamic_categories.find(dynamic_category.name); 806 if (it == incr_state->dynamic_categories.end()) { 807 // We haven't seen this category before. Let's figure out if it's enabled. 808 // This requires grabbing a lock to read the session's trace config. 809 auto ds = ctx->GetDataSourceLocked(); 810 Category category{Category::FromDynamicCategory(dynamic_category)}; 811 bool enabled = TrackEventInternal::IsCategoryEnabled( 812 *Registry, ds->config_, category); 813 // TODO(skyostil): Cap the size of |dynamic_categories|. 814 incr_state->dynamic_categories[dynamic_category.name] = enabled; 815 return enabled; 816 } 817 return it->second; 818 } 819 820 // Config for the current tracing session. 821 protos::gen::TrackEventConfig config_; 822 }; 823 824 } // namespace internal 825 } // namespace perfetto 826 827 #endif // INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_DATA_SOURCE_H_ 828