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