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