xref: /aosp_15_r20/external/perfetto/src/shared_lib/track_event.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2023 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/public/abi/track_event_abi.h"
18 #include "perfetto/public/abi/track_event_hl_abi.h"
19 #include "perfetto/public/abi/track_event_ll_abi.h"
20 
21 #include <algorithm>
22 #include <atomic>
23 #include <limits>
24 #include <mutex>
25 #include <optional>
26 
27 #include "perfetto/base/compiler.h"
28 #include "perfetto/base/flat_set.h"
29 #include "perfetto/base/thread_annotations.h"
30 #include "perfetto/ext/base/file_utils.h"
31 #include "perfetto/ext/base/no_destructor.h"
32 #include "perfetto/ext/base/string_splitter.h"
33 #include "perfetto/ext/base/string_view.h"
34 #include "perfetto/ext/base/thread_utils.h"
35 #include "perfetto/protozero/contiguous_memory_range.h"
36 #include "perfetto/public/compiler.h"
37 #include "perfetto/tracing/data_source.h"
38 #include "perfetto/tracing/internal/basic_types.h"
39 #include "perfetto/tracing/internal/data_source_internal.h"
40 #include "perfetto/tracing/internal/track_event_internal.h"
41 #include "perfetto/tracing/track.h"
42 #include "protos/perfetto/common/data_source_descriptor.gen.h"
43 #include "protos/perfetto/common/track_event_descriptor.pbzero.h"
44 #include "protos/perfetto/config/data_source_config.gen.h"
45 #include "protos/perfetto/config/track_event/track_event_config.gen.h"
46 #include "protos/perfetto/trace/clock_snapshot.pbzero.h"
47 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
48 #include "protos/perfetto/trace/trace_packet.pbzero.h"
49 #include "protos/perfetto/trace/trace_packet_defaults.pbzero.h"
50 #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
51 #include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
52 #include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
53 #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
54 #include "src/shared_lib/intern_map.h"
55 #include "src/shared_lib/reset_for_testing.h"
56 
57 struct PerfettoTeCategoryImpl* perfetto_te_any_categories;
58 
59 PERFETTO_ATOMIC(bool) * perfetto_te_any_categories_enabled;
60 
61 uint64_t perfetto_te_process_track_uuid;
62 
63 struct PerfettoTeCategoryImpl {
64   std::atomic<bool> flag{false};
65   std::atomic<uint8_t> instances{0};
66   PerfettoTeCategoryDescriptor* desc = nullptr;
67   uint64_t cat_iid = 0;
68   PerfettoTeCategoryImplCallback cb = nullptr;
69   void* cb_user_arg = nullptr;
70 };
71 
72 enum class MatchType { kExact, kPattern };
73 
NameMatchesPattern(const std::string & pattern,const perfetto::base::StringView & name,MatchType match_type)74 static bool NameMatchesPattern(const std::string& pattern,
75                                const perfetto::base::StringView& name,
76                                MatchType match_type) {
77   // To avoid pulling in all of std::regex, for now we only support a single "*"
78   // wildcard at the end of the pattern.
79   size_t i = pattern.find('*');
80   if (i != std::string::npos) {
81     if (match_type != MatchType::kPattern)
82       return false;
83     return name.substr(0, i) ==
84            perfetto::base::StringView(pattern).substr(0, i);
85   }
86   return name == perfetto::base::StringView(pattern);
87 }
88 
NameMatchesPatternList(const std::vector<std::string> & patterns,const perfetto::base::StringView & name,MatchType match_type)89 static bool NameMatchesPatternList(const std::vector<std::string>& patterns,
90                                    const perfetto::base::StringView& name,
91                                    MatchType match_type) {
92   for (const auto& pattern : patterns) {
93     if (NameMatchesPattern(pattern, name, match_type))
94       return true;
95   }
96   return false;
97 }
98 
IsSingleCategoryEnabled(const PerfettoTeCategoryDescriptor & c,const perfetto::protos::gen::TrackEventConfig & config)99 static bool IsSingleCategoryEnabled(
100     const PerfettoTeCategoryDescriptor& c,
101     const perfetto::protos::gen::TrackEventConfig& config) {
102   auto has_matching_tag = [&](std::function<bool(const char*)> matcher) {
103     for (size_t i = 0; i < c.num_tags; ++i) {
104       if (matcher(c.tags[i]))
105         return true;
106     }
107     return false;
108   };
109   // First try exact matches, then pattern matches.
110   const std::array<MatchType, 2> match_types = {
111       {MatchType::kExact, MatchType::kPattern}};
112   for (auto match_type : match_types) {
113     // 1. Enabled categories.
114     if (NameMatchesPatternList(config.enabled_categories(), c.name,
115                                match_type)) {
116       return true;
117     }
118 
119     // 2. Enabled tags.
120     if (has_matching_tag([&](const char* tag) {
121           return NameMatchesPatternList(config.enabled_tags(), tag, match_type);
122         })) {
123       return true;
124     }
125 
126     // 3. Disabled categories.
127     if (NameMatchesPatternList(config.disabled_categories(), c.name,
128                                match_type)) {
129       return false;
130     }
131 
132     // 4. Disabled tags.
133     if (has_matching_tag([&](const char* tag) {
134           return NameMatchesPatternList(config.disabled_tags(), tag,
135                                         match_type);
136         })) {
137       return false;
138     }
139   }
140 
141   // If nothing matched, the category is disabled by default. N.B. this behavior
142   // is different than the C++ TrackEvent API.
143   return false;
144 }
145 
IsRegisteredCategoryEnabled(const PerfettoTeCategoryImpl & cat,const perfetto::protos::gen::TrackEventConfig & config)146 static bool IsRegisteredCategoryEnabled(
147     const PerfettoTeCategoryImpl& cat,
148     const perfetto::protos::gen::TrackEventConfig& config) {
149   if (!cat.desc) {
150     return false;
151   }
152   return IsSingleCategoryEnabled(*cat.desc, config);
153 }
154 
EnableRegisteredCategory(PerfettoTeCategoryImpl * cat,uint32_t instance_index)155 static void EnableRegisteredCategory(PerfettoTeCategoryImpl* cat,
156                                      uint32_t instance_index) {
157   PERFETTO_DCHECK(instance_index < perfetto::internal::kMaxDataSourceInstances);
158   // Matches the acquire_load in DataSource::Trace().
159   uint8_t old = cat->instances.fetch_or(
160       static_cast<uint8_t>(1u << instance_index), std::memory_order_release);
161   bool global_state_changed = old == 0;
162   if (global_state_changed) {
163     cat->flag.store(true, std::memory_order_relaxed);
164   }
165   if (cat->cb) {
166     cat->cb(cat, instance_index, /*created=*/true, global_state_changed,
167             cat->cb_user_arg);
168   }
169 }
170 
DisableRegisteredCategory(PerfettoTeCategoryImpl * cat,uint32_t instance_index)171 static void DisableRegisteredCategory(PerfettoTeCategoryImpl* cat,
172                                       uint32_t instance_index) {
173   PERFETTO_DCHECK(instance_index < perfetto::internal::kMaxDataSourceInstances);
174   // Matches the acquire_load in DataSource::Trace().
175   cat->instances.fetch_and(static_cast<uint8_t>(~(1u << instance_index)),
176                            std::memory_order_release);
177   bool global_state_changed = false;
178   if (!cat->instances.load(std::memory_order_relaxed)) {
179     cat->flag.store(false, std::memory_order_relaxed);
180     global_state_changed = true;
181   }
182   if (cat->cb) {
183     cat->cb(cat, instance_index, /*created=*/false, global_state_changed,
184             cat->cb_user_arg);
185   }
186 }
187 
SerializeCategory(const PerfettoTeCategoryDescriptor & desc,perfetto::protos::pbzero::TrackEventDescriptor * ted)188 static void SerializeCategory(
189     const PerfettoTeCategoryDescriptor& desc,
190     perfetto::protos::pbzero::TrackEventDescriptor* ted) {
191   auto* c = ted->add_available_categories();
192   c->set_name(desc.name);
193   if (desc.desc)
194     c->set_description(desc.desc);
195   for (size_t j = 0; j < desc.num_tags; ++j) {
196     c->add_tags(desc.tags[j]);
197   }
198 }
199 
200 namespace perfetto {
201 namespace shlib {
202 
203 struct TrackEventIncrementalState {
204   // A heap-allocated message for storing newly seen interned data while we are
205   // in the middle of writing a track event. When a track event wants to write
206   // new interned data into the trace, it is first serialized into this message
207   // and then flushed to the real trace in EventContext when the packet ends.
208   // The message is cached here as a part of incremental state so that we can
209   // reuse the underlying buffer allocation for subsequently written interned
210   // data.
211   uint64_t last_timestamp_ns = 0;
212   protozero::HeapBuffered<protos::pbzero::InternedData>
213       serialized_interned_data;
214   bool was_cleared = true;
215   base::FlatSet<uint64_t> seen_track_uuids;
216   // Map from serialized representation of a dynamic category to its enabled
217   // state.
218   base::FlatHashMap<std::string, bool> dynamic_categories;
219   InternMap iids;
220 };
221 
222 struct TrackEventTlsState {
223   template <typename TraceContext>
TrackEventTlsStateperfetto::shlib::TrackEventTlsState224   explicit TrackEventTlsState(const TraceContext& trace_context) {
225     auto locked_ds = trace_context.GetDataSourceLocked();
226     bool disable_incremental_timestamps = false;
227     timestamp_unit_multiplier = 1;
228     if (locked_ds.valid()) {
229       const auto& config = locked_ds->GetConfig();
230       disable_incremental_timestamps = config.disable_incremental_timestamps();
231       if (config.has_timestamp_unit_multiplier() &&
232           config.timestamp_unit_multiplier() != 0) {
233         timestamp_unit_multiplier = config.timestamp_unit_multiplier();
234       }
235     }
236     if (disable_incremental_timestamps) {
237       if (timestamp_unit_multiplier == 1) {
238         default_clock_id = PERFETTO_I_CLOCK_INCREMENTAL_UNDERNEATH;
239       } else {
240         default_clock_id = PERFETTO_TE_TIMESTAMP_TYPE_ABSOLUTE;
241       }
242     } else {
243       default_clock_id = PERFETTO_TE_TIMESTAMP_TYPE_INCREMENTAL;
244     }
245   }
246   uint32_t default_clock_id;
247   uint64_t timestamp_unit_multiplier;
248 };
249 
250 struct TrackEventDataSourceTraits : public perfetto::DefaultDataSourceTraits {
251   using IncrementalStateType = TrackEventIncrementalState;
252   using TlsStateType = TrackEventTlsState;
253 };
254 
255 class TrackEvent
256     : public perfetto::DataSource<TrackEvent, TrackEventDataSourceTraits> {
257  public:
258   ~TrackEvent() override;
OnSetup(const DataSourceBase::SetupArgs & args)259   void OnSetup(const DataSourceBase::SetupArgs& args) override {
260     const std::string& config_raw = args.config->track_event_config_raw();
261     bool ok = config_.ParseFromArray(config_raw.data(), config_raw.size());
262     if (!ok) {
263       PERFETTO_LOG("Failed to parse config");
264     }
265     inst_id_ = args.internal_instance_index;
266   }
267 
OnStart(const DataSourceBase::StartArgs &)268   void OnStart(const DataSourceBase::StartArgs&) override {
269     GlobalState::Instance().OnStart(config_, inst_id_);
270   }
271 
OnStop(const DataSourceBase::StopArgs &)272   void OnStop(const DataSourceBase::StopArgs&) override {
273     GlobalState::Instance().OnStop(inst_id_);
274   }
275 
GetConfig() const276   const perfetto::protos::gen::TrackEventConfig& GetConfig() const {
277     return config_;
278   }
279 
Init()280   static void Init() {
281     DataSourceDescriptor dsd =
282         GlobalState::Instance().GenerateDescriptorFromCategories();
283     Register(dsd);
284   }
285 
RegisterCategory(PerfettoTeCategoryImpl * cat)286   static void RegisterCategory(PerfettoTeCategoryImpl* cat) {
287     GlobalState::Instance().RegisterCategory(cat);
288   }
289 
UpdateDescriptorFromCategories()290   static void UpdateDescriptorFromCategories() {
291     DataSourceDescriptor dsd =
292         GlobalState::Instance().GenerateDescriptorFromCategories();
293     UpdateDescriptor(dsd);
294   }
295 
UnregisterCategory(PerfettoTeCategoryImpl * cat)296   static void UnregisterCategory(PerfettoTeCategoryImpl* cat) {
297     GlobalState::Instance().UnregisterCategory(cat);
298   }
299 
CategorySetCallback(struct PerfettoTeCategoryImpl * cat,PerfettoTeCategoryImplCallback cb,void * user_arg)300   static void CategorySetCallback(struct PerfettoTeCategoryImpl* cat,
301                                   PerfettoTeCategoryImplCallback cb,
302                                   void* user_arg) {
303     GlobalState::Instance().CategorySetCallback(cat, cb, user_arg);
304   }
305 
306   static internal::DataSourceType* GetType();
307 
308   static internal::DataSourceThreadLocalState** GetTlsState();
309 
310  private:
311   class GlobalState {
312    public:
Instance()313     static GlobalState& Instance() {
314       static GlobalState* instance = new GlobalState();
315       return *instance;
316     }
317 
OnStart(const perfetto::protos::gen::TrackEventConfig & config,uint32_t instance_id)318     void OnStart(const perfetto::protos::gen::TrackEventConfig& config,
319                  uint32_t instance_id) PERFETTO_LOCKS_EXCLUDED(mu_) {
320       std::lock_guard<std::mutex> lock(mu_);
321       EnableRegisteredCategory(perfetto_te_any_categories, instance_id);
322       for (PerfettoTeCategoryImpl* cat : categories_) {
323         if (IsRegisteredCategoryEnabled(*cat, config)) {
324           EnableRegisteredCategory(cat, instance_id);
325         }
326       }
327     }
328 
OnStop(uint32_t instance_id)329     void OnStop(uint32_t instance_id) PERFETTO_LOCKS_EXCLUDED(mu_) {
330       std::lock_guard<std::mutex> lock(mu_);
331       for (PerfettoTeCategoryImpl* cat : categories_) {
332         DisableRegisteredCategory(cat, instance_id);
333       }
334       DisableRegisteredCategory(perfetto_te_any_categories, instance_id);
335     }
336 
RegisterCategory(PerfettoTeCategoryImpl * cat)337     void RegisterCategory(PerfettoTeCategoryImpl* cat)
338         PERFETTO_LOCKS_EXCLUDED(mu_) {
339       {
340         std::lock_guard<std::mutex> lock(mu_);
341         Trace([cat](TraceContext ctx) {
342           auto ds = ctx.GetDataSourceLocked();
343 
344           if (IsRegisteredCategoryEnabled(*cat, ds->GetConfig())) {
345             EnableRegisteredCategory(cat, ds->inst_id_);
346           }
347         });
348         categories_.push_back(cat);
349         cat->cat_iid = ++interned_categories_;
350       }
351     }
352 
UnregisterCategory(PerfettoTeCategoryImpl * cat)353     void UnregisterCategory(PerfettoTeCategoryImpl* cat)
354         PERFETTO_LOCKS_EXCLUDED(mu_) {
355       std::lock_guard<std::mutex> lock(mu_);
356       categories_.erase(
357           std::remove(categories_.begin(), categories_.end(), cat),
358           categories_.end());
359     }
360 
CategorySetCallback(struct PerfettoTeCategoryImpl * cat,PerfettoTeCategoryImplCallback cb,void * user_arg)361     void CategorySetCallback(struct PerfettoTeCategoryImpl* cat,
362                              PerfettoTeCategoryImplCallback cb,
363                              void* user_arg) PERFETTO_LOCKS_EXCLUDED(mu_) {
364       std::lock_guard<std::mutex> lock(mu_);
365       cat->cb = cb;
366       cat->cb_user_arg = user_arg;
367       if (!cat->cb) {
368         return;
369       }
370 
371       bool first = true;
372       uint8_t active_instances = cat->instances.load(std::memory_order_relaxed);
373       for (PerfettoDsInstanceIndex i = 0; i < internal::kMaxDataSourceInstances;
374            i++) {
375         if ((active_instances & (1 << i)) == 0) {
376           continue;
377         }
378         cb(cat, i, true, first, user_arg);
379         first = false;
380       }
381     }
382 
GenerateDescriptorFromCategories() const383     DataSourceDescriptor GenerateDescriptorFromCategories() const
384         PERFETTO_LOCKS_EXCLUDED(mu_) {
385       DataSourceDescriptor dsd;
386       dsd.set_name("track_event");
387 
388       protozero::HeapBuffered<perfetto::protos::pbzero::TrackEventDescriptor>
389           ted;
390       {
391         std::lock_guard<std::mutex> lock(mu_);
392         for (PerfettoTeCategoryImpl* cat : categories_) {
393           SerializeCategory(*cat->desc, ted.get());
394         }
395       }
396       dsd.set_track_event_descriptor_raw(ted.SerializeAsString());
397       return dsd;
398     }
399 
400    private:
GlobalState()401     GlobalState() : interned_categories_(0) {
402       perfetto_te_any_categories = new PerfettoTeCategoryImpl;
403       perfetto_te_any_categories_enabled = &perfetto_te_any_categories->flag;
404     }
405 
406     mutable std::mutex mu_;
407     std::vector<PerfettoTeCategoryImpl*> categories_ PERFETTO_GUARDED_BY(mu_);
408     uint64_t interned_categories_ PERFETTO_GUARDED_BY(mu_);
409   };
410 
411   uint32_t inst_id_;
412   perfetto::protos::gen::TrackEventConfig config_;
413 };
414 
415 TrackEvent::~TrackEvent() = default;
416 
ResetTrackEventTls()417 void ResetTrackEventTls() {
418   *TrackEvent::GetTlsState() = nullptr;
419 }
420 
421 struct TracePointTraits {
422   struct TracePointData {
423     struct PerfettoTeCategoryImpl* enabled;
424   };
GetActiveInstancesperfetto::shlib::TracePointTraits425   static constexpr std::atomic<uint8_t>* GetActiveInstances(
426       TracePointData data) {
427     return &data.enabled->instances;
428   }
429 };
430 
431 }  // namespace shlib
432 }  // namespace perfetto
433 
434 PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(
435     perfetto::shlib::TrackEvent,
436     perfetto::shlib::TrackEventDataSourceTraits);
437 
438 PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(
439     perfetto::shlib::TrackEvent,
440     perfetto::shlib::TrackEventDataSourceTraits);
441 
GetType()442 perfetto::internal::DataSourceType* perfetto::shlib::TrackEvent::GetType() {
443   return &perfetto::shlib::TrackEvent::Helper::type();
444 }
445 
446 perfetto::internal::DataSourceThreadLocalState**
GetTlsState()447 perfetto::shlib::TrackEvent::GetTlsState() {
448   return &tls_state_;
449 }
450 
451 namespace {
452 
453 using perfetto::internal::TrackEventInternal;
454 
EventType(int32_t type)455 perfetto::protos::pbzero::TrackEvent::Type EventType(int32_t type) {
456   using Type = perfetto::protos::pbzero::TrackEvent::Type;
457   auto enum_type = static_cast<PerfettoTeType>(type);
458   switch (enum_type) {
459     case PERFETTO_TE_TYPE_SLICE_BEGIN:
460       return Type::TYPE_SLICE_BEGIN;
461     case PERFETTO_TE_TYPE_SLICE_END:
462       return Type::TYPE_SLICE_END;
463     case PERFETTO_TE_TYPE_INSTANT:
464       return Type::TYPE_INSTANT;
465     case PERFETTO_TE_TYPE_COUNTER:
466       return Type::TYPE_COUNTER;
467   }
468   return Type::TYPE_UNSPECIFIED;
469 }
470 
471 protozero::MessageHandle<perfetto::protos::pbzero::TracePacket>
NewTracePacketInternal(perfetto::TraceWriterBase * trace_writer,perfetto::shlib::TrackEventIncrementalState * incr_state,const perfetto::shlib::TrackEventTlsState & tls_state,perfetto::TraceTimestamp timestamp,uint32_t seq_flags)472 NewTracePacketInternal(perfetto::TraceWriterBase* trace_writer,
473                        perfetto::shlib::TrackEventIncrementalState* incr_state,
474                        const perfetto::shlib::TrackEventTlsState& tls_state,
475                        perfetto::TraceTimestamp timestamp,
476                        uint32_t seq_flags) {
477   // PERFETTO_TE_TIMESTAMP_TYPE_INCREMENTAL is the default timestamp returned
478   // by TrackEventInternal::GetTraceTime(). If the configuration in `tls_state`
479   // uses a different clock, we have to use that instead.
480   if (PERFETTO_UNLIKELY(tls_state.default_clock_id !=
481                             PERFETTO_TE_TIMESTAMP_TYPE_INCREMENTAL &&
482                         timestamp.clock_id ==
483                             PERFETTO_TE_TIMESTAMP_TYPE_INCREMENTAL)) {
484     timestamp.clock_id = tls_state.default_clock_id;
485   }
486   auto packet = trace_writer->NewTracePacket();
487   auto ts_unit_multiplier = tls_state.timestamp_unit_multiplier;
488   if (PERFETTO_LIKELY(timestamp.clock_id ==
489                       PERFETTO_TE_TIMESTAMP_TYPE_INCREMENTAL)) {
490     if (PERFETTO_LIKELY(incr_state->last_timestamp_ns <= timestamp.value)) {
491       // No need to set the clock id here, since
492       // PERFETTO_TE_TIMESTAMP_TYPE_INCREMENTAL is the clock id assumed by
493       // default.
494       auto time_diff_ns = timestamp.value - incr_state->last_timestamp_ns;
495       auto time_diff_units = time_diff_ns / ts_unit_multiplier;
496       packet->set_timestamp(time_diff_units);
497       incr_state->last_timestamp_ns += time_diff_units * ts_unit_multiplier;
498     } else {
499       packet->set_timestamp(timestamp.value / ts_unit_multiplier);
500       packet->set_timestamp_clock_id(
501           ts_unit_multiplier == 1
502               ? static_cast<uint32_t>(PERFETTO_I_CLOCK_INCREMENTAL_UNDERNEATH)
503               : static_cast<uint32_t>(PERFETTO_TE_TIMESTAMP_TYPE_ABSOLUTE));
504     }
505   } else if (PERFETTO_LIKELY(timestamp.clock_id ==
506                              tls_state.default_clock_id)) {
507     packet->set_timestamp(timestamp.value / ts_unit_multiplier);
508   } else {
509     packet->set_timestamp(timestamp.value);
510     packet->set_timestamp_clock_id(timestamp.clock_id);
511   }
512   packet->set_sequence_flags(seq_flags);
513   return packet;
514 }
515 
516 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
517     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
GetCmdLine()518 std::vector<std::string> GetCmdLine() {
519   std::vector<std::string> cmdline_str;
520   std::string cmdline;
521   if (perfetto::base::ReadFile("/proc/self/cmdline", &cmdline)) {
522     perfetto::base::StringSplitter splitter(std::move(cmdline), '\0');
523     while (splitter.Next()) {
524       cmdline_str.emplace_back(splitter.cur_token(), splitter.cur_token_size());
525     }
526   }
527   return cmdline_str;
528 }
529 #endif
530 
ResetIncrementalStateIfRequired(perfetto::TraceWriterBase * trace_writer,perfetto::shlib::TrackEventIncrementalState * incr_state,const perfetto::shlib::TrackEventTlsState & tls_state,const perfetto::TraceTimestamp & timestamp)531 void ResetIncrementalStateIfRequired(
532     perfetto::TraceWriterBase* trace_writer,
533     perfetto::shlib::TrackEventIncrementalState* incr_state,
534     const perfetto::shlib::TrackEventTlsState& tls_state,
535     const perfetto::TraceTimestamp& timestamp) {
536   if (!incr_state->was_cleared) {
537     return;
538   }
539   incr_state->was_cleared = false;
540 
541   auto sequence_timestamp = timestamp;
542   if (timestamp.clock_id != PERFETTO_I_CLOCK_INCREMENTAL_UNDERNEATH &&
543       timestamp.clock_id != PERFETTO_TE_TIMESTAMP_TYPE_INCREMENTAL) {
544     sequence_timestamp = TrackEventInternal::GetTraceTime();
545   }
546 
547   incr_state->last_timestamp_ns = sequence_timestamp.value;
548   auto tid = perfetto::base::GetThreadId();
549   auto pid = perfetto::Platform::GetCurrentProcessId();
550   uint64_t thread_track_uuid =
551       perfetto_te_process_track_uuid ^ static_cast<uint64_t>(tid);
552   auto ts_unit_multiplier = tls_state.timestamp_unit_multiplier;
553   {
554     // Mark any incremental state before this point invalid. Also set up
555     // defaults so that we don't need to repeat constant data for each packet.
556     auto packet = NewTracePacketInternal(
557         trace_writer, incr_state, tls_state, timestamp,
558         perfetto::protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED);
559     auto defaults = packet->set_trace_packet_defaults();
560     defaults->set_timestamp_clock_id(tls_state.default_clock_id);
561     // Establish the default track for this event sequence.
562     auto track_defaults = defaults->set_track_event_defaults();
563     track_defaults->set_track_uuid(thread_track_uuid);
564 
565     if (tls_state.default_clock_id != PERFETTO_I_CLOCK_INCREMENTAL_UNDERNEATH) {
566       perfetto::protos::pbzero::ClockSnapshot* clocks =
567           packet->set_clock_snapshot();
568       // Trace clock.
569       perfetto::protos::pbzero::ClockSnapshot::Clock* trace_clock =
570           clocks->add_clocks();
571       trace_clock->set_clock_id(PERFETTO_I_CLOCK_INCREMENTAL_UNDERNEATH);
572       trace_clock->set_timestamp(sequence_timestamp.value);
573 
574       if (PERFETTO_LIKELY(tls_state.default_clock_id ==
575                           PERFETTO_TE_TIMESTAMP_TYPE_INCREMENTAL)) {
576         // Delta-encoded incremental clock in nanoseconds by default but
577         // configurable by |tls_state.timestamp_unit_multiplier|.
578         perfetto::protos::pbzero::ClockSnapshot::Clock* clock_incremental =
579             clocks->add_clocks();
580         clock_incremental->set_clock_id(PERFETTO_TE_TIMESTAMP_TYPE_INCREMENTAL);
581         clock_incremental->set_timestamp(sequence_timestamp.value /
582                                          ts_unit_multiplier);
583         clock_incremental->set_is_incremental(true);
584         clock_incremental->set_unit_multiplier_ns(ts_unit_multiplier);
585       }
586       if (ts_unit_multiplier > 1) {
587         // absolute clock with custom timestamp_unit_multiplier.
588         perfetto::protos::pbzero::ClockSnapshot::Clock* absolute_clock =
589             clocks->add_clocks();
590         absolute_clock->set_clock_id(PERFETTO_TE_TIMESTAMP_TYPE_ABSOLUTE);
591         absolute_clock->set_timestamp(sequence_timestamp.value /
592                                       ts_unit_multiplier);
593         absolute_clock->set_is_incremental(false);
594         absolute_clock->set_unit_multiplier_ns(ts_unit_multiplier);
595       }
596     }
597   }
598 
599   // Every thread should write a descriptor for its default track, because most
600   // trace points won't explicitly reference it. We also write the process
601   // descriptor from every thread that writes trace events to ensure it gets
602   // emitted at least once.
603   {
604     auto packet = NewTracePacketInternal(
605         trace_writer, incr_state, tls_state, timestamp,
606         perfetto::protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE);
607     auto* track = packet->set_track_descriptor();
608     track->set_uuid(thread_track_uuid);
609     track->set_parent_uuid(perfetto_te_process_track_uuid);
610     auto* td = track->set_thread();
611 
612     td->set_pid(static_cast<int32_t>(pid));
613     td->set_tid(static_cast<int32_t>(tid));
614     std::string thread_name;
615     if (perfetto::base::GetThreadName(thread_name))
616       td->set_thread_name(thread_name);
617   }
618   {
619     auto packet = NewTracePacketInternal(
620         trace_writer, incr_state, tls_state, timestamp,
621         perfetto::protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE);
622     auto* track = packet->set_track_descriptor();
623     track->set_uuid(perfetto_te_process_track_uuid);
624     auto* pd = track->set_process();
625 
626 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
627     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
628     static perfetto::base::NoDestructor<std::vector<std::string>> cmdline(
629         GetCmdLine());
630     if (!cmdline.ref().empty()) {
631       // Since cmdline is a zero-terminated list of arguments, this ends up
632       // writing just the first element, i.e., the process name, into the
633       // process name field.
634       pd->set_process_name(cmdline.ref()[0]);
635       for (const std::string& arg : cmdline.ref()) {
636         pd->add_cmdline(arg);
637       }
638     }
639 #endif
640     pd->set_pid(static_cast<int32_t>(pid));
641   }
642 }
643 
644 // Appends the fields described by `fields` to `msg`.
AppendHlProtoFields(protozero::Message * msg,PerfettoTeHlProtoField * const * fields)645 void AppendHlProtoFields(protozero::Message* msg,
646                          PerfettoTeHlProtoField* const* fields) {
647   for (PerfettoTeHlProtoField* const* p = fields; *p != nullptr; p++) {
648     switch ((*p)->type) {
649       case PERFETTO_TE_HL_PROTO_TYPE_CSTR: {
650         auto field = reinterpret_cast<PerfettoTeHlProtoFieldCstr*>(*p);
651         msg->AppendString(field->header.id, field->str);
652         break;
653       }
654       case PERFETTO_TE_HL_PROTO_TYPE_BYTES: {
655         auto field = reinterpret_cast<PerfettoTeHlProtoFieldBytes*>(*p);
656         msg->AppendBytes(field->header.id, field->buf, field->len);
657         break;
658       }
659       case PERFETTO_TE_HL_PROTO_TYPE_NESTED: {
660         auto field = reinterpret_cast<PerfettoTeHlProtoFieldNested*>(*p);
661         auto* nested =
662             msg->BeginNestedMessage<protozero::Message>(field->header.id);
663         AppendHlProtoFields(nested, field->fields);
664         break;
665       }
666       case PERFETTO_TE_HL_PROTO_TYPE_VARINT: {
667         auto field = reinterpret_cast<PerfettoTeHlProtoFieldVarInt*>(*p);
668         msg->AppendVarInt(field->header.id, field->value);
669         break;
670       }
671       case PERFETTO_TE_HL_PROTO_TYPE_FIXED64: {
672         auto field = reinterpret_cast<PerfettoTeHlProtoFieldFixed64*>(*p);
673         msg->AppendFixed(field->header.id, field->value);
674         break;
675       }
676       case PERFETTO_TE_HL_PROTO_TYPE_FIXED32: {
677         auto field = reinterpret_cast<PerfettoTeHlProtoFieldFixed32*>(*p);
678         msg->AppendFixed(field->header.id, field->value);
679         break;
680       }
681       case PERFETTO_TE_HL_PROTO_TYPE_DOUBLE: {
682         auto field = reinterpret_cast<PerfettoTeHlProtoFieldDouble*>(*p);
683         msg->AppendFixed(field->header.id, field->value);
684         break;
685       }
686       case PERFETTO_TE_HL_PROTO_TYPE_FLOAT: {
687         auto field = reinterpret_cast<PerfettoTeHlProtoFieldFloat*>(*p);
688         msg->AppendFixed(field->header.id, field->value);
689         break;
690       }
691     }
692   }
693 }
694 
WriteTrackEvent(perfetto::shlib::TrackEventIncrementalState * incr,perfetto::protos::pbzero::TrackEvent * event,PerfettoTeCategoryImpl * cat,perfetto::protos::pbzero::TrackEvent::Type type,const char * name,const PerfettoTeHlExtra * const * extra_data,std::optional<uint64_t> track_uuid,const PerfettoTeCategoryDescriptor * dynamic_cat,bool use_interning)695 void WriteTrackEvent(perfetto::shlib::TrackEventIncrementalState* incr,
696                      perfetto::protos::pbzero::TrackEvent* event,
697                      PerfettoTeCategoryImpl* cat,
698                      perfetto::protos::pbzero::TrackEvent::Type type,
699                      const char* name,
700                      const PerfettoTeHlExtra* const* extra_data,
701                      std::optional<uint64_t> track_uuid,
702                      const PerfettoTeCategoryDescriptor* dynamic_cat,
703                      bool use_interning) {
704   if (type != perfetto::protos::pbzero::TrackEvent::TYPE_UNSPECIFIED) {
705     event->set_type(type);
706   }
707 
708   if (!dynamic_cat &&
709       type != perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_END &&
710       type != perfetto::protos::pbzero::TrackEvent::TYPE_COUNTER) {
711     uint64_t iid = cat->cat_iid;
712     auto res = incr->iids.FindOrAssign(
713         perfetto::protos::pbzero::InternedData::kEventCategoriesFieldNumber,
714         &iid, sizeof(iid));
715     if (res.newly_assigned) {
716       auto* ser = incr->serialized_interned_data->add_event_categories();
717       ser->set_iid(iid);
718       ser->set_name(cat->desc->name);
719     }
720     event->add_category_iids(iid);
721   }
722 
723   if (type != perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_END) {
724     if (name) {
725       if (use_interning) {
726         const void* str = name;
727         size_t len = strlen(name);
728         auto res = incr->iids.FindOrAssign(
729             perfetto::protos::pbzero::InternedData::kEventNamesFieldNumber, str,
730             len);
731         if (res.newly_assigned) {
732           auto* ser = incr->serialized_interned_data->add_event_names();
733           ser->set_iid(res.iid);
734           ser->set_name(name);
735         }
736         event->set_name_iid(res.iid);
737       } else {
738         event->set_name(name);
739       }
740     }
741   }
742 
743   if (dynamic_cat &&
744       type != perfetto::protos::pbzero::TrackEvent::TYPE_SLICE_END &&
745       type != perfetto::protos::pbzero::TrackEvent::TYPE_COUNTER) {
746     event->add_categories(dynamic_cat->name);
747   }
748 
749   if (track_uuid) {
750     event->set_track_uuid(*track_uuid);
751   }
752 
753   for (const auto* it = extra_data; *it != nullptr; it++) {
754     const struct PerfettoTeHlExtra& extra = **it;
755     if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_INT64 &&
756         type == perfetto::protos::pbzero::TrackEvent::TYPE_COUNTER) {
757       event->set_counter_value(
758           reinterpret_cast<const struct PerfettoTeHlExtraCounterInt64&>(extra)
759               .value);
760     } else if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_DOUBLE) {
761       event->set_double_counter_value(
762           reinterpret_cast<const struct PerfettoTeHlExtraCounterDouble&>(extra)
763               .value);
764     }
765   }
766 
767   for (const auto* it = extra_data; *it != nullptr; it++) {
768     const struct PerfettoTeHlExtra& extra = **it;
769     if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_BOOL ||
770         extra.type == PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_UINT64 ||
771         extra.type == PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_INT64 ||
772         extra.type == PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_DOUBLE ||
773         extra.type == PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_STRING ||
774         extra.type == PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_POINTER) {
775       auto* dbg = event->add_debug_annotations();
776       const char* arg_name = nullptr;
777       if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_BOOL) {
778         const auto& arg =
779             reinterpret_cast<const struct PerfettoTeHlExtraDebugArgBool&>(
780                 extra);
781         dbg->set_bool_value(arg.value);
782         arg_name = arg.name;
783       } else if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_UINT64) {
784         const auto& arg =
785             reinterpret_cast<const struct PerfettoTeHlExtraDebugArgUint64&>(
786                 extra);
787         dbg->set_uint_value(arg.value);
788         arg_name = arg.name;
789       } else if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_INT64) {
790         const auto& arg =
791             reinterpret_cast<const struct PerfettoTeHlExtraDebugArgInt64&>(
792                 extra);
793         dbg->set_int_value(arg.value);
794         arg_name = arg.name;
795       } else if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_DOUBLE) {
796         const auto& arg =
797             reinterpret_cast<const struct PerfettoTeHlExtraDebugArgDouble&>(
798                 extra);
799         dbg->set_double_value(arg.value);
800         arg_name = arg.name;
801       } else if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_STRING) {
802         const auto& arg =
803             reinterpret_cast<const struct PerfettoTeHlExtraDebugArgString&>(
804                 extra);
805         dbg->set_string_value(arg.value);
806         arg_name = arg.name;
807       } else if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_DEBUG_ARG_POINTER) {
808         const auto& arg =
809             reinterpret_cast<const struct PerfettoTeHlExtraDebugArgPointer&>(
810                 extra);
811         dbg->set_pointer_value(arg.value);
812         arg_name = arg.name;
813       }
814 
815       if (arg_name != nullptr) {
816         const void* str = arg_name;
817         size_t len = strlen(arg_name);
818         auto res =
819             incr->iids.FindOrAssign(perfetto::protos::pbzero::InternedData::
820                                         kDebugAnnotationNamesFieldNumber,
821                                     str, len);
822         if (res.newly_assigned) {
823           auto* ser =
824               incr->serialized_interned_data->add_debug_annotation_names();
825           ser->set_iid(res.iid);
826           ser->set_name(arg_name);
827         }
828         dbg->set_name_iid(res.iid);
829       }
830     }
831   }
832 
833   for (const auto* it = extra_data; *it != nullptr; it++) {
834     const struct PerfettoTeHlExtra& extra = **it;
835     if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_FLOW) {
836       event->add_flow_ids(
837           reinterpret_cast<const struct PerfettoTeHlExtraFlow&>(extra).id);
838     }
839   }
840 
841   for (const auto* it = extra_data; *it != nullptr; it++) {
842     const struct PerfettoTeHlExtra& extra = **it;
843     if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_TERMINATING_FLOW) {
844       event->add_terminating_flow_ids(
845           reinterpret_cast<const struct PerfettoTeHlExtraFlow&>(extra).id);
846     }
847   }
848 
849   for (const auto* it = extra_data; *it != nullptr; it++) {
850     const struct PerfettoTeHlExtra& extra = **it;
851     if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_PROTO_FIELDS) {
852       const auto* fields =
853           reinterpret_cast<const struct PerfettoTeHlExtraProtoFields&>(extra)
854               .fields;
855       AppendHlProtoFields(event, fields);
856     }
857   }
858 }
859 
860 }  // namespace
861 
PerfettoTeCategoryImplCreate(struct PerfettoTeCategoryDescriptor * desc)862 struct PerfettoTeCategoryImpl* PerfettoTeCategoryImplCreate(
863     struct PerfettoTeCategoryDescriptor* desc) {
864   auto* cat = new PerfettoTeCategoryImpl;
865   cat->desc = desc;
866   perfetto::shlib::TrackEvent::RegisterCategory(cat);
867   return cat;
868 }
869 
PerfettoTePublishCategories()870 void PerfettoTePublishCategories() {
871   perfetto::shlib::TrackEvent::UpdateDescriptorFromCategories();
872 }
873 
PerfettoTeCategoryImplSetCallback(struct PerfettoTeCategoryImpl * cat,PerfettoTeCategoryImplCallback cb,void * user_arg)874 void PerfettoTeCategoryImplSetCallback(struct PerfettoTeCategoryImpl* cat,
875                                        PerfettoTeCategoryImplCallback cb,
876                                        void* user_arg) {
877   perfetto::shlib::TrackEvent::CategorySetCallback(cat, cb, user_arg);
878 }
879 
PERFETTO_ATOMIC(bool)880 PERFETTO_ATOMIC(bool) *
881     PerfettoTeCategoryImplGetEnabled(struct PerfettoTeCategoryImpl* cat) {
882   return &cat->flag;
883 }
884 
PerfettoTeCategoryImplGetIid(struct PerfettoTeCategoryImpl * cat)885 uint64_t PerfettoTeCategoryImplGetIid(struct PerfettoTeCategoryImpl* cat) {
886   return cat->cat_iid;
887 }
888 
PerfettoTeCategoryImplDestroy(struct PerfettoTeCategoryImpl * cat)889 void PerfettoTeCategoryImplDestroy(struct PerfettoTeCategoryImpl* cat) {
890   perfetto::shlib::TrackEvent::UnregisterCategory(cat);
891   delete cat;
892 }
893 
PerfettoTeInit(void)894 void PerfettoTeInit(void) {
895   perfetto::shlib::TrackEvent::Init();
896   perfetto_te_process_track_uuid =
897       perfetto::internal::TrackRegistry::ComputeProcessUuid();
898 }
899 
PerfettoTeGetTimestamp(void)900 struct PerfettoTeTimestamp PerfettoTeGetTimestamp(void) {
901   struct PerfettoTeTimestamp ret;
902   ret.clock_id = PERFETTO_TE_TIMESTAMP_TYPE_BOOT;
903   ret.value = TrackEventInternal::GetTimeNs();
904   return ret;
905 }
906 
IsDynamicCategoryEnabled(uint32_t inst_idx,perfetto::shlib::TrackEventIncrementalState * incr_state,const struct PerfettoTeCategoryDescriptor & desc)907 static bool IsDynamicCategoryEnabled(
908     uint32_t inst_idx,
909     perfetto::shlib::TrackEventIncrementalState* incr_state,
910     const struct PerfettoTeCategoryDescriptor& desc) {
911   constexpr size_t kMaxCacheSize = 20;
912   perfetto::internal::DataSourceType* ds =
913       perfetto::shlib::TrackEvent::GetType();
914   auto& cache = incr_state->dynamic_categories;
915   protozero::HeapBuffered<perfetto::protos::pbzero::TrackEventDescriptor> ted;
916   SerializeCategory(desc, ted.get());
917   std::string serialized = ted.SerializeAsString();
918   auto* cached = cache.Find(serialized);
919   if (cached) {
920     return *cached;
921   }
922 
923   auto* internal_state = ds->static_state()->TryGet(inst_idx);
924   if (!internal_state)
925     return false;
926   std::unique_lock<std::recursive_mutex> lock(internal_state->lock);
927   auto* sds = static_cast<perfetto::shlib::TrackEvent*>(
928       internal_state->data_source.get());
929 
930   bool res = IsSingleCategoryEnabled(desc, sds->GetConfig());
931   if (cache.size() < kMaxCacheSize) {
932     cache[serialized] = res;
933   }
934   return res;
935 }
936 
937 // If the category `dyn_cat` is enabled on the data source instance pointed by
938 // `ii`, returns immediately. Otherwise, advances `ii` to a data source instance
939 // where `dyn_cat` is enabled. If there's no data source instance where
940 // `dyn_cat` is enabled, `ii->instance` will be nullptr.
AdvanceToFirstEnabledDynamicCategory(perfetto::internal::DataSourceType::InstancesIterator * ii,perfetto::internal::DataSourceThreadLocalState * tls_state,struct PerfettoTeCategoryImpl * cat,const PerfettoTeCategoryDescriptor & dyn_cat)941 static void AdvanceToFirstEnabledDynamicCategory(
942     perfetto::internal::DataSourceType::InstancesIterator* ii,
943     perfetto::internal::DataSourceThreadLocalState* tls_state,
944     struct PerfettoTeCategoryImpl* cat,
945     const PerfettoTeCategoryDescriptor& dyn_cat) {
946   perfetto::internal::DataSourceType* ds =
947       perfetto::shlib::TrackEvent::GetType();
948   for (; ii->instance;
949        ds->NextIteration</*Traits=*/perfetto::shlib::TracePointTraits>(
950            ii, tls_state, {cat})) {
951     auto* incr_state =
952         static_cast<perfetto::shlib::TrackEventIncrementalState*>(
953             ds->GetIncrementalState(ii->instance, ii->i));
954     if (IsDynamicCategoryEnabled(ii->i, incr_state, dyn_cat)) {
955       break;
956     }
957   }
958 }
959 
InstanceOp(perfetto::internal::DataSourceType * ds,perfetto::internal::DataSourceType::InstancesIterator * ii,perfetto::internal::DataSourceThreadLocalState * tls_state,struct PerfettoTeCategoryImpl * cat,perfetto::protos::pbzero::TrackEvent::Type type,const char * name,struct PerfettoTeHlExtra * const * extra_data)960 static void InstanceOp(
961     perfetto::internal::DataSourceType* ds,
962     perfetto::internal::DataSourceType::InstancesIterator* ii,
963     perfetto::internal::DataSourceThreadLocalState* tls_state,
964     struct PerfettoTeCategoryImpl* cat,
965     perfetto::protos::pbzero::TrackEvent::Type type,
966     const char* name,
967     struct PerfettoTeHlExtra* const* extra_data) {
968   if (!ii->instance) {
969     return;
970   }
971 
972   std::variant<std::monostate, const PerfettoTeRegisteredTrackImpl*,
973                const PerfettoTeHlExtraNamedTrack*,
974                const PerfettoTeHlExtraProtoTrack*>
975       track;
976   std::optional<uint64_t> track_uuid;
977 
978   const struct PerfettoTeHlExtraTimestamp* custom_timestamp = nullptr;
979   const struct PerfettoTeCategoryDescriptor* dynamic_cat = nullptr;
980   std::optional<int64_t> int_counter;
981   std::optional<double> double_counter;
982   bool use_interning = true;
983   bool flush = false;
984 
985   for (const auto* it = extra_data; *it != nullptr; it++) {
986     const struct PerfettoTeHlExtra& extra = **it;
987     if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_REGISTERED_TRACK) {
988       const auto& cast =
989           reinterpret_cast<const struct PerfettoTeHlExtraRegisteredTrack&>(
990               extra);
991       track = cast.track;
992     } else if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_NAMED_TRACK) {
993       track =
994           &reinterpret_cast<const struct PerfettoTeHlExtraNamedTrack&>(extra);
995     } else if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_PROTO_TRACK) {
996       track =
997           &reinterpret_cast<const struct PerfettoTeHlExtraProtoTrack&>(extra);
998     } else if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_TIMESTAMP) {
999       custom_timestamp =
1000           &reinterpret_cast<const struct PerfettoTeHlExtraTimestamp&>(extra);
1001     } else if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_DYNAMIC_CATEGORY) {
1002       dynamic_cat =
1003           reinterpret_cast<const struct PerfettoTeHlExtraDynamicCategory&>(
1004               extra)
1005               .desc;
1006     } else if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_INT64) {
1007       int_counter =
1008           reinterpret_cast<const struct PerfettoTeHlExtraCounterInt64&>(extra)
1009               .value;
1010     } else if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_COUNTER_DOUBLE) {
1011       double_counter =
1012           reinterpret_cast<const struct PerfettoTeHlExtraCounterInt64&>(extra)
1013               .value;
1014     } else if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_NO_INTERN) {
1015       use_interning = false;
1016     } else if (extra.type == PERFETTO_TE_HL_EXTRA_TYPE_FLUSH) {
1017       flush = true;
1018     }
1019   }
1020 
1021   perfetto::TraceTimestamp ts;
1022   if (custom_timestamp) {
1023     ts.clock_id = custom_timestamp->timestamp.clock_id;
1024     ts.value = custom_timestamp->timestamp.value;
1025   } else {
1026     ts = TrackEventInternal::GetTraceTime();
1027   }
1028 
1029   if (PERFETTO_UNLIKELY(dynamic_cat)) {
1030     AdvanceToFirstEnabledDynamicCategory(ii, tls_state, cat, *dynamic_cat);
1031     if (!ii->instance) {
1032       return;
1033     }
1034   }
1035 
1036   const auto& track_event_tls =
1037       *static_cast<perfetto::shlib::TrackEventTlsState*>(
1038           ii->instance->data_source_custom_tls.get());
1039 
1040   auto* incr_state = static_cast<perfetto::shlib::TrackEventIncrementalState*>(
1041       ds->GetIncrementalState(ii->instance, ii->i));
1042   ResetIncrementalStateIfRequired(ii->instance->trace_writer.get(), incr_state,
1043                                   track_event_tls, ts);
1044 
1045   if (std::holds_alternative<const PerfettoTeRegisteredTrackImpl*>(track)) {
1046     auto* registered_track =
1047         std::get<const PerfettoTeRegisteredTrackImpl*>(track);
1048     if (incr_state->seen_track_uuids.insert(registered_track->uuid).second) {
1049       auto packet = ii->instance->trace_writer->NewTracePacket();
1050       auto* track_descriptor = packet->set_track_descriptor();
1051       track_descriptor->AppendRawProtoBytes(registered_track->descriptor,
1052                                             registered_track->descriptor_size);
1053     }
1054     track_uuid = registered_track->uuid;
1055   } else if (std::holds_alternative<const PerfettoTeHlExtraNamedTrack*>(
1056                  track)) {
1057     auto* named_track = std::get<const PerfettoTeHlExtraNamedTrack*>(track);
1058     uint64_t uuid = named_track->parent_uuid;
1059     uuid ^= PerfettoFnv1a(named_track->name, strlen(named_track->name));
1060     uuid ^= named_track->id;
1061     if (incr_state->seen_track_uuids.insert(uuid).second) {
1062       auto packet = ii->instance->trace_writer->NewTracePacket();
1063       auto* track_descriptor = packet->set_track_descriptor();
1064       track_descriptor->set_uuid(uuid);
1065       if (named_track->parent_uuid) {
1066         track_descriptor->set_parent_uuid(named_track->parent_uuid);
1067       }
1068       track_descriptor->set_name(named_track->name);
1069     }
1070     track_uuid = uuid;
1071   } else if (std::holds_alternative<const PerfettoTeHlExtraProtoTrack*>(
1072                  track)) {
1073     auto* counter_track = std::get<const PerfettoTeHlExtraProtoTrack*>(track);
1074     uint64_t uuid = counter_track->uuid;
1075     if (incr_state->seen_track_uuids.insert(uuid).second) {
1076       auto packet = ii->instance->trace_writer->NewTracePacket();
1077       auto* track_descriptor = packet->set_track_descriptor();
1078       track_descriptor->set_uuid(uuid);
1079       AppendHlProtoFields(track_descriptor, counter_track->fields);
1080     }
1081     track_uuid = uuid;
1082   }
1083 
1084   perfetto::TraceWriterBase* trace_writer = ii->instance->trace_writer.get();
1085   {
1086     auto packet = NewTracePacketInternal(
1087         trace_writer, incr_state, track_event_tls, ts,
1088         perfetto::protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE);
1089     auto* track_event = packet->set_track_event();
1090     WriteTrackEvent(incr_state, track_event, cat, type, name, extra_data,
1091                     track_uuid, dynamic_cat, use_interning);
1092     track_event->Finalize();
1093 
1094     if (!incr_state->serialized_interned_data.empty()) {
1095       auto ranges = incr_state->serialized_interned_data.GetRanges();
1096       packet->AppendScatteredBytes(
1097           perfetto::protos::pbzero::TracePacket::kInternedDataFieldNumber,
1098           ranges.data(), ranges.size());
1099       incr_state->serialized_interned_data.Reset();
1100     }
1101   }
1102 
1103   if (PERFETTO_UNLIKELY(flush)) {
1104     trace_writer->Flush();
1105   }
1106 }
1107 
PerfettoTeHlEmitImpl(struct PerfettoTeCategoryImpl * cat,int32_t type,const char * name,struct PerfettoTeHlExtra * const * extra_data)1108 void PerfettoTeHlEmitImpl(struct PerfettoTeCategoryImpl* cat,
1109                           int32_t type,
1110                           const char* name,
1111                           struct PerfettoTeHlExtra* const* extra_data) {
1112   uint32_t cached_instances =
1113       perfetto::shlib::TracePointTraits::GetActiveInstances({cat})->load(
1114           std::memory_order_relaxed);
1115   if (!cached_instances) {
1116     return;
1117   }
1118 
1119   perfetto::internal::DataSourceType* ds =
1120       perfetto::shlib::TrackEvent::GetType();
1121 
1122   perfetto::internal::DataSourceThreadLocalState*& tls_state =
1123       *perfetto::shlib::TrackEvent::GetTlsState();
1124 
1125   if (!ds->TracePrologue<perfetto::shlib::TrackEventDataSourceTraits,
1126                          perfetto::shlib::TracePointTraits>(
1127           &tls_state, &cached_instances, {cat})) {
1128     return;
1129   }
1130 
1131   for (perfetto::internal::DataSourceType::InstancesIterator ii =
1132            ds->BeginIteration<perfetto::shlib::TracePointTraits>(
1133                cached_instances, tls_state, {cat});
1134        ii.instance;
1135        ds->NextIteration</*Traits=*/perfetto::shlib::TracePointTraits>(
1136            &ii, tls_state, {cat})) {
1137     InstanceOp(ds, &ii, tls_state, cat, EventType(type), name, extra_data);
1138   }
1139   ds->TraceEpilogue(tls_state);
1140 }
1141 
FillIterator(const perfetto::internal::DataSourceType::InstancesIterator * ii,struct PerfettoTeTimestamp ts,struct PerfettoTeLlImplIterator * iterator)1142 static void FillIterator(
1143     const perfetto::internal::DataSourceType::InstancesIterator* ii,
1144     struct PerfettoTeTimestamp ts,
1145     struct PerfettoTeLlImplIterator* iterator) {
1146   perfetto::internal::DataSourceType* ds =
1147       perfetto::shlib::TrackEvent::GetType();
1148 
1149   auto& track_event_tls = *static_cast<perfetto::shlib::TrackEventTlsState*>(
1150       ii->instance->data_source_custom_tls.get());
1151 
1152   auto* incr_state = static_cast<perfetto::shlib::TrackEventIncrementalState*>(
1153       ds->GetIncrementalState(ii->instance, ii->i));
1154   perfetto::TraceTimestamp tts;
1155   tts.clock_id = ts.clock_id;
1156   tts.value = ts.value;
1157   ResetIncrementalStateIfRequired(ii->instance->trace_writer.get(), incr_state,
1158                                   track_event_tls, tts);
1159 
1160   iterator->incr = reinterpret_cast<struct PerfettoTeLlImplIncr*>(incr_state);
1161   iterator->tls =
1162       reinterpret_cast<struct PerfettoTeLlImplTls*>(&track_event_tls);
1163 }
1164 
PerfettoTeLlImplBegin(struct PerfettoTeCategoryImpl * cat,struct PerfettoTeTimestamp ts)1165 struct PerfettoTeLlImplIterator PerfettoTeLlImplBegin(
1166     struct PerfettoTeCategoryImpl* cat,
1167     struct PerfettoTeTimestamp ts) {
1168   struct PerfettoTeLlImplIterator ret = {};
1169   uint32_t cached_instances =
1170       perfetto::shlib::TracePointTraits::GetActiveInstances({cat})->load(
1171           std::memory_order_relaxed);
1172   if (!cached_instances) {
1173     return ret;
1174   }
1175 
1176   perfetto::internal::DataSourceType* ds =
1177       perfetto::shlib::TrackEvent::GetType();
1178 
1179   perfetto::internal::DataSourceThreadLocalState*& tls_state =
1180       *perfetto::shlib::TrackEvent::GetTlsState();
1181 
1182   if (!ds->TracePrologue<perfetto::shlib::TrackEventDataSourceTraits,
1183                          perfetto::shlib::TracePointTraits>(
1184           &tls_state, &cached_instances, {cat})) {
1185     return ret;
1186   }
1187 
1188   perfetto::internal::DataSourceType::InstancesIterator ii =
1189       ds->BeginIteration<perfetto::shlib::TracePointTraits>(cached_instances,
1190                                                             tls_state, {cat});
1191 
1192   ret.ds.inst_id = ii.i;
1193   tls_state->root_tls->cached_instances = ii.cached_instances;
1194   ret.ds.tracer = reinterpret_cast<struct PerfettoDsTracerImpl*>(ii.instance);
1195   if (!ret.ds.tracer) {
1196     ds->TraceEpilogue(tls_state);
1197     return ret;
1198   }
1199 
1200   FillIterator(&ii, ts, &ret);
1201 
1202   ret.ds.tls = reinterpret_cast<struct PerfettoDsTlsImpl*>(tls_state);
1203   return ret;
1204 }
1205 
PerfettoTeLlImplNext(struct PerfettoTeCategoryImpl * cat,struct PerfettoTeTimestamp ts,struct PerfettoTeLlImplIterator * iterator)1206 void PerfettoTeLlImplNext(struct PerfettoTeCategoryImpl* cat,
1207                           struct PerfettoTeTimestamp ts,
1208                           struct PerfettoTeLlImplIterator* iterator) {
1209   auto* tls = reinterpret_cast<perfetto::internal::DataSourceThreadLocalState*>(
1210       iterator->ds.tls);
1211 
1212   perfetto::internal::DataSourceType::InstancesIterator ii;
1213   ii.i = iterator->ds.inst_id;
1214   ii.cached_instances = tls->root_tls->cached_instances;
1215   ii.instance =
1216       reinterpret_cast<perfetto::internal::DataSourceInstanceThreadLocalState*>(
1217           iterator->ds.tracer);
1218 
1219   perfetto::internal::DataSourceType* ds =
1220       perfetto::shlib::TrackEvent::GetType();
1221 
1222   ds->NextIteration</*Traits=*/perfetto::shlib::TracePointTraits>(&ii, tls,
1223                                                                   {cat});
1224 
1225   iterator->ds.inst_id = ii.i;
1226   tls->root_tls->cached_instances = ii.cached_instances;
1227   iterator->ds.tracer =
1228       reinterpret_cast<struct PerfettoDsTracerImpl*>(ii.instance);
1229 
1230   if (!iterator->ds.tracer) {
1231     ds->TraceEpilogue(tls);
1232     return;
1233   }
1234 
1235   FillIterator(&ii, ts, iterator);
1236 }
1237 
PerfettoTeLlImplBreak(struct PerfettoTeCategoryImpl *,struct PerfettoTeLlImplIterator * iterator)1238 void PerfettoTeLlImplBreak(struct PerfettoTeCategoryImpl*,
1239                            struct PerfettoTeLlImplIterator* iterator) {
1240   auto* tls = reinterpret_cast<perfetto::internal::DataSourceThreadLocalState*>(
1241       iterator->ds.tls);
1242 
1243   perfetto::internal::DataSourceType* ds =
1244       perfetto::shlib::TrackEvent::GetType();
1245 
1246   ds->TraceEpilogue(tls);
1247 }
1248 
PerfettoTeLlImplDynCatEnabled(struct PerfettoDsTracerImpl * tracer,PerfettoDsInstanceIndex inst_id,const struct PerfettoTeCategoryDescriptor * dyn_cat)1249 bool PerfettoTeLlImplDynCatEnabled(
1250     struct PerfettoDsTracerImpl* tracer,
1251     PerfettoDsInstanceIndex inst_id,
1252     const struct PerfettoTeCategoryDescriptor* dyn_cat) {
1253   perfetto::internal::DataSourceType* ds =
1254       perfetto::shlib::TrackEvent::GetType();
1255 
1256   auto* tls_inst =
1257       reinterpret_cast<perfetto::internal::DataSourceInstanceThreadLocalState*>(
1258           tracer);
1259 
1260   auto* incr_state = static_cast<perfetto::shlib::TrackEventIncrementalState*>(
1261       ds->GetIncrementalState(tls_inst, inst_id));
1262 
1263   return IsDynamicCategoryEnabled(inst_id, incr_state, *dyn_cat);
1264 }
1265 
PerfettoTeLlImplTrackSeen(struct PerfettoTeLlImplIncr * incr,uint64_t uuid)1266 bool PerfettoTeLlImplTrackSeen(struct PerfettoTeLlImplIncr* incr,
1267                                uint64_t uuid) {
1268   auto* incr_state =
1269       reinterpret_cast<perfetto::shlib::TrackEventIncrementalState*>(incr);
1270 
1271   return !incr_state->seen_track_uuids.insert(uuid).second;
1272 }
1273 
PerfettoTeLlImplIntern(struct PerfettoTeLlImplIncr * incr,int32_t type,const void * data,size_t data_size,bool * seen)1274 uint64_t PerfettoTeLlImplIntern(struct PerfettoTeLlImplIncr* incr,
1275                                 int32_t type,
1276                                 const void* data,
1277                                 size_t data_size,
1278                                 bool* seen) {
1279   auto* incr_state =
1280       reinterpret_cast<perfetto::shlib::TrackEventIncrementalState*>(incr);
1281 
1282   auto res = incr_state->iids.FindOrAssign(type, data, data_size);
1283   *seen = !res.newly_assigned;
1284   return res.iid;
1285 }
1286