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