|
7 | 7 |
|
8 | 8 | #ifdef _WIN32 |
9 | 9 |
|
| 10 | +enum CONFIG_TYPE { |
| 11 | + CONFIG_TYPE_MINIMUM, |
| 12 | + CONFIG_TYPE_SMALL, |
| 13 | + CONFIG_TYPE_AVERAGE, |
| 14 | + CONFIG_TYPE_LARGE, |
| 15 | + CONFIG_TYPE_MAXIMUM, |
| 16 | + CONFIG_TYPE_COUNT |
| 17 | +}; |
| 18 | + |
| 19 | +static constexpr CONFIG_TYPE ConfigType = CONFIG_TYPE_SMALL; |
| 20 | +//static constexpr CONFIG_TYPE ConfigType = CONFIG_TYPE_LARGE; |
| 21 | + |
10 | 22 | enum class FREE_ORDER { FORWARD, BACKWARD, RANDOM, COUNT }; |
11 | 23 |
|
| 24 | +static const wchar_t* FREE_ORDER_NAMES[] = { |
| 25 | + L"FORWARD", |
| 26 | + L"BACKWARD", |
| 27 | + L"RANDOM", |
| 28 | +}; |
| 29 | + |
12 | 30 | struct AllocationSize |
13 | 31 | { |
14 | 32 | uint32_t Probability; |
@@ -1948,6 +1966,169 @@ static void ManuallyTestLinearAllocator() |
1948 | 1966 | vmaDestroyPool(g_hAllocator, pool); |
1949 | 1967 | } |
1950 | 1968 |
|
| 1969 | +static void BenchmarkLinearAllocatorCase(bool linear, bool empty, FREE_ORDER freeOrder) |
| 1970 | +{ |
| 1971 | + RandomNumberGenerator rand{16223}; |
| 1972 | + |
| 1973 | + const VkDeviceSize bufSizeMin = 32; |
| 1974 | + const VkDeviceSize bufSizeMax = 1024; |
| 1975 | + const size_t maxBufCapacity = 10000; |
| 1976 | + const uint32_t iterationCount = 10; |
| 1977 | + |
| 1978 | + VkBufferCreateInfo sampleBufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; |
| 1979 | + sampleBufCreateInfo.size = bufSizeMax; |
| 1980 | + sampleBufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; |
| 1981 | + |
| 1982 | + VmaAllocationCreateInfo sampleAllocCreateInfo = {}; |
| 1983 | + sampleAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; |
| 1984 | + |
| 1985 | + VmaPoolCreateInfo poolCreateInfo = {}; |
| 1986 | + VkResult res = vmaFindMemoryTypeIndexForBufferInfo(g_hAllocator, &sampleBufCreateInfo, &sampleAllocCreateInfo, &poolCreateInfo.memoryTypeIndex); |
| 1987 | + assert(res == VK_SUCCESS); |
| 1988 | + |
| 1989 | + poolCreateInfo.blockSize = bufSizeMax * maxBufCapacity; |
| 1990 | + if(linear) |
| 1991 | + poolCreateInfo.flags = VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT; |
| 1992 | + poolCreateInfo.minBlockCount = poolCreateInfo.maxBlockCount = 1; |
| 1993 | + |
| 1994 | + VmaPool pool = nullptr; |
| 1995 | + res = vmaCreatePool(g_hAllocator, &poolCreateInfo, &pool); |
| 1996 | + assert(res == VK_SUCCESS); |
| 1997 | + |
| 1998 | + // Buffer created just to get memory requirements. Never bound to any memory. |
| 1999 | + VkBuffer dummyBuffer = VK_NULL_HANDLE; |
| 2000 | + res = vkCreateBuffer(g_hDevice, &sampleBufCreateInfo, nullptr, &dummyBuffer); |
| 2001 | + assert(res == VK_SUCCESS && dummyBuffer); |
| 2002 | + |
| 2003 | + VkMemoryRequirements memReq = {}; |
| 2004 | + vkGetBufferMemoryRequirements(g_hDevice, dummyBuffer, &memReq); |
| 2005 | + |
| 2006 | + vkDestroyBuffer(g_hDevice, dummyBuffer, nullptr); |
| 2007 | + |
| 2008 | + VmaAllocationCreateInfo allocCreateInfo = {}; |
| 2009 | + allocCreateInfo.pool = pool; |
| 2010 | + |
| 2011 | + VmaAllocation alloc; |
| 2012 | + std::vector<VmaAllocation> baseAllocations; |
| 2013 | + |
| 2014 | + if(!empty) |
| 2015 | + { |
| 2016 | + // Make allocations up to half of pool size. |
| 2017 | + VkDeviceSize totalSize = 0; |
| 2018 | + while(totalSize < poolCreateInfo.blockSize / 2) |
| 2019 | + { |
| 2020 | + memReq.size = bufSizeMin + rand.Generate() % (bufSizeMax - bufSizeMin); |
| 2021 | + res = vmaAllocateMemory(g_hAllocator, &memReq, &allocCreateInfo, &alloc, nullptr); |
| 2022 | + assert(res == VK_SUCCESS); |
| 2023 | + baseAllocations.push_back(alloc); |
| 2024 | + totalSize += memReq.size; |
| 2025 | + } |
| 2026 | + |
| 2027 | + // Delete half of them, choose randomly. |
| 2028 | + size_t allocsToDelete = baseAllocations.size() / 2; |
| 2029 | + for(size_t i = 0; i < allocsToDelete; ++i) |
| 2030 | + { |
| 2031 | + const size_t index = (size_t)rand.Generate() % baseAllocations.size(); |
| 2032 | + vmaFreeMemory(g_hAllocator, baseAllocations[index]); |
| 2033 | + baseAllocations.erase(baseAllocations.begin() + index); |
| 2034 | + } |
| 2035 | + } |
| 2036 | + |
| 2037 | + // BENCHMARK |
| 2038 | + const size_t allocCount = maxBufCapacity / 2; |
| 2039 | + std::vector<VmaAllocation> testAllocations; |
| 2040 | + testAllocations.reserve(allocCount); |
| 2041 | + duration allocTotalDuration = duration::zero(); |
| 2042 | + duration freeTotalDuration = duration::zero(); |
| 2043 | + for(uint32_t iterationIndex = 0; iterationIndex < iterationCount; ++iterationIndex) |
| 2044 | + { |
| 2045 | + // Allocations |
| 2046 | + time_point allocTimeBeg = std::chrono::high_resolution_clock::now(); |
| 2047 | + for(size_t i = 0; i < allocCount; ++i) |
| 2048 | + { |
| 2049 | + memReq.size = bufSizeMin + rand.Generate() % (bufSizeMax - bufSizeMin); |
| 2050 | + res = vmaAllocateMemory(g_hAllocator, &memReq, &allocCreateInfo, &alloc, nullptr); |
| 2051 | + assert(res == VK_SUCCESS); |
| 2052 | + testAllocations.push_back(alloc); |
| 2053 | + } |
| 2054 | + allocTotalDuration += std::chrono::high_resolution_clock::now() - allocTimeBeg; |
| 2055 | + |
| 2056 | + // Deallocations |
| 2057 | + switch(freeOrder) |
| 2058 | + { |
| 2059 | + case FREE_ORDER::FORWARD: |
| 2060 | + // Leave testAllocations unchanged. |
| 2061 | + break; |
| 2062 | + case FREE_ORDER::BACKWARD: |
| 2063 | + std::reverse(testAllocations.begin(), testAllocations.end()); |
| 2064 | + break; |
| 2065 | + case FREE_ORDER::RANDOM: |
| 2066 | + std::shuffle(testAllocations.begin(), testAllocations.end(), MyUniformRandomNumberGenerator(rand)); |
| 2067 | + break; |
| 2068 | + default: assert(0); |
| 2069 | + } |
| 2070 | + |
| 2071 | + time_point freeTimeBeg = std::chrono::high_resolution_clock::now(); |
| 2072 | + for(size_t i = 0; i < allocCount; ++i) |
| 2073 | + vmaFreeMemory(g_hAllocator, testAllocations[i]); |
| 2074 | + freeTotalDuration += std::chrono::high_resolution_clock::now() - freeTimeBeg; |
| 2075 | + |
| 2076 | + testAllocations.clear(); |
| 2077 | + } |
| 2078 | + |
| 2079 | + // Delete baseAllocations |
| 2080 | + while(!baseAllocations.empty()) |
| 2081 | + { |
| 2082 | + vmaFreeMemory(g_hAllocator, baseAllocations.back()); |
| 2083 | + baseAllocations.pop_back(); |
| 2084 | + } |
| 2085 | + |
| 2086 | + vmaDestroyPool(g_hAllocator, pool); |
| 2087 | + |
| 2088 | + wprintf(L" LinearAlgorithm=%u %s FreeOrder=%s: allocations %g s, free %g s\n", |
| 2089 | + linear ? 1 : 0, |
| 2090 | + empty ? L"Empty" : L"Not empty", |
| 2091 | + FREE_ORDER_NAMES[(size_t)freeOrder], |
| 2092 | + ToFloatSeconds(allocTotalDuration), |
| 2093 | + ToFloatSeconds(freeTotalDuration)); |
| 2094 | +} |
| 2095 | + |
| 2096 | +static void BenchmarkLinearAllocator() |
| 2097 | +{ |
| 2098 | + wprintf(L"Benchmark linear allocator\n"); |
| 2099 | + |
| 2100 | + uint32_t freeOrderCount = 1; |
| 2101 | + if(ConfigType >= CONFIG_TYPE::CONFIG_TYPE_LARGE) |
| 2102 | + freeOrderCount = 3; |
| 2103 | + else if(ConfigType >= CONFIG_TYPE::CONFIG_TYPE_SMALL) |
| 2104 | + freeOrderCount = 2; |
| 2105 | + |
| 2106 | + const uint32_t emptyCount = ConfigType >= CONFIG_TYPE::CONFIG_TYPE_SMALL ? 2 : 1; |
| 2107 | + |
| 2108 | + for(uint32_t freeOrderIndex = 0; freeOrderIndex < freeOrderCount; ++freeOrderIndex) |
| 2109 | + { |
| 2110 | + FREE_ORDER freeOrder = FREE_ORDER::COUNT; |
| 2111 | + switch(freeOrderIndex) |
| 2112 | + { |
| 2113 | + case 0: freeOrder = FREE_ORDER::BACKWARD; break; |
| 2114 | + case 1: freeOrder = FREE_ORDER::FORWARD; break; |
| 2115 | + case 2: freeOrder = FREE_ORDER::RANDOM; break; |
| 2116 | + default: assert(0); |
| 2117 | + } |
| 2118 | + |
| 2119 | + for(uint32_t emptyIndex = 0; emptyIndex < emptyCount; ++emptyIndex) |
| 2120 | + { |
| 2121 | + for(uint32_t linearIndex = 0; linearIndex < 2; ++linearIndex) |
| 2122 | + { |
| 2123 | + BenchmarkLinearAllocatorCase( |
| 2124 | + linearIndex ? 1 : 0, // linear |
| 2125 | + emptyIndex ? 0 : 1, // empty |
| 2126 | + freeOrder); // freeOrder |
| 2127 | + } |
| 2128 | + } |
| 2129 | + } |
| 2130 | +} |
| 2131 | + |
1951 | 2132 | static void TestPool_SameSize() |
1952 | 2133 | { |
1953 | 2134 | const VkDeviceSize BUF_SIZE = 1024 * 1024; |
@@ -3194,17 +3375,6 @@ static void PerformCustomPoolTest(FILE* file) |
3194 | 3375 | WritePoolTestResult(file, "Code desc", "Test desc", config, result); |
3195 | 3376 | } |
3196 | 3377 |
|
3197 | | -enum CONFIG_TYPE { |
3198 | | - CONFIG_TYPE_MINIMUM, |
3199 | | - CONFIG_TYPE_SMALL, |
3200 | | - CONFIG_TYPE_AVERAGE, |
3201 | | - CONFIG_TYPE_LARGE, |
3202 | | - CONFIG_TYPE_MAXIMUM, |
3203 | | - CONFIG_TYPE_COUNT |
3204 | | -}; |
3205 | | - |
3206 | | -static constexpr CONFIG_TYPE ConfigType = CONFIG_TYPE_SMALL; |
3207 | | -//static constexpr CONFIG_TYPE ConfigType = CONFIG_TYPE_LARGE; |
3208 | 3378 | static const char* CODE_DESCRIPTION = "Foo"; |
3209 | 3379 |
|
3210 | 3380 | static void PerformMainTests(FILE* file) |
@@ -3687,6 +3857,7 @@ void Test() |
3687 | 3857 | TestMappingMultithreaded(); |
3688 | 3858 | TestLinearAllocator(); |
3689 | 3859 | ManuallyTestLinearAllocator(); |
| 3860 | + BenchmarkLinearAllocator(); |
3690 | 3861 | TestDefragmentationSimple(); |
3691 | 3862 | TestDefragmentationFull(); |
3692 | 3863 |
|
|
0 commit comments