mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-23 17:40:11 +01:00
vulkan: Add common RMV tracing infrastructure
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17331>
This commit is contained in:
parent
5f30a7538b
commit
defed48104
5 changed files with 345 additions and 0 deletions
|
|
@ -227,6 +227,8 @@ vk_device_finish(struct vk_device *device)
|
||||||
/* Drivers should tear down their own queues */
|
/* Drivers should tear down their own queues */
|
||||||
assert(list_is_empty(&device->queues));
|
assert(list_is_empty(&device->queues));
|
||||||
|
|
||||||
|
vk_memory_trace_finish(device);
|
||||||
|
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
if (device->swapchain_private) {
|
if (device->swapchain_private) {
|
||||||
hash_table_foreach(device->swapchain_private, entry)
|
hash_table_foreach(device->swapchain_private, entry)
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#ifndef VK_DEVICE_H
|
#ifndef VK_DEVICE_H
|
||||||
#define VK_DEVICE_H
|
#define VK_DEVICE_H
|
||||||
|
|
||||||
|
#include "rmv/vk_rmv_common.h"
|
||||||
#include "vk_dispatch_table.h"
|
#include "vk_dispatch_table.h"
|
||||||
#include "vk_extensions.h"
|
#include "vk_extensions.h"
|
||||||
#include "vk_object.h"
|
#include "vk_object.h"
|
||||||
|
|
@ -242,6 +243,8 @@ struct vk_device {
|
||||||
*/
|
*/
|
||||||
enum vk_queue_submit_mode submit_mode;
|
enum vk_queue_submit_mode submit_mode;
|
||||||
|
|
||||||
|
struct vk_memory_trace_data memory_trace_data;
|
||||||
|
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
mtx_t swapchain_private_mtx;
|
mtx_t swapchain_private_mtx;
|
||||||
struct hash_table *swapchain_private;
|
struct hash_table *swapchain_private;
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,8 @@ vk_cmd_queue_gen = files('vk_cmd_queue_gen.py')
|
||||||
vk_dispatch_trampolines_gen = files('vk_dispatch_trampolines_gen.py')
|
vk_dispatch_trampolines_gen = files('vk_dispatch_trampolines_gen.py')
|
||||||
|
|
||||||
files_vulkan_util = files(
|
files_vulkan_util = files(
|
||||||
|
'rmv/vk_rmv_common.c',
|
||||||
|
'rmv/vk_rmv_common.h',
|
||||||
'rmv/vk_rmv_tokens.h',
|
'rmv/vk_rmv_tokens.h',
|
||||||
'vk_alloc.c',
|
'vk_alloc.c',
|
||||||
'vk_alloc.h',
|
'vk_alloc.h',
|
||||||
|
|
|
||||||
175
src/vulkan/util/rmv/vk_rmv_common.c
Normal file
175
src/vulkan/util/rmv/vk_rmv_common.c
Normal file
|
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2022 Friedrich Vock
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "vk_rmv_common.h"
|
||||||
|
#include "vulkan/runtime/vk_buffer.h"
|
||||||
|
#include "vulkan/runtime/vk_device.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
vk_memory_trace_init(struct vk_device *device, const struct vk_rmv_device_info *device_info)
|
||||||
|
{
|
||||||
|
device->memory_trace_data.device_info = *device_info;
|
||||||
|
device->memory_trace_data.is_enabled = true;
|
||||||
|
util_dynarray_init(&device->memory_trace_data.tokens, NULL);
|
||||||
|
simple_mtx_init(&device->memory_trace_data.token_mtx, mtx_plain);
|
||||||
|
|
||||||
|
device->memory_trace_data.trace_frame_idx = vk_memory_trace_frame();
|
||||||
|
device->memory_trace_data.trigger_file_name = vk_memory_trace_trigger_file();
|
||||||
|
|
||||||
|
device->memory_trace_data.cur_frame_idx = 0;
|
||||||
|
device->memory_trace_data.next_resource_id = 1;
|
||||||
|
device->memory_trace_data.handle_table = _mesa_hash_table_u64_create(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vk_memory_trace_finish(struct vk_device *device)
|
||||||
|
{
|
||||||
|
if (!device->memory_trace_data.is_enabled)
|
||||||
|
return;
|
||||||
|
util_dynarray_foreach (&device->memory_trace_data.tokens, struct vk_rmv_token, token) {
|
||||||
|
switch (token->type) {
|
||||||
|
case VK_RMV_TOKEN_TYPE_RESOURCE_CREATE: {
|
||||||
|
struct vk_rmv_resource_create_token *create_token = &token->data.resource_create;
|
||||||
|
if (create_token->type == VK_RMV_RESOURCE_TYPE_DESCRIPTOR_POOL) {
|
||||||
|
free(create_token->descriptor_pool.pool_sizes);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VK_RMV_TOKEN_TYPE_USERDATA:
|
||||||
|
free(token->data.userdata.name);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
util_dynarray_fini(&device->memory_trace_data.tokens);
|
||||||
|
if (_mesa_hash_table_num_entries(device->memory_trace_data.handle_table->table))
|
||||||
|
fprintf(stderr,
|
||||||
|
"mesa: Unfreed resources detected at device destroy, there may be memory leaks!\n");
|
||||||
|
_mesa_hash_table_u64_destroy(device->memory_trace_data.handle_table);
|
||||||
|
device->memory_trace_data.is_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vk_rmv_handle_present_locked(struct vk_device *device)
|
||||||
|
{
|
||||||
|
struct vk_memory_trace_data *trace_data = &device->memory_trace_data;
|
||||||
|
|
||||||
|
if (!trace_data->is_enabled)
|
||||||
|
return;
|
||||||
|
bool frame_trigger = false;
|
||||||
|
bool file_trigger = false;
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
if (trace_data->trigger_file_name && access(trace_data->trigger_file_name, W_OK) == 0) {
|
||||||
|
if (unlink(trace_data->trigger_file_name) == 0)
|
||||||
|
file_trigger = true;
|
||||||
|
else
|
||||||
|
/* Do not enable tracing if we cannot remove the file,
|
||||||
|
* because by then we'll trace every frame ... */
|
||||||
|
fprintf(stderr, "mesa: could not remove memory trace trigger "
|
||||||
|
"file, ignoring\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int32_t new_frame_index = p_atomic_add_return(&trace_data->cur_frame_idx, 1);
|
||||||
|
frame_trigger =
|
||||||
|
(new_frame_index % trace_data->trace_frame_idx == 0) && trace_data->trace_frame_idx != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vk_rmv_emit_token(struct vk_memory_trace_data *data, enum vk_rmv_token_type type, void *token_data)
|
||||||
|
{
|
||||||
|
struct vk_rmv_token token;
|
||||||
|
token.type = type;
|
||||||
|
token.timestamp = (uint64_t)os_time_get_nano();
|
||||||
|
memcpy(&token.data, token_data, vk_rmv_token_size_from_type(type));
|
||||||
|
util_dynarray_append(&data->tokens, struct vk_rmv_token, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
vk_rmv_get_resource_id_locked(struct vk_device *device, uint64_t handle)
|
||||||
|
{
|
||||||
|
void *entry = _mesa_hash_table_u64_search(device->memory_trace_data.handle_table, handle);
|
||||||
|
if (!entry) {
|
||||||
|
uint32_t id = device->memory_trace_data.next_resource_id++;
|
||||||
|
_mesa_hash_table_u64_insert(device->memory_trace_data.handle_table, handle,
|
||||||
|
(void *)(uintptr_t)id);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
return (uint32_t)(uintptr_t)entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vk_rmv_destroy_resource_id_locked(struct vk_device *device, uint64_t handle)
|
||||||
|
{
|
||||||
|
_mesa_hash_table_u64_remove(device->memory_trace_data.handle_table, handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vk_rmv_log_buffer_create(struct vk_device *device, bool is_internal, VkBuffer _buffer)
|
||||||
|
{
|
||||||
|
if (!device->memory_trace_data.is_enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
VK_FROM_HANDLE(vk_buffer, buffer, _buffer);
|
||||||
|
simple_mtx_lock(&device->memory_trace_data.token_mtx);
|
||||||
|
struct vk_rmv_resource_create_token token = {0};
|
||||||
|
token.is_driver_internal = is_internal;
|
||||||
|
token.resource_id = vk_rmv_get_resource_id_locked(device, (uint64_t)_buffer);
|
||||||
|
token.type = VK_RMV_RESOURCE_TYPE_BUFFER;
|
||||||
|
token.buffer.create_flags = buffer->create_flags;
|
||||||
|
token.buffer.size = buffer->size;
|
||||||
|
token.buffer.usage_flags = buffer->usage;
|
||||||
|
|
||||||
|
vk_rmv_emit_token(&device->memory_trace_data, VK_RMV_TOKEN_TYPE_RESOURCE_CREATE, &token);
|
||||||
|
simple_mtx_unlock(&device->memory_trace_data.token_mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vk_rmv_log_cpu_map(struct vk_device *device, uint64_t va, bool is_unmap)
|
||||||
|
{
|
||||||
|
if (!device->memory_trace_data.is_enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct vk_rmv_cpu_map_token map_token;
|
||||||
|
map_token.address = va;
|
||||||
|
map_token.unmapped = is_unmap;
|
||||||
|
|
||||||
|
simple_mtx_lock(&device->memory_trace_data.token_mtx);
|
||||||
|
vk_rmv_emit_token(&device->memory_trace_data, VK_RMV_TOKEN_TYPE_CPU_MAP, &map_token);
|
||||||
|
simple_mtx_unlock(&device->memory_trace_data.token_mtx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vk_rmv_log_misc_token(struct vk_device *device, enum vk_rmv_misc_event_type type)
|
||||||
|
{
|
||||||
|
if (!device->memory_trace_data.is_enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
simple_mtx_lock(&device->memory_trace_data.token_mtx);
|
||||||
|
struct vk_rmv_misc_token token;
|
||||||
|
token.type = type;
|
||||||
|
vk_rmv_emit_token(&device->memory_trace_data, VK_RMV_TOKEN_TYPE_MISC, &token);
|
||||||
|
simple_mtx_unlock(&device->memory_trace_data.token_mtx);
|
||||||
|
}
|
||||||
163
src/vulkan/util/rmv/vk_rmv_common.h
Normal file
163
src/vulkan/util/rmv/vk_rmv_common.h
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2022 Friedrich Vock
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VK_RMV_COMMON_H
|
||||||
|
#define VK_RMV_COMMON_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "util/hash_table.h"
|
||||||
|
#include "util/simple_mtx.h"
|
||||||
|
#include "util/u_debug.h"
|
||||||
|
#include "util/u_dynarray.h"
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
#include "vk_rmv_tokens.h"
|
||||||
|
|
||||||
|
struct vk_memory_trace_data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The different memory domains RMV supports.
|
||||||
|
*/
|
||||||
|
enum vk_rmv_memory_location {
|
||||||
|
/* DEVICE_LOCAL | HOST_VISIBLE */
|
||||||
|
VK_RMV_MEMORY_LOCATION_DEVICE,
|
||||||
|
/* DEVICE_LOCAL */
|
||||||
|
VK_RMV_MEMORY_LOCATION_DEVICE_INVISIBLE,
|
||||||
|
/* HOST_VISIBLE | HOST_COHERENT */
|
||||||
|
VK_RMV_MEMORY_LOCATION_HOST,
|
||||||
|
|
||||||
|
/* add above here */
|
||||||
|
VK_RMV_MEMORY_LOCATION_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Information about a memory domain.
|
||||||
|
*/
|
||||||
|
struct vk_rmv_memory_info {
|
||||||
|
uint64_t size;
|
||||||
|
uint64_t physical_base_address;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum vk_rmv_memory_type {
|
||||||
|
VK_RMV_MEMORY_TYPE_UNKNOWN,
|
||||||
|
VK_RMV_MEMORY_TYPE_DDR2,
|
||||||
|
VK_RMV_MEMORY_TYPE_DDR3,
|
||||||
|
VK_RMV_MEMORY_TYPE_DDR4,
|
||||||
|
VK_RMV_MEMORY_TYPE_GDDR5,
|
||||||
|
VK_RMV_MEMORY_TYPE_GDDR6,
|
||||||
|
VK_RMV_MEMORY_TYPE_HBM,
|
||||||
|
VK_RMV_MEMORY_TYPE_HBM2,
|
||||||
|
VK_RMV_MEMORY_TYPE_HBM3,
|
||||||
|
VK_RMV_MEMORY_TYPE_LPDDR4,
|
||||||
|
VK_RMV_MEMORY_TYPE_LPDDR5,
|
||||||
|
VK_RMV_MEMORY_TYPE_DDR5
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device information for RMV traces.
|
||||||
|
*/
|
||||||
|
struct vk_rmv_device_info {
|
||||||
|
struct vk_rmv_memory_info memory_infos[VK_RMV_MEMORY_LOCATION_COUNT];
|
||||||
|
|
||||||
|
/* The memory type of dedicated VRAM. */
|
||||||
|
enum vk_rmv_memory_type vram_type;
|
||||||
|
|
||||||
|
char device_name[128];
|
||||||
|
|
||||||
|
uint32_t pcie_family_id;
|
||||||
|
uint32_t pcie_revision_id;
|
||||||
|
uint32_t pcie_device_id;
|
||||||
|
/* The minimum shader clock, in MHz. */
|
||||||
|
uint32_t minimum_shader_clock;
|
||||||
|
/* The maximum shader clock, in MHz. */
|
||||||
|
uint32_t maximum_shader_clock;
|
||||||
|
uint32_t vram_operations_per_clock;
|
||||||
|
uint32_t vram_bus_width;
|
||||||
|
/* The VRAM bandwidth, in GB/s (1 GB/s = 1000 MB/s). */
|
||||||
|
uint32_t vram_bandwidth;
|
||||||
|
/* The minimum memory clock, in MHz. */
|
||||||
|
uint32_t minimum_memory_clock;
|
||||||
|
/* The maximum memory clock, in MHz. */
|
||||||
|
uint32_t maximum_memory_clock;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vk_device;
|
||||||
|
|
||||||
|
struct vk_memory_trace_data {
|
||||||
|
struct util_dynarray tokens;
|
||||||
|
simple_mtx_t token_mtx;
|
||||||
|
|
||||||
|
int32_t cur_frame_idx;
|
||||||
|
int32_t trace_frame_idx;
|
||||||
|
const char *trigger_file_name;
|
||||||
|
|
||||||
|
bool is_enabled;
|
||||||
|
|
||||||
|
struct vk_rmv_device_info device_info;
|
||||||
|
|
||||||
|
struct hash_table_u64 *handle_table;
|
||||||
|
uint32_t next_resource_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vk_device;
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
vk_memory_trace_frame()
|
||||||
|
{
|
||||||
|
return (int)debug_get_num_option("MESA_VK_MEMORY_TRACE", -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const char *
|
||||||
|
vk_memory_trace_trigger_file()
|
||||||
|
{
|
||||||
|
return getenv("MESA_VK_MEMORY_TRACE_TRIGGER");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
vk_memory_trace_enabled()
|
||||||
|
{
|
||||||
|
return vk_memory_trace_frame() != -1 || vk_memory_trace_trigger_file();
|
||||||
|
}
|
||||||
|
|
||||||
|
void vk_memory_trace_init(struct vk_device *device, const struct vk_rmv_device_info *device_info);
|
||||||
|
|
||||||
|
void vk_memory_trace_finish(struct vk_device *device);
|
||||||
|
|
||||||
|
/* The memory trace mutex should be locked when entering this function. */
|
||||||
|
void vk_rmv_handle_present_locked(struct vk_device *device);
|
||||||
|
|
||||||
|
void vk_rmv_emit_token(struct vk_memory_trace_data *data, enum vk_rmv_token_type type,
|
||||||
|
void *token_data);
|
||||||
|
void vk_rmv_log_buffer_create(struct vk_device *device, bool is_internal, VkBuffer _buffer);
|
||||||
|
void vk_rmv_log_cpu_map(struct vk_device *device, uint64_t va, bool is_unmap);
|
||||||
|
void vk_rmv_log_misc_token(struct vk_device *device, enum vk_rmv_misc_event_type type);
|
||||||
|
|
||||||
|
/* Retrieves the unique resource id for the resource specified by handle.
|
||||||
|
* Allocates a new id if none exists already.
|
||||||
|
* The memory trace mutex should be locked when entering this function. */
|
||||||
|
uint32_t vk_rmv_get_resource_id_locked(struct vk_device *device, uint64_t handle);
|
||||||
|
/* Destroys a resource id. If the same handle is allocated again, a new resource
|
||||||
|
* id is given to it.
|
||||||
|
* The memory trace mutex should be locked when entering this function. */
|
||||||
|
void vk_rmv_destroy_resource_id_locked(struct vk_device *device, uint64_t handle);
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Add table
Reference in a new issue