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