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