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