1/*------------------------------------------------------------------------- 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2015 Google Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Simple memory allocation tests. 22 *//*--------------------------------------------------------------------*/ 23 24#include "vktMemoryAllocationTests.hpp" 25 26#include "vktTestCaseUtil.hpp" 27 28#include "tcuMaybe.hpp" 29#include "tcuResultCollector.hpp" 30#include "tcuTestLog.hpp" 31#include "tcuPlatform.hpp" 32#include "tcuCommandLine.hpp" 33 34#include "vkPlatform.hpp" 35#include "vkStrUtil.hpp" 36#include "vkRef.hpp" 37#include "vkDeviceUtil.hpp" 38#include "vkQueryUtil.hpp" 39#include "vkRefUtil.hpp" 40#include "vkAllocationCallbackUtil.hpp" 41 42#include "deUniquePtr.hpp" 43#include "deStringUtil.hpp" 44#include "deRandom.hpp" 45 46using tcu::Maybe; 47using tcu::TestLog; 48 49using std::string; 50using std::vector; 51 52using namespace vk; 53 54namespace vkt 55{ 56namespace memory 57{ 58namespace 59{ 60 61enum 62{ 63 // The min max for allocation count is 4096. Use 4000 to take into account 64 // possible memory allocations made by layers etc. 65 MAX_ALLOCATION_COUNT = 4000 66}; 67 68struct TestConfig 69{ 70 enum Order 71 { 72 ALLOC_FREE, 73 ALLOC_REVERSE_FREE, 74 MIXED_ALLOC_FREE, 75 ORDER_LAST 76 }; 77 78 Maybe<VkDeviceSize> memorySize; 79 Maybe<float> memoryPercentage; 80 deUint32 memoryAllocationCount; 81 Order order; 82 bool useDeviceGroups; 83 84 TestConfig (void) 85 : memoryAllocationCount ((deUint32)-1) 86 , order (ORDER_LAST) 87 , useDeviceGroups (false) 88 { 89 } 90}; 91 92struct TestConfigRandom 93{ 94 const deUint32 seed; 95 const bool useDeviceGroups; 96 97 TestConfigRandom (const deUint32 _seed, const bool _useDeviceGroups) 98 : seed (_seed) 99 , useDeviceGroups (_useDeviceGroups) 100 { 101 } 102}; 103 104vk::Move<VkInstance> createInstanceWithExtensions (const vk::PlatformInterface& vkp, deUint32 version, const std::vector<std::string>& enableExtensions) 105{ 106 std::vector<std::string> enableExtensionPtrs; 107 const std::vector<VkExtensionProperties> availableExtensions = enumerateInstanceExtensionProperties(vkp, DE_NULL); 108 for (size_t extensionID = 0; extensionID < enableExtensions.size(); extensionID++) 109 { 110 if (!isInstanceExtensionSupported(version, availableExtensions, RequiredExtension(enableExtensions[extensionID]))) 111 TCU_THROW(NotSupportedError, (enableExtensions[extensionID] + " is not supported").c_str()); 112 113 if (!isCoreInstanceExtension(version, enableExtensions[extensionID])) 114 enableExtensionPtrs.push_back(enableExtensions[extensionID]); 115 } 116 117 return createDefaultInstance(vkp, version, std::vector<std::string>() /* layers */, enableExtensionPtrs); 118} 119 120class BaseAllocateTestInstance : public TestInstance 121{ 122public: 123 BaseAllocateTestInstance (Context& context, bool useDeviceGroups) 124 : TestInstance (context) 125 , m_useDeviceGroups (useDeviceGroups) 126 , m_subsetAllocationAllowed (false) 127 , m_numPhysDevices (1) 128 , m_memoryProperties (getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice())) 129 { 130 if (m_useDeviceGroups) 131 createDeviceGroup(); 132 m_allocFlagsInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR; 133 m_allocFlagsInfo.pNext = DE_NULL; 134 m_allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT; 135 m_allocFlagsInfo.deviceMask = 0; 136 } 137 138 void createDeviceGroup (void); 139 const vk::DeviceInterface& getDeviceInterface (void) { return m_useDeviceGroups ? *m_deviceDriver : m_context.getDeviceInterface(); } 140 vk::VkDevice getDevice (void) { return m_useDeviceGroups ? m_logicalDevice.get() : m_context.getDevice(); } 141 142protected: 143 bool m_useDeviceGroups; 144 bool m_subsetAllocationAllowed; 145 VkMemoryAllocateFlagsInfo m_allocFlagsInfo; 146 deUint32 m_numPhysDevices; 147 VkPhysicalDeviceMemoryProperties m_memoryProperties; 148 149private: 150 vk::Move<vk::VkInstance> m_deviceGroupInstance; 151 vk::Move<vk::VkDevice> m_logicalDevice; 152 de::MovePtr<vk::DeviceDriver> m_deviceDriver; 153}; 154 155void BaseAllocateTestInstance::createDeviceGroup (void) 156{ 157 const tcu::CommandLine& cmdLine = m_context.getTestContext().getCommandLine(); 158 const deUint32 devGroupIdx = cmdLine.getVKDeviceGroupId() - 1; 159 const deUint32 physDeviceIdx = cmdLine.getVKDeviceId() - 1; 160 const float queuePriority = 1.0f; 161 deUint32 queueFamilyIndex = 0; 162 const std::vector<std::string> requiredExtensions (1, "VK_KHR_device_group_creation"); 163 m_deviceGroupInstance = createInstanceWithExtensions(m_context.getPlatformInterface(), m_context.getUsedApiVersion(), requiredExtensions); 164 std::vector<VkPhysicalDeviceGroupProperties> devGroupProperties = enumeratePhysicalDeviceGroups(m_context.getInstanceInterface(), m_deviceGroupInstance.get()); 165 m_numPhysDevices = devGroupProperties[devGroupIdx].physicalDeviceCount; 166 m_subsetAllocationAllowed = devGroupProperties[devGroupIdx].subsetAllocation; 167 if (m_numPhysDevices < 2) 168 TCU_THROW(NotSupportedError, "Device group allocation tests not supported with 1 physical device"); 169 std::vector<const char*> deviceExtensions; 170 171 if (!isCoreDeviceExtension(m_context.getUsedApiVersion(), "VK_KHR_device_group")) 172 deviceExtensions.push_back("VK_KHR_device_group"); 173 174 VkDeviceGroupDeviceCreateInfo deviceGroupInfo = 175 { 176 VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR, //stype 177 DE_NULL, //pNext 178 devGroupProperties[devGroupIdx].physicalDeviceCount, //physicalDeviceCount 179 devGroupProperties[devGroupIdx].physicalDevices //physicalDevices 180 }; 181 InstanceDriver instance (m_context.getPlatformInterface(), m_useDeviceGroups ? m_deviceGroupInstance.get() : m_context.getInstance()); 182 const VkPhysicalDeviceFeatures deviceFeatures = getPhysicalDeviceFeatures(instance, deviceGroupInfo.pPhysicalDevices[physDeviceIdx]); 183 184 const std::vector<VkQueueFamilyProperties> queueProps = getPhysicalDeviceQueueFamilyProperties(instance, devGroupProperties[devGroupIdx].physicalDevices[physDeviceIdx]); 185 for (size_t queueNdx = 0; queueNdx < queueProps.size(); queueNdx++) 186 { 187 if (queueProps[queueNdx].queueFlags & VK_QUEUE_COMPUTE_BIT) 188 queueFamilyIndex = (deUint32)queueNdx; 189 } 190 191 VkDeviceQueueCreateInfo queueInfo = 192 { 193 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType; 194 DE_NULL, // const void* pNext; 195 (VkDeviceQueueCreateFlags)0u, // VkDeviceQueueCreateFlags flags; 196 queueFamilyIndex, // deUint32 queueFamilyIndex; 197 1u, // deUint32 queueCount; 198 &queuePriority // const float* pQueuePriorities; 199 }; 200 201 const VkDeviceCreateInfo deviceInfo = 202 { 203 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // VkStructureType sType; 204 m_useDeviceGroups ? &deviceGroupInfo : DE_NULL, // const void* pNext; 205 (VkDeviceCreateFlags)0, // VkDeviceCreateFlags flags; 206 1u , // uint32_t queueCreateInfoCount; 207 &queueInfo, // const VkDeviceQueueCreateInfo* pQueueCreateInfos; 208 0u, // uint32_t enabledLayerCount; 209 DE_NULL, // const char* const* ppEnabledLayerNames; 210 deUint32(deviceExtensions.size()), // uint32_t enabledExtensionCount; 211 deviceExtensions.empty() ? DE_NULL : &deviceExtensions[0], // const char* const* ppEnabledExtensionNames; 212 &deviceFeatures, // const VkPhysicalDeviceFeatures* pEnabledFeatures; 213 }; 214 m_logicalDevice = createDevice(instance, deviceGroupInfo.pPhysicalDevices[physDeviceIdx], &deviceInfo); 215 m_deviceDriver = de::MovePtr<DeviceDriver>(new DeviceDriver(instance, *m_logicalDevice)); 216 m_memoryProperties = getPhysicalDeviceMemoryProperties(instance, deviceGroupInfo.pPhysicalDevices[physDeviceIdx]); 217} 218 219class AllocateFreeTestInstance : public BaseAllocateTestInstance 220{ 221public: 222 AllocateFreeTestInstance (Context& context, const TestConfig config) 223 : BaseAllocateTestInstance (context, config.useDeviceGroups) 224 , m_config (config) 225 , m_result (m_context.getTestContext().getLog()) 226 , m_memoryTypeIndex (0) 227 { 228 DE_ASSERT(!!m_config.memorySize != !!m_config.memoryPercentage); 229 } 230 231 tcu::TestStatus iterate (void); 232 233private: 234 const TestConfig m_config; 235 tcu::ResultCollector m_result; 236 deUint32 m_memoryTypeIndex; 237}; 238 239 240tcu::TestStatus AllocateFreeTestInstance::iterate (void) 241{ 242 TestLog& log = m_context.getTestContext().getLog(); 243 const VkDevice device = getDevice(); 244 const DeviceInterface& vkd = getDeviceInterface(); 245 246 DE_ASSERT(m_config.memoryAllocationCount <= MAX_ALLOCATION_COUNT); 247 248 if (m_memoryTypeIndex == 0) 249 { 250 log << TestLog::Message << "Memory allocation count: " << m_config.memoryAllocationCount << TestLog::EndMessage; 251 log << TestLog::Message << "Single allocation size: " << (m_config.memorySize ? de::toString(*m_config.memorySize) : de::toString(100.0f * (*m_config.memoryPercentage)) + " percent of the heap size.") << TestLog::EndMessage; 252 253 if (m_config.order == TestConfig::ALLOC_REVERSE_FREE) 254 log << TestLog::Message << "Memory is freed in reversed order. " << TestLog::EndMessage; 255 else if (m_config.order == TestConfig::ALLOC_FREE) 256 log << TestLog::Message << "Memory is freed in same order as allocated. " << TestLog::EndMessage; 257 else if (m_config.order == TestConfig::MIXED_ALLOC_FREE) 258 log << TestLog::Message << "Memory is freed right after allocation. " << TestLog::EndMessage; 259 else 260 DE_FATAL("Unknown allocation order"); 261 } 262 263 try 264 { 265 const VkMemoryType memoryType = m_memoryProperties.memoryTypes[m_memoryTypeIndex]; 266 const VkMemoryHeap memoryHeap = m_memoryProperties.memoryHeaps[memoryType.heapIndex]; 267 268 const VkDeviceSize allocationSize = (m_config.memorySize ? *m_config.memorySize : (VkDeviceSize)(*m_config.memoryPercentage * (float)memoryHeap.size)); 269 vector<VkDeviceMemory> memoryObjects (m_config.memoryAllocationCount, (VkDeviceMemory)0); 270 271 log << TestLog::Message << "Memory type index: " << m_memoryTypeIndex << TestLog::EndMessage; 272 273 if (memoryType.heapIndex >= m_memoryProperties.memoryHeapCount) 274 m_result.fail("Invalid heap index defined for memory type."); 275 276 { 277 log << TestLog::Message << "Memory type: " << memoryType << TestLog::EndMessage; 278 log << TestLog::Message << "Memory heap: " << memoryHeap << TestLog::EndMessage; 279 280 if (allocationSize * m_config.memoryAllocationCount * 8 > memoryHeap.size) 281 TCU_THROW(NotSupportedError, "Memory heap doesn't have enough memory."); 282 283#if (DE_PTR_SIZE == 4) 284 // For 32-bit binaries we cap the total host visible allocations to 1.5GB to 285 // avoid exhausting CPU virtual address space and throwing a false negative result. 286 if ((memoryType.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && 287 allocationSize * m_config.memoryAllocationCount >= 1610612736) 288 289 log << TestLog::Message << " Skipping: Not enough CPU virtual address space for all host visible allocations." << TestLog::EndMessage; 290 else 291 { 292#else 293 { 294#endif 295 296 try 297 { 298 const deUint32 totalDeviceMaskCombinations = m_subsetAllocationAllowed ? (1 << m_numPhysDevices) - 1 : 1; 299 for (deUint32 deviceMask = 1; deviceMask <= totalDeviceMaskCombinations; deviceMask++) 300 { 301 // Allocate on all physical devices if subset allocation is not allowed, do only once. 302 if (!m_subsetAllocationAllowed) 303 deviceMask = (1 << m_numPhysDevices) - 1; 304 m_allocFlagsInfo.deviceMask = deviceMask; 305 306 if (m_config.order == TestConfig::ALLOC_FREE || m_config.order == TestConfig::ALLOC_REVERSE_FREE) 307 { 308 for (size_t ndx = 0; ndx < m_config.memoryAllocationCount; ndx++) 309 { 310 VkMemoryAllocateInfo alloc = 311 { 312 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // sType 313 m_useDeviceGroups ? &m_allocFlagsInfo : DE_NULL, // pNext 314 allocationSize, // allocationSize 315 m_memoryTypeIndex // memoryTypeIndex; 316 }; 317 318 VK_CHECK(vkd.allocateMemory(device, &alloc, (const VkAllocationCallbacks*)DE_NULL, &memoryObjects[ndx])); 319 320 TCU_CHECK(!!memoryObjects[ndx]); 321 } 322 323 if (m_config.order == TestConfig::ALLOC_FREE) 324 { 325 for (size_t ndx = 0; ndx < m_config.memoryAllocationCount; ndx++) 326 { 327 const VkDeviceMemory mem = memoryObjects[memoryObjects.size() - 1 - ndx]; 328 329 vkd.freeMemory(device, mem, (const VkAllocationCallbacks*)DE_NULL); 330 memoryObjects[memoryObjects.size() - 1 - ndx] = (VkDeviceMemory)0; 331 } 332 } 333 else 334 { 335 for (size_t ndx = 0; ndx < m_config.memoryAllocationCount; ndx++) 336 { 337 const VkDeviceMemory mem = memoryObjects[ndx]; 338 339 vkd.freeMemory(device, mem, (const VkAllocationCallbacks*)DE_NULL); 340 memoryObjects[ndx] = (VkDeviceMemory)0; 341 } 342 } 343 } 344 else 345 { 346 for (size_t ndx = 0; ndx < m_config.memoryAllocationCount; ndx++) 347 { 348 const VkMemoryAllocateInfo alloc = 349 { 350 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // sType 351 m_useDeviceGroups ? &m_allocFlagsInfo : DE_NULL, // pNext 352 allocationSize, // allocationSize 353 m_memoryTypeIndex // memoryTypeIndex; 354 }; 355 356 VK_CHECK(vkd.allocateMemory(device, &alloc, (const VkAllocationCallbacks*)DE_NULL, &memoryObjects[ndx])); 357 TCU_CHECK(!!memoryObjects[ndx]); 358 359 vkd.freeMemory(device, memoryObjects[ndx], (const VkAllocationCallbacks*)DE_NULL); 360 memoryObjects[ndx] = (VkDeviceMemory)0; 361 } 362 } 363 } 364 } 365 catch (...) 366 { 367 for (size_t ndx = 0; ndx < m_config.memoryAllocationCount; ndx++) 368 { 369 const VkDeviceMemory mem = memoryObjects[ndx]; 370 371 if (!!mem) 372 { 373 vkd.freeMemory(device, mem, (const VkAllocationCallbacks*)DE_NULL); 374 memoryObjects[ndx] = (VkDeviceMemory)0; 375 } 376 } 377 378 throw; 379 } 380 } 381 } 382 } 383 catch (const tcu::TestError& error) 384 { 385 m_result.fail(error.getMessage()); 386 } 387 388 m_memoryTypeIndex++; 389 390 if (m_memoryTypeIndex < m_memoryProperties.memoryTypeCount) 391 return tcu::TestStatus::incomplete(); 392 else 393 return tcu::TestStatus(m_result.getResult(), m_result.getMessage()); 394} 395 396size_t computeDeviceMemorySystemMemFootprint (const DeviceInterface& vk, VkDevice device) 397{ 398 AllocationCallbackRecorder callbackRecorder (getSystemAllocator()); 399 400 { 401 // 1 B allocation from memory type 0 402 const VkMemoryAllocateInfo allocInfo = 403 { 404 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 405 DE_NULL, 406 1u, 407 0u, 408 }; 409 const Unique<VkDeviceMemory> memory (allocateMemory(vk, device, &allocInfo)); 410 AllocationCallbackValidationResults validateRes; 411 412 validateAllocationCallbacks(callbackRecorder, &validateRes); 413 414 TCU_CHECK(validateRes.violations.empty()); 415 416 return getLiveSystemAllocationTotal(validateRes) 417 + sizeof(void*)*validateRes.liveAllocations.size(); // allocation overhead 418 } 419} 420 421struct MemoryType 422{ 423 deUint32 index; 424 VkMemoryType type; 425}; 426 427struct MemoryObject 428{ 429 VkDeviceMemory memory; 430 VkDeviceSize size; 431}; 432 433struct Heap 434{ 435 VkMemoryHeap heap; 436 VkDeviceSize memoryUsage; 437 VkDeviceSize maxMemoryUsage; 438 vector<MemoryType> types; 439 vector<MemoryObject> objects; 440}; 441 442class RandomAllocFreeTestInstance : public BaseAllocateTestInstance 443{ 444public: 445 RandomAllocFreeTestInstance (Context& context, TestConfigRandom config); 446 ~RandomAllocFreeTestInstance (void); 447 448 tcu::TestStatus iterate (void); 449 450private: 451 const size_t m_opCount; 452 const size_t m_allocSysMemSize; 453 const PlatformMemoryLimits m_memoryLimits; 454 const deUint32 m_totalDeviceMaskCombinations; 455 456 deUint32 m_memoryObjectCount; 457 deUint32 m_currentDeviceMask; 458 size_t m_opNdx; 459 de::Random m_rng; 460 vector<Heap> m_heaps; 461 VkDeviceSize m_totalSystemMem; 462 VkDeviceSize m_totalDeviceMem; 463}; 464 465RandomAllocFreeTestInstance::RandomAllocFreeTestInstance (Context& context, TestConfigRandom config) 466 : BaseAllocateTestInstance (context, config.useDeviceGroups) 467 , m_opCount (128) 468 , m_allocSysMemSize (computeDeviceMemorySystemMemFootprint(getDeviceInterface(), context.getDevice()) 469 + sizeof(MemoryObject)) 470 , m_memoryLimits (getMemoryLimits(context.getTestContext().getPlatform().getVulkanPlatform())) 471 , m_totalDeviceMaskCombinations (m_subsetAllocationAllowed ? (1 << m_numPhysDevices) - 1 : 1) 472 , m_memoryObjectCount (0) 473 , m_currentDeviceMask (m_subsetAllocationAllowed ? 1 : (1 << m_numPhysDevices) - 1) 474 , m_opNdx (0) 475 , m_rng (config.seed) 476 , m_totalSystemMem (0) 477 , m_totalDeviceMem (0) 478{ 479 TCU_CHECK(m_memoryProperties.memoryHeapCount <= 32); 480 TCU_CHECK(m_memoryProperties.memoryTypeCount <= 32); 481 482 m_heaps.resize(m_memoryProperties.memoryHeapCount); 483 484 for (deUint32 heapNdx = 0; heapNdx < m_memoryProperties.memoryHeapCount; heapNdx++) 485 { 486 m_heaps[heapNdx].heap = m_memoryProperties.memoryHeaps[heapNdx]; 487 m_heaps[heapNdx].memoryUsage = 0; 488 m_heaps[heapNdx].maxMemoryUsage = m_heaps[heapNdx].heap.size / 2; /* Use at maximum 50% of heap */ 489 490 m_heaps[heapNdx].objects.reserve(100); 491 } 492 493 for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < m_memoryProperties.memoryTypeCount; memoryTypeNdx++) 494 { 495 const MemoryType type = 496 { 497 memoryTypeNdx, 498 m_memoryProperties.memoryTypes[memoryTypeNdx] 499 }; 500 501 TCU_CHECK(type.type.heapIndex < m_memoryProperties.memoryHeapCount); 502 503 m_heaps[type.type.heapIndex].types.push_back(type); 504 } 505} 506 507RandomAllocFreeTestInstance::~RandomAllocFreeTestInstance (void) 508{ 509 const VkDevice device = getDevice(); 510 const DeviceInterface& vkd = getDeviceInterface(); 511 512 for (deUint32 heapNdx = 0; heapNdx < (deUint32)m_heaps.size(); heapNdx++) 513 { 514 const Heap& heap = m_heaps[heapNdx]; 515 516 for (size_t objectNdx = 0; objectNdx < heap.objects.size(); objectNdx++) 517 { 518 if (!!heap.objects[objectNdx].memory) 519 vkd.freeMemory(device, heap.objects[objectNdx].memory, (const VkAllocationCallbacks*)DE_NULL); 520 } 521 } 522} 523 524tcu::TestStatus RandomAllocFreeTestInstance::iterate (void) 525{ 526 const VkDevice device = getDevice(); 527 const DeviceInterface& vkd = getDeviceInterface(); 528 TestLog& log = m_context.getTestContext().getLog(); 529 const bool isUMA = m_memoryLimits.totalDeviceLocalMemory == 0; 530 const VkDeviceSize usedSysMem = isUMA ? (m_totalDeviceMem+m_totalSystemMem) : m_totalSystemMem; 531 const bool canAllocateSys = usedSysMem + m_allocSysMemSize + 1024 < m_memoryLimits.totalSystemMemory; // \note Always leave room for 1 KiB sys mem alloc 532 const bool canAllocateDev = isUMA ? canAllocateSys : (m_totalDeviceMem + 16 < m_memoryLimits.totalDeviceLocalMemory); 533 vector<size_t> nonFullHeaps; 534 vector<size_t> nonEmptyHeaps; 535 bool allocateMore; 536 537 if (m_opNdx == 0) 538 { 539 log << TestLog::Message << "Performing " << m_opCount << " random VkAllocMemory() / VkFreeMemory() calls before freeing all memory." << TestLog::EndMessage; 540 log << TestLog::Message << "Using max 1/8 of the memory in each memory heap." << TestLog::EndMessage; 541 } 542 543 // Sort heaps based on whether allocations or frees are possible 544 for (size_t heapNdx = 0; heapNdx < m_heaps.size(); ++heapNdx) 545 { 546 const bool isDeviceLocal = (m_heaps[heapNdx].heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0; 547 const bool isHeapFull = m_heaps[heapNdx].memoryUsage >= m_heaps[heapNdx].maxMemoryUsage; 548 const bool isHeapEmpty = m_heaps[heapNdx].memoryUsage == 0; 549 550 if (!isHeapEmpty) 551 nonEmptyHeaps.push_back(heapNdx); 552 553 if (!isHeapFull && ((isUMA && canAllocateSys) || 554 (!isUMA && isDeviceLocal && canAllocateDev) || 555 (!isUMA && !isDeviceLocal && canAllocateSys))) 556 nonFullHeaps.push_back(heapNdx); 557 } 558 559 if (m_opNdx >= m_opCount) 560 { 561 if (nonEmptyHeaps.empty()) 562 { 563 m_currentDeviceMask++; 564 if (m_currentDeviceMask > m_totalDeviceMaskCombinations) 565 return tcu::TestStatus::pass("Pass"); 566 else 567 { 568 m_opNdx = 0; 569 return tcu::TestStatus::incomplete(); 570 } 571 } 572 else 573 allocateMore = false; 574 } 575 else if (!nonEmptyHeaps.empty() && 576 !nonFullHeaps.empty() && 577 (m_memoryObjectCount < MAX_ALLOCATION_COUNT) && 578 canAllocateSys) 579 allocateMore = m_rng.getBool(); // Randomize if both operations are doable. 580 else if (nonEmptyHeaps.empty()) 581 { 582 DE_ASSERT(canAllocateSys); 583 allocateMore = true; // Allocate more if there are no objects to free. 584 } 585 else if (nonFullHeaps.empty() || !canAllocateSys) 586 allocateMore = false; // Free objects if there is no free space for new objects. 587 else 588 { 589 allocateMore = false; 590 DE_FATAL("Fail"); 591 } 592 593 if (allocateMore) 594 { 595 const size_t nonFullHeapNdx = (size_t)(m_rng.getUint32() % (deUint32)nonFullHeaps.size()); 596 const size_t heapNdx = nonFullHeaps[nonFullHeapNdx]; 597 Heap& heap = m_heaps[heapNdx]; 598 const MemoryType& memoryType = m_rng.choose<MemoryType>(heap.types.begin(), heap.types.end()); 599 const bool isDeviceLocal = (heap.heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0; 600 const VkDeviceSize maxAllocSize = (isDeviceLocal && !isUMA) 601 ? de::min(heap.maxMemoryUsage - heap.memoryUsage, (VkDeviceSize)m_memoryLimits.totalDeviceLocalMemory - m_totalDeviceMem) 602 : de::min(heap.maxMemoryUsage - heap.memoryUsage, (VkDeviceSize)m_memoryLimits.totalSystemMemory - usedSysMem - m_allocSysMemSize); 603 const VkDeviceSize allocationSize = 1 + (m_rng.getUint64() % maxAllocSize); 604 605 if ((allocationSize > (deUint64)(heap.maxMemoryUsage - heap.memoryUsage)) && (allocationSize != 1)) 606 TCU_THROW(InternalError, "Test Error: trying to allocate memory more than the available heap size."); 607 608 const MemoryObject object = 609 { 610 (VkDeviceMemory)0, 611 allocationSize 612 }; 613 614 heap.objects.push_back(object); 615 616 m_allocFlagsInfo.deviceMask = m_currentDeviceMask; 617 const VkMemoryAllocateInfo alloc = 618 { 619 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // sType 620 m_useDeviceGroups ? &m_allocFlagsInfo : DE_NULL, // pNext 621 object.size, // allocationSize 622 memoryType.index // memoryTypeIndex; 623 }; 624 625 VK_CHECK(vkd.allocateMemory(device, &alloc, (const VkAllocationCallbacks*)DE_NULL, &heap.objects.back().memory)); 626 TCU_CHECK(!!heap.objects.back().memory); 627 m_memoryObjectCount++; 628 629 heap.memoryUsage += allocationSize; 630 (isDeviceLocal ? m_totalDeviceMem : m_totalSystemMem) += allocationSize; 631 m_totalSystemMem += m_allocSysMemSize; 632 } 633 else 634 { 635 const size_t nonEmptyHeapNdx = (size_t)(m_rng.getUint32() % (deUint32)nonEmptyHeaps.size()); 636 const size_t heapNdx = nonEmptyHeaps[nonEmptyHeapNdx]; 637 Heap& heap = m_heaps[heapNdx]; 638 const size_t memoryObjectNdx = m_rng.getUint32() % heap.objects.size(); 639 MemoryObject& memoryObject = heap.objects[memoryObjectNdx]; 640 const bool isDeviceLocal = (heap.heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0; 641 642 vkd.freeMemory(device, memoryObject.memory, (const VkAllocationCallbacks*)DE_NULL); 643 memoryObject.memory = (VkDeviceMemory)0; 644 m_memoryObjectCount--; 645 646 heap.memoryUsage -= memoryObject.size; 647 (isDeviceLocal ? m_totalDeviceMem : m_totalSystemMem) -= memoryObject.size; 648 m_totalSystemMem -= m_allocSysMemSize; 649 650 heap.objects[memoryObjectNdx] = heap.objects.back(); 651 heap.objects.pop_back(); 652 653 DE_ASSERT(heap.memoryUsage == 0 || !heap.objects.empty()); 654 } 655 656 m_opNdx++; 657 return tcu::TestStatus::incomplete(); 658} 659 660 661} // anonymous 662 663tcu::TestCaseGroup* createAllocationTestsCommon (tcu::TestContext& testCtx, bool useDeviceGroups) 664{ 665 const char* name = useDeviceGroups ? "device_group_allocation" : "allocation"; 666 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, name, "Memory allocation tests.")); 667 668 const VkDeviceSize KiB = 1024; 669 const VkDeviceSize MiB = 1024 * KiB; 670 671 const struct 672 { 673 const char* const str; 674 VkDeviceSize size; 675 } allocationSizes[] = 676 { 677 { "64", 64 }, 678 { "128", 128 }, 679 { "256", 256 }, 680 { "512", 512 }, 681 { "1KiB", 1*KiB }, 682 { "4KiB", 4*KiB }, 683 { "8KiB", 8*KiB }, 684 { "1MiB", 1*MiB } 685 }; 686 687 const int allocationPercents[] = 688 { 689 1 690 }; 691 692 const int allocationCounts[] = 693 { 694 1, 10, 100, 1000, -1 695 }; 696 697 const struct 698 { 699 const char* const str; 700 const TestConfig::Order order; 701 } orders[] = 702 { 703 { "forward", TestConfig::ALLOC_FREE }, 704 { "reverse", TestConfig::ALLOC_REVERSE_FREE }, 705 { "mixed", TestConfig::MIXED_ALLOC_FREE } 706 }; 707 708 { 709 de::MovePtr<tcu::TestCaseGroup> basicGroup(new tcu::TestCaseGroup(testCtx, "basic", "Basic memory allocation and free tests")); 710 711 for (size_t allocationSizeNdx = 0; allocationSizeNdx < DE_LENGTH_OF_ARRAY(allocationSizes); allocationSizeNdx++) 712 { 713 const VkDeviceSize allocationSize = allocationSizes[allocationSizeNdx].size; 714 const char* const allocationSizeName = allocationSizes[allocationSizeNdx].str; 715 de::MovePtr<tcu::TestCaseGroup> sizeGroup (new tcu::TestCaseGroup(testCtx, ("size_" + string(allocationSizeName)).c_str(), ("Test different allocation sizes " + de::toString(allocationSize)).c_str())); 716 717 for (size_t orderNdx = 0; orderNdx < DE_LENGTH_OF_ARRAY(orders); orderNdx++) 718 { 719 const TestConfig::Order order = orders[orderNdx].order; 720 const char* const orderName = orders[orderNdx].str; 721 const char* const orderDescription = orderName; 722 de::MovePtr<tcu::TestCaseGroup> orderGroup (new tcu::TestCaseGroup(testCtx, orderName, orderDescription)); 723 724 for (size_t allocationCountNdx = 0; allocationCountNdx < DE_LENGTH_OF_ARRAY(allocationCounts); allocationCountNdx++) 725 { 726 const int allocationCount = allocationCounts[allocationCountNdx]; 727 728 if (allocationCount != -1 && allocationCount * allocationSize > 50 * MiB) 729 continue; 730 731 TestConfig config; 732 733 config.memorySize = allocationSize; 734 config.order = order; 735 config.useDeviceGroups = useDeviceGroups; 736 if (allocationCount == -1) 737 { 738 if (allocationSize < 4096) 739 continue; 740 741 config.memoryAllocationCount = de::min((deUint32)(50 * MiB / allocationSize), (deUint32)MAX_ALLOCATION_COUNT); 742 743 if (config.memoryAllocationCount == 0 744 || config.memoryAllocationCount == 1 745 || config.memoryAllocationCount == 10 746 || config.memoryAllocationCount == 100 747 || config.memoryAllocationCount == 1000) 748 continue; 749 } 750 else 751 config.memoryAllocationCount = allocationCount; 752 753 orderGroup->addChild(new InstanceFactory1<AllocateFreeTestInstance, TestConfig>(testCtx, tcu::NODETYPE_SELF_VALIDATE, "count_" + de::toString(config.memoryAllocationCount), "", config)); 754 } 755 756 sizeGroup->addChild(orderGroup.release()); 757 } 758 759 basicGroup->addChild(sizeGroup.release()); 760 } 761 762 for (size_t allocationPercentNdx = 0; allocationPercentNdx < DE_LENGTH_OF_ARRAY(allocationPercents); allocationPercentNdx++) 763 { 764 const int allocationPercent = allocationPercents[allocationPercentNdx]; 765 de::MovePtr<tcu::TestCaseGroup> percentGroup (new tcu::TestCaseGroup(testCtx, ("percent_" + de::toString(allocationPercent)).c_str(), ("Test different allocation percents " + de::toString(allocationPercent)).c_str())); 766 767 for (size_t orderNdx = 0; orderNdx < DE_LENGTH_OF_ARRAY(orders); orderNdx++) 768 { 769 const TestConfig::Order order = orders[orderNdx].order; 770 const char* const orderName = orders[orderNdx].str; 771 const char* const orderDescription = orderName; 772 de::MovePtr<tcu::TestCaseGroup> orderGroup (new tcu::TestCaseGroup(testCtx, orderName, orderDescription)); 773 774 for (size_t allocationCountNdx = 0; allocationCountNdx < DE_LENGTH_OF_ARRAY(allocationCounts); allocationCountNdx++) 775 { 776 const int allocationCount = allocationCounts[allocationCountNdx]; 777 778 if ((allocationCount != -1) && ((float)allocationCount * (float)allocationPercent >= 1.00f / 8.00f)) 779 continue; 780 781 TestConfig config; 782 783 config.memoryPercentage = (float)allocationPercent / 100.0f; 784 config.order = order; 785 config.useDeviceGroups = useDeviceGroups; 786 787 if (allocationCount == -1) 788 { 789 config.memoryAllocationCount = de::min((deUint32)((1.00f / 8.00f) / ((float)allocationPercent / 100.0f)), (deUint32)MAX_ALLOCATION_COUNT); 790 791 if (config.memoryAllocationCount == 0 792 || config.memoryAllocationCount == 1 793 || config.memoryAllocationCount == 10 794 || config.memoryAllocationCount == 100 795 || config.memoryAllocationCount == 1000) 796 continue; 797 } 798 else 799 config.memoryAllocationCount = allocationCount; 800 801 orderGroup->addChild(new InstanceFactory1<AllocateFreeTestInstance, TestConfig>(testCtx, tcu::NODETYPE_SELF_VALIDATE, "count_" + de::toString(config.memoryAllocationCount), "", config)); 802 } 803 804 percentGroup->addChild(orderGroup.release()); 805 } 806 807 basicGroup->addChild(percentGroup.release()); 808 } 809 810 group->addChild(basicGroup.release()); 811 } 812 813 { 814 const deUint32 caseCount = 100; 815 de::MovePtr<tcu::TestCaseGroup> randomGroup (new tcu::TestCaseGroup(testCtx, "random", "Random memory allocation tests.")); 816 817 for (deUint32 caseNdx = 0; caseNdx < caseCount; caseNdx++) 818 { 819 TestConfigRandom config(deInt32Hash(caseNdx ^ 32480), useDeviceGroups); 820 821 randomGroup->addChild(new InstanceFactory1<RandomAllocFreeTestInstance, TestConfigRandom>(testCtx, tcu::NODETYPE_SELF_VALIDATE, de::toString(caseNdx), "Random case", config)); 822 } 823 824 group->addChild(randomGroup.release()); 825 } 826 827 return group.release(); 828} 829 830tcu::TestCaseGroup* createAllocationTests (tcu::TestContext& testCtx) 831{ 832 return createAllocationTestsCommon(testCtx, false); 833} 834 835tcu::TestCaseGroup* createDeviceGroupAllocationTests (tcu::TestContext& testCtx) 836{ 837 return createAllocationTestsCommon(testCtx, true); 838} 839 840} // memory 841} // vkt 842