• 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/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