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 <inttypes.h>
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
ParseGpuCounterEvent(int64_t ts,ConstBytes blob)117 void GpuEventParser::ParseGpuCounterEvent(int64_t ts, ConstBytes blob) {
118 protos::pbzero::GpuCounterEvent::Decoder event(blob.data, blob.size);
119
120 protos::pbzero::GpuCounterDescriptor::Decoder descriptor(
121 event.counter_descriptor());
122 // Add counter spec to ID map.
123 for (auto it = descriptor.specs(); it; ++it) {
124 protos::pbzero::GpuCounterDescriptor_GpuCounterSpec::Decoder spec(*it);
125 if (!spec.has_counter_id()) {
126 PERFETTO_ELOG("Counter spec missing counter id");
127 context_->storage->IncrementStats(stats::gpu_counters_invalid_spec);
128 continue;
129 }
130 if (!spec.has_name()) {
131 context_->storage->IncrementStats(stats::gpu_counters_invalid_spec);
132 continue;
133 }
134
135 auto counter_id = spec.counter_id();
136 auto name = spec.name();
137 if (gpu_counter_track_ids_.find(counter_id) ==
138 gpu_counter_track_ids_.end()) {
139 auto desc = spec.description();
140
141 StringId unit_id = kNullStringId;
142 if (spec.has_numerator_units() || spec.has_denominator_units()) {
143 char buffer[1024];
144 base::StringWriter unit(buffer, sizeof(buffer));
145 for (auto numer = spec.numerator_units(); numer; ++numer) {
146 if (unit.pos()) {
147 unit.AppendChar(':');
148 }
149 unit.AppendInt(*numer);
150 }
151 char sep = '/';
152 for (auto denom = spec.denominator_units(); denom; ++denom) {
153 unit.AppendChar(sep);
154 unit.AppendInt(*denom);
155 sep = ':';
156 }
157 unit_id = context_->storage->InternString(unit.GetStringView());
158 }
159
160 auto name_id = context_->storage->InternString(name);
161 auto desc_id = context_->storage->InternString(desc);
162 auto track_id = context_->track_tracker->CreateGpuCounterTrack(
163 name_id, 0 /* gpu_id */, desc_id, unit_id);
164 gpu_counter_track_ids_.emplace(counter_id, track_id);
165 if (spec.has_groups()) {
166 for (auto group = spec.groups(); group; ++group) {
167 tables::GpuCounterGroupTable::Row row;
168 row.group_id = *group;
169 row.track_id = track_id;
170 context_->storage->mutable_gpu_counter_group_table()->Insert(row);
171 }
172 } else {
173 tables::GpuCounterGroupTable::Row row;
174 row.group_id = protos::pbzero::GpuCounterDescriptor::UNCLASSIFIED;
175 row.track_id = track_id;
176 context_->storage->mutable_gpu_counter_group_table()->Insert(row);
177 }
178 } else {
179 // Either counter spec was repeated or it came after counter data.
180 PERFETTO_ELOG("Duplicated counter spec found. (counter_id=%d, name=%s)",
181 counter_id, name.ToStdString().c_str());
182 context_->storage->IncrementStats(stats::gpu_counters_invalid_spec);
183 }
184 }
185
186 for (auto it = event.counters(); it; ++it) {
187 protos::pbzero::GpuCounterEvent_GpuCounter::Decoder counter(*it);
188 if (counter.has_counter_id() &&
189 (counter.has_int_value() || counter.has_double_value())) {
190 auto counter_id = counter.counter_id();
191 // Check missing counter_id
192 if (gpu_counter_track_ids_.find(counter_id) ==
193 gpu_counter_track_ids_.end()) {
194 char buffer[64];
195 base::StringWriter writer(buffer, sizeof(buffer));
196 writer.AppendString("gpu_counter(");
197 writer.AppendUnsignedInt(counter_id);
198 writer.AppendString(")");
199 auto name_id = context_->storage->InternString(writer.GetStringView());
200
201 TrackId track = context_->track_tracker->CreateGpuCounterTrack(
202 name_id, 0 /* gpu_id */);
203 gpu_counter_track_ids_.emplace(counter_id, track);
204 context_->storage->IncrementStats(stats::gpu_counters_missing_spec);
205 }
206 if (counter.has_int_value()) {
207 context_->event_tracker->PushCounter(
208 ts, counter.int_value(), gpu_counter_track_ids_[counter_id]);
209 } else {
210 context_->event_tracker->PushCounter(
211 ts, counter.double_value(), gpu_counter_track_ids_[counter_id]);
212 }
213 }
214 }
215 }
216
GetFullStageName(const protos::pbzero::GpuRenderStageEvent_Decoder & event) const217 const StringId GpuEventParser::GetFullStageName(
218 const protos::pbzero::GpuRenderStageEvent_Decoder& event) const {
219 size_t stage_id = static_cast<size_t>(event.stage_id());
220 StringId stage_name;
221
222 if (stage_id < gpu_render_stage_ids_.size()) {
223 stage_name = gpu_render_stage_ids_[stage_id].first;
224 } else {
225 char buffer[64];
226 snprintf(buffer, sizeof(buffer), "render stage(%zu)", stage_id);
227 stage_name = context_->storage->InternString(buffer);
228 }
229 return stage_name;
230 }
231
232 /**
233 * Create a GPU render stage track based
234 * GpuRenderStageEvent.Specifications.Description.
235 */
InsertGpuTrack(const protos::pbzero::GpuRenderStageEvent_Specifications_Description_Decoder & hw_queue)236 void GpuEventParser::InsertGpuTrack(
237 const protos::pbzero::
238 GpuRenderStageEvent_Specifications_Description_Decoder& hw_queue) {
239 StringId track_name = context_->storage->InternString(hw_queue.name());
240 if (gpu_hw_queue_counter_ >= gpu_hw_queue_ids_.size() ||
241 !gpu_hw_queue_ids_[gpu_hw_queue_counter_].has_value()) {
242 tables::GpuTrackTable::Row track(track_name);
243 track.scope = gpu_render_stage_scope_id_;
244 track.description = context_->storage->InternString(hw_queue.description());
245 if (gpu_hw_queue_counter_ >= gpu_hw_queue_ids_.size()) {
246 gpu_hw_queue_ids_.emplace_back(
247 context_->track_tracker->InternGpuTrack(track));
248 } else {
249 // If a gpu_render_stage_event is received before the specification, it is
250 // possible that the slot has already been allocated.
251 gpu_hw_queue_ids_[gpu_hw_queue_counter_] =
252 context_->track_tracker->InternGpuTrack(track);
253 }
254 } else {
255 // If a gpu_render_stage_event is received before the specification, a track
256 // will be automatically generated. In that case, update the name and
257 // description.
258 auto track_id = gpu_hw_queue_ids_[gpu_hw_queue_counter_];
259 if (track_id.has_value()) {
260 auto row = context_->storage->mutable_gpu_track_table()
261 ->id()
262 .IndexOf(track_id.value())
263 .value();
264 context_->storage->mutable_gpu_track_table()->mutable_name()->Set(
265 row, track_name);
266 context_->storage->mutable_gpu_track_table()->mutable_description()->Set(
267 row, context_->storage->InternString(hw_queue.description()));
268 } else {
269 tables::GpuTrackTable::Row track(track_name);
270 track.scope = gpu_render_stage_scope_id_;
271 track.description =
272 context_->storage->InternString(hw_queue.description());
273 }
274 }
275 ++gpu_hw_queue_counter_;
276 }
FindDebugName(int32_t vk_object_type,uint64_t vk_handle) const277 base::Optional<std::string> GpuEventParser::FindDebugName(
278 int32_t vk_object_type,
279 uint64_t vk_handle) const {
280 auto map = debug_marker_names_.find(vk_object_type);
281 if (map == debug_marker_names_.end()) {
282 return base::nullopt;
283 }
284
285 auto name = map->second.find(vk_handle);
286 if (name == map->second.end()) {
287 return base::nullopt;
288 } else {
289 return name->second;
290 }
291 }
292
ParseGpuRenderStageEvent(int64_t ts,ConstBytes blob)293 void GpuEventParser::ParseGpuRenderStageEvent(int64_t ts, ConstBytes blob) {
294 protos::pbzero::GpuRenderStageEvent::Decoder event(blob.data, blob.size);
295
296 if (event.has_specifications()) {
297 protos::pbzero::GpuRenderStageEvent_Specifications::Decoder spec(
298 event.specifications().data, event.specifications().size);
299 for (auto it = spec.hw_queue(); it; ++it) {
300 protos::pbzero::GpuRenderStageEvent_Specifications_Description::Decoder
301 hw_queue(*it);
302 if (hw_queue.has_name()) {
303 InsertGpuTrack(hw_queue);
304 }
305 }
306 for (auto it = spec.stage(); it; ++it) {
307 protos::pbzero::GpuRenderStageEvent_Specifications_Description::Decoder
308 stage(*it);
309 if (stage.has_name()) {
310 gpu_render_stage_ids_.emplace_back(std::make_pair(
311 context_->storage->InternString(stage.name()),
312 context_->storage->InternString(stage.description())));
313 }
314 }
315 }
316
317 auto args_callback = [this, &event](ArgsTracker::BoundInserter* inserter) {
318 size_t stage_id = static_cast<size_t>(event.stage_id());
319 if (stage_id < gpu_render_stage_ids_.size()) {
320 auto description = gpu_render_stage_ids_[stage_id].second;
321 if (description != kNullStringId) {
322 inserter->AddArg(description_id_, Variadic::String(description));
323 }
324 }
325 for (auto it = event.extra_data(); it; ++it) {
326 protos::pbzero::GpuRenderStageEvent_ExtraData_Decoder datum(*it);
327 StringId name_id = context_->storage->InternString(datum.name());
328 StringId value = context_->storage->InternString(
329 datum.has_value() ? datum.value() : base::StringView());
330 inserter->AddArg(name_id, Variadic::String(value));
331 }
332 };
333
334 if (event.has_event_id()) {
335 TrackId track_id;
336 uint32_t hw_queue_id = static_cast<uint32_t>(event.hw_queue_id());
337 if (hw_queue_id < gpu_hw_queue_ids_.size() &&
338 gpu_hw_queue_ids_[hw_queue_id].has_value()) {
339 track_id = gpu_hw_queue_ids_[hw_queue_id].value();
340 } else {
341 // If the event has a hw_queue_id that does not have a Specification,
342 // create a new track for it.
343 char buf[128];
344 base::StringWriter writer(buf, sizeof(buf));
345 writer.AppendLiteral("Unknown GPU Queue ");
346 if (hw_queue_id > 1024) {
347 // We don't expect this to happen, but just in case there is a corrupt
348 // packet, make sure we don't allocate a ridiculous amount of memory.
349 hw_queue_id = 1024;
350 context_->storage->IncrementStats(
351 stats::gpu_render_stage_parser_errors);
352 PERFETTO_ELOG("Invalid hw_queue_id.");
353 } else {
354 writer.AppendInt(event.hw_queue_id());
355 }
356 StringId track_name =
357 context_->storage->InternString(writer.GetStringView());
358 tables::GpuTrackTable::Row track(track_name);
359 track.scope = gpu_render_stage_scope_id_;
360 track_id = context_->track_tracker->InternGpuTrack(track);
361 gpu_hw_queue_ids_.resize(hw_queue_id + 1);
362 gpu_hw_queue_ids_[hw_queue_id] = track_id;
363 }
364
365 auto render_target_name =
366 FindDebugName(VK_OBJECT_TYPE_FRAMEBUFFER, event.render_target_handle());
367 auto render_target_name_id = render_target_name.has_value()
368 ? context_->storage->InternString(
369 render_target_name.value().c_str())
370 : kNullStringId;
371 auto render_pass_name =
372 FindDebugName(VK_OBJECT_TYPE_RENDER_PASS, event.render_pass_handle());
373 auto render_pass_name_id =
374 render_pass_name.has_value()
375 ? context_->storage->InternString(render_pass_name.value().c_str())
376 : kNullStringId;
377 auto command_buffer_name = FindDebugName(VK_OBJECT_TYPE_COMMAND_BUFFER,
378 event.command_buffer_handle());
379 auto command_buffer_name_id = command_buffer_name.has_value()
380 ? context_->storage->InternString(
381 command_buffer_name.value().c_str())
382 : kNullStringId;
383
384 tables::GpuSliceTable::Row row;
385 row.ts = ts;
386 row.track_id = track_id;
387 row.name = GetFullStageName(event);
388 row.dur = static_cast<int64_t>(event.duration());
389 row.context_id = static_cast<int64_t>(event.context());
390 row.render_target = static_cast<int64_t>(event.render_target_handle());
391 row.render_target_name = render_target_name_id;
392 row.render_pass = static_cast<int64_t>(event.render_pass_handle());
393 row.render_pass_name = render_pass_name_id;
394 row.command_buffer = static_cast<int64_t>(event.command_buffer_handle());
395 row.command_buffer_name = command_buffer_name_id;
396 row.submission_id = event.submission_id();
397 row.hw_queue_id = hw_queue_id;
398
399 context_->slice_tracker->ScopedGpu(row, args_callback);
400 }
401 }
402
UpdateVulkanMemoryAllocationCounters(UniquePid upid,const VulkanMemoryEvent::Decoder & event)403 void GpuEventParser::UpdateVulkanMemoryAllocationCounters(
404 UniquePid upid,
405 const VulkanMemoryEvent::Decoder& event) {
406 StringId track_str_id = kNullStringId;
407 TrackId track = kInvalidTrackId;
408 auto allocation_scope = VulkanMemoryEvent::SCOPE_UNSPECIFIED;
409 uint32_t memory_type = std::numeric_limits<uint32_t>::max();
410 switch (event.source()) {
411 case VulkanMemoryEvent::SOURCE_DRIVER:
412 allocation_scope = static_cast<VulkanMemoryEvent::AllocationScope>(
413 event.allocation_scope());
414 if (allocation_scope == VulkanMemoryEvent::SCOPE_UNSPECIFIED)
415 return;
416 switch (event.operation()) {
417 case VulkanMemoryEvent::OP_CREATE:
418 vulkan_driver_memory_counters_[allocation_scope] +=
419 event.memory_size();
420 break;
421 case VulkanMemoryEvent::OP_DESTROY:
422 vulkan_driver_memory_counters_[allocation_scope] -=
423 event.memory_size();
424 break;
425 case VulkanMemoryEvent::OP_UNSPECIFIED:
426 case VulkanMemoryEvent::OP_BIND:
427 case VulkanMemoryEvent::OP_DESTROY_BOUND:
428 case VulkanMemoryEvent::OP_ANNOTATIONS:
429 return;
430 }
431 track_str_id = vulkan_memory_tracker_.FindAllocationScopeCounterString(
432 allocation_scope);
433 track = context_->track_tracker->InternProcessCounterTrack(track_str_id,
434 upid);
435 context_->event_tracker->PushCounter(
436 event.timestamp(), vulkan_driver_memory_counters_[allocation_scope],
437 track);
438 break;
439
440 case VulkanMemoryEvent::SOURCE_DEVICE_MEMORY:
441 memory_type = static_cast<uint32_t>(event.memory_type());
442 switch (event.operation()) {
443 case VulkanMemoryEvent::OP_CREATE:
444 vulkan_device_memory_counters_allocate_[memory_type] +=
445 event.memory_size();
446 break;
447 case VulkanMemoryEvent::OP_DESTROY:
448 vulkan_device_memory_counters_allocate_[memory_type] -=
449 event.memory_size();
450 break;
451 case VulkanMemoryEvent::OP_UNSPECIFIED:
452 case VulkanMemoryEvent::OP_BIND:
453 case VulkanMemoryEvent::OP_DESTROY_BOUND:
454 case VulkanMemoryEvent::OP_ANNOTATIONS:
455 return;
456 }
457 track_str_id = vulkan_memory_tracker_.FindMemoryTypeCounterString(
458 memory_type,
459 VulkanMemoryTracker::DeviceCounterType::kAllocationCounter);
460 track = context_->track_tracker->InternProcessCounterTrack(track_str_id,
461 upid);
462 context_->event_tracker->PushCounter(
463 event.timestamp(),
464 vulkan_device_memory_counters_allocate_[memory_type], track);
465 break;
466
467 case VulkanMemoryEvent::SOURCE_BUFFER:
468 case VulkanMemoryEvent::SOURCE_IMAGE:
469 memory_type = static_cast<uint32_t>(event.memory_type());
470 switch (event.operation()) {
471 case VulkanMemoryEvent::OP_BIND:
472 vulkan_device_memory_counters_bind_[memory_type] +=
473 event.memory_size();
474 break;
475 case VulkanMemoryEvent::OP_DESTROY_BOUND:
476 vulkan_device_memory_counters_bind_[memory_type] -=
477 event.memory_size();
478 break;
479 case VulkanMemoryEvent::OP_UNSPECIFIED:
480 case VulkanMemoryEvent::OP_CREATE:
481 case VulkanMemoryEvent::OP_DESTROY:
482 case VulkanMemoryEvent::OP_ANNOTATIONS:
483 return;
484 }
485 track_str_id = vulkan_memory_tracker_.FindMemoryTypeCounterString(
486 memory_type, VulkanMemoryTracker::DeviceCounterType::kBindCounter);
487 track = context_->track_tracker->InternProcessCounterTrack(track_str_id,
488 upid);
489 context_->event_tracker->PushCounter(
490 event.timestamp(), vulkan_device_memory_counters_bind_[memory_type],
491 track);
492 break;
493 case VulkanMemoryEvent::SOURCE_UNSPECIFIED:
494 case VulkanMemoryEvent::SOURCE_DEVICE:
495 return;
496 }
497 }
498
ParseVulkanMemoryEvent(PacketSequenceStateGeneration * sequence_state,ConstBytes blob)499 void GpuEventParser::ParseVulkanMemoryEvent(
500 PacketSequenceStateGeneration* sequence_state,
501 ConstBytes blob) {
502 using protos::pbzero::InternedData;
503 VulkanMemoryEvent::Decoder vulkan_memory_event(blob.data, blob.size);
504 tables::VulkanMemoryAllocationsTable::Row vulkan_memory_event_row;
505 vulkan_memory_event_row.source = vulkan_memory_tracker_.FindSourceString(
506 static_cast<VulkanMemoryEvent::Source>(vulkan_memory_event.source()));
507 vulkan_memory_event_row.operation =
508 vulkan_memory_tracker_.FindOperationString(
509 static_cast<VulkanMemoryEvent::Operation>(
510 vulkan_memory_event.operation()));
511 vulkan_memory_event_row.timestamp = vulkan_memory_event.timestamp();
512 vulkan_memory_event_row.upid =
513 context_->process_tracker->GetOrCreateProcess(vulkan_memory_event.pid());
514 if (vulkan_memory_event.has_device())
515 vulkan_memory_event_row.device =
516 static_cast<int64_t>(vulkan_memory_event.device());
517 if (vulkan_memory_event.has_device_memory())
518 vulkan_memory_event_row.device_memory =
519 static_cast<int64_t>(vulkan_memory_event.device_memory());
520 if (vulkan_memory_event.has_heap())
521 vulkan_memory_event_row.heap = vulkan_memory_event.heap();
522 if (vulkan_memory_event.has_memory_type())
523 vulkan_memory_event_row.memory_type = vulkan_memory_event.memory_type();
524 if (vulkan_memory_event.has_caller_iid()) {
525 vulkan_memory_event_row.function_name =
526 vulkan_memory_tracker_
527 .GetInternedString<InternedData::kFunctionNamesFieldNumber>(
528 sequence_state,
529 static_cast<uint64_t>(vulkan_memory_event.caller_iid()));
530 }
531 if (vulkan_memory_event.has_object_handle())
532 vulkan_memory_event_row.object_handle =
533 static_cast<int64_t>(vulkan_memory_event.object_handle());
534 if (vulkan_memory_event.has_memory_address())
535 vulkan_memory_event_row.memory_address =
536 static_cast<int64_t>(vulkan_memory_event.memory_address());
537 if (vulkan_memory_event.has_memory_size())
538 vulkan_memory_event_row.memory_size =
539 static_cast<int64_t>(vulkan_memory_event.memory_size());
540 if (vulkan_memory_event.has_allocation_scope())
541 vulkan_memory_event_row.scope =
542 vulkan_memory_tracker_.FindAllocationScopeString(
543 static_cast<VulkanMemoryEvent::AllocationScope>(
544 vulkan_memory_event.allocation_scope()));
545
546 UpdateVulkanMemoryAllocationCounters(vulkan_memory_event_row.upid.value(),
547 vulkan_memory_event);
548
549 auto* allocs = context_->storage->mutable_vulkan_memory_allocations_table();
550 VulkanAllocId id = allocs->Insert(vulkan_memory_event_row).id;
551
552 if (vulkan_memory_event.has_annotations()) {
553 auto inserter = context_->args_tracker->AddArgsTo(id);
554
555 for (auto it = vulkan_memory_event.annotations(); it; ++it) {
556 protos::pbzero::VulkanMemoryEventAnnotation::Decoder annotation(*it);
557
558 auto key_id =
559 vulkan_memory_tracker_
560 .GetInternedString<InternedData::kVulkanMemoryKeysFieldNumber>(
561 sequence_state, static_cast<uint64_t>(annotation.key_iid()));
562
563 if (annotation.has_int_value()) {
564 inserter.AddArg(key_id, Variadic::Integer(annotation.int_value()));
565 } else if (annotation.has_double_value()) {
566 inserter.AddArg(key_id, Variadic::Real(annotation.double_value()));
567 } else if (annotation.has_string_iid()) {
568 auto string_id =
569 vulkan_memory_tracker_
570 .GetInternedString<InternedData::kVulkanMemoryKeysFieldNumber>(
571 sequence_state,
572 static_cast<uint64_t>(annotation.string_iid()));
573
574 inserter.AddArg(key_id, Variadic::String(string_id));
575 }
576 }
577 }
578 }
579
ParseGpuLog(int64_t ts,ConstBytes blob)580 void GpuEventParser::ParseGpuLog(int64_t ts, ConstBytes blob) {
581 protos::pbzero::GpuLog::Decoder event(blob.data, blob.size);
582
583 tables::GpuTrackTable::Row track(gpu_log_track_name_id_);
584 track.scope = gpu_log_scope_id_;
585 TrackId track_id = context_->track_tracker->InternGpuTrack(track);
586
587 auto args_callback = [this, &event](ArgsTracker::BoundInserter* inserter) {
588 if (event.has_tag()) {
589 inserter->AddArg(
590 tag_id_,
591 Variadic::String(context_->storage->InternString(event.tag())));
592 }
593 if (event.has_log_message()) {
594 inserter->AddArg(log_message_id_,
595 Variadic::String(context_->storage->InternString(
596 event.log_message())));
597 }
598 };
599
600 auto severity = static_cast<size_t>(event.severity());
601 StringId severity_id =
602 severity < log_severity_ids_.size()
603 ? log_severity_ids_[static_cast<size_t>(event.severity())]
604 : log_severity_ids_[log_severity_ids_.size() - 1];
605
606 tables::GpuSliceTable::Row row;
607 row.ts = ts;
608 row.track_id = track_id;
609 row.name = severity_id;
610 row.dur = 0;
611 context_->slice_tracker->ScopedGpu(row, args_callback);
612 }
613
ParseVulkanApiEvent(int64_t ts,ConstBytes blob)614 void GpuEventParser::ParseVulkanApiEvent(int64_t ts, ConstBytes blob) {
615 protos::pbzero::VulkanApiEvent::Decoder vk_event(blob.data, blob.size);
616 if (vk_event.has_vk_debug_utils_object_name()) {
617 protos::pbzero::VulkanApiEvent_VkDebugUtilsObjectName::Decoder event(
618 vk_event.vk_debug_utils_object_name());
619 debug_marker_names_[event.object_type()][event.object()] =
620 event.object_name().ToStdString();
621 }
622 if (vk_event.has_vk_queue_submit()) {
623 protos::pbzero::VulkanApiEvent_VkQueueSubmit::Decoder event(
624 vk_event.vk_queue_submit());
625 // Once flow table is implemented, we can create a nice UI that link the
626 // vkQueueSubmit to GpuRenderStageEvent. For now, just add it as in a GPU
627 // track so that they can appear close to the render stage slices.
628 tables::GpuTrackTable::Row track(vk_event_track_id_);
629 track.scope = vk_event_scope_id_;
630 TrackId track_id = context_->track_tracker->InternGpuTrack(track);
631 tables::GpuSliceTable::Row row;
632 row.ts = ts;
633 row.dur = static_cast<int64_t>(event.duration_ns());
634 row.track_id = track_id;
635 row.name = vk_queue_submit_id_;
636 if (event.has_vk_command_buffers()) {
637 row.command_buffer = static_cast<int64_t>(*event.vk_command_buffers());
638 }
639 row.submission_id = event.submission_id();
640 auto args_callback = [this, &event](ArgsTracker::BoundInserter* inserter) {
641 inserter->AddArg(context_->storage->InternString("pid"),
642 Variadic::Integer(event.pid()));
643 inserter->AddArg(context_->storage->InternString("tid"),
644 Variadic::Integer(event.tid()));
645 };
646 context_->slice_tracker->ScopedGpu(row, args_callback);
647 }
648 }
649
650 } // namespace trace_processor
651 } // namespace perfetto
652