Fixed synchronization issue in TestPool_Benchmark

Variable res was incorrectly shared between threads.
This commit is contained in:
Adam Sawicki 2021-03-02 15:11:18 +01:00
parent e74dc79903
commit 41b411124e
3 changed files with 142 additions and 52 deletions

View File

@ -532,7 +532,7 @@ SparseBindingImage::~SparseBindingImage()
void TestSparseBinding() void TestSparseBinding()
{ {
wprintf(L"TESTING SPARSE BINDING:"); wprintf(L"TESTING SPARSE BINDING:\n");
struct ImageInfo struct ImageInfo
{ {

View File

@ -39,6 +39,7 @@ extern bool VK_EXT_memory_priority_enabled;
extern PFN_vkGetBufferDeviceAddressEXT g_vkGetBufferDeviceAddressEXT; extern PFN_vkGetBufferDeviceAddressEXT g_vkGetBufferDeviceAddressEXT;
void BeginSingleTimeCommands(); void BeginSingleTimeCommands();
void EndSingleTimeCommands(); void EndSingleTimeCommands();
void SetDebugUtilsObjectName(VkObjectType type, uint64_t handle, const char* name);
#ifndef VMA_DEBUG_MARGIN #ifndef VMA_DEBUG_MARGIN
#define VMA_DEBUG_MARGIN 0 #define VMA_DEBUG_MARGIN 0
@ -4347,27 +4348,27 @@ static void TestPool_Benchmark(
return sum + allocSize.Probability; return sum + allocSize.Probability;
}); });
VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; VkBufferCreateInfo bufferTemplateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
bufferInfo.size = 256; // Whatever. bufferTemplateInfo.size = 256; // Whatever.
bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; bufferTemplateInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; VkImageCreateInfo imageTemplateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
imageInfo.imageType = VK_IMAGE_TYPE_2D; imageTemplateInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent.width = 256; // Whatever. imageTemplateInfo.extent.width = 256; // Whatever.
imageInfo.extent.height = 256; // Whatever. imageTemplateInfo.extent.height = 256; // Whatever.
imageInfo.extent.depth = 1; imageTemplateInfo.extent.depth = 1;
imageInfo.mipLevels = 1; imageTemplateInfo.mipLevels = 1;
imageInfo.arrayLayers = 1; imageTemplateInfo.arrayLayers = 1;
imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM; imageTemplateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; // LINEAR if CPU memory. imageTemplateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; // LINEAR if CPU memory.
imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; imageTemplateInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; // TRANSFER_SRC if CPU memory. imageTemplateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; // TRANSFER_SRC if CPU memory.
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageTemplateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
uint32_t bufferMemoryTypeBits = UINT32_MAX; uint32_t bufferMemoryTypeBits = UINT32_MAX;
{ {
VkBuffer dummyBuffer; VkBuffer dummyBuffer;
VkResult res = vkCreateBuffer(g_hDevice, &bufferInfo, g_Allocs, &dummyBuffer); VkResult res = vkCreateBuffer(g_hDevice, &bufferTemplateInfo, g_Allocs, &dummyBuffer);
TEST(res == VK_SUCCESS); TEST(res == VK_SUCCESS);
VkMemoryRequirements memReq; VkMemoryRequirements memReq;
@ -4380,7 +4381,7 @@ static void TestPool_Benchmark(
uint32_t imageMemoryTypeBits = UINT32_MAX; uint32_t imageMemoryTypeBits = UINT32_MAX;
{ {
VkImage dummyImage; VkImage dummyImage;
VkResult res = vkCreateImage(g_hDevice, &imageInfo, g_Allocs, &dummyImage); VkResult res = vkCreateImage(g_hDevice, &imageTemplateInfo, g_Allocs, &dummyImage);
TEST(res == VK_SUCCESS); TEST(res == VK_SUCCESS);
VkMemoryRequirements memReq; VkMemoryRequirements memReq;
@ -4444,13 +4445,31 @@ static void TestPool_Benchmark(
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// ThreadProc // ThreadProc
auto ThreadProc = [&]( auto ThreadProc = [&config, allocationSizeProbabilitySum, pool](
PoolTestThreadResult* outThreadResult, PoolTestThreadResult* outThreadResult,
uint32_t randSeed, uint32_t randSeed,
HANDLE frameStartEvent, HANDLE frameStartEvent,
HANDLE frameEndEvent) -> void HANDLE frameEndEvent) -> void
{ {
RandomNumberGenerator threadRand{randSeed}; RandomNumberGenerator threadRand{randSeed};
VkResult res = VK_SUCCESS;
VkBufferCreateInfo bufferInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
bufferInfo.size = 256; // Whatever.
bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent.width = 256; // Whatever.
imageInfo.extent.height = 256; // Whatever.
imageInfo.extent.depth = 1;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; // LINEAR if CPU memory.
imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; // TRANSFER_SRC if CPU memory.
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
outThreadResult->AllocationTimeMin = duration::max(); outThreadResult->AllocationTimeMin = duration::max();
outThreadResult->AllocationTimeSum = duration::zero(); outThreadResult->AllocationTimeSum = duration::zero();
@ -4467,16 +4486,62 @@ static void TestPool_Benchmark(
struct Item struct Item
{ {
VkDeviceSize BufferSize; VkDeviceSize BufferSize = 0;
VkExtent2D ImageSize; VkExtent2D ImageSize = { 0, 0 };
VkBuffer Buf; VkBuffer Buf = VK_NULL_HANDLE;
VkImage Image; VkImage Image = VK_NULL_HANDLE;
VmaAllocation Alloc; VmaAllocation Alloc = VK_NULL_HANDLE;
Item() { }
Item(Item&& src) :
BufferSize(src.BufferSize), ImageSize(src.ImageSize), Buf(src.Buf), Image(src.Image), Alloc(src.Alloc)
{
src.BufferSize = 0;
src.ImageSize = {0, 0};
src.Buf = VK_NULL_HANDLE;
src.Image = VK_NULL_HANDLE;
src.Alloc = VK_NULL_HANDLE;
}
Item(const Item& src) = delete;
~Item()
{
DestroyResources();
}
Item& operator=(Item&& src)
{
if(&src != this)
{
DestroyResources();
BufferSize = src.BufferSize; ImageSize = src.ImageSize;
Buf = src.Buf; Image = src.Image; Alloc = src.Alloc;
src.BufferSize = 0;
src.ImageSize = {0, 0};
src.Buf = VK_NULL_HANDLE;
src.Image = VK_NULL_HANDLE;
src.Alloc = VK_NULL_HANDLE;
}
return *this;
}
Item& operator=(const Item& src) = delete;
void DestroyResources()
{
if(Buf)
{
assert(Image == VK_NULL_HANDLE);
vmaDestroyBuffer(g_hAllocator, Buf, Alloc);
Buf = VK_NULL_HANDLE;
}
else
{
vmaDestroyImage(g_hAllocator, Image, Alloc);
Image = VK_NULL_HANDLE;
}
Alloc = VK_NULL_HANDLE;
}
VkDeviceSize CalcSizeBytes() const VkDeviceSize CalcSizeBytes() const
{ {
return BufferSize + return BufferSize +
ImageSize.width * ImageSize.height * 4; 4ull * ImageSize.width * ImageSize.height;
} }
}; };
std::vector<Item> unusedItems, usedItems; std::vector<Item> unusedItems, usedItems;
@ -4518,11 +4583,13 @@ static void TestPool_Benchmark(
} }
} }
unusedItems.push_back(item); unusedItems.push_back(std::move(item));
} }
auto Allocate = [&](Item& item) -> VkResult auto Allocate = [&](Item& item) -> VkResult
{ {
assert(item.Buf == VK_NULL_HANDLE && item.Image == VK_NULL_HANDLE && item.Alloc == VK_NULL_HANDLE);
VmaAllocationCreateInfo allocCreateInfo = {}; VmaAllocationCreateInfo allocCreateInfo = {};
allocCreateInfo.pool = pool; allocCreateInfo.pool = pool;
allocCreateInfo.flags = VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT | allocCreateInfo.flags = VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT |
@ -4531,8 +4598,14 @@ static void TestPool_Benchmark(
if(item.BufferSize) if(item.BufferSize)
{ {
bufferInfo.size = item.BufferSize; bufferInfo.size = item.BufferSize;
PoolAllocationTimeRegisterObj timeRegisterObj(*outThreadResult); VkResult res = VK_SUCCESS;
return vmaCreateBuffer(g_hAllocator, &bufferInfo, &allocCreateInfo, &item.Buf, &item.Alloc, nullptr); {
PoolAllocationTimeRegisterObj timeRegisterObj(*outThreadResult);
res = vmaCreateBuffer(g_hAllocator, &bufferInfo, &allocCreateInfo, &item.Buf, &item.Alloc, nullptr);
}
if(res == VK_SUCCESS)
SetDebugUtilsObjectName(VK_OBJECT_TYPE_BUFFER, (uint64_t)item.Buf, "TestPool_Benchmark_Buffer");
return res;
} }
else else
{ {
@ -4540,8 +4613,14 @@ static void TestPool_Benchmark(
imageInfo.extent.width = item.ImageSize.width; imageInfo.extent.width = item.ImageSize.width;
imageInfo.extent.height = item.ImageSize.height; imageInfo.extent.height = item.ImageSize.height;
PoolAllocationTimeRegisterObj timeRegisterObj(*outThreadResult); VkResult res = VK_SUCCESS;
return vmaCreateImage(g_hAllocator, &imageInfo, &allocCreateInfo, &item.Image, &item.Alloc, nullptr); {
PoolAllocationTimeRegisterObj timeRegisterObj(*outThreadResult);
res = vmaCreateImage(g_hAllocator, &imageInfo, &allocCreateInfo, &item.Image, &item.Alloc, nullptr);
}
if(res == VK_SUCCESS)
SetDebugUtilsObjectName(VK_OBJECT_TYPE_IMAGE, (uint64_t)item.Image, "TestPool_Benchmark_Image");
return res;
} }
}; };
@ -4556,8 +4635,10 @@ static void TestPool_Benchmark(
for(size_t i = 0; i < bufsToMakeUnused; ++i) for(size_t i = 0; i < bufsToMakeUnused; ++i)
{ {
size_t index = threadRand.Generate() % usedItems.size(); size_t index = threadRand.Generate() % usedItems.size();
unusedItems.push_back(usedItems[index]); auto it = usedItems.begin() + index;
usedItems.erase(usedItems.begin() + index); Item item = std::move(*it);
usedItems.erase(it);
unusedItems.push_back(std::move(item));
} }
// Determine which bufs we want to use in this frame. // Determine which bufs we want to use in this frame.
@ -4568,15 +4649,19 @@ static void TestPool_Benchmark(
while(usedBufCount < usedItems.size()) while(usedBufCount < usedItems.size())
{ {
size_t index = threadRand.Generate() % usedItems.size(); size_t index = threadRand.Generate() % usedItems.size();
unusedItems.push_back(usedItems[index]); auto it = usedItems.begin() + index;
usedItems.erase(usedItems.begin() + index); Item item = std::move(*it);
usedItems.erase(it);
unusedItems.push_back(std::move(item));
} }
// Move some unused to used. // Move some unused to used.
while(usedBufCount > usedItems.size()) while(usedBufCount > usedItems.size())
{ {
size_t index = threadRand.Generate() % unusedItems.size(); size_t index = threadRand.Generate() % unusedItems.size();
usedItems.push_back(unusedItems[index]); auto it = unusedItems.begin() + index;
unusedItems.erase(unusedItems.begin() + index); Item item = std::move(*it);
unusedItems.erase(it);
usedItems.push_back(std::move(item));
} }
uint32_t touchExistingCount = 0; uint32_t touchExistingCount = 0;
@ -4595,8 +4680,7 @@ static void TestPool_Benchmark(
++outThreadResult->AllocationCount; ++outThreadResult->AllocationCount;
if(res != VK_SUCCESS) if(res != VK_SUCCESS)
{ {
item.Alloc = VK_NULL_HANDLE; assert(item.Alloc == VK_NULL_HANDLE && item.Buf == VK_NULL_HANDLE && item.Image == VK_NULL_HANDLE);
item.Buf = VK_NULL_HANDLE;
++outThreadResult->FailedAllocationCount; ++outThreadResult->FailedAllocationCount;
outThreadResult->FailedAllocationTotalSize += item.CalcSizeBytes(); outThreadResult->FailedAllocationTotalSize += item.CalcSizeBytes();
++createFailedCount; ++createFailedCount;
@ -4617,14 +4701,9 @@ static void TestPool_Benchmark(
// Destroy. // Destroy.
{ {
PoolDeallocationTimeRegisterObj timeRegisterObj(*outThreadResult); PoolDeallocationTimeRegisterObj timeRegisterObj(*outThreadResult);
if(item.Buf) item.DestroyResources();
vmaDestroyBuffer(g_hAllocator, item.Buf, item.Alloc);
else
vmaDestroyImage(g_hAllocator, item.Image, item.Alloc);
++outThreadResult->DeallocationCount; ++outThreadResult->DeallocationCount;
} }
item.Alloc = VK_NULL_HANDLE;
item.Buf = VK_NULL_HANDLE;
++outThreadResult->LostAllocationCount; ++outThreadResult->LostAllocationCount;
outThreadResult->LostAllocationTotalSize += item.CalcSizeBytes(); outThreadResult->LostAllocationTotalSize += item.CalcSizeBytes();
@ -4635,6 +4714,7 @@ static void TestPool_Benchmark(
// Creation failed. // Creation failed.
if(res != VK_SUCCESS) if(res != VK_SUCCESS)
{ {
TEST(item.Alloc == VK_NULL_HANDLE && item.Buf == VK_NULL_HANDLE && item.Image == VK_NULL_HANDLE);
++outThreadResult->FailedAllocationCount; ++outThreadResult->FailedAllocationCount;
outThreadResult->FailedAllocationTotalSize += item.CalcSizeBytes(); outThreadResult->FailedAllocationTotalSize += item.CalcSizeBytes();
++createFailedCount; ++createFailedCount;
@ -4661,19 +4741,13 @@ static void TestPool_Benchmark(
for(size_t i = usedItems.size(); i--; ) for(size_t i = usedItems.size(); i--; )
{ {
PoolDeallocationTimeRegisterObj timeRegisterObj(*outThreadResult); PoolDeallocationTimeRegisterObj timeRegisterObj(*outThreadResult);
if(usedItems[i].Buf) usedItems[i].DestroyResources();
vmaDestroyBuffer(g_hAllocator, usedItems[i].Buf, usedItems[i].Alloc);
else
vmaDestroyImage(g_hAllocator, usedItems[i].Image, usedItems[i].Alloc);
++outThreadResult->DeallocationCount; ++outThreadResult->DeallocationCount;
} }
for(size_t i = unusedItems.size(); i--; ) for(size_t i = unusedItems.size(); i--; )
{ {
PoolDeallocationTimeRegisterObj timeRegisterOb(*outThreadResult); PoolDeallocationTimeRegisterObj timeRegisterOb(*outThreadResult);
if(unusedItems[i].Buf) unusedItems[i].DestroyResources();
vmaDestroyBuffer(g_hAllocator, unusedItems[i].Buf, unusedItems[i].Alloc);
else
vmaDestroyImage(g_hAllocator, unusedItems[i].Image, unusedItems[i].Alloc);
++outThreadResult->DeallocationCount; ++outThreadResult->DeallocationCount;
} }
}; };

View File

@ -107,6 +107,7 @@ static const VkDebugUtilsMessageTypeFlagsEXT DEBUG_UTILS_MESSENGER_MESSAGE_TYPE
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
static PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT_Func; static PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT_Func;
static PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT_Func; static PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT_Func;
static PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT_Func;
static VkDebugUtilsMessengerEXT g_DebugUtilsMessenger; static VkDebugUtilsMessengerEXT g_DebugUtilsMessenger;
static VkQueue g_hGraphicsQueue; static VkQueue g_hGraphicsQueue;
@ -180,6 +181,18 @@ static const VkAllocationCallbacks g_CpuAllocationCallbacks = {
const VkAllocationCallbacks* g_Allocs; const VkAllocationCallbacks* g_Allocs;
void SetDebugUtilsObjectName(VkObjectType type, uint64_t handle, const char* name)
{
if(vkSetDebugUtilsObjectNameEXT_Func == nullptr)
return;
VkDebugUtilsObjectNameInfoEXT info = { VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT };
info.objectType = type;
info.objectHandle = handle;
info.pObjectName = name;
vkSetDebugUtilsObjectNameEXT_Func(g_hDevice, &info);
}
void BeginSingleTimeCommands() void BeginSingleTimeCommands()
{ {
VkCommandBufferBeginInfo cmdBufBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; VkCommandBufferBeginInfo cmdBufBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
@ -570,8 +583,11 @@ static void RegisterDebugCallbacks()
g_hVulkanInstance, "vkCreateDebugUtilsMessengerEXT"); g_hVulkanInstance, "vkCreateDebugUtilsMessengerEXT");
vkDestroyDebugUtilsMessengerEXT_Func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr( vkDestroyDebugUtilsMessengerEXT_Func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
g_hVulkanInstance, "vkDestroyDebugUtilsMessengerEXT"); g_hVulkanInstance, "vkDestroyDebugUtilsMessengerEXT");
vkSetDebugUtilsObjectNameEXT_Func = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(
g_hVulkanInstance, "vkSetDebugUtilsObjectNameEXT");
assert(vkCreateDebugUtilsMessengerEXT_Func); assert(vkCreateDebugUtilsMessengerEXT_Func);
assert(vkDestroyDebugUtilsMessengerEXT_Func); assert(vkDestroyDebugUtilsMessengerEXT_Func);
assert(vkSetDebugUtilsObjectNameEXT_Func);
VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = { VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT }; VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = { VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT };
messengerCreateInfo.messageSeverity = DEBUG_UTILS_MESSENGER_MESSAGE_SEVERITY; messengerCreateInfo.messageSeverity = DEBUG_UTILS_MESSENGER_MESSAGE_SEVERITY;