• 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 #include "perfetto/tracing/internal/track_event_internal.h"
18 
19 #include "perfetto/base/proc_utils.h"
20 #include "perfetto/base/time.h"
21 #include "perfetto/tracing/core/data_source_config.h"
22 #include "perfetto/tracing/internal/track_event_interned_fields.h"
23 #include "perfetto/tracing/track_event.h"
24 #include "perfetto/tracing/track_event_category_registry.h"
25 #include "perfetto/tracing/track_event_interned_data_index.h"
26 #include "protos/perfetto/common/data_source_descriptor.gen.h"
27 #include "protos/perfetto/common/track_event_descriptor.pbzero.h"
28 #include "protos/perfetto/trace/clock_snapshot.pbzero.h"
29 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
30 #include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
31 #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
32 #include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
33 
34 using perfetto::protos::pbzero::ClockSnapshot;
35 
36 namespace perfetto {
37 
38 TrackEventSessionObserver::~TrackEventSessionObserver() = default;
OnSetup(const DataSourceBase::SetupArgs &)39 void TrackEventSessionObserver::OnSetup(const DataSourceBase::SetupArgs&) {}
OnStart(const DataSourceBase::StartArgs &)40 void TrackEventSessionObserver::OnStart(const DataSourceBase::StartArgs&) {}
OnStop(const DataSourceBase::StopArgs &)41 void TrackEventSessionObserver::OnStop(const DataSourceBase::StopArgs&) {}
WillClearIncrementalState(const DataSourceBase::ClearIncrementalStateArgs &)42 void TrackEventSessionObserver::WillClearIncrementalState(
43     const DataSourceBase::ClearIncrementalStateArgs&) {}
44 
45 TrackEventTlsStateUserData::~TrackEventTlsStateUserData() = default;
46 
47 namespace internal {
48 
49 BaseTrackEventInternedDataIndex::~BaseTrackEventInternedDataIndex() = default;
50 
51 namespace {
52 
53 static constexpr const char kLegacySlowPrefix[] = "disabled-by-default-";
54 static constexpr const char kSlowTag[] = "slow";
55 static constexpr const char kDebugTag[] = "debug";
56 static constexpr const char kFilteredEventName[] = "FILTERED";
57 
58 constexpr auto kClockIdIncremental =
59     TrackEventIncrementalState::kClockIdIncremental;
60 
61 constexpr auto kClockIdAbsolute = TrackEventIncrementalState::kClockIdAbsolute;
62 
63 class TrackEventSessionObserverRegistry {
64  public:
GetInstance()65   static TrackEventSessionObserverRegistry* GetInstance() {
66     static TrackEventSessionObserverRegistry* instance =
67         new TrackEventSessionObserverRegistry();  // leaked
68     return instance;
69   }
70 
AddObserverForRegistry(const TrackEventCategoryRegistry & registry,TrackEventSessionObserver * observer)71   void AddObserverForRegistry(const TrackEventCategoryRegistry& registry,
72                               TrackEventSessionObserver* observer) {
73     std::unique_lock<std::recursive_mutex> lock(mutex_);
74     observers_.emplace_back(&registry, observer);
75   }
76 
RemoveObserverForRegistry(const TrackEventCategoryRegistry & registry,TrackEventSessionObserver * observer)77   void RemoveObserverForRegistry(const TrackEventCategoryRegistry& registry,
78                                  TrackEventSessionObserver* observer) {
79     std::unique_lock<std::recursive_mutex> lock(mutex_);
80     observers_.erase(std::remove(observers_.begin(), observers_.end(),
81                                  RegisteredObserver(&registry, observer)),
82                      observers_.end());
83   }
84 
ForEachObserverForRegistry(const TrackEventCategoryRegistry & registry,std::function<void (TrackEventSessionObserver *)> callback)85   void ForEachObserverForRegistry(
86       const TrackEventCategoryRegistry& registry,
87       std::function<void(TrackEventSessionObserver*)> callback) {
88     std::unique_lock<std::recursive_mutex> lock(mutex_);
89     for (auto& registered_observer : observers_) {
90       if (&registry == registered_observer.registry) {
91         callback(registered_observer.observer);
92       }
93     }
94   }
95 
96  private:
97   struct RegisteredObserver {
RegisteredObserverperfetto::internal::__anon4f01de9d0111::TrackEventSessionObserverRegistry::RegisteredObserver98     RegisteredObserver(const TrackEventCategoryRegistry* r,
99                        TrackEventSessionObserver* o)
100         : registry(r), observer(o) {}
operator ==perfetto::internal::__anon4f01de9d0111::TrackEventSessionObserverRegistry::RegisteredObserver101     bool operator==(const RegisteredObserver& other) {
102       return registry == other.registry && observer == other.observer;
103     }
104     const TrackEventCategoryRegistry* registry;
105     TrackEventSessionObserver* observer;
106   };
107 
108   std::recursive_mutex mutex_;
109   std::vector<RegisteredObserver> observers_;
110 };
111 
112 enum class MatchType { kExact, kPattern };
113 
NameMatchesPattern(const std::string & pattern,const std::string & name,MatchType match_type)114 bool NameMatchesPattern(const std::string& pattern,
115                         const std::string& name,
116                         MatchType match_type) {
117   // To avoid pulling in all of std::regex, for now we only support a single "*"
118   // wildcard at the end of the pattern.
119   size_t i = pattern.find('*');
120   if (i != std::string::npos) {
121     PERFETTO_DCHECK(i == pattern.size() - 1);
122     if (match_type != MatchType::kPattern)
123       return false;
124     return name.substr(0, i) == pattern.substr(0, i);
125   }
126   return name == pattern;
127 }
128 
NameMatchesPatternList(const std::vector<std::string> & patterns,const std::string & name,MatchType match_type)129 bool NameMatchesPatternList(const std::vector<std::string>& patterns,
130                             const std::string& name,
131                             MatchType match_type) {
132   for (const auto& pattern : patterns) {
133     if (NameMatchesPattern(pattern, name, match_type))
134       return true;
135   }
136   return false;
137 }
138 
139 }  // namespace
140 
141 // static
142 const Track TrackEventInternal::kDefaultTrack{};
143 
144 // static
145 std::atomic<int> TrackEventInternal::session_count_{};
146 
147 // static
Initialize(const TrackEventCategoryRegistry & registry,bool (* register_data_source)(const DataSourceDescriptor &))148 bool TrackEventInternal::Initialize(
149     const TrackEventCategoryRegistry& registry,
150     bool (*register_data_source)(const DataSourceDescriptor&)) {
151   DataSourceDescriptor dsd;
152   dsd.set_name("track_event");
153 
154   protozero::HeapBuffered<protos::pbzero::TrackEventDescriptor> ted;
155   for (size_t i = 0; i < registry.category_count(); i++) {
156     auto category = registry.GetCategory(i);
157     // Don't register group categories.
158     if (category->IsGroup())
159       continue;
160     auto cat = ted->add_available_categories();
161     cat->set_name(category->name);
162     if (category->description)
163       cat->set_description(category->description);
164     for (const auto& tag : category->tags) {
165       if (tag)
166         cat->add_tags(tag);
167     }
168     // Disabled-by-default categories get a "slow" tag.
169     if (!strncmp(category->name, kLegacySlowPrefix, strlen(kLegacySlowPrefix)))
170       cat->add_tags(kSlowTag);
171   }
172   dsd.set_track_event_descriptor_raw(ted.SerializeAsString());
173 
174   return register_data_source(dsd);
175 }
176 
177 // static
AddSessionObserver(const TrackEventCategoryRegistry & registry,TrackEventSessionObserver * observer)178 bool TrackEventInternal::AddSessionObserver(
179     const TrackEventCategoryRegistry& registry,
180     TrackEventSessionObserver* observer) {
181   TrackEventSessionObserverRegistry::GetInstance()->AddObserverForRegistry(
182       registry, observer);
183   return true;
184 }
185 
186 // static
RemoveSessionObserver(const TrackEventCategoryRegistry & registry,TrackEventSessionObserver * observer)187 void TrackEventInternal::RemoveSessionObserver(
188     const TrackEventCategoryRegistry& registry,
189     TrackEventSessionObserver* observer) {
190   TrackEventSessionObserverRegistry::GetInstance()->RemoveObserverForRegistry(
191       registry, observer);
192 }
193 
194 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) && \
195     !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
196 static constexpr protos::pbzero::BuiltinClock kDefaultTraceClock =
197     protos::pbzero::BUILTIN_CLOCK_BOOTTIME;
198 #else
199 static constexpr protos::pbzero::BuiltinClock kDefaultTraceClock =
200     protos::pbzero::BUILTIN_CLOCK_MONOTONIC;
201 #endif
202 
203 // static
204 protos::pbzero::BuiltinClock TrackEventInternal::clock_ = kDefaultTraceClock;
205 
206 // static
207 bool TrackEventInternal::disallow_merging_with_system_tracks_ = false;
208 
209 // static
EnableTracing(const TrackEventCategoryRegistry & registry,const protos::gen::TrackEventConfig & config,const DataSourceBase::SetupArgs & args)210 void TrackEventInternal::EnableTracing(
211     const TrackEventCategoryRegistry& registry,
212     const protos::gen::TrackEventConfig& config,
213     const DataSourceBase::SetupArgs& args) {
214   for (size_t i = 0; i < registry.category_count(); i++) {
215     if (IsCategoryEnabled(registry, config, *registry.GetCategory(i)))
216       registry.EnableCategoryForInstance(i, args.internal_instance_index);
217   }
218   TrackEventSessionObserverRegistry::GetInstance()->ForEachObserverForRegistry(
219       registry, [&](TrackEventSessionObserver* o) { o->OnSetup(args); });
220 }
221 
222 // static
OnStart(const TrackEventCategoryRegistry & registry,const DataSourceBase::StartArgs & args)223 void TrackEventInternal::OnStart(const TrackEventCategoryRegistry& registry,
224                                  const DataSourceBase::StartArgs& args) {
225   session_count_.fetch_add(1);
226   TrackEventSessionObserverRegistry::GetInstance()->ForEachObserverForRegistry(
227       registry, [&](TrackEventSessionObserver* o) { o->OnStart(args); });
228 }
229 
230 // static
OnStop(const TrackEventCategoryRegistry & registry,const DataSourceBase::StopArgs & args)231 void TrackEventInternal::OnStop(const TrackEventCategoryRegistry& registry,
232                                 const DataSourceBase::StopArgs& args) {
233   TrackEventSessionObserverRegistry::GetInstance()->ForEachObserverForRegistry(
234       registry, [&](TrackEventSessionObserver* o) { o->OnStop(args); });
235 }
236 
237 // static
DisableTracing(const TrackEventCategoryRegistry & registry,uint32_t internal_instance_index)238 void TrackEventInternal::DisableTracing(
239     const TrackEventCategoryRegistry& registry,
240     uint32_t internal_instance_index) {
241   for (size_t i = 0; i < registry.category_count(); i++)
242     registry.DisableCategoryForInstance(i, internal_instance_index);
243 }
244 
245 // static
WillClearIncrementalState(const TrackEventCategoryRegistry & registry,const DataSourceBase::ClearIncrementalStateArgs & args)246 void TrackEventInternal::WillClearIncrementalState(
247     const TrackEventCategoryRegistry& registry,
248     const DataSourceBase::ClearIncrementalStateArgs& args) {
249   TrackEventSessionObserverRegistry::GetInstance()->ForEachObserverForRegistry(
250       registry, [&](TrackEventSessionObserver* o) {
251         o->WillClearIncrementalState(args);
252       });
253 }
254 
255 // static
IsCategoryEnabled(const TrackEventCategoryRegistry & registry,const protos::gen::TrackEventConfig & config,const Category & category)256 bool TrackEventInternal::IsCategoryEnabled(
257     const TrackEventCategoryRegistry& registry,
258     const protos::gen::TrackEventConfig& config,
259     const Category& category) {
260   // If this is a group category, check if any of its constituent categories are
261   // enabled. If so, then this one is enabled too.
262   if (category.IsGroup()) {
263     bool result = false;
264     category.ForEachGroupMember([&](const char* member_name, size_t name_size) {
265       for (size_t i = 0; i < registry.category_count(); i++) {
266         const auto ref_category = registry.GetCategory(i);
267         // Groups can't refer to other groups.
268         if (ref_category->IsGroup())
269           continue;
270         // Require an exact match.
271         if (ref_category->name_size() != name_size ||
272             strncmp(ref_category->name, member_name, name_size)) {
273           continue;
274         }
275         if (IsCategoryEnabled(registry, config, *ref_category)) {
276           result = true;
277           // Break ForEachGroupMember() loop.
278           return false;
279         }
280         break;
281       }
282       // No match? Must be a dynamic category.
283       DynamicCategory dyn_category(std::string(member_name, name_size));
284       Category ref_category{Category::FromDynamicCategory(dyn_category)};
285       if (IsCategoryEnabled(registry, config, ref_category)) {
286         result = true;
287         // Break ForEachGroupMember() loop.
288         return false;
289       }
290       // No match found => keep iterating.
291       return true;
292     });
293     return result;
294   }
295 
296   auto has_matching_tag = [&](std::function<bool(const char*)> matcher) {
297     for (const auto& tag : category.tags) {
298       if (!tag)
299         break;
300       if (matcher(tag))
301         return true;
302     }
303     // Legacy "disabled-by-default" categories automatically get the "slow" tag.
304     if (!strncmp(category.name, kLegacySlowPrefix, strlen(kLegacySlowPrefix)) &&
305         matcher(kSlowTag)) {
306       return true;
307     }
308     return false;
309   };
310 
311   // First try exact matches, then pattern matches.
312   const std::array<MatchType, 2> match_types = {
313       {MatchType::kExact, MatchType::kPattern}};
314   for (auto match_type : match_types) {
315     // 1. Enabled categories.
316     if (NameMatchesPatternList(config.enabled_categories(), category.name,
317                                match_type)) {
318       return true;
319     }
320 
321     // 2. Enabled tags.
322     if (has_matching_tag([&](const char* tag) {
323           return NameMatchesPatternList(config.enabled_tags(), tag, match_type);
324         })) {
325       return true;
326     }
327 
328     // 2.5. A special case for Chrome's legacy disabled-by-default categories.
329     // We treat them as having a "slow" tag with one exception: they can be
330     // enabled by a pattern if the pattern starts with "disabled-by-default-"
331     // itself.
332     if (match_type == MatchType::kExact &&
333         !strncmp(category.name, kLegacySlowPrefix, strlen(kLegacySlowPrefix))) {
334       for (const auto& pattern : config.enabled_categories()) {
335         if (!strncmp(pattern.c_str(), kLegacySlowPrefix,
336                      strlen(kLegacySlowPrefix)) &&
337             NameMatchesPattern(pattern, category.name, MatchType::kPattern)) {
338           return true;
339         }
340       }
341     }
342 
343     // 3. Disabled categories.
344     if (NameMatchesPatternList(config.disabled_categories(), category.name,
345                                match_type)) {
346       return false;
347     }
348 
349     // 4. Disabled tags.
350     if (has_matching_tag([&](const char* tag) {
351           if (config.disabled_tags_size()) {
352             return NameMatchesPatternList(config.disabled_tags(), tag,
353                                           match_type);
354           } else {
355             // The "slow" and "debug" tags are disabled by default.
356             return NameMatchesPattern(kSlowTag, tag, match_type) ||
357                    NameMatchesPattern(kDebugTag, tag, match_type);
358           }
359         })) {
360       return false;
361     }
362   }
363 
364   // If nothing matched, enable the category by default.
365   return true;
366 }
367 
368 // static
GetTimeNs()369 uint64_t TrackEventInternal::GetTimeNs() {
370   if (GetClockId() == protos::pbzero::BUILTIN_CLOCK_BOOTTIME)
371     return static_cast<uint64_t>(perfetto::base::GetBootTimeNs().count());
372   else if (GetClockId() == protos::pbzero::BUILTIN_CLOCK_MONOTONIC)
373     return static_cast<uint64_t>(perfetto::base::GetWallTimeNs().count());
374   PERFETTO_DCHECK(GetClockId() == protos::pbzero::BUILTIN_CLOCK_MONOTONIC_RAW);
375   return static_cast<uint64_t>(perfetto::base::GetWallTimeRawNs().count());
376 }
377 
378 // static
GetTraceTime()379 TraceTimestamp TrackEventInternal::GetTraceTime() {
380   return {kClockIdIncremental, GetTimeNs()};
381 }
382 
383 // static
GetSessionCount()384 int TrackEventInternal::GetSessionCount() {
385   return session_count_.load();
386 }
387 
388 // static
ResetIncrementalState(TraceWriterBase * trace_writer,TrackEventIncrementalState * incr_state,const TrackEventTlsState & tls_state,const TraceTimestamp & timestamp)389 void TrackEventInternal::ResetIncrementalState(
390     TraceWriterBase* trace_writer,
391     TrackEventIncrementalState* incr_state,
392     const TrackEventTlsState& tls_state,
393     const TraceTimestamp& timestamp) {
394   auto sequence_timestamp = timestamp;
395   if (timestamp.clock_id != kClockIdIncremental) {
396     sequence_timestamp = TrackEventInternal::GetTraceTime();
397   }
398 
399   incr_state->last_timestamp_ns = sequence_timestamp.value;
400   auto default_track = ThreadTrack::Current();
401   auto ts_unit_multiplier = tls_state.timestamp_unit_multiplier;
402   auto thread_time_counter_track =
403       CounterTrack("thread_time", default_track)
404           .set_is_incremental(true)
405           .set_unit_multiplier(static_cast<int64_t>(ts_unit_multiplier))
406           .set_type(protos::gen::CounterDescriptor::COUNTER_THREAD_TIME_NS);
407   {
408     // Mark any incremental state before this point invalid. Also set up
409     // defaults so that we don't need to repeat constant data for each packet.
410     auto packet = NewTracePacket(
411         trace_writer, incr_state, tls_state, timestamp,
412         protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED);
413     auto defaults = packet->set_trace_packet_defaults();
414     defaults->set_timestamp_clock_id(tls_state.default_clock);
415     // Establish the default track for this event sequence.
416     auto track_defaults = defaults->set_track_event_defaults();
417     track_defaults->set_track_uuid(default_track.uuid);
418     if (tls_state.enable_thread_time_sampling) {
419       track_defaults->add_extra_counter_track_uuids(
420           thread_time_counter_track.uuid);
421     }
422 
423     if (tls_state.default_clock != static_cast<uint32_t>(GetClockId())) {
424       ClockSnapshot* clocks = packet->set_clock_snapshot();
425       // Trace clock.
426       ClockSnapshot::Clock* trace_clock = clocks->add_clocks();
427       trace_clock->set_clock_id(static_cast<uint32_t>(GetClockId()));
428       trace_clock->set_timestamp(sequence_timestamp.value);
429 
430       if (PERFETTO_LIKELY(tls_state.default_clock == kClockIdIncremental)) {
431         // Delta-encoded incremental clock in nanoseconds by default but
432         // configurable by |tls_state.timestamp_unit_multiplier|.
433         ClockSnapshot::Clock* clock_incremental = clocks->add_clocks();
434         clock_incremental->set_clock_id(kClockIdIncremental);
435         clock_incremental->set_timestamp(sequence_timestamp.value /
436                                          ts_unit_multiplier);
437         clock_incremental->set_is_incremental(true);
438         clock_incremental->set_unit_multiplier_ns(ts_unit_multiplier);
439       }
440       if (ts_unit_multiplier > 1) {
441         // absolute clock with custom timestamp_unit_multiplier.
442         ClockSnapshot::Clock* absolute_clock = clocks->add_clocks();
443         absolute_clock->set_clock_id(kClockIdAbsolute);
444         absolute_clock->set_timestamp(sequence_timestamp.value /
445                                       ts_unit_multiplier);
446         absolute_clock->set_is_incremental(false);
447         absolute_clock->set_unit_multiplier_ns(ts_unit_multiplier);
448       }
449     }
450   }
451 
452   // Every thread should write a descriptor for its default track, because most
453   // trace points won't explicitly reference it. We also write the process
454   // descriptor from every thread that writes trace events to ensure it gets
455   // emitted at least once.
456   WriteTrackDescriptor(default_track, trace_writer, incr_state, tls_state,
457                        sequence_timestamp);
458 
459   WriteTrackDescriptor(ProcessTrack::Current(), trace_writer, incr_state,
460                        tls_state, sequence_timestamp);
461 
462   if (tls_state.enable_thread_time_sampling) {
463     WriteTrackDescriptor(thread_time_counter_track, trace_writer, incr_state,
464                          tls_state, sequence_timestamp);
465   }
466 }
467 
468 // static
469 protozero::MessageHandle<protos::pbzero::TracePacket>
NewTracePacket(TraceWriterBase * trace_writer,TrackEventIncrementalState * incr_state,const TrackEventTlsState & tls_state,TraceTimestamp timestamp,uint32_t seq_flags)470 TrackEventInternal::NewTracePacket(TraceWriterBase* trace_writer,
471                                    TrackEventIncrementalState* incr_state,
472                                    const TrackEventTlsState& tls_state,
473                                    TraceTimestamp timestamp,
474                                    uint32_t seq_flags) {
475   if (PERFETTO_UNLIKELY(tls_state.default_clock != kClockIdIncremental &&
476                         timestamp.clock_id == kClockIdIncremental)) {
477     timestamp.clock_id = tls_state.default_clock;
478   }
479   auto packet = trace_writer->NewTracePacket();
480   auto ts_unit_multiplier = tls_state.timestamp_unit_multiplier;
481   if (PERFETTO_LIKELY(timestamp.clock_id == kClockIdIncremental)) {
482     if (PERFETTO_LIKELY(incr_state->last_timestamp_ns <= timestamp.value)) {
483       // No need to set the clock id here, since kClockIdIncremental is the
484       // clock id assumed by default.
485       auto time_diff_ns = timestamp.value - incr_state->last_timestamp_ns;
486       auto time_diff_units = time_diff_ns / ts_unit_multiplier;
487       packet->set_timestamp(time_diff_units);
488       incr_state->last_timestamp_ns += time_diff_units * ts_unit_multiplier;
489     } else {
490       packet->set_timestamp(timestamp.value / ts_unit_multiplier);
491       packet->set_timestamp_clock_id(ts_unit_multiplier == 1
492                                          ? static_cast<uint32_t>(GetClockId())
493                                          : kClockIdAbsolute);
494     }
495   } else if (PERFETTO_LIKELY(timestamp.clock_id == tls_state.default_clock)) {
496     packet->set_timestamp(timestamp.value / ts_unit_multiplier);
497   } else {
498     packet->set_timestamp(timestamp.value);
499     packet->set_timestamp_clock_id(timestamp.clock_id);
500   }
501   packet->set_sequence_flags(seq_flags);
502   return packet;
503 }
504 
505 // static
WriteEventName(StaticString event_name,perfetto::EventContext & event_ctx,const TrackEventTlsState &)506 void TrackEventInternal::WriteEventName(StaticString event_name,
507                                         perfetto::EventContext& event_ctx,
508                                         const TrackEventTlsState&) {
509   if (PERFETTO_LIKELY(event_name.value != nullptr)) {
510     size_t name_iid = InternedEventName::Get(&event_ctx, event_name.value);
511     event_ctx.event()->set_name_iid(name_iid);
512   }
513 }
514 
515 // static
WriteEventName(perfetto::DynamicString event_name,perfetto::EventContext & event_ctx,const TrackEventTlsState & tls_state)516 void TrackEventInternal::WriteEventName(perfetto::DynamicString event_name,
517                                         perfetto::EventContext& event_ctx,
518                                         const TrackEventTlsState& tls_state) {
519   if (PERFETTO_UNLIKELY(tls_state.filter_dynamic_event_names)) {
520     event_ctx.event()->set_name(kFilteredEventName,
521                                 sizeof(kFilteredEventName) - 1);
522   } else {
523     event_ctx.event()->set_name(event_name.value, event_name.length);
524   }
525 }
526 
527 // static
WriteEvent(TraceWriterBase * trace_writer,TrackEventIncrementalState * incr_state,TrackEventTlsState & tls_state,const Category * category,perfetto::protos::pbzero::TrackEvent::Type type,const TraceTimestamp & timestamp,bool on_current_thread_track)528 EventContext TrackEventInternal::WriteEvent(
529     TraceWriterBase* trace_writer,
530     TrackEventIncrementalState* incr_state,
531     TrackEventTlsState& tls_state,
532     const Category* category,
533     perfetto::protos::pbzero::TrackEvent::Type type,
534     const TraceTimestamp& timestamp,
535     bool on_current_thread_track) {
536   PERFETTO_DCHECK(!incr_state->was_cleared);
537   auto packet = NewTracePacket(trace_writer, incr_state, tls_state, timestamp);
538   EventContext ctx(trace_writer, std::move(packet), incr_state, &tls_state);
539 
540   auto track_event = ctx.event();
541   if (type != protos::pbzero::TrackEvent::TYPE_UNSPECIFIED)
542     track_event->set_type(type);
543 
544   if (tls_state.enable_thread_time_sampling && on_current_thread_track) {
545     int64_t thread_time_ns = base::GetThreadCPUTimeNs().count();
546     auto thread_time_delta_ns =
547         thread_time_ns - incr_state->last_thread_time_ns;
548     incr_state->last_thread_time_ns = thread_time_ns;
549     track_event->add_extra_counter_values(
550         thread_time_delta_ns /
551         static_cast<int64_t>(tls_state.timestamp_unit_multiplier));
552   }
553 
554   // We assume that |category| points to the string with static lifetime.
555   // This means we can use their addresses as interning keys.
556   // TODO(skyostil): Intern categories at compile time.
557   if (category && type != protos::pbzero::TrackEvent::TYPE_SLICE_END &&
558       type != protos::pbzero::TrackEvent::TYPE_COUNTER) {
559     category->ForEachGroupMember(
560         [&](const char* member_name, size_t name_size) {
561           size_t category_iid =
562               InternedEventCategory::Get(&ctx, member_name, name_size);
563           track_event->add_category_iids(category_iid);
564           return true;
565         });
566   }
567   return ctx;
568 }
569 
570 // static
AddDebugAnnotation(perfetto::EventContext * event_ctx,const char * name)571 protos::pbzero::DebugAnnotation* TrackEventInternal::AddDebugAnnotation(
572     perfetto::EventContext* event_ctx,
573     const char* name) {
574   auto annotation = event_ctx->event()->add_debug_annotations();
575   annotation->set_name_iid(InternedDebugAnnotationName::Get(event_ctx, name));
576   return annotation;
577 }
578 
579 // static
AddDebugAnnotation(perfetto::EventContext * event_ctx,perfetto::DynamicString name)580 protos::pbzero::DebugAnnotation* TrackEventInternal::AddDebugAnnotation(
581     perfetto::EventContext* event_ctx,
582     perfetto::DynamicString name) {
583   auto annotation = event_ctx->event()->add_debug_annotations();
584   annotation->set_name(name.value);
585   return annotation;
586 }
587 
588 }  // namespace internal
589 }  // namespace perfetto
590