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