zink: add mem debugging
modeled off turnip's debug infra, this adds debug printing for oom scenarios Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/23653>
This commit is contained in:

committed by
Marge Bot

parent
65fad783c7
commit
4edbe8f5a0
@@ -315,6 +315,8 @@ variable:
|
|||||||
Disable async optimized pipeline compiles
|
Disable async optimized pipeline compiles
|
||||||
``nobgc``
|
``nobgc``
|
||||||
Disable all async pipeline compiles
|
Disable all async pipeline compiles
|
||||||
|
``mem``
|
||||||
|
Enable memory allocation debugging
|
||||||
|
|
||||||
Vulkan Validation Layers
|
Vulkan Validation Layers
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@@ -303,6 +303,11 @@ bo_create_internal(struct zink_screen *screen,
|
|||||||
VkResult ret = VKSCR(AllocateMemory)(screen->dev, &mai, NULL, &bo->mem);
|
VkResult ret = VKSCR(AllocateMemory)(screen->dev, &mai, NULL, &bo->mem);
|
||||||
if (!zink_screen_handle_vkresult(screen, ret)) {
|
if (!zink_screen_handle_vkresult(screen, ret)) {
|
||||||
mesa_loge("zink: couldn't allocate memory: heap=%u size=%" PRIu64, heap, size);
|
mesa_loge("zink: couldn't allocate memory: heap=%u size=%" PRIu64, heap, size);
|
||||||
|
if (zink_debug & ZINK_DEBUG_MEM) {
|
||||||
|
zink_debug_mem_print_stats(screen);
|
||||||
|
/* abort with mem debug to allow debugging */
|
||||||
|
abort();
|
||||||
|
}
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -65,6 +65,102 @@
|
|||||||
|
|
||||||
#define ZINK_EXTERNAL_MEMORY_HANDLE 999
|
#define ZINK_EXTERNAL_MEMORY_HANDLE 999
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct zink_debug_mem_entry {
|
||||||
|
uint32_t count;
|
||||||
|
uint64_t size;
|
||||||
|
const char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
zink_debug_mem_add(struct zink_screen *screen, uint64_t size, const char *name)
|
||||||
|
{
|
||||||
|
assert(name);
|
||||||
|
|
||||||
|
simple_mtx_lock(&screen->debug_mem_lock);
|
||||||
|
struct hash_entry *entry = _mesa_hash_table_search(screen->debug_mem_sizes, name);
|
||||||
|
struct zink_debug_mem_entry *debug_bos;
|
||||||
|
|
||||||
|
if (!entry) {
|
||||||
|
debug_bos = calloc(1, sizeof(struct zink_debug_mem_entry));
|
||||||
|
debug_bos->name = strdup(name);
|
||||||
|
_mesa_hash_table_insert(screen->debug_mem_sizes, debug_bos->name, debug_bos);
|
||||||
|
} else {
|
||||||
|
debug_bos = (struct zink_debug_mem_entry *) entry->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_bos->count++;
|
||||||
|
debug_bos->size += align(size, 4096);
|
||||||
|
simple_mtx_unlock(&screen->debug_mem_lock);
|
||||||
|
|
||||||
|
return debug_bos->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
zink_debug_mem_del(struct zink_screen *screen, struct zink_bo *bo)
|
||||||
|
{
|
||||||
|
simple_mtx_lock(&screen->debug_mem_lock);
|
||||||
|
struct hash_entry *entry = _mesa_hash_table_search(screen->debug_mem_sizes, bo->name);
|
||||||
|
/* If we're finishing the BO, it should have been added already */
|
||||||
|
assert(entry);
|
||||||
|
|
||||||
|
struct zink_debug_mem_entry *debug_bos = entry->data;
|
||||||
|
debug_bos->count--;
|
||||||
|
debug_bos->size -= align(zink_bo_get_size(bo), 4096);
|
||||||
|
if (!debug_bos->count) {
|
||||||
|
_mesa_hash_table_remove(screen->debug_mem_sizes, entry);
|
||||||
|
free((void*)debug_bos->name);
|
||||||
|
free(debug_bos);
|
||||||
|
}
|
||||||
|
simple_mtx_unlock(&screen->debug_mem_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
debug_bos_count_compare(const void *in_a, const void *in_b)
|
||||||
|
{
|
||||||
|
struct zink_debug_mem_entry *a = *(struct zink_debug_mem_entry **)in_a;
|
||||||
|
struct zink_debug_mem_entry *b = *(struct zink_debug_mem_entry **)in_b;
|
||||||
|
return a->count - b->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
zink_debug_mem_print_stats(struct zink_screen *screen)
|
||||||
|
{
|
||||||
|
simple_mtx_lock(&screen->debug_mem_lock);
|
||||||
|
|
||||||
|
/* Put the HT's sizes data in an array so we can sort by number of allocations. */
|
||||||
|
struct util_dynarray dyn;
|
||||||
|
util_dynarray_init(&dyn, NULL);
|
||||||
|
|
||||||
|
uint32_t size = 0;
|
||||||
|
uint32_t count = 0;
|
||||||
|
hash_table_foreach(screen->debug_mem_sizes, entry)
|
||||||
|
{
|
||||||
|
struct zink_debug_mem_entry *debug_bos = entry->data;
|
||||||
|
util_dynarray_append(&dyn, struct zink_debug_mem_entry *, debug_bos);
|
||||||
|
size += debug_bos->size / 1024;
|
||||||
|
count += debug_bos->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(dyn.data,
|
||||||
|
util_dynarray_num_elements(&dyn, struct zink_debug_mem_entry *),
|
||||||
|
sizeof(struct zink_debug_mem_entryos_entry *), debug_bos_count_compare);
|
||||||
|
|
||||||
|
util_dynarray_foreach(&dyn, struct zink_debug_mem_entry *, entryp)
|
||||||
|
{
|
||||||
|
struct zink_debug_mem_entry *debug_bos = *entryp;
|
||||||
|
mesa_logi("%30s: %4d bos, %lld kb\n", debug_bos->name, debug_bos->count,
|
||||||
|
(long long) (debug_bos->size / 1024));
|
||||||
|
}
|
||||||
|
|
||||||
|
mesa_logi("submitted %d bos (%d MB)\n", count, DIV_ROUND_UP(size, 1024));
|
||||||
|
|
||||||
|
util_dynarray_fini(&dyn);
|
||||||
|
|
||||||
|
simple_mtx_unlock(&screen->debug_mem_lock);
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
equals_ivci(const void *a, const void *b)
|
equals_ivci(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
@@ -104,6 +200,8 @@ zink_destroy_resource_object(struct zink_screen *screen, struct zink_resource_ob
|
|||||||
while (util_dynarray_contains(&obj->views, VkImageView))
|
while (util_dynarray_contains(&obj->views, VkImageView))
|
||||||
VKSCR(DestroyImageView)(screen->dev, util_dynarray_pop(&obj->views, VkImageView), NULL);
|
VKSCR(DestroyImageView)(screen->dev, util_dynarray_pop(&obj->views, VkImageView), NULL);
|
||||||
}
|
}
|
||||||
|
if (!obj->dt && zink_debug & ZINK_DEBUG_MEM)
|
||||||
|
zink_debug_mem_del(screen, obj->bo);
|
||||||
util_dynarray_fini(&obj->views);
|
util_dynarray_fini(&obj->views);
|
||||||
for (unsigned i = 0; i < ARRAY_SIZE(obj->copies); i++)
|
for (unsigned i = 0; i < ARRAY_SIZE(obj->copies); i++)
|
||||||
util_dynarray_fini(&obj->copies[i]);
|
util_dynarray_fini(&obj->copies[i]);
|
||||||
@@ -1147,6 +1245,35 @@ retry:
|
|||||||
obj->offset = zink_bo_get_offset(obj->bo);
|
obj->offset = zink_bo_get_offset(obj->bo);
|
||||||
obj->size = zink_bo_get_size(obj->bo);
|
obj->size = zink_bo_get_size(obj->bo);
|
||||||
}
|
}
|
||||||
|
if (zink_debug & ZINK_DEBUG_MEM) {
|
||||||
|
char buf[4096];
|
||||||
|
unsigned idx = 0;
|
||||||
|
if (obj->is_buffer) {
|
||||||
|
size_t size = (size_t)DIV_ROUND_UP(obj->size, 1024);
|
||||||
|
if (templ->bind == PIPE_BIND_QUERY_BUFFER && templ->usage == PIPE_USAGE_STAGING) //internal qbo
|
||||||
|
idx += snprintf(buf, sizeof(buf), "QBO(%zu)", size);
|
||||||
|
else
|
||||||
|
idx += snprintf(buf, sizeof(buf), "BUF(%zu)", size);
|
||||||
|
} else {
|
||||||
|
idx += snprintf(buf, sizeof(buf), "IMG(%s:%ux%ux%u)", util_format_short_name(templ->format), templ->width0, templ->height0, templ->depth0);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
zink_vkflags_func flag_func = obj->is_buffer ? (zink_vkflags_func)vk_BufferCreateFlagBits_to_str : (zink_vkflags_func)vk_ImageCreateFlagBits_to_str;
|
||||||
|
zink_vkflags_func usage_func = obj->is_buffer ? (zink_vkflags_func)vk_BufferUsageFlagBits_to_str : (zink_vkflags_func)vk_ImageUsageFlagBits_to_str;
|
||||||
|
if (obj->vkflags) {
|
||||||
|
buf[idx++] = '[';
|
||||||
|
idx += zink_string_vkflags_unroll(&buf[idx], sizeof(buf) - idx, obj->vkflags, flag_func);
|
||||||
|
buf[idx++] = ']';
|
||||||
|
}
|
||||||
|
if (obj->vkusage) {
|
||||||
|
buf[idx++] = '[';
|
||||||
|
idx += zink_string_vkflags_unroll(&buf[idx], sizeof(buf) - idx, obj->vkusage, usage_func);
|
||||||
|
buf[idx++] = ']';
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
buf[idx] = 0;
|
||||||
|
obj->bo->name = zink_debug_mem_add(screen, obj->size, buf);
|
||||||
|
}
|
||||||
|
|
||||||
obj->coherent = screen->info.mem_props.memoryTypes[obj->bo->base.placement].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
obj->coherent = screen->info.mem_props.memoryTypes[obj->bo->base.placement].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||||
if (!(templ->flags & PIPE_RESOURCE_FLAG_SPARSE)) {
|
if (!(templ->flags & PIPE_RESOURCE_FLAG_SPARSE)) {
|
||||||
@@ -1192,6 +1319,7 @@ retry:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < max_level; i++)
|
for (unsigned i = 0; i < max_level; i++)
|
||||||
util_dynarray_init(&obj->copies[i], NULL);
|
util_dynarray_init(&obj->copies[i], NULL);
|
||||||
return obj;
|
return obj;
|
||||||
|
@@ -191,6 +191,9 @@ zink_batch_resource_usage_set(struct zink_batch *batch, struct zink_resource *re
|
|||||||
batch->has_work = true;
|
batch->has_work = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
zink_debug_mem_print_stats(struct zink_screen *screen);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -97,6 +97,7 @@ zink_debug_options[] = {
|
|||||||
{ "noopt", ZINK_DEBUG_NOOPT, "Disable async optimized pipeline compiles" },
|
{ "noopt", ZINK_DEBUG_NOOPT, "Disable async optimized pipeline compiles" },
|
||||||
{ "nobgc", ZINK_DEBUG_NOBGC, "Disable all async pipeline compiles" },
|
{ "nobgc", ZINK_DEBUG_NOBGC, "Disable all async pipeline compiles" },
|
||||||
{ "dgc", ZINK_DEBUG_DGC, "Use DGC (driver testing only)" },
|
{ "dgc", ZINK_DEBUG_DGC, "Use DGC (driver testing only)" },
|
||||||
|
{ "mem", ZINK_DEBUG_MEM, "Debug memory allocations" },
|
||||||
DEBUG_NAMED_VALUE_END
|
DEBUG_NAMED_VALUE_END
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1493,6 +1494,9 @@ zink_destroy_screen(struct pipe_screen *pscreen)
|
|||||||
if (screen->bindless_layout)
|
if (screen->bindless_layout)
|
||||||
VKSCR(DestroyDescriptorSetLayout)(screen->dev, screen->bindless_layout, NULL);
|
VKSCR(DestroyDescriptorSetLayout)(screen->dev, screen->bindless_layout, NULL);
|
||||||
|
|
||||||
|
if (zink_debug & ZINK_DEBUG_MEM)
|
||||||
|
simple_mtx_destroy(&screen->debug_mem_lock);
|
||||||
|
|
||||||
simple_mtx_destroy(&screen->queue_lock);
|
simple_mtx_destroy(&screen->queue_lock);
|
||||||
VKSCR(DestroyDevice)(screen->dev, NULL);
|
VKSCR(DestroyDevice)(screen->dev, NULL);
|
||||||
VKSCR(DestroyInstance)(screen->instance, NULL);
|
VKSCR(DestroyInstance)(screen->instance, NULL);
|
||||||
@@ -2896,6 +2900,11 @@ zink_internal_create_screen(const struct pipe_screen_config *config)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (zink_debug & ZINK_DEBUG_MEM) {
|
||||||
|
simple_mtx_init(&screen->debug_mem_lock, mtx_plain);
|
||||||
|
screen->debug_mem_sizes = _mesa_hash_table_create(screen, _mesa_hash_string, _mesa_key_string_equal);
|
||||||
|
}
|
||||||
|
|
||||||
init_driver_workarounds(screen);
|
init_driver_workarounds(screen);
|
||||||
|
|
||||||
screen->dev = zink_create_logical_device(screen);
|
screen->dev = zink_create_logical_device(screen);
|
||||||
|
@@ -108,7 +108,7 @@ zink_string_vkflags_unroll(char *buf, size_t bufsize, uint64_t flags, zink_vkfla
|
|||||||
u_foreach_bit64(bit, flags) {
|
u_foreach_bit64(bit, flags) {
|
||||||
if (!first)
|
if (!first)
|
||||||
buf[idx++] = '|';
|
buf[idx++] = '|';
|
||||||
idx += snprintf(&buf[idx], bufsize - idx, "%s", func((1ul<<bit)));
|
idx += snprintf(&buf[idx], bufsize - idx, "%s", func((BITFIELD64_BIT(bit))));
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
return idx;
|
return idx;
|
||||||
|
@@ -238,6 +238,7 @@ enum zink_debug {
|
|||||||
ZINK_DEBUG_NOOPT = (1<<15),
|
ZINK_DEBUG_NOOPT = (1<<15),
|
||||||
ZINK_DEBUG_NOBGC = (1<<16),
|
ZINK_DEBUG_NOBGC = (1<<16),
|
||||||
ZINK_DEBUG_DGC = (1<<17),
|
ZINK_DEBUG_DGC = (1<<17),
|
||||||
|
ZINK_DEBUG_MEM = (1<<18),
|
||||||
};
|
};
|
||||||
|
|
||||||
enum zink_pv_emulation_primitive {
|
enum zink_pv_emulation_primitive {
|
||||||
@@ -711,6 +712,7 @@ struct zink_bo {
|
|||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
|
|
||||||
uint32_t unique_id;
|
uint32_t unique_id;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
simple_mtx_t lock;
|
simple_mtx_t lock;
|
||||||
|
|
||||||
@@ -1253,8 +1255,8 @@ struct zink_resource_object {
|
|||||||
|
|
||||||
|
|
||||||
VkDeviceSize offset, size, alignment;
|
VkDeviceSize offset, size, alignment;
|
||||||
VkImageCreateFlags vkflags;
|
uint64_t vkflags;
|
||||||
VkImageUsageFlags vkusage;
|
uint64_t vkusage;
|
||||||
VkFormatFeatureFlags vkfeats;
|
VkFormatFeatureFlags vkfeats;
|
||||||
uint64_t modifier;
|
uint64_t modifier;
|
||||||
VkImageAspectFlags modifier_aspect;
|
VkImageAspectFlags modifier_aspect;
|
||||||
@@ -1429,6 +1431,9 @@ struct zink_screen {
|
|||||||
VkInstance instance;
|
VkInstance instance;
|
||||||
struct zink_instance_info instance_info;
|
struct zink_instance_info instance_info;
|
||||||
|
|
||||||
|
struct hash_table *debug_mem_sizes;
|
||||||
|
simple_mtx_t debug_mem_lock;
|
||||||
|
|
||||||
VkPhysicalDevice pdev;
|
VkPhysicalDevice pdev;
|
||||||
uint32_t vk_version, spirv_version;
|
uint32_t vk_version, spirv_version;
|
||||||
struct util_idalloc_mt buffer_ids;
|
struct util_idalloc_mt buffer_ids;
|
||||||
|
Reference in New Issue
Block a user