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/template_util.h" 21 #include "perfetto/base/thread_annotations.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()), 80 timestamp}; 81 } 82 }; 83 84 // A pass-through implementation for the trace timestamp structure. 85 template <> 86 struct TraceTimestampTraits<TraceTimestamp> { 87 static inline TraceTimestamp ConvertTimestampToTraceTimeNs( 88 const TraceTimestamp& timestamp) { 89 return timestamp; 90 } 91 }; 92 93 namespace internal { 94 namespace { 95 96 // Checks if |T| is a valid track. 97 template <typename T> 98 static constexpr bool IsValidTrack() { 99 return std::is_convertible<T, Track>::value; 100 } 101 102 // Checks if |T| is a valid non-counter track. 103 template <typename T> 104 static constexpr bool IsValidNormalTrack() { 105 return std::is_convertible<T, Track>::value && 106 !std::is_convertible<T, CounterTrack>::value; 107 } 108 109 // Because the user can use arbitrary timestamp types, we can't compare against 110 // any known base type here. Instead, we check that a track or a trace lambda 111 // isn't being interpreted as a timestamp. 112 template < 113 typename T, 114 typename CanBeConvertedToNsCheck = 115 decltype(::perfetto::TraceTimestampTraits<typename base::remove_cvref_t< 116 T>>::ConvertTimestampToTraceTimeNs(std::declval<T>())), 117 typename NotTrackCheck = 118 typename std::enable_if<!IsValidNormalTrack<T>()>::type, 119 typename NotLambdaCheck = 120 typename std::enable_if<!IsValidTraceLambda<T>()>::type> 121 static constexpr bool IsValidTimestamp() { 122 return true; 123 } 124 125 // Taken from C++17 126 template <typename...> 127 using void_t = void; 128 129 // Returns true iff `GetStaticString(T)` is defined OR T == DynamicString. 130 template <typename T, typename = void> 131 struct IsValidEventNameType 132 : std::is_same<perfetto::DynamicString, typename std::decay<T>::type> {}; 133 134 template <typename T> 135 struct IsValidEventNameType< 136 T, 137 void_t<decltype(GetStaticString(std::declval<T>()))>> : std::true_type {}; 138 139 template <typename T> 140 inline void ValidateEventNameType() { 141 static_assert( 142 IsValidEventNameType<T>::value, 143 "Event names must be static strings. To use dynamic event names, see " 144 "https://perfetto.dev/docs/instrumentation/" 145 "track-events#dynamic-event-names"); 146 } 147 148 inline bool UnorderedEqual(std::vector<std::string> vec1, 149 std::vector<std::string> vec2) { 150 std::sort(vec1.begin(), vec1.end()); 151 vec1.erase(std::unique(vec1.begin(), vec1.end()), vec1.end()); 152 std::sort(vec2.begin(), vec2.end()); 153 vec2.erase(std::unique(vec2.begin(), vec2.end()), vec2.end()); 154 return vec1 == vec2; 155 } 156 157 } // namespace 158 159 inline ::perfetto::DynamicString DecayEventNameType( 160 ::perfetto::DynamicString name) { 161 return name; 162 } 163 164 inline ::perfetto::StaticString DecayEventNameType( 165 ::perfetto::StaticString name) { 166 return name; 167 } 168 169 // Convert all static strings of different length to StaticString to avoid 170 // unnecessary template instantiations. 171 inline ::perfetto::StaticString DecayEventNameType(const char* name) { 172 return ::perfetto::StaticString{name}; 173 } 174 175 // Traits for dynamic categories. 176 template <typename CategoryType> 177 struct CategoryTraits { 178 static constexpr bool kIsDynamic = true; 179 static constexpr const Category* GetStaticCategory( 180 const TrackEventCategoryRegistry*, 181 const CategoryType&) { 182 return nullptr; 183 } 184 static size_t GetStaticIndex(const CategoryType&) { 185 PERFETTO_DCHECK(false); // Not reached. 186 return TrackEventCategoryRegistry::kDynamicCategoryIndex; 187 } 188 static DynamicCategory GetDynamicCategory(const CategoryType& category) { 189 return DynamicCategory{category}; 190 } 191 }; 192 193 // Traits for static categories. 194 template <> 195 struct CategoryTraits<size_t> { 196 static constexpr bool kIsDynamic = false; 197 static const Category* GetStaticCategory( 198 const TrackEventCategoryRegistry* registry, 199 size_t category_index) { 200 return registry->GetCategory(category_index); 201 } 202 static constexpr size_t GetStaticIndex(size_t category_index) { 203 return category_index; 204 } 205 static DynamicCategory GetDynamicCategory(size_t) { 206 PERFETTO_DCHECK(false); // Not reached. 207 return DynamicCategory(); 208 } 209 }; 210 211 struct TrackEventDataSourceTraits : public perfetto::DefaultDataSourceTraits { 212 using IncrementalStateType = TrackEventIncrementalState; 213 using TlsStateType = TrackEventTlsState; 214 215 // Use a one shared TLS slot so that all track event data sources write into 216 // the same sequence and share interning dictionaries. 217 static DataSourceThreadLocalState* GetDataSourceTLS(DataSourceStaticState*, 218 TracingTLS* root_tls) { 219 return &root_tls->track_event_tls; 220 } 221 }; 222 223 // A generic track event data source which is instantiated once per track event 224 // category namespace. 225 template <typename DerivedDataSource, 226 const TrackEventCategoryRegistry* Registry> 227 class TrackEventDataSource 228 : public DataSource<DerivedDataSource, TrackEventDataSourceTraits> { 229 using Base = DataSource<DerivedDataSource, TrackEventDataSourceTraits>; 230 231 public: 232 static constexpr bool kRequiresCallbacksUnderLock = false; 233 234 // Add or remove a session observer for this track event data source. The 235 // observer will be notified about started and stopped tracing sessions. 236 // Returns |true| if the observer was successfully added (i.e., the maximum 237 // number of observers wasn't exceeded). 238 static bool AddSessionObserver(TrackEventSessionObserver* observer) { 239 return TrackEventInternal::AddSessionObserver(*Registry, observer); 240 } 241 242 static void RemoveSessionObserver(TrackEventSessionObserver* observer) { 243 TrackEventInternal::RemoveSessionObserver(*Registry, observer); 244 } 245 246 // DataSource implementation. 247 void OnSetup(const DataSourceBase::SetupArgs& args) override { 248 auto config_raw = args.config->track_event_config_raw(); 249 bool ok = config_.ParseFromArray(config_raw.data(), config_raw.size()); 250 PERFETTO_DCHECK(ok); 251 TrackEventInternal::EnableTracing(*Registry, config_, args); 252 } 253 254 void OnStart(const DataSourceBase::StartArgs& args) override { 255 TrackEventInternal::OnStart(*Registry, args); 256 } 257 258 void OnStop(const DataSourceBase::StopArgs& args) override { 259 auto outer_stop_closure = args.HandleStopAsynchronously(); 260 StopArgsImpl inner_stop_args{}; 261 uint32_t internal_instance_index = args.internal_instance_index; 262 inner_stop_args.internal_instance_index = internal_instance_index; 263 inner_stop_args.async_stop_closure = [internal_instance_index, 264 outer_stop_closure] { 265 TrackEventInternal::DisableTracing(*Registry, internal_instance_index); 266 outer_stop_closure(); 267 }; 268 269 TrackEventInternal::OnStop(*Registry, inner_stop_args); 270 271 // If inner_stop_args.HandleStopAsynchronously() hasn't been called, 272 // run the async closure here. 273 if (inner_stop_args.async_stop_closure) 274 std::move(inner_stop_args.async_stop_closure)(); 275 } 276 277 void WillClearIncrementalState( 278 const DataSourceBase::ClearIncrementalStateArgs& args) override { 279 TrackEventInternal::WillClearIncrementalState(*Registry, args); 280 } 281 282 // In Chrome, startup sessions are propagated from the browser process to 283 // child processes using command-line flags. Command-line flags can only 284 // convey the category filter and privacy settings, so we use only those 285 // to determine which startup sessions to adopt. 286 // TODO(khokhlov): After Chrome is able to propagate the entire config to the 287 // child process, we can make this comparison more strict by only clearing 288 // selected fields and comparing everything else. One specific thing to keep 289 // in mind is to clear the |convert_to_legacy_json| field, because Telemetry 290 // initiates tracing with proto format, but in some cases adopts the tracing 291 // session later via devtools which expect json format. 292 bool CanAdoptStartupSession(const DataSourceConfig& startup_config, 293 const DataSourceConfig& service_config) override { 294 if (startup_config.track_event_config_raw().empty() || 295 service_config.track_event_config_raw().empty()) { 296 return false; 297 } 298 299 protos::gen::TrackEventConfig startup_te_cfg; 300 startup_te_cfg.ParseFromString(startup_config.track_event_config_raw()); 301 protos::gen::TrackEventConfig service_te_cfg; 302 service_te_cfg.ParseFromString(service_config.track_event_config_raw()); 303 304 if (!UnorderedEqual(startup_te_cfg.enabled_categories(), 305 service_te_cfg.enabled_categories())) { 306 return false; 307 } 308 if (!UnorderedEqual(startup_te_cfg.disabled_categories(), 309 service_te_cfg.disabled_categories())) { 310 return false; 311 } 312 if (!UnorderedEqual(startup_te_cfg.enabled_tags(), 313 service_te_cfg.enabled_tags())) { 314 return false; 315 } 316 if (!UnorderedEqual(startup_te_cfg.disabled_tags(), 317 service_te_cfg.disabled_tags())) { 318 return false; 319 } 320 if (startup_te_cfg.filter_debug_annotations() != 321 service_te_cfg.filter_debug_annotations()) { 322 return false; 323 } 324 if (startup_te_cfg.filter_dynamic_event_names() != 325 service_te_cfg.filter_dynamic_event_names()) { 326 return false; 327 } 328 329 return true; 330 } 331 332 static void Flush() { 333 Base::Trace([](typename Base::TraceContext ctx) { ctx.Flush(); }); 334 } 335 336 // Determine if *any* tracing category is enabled. 337 static bool IsEnabled() { 338 bool enabled = false; 339 Base::CallIfEnabled([&](uint32_t /*instances*/) { enabled = true; }); 340 return enabled; 341 } 342 343 // Determine if tracing for the given static category is enabled. 344 static bool IsCategoryEnabled(size_t category_index) { 345 return Registry->GetCategoryState(category_index) 346 ->load(std::memory_order_relaxed); 347 } 348 349 // Determine if tracing for the given dynamic category is enabled. 350 static bool IsDynamicCategoryEnabled( 351 const DynamicCategory& dynamic_category) { 352 bool enabled = false; 353 Base::Trace([&](typename Base::TraceContext ctx) { 354 enabled = enabled || IsDynamicCategoryEnabled(&ctx, dynamic_category); 355 }); 356 return enabled; 357 } 358 359 // This is the inlined entrypoint for all track event trace points. It tries 360 // to be as lightweight as possible in terms of instructions and aims to 361 // compile down to an unlikely conditional jump to the actual trace writing 362 // function. 363 template <typename Callback> 364 static void CallIfCategoryEnabled(size_t category_index, 365 Callback callback) PERFETTO_ALWAYS_INLINE { 366 Base::template CallIfEnabled<CategoryTracePointTraits>( 367 [&callback](uint32_t instances) { callback(instances); }, 368 {category_index}); 369 } 370 371 // The following methods forward all arguments to TraceForCategoryBody 372 // while casting string constants to const char* and integer arguments to 373 // int64_t, uint64_t or bool. 374 template <typename CategoryType, 375 typename EventNameType, 376 typename... Arguments> 377 static void TraceForCategory(uint32_t instances, 378 const CategoryType& category, 379 const EventNameType& name, 380 perfetto::protos::pbzero::TrackEvent::Type type, 381 Arguments&&... args) PERFETTO_ALWAYS_INLINE { 382 TraceForCategoryBody(instances, DecayStrType(category), DecayStrType(name), 383 type, DecayArgType(args)...); 384 } 385 386 #if PERFETTO_ENABLE_LEGACY_TRACE_EVENTS 387 template <typename TrackType, 388 typename CategoryType, 389 typename EventNameType, 390 typename... Arguments, 391 typename TrackTypeCheck = typename std::enable_if< 392 std::is_convertible<TrackType, Track>::value>::type> 393 static void TraceForCategoryLegacy( 394 uint32_t instances, 395 const CategoryType& category, 396 const EventNameType& event_name, 397 perfetto::protos::pbzero::TrackEvent::Type type, 398 TrackType&& track, 399 char phase, 400 uint32_t flags, 401 Arguments&&... args) PERFETTO_ALWAYS_INLINE { 402 TraceForCategoryLegacyBody(instances, DecayStrType(category), 403 DecayStrType(event_name), type, track, phase, 404 flags, DecayArgType(args)...); 405 } 406 407 template <typename TrackType, 408 typename CategoryType, 409 typename EventNameType, 410 typename TimestampType = uint64_t, 411 typename... Arguments, 412 typename TrackTypeCheck = typename std::enable_if< 413 std::is_convertible<TrackType, Track>::value>::type, 414 typename TimestampTypeCheck = typename std::enable_if< 415 IsValidTimestamp<TimestampType>()>::type> 416 static void TraceForCategoryLegacy( 417 uint32_t instances, 418 const CategoryType& category, 419 const EventNameType& event_name, 420 perfetto::protos::pbzero::TrackEvent::Type type, 421 TrackType&& track, 422 char phase, 423 uint32_t flags, 424 TimestampType&& timestamp, 425 Arguments&&... args) PERFETTO_ALWAYS_INLINE { 426 TraceForCategoryLegacyBody(instances, DecayStrType(category), 427 DecayStrType(event_name), type, track, phase, 428 flags, timestamp, DecayArgType(args)...); 429 } 430 431 template <typename TrackType, 432 typename CategoryType, 433 typename EventNameType, 434 typename ThreadIdType, 435 typename LegacyIdType, 436 typename... Arguments, 437 typename TrackTypeCheck = typename std::enable_if< 438 std::is_convertible<TrackType, Track>::value>::type> 439 static void TraceForCategoryLegacyWithId( 440 uint32_t instances, 441 const CategoryType& category, 442 const EventNameType& event_name, 443 perfetto::protos::pbzero::TrackEvent::Type type, 444 TrackType&& track, 445 char phase, 446 uint32_t flags, 447 ThreadIdType thread_id, 448 LegacyIdType legacy_id, 449 Arguments&&... args) PERFETTO_ALWAYS_INLINE { 450 TraceForCategoryLegacyWithIdBody( 451 instances, DecayStrType(category), DecayStrType(event_name), type, 452 track, phase, flags, thread_id, legacy_id, DecayArgType(args)...); 453 } 454 455 template <typename TrackType, 456 typename CategoryType, 457 typename EventNameType, 458 typename ThreadIdType, 459 typename LegacyIdType, 460 typename TimestampType = uint64_t, 461 typename... Arguments, 462 typename TrackTypeCheck = typename std::enable_if< 463 std::is_convertible<TrackType, Track>::value>::type, 464 typename TimestampTypeCheck = typename std::enable_if< 465 IsValidTimestamp<TimestampType>()>::type> 466 static void TraceForCategoryLegacyWithId( 467 uint32_t instances, 468 const CategoryType& category, 469 const EventNameType& event_name, 470 perfetto::protos::pbzero::TrackEvent::Type type, 471 TrackType&& track, 472 char phase, 473 uint32_t flags, 474 ThreadIdType thread_id, 475 LegacyIdType legacy_id, 476 TimestampType&& timestamp, 477 Arguments&&... args) PERFETTO_ALWAYS_INLINE { 478 TraceForCategoryLegacyWithIdBody(instances, DecayStrType(category), 479 DecayStrType(event_name), type, track, 480 phase, flags, thread_id, legacy_id, 481 timestamp, DecayArgType(args)...); 482 } 483 #endif 484 485 // Initialize the track event library. Should be called before tracing is 486 // enabled. 487 static bool Register() { 488 // Registration is performed out-of-line so users don't need to depend on 489 // DataSourceDescriptor C++ bindings. 490 return TrackEventInternal::Initialize( 491 *Registry, 492 [](const DataSourceDescriptor& dsd) { return Base::Register(dsd); }); 493 } 494 495 // Record metadata about different types of timeline tracks. See Track. 496 static void SetTrackDescriptor(const Track& track, 497 const protos::gen::TrackDescriptor& desc) { 498 PERFETTO_DCHECK(track.uuid == desc.uuid()); 499 TrackRegistry::Get()->UpdateTrack(track, desc.SerializeAsString()); 500 Base::Trace([&](typename Base::TraceContext ctx) { 501 TrackEventInternal::WriteTrackDescriptor( 502 track, ctx.tls_inst_->trace_writer.get(), ctx.GetIncrementalState(), 503 *ctx.GetCustomTlsState(), TrackEventInternal::GetTraceTime()); 504 }); 505 } 506 507 static void EraseTrackDescriptor(const Track& track) { 508 TrackRegistry::Get()->EraseTrack(track); 509 } 510 511 // Returns the current trace timestamp in nanoseconds. Note the returned 512 // timebase may vary depending on the platform, but will always match the 513 // timestamps recorded by track events (see GetTraceClockId). 514 static uint64_t GetTraceTimeNs() { return TrackEventInternal::GetTimeNs(); } 515 516 // Returns the type of clock used by GetTraceTimeNs(). 517 static constexpr protos::pbzero::BuiltinClock GetTraceClockId() { 518 return TrackEventInternal::GetClockId(); 519 } 520 521 const protos::gen::TrackEventConfig& GetConfig() const { return config_; } 522 523 private: 524 // The DecayStrType method is used to avoid unnecessary instantiations of 525 // templates on string constants of different sizes. Without it, strings 526 // of different lengths have different types: char[10], char[15] etc. 527 // DecayStrType forwards all types of arguments as is, with the exception 528 // of string constants which are all cast to const char*. This allows to 529 // avoid extra instantiations of TraceForCategory templates. 530 template <typename T> 531 static T&& DecayStrType(T&& t) { 532 return std::forward<T>(t); 533 } 534 535 static const char* DecayStrType(const char* t) { return t; } 536 537 // The DecayArgType method is used to avoid unnecessary instantiations of 538 // templates on: 539 // * string constants of different sizes. 540 // * primitive of different constness (or references). 541 // This avoids extra instantiations of TraceForCategory templates. 542 template <typename T> 543 static T&& DecayArgType(T&& t) { 544 return std::forward<T>(t); 545 } 546 547 static const char* DecayArgType(const char* s) { return s; } 548 static uint64_t DecayArgType(uint64_t u) { return u; } 549 static uint32_t DecayArgType(uint32_t u) { return u; } 550 static uint16_t DecayArgType(uint16_t u) { return u; } 551 static uint8_t DecayArgType(uint8_t u) { return u; } 552 static int64_t DecayArgType(int64_t i) { return i; } 553 static int32_t DecayArgType(int32_t i) { return i; } 554 static int16_t DecayArgType(int16_t i) { return i; } 555 static int8_t DecayArgType(int8_t i) { return i; } 556 static bool DecayArgType(bool b) { return b; } 557 static float DecayArgType(float f) { return f; } 558 static double DecayArgType(double f) { return f; } 559 560 // Once we've determined tracing to be enabled for this category, actually 561 // write a trace event onto this thread's default track. Outlined to avoid 562 // bloating code (mostly stack depth) at the actual trace point. 563 // 564 // The following combination of parameters is supported (in the given order): 565 // - Zero or one track, 566 // - Zero or one custom timestamp, 567 // - Arbitrary number of debug annotations. 568 // - Zero or one lambda. 569 570 // Trace point which does not take a track or timestamp. 571 template <typename CategoryType, 572 typename EventNameType, 573 typename... Arguments> 574 static void TraceForCategoryBody( 575 uint32_t instances, 576 const CategoryType& category, 577 const EventNameType& event_name, 578 perfetto::protos::pbzero::TrackEvent::Type type, 579 Arguments&&... args) PERFETTO_NO_INLINE { 580 TraceForCategoryImplNoTimestamp(instances, category, event_name, type, 581 TrackEventInternal::kDefaultTrack, 582 std::forward<Arguments>(args)...); 583 } 584 585 // Trace point which takes a track, but not timestamp. 586 // NOTE: Here track should be captured using universal reference (TrackType&&) 587 // instead of const TrackType& to ensure that the proper overload is selected 588 // (otherwise the compiler will fail to disambiguate between adding const& and 589 // parsing track as a part of Arguments...). 590 template <typename TrackType, 591 typename CategoryType, 592 typename EventNameType, 593 typename... Arguments, 594 typename TrackTypeCheck = typename std::enable_if< 595 std::is_convertible<TrackType, Track>::value>::type> 596 static void TraceForCategoryBody( 597 uint32_t instances, 598 const CategoryType& category, 599 const EventNameType& event_name, 600 perfetto::protos::pbzero::TrackEvent::Type type, 601 TrackType&& track, 602 Arguments&&... args) PERFETTO_NO_INLINE { 603 TraceForCategoryImplNoTimestamp(instances, category, event_name, type, 604 std::forward<TrackType>(track), 605 std::forward<Arguments>(args)...); 606 } 607 608 // Trace point which takes a timestamp, but not track. 609 template <typename CategoryType, 610 typename EventNameType, 611 typename TimestampType = uint64_t, 612 typename... Arguments, 613 typename TimestampTypeCheck = typename std::enable_if< 614 IsValidTimestamp<TimestampType>()>::type> 615 static void TraceForCategoryBody( 616 uint32_t instances, 617 const CategoryType& category, 618 const EventNameType& event_name, 619 perfetto::protos::pbzero::TrackEvent::Type type, 620 TimestampType&& timestamp, 621 Arguments&&... args) PERFETTO_NO_INLINE { 622 TraceForCategoryImpl(instances, category, event_name, type, 623 TrackEventInternal::kDefaultTrack, 624 std::forward<TimestampType>(timestamp), 625 std::forward<Arguments>(args)...); 626 } 627 628 // Trace point which takes a timestamp and a track. 629 template <typename TrackType, 630 typename CategoryType, 631 typename EventNameType, 632 typename TimestampType = uint64_t, 633 typename... Arguments, 634 typename TrackTypeCheck = typename std::enable_if< 635 std::is_convertible<TrackType, Track>::value>::type, 636 typename TimestampTypeCheck = typename std::enable_if< 637 IsValidTimestamp<TimestampType>()>::type> 638 static void TraceForCategoryBody( 639 uint32_t instances, 640 const CategoryType& category, 641 const EventNameType& event_name, 642 perfetto::protos::pbzero::TrackEvent::Type type, 643 TrackType&& track, 644 TimestampType&& timestamp, 645 Arguments&&... args) PERFETTO_NO_INLINE { 646 TraceForCategoryImpl(instances, category, event_name, type, 647 std::forward<TrackType>(track), 648 std::forward<TimestampType>(timestamp), 649 std::forward<Arguments>(args)...); 650 } 651 652 // Trace point with with a counter sample. 653 template <typename CategoryType, typename EventNameType, typename ValueType> 654 static void TraceForCategoryBody( 655 uint32_t instances, 656 const CategoryType& category, 657 const EventNameType&, 658 perfetto::protos::pbzero::TrackEvent::Type type, 659 CounterTrack track, 660 ValueType value) PERFETTO_ALWAYS_INLINE { 661 PERFETTO_DCHECK(type == perfetto::protos::pbzero::TrackEvent::TYPE_COUNTER); 662 TraceForCategory(instances, category, /*name=*/nullptr, type, track, 663 TrackEventInternal::GetTraceTime(), value); 664 } 665 666 // Trace point with with a timestamp and a counter sample. 667 template <typename CategoryType, 668 typename EventNameType, 669 typename TimestampType = uint64_t, 670 typename TimestampTypeCheck = typename std::enable_if< 671 IsValidTimestamp<TimestampType>()>::type, 672 typename ValueType> 673 static void TraceForCategoryBody( 674 uint32_t instances, 675 const CategoryType& category, 676 const EventNameType&, 677 perfetto::protos::pbzero::TrackEvent::Type type, 678 CounterTrack track, 679 TimestampType timestamp, 680 ValueType value) PERFETTO_NO_INLINE { 681 PERFETTO_DCHECK(type == perfetto::protos::pbzero::TrackEvent::TYPE_COUNTER); 682 TraceForCategoryImpl( 683 instances, category, /*name=*/nullptr, type, track, timestamp, 684 [&](EventContext event_ctx) { 685 if (std::is_integral<ValueType>::value) { 686 int64_t value_int64 = static_cast<int64_t>(value); 687 if (track.is_incremental()) { 688 TrackEventIncrementalState* incr_state = 689 event_ctx.GetIncrementalState(); 690 PERFETTO_DCHECK(incr_state != nullptr); 691 auto prv_value = 692 incr_state->last_counter_value_per_track[track.uuid]; 693 event_ctx.event()->set_counter_value(value_int64 - prv_value); 694 prv_value = value_int64; 695 incr_state->last_counter_value_per_track[track.uuid] = prv_value; 696 } else { 697 event_ctx.event()->set_counter_value(value_int64); 698 } 699 } else { 700 event_ctx.event()->set_double_counter_value( 701 static_cast<double>(value)); 702 } 703 }); 704 } 705 706 // Additional trace points used in legacy macros. 707 // It's possible to implement legacy macros using a common TraceForCategory, 708 // by supplying a lambda that sets all necessary legacy fields. But this 709 // results in a binary size bloat because every trace point generates its own 710 // template instantiation with its own lambda. ICF can't eliminate those as 711 // each lambda captures different variables and so the code is not completely 712 // identical. 713 // What we do instead is define additional TraceForCategoryLegacy templates 714 // that take legacy arguments directly. Their instantiations can have the same 715 // binary code for at least some macro invocations and so can be successfully 716 // folded by the linker. 717 #if PERFETTO_ENABLE_LEGACY_TRACE_EVENTS 718 template <typename TrackType, 719 typename CategoryType, 720 typename EventNameType, 721 typename... Arguments, 722 typename TrackTypeCheck = typename std::enable_if< 723 std::is_convertible<TrackType, Track>::value>::type> 724 static void TraceForCategoryLegacyBody( 725 uint32_t instances, 726 const CategoryType& category, 727 const EventNameType& event_name, 728 perfetto::protos::pbzero::TrackEvent::Type type, 729 TrackType&& track, 730 char phase, 731 uint32_t flags, 732 Arguments&&... args) PERFETTO_NO_INLINE { 733 TraceForCategoryImplNoTimestamp( 734 instances, category, event_name, type, track, 735 [&](perfetto::EventContext ctx) PERFETTO_NO_THREAD_SAFETY_ANALYSIS { 736 using ::perfetto::internal::TrackEventLegacy; 737 TrackEventLegacy::WriteLegacyEvent(std::move(ctx), phase, flags, 738 args...); 739 }); 740 } 741 742 template <typename TrackType, 743 typename CategoryType, 744 typename EventNameType, 745 typename TimestampType = uint64_t, 746 typename... Arguments, 747 typename TrackTypeCheck = typename std::enable_if< 748 std::is_convertible<TrackType, Track>::value>::type, 749 typename TimestampTypeCheck = typename std::enable_if< 750 IsValidTimestamp<TimestampType>()>::type> 751 static void TraceForCategoryLegacyBody( 752 uint32_t instances, 753 const CategoryType& category, 754 const EventNameType& event_name, 755 perfetto::protos::pbzero::TrackEvent::Type type, 756 TrackType&& track, 757 char phase, 758 uint32_t flags, 759 TimestampType&& timestamp, 760 Arguments&&... args) PERFETTO_NO_INLINE { 761 TraceForCategoryImpl( 762 instances, category, event_name, type, track, timestamp, 763 [&](perfetto::EventContext ctx) PERFETTO_NO_THREAD_SAFETY_ANALYSIS { 764 using ::perfetto::internal::TrackEventLegacy; 765 TrackEventLegacy::WriteLegacyEvent(std::move(ctx), phase, flags, 766 args...); 767 }); 768 } 769 770 template <typename TrackType, 771 typename CategoryType, 772 typename EventNameType, 773 typename ThreadIdType, 774 typename LegacyIdType, 775 typename... Arguments, 776 typename TrackTypeCheck = typename std::enable_if< 777 std::is_convertible<TrackType, Track>::value>::type> 778 static void TraceForCategoryLegacyWithIdBody( 779 uint32_t instances, 780 const CategoryType& category, 781 const EventNameType& event_name, 782 perfetto::protos::pbzero::TrackEvent::Type type, 783 TrackType&& track, 784 char phase, 785 uint32_t flags, 786 ThreadIdType thread_id, 787 LegacyIdType legacy_id, 788 Arguments&&... args) PERFETTO_NO_INLINE { 789 TraceForCategoryImplNoTimestamp( 790 instances, category, event_name, type, track, 791 [&](perfetto::EventContext ctx) PERFETTO_NO_THREAD_SAFETY_ANALYSIS { 792 using ::perfetto::internal::TrackEventLegacy; 793 ::perfetto::internal::LegacyTraceId trace_id{legacy_id}; 794 TrackEventLegacy::WriteLegacyEventWithIdAndTid( 795 std::move(ctx), phase, flags, trace_id, thread_id, args...); 796 }); 797 } 798 799 template <typename TrackType, 800 typename CategoryType, 801 typename EventNameType, 802 typename ThreadIdType, 803 typename LegacyIdType, 804 typename TimestampType = uint64_t, 805 typename... Arguments, 806 typename TrackTypeCheck = typename std::enable_if< 807 std::is_convertible<TrackType, Track>::value>::type, 808 typename TimestampTypeCheck = typename std::enable_if< 809 IsValidTimestamp<TimestampType>()>::type> 810 static void TraceForCategoryLegacyWithIdBody( 811 uint32_t instances, 812 const CategoryType& category, 813 const EventNameType& event_name, 814 perfetto::protos::pbzero::TrackEvent::Type type, 815 TrackType&& track, 816 char phase, 817 uint32_t flags, 818 ThreadIdType thread_id, 819 LegacyIdType legacy_id, 820 TimestampType&& timestamp, 821 Arguments&&... args) PERFETTO_NO_INLINE { 822 TraceForCategoryImpl( 823 instances, category, event_name, type, track, timestamp, 824 [&](perfetto::EventContext ctx) PERFETTO_NO_THREAD_SAFETY_ANALYSIS { 825 using ::perfetto::internal::TrackEventLegacy; 826 ::perfetto::internal::LegacyTraceId trace_id{legacy_id}; 827 TrackEventLegacy::WriteLegacyEventWithIdAndTid( 828 std::move(ctx), phase, flags, trace_id, thread_id, args...); 829 }); 830 } 831 #endif // PERFETTO_ENABLE_LEGACY_TRACE_EVENTS 832 833 // Each category has its own enabled/disabled state, stored in the category 834 // registry. 835 struct CategoryTracePointTraits { 836 // Each trace point with a static category has an associated category index. 837 struct TracePointData { 838 size_t category_index; 839 }; 840 // Called to get the enabled state bitmap of a given category. 841 // |data| is the trace point data structure given to 842 // DataSource::TraceWithInstances. 843 static constexpr std::atomic<uint8_t>* GetActiveInstances( 844 TracePointData data) { 845 return Registry->GetCategoryState(data.category_index); 846 } 847 }; 848 849 template <typename CategoryType, 850 typename EventNameType, 851 typename TrackType = Track, 852 typename TrackTypeCheck = 853 typename std::enable_if<IsValidTrack<TrackType>()>::type> 854 static perfetto::EventContext WriteTrackEventImpl( 855 typename Base::TraceContext& ctx, 856 const CategoryType& category, 857 const EventNameType& event_name, 858 perfetto::protos::pbzero::TrackEvent::Type type, 859 const TrackType& track, 860 const TraceTimestamp& trace_timestamp) PERFETTO_ALWAYS_INLINE { 861 using CatTraits = CategoryTraits<CategoryType>; 862 const Category* static_category = 863 CatTraits::GetStaticCategory(Registry, category); 864 865 TrackEventTlsState& tls_state = *ctx.GetCustomTlsState(); 866 TraceWriterBase* trace_writer = ctx.tls_inst_->trace_writer.get(); 867 // Make sure incremental state is valid. 868 TrackEventIncrementalState* incr_state = ctx.GetIncrementalState(); 869 TrackEventInternal::ResetIncrementalStateIfRequired( 870 trace_writer, incr_state, tls_state, trace_timestamp); 871 872 // Write the track descriptor before any event on the track. 873 if (track) { 874 TrackEventInternal::WriteTrackDescriptorIfNeeded( 875 track, trace_writer, incr_state, tls_state, trace_timestamp); 876 } 877 878 // Write the event itself. 879 bool on_current_thread_track = 880 (&track == &TrackEventInternal::kDefaultTrack); 881 auto event_ctx = TrackEventInternal::WriteEvent( 882 trace_writer, incr_state, tls_state, static_category, type, 883 trace_timestamp, on_current_thread_track); 884 // event name should be emitted with `TRACE_EVENT_BEGIN` macros 885 // but not with `TRACE_EVENT_END`. 886 if (type != protos::pbzero::TrackEvent::TYPE_SLICE_END) { 887 TrackEventInternal::WriteEventName(event_name, event_ctx, tls_state); 888 } 889 // Write dynamic categories (except for events that don't require 890 // categories). For counter events, the counter name (and optional 891 // category) is stored as part of the track descriptor instead being 892 // recorded with individual events. 893 if (CatTraits::kIsDynamic && 894 type != protos::pbzero::TrackEvent::TYPE_SLICE_END && 895 type != protos::pbzero::TrackEvent::TYPE_COUNTER) { 896 DynamicCategory dynamic_category = 897 CatTraits::GetDynamicCategory(category); 898 Category cat = Category::FromDynamicCategory(dynamic_category); 899 cat.ForEachGroupMember([&](const char* member_name, size_t name_size) { 900 event_ctx.event()->add_categories(member_name, name_size); 901 return true; 902 }); 903 } 904 if (type == protos::pbzero::TrackEvent::TYPE_UNSPECIFIED) { 905 // Explicitly clear the track, so that the event is not associated 906 // with the default track, but instead uses the legacy mechanism 907 // based on the phase and pid/tid override. 908 event_ctx.event()->set_track_uuid(0); 909 } else if (!on_current_thread_track) { 910 // We emit these events using TrackDescriptors, and we cannot emit 911 // events on behalf of other processes using the TrackDescriptor 912 // format. Chrome is the only user of events with explicit process 913 // ids and currently only Chrome emits PHASE_MEMORY_DUMP events 914 // with an explicit process id, so we should be fine here. 915 // TODO(mohitms): Get rid of events with explicit process ids 916 // entirely. 917 event_ctx.event()->set_track_uuid(track.uuid); 918 } 919 920 return event_ctx; 921 } 922 923 template <typename CategoryType, 924 typename EventNameType, 925 typename TrackType = Track, 926 typename TimestampType = uint64_t, 927 typename TimestampTypeCheck = typename std::enable_if< 928 IsValidTimestamp<TimestampType>()>::type, 929 typename TrackTypeCheck = 930 typename std::enable_if<IsValidTrack<TrackType>()>::type> 931 static perfetto::EventContext WriteTrackEvent( 932 typename Base::TraceContext& ctx, 933 const CategoryType& category, 934 const EventNameType& event_name, 935 perfetto::protos::pbzero::TrackEvent::Type type, 936 const TrackType& track, 937 const TimestampType& timestamp) PERFETTO_NO_INLINE { 938 TraceTimestamp trace_timestamp = ::perfetto::TraceTimestampTraits< 939 TimestampType>::ConvertTimestampToTraceTimeNs(timestamp); 940 return WriteTrackEventImpl(ctx, category, event_name, type, track, 941 trace_timestamp); 942 } 943 944 template <typename CategoryType, 945 typename EventNameType, 946 typename TrackType = Track, 947 typename TrackTypeCheck = 948 typename std::enable_if<IsValidTrack<TrackType>()>::type> 949 static perfetto::EventContext WriteTrackEvent( 950 typename Base::TraceContext& ctx, 951 const CategoryType& category, 952 const EventNameType& event_name, 953 perfetto::protos::pbzero::TrackEvent::Type type, 954 const TrackType& track) PERFETTO_NO_INLINE { 955 TraceTimestamp trace_timestamp = TrackEventInternal::GetTraceTime(); 956 return WriteTrackEventImpl(ctx, category, event_name, type, track, 957 trace_timestamp); 958 } 959 960 template <typename CategoryType, 961 typename EventNameType, 962 typename TrackType = Track, 963 typename TimestampType = uint64_t, 964 typename TimestampTypeCheck = typename std::enable_if< 965 IsValidTimestamp<TimestampType>()>::type, 966 typename TrackTypeCheck = 967 typename std::enable_if<IsValidTrack<TrackType>()>::type, 968 typename... Arguments> 969 static void TraceForCategoryImpl( 970 uint32_t instances, 971 const CategoryType& category, 972 const EventNameType& event_name, 973 perfetto::protos::pbzero::TrackEvent::Type type, 974 const TrackType& track, 975 const TimestampType& timestamp, 976 Arguments&&... args) PERFETTO_ALWAYS_INLINE { 977 using CatTraits = CategoryTraits<CategoryType>; 978 TraceWithInstances( 979 instances, category, [&](typename Base::TraceContext ctx) { 980 // If this category is dynamic, first check whether it's enabled. 981 if (CatTraits::kIsDynamic && 982 !IsDynamicCategoryEnabled( 983 &ctx, CatTraits::GetDynamicCategory(category))) { 984 return; 985 } 986 987 auto event_ctx = WriteTrackEvent(ctx, category, event_name, type, 988 track, timestamp); 989 WriteTrackEventArgs(std::move(event_ctx), 990 std::forward<Arguments>(args)...); 991 }); 992 } 993 994 template <typename CategoryType, 995 typename EventNameType, 996 typename TrackType = Track, 997 typename TrackTypeCheck = 998 typename std::enable_if<IsValidTrack<TrackType>()>::type, 999 typename... Arguments> 1000 static void TraceForCategoryImplNoTimestamp( 1001 uint32_t instances, 1002 const CategoryType& category, 1003 const EventNameType& event_name, 1004 perfetto::protos::pbzero::TrackEvent::Type type, 1005 const TrackType& track, 1006 Arguments&&... args) PERFETTO_ALWAYS_INLINE { 1007 using CatTraits = CategoryTraits<CategoryType>; 1008 TraceWithInstances( 1009 instances, category, [&](typename Base::TraceContext ctx) { 1010 // If this category is dynamic, first check whether it's enabled. 1011 if (CatTraits::kIsDynamic && 1012 !IsDynamicCategoryEnabled( 1013 &ctx, CatTraits::GetDynamicCategory(category))) { 1014 return; 1015 } 1016 1017 auto event_ctx = 1018 WriteTrackEvent(ctx, category, event_name, type, track); 1019 WriteTrackEventArgs(std::move(event_ctx), 1020 std::forward<Arguments>(args)...); 1021 }); 1022 } 1023 1024 template <typename CategoryType, typename Lambda> 1025 static void TraceWithInstances(uint32_t instances, 1026 const CategoryType& category, 1027 Lambda lambda) PERFETTO_ALWAYS_INLINE { 1028 using CatTraits = CategoryTraits<CategoryType>; 1029 if (CatTraits::kIsDynamic) { 1030 Base::TraceWithInstances(instances, std::move(lambda)); 1031 } else { 1032 Base::template TraceWithInstances<CategoryTracePointTraits>( 1033 instances, std::move(lambda), {CatTraits::GetStaticIndex(category)}); 1034 } 1035 } 1036 1037 // Determines if the given dynamic category is enabled, first by checking the 1038 // per-trace writer cache or by falling back to computing it based on the 1039 // trace config for the given session. 1040 static bool IsDynamicCategoryEnabled( 1041 typename Base::TraceContext* ctx, 1042 const DynamicCategory& dynamic_category) { 1043 auto incr_state = ctx->GetIncrementalState(); 1044 auto it = incr_state->dynamic_categories.find(dynamic_category.name); 1045 if (it == incr_state->dynamic_categories.end()) { 1046 // We haven't seen this category before. Let's figure out if it's enabled. 1047 // This requires grabbing a lock to read the session's trace config. 1048 auto ds = ctx->GetDataSourceLocked(); 1049 if (!ds) { 1050 return false; 1051 } 1052 Category category{Category::FromDynamicCategory(dynamic_category)}; 1053 bool enabled = TrackEventInternal::IsCategoryEnabled( 1054 *Registry, ds->config_, category); 1055 // TODO(skyostil): Cap the size of |dynamic_categories|. 1056 incr_state->dynamic_categories[dynamic_category.name] = enabled; 1057 return enabled; 1058 } 1059 return it->second; 1060 } 1061 1062 // Config for the current tracing session. 1063 protos::gen::TrackEventConfig config_; 1064 }; 1065 1066 } // namespace internal 1067 } // namespace perfetto 1068 1069 #endif // INCLUDE_PERFETTO_TRACING_INTERNAL_TRACK_EVENT_DATA_SOURCE_H_ 1070