• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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