xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/common/async_track_set_tracker.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/trace_processor/importers/common/async_track_set_tracker.h"
18 
19 #include "src/trace_processor/importers/common/process_track_translation_table.h"
20 #include "src/trace_processor/importers/common/track_tracker.h"
21 #include "src/trace_processor/storage/trace_storage.h"
22 #include "src/trace_processor/types/trace_processor_context.h"
23 
24 namespace perfetto::trace_processor {
25 
AsyncTrackSetTracker(TraceProcessorContext * context)26 AsyncTrackSetTracker::AsyncTrackSetTracker(TraceProcessorContext* context)
27     : android_source_(context->storage->InternString("android")),
28       context_(context) {}
29 
InternGlobalTrackSet(StringId name)30 AsyncTrackSetTracker::TrackSetId AsyncTrackSetTracker::InternGlobalTrackSet(
31     StringId name) {
32   auto it = global_track_set_ids_.find(name);
33   if (it != global_track_set_ids_.end()) {
34     return it->second;
35   }
36 
37   uint32_t id = static_cast<uint32_t>(track_sets_.size());
38   TrackSet set;
39   set.global_track_name = name;
40   set.scope = TrackSetScope::kGlobal;
41   set.nesting_behaviour = NestingBehaviour::kNestable;
42   track_sets_.emplace_back(set);
43 
44   return global_track_set_ids_[name] = id;
45 }
46 
InternProcessTrackSet(UniquePid upid,StringId name)47 AsyncTrackSetTracker::TrackSetId AsyncTrackSetTracker::InternProcessTrackSet(
48     UniquePid upid,
49     StringId name) {
50   ProcessTuple tuple{upid, name};
51 
52   auto it = process_track_set_ids_.find(tuple);
53   if (it != process_track_set_ids_.end())
54     return it->second;
55 
56   uint32_t id = static_cast<uint32_t>(track_sets_.size());
57 
58   TrackSet set;
59   set.process_tuple = tuple;
60   set.scope = TrackSetScope::kProcess;
61   set.nesting_behaviour = NestingBehaviour::kNestable;
62   track_sets_.emplace_back(set);
63 
64   process_track_set_ids_[tuple] = id;
65   return id;
66 }
67 
68 AsyncTrackSetTracker::TrackSetId
InternAndroidLegacyUnnestableTrackSet(UniquePid upid,StringId name)69 AsyncTrackSetTracker::InternAndroidLegacyUnnestableTrackSet(UniquePid upid,
70                                                             StringId name) {
71   ProcessTuple tuple{upid, name};
72 
73   auto it = android_legacy_unnestable_track_set_ids_.find(tuple);
74   if (it != android_legacy_unnestable_track_set_ids_.end())
75     return it->second;
76 
77   uint32_t id = static_cast<uint32_t>(track_sets_.size());
78 
79   TrackSet set;
80   set.process_tuple = tuple;
81   set.scope = TrackSetScope::kProcess;
82   set.nesting_behaviour = NestingBehaviour::kLegacySaturatingUnnestable;
83   track_sets_.emplace_back(set);
84 
85   android_legacy_unnestable_track_set_ids_[tuple] = id;
86   return id;
87 }
88 
Begin(TrackSetId id,int64_t cookie)89 TrackId AsyncTrackSetTracker::Begin(TrackSetId id, int64_t cookie) {
90   PERFETTO_DCHECK(id < track_sets_.size());
91 
92   TrackSet& set = track_sets_[id];
93   TrackState& state = GetOrCreateTrackForCookie(set, cookie);
94   switch (set.nesting_behaviour) {
95     case NestingBehaviour::kNestable:
96       state.nest_count++;
97       break;
98     case NestingBehaviour::kLegacySaturatingUnnestable:
99       PERFETTO_DCHECK(state.nest_count <= 1);
100       state.nest_count = 1;
101       break;
102   }
103   return state.id;
104 }
105 
End(TrackSetId id,int64_t cookie)106 TrackId AsyncTrackSetTracker::End(TrackSetId id, int64_t cookie) {
107   PERFETTO_DCHECK(id < track_sets_.size());
108 
109   TrackSet& set = track_sets_[id];
110   TrackState& state = GetOrCreateTrackForCookie(set, cookie);
111 
112   // It's possible to have a nest count of 0 even when we know about the track.
113   // Suppose the following sequence of events for some |id| and |cookie|:
114   //   Begin
115   //   (trace starts)
116   //   Begin
117   //   End
118   //   End <- nest count == 0 here even though we have a record of this track.
119   if (state.nest_count > 0)
120     state.nest_count--;
121   return state.id;
122 }
123 
Scoped(TrackSetId id,int64_t ts,int64_t dur)124 TrackId AsyncTrackSetTracker::Scoped(TrackSetId id, int64_t ts, int64_t dur) {
125   PERFETTO_DCHECK(id < track_sets_.size());
126 
127   TrackSet& set = track_sets_[id];
128   PERFETTO_DCHECK(set.nesting_behaviour !=
129                   NestingBehaviour::kLegacySaturatingUnnestable);
130 
131   auto it = std::find_if(
132       set.tracks.begin(), set.tracks.end(), [ts](const TrackState& state) {
133         return state.slice_type == TrackState::SliceType::kTimestamp &&
134                state.ts_end <= ts;
135       });
136   if (it != set.tracks.end()) {
137     it->ts_end = ts + dur;
138     return it->id;
139   }
140 
141   TrackState state;
142   state.slice_type = TrackState::SliceType::kTimestamp;
143   state.ts_end = ts + dur;
144   state.id = CreateTrackForSet(set);
145   set.tracks.emplace_back(state);
146 
147   return state.id;
148 }
149 
150 AsyncTrackSetTracker::TrackState&
GetOrCreateTrackForCookie(TrackSet & set,int64_t cookie)151 AsyncTrackSetTracker::GetOrCreateTrackForCookie(TrackSet& set, int64_t cookie) {
152   auto it = std::find_if(
153       set.tracks.begin(), set.tracks.end(), [cookie](const TrackState& state) {
154         return state.slice_type == TrackState::SliceType::kCookie &&
155                state.cookie == cookie;
156       });
157   if (it != set.tracks.end())
158     return *it;
159 
160   it = std::find_if(
161       set.tracks.begin(), set.tracks.end(), [](const TrackState& state) {
162         return state.slice_type == TrackState::SliceType::kCookie &&
163                state.nest_count == 0;
164       });
165   if (it != set.tracks.end()) {
166     // Adopt this track for the cookie to make sure future slices with this
167     // cookie also get associated to this track.
168     it->cookie = cookie;
169     return *it;
170   }
171 
172   TrackState state;
173   state.id = CreateTrackForSet(set);
174   state.slice_type = TrackState::SliceType::kCookie;
175   state.cookie = cookie;
176   state.nest_count = 0;
177   set.tracks.emplace_back(state);
178 
179   return set.tracks.back();
180 }
181 
CreateTrackForSet(const TrackSet & set)182 TrackId AsyncTrackSetTracker::CreateTrackForSet(const TrackSet& set) {
183   switch (set.scope) {
184     case TrackSetScope::kGlobal: {
185       // TODO(lalitm): propogate source from callers as a dimension
186       TrackTracker::DimensionsBuilder builder =
187           context_->track_tracker->CreateDimensionsBuilder();
188       builder.AppendName(set.global_track_name);
189       return context_->track_tracker->CreateTrack(
190           tracks::unknown, std::move(builder).Build(),
191           TrackTracker::LegacyStringIdName{set.global_track_name});
192     }
193     case TrackSetScope::kProcess:
194       // TODO(lalitm): propogate source from callers rather than just passing
195       // kNullStringId here.
196       StringId source =
197           set.nesting_behaviour == NestingBehaviour::kLegacySaturatingUnnestable
198               ? android_source_
199               : kNullStringId;
200 
201       const StringId name =
202           context_->process_track_translation_table->TranslateName(
203               set.process_tuple.name);
204       TrackTracker::DimensionsBuilder dims_builder =
205           context_->track_tracker->CreateDimensionsBuilder();
206       dims_builder.AppendName(name);
207       dims_builder.AppendUpid(set.process_tuple.upid);
208       TrackTracker::Dimensions dims_id = std::move(dims_builder).Build();
209 
210       TrackId id = context_->track_tracker->CreateProcessTrack(
211           tracks::unknown, set.process_tuple.upid, dims_id,
212           TrackTracker::LegacyStringIdName{name});
213 
214       if (!source.is_null()) {
215         context_->args_tracker->AddArgsTo(id).AddArg(source,
216                                                      Variadic::String(source));
217       }
218       return id;
219   }
220 
221   PERFETTO_FATAL("For GCC");
222 }
223 
224 }  // namespace perfetto::trace_processor
225