xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/proto/track_event_tracker.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2020 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 "src/trace_processor/importers/proto/track_event_tracker.h"
18 
19 #include <algorithm>
20 #include <cinttypes>
21 #include <cstddef>
22 #include <cstdint>
23 #include <map>
24 #include <memory>
25 #include <optional>
26 #include <tuple>
27 #include <utility>
28 #include <vector>
29 
30 #include "perfetto/base/logging.h"
31 #include "src/trace_processor/importers/common/args_tracker.h"
32 #include "src/trace_processor/importers/common/process_track_translation_table.h"
33 #include "src/trace_processor/importers/common/process_tracker.h"
34 #include "src/trace_processor/importers/common/track_tracker.h"
35 #include "src/trace_processor/importers/common/tracks.h"
36 #include "src/trace_processor/importers/common/tracks_common.h"
37 #include "src/trace_processor/importers/common/tracks_internal.h"
38 #include "src/trace_processor/storage/stats.h"
39 #include "src/trace_processor/storage/trace_storage.h"
40 #include "src/trace_processor/types/trace_processor_context.h"
41 #include "src/trace_processor/types/variadic.h"
42 
43 namespace perfetto::trace_processor {
44 
45 namespace {
46 
47 constexpr auto kThreadCounterTrackBlueprint = tracks::CounterBlueprint(
48     "thread_counter_track_event",
49     tracks::DynamicUnitBlueprint(),
50     tracks::DimensionBlueprints(tracks::kThreadDimensionBlueprint,
51                                 tracks::LongDimensionBlueprint("track_uuid")),
52     tracks::DynamicNameBlueprint());
53 
54 constexpr auto kProcessCounterTrackBlueprint = tracks::CounterBlueprint(
55     "process_counter_track_event",
56     tracks::DynamicUnitBlueprint(),
57     tracks::DimensionBlueprints(tracks::kProcessDimensionBlueprint,
58                                 tracks::LongDimensionBlueprint("track_uuid")),
59     tracks::DynamicNameBlueprint());
60 
61 constexpr auto kGlobalCounterTrackBlueprint = tracks::CounterBlueprint(
62     "global_track_event",
63     tracks::DynamicUnitBlueprint(),
64     tracks::DimensionBlueprints(tracks::LongDimensionBlueprint("track_uuid")),
65     tracks::DynamicNameBlueprint());
66 
67 }  // namespace
68 
TrackEventTracker(TraceProcessorContext * context)69 TrackEventTracker::TrackEventTracker(TraceProcessorContext* context)
70     : source_key_(context->storage->InternString("source")),
71       source_id_key_(context->storage->InternString("trace_id")),
72       is_root_in_scope_key_(context->storage->InternString("is_root_in_scope")),
73       category_key_(context->storage->InternString("category")),
74       has_first_packet_on_sequence_key_id_(
75           context->storage->InternString("has_first_packet_on_sequence")),
76       child_ordering_key_(context->storage->InternString("child_ordering")),
77       explicit_id_(context->storage->InternString("explicit")),
78       lexicographic_id_(context->storage->InternString("lexicographic")),
79       chronological_id_(context->storage->InternString("chronological")),
80       sibling_order_rank_key_(
81           context->storage->InternString("sibling_order_rank")),
82       descriptor_source_(context->storage->InternString("descriptor")),
83       default_descriptor_track_name_(
84           context->storage->InternString("Default Track")),
85       context_(context) {}
86 
ReserveDescriptorTrack(uint64_t uuid,const DescriptorTrackReservation & reservation)87 void TrackEventTracker::ReserveDescriptorTrack(
88     uint64_t uuid,
89     const DescriptorTrackReservation& reservation) {
90   std::map<uint64_t, DescriptorTrackReservation>::iterator it;
91   bool inserted;
92   std::tie(it, inserted) =
93       reserved_descriptor_tracks_.insert(std::make_pair<>(uuid, reservation));
94 
95   if (inserted)
96     return;
97 
98   if (!it->second.IsForSameTrack(reservation)) {
99     PERFETTO_DLOG("New track reservation for process track with uuid %" PRIu64
100                   " doesn't match earlier one",
101                   uuid);
102     context_->storage->IncrementStats(stats::track_event_tokenizer_errors);
103     return;
104   }
105   it->second.min_timestamp =
106       std::min(it->second.min_timestamp, reservation.min_timestamp);
107 }
108 
GetDescriptorTrack(uint64_t uuid,StringId event_name,std::optional<uint32_t> packet_sequence_id)109 std::optional<TrackId> TrackEventTracker::GetDescriptorTrack(
110     uint64_t uuid,
111     StringId event_name,
112     std::optional<uint32_t> packet_sequence_id) {
113   std::optional<TrackId> track_id =
114       GetDescriptorTrackImpl(uuid, packet_sequence_id);
115   if (!track_id || event_name.is_null())
116     return track_id;
117 
118   // Update the name of the track if unset and the track is not the primary
119   // track of a process/thread or a counter track.
120   auto rr = *context_->storage->mutable_track_table()->FindById(*track_id);
121   if (!rr.name().is_null()) {
122     return track_id;
123   }
124 
125   // Check reservation for track type.
126   auto reservation_it = reserved_descriptor_tracks_.find(uuid);
127   PERFETTO_CHECK(reservation_it != reserved_descriptor_tracks_.end());
128 
129   if (reservation_it->second.pid || reservation_it->second.tid ||
130       reservation_it->second.is_counter) {
131     return track_id;
132   }
133   rr.set_name(
134       context_->process_track_translation_table->TranslateName(event_name));
135   return track_id;
136 }
137 
GetDescriptorTrackImpl(uint64_t uuid,std::optional<uint32_t> packet_sequence_id)138 std::optional<TrackId> TrackEventTracker::GetDescriptorTrackImpl(
139     uint64_t uuid,
140     std::optional<uint32_t> packet_sequence_id) {
141   auto it = descriptor_tracks_.find(uuid);
142   if (it != descriptor_tracks_.end())
143     return it->second;
144 
145   std::optional<ResolvedDescriptorTrack> resolved_track =
146       ResolveDescriptorTrack(uuid, nullptr);
147   if (!resolved_track)
148     return std::nullopt;
149 
150   // The reservation must exist as |resolved_track| would have been std::nullopt
151   // otherwise.
152   auto reserved_it = reserved_descriptor_tracks_.find(uuid);
153   PERFETTO_CHECK(reserved_it != reserved_descriptor_tracks_.end());
154 
155   const auto& reservation = reserved_it->second;
156 
157   // We resolve parent_id here to ensure that it's going to be smaller
158   // than the id of the child.
159   std::optional<TrackId> parent_id;
160   if (reservation.parent_uuid != 0) {
161     parent_id = GetDescriptorTrackImpl(reservation.parent_uuid);
162   }
163 
164   TrackId track_id = CreateTrackFromResolved(uuid, packet_sequence_id,
165                                              reservation, *resolved_track);
166   descriptor_tracks_[uuid] = track_id;
167 
168   auto row_ref = *context_->storage->mutable_track_table()->FindById(track_id);
169   if (!row_ref.source_arg_set_id().has_value()) {
170     auto inserter = context_->args_tracker->AddArgsTo(track_id);
171     AddTrackArgs(uuid, packet_sequence_id, reservation, *resolved_track,
172                  inserter);
173   }
174   if (parent_id) {
175     row_ref.set_parent_id(*parent_id);
176   }
177   if (!reservation.name.is_null()) {
178     // Initialize the track name here, so that, if a name was given in the
179     // reservation, it is set immediately after resolution takes place.
180     row_ref.set_name(reservation.name);
181   }
182   return track_id;
183 }
184 
CreateTrackFromResolved(uint64_t uuid,std::optional<uint32_t> packet_sequence_id,const DescriptorTrackReservation & reservation,const ResolvedDescriptorTrack & track)185 TrackId TrackEventTracker::CreateTrackFromResolved(
186     uint64_t uuid,
187     std::optional<uint32_t> packet_sequence_id,
188     const DescriptorTrackReservation& reservation,
189     const ResolvedDescriptorTrack& track) {
190   if (track.is_root_in_scope()) {
191     switch (track.scope()) {
192       case ResolvedDescriptorTrack::Scope::kThread: {
193         if (track.use_separate_track()) {
194           auto it = thread_tracks_.find(track.utid());
195           if (it != thread_tracks_.end()) {
196             return it->second;
197           }
198           TrackId id = context_->track_tracker->CreateThreadTrack(
199               tracks::track_event, track.utid(), TrackTracker::AutoName());
200           thread_tracks_[track.utid()] = id;
201           return id;
202         }
203         return context_->track_tracker->InternThreadTrack(track.utid());
204       }
205       case ResolvedDescriptorTrack::Scope::kProcess:
206         return context_->track_tracker->InternProcessTrack(tracks::track_event,
207                                                            track.upid());
208       case ResolvedDescriptorTrack::Scope::kGlobal:
209         // Will be handled below.
210         break;
211     }
212   }
213 
214   if (track.is_counter()) {
215     switch (track.scope()) {
216       case ResolvedDescriptorTrack::Scope::kThread:
217         return context_->track_tracker->InternTrack(
218             kThreadCounterTrackBlueprint,
219             tracks::Dimensions(track.utid(), static_cast<int64_t>(uuid)),
220             tracks::DynamicName(kNullStringId),
221             [&, this](ArgsTracker::BoundInserter& inserter) {
222               AddTrackArgs(uuid, packet_sequence_id, reservation, track,
223                            inserter);
224             },
225             tracks::DynamicUnit(reservation.counter_details->unit));
226       case ResolvedDescriptorTrack::Scope::kProcess:
227         return context_->track_tracker->InternTrack(
228             kProcessCounterTrackBlueprint,
229             tracks::Dimensions(track.upid(), static_cast<int64_t>(uuid)),
230             tracks::DynamicName(kNullStringId),
231             [&, this](ArgsTracker::BoundInserter& inserter) {
232               AddTrackArgs(uuid, packet_sequence_id, reservation, track,
233                            inserter);
234             },
235             tracks::DynamicUnit(reservation.counter_details->unit));
236       case ResolvedDescriptorTrack::Scope::kGlobal:
237         return context_->track_tracker->InternTrack(
238             kGlobalCounterTrackBlueprint,
239             tracks::Dimensions(static_cast<int64_t>(uuid)),
240             tracks::DynamicName(kNullStringId),
241             [&, this](ArgsTracker::BoundInserter& inserter) {
242               AddTrackArgs(uuid, packet_sequence_id, reservation, track,
243                            inserter);
244             },
245             tracks::DynamicUnit(reservation.counter_details->unit));
246     }
247   }
248 
249   switch (track.scope()) {
250     case ResolvedDescriptorTrack::Scope::kThread: {
251       return context_->track_tracker->CreateThreadTrack(
252           tracks::track_event, track.utid(), TrackTracker::AutoName());
253     }
254     case ResolvedDescriptorTrack::Scope::kProcess: {
255       return context_->track_tracker->CreateProcessTrack(
256           tracks::track_event, track.upid(), std::nullopt,
257           TrackTracker::AutoName());
258     }
259     case ResolvedDescriptorTrack::Scope::kGlobal: {
260       return context_->track_tracker->CreateTrack(
261           tracks::track_event, std::nullopt, TrackTracker::AutoName());
262     }
263   }
264   PERFETTO_FATAL("For GCC");
265 }
266 
267 std::optional<TrackEventTracker::ResolvedDescriptorTrack>
ResolveDescriptorTrack(uint64_t uuid,std::vector<uint64_t> * descendent_uuids)268 TrackEventTracker::ResolveDescriptorTrack(
269     uint64_t uuid,
270     std::vector<uint64_t>* descendent_uuids) {
271   auto it = resolved_descriptor_tracks_.find(uuid);
272   if (it != resolved_descriptor_tracks_.end())
273     return it->second;
274 
275   auto reservation_it = reserved_descriptor_tracks_.find(uuid);
276   if (reservation_it == reserved_descriptor_tracks_.end())
277     return std::nullopt;
278 
279   // Resolve process and thread id for tracks produced from within a pid
280   // namespace.
281   // Get the root-level trusted_pid for the process that produces the track
282   // event.
283   auto opt_trusted_pid = context_->process_tracker->GetTrustedPid(uuid);
284   auto& reservation = reservation_it->second;
285   // Try to resolve to root-level pid and tid if the process is pid-namespaced.
286   if (opt_trusted_pid && reservation.tid) {
287     auto opt_resolved_tid = context_->process_tracker->ResolveNamespacedTid(
288         *opt_trusted_pid, *reservation.tid);
289     if (opt_resolved_tid)
290       reservation.tid = *opt_resolved_tid;
291   }
292   if (opt_trusted_pid && reservation.pid) {
293     auto opt_resolved_pid = context_->process_tracker->ResolveNamespacedTid(
294         *opt_trusted_pid, *reservation.pid);
295     if (opt_resolved_pid)
296       reservation.pid = *opt_resolved_pid;
297   }
298 
299   std::optional<ResolvedDescriptorTrack> resolved_track =
300       ResolveDescriptorTrackImpl(uuid, reservation, descendent_uuids);
301   if (!resolved_track) {
302     return std::nullopt;
303   }
304   resolved_descriptor_tracks_[uuid] = *resolved_track;
305   return resolved_track;
306 }
307 
308 std::optional<TrackEventTracker::ResolvedDescriptorTrack>
ResolveDescriptorTrackImpl(uint64_t uuid,const DescriptorTrackReservation & reservation,std::vector<uint64_t> * descendent_uuids)309 TrackEventTracker::ResolveDescriptorTrackImpl(
310     uint64_t uuid,
311     const DescriptorTrackReservation& reservation,
312     std::vector<uint64_t>* descendent_uuids) {
313   static constexpr size_t kMaxAncestors = 10;
314 
315   // Try to resolve any parent tracks recursively, too.
316   std::optional<ResolvedDescriptorTrack> parent_resolved_track;
317   if (reservation.parent_uuid) {
318     // Input data may contain loops or extremely long ancestor track chains. To
319     // avoid stack overflow in these situations, we keep track of the ancestors
320     // seen in the recursion.
321     std::unique_ptr<std::vector<uint64_t>> owned_descendent_uuids;
322     if (!descendent_uuids) {
323       owned_descendent_uuids = std::make_unique<std::vector<uint64_t>>();
324       descendent_uuids = owned_descendent_uuids.get();
325     }
326     descendent_uuids->push_back(uuid);
327 
328     if (descendent_uuids->size() > kMaxAncestors) {
329       PERFETTO_ELOG(
330           "Too many ancestors in parent_track_uuid hierarchy at track %" PRIu64
331           " with parent %" PRIu64,
332           uuid, reservation.parent_uuid);
333       return std::nullopt;
334     }
335 
336     if (std::find(descendent_uuids->begin(), descendent_uuids->end(),
337                   reservation.parent_uuid) != descendent_uuids->end()) {
338       PERFETTO_ELOG(
339           "Loop detected in parent_track_uuid hierarchy at track %" PRIu64
340           " with parent %" PRIu64,
341           uuid, reservation.parent_uuid);
342       return std::nullopt;
343     }
344 
345     parent_resolved_track =
346         ResolveDescriptorTrack(reservation.parent_uuid, descendent_uuids);
347     if (!parent_resolved_track) {
348       PERFETTO_ELOG("Unknown parent track %" PRIu64 " for track %" PRIu64,
349                     reservation.parent_uuid, uuid);
350     }
351 
352     descendent_uuids->pop_back();
353     if (owned_descendent_uuids)
354       descendent_uuids = nullptr;
355   }
356 
357   if (reservation.tid) {
358     UniqueTid utid = context_->process_tracker->UpdateThread(*reservation.tid,
359                                                              *reservation.pid);
360     auto it_and_inserted =
361         descriptor_uuids_by_utid_.insert(std::make_pair<>(utid, uuid));
362     if (!it_and_inserted.second) {
363       // We already saw a another track with a different uuid for this thread.
364       // Since there should only be one descriptor track for each thread, we
365       // assume that its tid was reused. So, start a new thread.
366       uint64_t old_uuid = it_and_inserted.first->second;
367       PERFETTO_DCHECK(old_uuid != uuid);  // Every track is only resolved once.
368 
369       PERFETTO_DLOG("Detected tid reuse (pid: %" PRIu32 " tid: %" PRIu32
370                     ") from track descriptors (old uuid: %" PRIu64
371                     " new uuid: %" PRIu64 " timestamp: %" PRId64 ")",
372                     *reservation.pid, *reservation.tid, old_uuid, uuid,
373                     reservation.min_timestamp);
374 
375       utid = context_->process_tracker->StartNewThread(std::nullopt,
376                                                        *reservation.tid);
377 
378       // Associate the new thread with its process.
379       PERFETTO_CHECK(context_->process_tracker->UpdateThread(
380                          *reservation.tid, *reservation.pid) == utid);
381 
382       descriptor_uuids_by_utid_[utid] = uuid;
383     }
384     return ResolvedDescriptorTrack::Thread(utid, false /* is_counter */,
385                                            true /* is_root*/,
386                                            reservation.use_separate_track);
387   }
388 
389   if (reservation.pid) {
390     UniquePid upid =
391         context_->process_tracker->GetOrCreateProcess(*reservation.pid);
392     auto it_and_inserted =
393         descriptor_uuids_by_upid_.insert(std::make_pair<>(upid, uuid));
394     if (!it_and_inserted.second) {
395       // We already saw a another track with a different uuid for this process.
396       // Since there should only be one descriptor track for each process, we
397       // assume that its pid was reused. So, start a new process.
398       uint64_t old_uuid = it_and_inserted.first->second;
399       PERFETTO_DCHECK(old_uuid != uuid);  // Every track is only resolved once.
400 
401       PERFETTO_DLOG("Detected pid reuse (pid: %" PRIu32
402                     ") from track descriptors (old uuid: %" PRIu64
403                     " new uuid: %" PRIu64 " timestamp: %" PRId64 ")",
404                     *reservation.pid, old_uuid, uuid,
405                     reservation.min_timestamp);
406 
407       upid = context_->process_tracker->StartNewProcess(
408           std::nullopt, std::nullopt, *reservation.pid, kNullStringId,
409           ThreadNamePriority::kTrackDescriptor);
410 
411       descriptor_uuids_by_upid_[upid] = uuid;
412     }
413     return ResolvedDescriptorTrack::Process(upid, false /* is_counter */,
414                                             true /* is_root*/);
415   }
416 
417   if (parent_resolved_track) {
418     switch (parent_resolved_track->scope()) {
419       case ResolvedDescriptorTrack::Scope::kThread:
420         // If parent is a thread track, create another thread-associated track.
421         return ResolvedDescriptorTrack::Thread(
422             parent_resolved_track->utid(), reservation.is_counter,
423             false /* is_root*/, parent_resolved_track->use_separate_track());
424       case ResolvedDescriptorTrack::Scope::kProcess:
425         // If parent is a process track, create another process-associated
426         // track.
427         return ResolvedDescriptorTrack::Process(parent_resolved_track->upid(),
428                                                 reservation.is_counter,
429                                                 false /* is_root*/);
430       case ResolvedDescriptorTrack::Scope::kGlobal:
431         break;
432     }
433   }
434 
435   // Otherwise create a global track.
436 
437   // The global track with no uuid is the default global track (e.g. for
438   // global instant events). Any other global tracks are considered children
439   // of the default track.
440   bool is_root_in_scope = !parent_resolved_track;
441   if (!parent_resolved_track && uuid) {
442     // Detect loops where the default track has a parent that itself is a
443     // global track (and thus should be parent of the default track).
444     if (descendent_uuids &&
445         std::find(descendent_uuids->begin(), descendent_uuids->end(),
446                   kDefaultDescriptorTrackUuid) != descendent_uuids->end()) {
447       PERFETTO_ELOG(
448           "Loop detected in parent_track_uuid hierarchy at track %" PRIu64
449           " with parent %" PRIu64,
450           uuid, kDefaultDescriptorTrackUuid);
451       return std::nullopt;
452     }
453 
454     // This track will be implicitly a child of the default global track.
455     is_root_in_scope = false;
456   }
457   return ResolvedDescriptorTrack::Global(reservation.is_counter,
458                                          is_root_in_scope);
459 }
460 
GetOrCreateDefaultDescriptorTrack()461 TrackId TrackEventTracker::GetOrCreateDefaultDescriptorTrack() {
462   // If the default track was already reserved (e.g. because a producer emitted
463   // a descriptor for it) or created, resolve and return it.
464   std::optional<TrackId> track_id =
465       GetDescriptorTrack(kDefaultDescriptorTrackUuid);
466   if (track_id)
467     return *track_id;
468 
469   // Otherwise reserve a new track and resolve it.
470   DescriptorTrackReservation r;
471   r.parent_uuid = 0;
472   r.name = default_descriptor_track_name_;
473   ReserveDescriptorTrack(kDefaultDescriptorTrackUuid, r);
474   return *GetDescriptorTrack(kDefaultDescriptorTrackUuid);
475 }
476 
ConvertToAbsoluteCounterValue(uint64_t counter_track_uuid,uint32_t packet_sequence_id,double value)477 std::optional<double> TrackEventTracker::ConvertToAbsoluteCounterValue(
478     uint64_t counter_track_uuid,
479     uint32_t packet_sequence_id,
480     double value) {
481   auto reservation_it = reserved_descriptor_tracks_.find(counter_track_uuid);
482   if (reservation_it == reserved_descriptor_tracks_.end()) {
483     PERFETTO_DLOG("Unknown counter track with uuid %" PRIu64,
484                   counter_track_uuid);
485     return std::nullopt;
486   }
487 
488   DescriptorTrackReservation& reservation = reservation_it->second;
489   if (!reservation.is_counter) {
490     PERFETTO_DLOG("Track with uuid %" PRIu64 " is not a counter track",
491                   counter_track_uuid);
492     return std::nullopt;
493   }
494   if (!reservation.counter_details) {
495     PERFETTO_FATAL("Counter tracks require `counter_details`.");
496   }
497   DescriptorTrackReservation::CounterDetails& c_details =
498       *reservation.counter_details;
499 
500   if (c_details.unit_multiplier > 0)
501     value *= static_cast<double>(c_details.unit_multiplier);
502 
503   if (c_details.is_incremental) {
504     if (c_details.packet_sequence_id != packet_sequence_id) {
505       PERFETTO_DLOG(
506           "Incremental counter track with uuid %" PRIu64
507           " was updated from the wrong packet sequence (expected: %" PRIu32
508           " got:%" PRIu32 ")",
509           counter_track_uuid, c_details.packet_sequence_id, packet_sequence_id);
510       return std::nullopt;
511     }
512 
513     c_details.latest_value += value;
514     value = c_details.latest_value;
515   }
516 
517   return value;
518 }
519 
OnIncrementalStateCleared(uint32_t packet_sequence_id)520 void TrackEventTracker::OnIncrementalStateCleared(uint32_t packet_sequence_id) {
521   // TODO(eseckler): Improve on the runtime complexity of this. At O(hundreds)
522   // of packet sequences, incremental state clearing at O(trace second), and
523   // total number of tracks in O(thousands), a linear scan through all tracks
524   // here might not be fast enough.
525   for (auto& entry : reserved_descriptor_tracks_) {
526     DescriptorTrackReservation& reservation = entry.second;
527     // Only consider incremental counter tracks for current sequence.
528     if (!reservation.is_counter || !reservation.counter_details ||
529         !reservation.counter_details->is_incremental ||
530         reservation.counter_details->packet_sequence_id != packet_sequence_id) {
531       continue;
532     }
533     // Reset their value to 0, see CounterDescriptor's |is_incremental|.
534     reservation.counter_details->latest_value = 0;
535   }
536 }
537 
OnFirstPacketOnSequence(uint32_t packet_sequence_id)538 void TrackEventTracker::OnFirstPacketOnSequence(uint32_t packet_sequence_id) {
539   sequences_with_first_packet_.insert(packet_sequence_id);
540 }
541 
AddTrackArgs(uint64_t uuid,std::optional<uint32_t> packet_sequence_id,const DescriptorTrackReservation & reservation,const ResolvedDescriptorTrack & track,ArgsTracker::BoundInserter & args)542 void TrackEventTracker::AddTrackArgs(
543     uint64_t uuid,
544     std::optional<uint32_t> packet_sequence_id,
545     const DescriptorTrackReservation& reservation,
546     const ResolvedDescriptorTrack& track,
547     ArgsTracker::BoundInserter& args) {
548   args.AddArg(source_key_, Variadic::String(descriptor_source_))
549       .AddArg(source_id_key_, Variadic::Integer(static_cast<int64_t>(uuid)))
550       .AddArg(is_root_in_scope_key_,
551               Variadic::Boolean(track.is_root_in_scope()));
552   if (reservation.counter_details &&
553       !reservation.counter_details->category.is_null())
554     args.AddArg(category_key_,
555                 Variadic::String(reservation.counter_details->category));
556   if (packet_sequence_id &&
557       sequences_with_first_packet_.find(*packet_sequence_id) !=
558           sequences_with_first_packet_.end()) {
559     args.AddArg(has_first_packet_on_sequence_key_id_, Variadic::Boolean(true));
560   }
561 
562   switch (reservation.ordering) {
563     case DescriptorTrackReservation::ChildTracksOrdering::kLexicographic:
564       args.AddArg(child_ordering_key_, Variadic::String(lexicographic_id_));
565       break;
566     case DescriptorTrackReservation::ChildTracksOrdering::kChronological:
567       args.AddArg(child_ordering_key_, Variadic::String(chronological_id_));
568       break;
569     case DescriptorTrackReservation::ChildTracksOrdering::kExplicit:
570       args.AddArg(child_ordering_key_, Variadic::String(explicit_id_));
571       break;
572     case DescriptorTrackReservation::ChildTracksOrdering::kUnknown:
573       break;
574   }
575 
576   if (reservation.sibling_order_rank) {
577     args.AddArg(sibling_order_rank_key_,
578                 Variadic::Integer(*reservation.sibling_order_rank));
579   }
580 }
581 
582 TrackEventTracker::ResolvedDescriptorTrack
Process(UniquePid upid,bool is_counter,bool is_root)583 TrackEventTracker::ResolvedDescriptorTrack::Process(UniquePid upid,
584                                                     bool is_counter,
585                                                     bool is_root) {
586   ResolvedDescriptorTrack track;
587   track.scope_ = Scope::kProcess;
588   track.is_counter_ = is_counter;
589   track.is_root_in_scope_ = is_root;
590   track.upid_ = upid;
591   return track;
592 }
593 
594 TrackEventTracker::ResolvedDescriptorTrack
Thread(UniqueTid utid,bool is_counter,bool is_root,bool use_separate_track)595 TrackEventTracker::ResolvedDescriptorTrack::Thread(UniqueTid utid,
596                                                    bool is_counter,
597                                                    bool is_root,
598                                                    bool use_separate_track) {
599   ResolvedDescriptorTrack track;
600   track.scope_ = Scope::kThread;
601   track.is_counter_ = is_counter;
602   track.is_root_in_scope_ = is_root;
603   track.utid_ = utid;
604   track.use_separate_track_ = use_separate_track;
605   return track;
606 }
607 
608 TrackEventTracker::ResolvedDescriptorTrack
Global(bool is_counter,bool is_root)609 TrackEventTracker::ResolvedDescriptorTrack::Global(bool is_counter,
610                                                    bool is_root) {
611   ResolvedDescriptorTrack track;
612   track.scope_ = Scope::kGlobal;
613   track.is_counter_ = is_counter;
614   track.is_root_in_scope_ = is_root;
615   return track;
616 }
617 
618 }  // namespace perfetto::trace_processor
619