xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/proto/gpu_event_parser.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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/proto/gpu_event_parser.h"
18 
19 #include <array>
20 #include <cinttypes>
21 #include <cstddef>
22 #include <cstdint>
23 #include <limits>
24 #include <optional>
25 #include <string>
26 #include <vector>
27 
28 #include "perfetto/base/logging.h"
29 #include "perfetto/ext/base/string_utils.h"
30 #include "perfetto/ext/base/string_view.h"
31 #include "perfetto/ext/base/string_writer.h"
32 #include "perfetto/protozero/field.h"
33 #include "protos/perfetto/trace/android/gpu_mem_event.pbzero.h"
34 #include "src/trace_processor/importers/common/args_tracker.h"
35 #include "src/trace_processor/importers/common/event_tracker.h"
36 #include "src/trace_processor/importers/common/process_tracker.h"
37 #include "src/trace_processor/importers/common/slice_tracker.h"
38 #include "src/trace_processor/importers/common/track_tracker.h"
39 #include "src/trace_processor/importers/common/tracks.h"
40 #include "src/trace_processor/importers/common/tracks_common.h"
41 #include "src/trace_processor/importers/proto/packet_sequence_state_generation.h"
42 #include "src/trace_processor/importers/proto/vulkan_memory_tracker.h"
43 #include "src/trace_processor/storage/stats.h"
44 #include "src/trace_processor/storage/trace_storage.h"
45 #include "src/trace_processor/tables/profiler_tables_py.h"
46 #include "src/trace_processor/tables/slice_tables_py.h"
47 #include "src/trace_processor/tables/track_tables_py.h"
48 #include "src/trace_processor/types/trace_processor_context.h"
49 #include "src/trace_processor/types/variadic.h"
50 
51 #include "protos/perfetto/common/gpu_counter_descriptor.pbzero.h"
52 #include "protos/perfetto/trace/gpu/gpu_counter_event.pbzero.h"
53 #include "protos/perfetto/trace/gpu/gpu_log.pbzero.h"
54 #include "protos/perfetto/trace/gpu/gpu_render_stage_event.pbzero.h"
55 #include "protos/perfetto/trace/gpu/vulkan_api_event.pbzero.h"
56 #include "protos/perfetto/trace/gpu/vulkan_memory_event.pbzero.h"
57 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
58 
59 namespace perfetto::trace_processor {
60 
61 namespace {
62 
63 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkObjectType.html
64 enum VkObjectType {
65   VK_OBJECT_TYPE_UNKNOWN = 0,
66   VK_OBJECT_TYPE_INSTANCE = 1,
67   VK_OBJECT_TYPE_PHYSICAL_DEVICE = 2,
68   VK_OBJECT_TYPE_DEVICE = 3,
69   VK_OBJECT_TYPE_QUEUE = 4,
70   VK_OBJECT_TYPE_SEMAPHORE = 5,
71   VK_OBJECT_TYPE_COMMAND_BUFFER = 6,
72   VK_OBJECT_TYPE_FENCE = 7,
73   VK_OBJECT_TYPE_DEVICE_MEMORY = 8,
74   VK_OBJECT_TYPE_BUFFER = 9,
75   VK_OBJECT_TYPE_IMAGE = 10,
76   VK_OBJECT_TYPE_EVENT = 11,
77   VK_OBJECT_TYPE_QUERY_POOL = 12,
78   VK_OBJECT_TYPE_BUFFER_VIEW = 13,
79   VK_OBJECT_TYPE_IMAGE_VIEW = 14,
80   VK_OBJECT_TYPE_SHADER_MODULE = 15,
81   VK_OBJECT_TYPE_PIPELINE_CACHE = 16,
82   VK_OBJECT_TYPE_PIPELINE_LAYOUT = 17,
83   VK_OBJECT_TYPE_RENDER_PASS = 18,
84   VK_OBJECT_TYPE_PIPELINE = 19,
85   VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 20,
86   VK_OBJECT_TYPE_SAMPLER = 21,
87   VK_OBJECT_TYPE_DESCRIPTOR_POOL = 22,
88   VK_OBJECT_TYPE_DESCRIPTOR_SET = 23,
89   VK_OBJECT_TYPE_FRAMEBUFFER = 24,
90   VK_OBJECT_TYPE_COMMAND_POOL = 25,
91   VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000,
92   VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000,
93   VK_OBJECT_TYPE_SURFACE_KHR = 1000000000,
94   VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000,
95   VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000,
96   VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001,
97   VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000,
98   VK_OBJECT_TYPE_OBJECT_TABLE_NVX = 1000086000,
99   VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001,
100   VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000,
101   VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000,
102   VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000,
103   VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL = 1000210000,
104   VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR =
105       VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE,
106   VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR =
107       VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION,
108   VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF
109 };
110 
111 using protos::pbzero::VulkanMemoryEvent;
112 
113 }  // anonymous namespace
114 
GpuEventParser(TraceProcessorContext * context)115 GpuEventParser::GpuEventParser(TraceProcessorContext* context)
116     : context_(context),
117       vulkan_memory_tracker_(context),
118       description_id_(context->storage->InternString("description")),
119       gpu_render_stage_scope_id_(
120           context->storage->InternString("gpu_render_stage")),
121       gpu_log_track_name_id_(context_->storage->InternString("GPU Log")),
122       gpu_log_scope_id_(context_->storage->InternString("gpu_log")),
123       tag_id_(context_->storage->InternString("tag")),
124       log_message_id_(context->storage->InternString("message")),
125       log_severity_ids_{{context_->storage->InternString("UNSPECIFIED"),
126                          context_->storage->InternString("VERBOSE"),
127                          context_->storage->InternString("DEBUG"),
128                          context_->storage->InternString("INFO"),
129                          context_->storage->InternString("WARNING"),
130                          context_->storage->InternString("ERROR"),
131                          context_->storage->InternString(
132                              "UNKNOWN_SEVERITY") /* must be last */}},
133       vk_event_track_id_(context->storage->InternString("Vulkan Events")),
134       vk_event_scope_id_(context->storage->InternString("vulkan_events")),
135       vk_queue_submit_id_(context->storage->InternString("vkQueueSubmit")) {}
136 
ParseGpuCounterEvent(int64_t ts,ConstBytes blob)137 void GpuEventParser::ParseGpuCounterEvent(int64_t ts, ConstBytes blob) {
138   protos::pbzero::GpuCounterEvent::Decoder event(blob.data, blob.size);
139 
140   protos::pbzero::GpuCounterDescriptor::Decoder descriptor(
141       event.counter_descriptor());
142   // Add counter spec to ID map.
143   for (auto it = descriptor.specs(); it; ++it) {
144     protos::pbzero::GpuCounterDescriptor_GpuCounterSpec::Decoder spec(*it);
145     if (!spec.has_counter_id()) {
146       PERFETTO_ELOG("Counter spec missing counter id");
147       context_->storage->IncrementStats(stats::gpu_counters_invalid_spec);
148       continue;
149     }
150     if (!spec.has_name()) {
151       context_->storage->IncrementStats(stats::gpu_counters_invalid_spec);
152       continue;
153     }
154 
155     auto counter_id = spec.counter_id();
156     auto name = spec.name();
157     if (gpu_counter_track_ids_.find(counter_id) ==
158         gpu_counter_track_ids_.end()) {
159       auto desc = spec.description();
160 
161       StringId unit_id = kNullStringId;
162       if (spec.has_numerator_units() || spec.has_denominator_units()) {
163         char buffer[1024];
164         base::StringWriter unit(buffer, sizeof(buffer));
165         for (auto numer = spec.numerator_units(); numer; ++numer) {
166           if (unit.pos()) {
167             unit.AppendChar(':');
168           }
169           unit.AppendInt(*numer);
170         }
171         char sep = '/';
172         for (auto denom = spec.denominator_units(); denom; ++denom) {
173           unit.AppendChar(sep);
174           unit.AppendInt(*denom);
175           sep = ':';
176         }
177         unit_id = context_->storage->InternString(unit.GetStringView());
178       }
179 
180       auto name_id = context_->storage->InternString(name);
181       auto desc_id = context_->storage->InternString(desc);
182       auto track_id = context_->track_tracker->InternTrack(
183           tracks::kGpuCounterBlueprint,
184           tracks::Dimensions(0 /* gpu_id */, name),
185           tracks::DynamicName(name_id),
186           [&, this](ArgsTracker::BoundInserter& inserter) {
187             inserter.AddArg(description_id_, Variadic::String(desc_id));
188           },
189           tracks::DynamicUnit(unit_id));
190       gpu_counter_track_ids_.emplace(counter_id, track_id);
191       if (spec.has_groups()) {
192         for (auto group = spec.groups(); group; ++group) {
193           tables::GpuCounterGroupTable::Row row;
194           row.group_id = *group;
195           row.track_id = track_id;
196           context_->storage->mutable_gpu_counter_group_table()->Insert(row);
197         }
198       } else {
199         tables::GpuCounterGroupTable::Row row;
200         row.group_id = protos::pbzero::GpuCounterDescriptor::UNCLASSIFIED;
201         row.track_id = track_id;
202         context_->storage->mutable_gpu_counter_group_table()->Insert(row);
203       }
204     } else {
205       // Either counter spec was repeated or it came after counter data.
206       PERFETTO_ELOG("Duplicated counter spec found. (counter_id=%d, name=%s)",
207                     counter_id, name.ToStdString().c_str());
208       context_->storage->IncrementStats(stats::gpu_counters_invalid_spec);
209     }
210   }
211 
212   for (auto it = event.counters(); it; ++it) {
213     protos::pbzero::GpuCounterEvent_GpuCounter::Decoder counter(*it);
214     if (counter.has_counter_id() &&
215         (counter.has_int_value() || counter.has_double_value())) {
216       auto counter_id = counter.counter_id();
217       // Check missing counter_id
218       if (gpu_counter_track_ids_.find(counter_id) ==
219           gpu_counter_track_ids_.end()) {
220         continue;
221       }
222       double counter_val = counter.has_int_value()
223                                ? static_cast<double>(counter.int_value())
224                                : counter.double_value();
225       context_->event_tracker->PushCounter(ts, counter_val,
226                                            gpu_counter_track_ids_[counter_id]);
227     }
228   }
229 }
230 
GetFullStageName(PacketSequenceStateGeneration * sequence_state,const protos::pbzero::GpuRenderStageEvent_Decoder & event) const231 StringId GpuEventParser::GetFullStageName(
232     PacketSequenceStateGeneration* sequence_state,
233     const protos::pbzero::GpuRenderStageEvent_Decoder& event) const {
234   StringId stage_name;
235   if (event.has_stage_iid()) {
236     auto stage_iid = event.stage_iid();
237     auto* decoder = sequence_state->LookupInternedMessage<
238         protos::pbzero::InternedData::kGpuSpecificationsFieldNumber,
239         protos::pbzero::InternedGpuRenderStageSpecification>(stage_iid);
240     if (!decoder) {
241       return kNullStringId;
242     }
243     stage_name = context_->storage->InternString(decoder->name());
244   } else {
245     auto stage_id = static_cast<uint64_t>(event.stage_id());
246     if (stage_id < gpu_render_stage_ids_.size()) {
247       stage_name = gpu_render_stage_ids_[static_cast<size_t>(stage_id)].first;
248     } else {
249       base::StackString<64> name("render stage(%" PRIu64 ")", stage_id);
250       stage_name = context_->storage->InternString(name.string_view());
251     }
252   }
253   return stage_name;
254 }
255 
256 /**
257  * Create a GPU render stage track based
258  * GpuRenderStageEvent.Specifications.Description.
259  */
InsertGpuTrack(const protos::pbzero::GpuRenderStageEvent_Specifications_Description_Decoder & hw_queue)260 void GpuEventParser::InsertGpuTrack(
261     const protos::pbzero::
262         GpuRenderStageEvent_Specifications_Description_Decoder& hw_queue) {
263   StringId track_name = context_->storage->InternString(hw_queue.name());
264   if (gpu_hw_queue_counter_ >= gpu_hw_queue_ids_.size() ||
265       !gpu_hw_queue_ids_[gpu_hw_queue_counter_].has_value()) {
266     tables::GpuTrackTable::Row track(track_name);
267     track.scope = gpu_render_stage_scope_id_;
268     track.description = context_->storage->InternString(hw_queue.description());
269     if (gpu_hw_queue_counter_ >= gpu_hw_queue_ids_.size()) {
270       gpu_hw_queue_ids_.emplace_back(
271           context_->track_tracker->LegacyInternGpuTrack(track));
272     } else {
273       // If a gpu_render_stage_event is received before the specification, it is
274       // possible that the slot has already been allocated.
275       gpu_hw_queue_ids_[gpu_hw_queue_counter_] =
276           context_->track_tracker->LegacyInternGpuTrack(track);
277     }
278   } else {
279     // If a gpu_render_stage_event is received before the specification, a track
280     // will be automatically generated.  In that case, update the name and
281     // description.
282     auto track_id = gpu_hw_queue_ids_[gpu_hw_queue_counter_];
283     if (track_id.has_value()) {
284       auto rr = *context_->storage->mutable_gpu_track_table()->FindById(
285           track_id.value());
286       rr.set_name(track_name);
287       rr.set_description(
288           context_->storage->InternString(hw_queue.description()));
289     } else {
290       tables::GpuTrackTable::Row track(track_name);
291       track.scope = gpu_render_stage_scope_id_;
292       track.description =
293           context_->storage->InternString(hw_queue.description());
294     }
295   }
296   ++gpu_hw_queue_counter_;
297 }
FindDebugName(int32_t vk_object_type,uint64_t vk_handle) const298 std::optional<std::string> GpuEventParser::FindDebugName(
299     int32_t vk_object_type,
300     uint64_t vk_handle) const {
301   auto map = debug_marker_names_.find(vk_object_type);
302   if (map == debug_marker_names_.end()) {
303     return std::nullopt;
304   }
305 
306   auto name = map->second.find(vk_handle);
307   if (name == map->second.end()) {
308     return std::nullopt;
309   }
310   return name->second;
311 }
312 
ParseRenderSubpasses(const protos::pbzero::GpuRenderStageEvent_Decoder & event) const313 StringId GpuEventParser::ParseRenderSubpasses(
314     const protos::pbzero::GpuRenderStageEvent_Decoder& event) const {
315   if (!event.has_render_subpass_index_mask()) {
316     return kNullStringId;
317   }
318   char buf[256];
319   base::StringWriter writer(buf, sizeof(buf));
320   uint32_t bit_index = 0;
321   bool first = true;
322   for (auto it = event.render_subpass_index_mask(); it; ++it) {
323     auto subpasses_bits = *it;
324     do {
325       if ((subpasses_bits & 1) != 0) {
326         if (!first) {
327           writer.AppendChar(',');
328         }
329         first = false;
330         writer.AppendUnsignedInt(bit_index);
331       }
332       subpasses_bits >>= 1;
333       ++bit_index;
334     } while (subpasses_bits != 0);
335     // Round up to the next multiple of 64.
336     bit_index = ((bit_index - 1) / 64 + 1) * 64;
337   }
338   return context_->storage->InternString(writer.GetStringView());
339 }
340 
ParseGpuRenderStageEvent(int64_t ts,PacketSequenceStateGeneration * sequence_state,ConstBytes blob)341 void GpuEventParser::ParseGpuRenderStageEvent(
342     int64_t ts,
343     PacketSequenceStateGeneration* sequence_state,
344     ConstBytes blob) {
345   protos::pbzero::GpuRenderStageEvent::Decoder event(blob.data, blob.size);
346 
347   int32_t pid = 0;
348   if (event.has_specifications()) {
349     protos::pbzero::GpuRenderStageEvent_Specifications::Decoder spec(
350         event.specifications().data, event.specifications().size);
351     for (auto it = spec.hw_queue(); it; ++it) {
352       protos::pbzero::GpuRenderStageEvent_Specifications_Description::Decoder
353           hw_queue(*it);
354       if (hw_queue.has_name()) {
355         InsertGpuTrack(hw_queue);
356       }
357     }
358     for (auto it = spec.stage(); it; ++it) {
359       protos::pbzero::GpuRenderStageEvent_Specifications_Description::Decoder
360           stage(*it);
361       if (stage.has_name()) {
362         gpu_render_stage_ids_.emplace_back(
363             context_->storage->InternString(stage.name()),
364             context_->storage->InternString(stage.description()));
365       }
366     }
367     if (spec.has_context_spec()) {
368       protos::pbzero::GpuRenderStageEvent_Specifications_ContextSpec::Decoder
369           context_spec(spec.context_spec());
370       if (context_spec.has_pid()) {
371         pid = context_spec.pid();
372       }
373     }
374   }
375 
376   if (event.has_context()) {
377     uint64_t context_id = event.context();
378     auto* decoder = sequence_state->LookupInternedMessage<
379         protos::pbzero::InternedData::kGraphicsContextsFieldNumber,
380         protos::pbzero::InternedGraphicsContext>(context_id);
381     if (decoder) {
382       pid = decoder->pid();
383     }
384   }
385 
386   auto args_callback = [this, &event,
387                         sequence_state](ArgsTracker::BoundInserter* inserter) {
388     if (event.has_stage_iid()) {
389       size_t stage_iid = static_cast<size_t>(event.stage_iid());
390       auto* decoder = sequence_state->LookupInternedMessage<
391           protos::pbzero::InternedData::kGpuSpecificationsFieldNumber,
392           protos::pbzero::InternedGpuRenderStageSpecification>(stage_iid);
393       if (decoder) {
394         // TODO: Add RenderStageCategory to gpu_slice table.
395         inserter->AddArg(description_id_,
396                          Variadic::String(context_->storage->InternString(
397                              decoder->description())));
398       }
399     } else if (event.has_stage_id()) {
400       size_t stage_id = static_cast<size_t>(event.stage_id());
401       if (stage_id < gpu_render_stage_ids_.size()) {
402         auto description = gpu_render_stage_ids_[stage_id].second;
403         if (description != kNullStringId) {
404           inserter->AddArg(description_id_, Variadic::String(description));
405         }
406       }
407     }
408     for (auto it = event.extra_data(); it; ++it) {
409       protos::pbzero::GpuRenderStageEvent_ExtraData_Decoder datum(*it);
410       StringId name_id = context_->storage->InternString(datum.name());
411       StringId value = context_->storage->InternString(
412           datum.has_value() ? datum.value() : base::StringView());
413       inserter->AddArg(name_id, Variadic::String(value));
414     }
415   };
416 
417   if (event.has_event_id()) {
418     TrackId track_id;
419     uint64_t hw_queue_id = 0;
420     if (event.has_hw_queue_iid()) {
421       hw_queue_id = event.hw_queue_iid();
422       auto* decoder = sequence_state->LookupInternedMessage<
423           protos::pbzero::InternedData::kGpuSpecificationsFieldNumber,
424           protos::pbzero::InternedGpuRenderStageSpecification>(hw_queue_id);
425       if (!decoder) {
426         // Skip
427         return;
428       }
429       // TODO: Add RenderStageCategory to gpu_track table.
430       tables::GpuTrackTable::Row track(
431           context_->storage->InternString(decoder->name()));
432       track.scope = gpu_render_stage_scope_id_;
433       track.description =
434           context_->storage->InternString(decoder->description());
435       track_id = context_->track_tracker->LegacyInternGpuTrack(track);
436     } else {
437       uint32_t id = static_cast<uint32_t>(event.hw_queue_id());
438       if (id < gpu_hw_queue_ids_.size() && gpu_hw_queue_ids_[id].has_value()) {
439         track_id = gpu_hw_queue_ids_[id].value();
440       } else {
441         // If the event has a hw_queue_id that does not have a Specification,
442         // create a new track for it.
443         char buf[128];
444         base::StringWriter writer(buf, sizeof(buf));
445         writer.AppendLiteral("Unknown GPU Queue ");
446         if (id > 1024) {
447           // We don't expect this to happen, but just in case there is a corrupt
448           // packet, make sure we don't allocate a ridiculous amount of memory.
449           id = 1024;
450           context_->storage->IncrementStats(
451               stats::gpu_render_stage_parser_errors);
452           PERFETTO_ELOG("Invalid hw_queue_id.");
453         } else {
454           writer.AppendInt(event.hw_queue_id());
455         }
456         StringId track_name =
457             context_->storage->InternString(writer.GetStringView());
458         tables::GpuTrackTable::Row track(track_name);
459         track.scope = gpu_render_stage_scope_id_;
460         track_id = context_->track_tracker->LegacyInternGpuTrack(track);
461         gpu_hw_queue_ids_.resize(id + 1);
462         gpu_hw_queue_ids_[id] = track_id;
463       }
464       hw_queue_id = id;
465     }
466 
467     auto render_target_name =
468         FindDebugName(VK_OBJECT_TYPE_FRAMEBUFFER, event.render_target_handle());
469     auto render_target_name_id = render_target_name.has_value()
470                                      ? context_->storage->InternString(
471                                            render_target_name.value().c_str())
472                                      : kNullStringId;
473     auto render_pass_name =
474         FindDebugName(VK_OBJECT_TYPE_RENDER_PASS, event.render_pass_handle());
475     auto render_pass_name_id =
476         render_pass_name.has_value()
477             ? context_->storage->InternString(render_pass_name.value().c_str())
478             : kNullStringId;
479     auto command_buffer_name = FindDebugName(VK_OBJECT_TYPE_COMMAND_BUFFER,
480                                              event.command_buffer_handle());
481     auto command_buffer_name_id = command_buffer_name.has_value()
482                                       ? context_->storage->InternString(
483                                             command_buffer_name.value().c_str())
484                                       : kNullStringId;
485 
486     tables::GpuSliceTable::Row row;
487     row.ts = ts;
488     row.track_id = track_id;
489     row.name = GetFullStageName(sequence_state, event);
490     row.dur = static_cast<int64_t>(event.duration());
491     // TODO: Create table for graphics context and lookup
492     // InternedGraphicsContext.
493     row.context_id = static_cast<int64_t>(event.context());
494     row.render_target = static_cast<int64_t>(event.render_target_handle());
495     row.render_target_name = render_target_name_id;
496     row.render_pass = static_cast<int64_t>(event.render_pass_handle());
497     row.render_pass_name = render_pass_name_id;
498     row.render_subpasses = ParseRenderSubpasses(event);
499     row.command_buffer = static_cast<int64_t>(event.command_buffer_handle());
500     row.command_buffer_name = command_buffer_name_id;
501     row.submission_id = event.submission_id();
502     row.hw_queue_id = static_cast<int64_t>(hw_queue_id);
503     row.upid = context_->process_tracker->GetOrCreateProcess(
504         static_cast<uint32_t>(pid));
505     context_->slice_tracker->ScopedTyped(
506         context_->storage->mutable_gpu_slice_table(), row, args_callback);
507   }
508 }
509 
UpdateVulkanMemoryAllocationCounters(UniquePid upid,const VulkanMemoryEvent::Decoder & event)510 void GpuEventParser::UpdateVulkanMemoryAllocationCounters(
511     UniquePid upid,
512     const VulkanMemoryEvent::Decoder& event) {
513   switch (event.source()) {
514     case VulkanMemoryEvent::SOURCE_DRIVER: {
515       auto allocation_scope = static_cast<VulkanMemoryEvent::AllocationScope>(
516           event.allocation_scope());
517       if (allocation_scope == VulkanMemoryEvent::SCOPE_UNSPECIFIED) {
518         return;
519       }
520       switch (event.operation()) {
521         case VulkanMemoryEvent::OP_CREATE:
522           vulkan_driver_memory_counters_[allocation_scope] +=
523               event.memory_size();
524           break;
525         case VulkanMemoryEvent::OP_DESTROY:
526           vulkan_driver_memory_counters_[allocation_scope] -=
527               event.memory_size();
528           break;
529         case VulkanMemoryEvent::OP_UNSPECIFIED:
530         case VulkanMemoryEvent::OP_BIND:
531         case VulkanMemoryEvent::OP_DESTROY_BOUND:
532         case VulkanMemoryEvent::OP_ANNOTATIONS:
533           return;
534       }
535       static constexpr auto kBlueprint = tracks::CounterBlueprint(
536           "vulkan_driver_mem", tracks::UnknownUnitBlueprint(),
537           tracks::DimensionBlueprints(
538               tracks::kProcessDimensionBlueprint,
539               tracks::StringDimensionBlueprint("vulkan_allocation_scope")),
540           tracks::FnNameBlueprint([](UniquePid, base::StringView scope) {
541             return base::StackString<1024>("vulkan.mem.driver.scope.%.*s",
542                                            int(scope.size()), scope.data());
543           }));
544       static constexpr std::array kEventScopes = {
545           "UNSPECIFIED", "COMMAND", "OBJECT", "CACHE", "DEVICE", "INSTANCE",
546       };
547       TrackId track = context_->track_tracker->InternTrack(
548           kBlueprint,
549           tracks::Dimensions(upid, kEventScopes[uint32_t(allocation_scope)]));
550       context_->event_tracker->PushCounter(
551           event.timestamp(),
552           static_cast<double>(vulkan_driver_memory_counters_[allocation_scope]),
553           track);
554       break;
555     }
556     case VulkanMemoryEvent::SOURCE_DEVICE_MEMORY: {
557       auto memory_type = static_cast<uint32_t>(event.memory_type());
558       switch (event.operation()) {
559         case VulkanMemoryEvent::OP_CREATE:
560           vulkan_device_memory_counters_allocate_[memory_type] +=
561               event.memory_size();
562           break;
563         case VulkanMemoryEvent::OP_DESTROY:
564           vulkan_device_memory_counters_allocate_[memory_type] -=
565               event.memory_size();
566           break;
567         case VulkanMemoryEvent::OP_UNSPECIFIED:
568         case VulkanMemoryEvent::OP_BIND:
569         case VulkanMemoryEvent::OP_DESTROY_BOUND:
570         case VulkanMemoryEvent::OP_ANNOTATIONS:
571           return;
572       }
573       static constexpr auto kBlueprint = tracks::CounterBlueprint(
574           "vulkan_device_mem_allocation", tracks::UnknownUnitBlueprint(),
575           tracks::DimensionBlueprints(
576               tracks::kProcessDimensionBlueprint,
577               tracks::UintDimensionBlueprint("vulkan_memory_type")),
578           tracks::FnNameBlueprint([](UniquePid, uint32_t type) {
579             return base::StackString<1024>(
580                 "vulkan.mem.device.memory.type.%u.allocation", type);
581           }));
582       TrackId track = context_->track_tracker->InternTrack(
583           kBlueprint, tracks::Dimensions(upid, memory_type));
584       context_->event_tracker->PushCounter(
585           event.timestamp(),
586           static_cast<double>(
587               vulkan_device_memory_counters_allocate_[memory_type]),
588           track);
589       break;
590     }
591     case VulkanMemoryEvent::SOURCE_BUFFER:
592     case VulkanMemoryEvent::SOURCE_IMAGE: {
593       auto memory_type = static_cast<uint32_t>(event.memory_type());
594       switch (event.operation()) {
595         case VulkanMemoryEvent::OP_BIND:
596           vulkan_device_memory_counters_bind_[memory_type] +=
597               event.memory_size();
598           break;
599         case VulkanMemoryEvent::OP_DESTROY_BOUND:
600           vulkan_device_memory_counters_bind_[memory_type] -=
601               event.memory_size();
602           break;
603         case VulkanMemoryEvent::OP_UNSPECIFIED:
604         case VulkanMemoryEvent::OP_CREATE:
605         case VulkanMemoryEvent::OP_DESTROY:
606         case VulkanMemoryEvent::OP_ANNOTATIONS:
607           return;
608       }
609       static constexpr auto kBlueprint = tracks::CounterBlueprint(
610           "vulkan_device_mem_bind", tracks::UnknownUnitBlueprint(),
611           tracks::DimensionBlueprints(
612               tracks::kProcessDimensionBlueprint,
613               tracks::UintDimensionBlueprint("vulkan_memory_type")),
614           tracks::FnNameBlueprint([](UniquePid, uint32_t type) {
615             return base::StackString<1024>(
616                 "vulkan.mem.device.memory.type.%u.bind", type);
617           }));
618       TrackId track = context_->track_tracker->InternTrack(
619           kBlueprint, tracks::Dimensions(upid, memory_type));
620       context_->event_tracker->PushCounter(
621           event.timestamp(),
622           static_cast<double>(vulkan_device_memory_counters_bind_[memory_type]),
623           track);
624       break;
625     }
626     case VulkanMemoryEvent::SOURCE_UNSPECIFIED:
627     case VulkanMemoryEvent::SOURCE_DEVICE:
628       return;
629   }
630 }
631 
ParseVulkanMemoryEvent(PacketSequenceStateGeneration * sequence_state,ConstBytes blob)632 void GpuEventParser::ParseVulkanMemoryEvent(
633     PacketSequenceStateGeneration* sequence_state,
634     ConstBytes blob) {
635   using protos::pbzero::InternedData;
636   VulkanMemoryEvent::Decoder vulkan_memory_event(blob.data, blob.size);
637   tables::VulkanMemoryAllocationsTable::Row vulkan_memory_event_row;
638   vulkan_memory_event_row.source = vulkan_memory_tracker_.FindSourceString(
639       static_cast<VulkanMemoryEvent::Source>(vulkan_memory_event.source()));
640   vulkan_memory_event_row.operation =
641       vulkan_memory_tracker_.FindOperationString(
642           static_cast<VulkanMemoryEvent::Operation>(
643               vulkan_memory_event.operation()));
644   vulkan_memory_event_row.timestamp = vulkan_memory_event.timestamp();
645   vulkan_memory_event_row.upid =
646       context_->process_tracker->GetOrCreateProcess(vulkan_memory_event.pid());
647   if (vulkan_memory_event.has_device()) {
648     vulkan_memory_event_row.device =
649         static_cast<int64_t>(vulkan_memory_event.device());
650   }
651   if (vulkan_memory_event.has_device_memory()) {
652     vulkan_memory_event_row.device_memory =
653         static_cast<int64_t>(vulkan_memory_event.device_memory());
654   }
655   if (vulkan_memory_event.has_heap()) {
656     vulkan_memory_event_row.heap = vulkan_memory_event.heap();
657   }
658   if (vulkan_memory_event.has_memory_type()) {
659     vulkan_memory_event_row.memory_type = vulkan_memory_event.memory_type();
660   }
661   if (vulkan_memory_event.has_caller_iid()) {
662     vulkan_memory_event_row.function_name =
663         vulkan_memory_tracker_
664             .GetInternedString<InternedData::kFunctionNamesFieldNumber>(
665                 sequence_state,
666                 static_cast<uint64_t>(vulkan_memory_event.caller_iid()));
667   }
668   if (vulkan_memory_event.has_object_handle()) {
669     vulkan_memory_event_row.object_handle =
670         static_cast<int64_t>(vulkan_memory_event.object_handle());
671   }
672   if (vulkan_memory_event.has_memory_address()) {
673     vulkan_memory_event_row.memory_address =
674         static_cast<int64_t>(vulkan_memory_event.memory_address());
675   }
676   if (vulkan_memory_event.has_memory_size()) {
677     vulkan_memory_event_row.memory_size =
678         static_cast<int64_t>(vulkan_memory_event.memory_size());
679   }
680   if (vulkan_memory_event.has_allocation_scope()) {
681     vulkan_memory_event_row.scope =
682         vulkan_memory_tracker_.FindAllocationScopeString(
683             static_cast<VulkanMemoryEvent::AllocationScope>(
684                 vulkan_memory_event.allocation_scope()));
685   }
686 
687   UpdateVulkanMemoryAllocationCounters(vulkan_memory_event_row.upid.value(),
688                                        vulkan_memory_event);
689 
690   auto* allocs = context_->storage->mutable_vulkan_memory_allocations_table();
691   VulkanAllocId id = allocs->Insert(vulkan_memory_event_row).id;
692 
693   if (vulkan_memory_event.has_annotations()) {
694     auto inserter = context_->args_tracker->AddArgsTo(id);
695 
696     for (auto it = vulkan_memory_event.annotations(); it; ++it) {
697       protos::pbzero::VulkanMemoryEventAnnotation::Decoder annotation(*it);
698 
699       auto key_id =
700           vulkan_memory_tracker_
701               .GetInternedString<InternedData::kVulkanMemoryKeysFieldNumber>(
702                   sequence_state, static_cast<uint64_t>(annotation.key_iid()));
703 
704       if (annotation.has_int_value()) {
705         inserter.AddArg(key_id, Variadic::Integer(annotation.int_value()));
706       } else if (annotation.has_double_value()) {
707         inserter.AddArg(key_id, Variadic::Real(annotation.double_value()));
708       } else if (annotation.has_string_iid()) {
709         auto string_id =
710             vulkan_memory_tracker_
711                 .GetInternedString<InternedData::kVulkanMemoryKeysFieldNumber>(
712                     sequence_state,
713                     static_cast<uint64_t>(annotation.string_iid()));
714 
715         inserter.AddArg(key_id, Variadic::String(string_id));
716       }
717     }
718   }
719 }
720 
ParseGpuLog(int64_t ts,ConstBytes blob)721 void GpuEventParser::ParseGpuLog(int64_t ts, ConstBytes blob) {
722   protos::pbzero::GpuLog::Decoder event(blob.data, blob.size);
723 
724   tables::GpuTrackTable::Row track(gpu_log_track_name_id_);
725   track.scope = gpu_log_scope_id_;
726   TrackId track_id = context_->track_tracker->LegacyInternGpuTrack(track);
727 
728   auto args_callback = [this, &event](ArgsTracker::BoundInserter* inserter) {
729     if (event.has_tag()) {
730       inserter->AddArg(
731           tag_id_,
732           Variadic::String(context_->storage->InternString(event.tag())));
733     }
734     if (event.has_log_message()) {
735       inserter->AddArg(log_message_id_,
736                        Variadic::String(context_->storage->InternString(
737                            event.log_message())));
738     }
739   };
740 
741   auto severity = static_cast<size_t>(event.severity());
742   StringId severity_id =
743       severity < log_severity_ids_.size()
744           ? log_severity_ids_[static_cast<size_t>(event.severity())]
745           : log_severity_ids_[log_severity_ids_.size() - 1];
746 
747   tables::GpuSliceTable::Row row;
748   row.ts = ts;
749   row.track_id = track_id;
750   row.name = severity_id;
751   row.dur = 0;
752   context_->slice_tracker->ScopedTyped(
753       context_->storage->mutable_gpu_slice_table(), row, args_callback);
754 }
755 
ParseVulkanApiEvent(int64_t ts,ConstBytes blob)756 void GpuEventParser::ParseVulkanApiEvent(int64_t ts, ConstBytes blob) {
757   protos::pbzero::VulkanApiEvent::Decoder vk_event(blob.data, blob.size);
758   if (vk_event.has_vk_debug_utils_object_name()) {
759     protos::pbzero::VulkanApiEvent_VkDebugUtilsObjectName::Decoder event(
760         vk_event.vk_debug_utils_object_name());
761     debug_marker_names_[event.object_type()][event.object()] =
762         event.object_name().ToStdString();
763   }
764   if (vk_event.has_vk_queue_submit()) {
765     protos::pbzero::VulkanApiEvent_VkQueueSubmit::Decoder event(
766         vk_event.vk_queue_submit());
767     // Once flow table is implemented, we can create a nice UI that link the
768     // vkQueueSubmit to GpuRenderStageEvent.  For now, just add it as in a GPU
769     // track so that they can appear close to the render stage slices.
770     tables::GpuTrackTable::Row track(vk_event_track_id_);
771     track.scope = vk_event_scope_id_;
772     TrackId track_id = context_->track_tracker->LegacyInternGpuTrack(track);
773     tables::GpuSliceTable::Row row;
774     row.ts = ts;
775     row.dur = static_cast<int64_t>(event.duration_ns());
776     row.track_id = track_id;
777     row.name = vk_queue_submit_id_;
778     if (event.has_vk_command_buffers()) {
779       row.command_buffer = static_cast<int64_t>(*event.vk_command_buffers());
780     }
781     row.submission_id = event.submission_id();
782     auto args_callback = [this, &event](ArgsTracker::BoundInserter* inserter) {
783       inserter->AddArg(context_->storage->InternString("pid"),
784                        Variadic::Integer(event.pid()));
785       inserter->AddArg(context_->storage->InternString("tid"),
786                        Variadic::Integer(event.tid()));
787     };
788     context_->slice_tracker->ScopedTyped(
789         context_->storage->mutable_gpu_slice_table(), row, args_callback);
790   }
791 }
792 
ParseGpuMemTotalEvent(int64_t ts,ConstBytes blob)793 void GpuEventParser::ParseGpuMemTotalEvent(int64_t ts, ConstBytes blob) {
794   protos::pbzero::GpuMemTotalEvent::Decoder gpu_mem_total(blob);
795 
796   TrackId track = kInvalidTrackId;
797   const uint32_t pid = gpu_mem_total.pid();
798   if (pid == 0) {
799     // Pid 0 is used to indicate the global total
800     track =
801         context_->track_tracker->InternTrack(tracks::kGlobalGpuMemoryBlueprint);
802   } else {
803     // Process emitting the packet can be different from the pid in the event.
804     UniqueTid utid = context_->process_tracker->UpdateThread(pid, pid);
805     UniquePid upid = context_->storage->thread_table()[utid].upid().value_or(0);
806     track = context_->track_tracker->InternTrack(
807         tracks::kProcessGpuMemoryBlueprint, tracks::Dimensions(upid));
808   }
809   context_->event_tracker->PushCounter(
810       ts, static_cast<double>(gpu_mem_total.size()), track);
811 }
812 
813 }  // namespace perfetto::trace_processor
814