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