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