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