1 /*
2 * Copyright (C) 2019 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/track_tracker.h"
18
19 #include <cstddef>
20 #include <cstdint>
21 #include <optional>
22 #include <utility>
23
24 #include "perfetto/base/compiler.h"
25 #include "perfetto/base/logging.h"
26 #include "perfetto/ext/base/string_view.h"
27 #include "src/trace_processor/importers/common/args_tracker.h"
28 #include "src/trace_processor/importers/common/cpu_tracker.h"
29 #include "src/trace_processor/importers/common/process_track_translation_table.h"
30 #include "src/trace_processor/importers/common/tracks_internal.h"
31 #include "src/trace_processor/storage/trace_storage.h"
32 #include "src/trace_processor/tables/track_tables_py.h"
33 #include "src/trace_processor/types/trace_processor_context.h"
34 #include "src/trace_processor/types/variadic.h"
35
36 namespace perfetto::trace_processor {
37 namespace {
38
IsLegacyStringIdNameAllowed(tracks::TrackClassification classification)39 bool IsLegacyStringIdNameAllowed(tracks::TrackClassification classification) {
40 // **DO NOT** add new values here. Use TrackTracker::AutoName instead.
41 return classification == tracks::unknown;
42 }
43
IsLegacyCharArrayNameAllowed(tracks::TrackClassification classification)44 bool IsLegacyCharArrayNameAllowed(tracks::TrackClassification classification) {
45 // **DO NOT** add new values here. Use TrackTracker::AutoName instead.
46 return classification == tracks::cpu_funcgraph ||
47 classification == tracks::cpu_irq ||
48 classification == tracks::cpu_mali_irq ||
49 classification == tracks::cpu_napi_gro ||
50 classification == tracks::cpu_softirq ||
51 classification == tracks::pkvm_hypervisor;
52 }
53
54 } // namespace
55
TrackTracker(TraceProcessorContext * context)56 TrackTracker::TrackTracker(TraceProcessorContext* context)
57 : source_key_(context->storage->InternString("source")),
58 trace_id_key_(context->storage->InternString("trace_id")),
59 trace_id_is_process_scoped_key_(
60 context->storage->InternString("trace_id_is_process_scoped")),
61 source_scope_key_(context->storage->InternString("source_scope")),
62 category_key_(context->storage->InternString("category")),
63 scope_id_(context->storage->InternString("scope")),
64 cookie_id_(context->storage->InternString("cookie")),
65 fuchsia_source_(context->storage->InternString("fuchsia")),
66 chrome_source_(context->storage->InternString("chrome")),
67 utid_id_(context->storage->InternString("utid")),
68 upid_id_(context->storage->InternString("upid")),
69 cpu_id_(context->storage->InternString("cpu")),
70 uid_id_(context->storage->InternString("uid")),
71 gpu_id_(context->storage->InternString("gpu")),
72 name_id_(context->storage->InternString("name")),
73 context_(context),
74 args_tracker_(context) {}
75
CreateTrack(tracks::TrackClassification classification,std::optional<Dimensions> dimensions,const TrackName & name)76 TrackId TrackTracker::CreateTrack(tracks::TrackClassification classification,
77 std::optional<Dimensions> dimensions,
78 const TrackName& name) {
79 tables::TrackTable::Row row(StringIdFromTrackName(classification, name));
80 row.classification =
81 context_->storage->InternString(tracks::ToString(classification));
82 if (dimensions) {
83 row.dimension_arg_set_id = dimensions->arg_set_id;
84 }
85 row.machine_id = context_->machine_id();
86
87 return context_->storage->mutable_track_table()->Insert(row).id;
88 }
89
CreateProcessTrack(tracks::TrackClassification classification,UniquePid upid,std::optional<Dimensions> dims,const TrackName & name)90 TrackId TrackTracker::CreateProcessTrack(
91 tracks::TrackClassification classification,
92 UniquePid upid,
93 std::optional<Dimensions> dims,
94 const TrackName& name) {
95 Dimensions dims_id =
96 dims ? *dims : SingleDimension(upid_id_, Variadic::Integer(upid));
97
98 tables::ProcessTrackTable::Row row(
99 StringIdFromTrackName(classification, name));
100 row.upid = upid;
101 row.dimension_arg_set_id = dims_id.arg_set_id;
102 row.classification =
103 context_->storage->InternString(tracks::ToString(classification));
104 row.machine_id = context_->machine_id();
105
106 return context_->storage->mutable_process_track_table()->Insert(row).id;
107 }
108
CreateThreadTrack(tracks::TrackClassification classification,UniqueTid utid,const TrackName & name)109 TrackId TrackTracker::CreateThreadTrack(
110 tracks::TrackClassification classification,
111 UniqueTid utid,
112 const TrackName& name) {
113 Dimensions dims_id = SingleDimension(utid_id_, Variadic::Integer(utid));
114
115 tables::ThreadTrackTable::Row row(
116 StringIdFromTrackName(classification, name));
117 row.utid = utid;
118 row.classification =
119 context_->storage->InternString(tracks::ToString(classification));
120 row.dimension_arg_set_id = dims_id.arg_set_id;
121 row.machine_id = context_->machine_id();
122
123 return context_->storage->mutable_thread_track_table()->Insert(row).id;
124 }
125
InternProcessTrack(tracks::TrackClassification classification,UniquePid upid,const TrackName & name)126 TrackId TrackTracker::InternProcessTrack(
127 tracks::TrackClassification classification,
128 UniquePid upid,
129 const TrackName& name) {
130 Dimensions dims_id = SingleDimension(upid_id_, Variadic::Integer(upid));
131
132 auto* it = tracks_.Find({classification, dims_id});
133 if (it)
134 return *it;
135
136 TrackId track_id =
137 CreateProcessTrack(classification, upid, std::nullopt, name);
138 tracks_[{classification, dims_id}] = track_id;
139 return track_id;
140 }
141
InternThreadTrack(UniqueTid utid,const TrackName & name)142 TrackId TrackTracker::InternThreadTrack(UniqueTid utid, const TrackName& name) {
143 Dimensions dims = SingleDimension(utid_id_, Variadic::Integer(utid));
144
145 auto* it = tracks_.Find({tracks::thread, dims});
146 if (it)
147 return *it;
148 TrackId track_id = CreateThreadTrack(tracks::thread, utid, name);
149 tracks_[{tracks::thread, dims}] = track_id;
150 return track_id;
151 }
152
InternCpuTrack(tracks::TrackClassification classification,uint32_t cpu,const TrackName & name)153 TrackId TrackTracker::InternCpuTrack(tracks::TrackClassification classification,
154 uint32_t cpu,
155 const TrackName& name) {
156 MarkCpuValid(cpu);
157
158 Dimensions dims_id = SingleDimension(cpu_id_, Variadic::Integer(cpu));
159 auto* it = tracks_.Find({classification, dims_id});
160 if (it) {
161 return *it;
162 }
163
164 tables::CpuTrackTable::Row row(StringIdFromTrackName(classification, name));
165 row.cpu = cpu;
166 row.machine_id = context_->machine_id();
167 row.classification =
168 context_->storage->InternString(tracks::ToString(classification));
169 row.dimension_arg_set_id = dims_id.arg_set_id;
170
171 TrackId track_id =
172 context_->storage->mutable_cpu_track_table()->Insert(row).id;
173 tracks_[{classification, dims_id}] = track_id;
174 return track_id;
175 }
176
LegacyInternGpuTrack(const tables::GpuTrackTable::Row & row)177 TrackId TrackTracker::LegacyInternGpuTrack(
178 const tables::GpuTrackTable::Row& row) {
179 DimensionsBuilder dims_builder = CreateDimensionsBuilder();
180 dims_builder.AppendGpu(row.context_id.value_or(0));
181 if (row.scope != kNullStringId) {
182 dims_builder.AppendDimension(scope_id_, Variadic::String(row.scope));
183 }
184 dims_builder.AppendName(row.name);
185 Dimensions dims_id = std::move(dims_builder).Build();
186
187 TrackMapKey key;
188 key.classification = tracks::unknown;
189 key.dimensions = dims_id;
190
191 auto* it = tracks_.Find(key);
192 if (it)
193 return *it;
194
195 auto row_copy = row;
196 row_copy.classification =
197 context_->storage->InternString(tracks::ToString(tracks::unknown));
198 row_copy.dimension_arg_set_id = dims_id.arg_set_id;
199 row_copy.machine_id = context_->machine_id();
200
201 TrackId track_id =
202 context_->storage->mutable_gpu_track_table()->Insert(row_copy).id;
203 tracks_[key] = track_id;
204 return track_id;
205 }
206
LegacyInternLegacyChromeAsyncTrack(StringId raw_name,uint32_t upid,int64_t trace_id,bool trace_id_is_process_scoped,StringId source_scope)207 TrackId TrackTracker::LegacyInternLegacyChromeAsyncTrack(
208 StringId raw_name,
209 uint32_t upid,
210 int64_t trace_id,
211 bool trace_id_is_process_scoped,
212 StringId source_scope) {
213 DimensionsBuilder dims_builder = CreateDimensionsBuilder();
214 dims_builder.AppendDimension(scope_id_, Variadic::String(source_scope));
215 if (trace_id_is_process_scoped) {
216 dims_builder.AppendUpid(upid);
217 }
218 dims_builder.AppendDimension(cookie_id_, Variadic::Integer(trace_id));
219
220 const StringId name =
221 context_->process_track_translation_table->TranslateName(raw_name);
222
223 TrackMapKey key;
224 key.classification = tracks::unknown;
225 key.dimensions = std::move(dims_builder).Build();
226
227 auto* it = tracks_.Find(key);
228 if (it) {
229 if (name != kNullStringId) {
230 // The track may have been created for an end event without name. In
231 // that case, update it with this event's name.
232 auto& tracks = *context_->storage->mutable_track_table();
233 auto rr = *tracks.FindById(*it);
234 if (rr.name() == kNullStringId) {
235 rr.set_name(name);
236 }
237 }
238 return *it;
239 }
240
241 // Legacy async tracks are always drawn in the context of a process, even if
242 // the ID's scope is global.
243 tables::ProcessTrackTable::Row track(name);
244 track.upid = upid;
245 track.classification =
246 context_->storage->InternString(tracks::ToString(tracks::unknown));
247 track.dimension_arg_set_id = key.dimensions->arg_set_id;
248 track.machine_id = context_->machine_id();
249
250 TrackId id =
251 context_->storage->mutable_process_track_table()->Insert(track).id;
252 tracks_[key] = id;
253
254 args_tracker_.AddArgsTo(id)
255 .AddArg(source_key_, Variadic::String(chrome_source_))
256 .AddArg(trace_id_key_, Variadic::Integer(trace_id))
257 .AddArg(trace_id_is_process_scoped_key_,
258 Variadic::Boolean(trace_id_is_process_scoped))
259 .AddArg(source_scope_key_, Variadic::String(source_scope));
260 args_tracker_.Flush();
261
262 return id;
263 }
264
StringIdFromTrackName(tracks::TrackClassification classification,const TrackTracker::TrackName & name)265 StringId TrackTracker::StringIdFromTrackName(
266 tracks::TrackClassification classification,
267 const TrackTracker::TrackName& name) {
268 switch (name.index()) {
269 case base::variant_index<TrackName, AutoName>():
270 return kNullStringId;
271 case base::variant_index<TrackName, LegacyStringIdName>():
272 PERFETTO_DCHECK(IsLegacyStringIdNameAllowed(classification));
273 return std::get<LegacyStringIdName>(name).id;
274 case base::variant_index<TrackName, LegacyCharArrayName>():
275 PERFETTO_DCHECK(IsLegacyCharArrayNameAllowed(classification));
276 return context_->storage->InternString(
277 std::get<LegacyCharArrayName>(name).name);
278 }
279 PERFETTO_FATAL("For GCC");
280 }
281
AddTrack(const tracks::BlueprintBase & blueprint,StringId name,StringId counter_unit,GlobalArgsTracker::CompactArg * d_args,uint32_t d_size,const SetArgsCallback & args)282 TrackId TrackTracker::AddTrack(const tracks::BlueprintBase& blueprint,
283 StringId name,
284 StringId counter_unit,
285 GlobalArgsTracker::CompactArg* d_args,
286 uint32_t d_size,
287 const SetArgsCallback& args) {
288 const auto* dims = blueprint.dimension_blueprints.data();
289 for (uint32_t i = 0; i < d_size; ++i) {
290 StringId key = context_->storage->InternString(
291 base::StringView(dims[i].name.data(), dims[i].name.size()));
292 d_args[i].key = key;
293 d_args[i].flat_key = key;
294 }
295
296 tables::TrackTable::Row row(name);
297 row.machine_id = context_->machine_id();
298 row.classification = context_->storage->InternString(base::StringView(
299 blueprint.classification.data(), blueprint.classification.size()));
300 if (d_size > 0) {
301 row.dimension_arg_set_id =
302 context_->global_args_tracker->AddArgSet(d_args, 0, d_size);
303 }
304 row.event_type = context_->storage->InternString(blueprint.event_type);
305 row.counter_unit = counter_unit;
306 TrackId id = context_->storage->mutable_track_table()->Insert(row).id;
307 if (args) {
308 auto inserter = args_tracker_.AddArgsTo(id);
309 args(inserter);
310 args_tracker_.Flush();
311 }
312 return id;
313 }
314
MarkCpuValid(uint32_t cpu)315 void TrackTracker::MarkCpuValid(uint32_t cpu) {
316 context_->cpu_tracker->MarkCpuValid(cpu);
317 }
318
319 } // namespace perfetto::trace_processor
320