Home | History | Annotate | Download | only in memory
      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 
     46 using tcu::Maybe;
     47 using tcu::TestLog;
     48 
     49 using std::string;
     50 using std::vector;
     51 
     52 using namespace vk;
     53 
     54 namespace vkt
     55 {
     56 namespace memory
     57 {
     58 namespace
     59 {
     60 
     61 enum
     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 
     68 struct 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 
     92 struct 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 
    104 vk::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 
    120 class BaseAllocateTestInstance : public TestInstance
    121 {
    122 public:
    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 
    142 protected:
    143 	bool									m_useDeviceGroups;
    144 	bool									m_subsetAllocationAllowed;
    145 	VkMemoryAllocateFlagsInfo				m_allocFlagsInfo;
    146 	deUint32								m_numPhysDevices;
    147 	VkPhysicalDeviceMemoryProperties		m_memoryProperties;
    148 
    149 private:
    150 	vk::Move<vk::VkInstance>		m_deviceGroupInstance;
    151 	vk::Move<vk::VkDevice>			m_logicalDevice;
    152 	de::MovePtr<vk::DeviceDriver>	m_deviceDriver;
    153 };
    154 
    155 void 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 
    219 class AllocateFreeTestInstance : public BaseAllocateTestInstance
    220 {
    221 public:
    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 
    233 private:
    234 	const TestConfig						m_config;
    235 	tcu::ResultCollector					m_result;
    236 	deUint32								m_memoryTypeIndex;
    237 };
    238 
    239 
    240 tcu::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 
    396 size_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 
    421 struct MemoryType
    422 {
    423 	deUint32		index;
    424 	VkMemoryType	type;
    425 };
    426 
    427 struct MemoryObject
    428 {
    429 	VkDeviceMemory	memory;
    430 	VkDeviceSize	size;
    431 };
    432 
    433 struct Heap
    434 {
    435 	VkMemoryHeap			heap;
    436 	VkDeviceSize			memoryUsage;
    437 	VkDeviceSize			maxMemoryUsage;
    438 	vector<MemoryType>		types;
    439 	vector<MemoryObject>	objects;
    440 };
    441 
    442 class RandomAllocFreeTestInstance : public BaseAllocateTestInstance
    443 {
    444 public:
    445 								RandomAllocFreeTestInstance		(Context& context, TestConfigRandom config);
    446 								~RandomAllocFreeTestInstance	(void);
    447 
    448 	tcu::TestStatus				iterate							(void);
    449 
    450 private:
    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 
    465 RandomAllocFreeTestInstance::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 
    507 RandomAllocFreeTestInstance::~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 
    524 tcu::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 
    663 tcu::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 
    830 tcu::TestCaseGroup* createAllocationTests (tcu::TestContext& testCtx)
    831 {
    832 	return createAllocationTestsCommon(testCtx, false);
    833 }
    834 
    835 tcu::TestCaseGroup* createDeviceGroupAllocationTests (tcu::TestContext& testCtx)
    836 {
    837 	return createAllocationTestsCommon(testCtx, true);
    838 }
    839 
    840 } // memory
    841 } // vkt
    842