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 <optional>
20
21 #include "src/trace_processor/importers/common/args_tracker.h"
22 #include "src/trace_processor/importers/common/process_track_translation_table.h"
23 #include "src/trace_processor/storage/trace_storage.h"
24 #include "src/trace_processor/tables/profiler_tables_py.h"
25 #include "src/trace_processor/types/trace_processor_context.h"
26
27 namespace perfetto {
28 namespace trace_processor {
29
30 namespace {
31
GetNameForGroup(TrackTracker::Group group)32 const char* GetNameForGroup(TrackTracker::Group group) {
33 switch (group) {
34 case TrackTracker::Group::kMemory:
35 return "Memory";
36 case TrackTracker::Group::kIo:
37 return "IO";
38 case TrackTracker::Group::kVirtio:
39 return "Virtio";
40 case TrackTracker::Group::kNetwork:
41 return "Network";
42 case TrackTracker::Group::kPower:
43 return "Power";
44 case TrackTracker::Group::kDeviceState:
45 return "Device State";
46 case TrackTracker::Group::kThermals:
47 return "Thermals";
48 case TrackTracker::Group::kClockFrequency:
49 return "Clock Freqeuncy";
50 case TrackTracker::Group::kBatteryMitigation:
51 return "Battery Mitigation";
52 case TrackTracker::Group::kSizeSentinel:
53 PERFETTO_FATAL("Unexpected size passed as group");
54 }
55 PERFETTO_FATAL("For GCC");
56 }
57
58 } // namespace
59
TrackTracker(TraceProcessorContext * context)60 TrackTracker::TrackTracker(TraceProcessorContext* context)
61 : source_key_(context->storage->InternString("source")),
62 trace_id_key_(context->storage->InternString("trace_id")),
63 trace_id_is_process_scoped_key_(
64 context->storage->InternString("trace_id_is_process_scoped")),
65 source_scope_key_(context->storage->InternString("source_scope")),
66 category_key_(context->storage->InternString("category")),
67 fuchsia_source_(context->storage->InternString("fuchsia")),
68 chrome_source_(context->storage->InternString("chrome")),
69 context_(context) {}
70
InternThreadTrack(UniqueTid utid)71 TrackId TrackTracker::InternThreadTrack(UniqueTid utid) {
72 auto it = thread_tracks_.find(utid);
73 if (it != thread_tracks_.end())
74 return it->second;
75
76 tables::ThreadTrackTable::Row row;
77 row.utid = utid;
78 row.machine_id = context_->machine_id();
79 auto id = context_->storage->mutable_thread_track_table()->Insert(row).id;
80 thread_tracks_[utid] = id;
81 return id;
82 }
83
InternProcessTrack(UniquePid upid)84 TrackId TrackTracker::InternProcessTrack(UniquePid upid) {
85 auto it = process_tracks_.find(upid);
86 if (it != process_tracks_.end())
87 return it->second;
88
89 tables::ProcessTrackTable::Row row;
90 row.upid = upid;
91 row.machine_id = context_->machine_id();
92 auto id = context_->storage->mutable_process_track_table()->Insert(row).id;
93 process_tracks_[upid] = id;
94 return id;
95 }
96
InternFuchsiaAsyncTrack(StringId name,uint32_t upid,int64_t correlation_id)97 TrackId TrackTracker::InternFuchsiaAsyncTrack(StringId name,
98 uint32_t upid,
99 int64_t correlation_id) {
100 return InternLegacyChromeAsyncTrack(name, upid, correlation_id, false,
101 StringId());
102 }
103
InternCpuTrack(StringId name,uint32_t cpu)104 TrackId TrackTracker::InternCpuTrack(StringId name, uint32_t cpu) {
105 auto it = cpu_tracks_.find(std::make_pair(name, cpu));
106 if (it != cpu_tracks_.end()) {
107 return it->second;
108 }
109
110 tables::CpuTrackTable::Row row(name);
111 row.cpu = cpu;
112 row.machine_id = context_->machine_id();
113 auto id = context_->storage->mutable_cpu_track_table()->Insert(row).id;
114 cpu_tracks_[std::make_pair(name, cpu)] = id;
115
116 return id;
117 }
118
InternGpuTrack(const tables::GpuTrackTable::Row & row)119 TrackId TrackTracker::InternGpuTrack(const tables::GpuTrackTable::Row& row) {
120 GpuTrackTuple tuple{row.name, row.scope, row.context_id.value_or(0)};
121
122 auto it = gpu_tracks_.find(tuple);
123 if (it != gpu_tracks_.end())
124 return it->second;
125
126 auto row_copy = row;
127 row_copy.machine_id = context_->machine_id();
128 auto id = context_->storage->mutable_gpu_track_table()->Insert(row_copy).id;
129 gpu_tracks_[tuple] = id;
130 return id;
131 }
132
InternGpuWorkPeriodTrack(const tables::GpuWorkPeriodTrackTable::Row & row)133 TrackId TrackTracker::InternGpuWorkPeriodTrack(
134 const tables::GpuWorkPeriodTrackTable::Row& row) {
135 GpuWorkPeriodTrackTuple tuple{row.name, row.gpu_id, row.uid};
136
137 auto it = gpu_work_period_tracks_.find(tuple);
138 if (it != gpu_work_period_tracks_.end())
139 return it->second;
140
141 auto id =
142 context_->storage->mutable_gpu_work_period_track_table()->Insert(row).id;
143 gpu_work_period_tracks_[tuple] = id;
144 return id;
145 }
146
InternLegacyChromeAsyncTrack(StringId raw_name,uint32_t upid,int64_t trace_id,bool trace_id_is_process_scoped,StringId source_scope)147 TrackId TrackTracker::InternLegacyChromeAsyncTrack(
148 StringId raw_name,
149 uint32_t upid,
150 int64_t trace_id,
151 bool trace_id_is_process_scoped,
152 StringId source_scope) {
153 ChromeTrackTuple tuple;
154 if (trace_id_is_process_scoped)
155 tuple.upid = upid;
156 tuple.trace_id = trace_id;
157 tuple.source_scope = source_scope;
158
159 const StringId name =
160 context_->process_track_translation_table->TranslateName(raw_name);
161 auto it = chrome_tracks_.find(tuple);
162 if (it != chrome_tracks_.end()) {
163 if (name != kNullStringId) {
164 // The track may have been created for an end event without name. In that
165 // case, update it with this event's name.
166 auto* tracks = context_->storage->mutable_track_table();
167 uint32_t track_row = *tracks->id().IndexOf(it->second);
168 if (tracks->name()[track_row] == kNullStringId)
169 tracks->mutable_name()->Set(track_row, name);
170 }
171 return it->second;
172 }
173
174 // Legacy async tracks are always drawn in the context of a process, even if
175 // the ID's scope is global.
176 tables::ProcessTrackTable::Row track(name);
177 track.upid = upid;
178 track.machine_id = context_->machine_id();
179 TrackId id =
180 context_->storage->mutable_process_track_table()->Insert(track).id;
181 chrome_tracks_[tuple] = id;
182
183 context_->args_tracker->AddArgsTo(id)
184 .AddArg(source_key_, Variadic::String(chrome_source_))
185 .AddArg(trace_id_key_, Variadic::Integer(trace_id))
186 .AddArg(trace_id_is_process_scoped_key_,
187 Variadic::Boolean(trace_id_is_process_scoped))
188 .AddArg(source_scope_key_, Variadic::String(source_scope));
189
190 return id;
191 }
192
CreateGlobalAsyncTrack(StringId name,StringId source)193 TrackId TrackTracker::CreateGlobalAsyncTrack(StringId name, StringId source) {
194 tables::TrackTable::Row row(name);
195 row.machine_id = context_->machine_id();
196 auto id = context_->storage->mutable_track_table()->Insert(row).id;
197 if (!source.is_null()) {
198 context_->args_tracker->AddArgsTo(id).AddArg(source_key_,
199 Variadic::String(source));
200 }
201 return id;
202 }
203
CreateProcessAsyncTrack(StringId raw_name,UniquePid upid,StringId source)204 TrackId TrackTracker::CreateProcessAsyncTrack(StringId raw_name,
205 UniquePid upid,
206 StringId source) {
207 const StringId name =
208 context_->process_track_translation_table->TranslateName(raw_name);
209 tables::ProcessTrackTable::Row row(name);
210 row.upid = upid;
211 row.machine_id = context_->machine_id();
212 auto id = context_->storage->mutable_process_track_table()->Insert(row).id;
213 if (!source.is_null()) {
214 context_->args_tracker->AddArgsTo(id).AddArg(source_key_,
215 Variadic::String(source));
216 }
217 return id;
218 }
219
InternLegacyChromeProcessInstantTrack(UniquePid upid)220 TrackId TrackTracker::InternLegacyChromeProcessInstantTrack(UniquePid upid) {
221 auto it = chrome_process_instant_tracks_.find(upid);
222 if (it != chrome_process_instant_tracks_.end())
223 return it->second;
224
225 tables::ProcessTrackTable::Row row;
226 row.upid = upid;
227 row.machine_id = context_->machine_id();
228 auto id = context_->storage->mutable_process_track_table()->Insert(row).id;
229 chrome_process_instant_tracks_[upid] = id;
230
231 context_->args_tracker->AddArgsTo(id).AddArg(
232 source_key_, Variadic::String(chrome_source_));
233
234 return id;
235 }
236
GetOrCreateLegacyChromeGlobalInstantTrack()237 TrackId TrackTracker::GetOrCreateLegacyChromeGlobalInstantTrack() {
238 if (!chrome_global_instant_track_id_) {
239 tables::TrackTable::Row row;
240 row.machine_id = context_->machine_id();
241 chrome_global_instant_track_id_ =
242 context_->storage->mutable_track_table()->Insert(row).id;
243
244 context_->args_tracker->AddArgsTo(*chrome_global_instant_track_id_)
245 .AddArg(source_key_, Variadic::String(chrome_source_));
246 }
247 return *chrome_global_instant_track_id_;
248 }
249
GetOrCreateTriggerTrack()250 TrackId TrackTracker::GetOrCreateTriggerTrack() {
251 if (trigger_track_id_) {
252 return *trigger_track_id_;
253 }
254 tables::TrackTable::Row row;
255 row.name = context_->storage->InternString("Trace Triggers");
256 row.machine_id = context_->machine_id();
257 trigger_track_id_ = context_->storage->mutable_track_table()->Insert(row).id;
258 return *trigger_track_id_;
259 }
260
GetOrCreateInterconnectTrack()261 TrackId TrackTracker::GetOrCreateInterconnectTrack() {
262 if (interconnect_events_track_id_) {
263 return *interconnect_events_track_id_;
264 }
265 tables::TrackTable::Row row;
266 row.name = context_->storage->InternString("Interconnect Events");
267 row.machine_id = context_->machine_id();
268 interconnect_events_track_id_ =
269 context_->storage->mutable_track_table()->Insert(row).id;
270 return *interconnect_events_track_id_;
271 }
272
InternGlobalCounterTrack(TrackTracker::Group group,StringId name,SetArgsCallback callback,StringId unit,StringId description)273 TrackId TrackTracker::InternGlobalCounterTrack(TrackTracker::Group group,
274 StringId name,
275 SetArgsCallback callback,
276 StringId unit,
277 StringId description) {
278 auto it = global_counter_tracks_by_name_.find(name);
279 if (it != global_counter_tracks_by_name_.end()) {
280 return it->second;
281 }
282
283 tables::CounterTrackTable::Row row(name);
284 row.parent_id = InternTrackForGroup(group);
285 row.unit = unit;
286 row.description = description;
287 row.machine_id = context_->machine_id();
288 TrackId track =
289 context_->storage->mutable_counter_track_table()->Insert(row).id;
290 global_counter_tracks_by_name_[name] = track;
291 if (callback) {
292 auto inserter = context_->args_tracker->AddArgsTo(track);
293 callback(inserter);
294 }
295 return track;
296 }
297
InternCpuCounterTrack(StringId name,uint32_t cpu)298 TrackId TrackTracker::InternCpuCounterTrack(StringId name, uint32_t cpu) {
299 auto it = cpu_counter_tracks_.find(std::make_pair(name, cpu));
300 if (it != cpu_counter_tracks_.end()) {
301 return it->second;
302 }
303
304 tables::CpuCounterTrackTable::Row row(name);
305 row.cpu = cpu;
306 row.machine_id = context_->machine_id();
307
308 TrackId track =
309 context_->storage->mutable_cpu_counter_track_table()->Insert(row).id;
310 cpu_counter_tracks_[std::make_pair(name, cpu)] = track;
311 return track;
312 }
313
InternThreadCounterTrack(StringId name,UniqueTid utid)314 TrackId TrackTracker::InternThreadCounterTrack(StringId name, UniqueTid utid) {
315 auto it = utid_counter_tracks_.find(std::make_pair(name, utid));
316 if (it != utid_counter_tracks_.end()) {
317 return it->second;
318 }
319
320 tables::ThreadCounterTrackTable::Row row(name);
321 row.utid = utid;
322 row.machine_id = context_->machine_id();
323
324 TrackId track =
325 context_->storage->mutable_thread_counter_track_table()->Insert(row).id;
326 utid_counter_tracks_[std::make_pair(name, utid)] = track;
327 return track;
328 }
329
InternProcessCounterTrack(StringId raw_name,UniquePid upid,StringId unit,StringId description)330 TrackId TrackTracker::InternProcessCounterTrack(StringId raw_name,
331 UniquePid upid,
332 StringId unit,
333 StringId description) {
334 const StringId name =
335 context_->process_track_translation_table->TranslateName(raw_name);
336 auto it = upid_counter_tracks_.find(std::make_pair(name, upid));
337 if (it != upid_counter_tracks_.end()) {
338 return it->second;
339 }
340
341 tables::ProcessCounterTrackTable::Row row(name);
342 row.upid = upid;
343 row.unit = unit;
344 row.description = description;
345 row.machine_id = context_->machine_id();
346
347 TrackId track =
348 context_->storage->mutable_process_counter_track_table()->Insert(row).id;
349 upid_counter_tracks_[std::make_pair(name, upid)] = track;
350 return track;
351 }
352
InternIrqCounterTrack(StringId name,int32_t irq)353 TrackId TrackTracker::InternIrqCounterTrack(StringId name, int32_t irq) {
354 auto it = irq_counter_tracks_.find(std::make_pair(name, irq));
355 if (it != irq_counter_tracks_.end()) {
356 return it->second;
357 }
358
359 tables::IrqCounterTrackTable::Row row(name);
360 row.irq = irq;
361 row.machine_id = context_->machine_id();
362
363 TrackId track =
364 context_->storage->mutable_irq_counter_track_table()->Insert(row).id;
365 irq_counter_tracks_[std::make_pair(name, irq)] = track;
366 return track;
367 }
368
InternSoftirqCounterTrack(StringId name,int32_t softirq)369 TrackId TrackTracker::InternSoftirqCounterTrack(StringId name,
370 int32_t softirq) {
371 auto it = softirq_counter_tracks_.find(std::make_pair(name, softirq));
372 if (it != softirq_counter_tracks_.end()) {
373 return it->second;
374 }
375
376 tables::SoftirqCounterTrackTable::Row row(name);
377 row.softirq = softirq;
378 row.machine_id = context_->machine_id();
379
380 TrackId track =
381 context_->storage->mutable_softirq_counter_track_table()->Insert(row).id;
382 softirq_counter_tracks_[std::make_pair(name, softirq)] = track;
383 return track;
384 }
385
InternGpuCounterTrack(StringId name,uint32_t gpu_id)386 TrackId TrackTracker::InternGpuCounterTrack(StringId name, uint32_t gpu_id) {
387 auto it = gpu_counter_tracks_.find(std::make_pair(name, gpu_id));
388 if (it != gpu_counter_tracks_.end()) {
389 return it->second;
390 }
391 TrackId track = CreateGpuCounterTrack(name, gpu_id);
392 gpu_counter_tracks_[std::make_pair(name, gpu_id)] = track;
393 return track;
394 }
395
InternEnergyCounterTrack(StringId name,int32_t consumer_id,StringId consumer_type,int32_t ordinal)396 TrackId TrackTracker::InternEnergyCounterTrack(StringId name,
397 int32_t consumer_id,
398 StringId consumer_type,
399 int32_t ordinal) {
400 auto it = energy_counter_tracks_.find(std::make_pair(name, consumer_id));
401 if (it != energy_counter_tracks_.end()) {
402 return it->second;
403 }
404 tables::EnergyCounterTrackTable::Row row(name);
405 row.consumer_id = consumer_id;
406 row.consumer_type = consumer_type;
407 row.ordinal = ordinal;
408 row.machine_id = context_->machine_id();
409 TrackId track =
410 context_->storage->mutable_energy_counter_track_table()->Insert(row).id;
411 energy_counter_tracks_[std::make_pair(name, consumer_id)] = track;
412 return track;
413 }
414
InternEnergyPerUidCounterTrack(StringId name,int32_t consumer_id,int32_t uid)415 TrackId TrackTracker::InternEnergyPerUidCounterTrack(StringId name,
416 int32_t consumer_id,
417 int32_t uid) {
418 auto it = energy_per_uid_counter_tracks_.find(std::make_pair(name, uid));
419 if (it != energy_per_uid_counter_tracks_.end()) {
420 return it->second;
421 }
422
423 tables::EnergyPerUidCounterTrackTable::Row row(name);
424 row.consumer_id = consumer_id;
425 row.uid = uid;
426 row.machine_id = context_->machine_id();
427 TrackId track =
428 context_->storage->mutable_energy_per_uid_counter_track_table()
429 ->Insert(row)
430 .id;
431 energy_per_uid_counter_tracks_[std::make_pair(name, uid)] = track;
432 return track;
433 }
434
InternLinuxDeviceTrack(StringId name)435 TrackId TrackTracker::InternLinuxDeviceTrack(StringId name) {
436 if (auto it = linux_device_tracks_.find(name);
437 it != linux_device_tracks_.end()) {
438 return it->second;
439 }
440
441 tables::LinuxDeviceTrackTable::Row row(name);
442 TrackId track =
443 context_->storage->mutable_linux_device_track_table()->Insert(row).id;
444 linux_device_tracks_[name] = track;
445 return track;
446 }
447
CreateGpuCounterTrack(StringId name,uint32_t gpu_id,StringId description,StringId unit)448 TrackId TrackTracker::CreateGpuCounterTrack(StringId name,
449 uint32_t gpu_id,
450 StringId description,
451 StringId unit) {
452 tables::GpuCounterTrackTable::Row row(name);
453 row.gpu_id = gpu_id;
454 row.description = description;
455 row.unit = unit;
456 row.machine_id = context_->machine_id();
457
458 return context_->storage->mutable_gpu_counter_track_table()->Insert(row).id;
459 }
460
CreatePerfCounterTrack(StringId name,tables::PerfSessionTable::Id perf_session_id,uint32_t cpu,bool is_timebase)461 TrackId TrackTracker::CreatePerfCounterTrack(
462 StringId name,
463 tables::PerfSessionTable::Id perf_session_id,
464 uint32_t cpu,
465 bool is_timebase) {
466 tables::PerfCounterTrackTable::Row row(name);
467 row.perf_session_id = perf_session_id;
468 row.cpu = cpu;
469 row.is_timebase = is_timebase;
470 row.machine_id = context_->machine_id();
471 return context_->storage->mutable_perf_counter_track_table()->Insert(row).id;
472 }
473
InternTrackForGroup(TrackTracker::Group group)474 TrackId TrackTracker::InternTrackForGroup(TrackTracker::Group group) {
475 uint32_t group_idx = static_cast<uint32_t>(group);
476 const std::optional<TrackId>& group_id = group_track_ids_[group_idx];
477 if (group_id) {
478 return *group_id;
479 }
480
481 StringId id = context_->storage->InternString(GetNameForGroup(group));
482 tables::TrackTable::Row row{id};
483 row.machine_id = context_->machine_id();
484 TrackId track_id = context_->storage->mutable_track_table()->Insert(row).id;
485 group_track_ids_[group_idx] = track_id;
486 return track_id;
487 }
488
489 } // namespace trace_processor
490 } // namespace perfetto
491