vk: profiler: devmem: save `peak` instead of `total` metrics
Also minor code structure changes.
This commit is contained in:
parent
e3d86af5ab
commit
79e0e52061
|
@ -115,15 +115,12 @@ static void speedsPrintf( const char *msg, ... ) {
|
|||
|
||||
static void metricTypeSnprintf(char *buf, int buf_size, int value, r_speeds_metric_type_t type) {
|
||||
switch (type) {
|
||||
case kSpeedsMetricCount: {
|
||||
case kSpeedsMetricCount:
|
||||
Q_snprintf( buf, buf_size, "%d", value );
|
||||
break;
|
||||
}
|
||||
case kSpeedsMetricBytes: {
|
||||
char *memory_str = Q_memprint( (float) value );
|
||||
Q_strncpy( buf, memory_str, buf_size );
|
||||
case kSpeedsMetricBytes:
|
||||
Q_strncpy( buf, Q_memprint( (float) value ), buf_size );
|
||||
break;
|
||||
}
|
||||
case kSpeedsMetricMicroseconds: {
|
||||
float msecs = value * 1e-3f; // us -> ms
|
||||
Q_snprintf( buf, buf_size, "%.03f ms", msecs );
|
||||
|
|
|
@ -18,11 +18,10 @@ qboolean VK_BufferCreate(const char *debug_name, vk_buffer_t *buf, uint32_t size
|
|||
memreq.alignment = ALIGN_UP(memreq.alignment, vk_core.physical_device.properties_ray_tracing_pipeline.shaderGroupBaseAlignment);
|
||||
}
|
||||
|
||||
usage = (usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) ? VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT : 0;
|
||||
vk_devmem_allocate_args_t args = (vk_devmem_allocate_args_t) {
|
||||
.requirements = memreq,
|
||||
.property_flags = flags,
|
||||
.allocate_flags = usage,
|
||||
.allocate_flags = (usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) ? VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT : 0,
|
||||
};
|
||||
buf->devmem = VK_DevMemAllocateBuffer( debug_name, args );
|
||||
|
||||
|
|
|
@ -21,20 +21,22 @@ typedef struct vk_device_memory_slot_s {
|
|||
} vk_device_memory_slot_t;
|
||||
|
||||
typedef struct vk_devmem_allocation_stats_s {
|
||||
// Note:
|
||||
// `..._current` - Current size or number of allocations which gets updated on every allocation and deallocation.
|
||||
// `..._total` - Total size or number of allocations through the whole program runtime.
|
||||
// Metrics updated on every allocation and deallocation.
|
||||
struct {
|
||||
int allocations; // Current number of active (not freed) allocations.
|
||||
int allocated; // Current size of allocated memory.
|
||||
int align_holes; // Current number of alignment holes in active (not freed) allocations.
|
||||
int align_holes_size; // Current size of alignment holes in active (not freed) allocations.
|
||||
} current;
|
||||
|
||||
int allocations_current; // Current number of active (not freed) allocations.
|
||||
int allocated_current; // Current size of allocated memory.
|
||||
int allocations_total; // Total number of memory allocations.
|
||||
int allocated_total; // Total size of allocated memory.
|
||||
int frees_total; // Total number of memory deallocations (frees).
|
||||
int freed_total; // Total size of deallocated (freed) memory.
|
||||
int align_holes_current; // Current number of alignment holes in active (not freed) allocations.
|
||||
int align_holes_size_current; // Current size of alignment holes in active (not freed) allocations.
|
||||
int align_holes_total; // Total number of alignment holes in all of allocations made.
|
||||
int align_holes_size_total; // Total size of alignment holes in all of allocations made.
|
||||
// Metrics updated whenever new highest value is registered.
|
||||
struct {
|
||||
int allocations; // Highest number of allocations made.
|
||||
int allocated; // Largest size of allocated memory.
|
||||
int align_holes; // Highest number of alignment holes made.
|
||||
int align_holes_size; // Largest size of alignment holes made.
|
||||
int align_hole_size; // Largest size of the largest alignment hole made.
|
||||
} peak;
|
||||
} vk_devmem_allocation_stats_t;
|
||||
|
||||
static struct {
|
||||
|
@ -49,123 +51,116 @@ static struct {
|
|||
vk_devmem_allocation_stats_t stats[VK_DEVMEM_USAGE_TYPES_COUNT];
|
||||
|
||||
qboolean verbose;
|
||||
} g_vk_devmem;
|
||||
} g_devmem;
|
||||
|
||||
// Register allocation in overall stats and for the corresponding type too.
|
||||
// This is "scalable" approach, which can be simplified if needed.
|
||||
#define REGISTER_ALLOCATION( type, size, alignment ) { \
|
||||
g_vk_devmem.stats[VK_DEVMEM_USAGE_TYPE_ALL].allocations_current += 1; \
|
||||
g_vk_devmem.stats[VK_DEVMEM_USAGE_TYPE_ALL].allocated_current += size; \
|
||||
g_vk_devmem.stats[VK_DEVMEM_USAGE_TYPE_ALL].allocations_total += 1; \
|
||||
g_vk_devmem.stats[VK_DEVMEM_USAGE_TYPE_ALL].allocated_total += size; \
|
||||
int alignment_hole = size % alignment; \
|
||||
if ( alignment_hole > 0 ) { \
|
||||
g_vk_devmem.stats[VK_DEVMEM_USAGE_TYPE_ALL].align_holes_current += 1; \
|
||||
g_vk_devmem.stats[VK_DEVMEM_USAGE_TYPE_ALL].align_holes_size_current += alignment_hole; \
|
||||
g_vk_devmem.stats[VK_DEVMEM_USAGE_TYPE_ALL].align_holes_total += 1; \
|
||||
g_vk_devmem.stats[VK_DEVMEM_USAGE_TYPE_ALL].align_holes_size_total += alignment_hole; \
|
||||
} \
|
||||
for ( int type_idx = VK_DEVMEM_USAGE_TYPE_ALL + 1; type_idx < VK_DEVMEM_USAGE_TYPES_COUNT; type_idx += 1 ) { \
|
||||
if ( type_idx == type ) { \
|
||||
g_vk_devmem.stats[type_idx].allocations_current += 1; \
|
||||
g_vk_devmem.stats[type_idx].allocated_current += size; \
|
||||
g_vk_devmem.stats[type_idx].allocations_total += 1; \
|
||||
g_vk_devmem.stats[type_idx].allocated_total += size; \
|
||||
if ( alignment_hole > 0 ) { \
|
||||
g_vk_devmem.stats[type_idx].align_holes_current += 1; \
|
||||
g_vk_devmem.stats[type_idx].align_holes_size_current += alignment_hole; \
|
||||
g_vk_devmem.stats[type_idx].align_holes_total += 1; \
|
||||
g_vk_devmem.stats[type_idx].align_holes_size_total += alignment_hole; \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
// Register allocation in overall stats and for the corresponding type stats too.
|
||||
#define REGISTER_ALLOCATION( type, size, alignment ) \
|
||||
register_allocation_for_type( VK_DEVMEM_USAGE_TYPE_ALL, size, alignment ); \
|
||||
register_allocation_for_type( type, size, alignment );
|
||||
|
||||
// Register deallocation (freeing) in overall stats and for the corresponding type stats too.
|
||||
#define REGISTER_FREE( type, size, alignment ) \
|
||||
register_free_for_type( VK_DEVMEM_USAGE_TYPE_ALL, size, alignment ); \
|
||||
register_free_for_type( type, size, alignment );
|
||||
|
||||
// Register allocation in stats of the provided type.
|
||||
static void register_allocation_for_type( vk_devmem_usage_type_t type, int size, int alignment ) {
|
||||
ASSERT( type >= VK_DEVMEM_USAGE_TYPE_ALL );
|
||||
ASSERT( type < VK_DEVMEM_USAGE_TYPES_COUNT );
|
||||
|
||||
vk_devmem_allocation_stats_t *const stats = &g_devmem.stats[type];
|
||||
|
||||
/* Update allocations stats. */
|
||||
|
||||
// Update current allocations.
|
||||
stats->current.allocations += 1;
|
||||
stats->current.allocated += size;
|
||||
|
||||
// Update peak allocations.
|
||||
if ( stats->peak.allocations < stats->current.allocations )
|
||||
stats->peak.allocations = stats->current.allocations;
|
||||
|
||||
if ( stats->peak.allocated < stats->current.allocated )
|
||||
stats->peak.allocated = stats->current.allocated;
|
||||
|
||||
/* Update alignment holes stats. */
|
||||
|
||||
int alignment_hole = size % alignment;
|
||||
if ( alignment_hole > 0 ) {
|
||||
// Update current alignment holes stats.
|
||||
stats->current.align_holes += 1;
|
||||
stats->current.align_holes_size += alignment_hole;
|
||||
|
||||
// Update peak alignment holes stats.
|
||||
if ( stats->peak.align_holes < stats->current.align_holes )
|
||||
stats->peak.align_holes = stats->current.align_holes;
|
||||
|
||||
if ( stats->peak.align_holes_size < stats->current.align_holes_size )
|
||||
stats->peak.align_holes_size = stats->current.align_holes_size;
|
||||
|
||||
if ( stats->peak.align_hole_size < alignment_hole )
|
||||
stats->peak.align_hole_size = alignment_hole;
|
||||
}
|
||||
}
|
||||
|
||||
// Register deallocation (freeing) in overall stats and for the corresponding type too.
|
||||
// This is "scalable" approach, which can be simplified if needed.
|
||||
#define REGISTER_FREE( type, size, alignment ) \
|
||||
g_vk_devmem.stats[VK_DEVMEM_USAGE_TYPE_ALL].allocations_current -= 1; \
|
||||
g_vk_devmem.stats[VK_DEVMEM_USAGE_TYPE_ALL].allocated_current -= size; \
|
||||
g_vk_devmem.stats[VK_DEVMEM_USAGE_TYPE_ALL].frees_total += 1; \
|
||||
g_vk_devmem.stats[VK_DEVMEM_USAGE_TYPE_ALL].freed_total += size; \
|
||||
int alignment_hole = size % alignment; \
|
||||
if ( alignment_hole > 0 ) { \
|
||||
g_vk_devmem.stats[VK_DEVMEM_USAGE_TYPE_ALL].align_holes_current -= 1; \
|
||||
g_vk_devmem.stats[VK_DEVMEM_USAGE_TYPE_ALL].align_holes_size_current -= alignment_hole; \
|
||||
} \
|
||||
for ( int type_idx = VK_DEVMEM_USAGE_TYPE_ALL + 1; type_idx < VK_DEVMEM_USAGE_TYPES_COUNT; type_idx += 1 ) { \
|
||||
if ( type_idx == type ) { \
|
||||
g_vk_devmem.stats[type_idx].allocations_current -= 1; \
|
||||
g_vk_devmem.stats[type_idx].allocated_current -= size; \
|
||||
g_vk_devmem.stats[type_idx].frees_total += 1; \
|
||||
g_vk_devmem.stats[type_idx].freed_total += size; \
|
||||
break; \
|
||||
if ( alignment_hole > 0 ) { \
|
||||
g_vk_devmem.stats[type_idx].align_holes_current -= 1; \
|
||||
g_vk_devmem.stats[type_idx].align_holes_size_current -= alignment_hole; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
// Register deallocation (freeing) in stats of the provided type.
|
||||
static void register_free_for_type( vk_devmem_usage_type_t type, int size, int alignment ) {
|
||||
ASSERT( type >= VK_DEVMEM_USAGE_TYPE_ALL );
|
||||
ASSERT( type < VK_DEVMEM_USAGE_TYPES_COUNT );
|
||||
|
||||
vk_devmem_allocation_stats_t *const stats = &g_devmem.stats[type];
|
||||
|
||||
/* Update current allocations stats. */
|
||||
|
||||
stats->current.allocations -= 1;
|
||||
stats->current.allocated -= size;
|
||||
|
||||
/* Update current alignment holes stats. */
|
||||
|
||||
int alignment_hole = size % alignment;
|
||||
if ( alignment_hole > 0 ) {
|
||||
stats->current.align_holes -= 1;
|
||||
stats->current.align_holes_size -= size;
|
||||
}
|
||||
}
|
||||
|
||||
#define VKMEMPROPFLAGS_COUNT 5
|
||||
#define VKMEMPROPFLAGS_MINSTRLEN (VKMEMPROPFLAGS_COUNT + 1)
|
||||
#define VKMEMPROPFLAGS_STRLEN (VKMEMPROPFLAGS_COUNT + 1)
|
||||
|
||||
// Fills string `out_flags` with characters at each corresponding flag slot.
|
||||
// Returns number of flags set.
|
||||
static int VK_MemoryPropertyFlags_String( VkMemoryPropertyFlags flags, char *out_flags, size_t out_flags_size ) {
|
||||
ASSERT( out_flags_size >= VKMEMPROPFLAGS_MINSTRLEN );
|
||||
int set_flags = 0;
|
||||
if ( out_flags_size < VKMEMPROPFLAGS_MINSTRLEN ) {
|
||||
out_flags[0] = '\0';
|
||||
return set_flags;
|
||||
}
|
||||
|
||||
static void VK_MemoryPropertyFlags_String( VkMemoryPropertyFlags flags, char out_flags[VKMEMPROPFLAGS_STRLEN] ) {
|
||||
int flag = 0;
|
||||
if ( flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) {out_flags[flag] = 'D'; set_flags += 1;} else {out_flags[flag] = '-';} flag += 1;
|
||||
if ( flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT ) {out_flags[flag] = 'V'; set_flags += 1;} else {out_flags[flag] = '-';} flag += 1;
|
||||
if ( flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ) {out_flags[flag] = 'C'; set_flags += 1;} else {out_flags[flag] = '-';} flag += 1;
|
||||
if ( flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT ) {out_flags[flag] = '$'; set_flags += 1;} else {out_flags[flag] = '-';} flag += 1;
|
||||
if ( flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT ) {out_flags[flag] = 'L'; set_flags += 1;} else {out_flags[flag] = '-';} flag += 1;
|
||||
if ( flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) {out_flags[flag] = 'D';} else {out_flags[flag] = '-';} flag += 1;
|
||||
if ( flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT ) {out_flags[flag] = 'V';} else {out_flags[flag] = '-';} flag += 1;
|
||||
if ( flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ) {out_flags[flag] = 'C';} else {out_flags[flag] = '-';} flag += 1;
|
||||
if ( flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT ) {out_flags[flag] = '$';} else {out_flags[flag] = '-';} flag += 1;
|
||||
if ( flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT ) {out_flags[flag] = 'L';} else {out_flags[flag] = '-';} flag += 1;
|
||||
// VK_MEMORY_PROPERTY_PROTECTED_BIT
|
||||
// VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD
|
||||
// VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD
|
||||
// VK_MEMORY_PROPERTY_RDMA_CAPABLE_BIT_NV
|
||||
out_flags[flag] = '\0';
|
||||
|
||||
return set_flags;
|
||||
}
|
||||
|
||||
#define VKMEMALLOCFLAGS_COUNT 3
|
||||
#define VKMEMALLOCFLAGS_MINSTRLEN (VKMEMALLOCFLAGS_COUNT + 1)
|
||||
#define VKMEMALLOCFLAGS_STRLEN (VKMEMALLOCFLAGS_COUNT + 1)
|
||||
|
||||
// Fills string `out_flags` with characters at each corresponding flag slot.
|
||||
// Returns number of flags set.
|
||||
static int VK_MemoryAllocateFlags_String( VkMemoryAllocateFlags flags, char *out_flags, size_t out_flags_size ) {
|
||||
ASSERT( out_flags_size >= VKMEMALLOCFLAGS_MINSTRLEN );
|
||||
int set_flags = 0;
|
||||
if ( out_flags_size < VKMEMALLOCFLAGS_MINSTRLEN ) {
|
||||
out_flags[0] = '\0';
|
||||
return set_flags;
|
||||
}
|
||||
|
||||
static void VK_MemoryAllocateFlags_String( VkMemoryAllocateFlags flags, char out_flags[VKMEMALLOCFLAGS_STRLEN] ) {
|
||||
int flag = 0;
|
||||
if ( flags & VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT ) {out_flags[flag] = 'M'; set_flags += 1;} else {out_flags[flag] = '-';} flag += 1;
|
||||
if ( flags & VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT ) {out_flags[flag] = 'A'; set_flags += 1;} else {out_flags[flag] = '-';} flag += 1;
|
||||
if ( flags & VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT ) {out_flags[flag] = 'R'; set_flags += 1;} else {out_flags[flag] = '-';} flag += 1;
|
||||
if ( flags & VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT ) {out_flags[flag] = 'M';} else {out_flags[flag] = '-';} flag += 1;
|
||||
if ( flags & VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT ) {out_flags[flag] = 'A';} else {out_flags[flag] = '-';} flag += 1;
|
||||
if ( flags & VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT ) {out_flags[flag] = 'R';} else {out_flags[flag] = '-';} flag += 1;
|
||||
out_flags[flag] = '\0';
|
||||
|
||||
return set_flags;
|
||||
}
|
||||
|
||||
static int findMemoryWithType(uint32_t type_index_bits, VkMemoryPropertyFlags flags) {
|
||||
VkPhysicalDeviceMemoryProperties properties = vk_core.physical_device.memory_properties2.memoryProperties;
|
||||
for ( int type = 0; type < (int)properties.memoryTypeCount; type += 1 ) {
|
||||
const VkPhysicalDeviceMemoryProperties *const properties = &vk_core.physical_device.memory_properties2.memoryProperties;
|
||||
for ( int type = 0; type < (int)properties->memoryTypeCount; type += 1 ) {
|
||||
if ( !( type_index_bits & ( 1 << type ) ) )
|
||||
continue;
|
||||
|
||||
if ( ( properties.memoryTypes[type].propertyFlags & flags ) == flags )
|
||||
if ( ( properties->memoryTypes[type].propertyFlags & flags ) == flags )
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -184,7 +179,7 @@ static VkDeviceSize optimalSize(VkDeviceSize size) {
|
|||
}
|
||||
|
||||
static int allocateDeviceMemory(VkMemoryRequirements req, int type_index, VkMemoryAllocateFlags allocate_flags) {
|
||||
if ( g_vk_devmem.alloc_slots_count == MAX_DEVMEM_ALLOC_SLOTS ) {
|
||||
if ( g_devmem.alloc_slots_count == MAX_DEVMEM_ALLOC_SLOTS ) {
|
||||
gEngine.Host_Error( "Ran out of device memory allocation slots\n" );
|
||||
return -1;
|
||||
}
|
||||
|
@ -202,26 +197,26 @@ static int allocateDeviceMemory(VkMemoryRequirements req, int type_index, VkMemo
|
|||
.memoryTypeIndex = type_index,
|
||||
};
|
||||
|
||||
if ( g_vk_devmem.verbose ) {
|
||||
char allocate_flags_str[VKMEMALLOCFLAGS_MINSTRLEN];
|
||||
VK_MemoryAllocateFlags_String( allocate_flags, &allocate_flags_str[0], sizeof( allocate_flags_str ) );
|
||||
if ( g_devmem.verbose ) {
|
||||
char allocate_flags_str[VKMEMALLOCFLAGS_STRLEN];
|
||||
VK_MemoryAllocateFlags_String( allocate_flags, allocate_flags_str );
|
||||
unsigned long long size = (unsigned long long) mai.allocationSize;
|
||||
gEngine.Con_Reportf( " ^3->^7 ^6AllocateDeviceMemory:^7 { size: %llu, memoryTypeBits: 0x%x, allocate_flags: %s => typeIndex: %d }\n",
|
||||
size, req.memoryTypeBits, allocate_flags_str, mai.memoryTypeIndex );
|
||||
}
|
||||
ASSERT( mai.memoryTypeIndex != UINT32_MAX );
|
||||
|
||||
vk_device_memory_slot_t *slot = &g_vk_devmem.alloc_slots[g_vk_devmem.alloc_slots_count];
|
||||
vk_device_memory_slot_t *slot = &g_devmem.alloc_slots[g_devmem.alloc_slots_count];
|
||||
XVK_CHECK( vkAllocateMemory( vk_core.device, &mai, NULL, &slot->device_memory ) );
|
||||
|
||||
VkPhysicalDeviceMemoryProperties properties = vk_core.physical_device.memory_properties2.memoryProperties;
|
||||
slot->property_flags = properties.memoryTypes[mai.memoryTypeIndex].propertyFlags;
|
||||
const VkPhysicalDeviceMemoryProperties *const properties = &vk_core.physical_device.memory_properties2.memoryProperties;
|
||||
slot->property_flags = properties->memoryTypes[mai.memoryTypeIndex].propertyFlags;
|
||||
slot->allocate_flags = allocate_flags;
|
||||
slot->type_index = mai.memoryTypeIndex;
|
||||
slot->refcount = 0;
|
||||
slot->size = mai.allocationSize;
|
||||
|
||||
g_vk_devmem.device_allocated += mai.allocationSize;
|
||||
g_devmem.device_allocated += mai.allocationSize;
|
||||
|
||||
const int expected_allocations = 0;
|
||||
const int min_alignment = 16;
|
||||
|
@ -229,7 +224,7 @@ static int allocateDeviceMemory(VkMemoryRequirements req, int type_index, VkMemo
|
|||
|
||||
if ( slot->property_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT ) {
|
||||
XVK_CHECK( vkMapMemory( vk_core.device, slot->device_memory, 0, slot->size, 0, &slot->mapped ) );
|
||||
if ( g_vk_devmem.verbose ) {
|
||||
if ( g_devmem.verbose ) {
|
||||
size_t size = (size_t) slot->size;
|
||||
size_t device = (size_t) vk_core.device;
|
||||
size_t device_memory = (size_t) slot->device_memory;
|
||||
|
@ -242,7 +237,7 @@ static int allocateDeviceMemory(VkMemoryRequirements req, int type_index, VkMemo
|
|||
}
|
||||
}
|
||||
|
||||
return g_vk_devmem.alloc_slots_count++;
|
||||
return g_devmem.alloc_slots_count++;
|
||||
}
|
||||
|
||||
vk_devmem_t VK_DevMemAllocate(const char *name, vk_devmem_usage_type_t usage_type, vk_devmem_allocate_args_t devmem_allocate_args) {
|
||||
|
@ -253,11 +248,11 @@ vk_devmem_t VK_DevMemAllocate(const char *name, vk_devmem_usage_type_t usage_typ
|
|||
vk_devmem_t devmem = { .usage_type = usage_type };
|
||||
const int type_index = findMemoryWithType(req.memoryTypeBits, property_flags);
|
||||
|
||||
if ( g_vk_devmem.verbose ) {
|
||||
char property_flags_str[VKMEMPROPFLAGS_MINSTRLEN];
|
||||
char allocate_flags_str[VKMEMALLOCFLAGS_MINSTRLEN];
|
||||
VK_MemoryPropertyFlags_String( property_flags, &property_flags_str[0], sizeof( property_flags_str ) );
|
||||
VK_MemoryAllocateFlags_String( allocate_flags, &allocate_flags_str[0], sizeof( allocate_flags_str ) );
|
||||
if ( g_devmem.verbose ) {
|
||||
char property_flags_str[VKMEMPROPFLAGS_STRLEN];
|
||||
char allocate_flags_str[VKMEMALLOCFLAGS_STRLEN];
|
||||
VK_MemoryPropertyFlags_String( property_flags, property_flags_str );
|
||||
VK_MemoryAllocateFlags_String( allocate_flags, allocate_flags_str );
|
||||
|
||||
const char *usage_type_str = VK_DevMemUsageTypeString( usage_type );
|
||||
|
||||
|
@ -275,8 +270,8 @@ vk_devmem_t VK_DevMemAllocate(const char *name, vk_devmem_usage_type_t usage_typ
|
|||
|
||||
alo_block_t block;
|
||||
int slot_index = -1;
|
||||
for ( int _slot_index = 0; _slot_index < g_vk_devmem.alloc_slots_count; _slot_index += 1 ) {
|
||||
vk_device_memory_slot_t *const slot = g_vk_devmem.alloc_slots + _slot_index;
|
||||
for ( int _slot_index = 0; _slot_index < g_devmem.alloc_slots_count; _slot_index += 1 ) {
|
||||
vk_device_memory_slot_t *const slot = g_devmem.alloc_slots + _slot_index;
|
||||
if ( slot->type_index != type_index )
|
||||
continue;
|
||||
|
||||
|
@ -300,18 +295,18 @@ vk_devmem_t VK_DevMemAllocate(const char *name, vk_devmem_usage_type_t usage_typ
|
|||
if ( slot_index < 0 )
|
||||
return devmem;
|
||||
|
||||
struct alo_pool_s *allocator = g_vk_devmem.alloc_slots[slot_index].allocator;
|
||||
struct alo_pool_s *allocator = g_devmem.alloc_slots[slot_index].allocator;
|
||||
block = aloPoolAllocate( allocator, req.size, req.alignment );
|
||||
ASSERT( block.size != 0 );
|
||||
}
|
||||
|
||||
{
|
||||
vk_device_memory_slot_t *const slot = g_vk_devmem.alloc_slots + slot_index;
|
||||
vk_device_memory_slot_t *const slot = g_devmem.alloc_slots + slot_index;
|
||||
devmem.device_memory = slot->device_memory;
|
||||
devmem.offset = block.offset;
|
||||
devmem.mapped = slot->mapped ? (char *)slot->mapped + block.offset : NULL;
|
||||
|
||||
if ( g_vk_devmem.verbose ) {
|
||||
if ( g_devmem.verbose ) {
|
||||
gEngine.Con_Reportf( " ^3->^7 Allocated: { slot: %d, block: %d, offset: %d, size: %d }\n",
|
||||
slot_index, block.index, (int)block.offset, (int)block.size );
|
||||
}
|
||||
|
@ -330,13 +325,13 @@ vk_devmem_t VK_DevMemAllocate(const char *name, vk_devmem_usage_type_t usage_typ
|
|||
|
||||
void VK_DevMemFree(const vk_devmem_t *mem) {
|
||||
ASSERT( mem->_slot_index >= 0 );
|
||||
ASSERT( mem->_slot_index < g_vk_devmem.alloc_slots_count );
|
||||
ASSERT( mem->_slot_index < g_devmem.alloc_slots_count );
|
||||
|
||||
int slot_index = mem->_slot_index;
|
||||
vk_device_memory_slot_t *const slot = g_vk_devmem.alloc_slots + slot_index;
|
||||
vk_device_memory_slot_t *const slot = g_devmem.alloc_slots + slot_index;
|
||||
ASSERT( mem->device_memory == slot->device_memory );
|
||||
|
||||
if ( g_vk_devmem.verbose ) {
|
||||
if ( g_devmem.verbose ) {
|
||||
const char *usage_type = VK_DevMemUsageTypeString( mem->usage_type );
|
||||
int align_hole = mem->_block_size % mem->_block_alignment;
|
||||
gEngine.Con_Reportf( "^2VK_DevMemFree:^7 { slot: %d, block: %d, usage: %s, size: %d, alignment: %d, hole: %d }\n",
|
||||
|
@ -350,54 +345,48 @@ void VK_DevMemFree(const vk_devmem_t *mem) {
|
|||
slot->refcount--;
|
||||
}
|
||||
|
||||
// Little helper macro to turn anything into string.
|
||||
#define STRING( str ) #str
|
||||
|
||||
// Register single stats variable.
|
||||
#define REGISTER_STATS_METRIC( var, metric_name, var_name, metric_type ) \
|
||||
R_SpeedsRegisterMetric( &(var), MODULE_NAME, metric_name, metric_type, /*reset*/ false, var_name, __FILE__, __LINE__ );
|
||||
R_SpeedsRegisterMetric( &(var), MODULE_NAME, #metric_name, metric_type, /*reset*/ false, #var_name, __FILE__, __LINE__ );
|
||||
|
||||
// NOTE(nilsoncore): I know, this is a mess... Sorry.
|
||||
// It could have been avoided by having short `VK_DevMemUsageTypes` enum names,
|
||||
// but I have done it this way because I want those enum names to be as descriptive as possible.
|
||||
// This basically replaces those enum names with ones provided by suffixes, which are just their endings.
|
||||
//
|
||||
// | var | metric_name | var_name | metric_type |
|
||||
// | -------------------------------- | -------------------------------------- | ----------------------------------------------------- | ------------------ |
|
||||
#define REGISTER_STATS_METRICS( usage_type, usage_suffix ) { \
|
||||
REGISTER_STATS_METRIC( g_vk_devmem.stats[usage_type].allocations_current, STRING( allocations_current##usage_suffix ), STRING( g_vk_devmem.stats[usage_suffix].allocations_current ), kSpeedsMetricCount ); \
|
||||
REGISTER_STATS_METRIC( g_vk_devmem.stats[usage_type].allocated_current, STRING( allocated_current##usage_suffix ), STRING( g_vk_devmem.stats[usage_suffix].allocated_current ), kSpeedsMetricBytes ); \
|
||||
REGISTER_STATS_METRIC( g_vk_devmem.stats[usage_type].allocations_total, STRING( allocations_total##usage_suffix ), STRING( g_vk_devmem.stats[usage_suffix].allocations_total ), kSpeedsMetricCount ); \
|
||||
REGISTER_STATS_METRIC( g_vk_devmem.stats[usage_type].allocated_total, STRING( allocated_total##usage_suffix ), STRING( g_vk_devmem.stats[usage_suffix].allocated_total ), kSpeedsMetricBytes ); \
|
||||
REGISTER_STATS_METRIC( g_vk_devmem.stats[usage_type].frees_total, STRING( frees_total##usage_suffix ), STRING( g_vk_devmem.stats[usage_suffix].frees_total ), kSpeedsMetricCount ); \
|
||||
REGISTER_STATS_METRIC( g_vk_devmem.stats[usage_type].freed_total, STRING( freed_total##usage_suffix ), STRING( g_vk_devmem.stats[usage_suffix].freed_total ), kSpeedsMetricBytes ); \
|
||||
REGISTER_STATS_METRIC( g_vk_devmem.stats[usage_type].align_holes_current, STRING( align_holes_current##usage_suffix ), STRING( g_vk_devmem.stats[usage_suffix].align_holes_current ), kSpeedsMetricCount ); \
|
||||
REGISTER_STATS_METRIC( g_vk_devmem.stats[usage_type].align_holes_size_current, STRING( align_holes_size_current##usage_suffix ), STRING( g_vk_devmem.stats[usage_suffix].align_holes_size_current ), kSpeedsMetricBytes ); \
|
||||
REGISTER_STATS_METRIC( g_vk_devmem.stats[usage_type].align_holes_total, STRING( align_holes_total##usage_suffix ), STRING( g_vk_devmem.stats[usage_suffix].align_holes_total ), kSpeedsMetricCount ); \
|
||||
REGISTER_STATS_METRIC( g_vk_devmem.stats[usage_type].align_holes_size_total, STRING( align_holes_size_total##usage_suffix ), STRING( g_vk_devmem.stats[usage_suffix].align_holes_size_total ), kSpeedsMetricBytes ); \
|
||||
vk_devmem_allocation_stats_t *const stats = &g_devmem.stats[usage_type]; \
|
||||
REGISTER_STATS_METRIC( stats->current.allocations, current_allocations##usage_suffix, g_devmem.stats[usage_suffix].current.allocations, kSpeedsMetricCount ); \
|
||||
REGISTER_STATS_METRIC( stats->current.allocated, current_allocated##usage_suffix, g_devmem.stats[usage_suffix].current.allocated, kSpeedsMetricBytes ); \
|
||||
REGISTER_STATS_METRIC( stats->current.align_holes, current_align_holes##usage_suffix, g_devmem.stats[usage_suffix].current.align_holes, kSpeedsMetricCount ); \
|
||||
REGISTER_STATS_METRIC( stats->current.align_holes_size, current_align_holes_size##usage_suffix, g_devmem.stats[usage_suffix].current.align_holes_size, kSpeedsMetricBytes ); \
|
||||
REGISTER_STATS_METRIC( stats->peak.allocations, peak_allocations##usage_suffix, g_devmem.stats[usage_suffix].peak.allocations, kSpeedsMetricCount ); \
|
||||
REGISTER_STATS_METRIC( stats->peak.allocated, peak_allocated##usage_suffix, g_devmem.stats[usage_suffix].peak.allocated, kSpeedsMetricBytes ); \
|
||||
REGISTER_STATS_METRIC( stats->peak.align_holes, peak_align_holes##usage_suffix, g_devmem.stats[usage_suffix].peak.align_holes, kSpeedsMetricCount ); \
|
||||
REGISTER_STATS_METRIC( stats->peak.align_holes_size, peak_align_holes_size##usage_suffix, g_devmem.stats[usage_suffix].peak.align_holes_size, kSpeedsMetricBytes ); \
|
||||
REGISTER_STATS_METRIC( stats->peak.align_hole_size, peak_align_hole_size##usage_suffix, g_devmem.stats[usage_suffix].peak.align_hole_size, kSpeedsMetricBytes ); \
|
||||
}
|
||||
|
||||
qboolean VK_DevMemInit( void ) {
|
||||
g_vk_devmem.verbose = gEngine.Sys_CheckParm( "-vkdebugmem" );
|
||||
g_devmem.verbose = gEngine.Sys_CheckParm( "-vkdebugmem" );
|
||||
|
||||
// Register standalone metrics.
|
||||
R_SPEEDS_METRIC( g_vk_devmem.alloc_slots_count, "allocated_slots", kSpeedsMetricCount );
|
||||
R_SPEEDS_METRIC( g_vk_devmem.device_allocated, "device_allocated", kSpeedsMetricBytes );
|
||||
R_SPEEDS_METRIC( g_devmem.alloc_slots_count, "allocated_slots", kSpeedsMetricCount );
|
||||
R_SPEEDS_METRIC( g_devmem.device_allocated, "device_allocated", kSpeedsMetricBytes );
|
||||
|
||||
// Register stats metrics for each usage type.
|
||||
// Maybe these metrics should be enabled only with `-vkdebugmem`?
|
||||
REGISTER_STATS_METRICS( VK_DEVMEM_USAGE_TYPE_ALL, _ALL );
|
||||
REGISTER_STATS_METRICS( VK_DEVMEM_USAGE_TYPE_ALL, _ALL );
|
||||
REGISTER_STATS_METRICS( VK_DEVMEM_USAGE_TYPE_BUFFER, _BUFFER );
|
||||
REGISTER_STATS_METRICS( VK_DEVMEM_USAGE_TYPE_IMAGE, _IMAGE );
|
||||
REGISTER_STATS_METRICS( VK_DEVMEM_USAGE_TYPE_IMAGE, _IMAGE );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOTE(nilsoncore):
|
||||
// It has to be undefined only after `VK_DevMemInit` because
|
||||
// otherwise the function would not know what this is.
|
||||
#undef STRING
|
||||
|
||||
void VK_DevMemDestroy( void ) {
|
||||
for ( int slot_index = 0; slot_index < g_vk_devmem.alloc_slots_count; slot_index += 1 ) {
|
||||
const vk_device_memory_slot_t *const slot = g_vk_devmem.alloc_slots + slot_index;
|
||||
for ( int slot_index = 0; slot_index < g_devmem.alloc_slots_count; slot_index += 1 ) {
|
||||
const vk_device_memory_slot_t *const slot = g_devmem.alloc_slots + slot_index;
|
||||
ASSERT( slot->refcount == 0 );
|
||||
|
||||
// TODO check that everything has been freed
|
||||
|
@ -409,7 +398,7 @@ void VK_DevMemDestroy( void ) {
|
|||
vkFreeMemory( vk_core.device, slot->device_memory, NULL );
|
||||
}
|
||||
|
||||
g_vk_devmem.alloc_slots_count = 0;
|
||||
g_devmem.alloc_slots_count = 0;
|
||||
}
|
||||
|
||||
const char *VK_DevMemUsageTypeString( vk_devmem_usage_type_t type ) {
|
||||
|
|
|
@ -45,10 +45,9 @@ xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create) {
|
|||
|
||||
vkGetImageMemoryRequirements(vk_core.device, image.image, &memreq);
|
||||
|
||||
VkMemoryPropertyFlags memory_props = (create->memory_props) ? create->memory_props : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
vk_devmem_allocate_args_t args = (vk_devmem_allocate_args_t) {
|
||||
.requirements = memreq,
|
||||
.property_flags = memory_props,
|
||||
.property_flags = (create->memory_props) ? create->memory_props : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
.allocate_flags = 0,
|
||||
};
|
||||
image.devmem = VK_DevMemAllocateImage( create->debug_name, args );
|
||||
|
|
Loading…
Reference in New Issue