1 /*
2  * Copyright © 2022 Friedrich Vock
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "vk_rmv_common.h"
25 #include "vulkan/runtime/vk_buffer.h"
26 #include "vulkan/runtime/vk_device.h"
27 
28 void
vk_memory_trace_init(struct vk_device * device,const struct vk_rmv_device_info * device_info)29 vk_memory_trace_init(struct vk_device *device, const struct vk_rmv_device_info *device_info)
30 {
31    device->memory_trace_data.device_info = *device_info;
32    device->memory_trace_data.is_enabled = true;
33    util_dynarray_init(&device->memory_trace_data.tokens, NULL);
34    simple_mtx_init(&device->memory_trace_data.token_mtx, mtx_plain);
35 
36    device->memory_trace_data.next_resource_id = 1;
37    device->memory_trace_data.handle_table = _mesa_hash_table_u64_create(NULL);
38 }
39 
40 void
vk_memory_trace_finish(struct vk_device * device)41 vk_memory_trace_finish(struct vk_device *device)
42 {
43    if (!device->memory_trace_data.is_enabled)
44       return;
45    util_dynarray_foreach (&device->memory_trace_data.tokens, struct vk_rmv_token, token) {
46       switch (token->type) {
47       case VK_RMV_TOKEN_TYPE_RESOURCE_CREATE: {
48          struct vk_rmv_resource_create_token *create_token = &token->data.resource_create;
49          if (create_token->type == VK_RMV_RESOURCE_TYPE_DESCRIPTOR_POOL) {
50             free(create_token->descriptor_pool.pool_sizes);
51          }
52          break;
53       }
54       case VK_RMV_TOKEN_TYPE_USERDATA:
55          free(token->data.userdata.name);
56          break;
57       default:
58          break;
59       }
60    }
61    util_dynarray_fini(&device->memory_trace_data.tokens);
62    if (_mesa_hash_table_num_entries(device->memory_trace_data.handle_table->table))
63       fprintf(stderr,
64               "mesa: Unfreed resources detected at device destroy, there may be memory leaks!\n");
65    _mesa_hash_table_u64_destroy(device->memory_trace_data.handle_table);
66    device->memory_trace_data.is_enabled = false;
67 }
68 
69 void
vk_rmv_emit_token(struct vk_memory_trace_data * data,enum vk_rmv_token_type type,void * token_data)70 vk_rmv_emit_token(struct vk_memory_trace_data *data, enum vk_rmv_token_type type, void *token_data)
71 {
72    struct vk_rmv_token token;
73    token.type = type;
74    token.timestamp = (uint64_t)os_time_get_nano();
75    memcpy(&token.data, token_data, vk_rmv_token_size_from_type(type));
76    util_dynarray_append(&data->tokens, struct vk_rmv_token, token);
77 }
78 
79 uint32_t
vk_rmv_get_resource_id_locked(struct vk_device * device,uint64_t handle)80 vk_rmv_get_resource_id_locked(struct vk_device *device, uint64_t handle)
81 {
82    void *entry = _mesa_hash_table_u64_search(device->memory_trace_data.handle_table, handle);
83    if (!entry) {
84       uint32_t id = device->memory_trace_data.next_resource_id++;
85       _mesa_hash_table_u64_insert(device->memory_trace_data.handle_table, handle,
86                                   (void *)(uintptr_t)id);
87       return id;
88    }
89    return (uint32_t)(uintptr_t)entry;
90 }
91 
92 void
vk_rmv_destroy_resource_id_locked(struct vk_device * device,uint64_t handle)93 vk_rmv_destroy_resource_id_locked(struct vk_device *device, uint64_t handle)
94 {
95    _mesa_hash_table_u64_remove(device->memory_trace_data.handle_table, handle);
96 }
97 
98 void
vk_rmv_log_buffer_create(struct vk_device * device,bool is_internal,VkBuffer _buffer)99 vk_rmv_log_buffer_create(struct vk_device *device, bool is_internal, VkBuffer _buffer)
100 {
101    if (!device->memory_trace_data.is_enabled)
102       return;
103 
104    VK_FROM_HANDLE(vk_buffer, buffer, _buffer);
105    simple_mtx_lock(&device->memory_trace_data.token_mtx);
106    struct vk_rmv_resource_create_token token = {0};
107    token.is_driver_internal = is_internal;
108    token.resource_id = vk_rmv_get_resource_id_locked(device, (uint64_t)_buffer);
109    token.type = VK_RMV_RESOURCE_TYPE_BUFFER;
110    token.buffer.create_flags = buffer->create_flags;
111    token.buffer.size = buffer->size;
112    token.buffer.usage_flags = buffer->usage;
113 
114    vk_rmv_emit_token(&device->memory_trace_data, VK_RMV_TOKEN_TYPE_RESOURCE_CREATE, &token);
115    simple_mtx_unlock(&device->memory_trace_data.token_mtx);
116 }
117 
118 void
vk_rmv_log_cpu_map(struct vk_device * device,uint64_t va,bool is_unmap)119 vk_rmv_log_cpu_map(struct vk_device *device, uint64_t va, bool is_unmap)
120 {
121    if (!device->memory_trace_data.is_enabled)
122       return;
123 
124    struct vk_rmv_cpu_map_token map_token;
125    map_token.address = va;
126    map_token.unmapped = is_unmap;
127 
128    simple_mtx_lock(&device->memory_trace_data.token_mtx);
129    vk_rmv_emit_token(&device->memory_trace_data, VK_RMV_TOKEN_TYPE_CPU_MAP, &map_token);
130    simple_mtx_unlock(&device->memory_trace_data.token_mtx);
131 }
132 
133 void
vk_rmv_log_misc_token(struct vk_device * device,enum vk_rmv_misc_event_type type)134 vk_rmv_log_misc_token(struct vk_device *device, enum vk_rmv_misc_event_type type)
135 {
136    if (!device->memory_trace_data.is_enabled)
137       return;
138 
139    simple_mtx_lock(&device->memory_trace_data.token_mtx);
140    struct vk_rmv_misc_token token;
141    token.type = type;
142    vk_rmv_emit_token(&device->memory_trace_data, VK_RMV_TOKEN_TYPE_MISC, &token);
143    simple_mtx_unlock(&device->memory_trace_data.token_mtx);
144 }
145