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 
33 #include "vkPlatform.hpp"
34 #include "vkStrUtil.hpp"
35 #include "vkRef.hpp"
36 #include "vkDeviceUtil.hpp"
37 #include "vkQueryUtil.hpp"
38 #include "vkRefUtil.hpp"
39 #include "vkAllocationCallbackUtil.hpp"
40 
41 #include "deUniquePtr.hpp"
42 #include "deStringUtil.hpp"
43 #include "deRandom.hpp"
44 
45 using tcu::Maybe;
46 using tcu::TestLog;
47 
48 using std::string;
49 using std::vector;
50 
51 using namespace vk;
52 
53 namespace vkt
54 {
55 namespace memory
56 {
57 namespace
58 {
59 
60 enum
61 {
62 	// The min max for allocation count is 4096. Use 4000 to take into account
63 	// possible memory allocations made by layers etc.
64 	MAX_ALLOCATION_COUNT = 4000
65 };
66 
67 struct TestConfig
68 {
69 	enum Order
70 	{
71 		ALLOC_FREE,
72 		ALLOC_REVERSE_FREE,
73 		MIXED_ALLOC_FREE,
74 		ORDER_LAST
75 	};
76 
77 	Maybe<VkDeviceSize>	memorySize;
78 	Maybe<float>		memoryPercentage;
79 	deUint32			memoryAllocationCount;
80 	Order				order;
81 
TestConfigvkt::memory::__anon9eb46d4e0111::TestConfig82 	TestConfig (void)
83 		: memoryAllocationCount	((deUint32)-1)
84 		, order					(ORDER_LAST)
85 	{
86 	}
87 };
88 
89 class AllocateFreeTestInstance : public TestInstance
90 {
91 public:
AllocateFreeTestInstance(Context & context,const TestConfig config)92 						AllocateFreeTestInstance		(Context& context, const TestConfig config)
93 		: TestInstance			(context)
94 		, m_config				(config)
95 		, m_result				(m_context.getTestContext().getLog())
96 		, m_memoryTypeIndex		(0)
97 		, m_memoryProperties	(getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()))
98 	{
99 		DE_ASSERT(!!m_config.memorySize != !!m_config.memoryPercentage);
100 	}
101 
102 	tcu::TestStatus		iterate							(void);
103 
104 private:
105 	const TestConfig						m_config;
106 	tcu::ResultCollector					m_result;
107 	deUint32								m_memoryTypeIndex;
108 	const VkPhysicalDeviceMemoryProperties	m_memoryProperties;
109 };
110 
iterate(void)111 tcu::TestStatus AllocateFreeTestInstance::iterate (void)
112 {
113 	TestLog&								log					= m_context.getTestContext().getLog();
114 	const VkDevice							device				= m_context.getDevice();
115 	const DeviceInterface&					vkd					= m_context.getDeviceInterface();
116 
117 	DE_ASSERT(m_config.memoryAllocationCount <= MAX_ALLOCATION_COUNT);
118 
119 	if (m_memoryTypeIndex == 0)
120 	{
121 		log << TestLog::Message << "Memory allocation count: " << m_config.memoryAllocationCount << TestLog::EndMessage;
122 		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;
123 
124 		if (m_config.order == TestConfig::ALLOC_REVERSE_FREE)
125 			log << TestLog::Message << "Memory is freed in reversed order. " << TestLog::EndMessage;
126 		else if (m_config.order == TestConfig::ALLOC_FREE)
127 			log << TestLog::Message << "Memory is freed in same order as allocated. " << TestLog::EndMessage;
128 		else if (m_config.order == TestConfig::MIXED_ALLOC_FREE)
129 			log << TestLog::Message << "Memory is freed right after allocation. " << TestLog::EndMessage;
130 		else
131 			DE_FATAL("Unknown allocation order");
132 	}
133 
134 	try
135 	{
136 		const VkMemoryType		memoryType		= m_memoryProperties.memoryTypes[m_memoryTypeIndex];
137 		const VkMemoryHeap		memoryHeap		= m_memoryProperties.memoryHeaps[memoryType.heapIndex];
138 
139 		const VkDeviceSize		allocationSize	= (m_config.memorySize ? *m_config.memorySize : (VkDeviceSize)(*m_config.memoryPercentage * (float)memoryHeap.size));
140 		vector<VkDeviceMemory>	memoryObjects	(m_config.memoryAllocationCount, (VkDeviceMemory)0);
141 
142 		log << TestLog::Message << "Memory type index: " << m_memoryTypeIndex << TestLog::EndMessage;
143 
144 		if (memoryType.heapIndex >= m_memoryProperties.memoryHeapCount)
145 			m_result.fail("Invalid heap index defined for memory type.");
146 
147 		{
148 			log << TestLog::Message << "Memory type: " << memoryType << TestLog::EndMessage;
149 			log << TestLog::Message << "Memory heap: " << memoryHeap << TestLog::EndMessage;
150 
151 			if (allocationSize * m_config.memoryAllocationCount * 8 > memoryHeap.size)
152 				TCU_THROW(NotSupportedError, "Memory heap doesn't have enough memory.");
153 
154 			try
155 			{
156 				if (m_config.order == TestConfig::ALLOC_FREE || m_config.order == TestConfig::ALLOC_REVERSE_FREE)
157 				{
158 					for (size_t ndx = 0; ndx < m_config.memoryAllocationCount; ndx++)
159 					{
160 						const VkMemoryAllocateInfo alloc =
161 						{
162 							VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,	// sType
163 							DE_NULL,								// pNext
164 							allocationSize,							// allocationSize
165 							m_memoryTypeIndex						// memoryTypeIndex;
166 						};
167 
168 						VK_CHECK(vkd.allocateMemory(device, &alloc, (const VkAllocationCallbacks*)DE_NULL, &memoryObjects[ndx]));
169 
170 						TCU_CHECK(!!memoryObjects[ndx]);
171 					}
172 
173 					if (m_config.order == TestConfig::ALLOC_FREE)
174 					{
175 						for (size_t ndx = 0; ndx < m_config.memoryAllocationCount; ndx++)
176 						{
177 							const VkDeviceMemory mem = memoryObjects[memoryObjects.size() - 1 - ndx];
178 
179 							vkd.freeMemory(device, mem, (const VkAllocationCallbacks*)DE_NULL);
180 							memoryObjects[memoryObjects.size() - 1 - ndx] = (VkDeviceMemory)0;
181 						}
182 					}
183 					else
184 					{
185 						for (size_t ndx = 0; ndx < m_config.memoryAllocationCount; ndx++)
186 						{
187 							const VkDeviceMemory mem = memoryObjects[ndx];
188 
189 							vkd.freeMemory(device, mem, (const VkAllocationCallbacks*)DE_NULL);
190 							memoryObjects[ndx] = (VkDeviceMemory)0;
191 						}
192 					}
193 				}
194 				else
195 				{
196 					for (size_t ndx = 0; ndx < m_config.memoryAllocationCount; ndx++)
197 					{
198 						const VkMemoryAllocateInfo alloc =
199 						{
200 							VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,	// sType
201 							DE_NULL,								// pNext
202 							allocationSize,							// allocationSize
203 							m_memoryTypeIndex						// memoryTypeIndex;
204 						};
205 
206 						VK_CHECK(vkd.allocateMemory(device, &alloc, (const VkAllocationCallbacks*)DE_NULL, &memoryObjects[ndx]));
207 						TCU_CHECK(!!memoryObjects[ndx]);
208 
209 						vkd.freeMemory(device, memoryObjects[ndx], (const VkAllocationCallbacks*)DE_NULL);
210 						memoryObjects[ndx] = (VkDeviceMemory)0;
211 					}
212 				}
213 			}
214 			catch (...)
215 			{
216 				for (size_t ndx = 0; ndx < m_config.memoryAllocationCount; ndx++)
217 				{
218 					const VkDeviceMemory mem = memoryObjects[ndx];
219 
220 					if (!!mem)
221 					{
222 						vkd.freeMemory(device, mem, (const VkAllocationCallbacks*)DE_NULL);
223 						memoryObjects[ndx] = (VkDeviceMemory)0;
224 					}
225 				}
226 
227 				throw;
228 			}
229 		}
230 	}
231 	catch (const tcu::TestError& error)
232 	{
233 		m_result.fail(error.getMessage());
234 	}
235 
236 	m_memoryTypeIndex++;
237 
238 	if (m_memoryTypeIndex < m_memoryProperties.memoryTypeCount)
239 		return tcu::TestStatus::incomplete();
240 	else
241 		return tcu::TestStatus(m_result.getResult(), m_result.getMessage());
242 }
243 
computeDeviceMemorySystemMemFootprint(const DeviceInterface & vk,VkDevice device)244 size_t computeDeviceMemorySystemMemFootprint (const DeviceInterface& vk, VkDevice device)
245 {
246 	AllocationCallbackRecorder	callbackRecorder	(getSystemAllocator());
247 
248 	{
249 		// 1 B allocation from memory type 0
250 		const VkMemoryAllocateInfo	allocInfo	=
251 		{
252 			VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
253 			DE_NULL,
254 			1u,
255 			0u,
256 		};
257 		const Unique<VkDeviceMemory>			memory			(allocateMemory(vk, device, &allocInfo));
258 		AllocationCallbackValidationResults		validateRes;
259 
260 		validateAllocationCallbacks(callbackRecorder, &validateRes);
261 
262 		TCU_CHECK(validateRes.violations.empty());
263 
264 		return getLiveSystemAllocationTotal(validateRes)
265 			   + sizeof(void*)*validateRes.liveAllocations.size(); // allocation overhead
266 	}
267 }
268 
269 struct MemoryType
270 {
271 	deUint32		index;
272 	VkMemoryType	type;
273 };
274 
275 struct MemoryObject
276 {
277 	VkDeviceMemory	memory;
278 	VkDeviceSize	size;
279 };
280 
281 struct Heap
282 {
283 	VkMemoryHeap			heap;
284 	VkDeviceSize			memoryUsage;
285 	VkDeviceSize			maxMemoryUsage;
286 	vector<MemoryType>		types;
287 	vector<MemoryObject>	objects;
288 };
289 
290 class RandomAllocFreeTestInstance : public TestInstance
291 {
292 public:
293 								RandomAllocFreeTestInstance		(Context& context, deUint32 seed);
294 								~RandomAllocFreeTestInstance	(void);
295 
296 	tcu::TestStatus				iterate							(void);
297 
298 private:
299 	const size_t				m_opCount;
300 	const size_t				m_allocSysMemSize;
301 	const PlatformMemoryLimits	m_memoryLimits;
302 
303 	deUint32					m_memoryObjectCount;
304 	size_t						m_opNdx;
305 	de::Random					m_rng;
306 	vector<Heap>				m_heaps;
307 	VkDeviceSize				m_totalSystemMem;
308 	VkDeviceSize				m_totalDeviceMem;
309 };
310 
RandomAllocFreeTestInstance(Context & context,deUint32 seed)311 RandomAllocFreeTestInstance::RandomAllocFreeTestInstance (Context& context, deUint32 seed)
312 	: TestInstance			(context)
313 	, m_opCount				(128)
314 	, m_allocSysMemSize		(computeDeviceMemorySystemMemFootprint(context.getDeviceInterface(), context.getDevice())
315 							 + sizeof(MemoryObject))
316 	, m_memoryLimits		(getMemoryLimits(context.getTestContext().getPlatform().getVulkanPlatform()))
317 	, m_memoryObjectCount	(0)
318 	, m_opNdx				(0)
319 	, m_rng					(seed)
320 	, m_totalSystemMem		(0)
321 	, m_totalDeviceMem		(0)
322 {
323 	const VkPhysicalDevice					physicalDevice		= context.getPhysicalDevice();
324 	const InstanceInterface&				vki					= context.getInstanceInterface();
325 	const VkPhysicalDeviceMemoryProperties	memoryProperties	= getPhysicalDeviceMemoryProperties(vki, physicalDevice);
326 
327 	TCU_CHECK(memoryProperties.memoryHeapCount <= 32);
328 	TCU_CHECK(memoryProperties.memoryTypeCount <= 32);
329 
330 	m_heaps.resize(memoryProperties.memoryHeapCount);
331 
332 	for (deUint32 heapNdx = 0; heapNdx < memoryProperties.memoryHeapCount; heapNdx++)
333 	{
334 		m_heaps[heapNdx].heap			= memoryProperties.memoryHeaps[heapNdx];
335 		m_heaps[heapNdx].memoryUsage	= 0;
336 		m_heaps[heapNdx].maxMemoryUsage	= m_heaps[heapNdx].heap.size / 2; /* Use at maximum 50% of heap */
337 
338 		m_heaps[heapNdx].objects.reserve(100);
339 	}
340 
341 	for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < memoryProperties.memoryTypeCount; memoryTypeNdx++)
342 	{
343 		const MemoryType type =
344 		{
345 			memoryTypeNdx,
346 			memoryProperties.memoryTypes[memoryTypeNdx]
347 		};
348 
349 		TCU_CHECK(type.type.heapIndex < memoryProperties.memoryHeapCount);
350 
351 		m_heaps[type.type.heapIndex].types.push_back(type);
352 	}
353 }
354 
~RandomAllocFreeTestInstance(void)355 RandomAllocFreeTestInstance::~RandomAllocFreeTestInstance (void)
356 {
357 	const VkDevice							device				= m_context.getDevice();
358 	const DeviceInterface&					vkd					= m_context.getDeviceInterface();
359 
360 	for (deUint32 heapNdx = 0; heapNdx < (deUint32)m_heaps.size(); heapNdx++)
361 	{
362 		const Heap&	heap	= m_heaps[heapNdx];
363 
364 		for (size_t objectNdx = 0; objectNdx < heap.objects.size(); objectNdx++)
365 		{
366 			if (!!heap.objects[objectNdx].memory)
367 				vkd.freeMemory(device, heap.objects[objectNdx].memory, (const VkAllocationCallbacks*)DE_NULL);
368 		}
369 	}
370 }
371 
iterate(void)372 tcu::TestStatus RandomAllocFreeTestInstance::iterate (void)
373 {
374 	const VkDevice			device			= m_context.getDevice();
375 	const DeviceInterface&	vkd				= m_context.getDeviceInterface();
376 	TestLog&				log				= m_context.getTestContext().getLog();
377 	const bool				isUMA			= m_memoryLimits.totalDeviceLocalMemory == 0;
378 	const VkDeviceSize		usedSysMem		= isUMA ? (m_totalDeviceMem+m_totalSystemMem) : m_totalSystemMem;
379 	const bool				canAllocateSys	= usedSysMem + m_allocSysMemSize + 1024 < m_memoryLimits.totalSystemMemory; // \note Always leave room for 1 KiB sys mem alloc
380 	const bool				canAllocateDev	= isUMA ? canAllocateSys : (m_totalDeviceMem + 16 < m_memoryLimits.totalDeviceLocalMemory);
381 	vector<size_t>			nonFullHeaps;
382 	vector<size_t>			nonEmptyHeaps;
383 	bool					allocateMore;
384 
385 	if (m_opNdx == 0)
386 	{
387 		log << TestLog::Message << "Performing " << m_opCount << " random VkAllocMemory() / VkFreeMemory() calls before freeing all memory." << TestLog::EndMessage;
388 		log << TestLog::Message << "Using max 1/8 of the memory in each memory heap." << TestLog::EndMessage;
389 	}
390 
391 	// Sort heaps based on whether allocations or frees are possible
392 	for (size_t heapNdx = 0; heapNdx < m_heaps.size(); ++heapNdx)
393 	{
394 		const bool	isDeviceLocal	= (m_heaps[heapNdx].heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0;
395 		const bool	isHeapFull		= m_heaps[heapNdx].memoryUsage >= m_heaps[heapNdx].maxMemoryUsage;
396 		const bool	isHeapEmpty		= m_heaps[heapNdx].memoryUsage == 0;
397 
398 		if (!isHeapEmpty)
399 			nonEmptyHeaps.push_back(heapNdx);
400 
401 		if (!isHeapFull && ((isUMA && canAllocateSys) ||
402 							(!isUMA && isDeviceLocal && canAllocateDev) ||
403 							(!isUMA && !isDeviceLocal && canAllocateSys)))
404 			nonFullHeaps.push_back(heapNdx);
405 	}
406 
407 	if (m_opNdx >= m_opCount)
408 	{
409 		if (nonEmptyHeaps.empty())
410 			return tcu::TestStatus::pass("Pass");
411 		else
412 			allocateMore = false;
413 	}
414 	else if (!nonEmptyHeaps.empty() &&
415 			 !nonFullHeaps.empty() &&
416 			 (m_memoryObjectCount < MAX_ALLOCATION_COUNT) &&
417 			 canAllocateSys)
418 		allocateMore = m_rng.getBool(); // Randomize if both operations are doable.
419 	else if (nonEmptyHeaps.empty())
420 	{
421 		DE_ASSERT(canAllocateSys);
422 		allocateMore = true; // Allocate more if there are no objects to free.
423 	}
424 	else if (nonFullHeaps.empty() || !canAllocateSys)
425 		allocateMore = false; // Free objects if there is no free space for new objects.
426 	else
427 	{
428 		allocateMore = false;
429 		DE_FATAL("Fail");
430 	}
431 
432 	if (allocateMore)
433 	{
434 		const size_t		nonFullHeapNdx	= (size_t)(m_rng.getUint32() % (deUint32)nonFullHeaps.size());
435 		const size_t		heapNdx			= nonFullHeaps[nonFullHeapNdx];
436 		Heap&				heap			= m_heaps[heapNdx];
437 		const MemoryType&	memoryType		= m_rng.choose<MemoryType>(heap.types.begin(), heap.types.end());
438 		const bool			isDeviceLocal	= (heap.heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0;
439 		const VkDeviceSize	maxAllocSize	= (isDeviceLocal && !isUMA)
440 											? de::min(heap.maxMemoryUsage - heap.memoryUsage, (VkDeviceSize)m_memoryLimits.totalDeviceLocalMemory - m_totalDeviceMem)
441 											: de::min(heap.maxMemoryUsage - heap.memoryUsage, (VkDeviceSize)m_memoryLimits.totalSystemMemory - usedSysMem - m_allocSysMemSize);
442 		const VkDeviceSize	allocationSize	= 1 + (m_rng.getUint64() % maxAllocSize);
443 
444 		if ((allocationSize > (deUint64)(heap.maxMemoryUsage - heap.memoryUsage)) && (allocationSize != 1))
445 			TCU_THROW(InternalError, "Test Error: trying to allocate memory more than the available heap size.");
446 
447 		const MemoryObject object =
448 		{
449 			(VkDeviceMemory)0,
450 			allocationSize
451 		};
452 
453 		heap.objects.push_back(object);
454 
455 		const VkMemoryAllocateInfo alloc =
456 		{
457 			VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,	// sType
458 			DE_NULL,								// pNext
459 			object.size,							// allocationSize
460 			memoryType.index						// memoryTypeIndex;
461 		};
462 
463 		VK_CHECK(vkd.allocateMemory(device, &alloc, (const VkAllocationCallbacks*)DE_NULL, &heap.objects.back().memory));
464 		TCU_CHECK(!!heap.objects.back().memory);
465 		m_memoryObjectCount++;
466 
467 		heap.memoryUsage										+= allocationSize;
468 		(isDeviceLocal ? m_totalDeviceMem : m_totalSystemMem)	+= allocationSize;
469 		m_totalSystemMem										+= m_allocSysMemSize;
470 	}
471 	else
472 	{
473 		const size_t		nonEmptyHeapNdx	= (size_t)(m_rng.getUint32() % (deUint32)nonEmptyHeaps.size());
474 		const size_t		heapNdx			= nonEmptyHeaps[nonEmptyHeapNdx];
475 		Heap&				heap			= m_heaps[heapNdx];
476 		const size_t		memoryObjectNdx	= m_rng.getUint32() % heap.objects.size();
477 		MemoryObject&		memoryObject	= heap.objects[memoryObjectNdx];
478 		const bool			isDeviceLocal	= (heap.heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0;
479 
480 		vkd.freeMemory(device, memoryObject.memory, (const VkAllocationCallbacks*)DE_NULL);
481 		memoryObject.memory = (VkDeviceMemory)0;
482 		m_memoryObjectCount--;
483 
484 		heap.memoryUsage										-= memoryObject.size;
485 		(isDeviceLocal ? m_totalDeviceMem : m_totalSystemMem)	-= memoryObject.size;
486 		m_totalSystemMem										-= m_allocSysMemSize;
487 
488 		heap.objects[memoryObjectNdx] = heap.objects.back();
489 		heap.objects.pop_back();
490 
491 		DE_ASSERT(heap.memoryUsage == 0 || !heap.objects.empty());
492 	}
493 
494 	m_opNdx++;
495 	return tcu::TestStatus::incomplete();
496 }
497 
498 
499 } // anonymous
500 
createAllocationTests(tcu::TestContext & testCtx)501 tcu::TestCaseGroup* createAllocationTests (tcu::TestContext& testCtx)
502 {
503 	de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "allocation", "Memory allocation tests."));
504 
505 	const VkDeviceSize	KiB	= 1024;
506 	const VkDeviceSize	MiB	= 1024 * KiB;
507 
508 	const struct
509 	{
510 		const char* const	str;
511 		VkDeviceSize		size;
512 	} allocationSizes[] =
513 	{
514 		{   "64", 64 },
515 		{  "128", 128 },
516 		{  "256", 256 },
517 		{  "512", 512 },
518 		{ "1KiB", 1*KiB },
519 		{ "4KiB", 4*KiB },
520 		{ "8KiB", 8*KiB },
521 		{ "1MiB", 1*MiB }
522 	};
523 
524 	const int allocationPercents[] =
525 	{
526 		1
527 	};
528 
529 	const int allocationCounts[] =
530 	{
531 		1, 10, 100, 1000, -1
532 	};
533 
534 	const struct
535 	{
536 		const char* const		str;
537 		const TestConfig::Order	order;
538 	} orders[] =
539 	{
540 		{ "forward",	TestConfig::ALLOC_FREE },
541 		{ "reverse",	TestConfig::ALLOC_REVERSE_FREE },
542 		{ "mixed",		TestConfig::MIXED_ALLOC_FREE }
543 	};
544 
545 	{
546 		de::MovePtr<tcu::TestCaseGroup>	basicGroup	(new tcu::TestCaseGroup(testCtx, "basic", "Basic memory allocation and free tests"));
547 
548 		for (size_t allocationSizeNdx = 0; allocationSizeNdx < DE_LENGTH_OF_ARRAY(allocationSizes); allocationSizeNdx++)
549 		{
550 			const VkDeviceSize				allocationSize		= allocationSizes[allocationSizeNdx].size;
551 			const char* const				allocationSizeName	= allocationSizes[allocationSizeNdx].str;
552 			de::MovePtr<tcu::TestCaseGroup>	sizeGroup			(new tcu::TestCaseGroup(testCtx, ("size_" + string(allocationSizeName)).c_str(), ("Test different allocation sizes " + de::toString(allocationSize)).c_str()));
553 
554 			for (size_t orderNdx = 0; orderNdx < DE_LENGTH_OF_ARRAY(orders); orderNdx++)
555 			{
556 				const TestConfig::Order			order				= orders[orderNdx].order;
557 				const char* const				orderName			= orders[orderNdx].str;
558 				const char* const				orderDescription	= orderName;
559 				de::MovePtr<tcu::TestCaseGroup>	orderGroup			(new tcu::TestCaseGroup(testCtx, orderName, orderDescription));
560 
561 				for (size_t allocationCountNdx = 0; allocationCountNdx < DE_LENGTH_OF_ARRAY(allocationCounts); allocationCountNdx++)
562 				{
563 					const int allocationCount = allocationCounts[allocationCountNdx];
564 
565 					if (allocationCount != -1 && allocationCount * allocationSize > 50 * MiB)
566 						continue;
567 
568 					TestConfig config;
569 
570 					config.memorySize				= allocationSize;
571 					config.order					= order;
572 
573 					if (allocationCount == -1)
574 					{
575 						if (allocationSize < 4096)
576 							continue;
577 
578 						config.memoryAllocationCount	= de::min((deUint32)(50 * MiB / allocationSize), (deUint32)MAX_ALLOCATION_COUNT);
579 
580 						if (config.memoryAllocationCount == 0
581 							|| config.memoryAllocationCount == 1
582 							|| config.memoryAllocationCount == 10
583 							|| config.memoryAllocationCount == 100
584 							|| config.memoryAllocationCount == 1000)
585 						continue;
586 					}
587 					else
588 						config.memoryAllocationCount	= allocationCount;
589 
590 					orderGroup->addChild(new InstanceFactory1<AllocateFreeTestInstance, TestConfig>(testCtx, tcu::NODETYPE_SELF_VALIDATE, "count_" + de::toString(config.memoryAllocationCount), "", config));
591 				}
592 
593 				sizeGroup->addChild(orderGroup.release());
594 			}
595 
596 			basicGroup->addChild(sizeGroup.release());
597 		}
598 
599 		for (size_t allocationPercentNdx = 0; allocationPercentNdx < DE_LENGTH_OF_ARRAY(allocationPercents); allocationPercentNdx++)
600 		{
601 			const int						allocationPercent	= allocationPercents[allocationPercentNdx];
602 			de::MovePtr<tcu::TestCaseGroup>	percentGroup		(new tcu::TestCaseGroup(testCtx, ("percent_" + de::toString(allocationPercent)).c_str(), ("Test different allocation percents " + de::toString(allocationPercent)).c_str()));
603 
604 			for (size_t orderNdx = 0; orderNdx < DE_LENGTH_OF_ARRAY(orders); orderNdx++)
605 			{
606 				const TestConfig::Order			order				= orders[orderNdx].order;
607 				const char* const				orderName			= orders[orderNdx].str;
608 				const char* const				orderDescription	= orderName;
609 				de::MovePtr<tcu::TestCaseGroup>	orderGroup			(new tcu::TestCaseGroup(testCtx, orderName, orderDescription));
610 
611 				for (size_t allocationCountNdx = 0; allocationCountNdx < DE_LENGTH_OF_ARRAY(allocationCounts); allocationCountNdx++)
612 				{
613 					const int allocationCount = allocationCounts[allocationCountNdx];
614 
615 					if ((allocationCount != -1) && ((float)allocationCount * (float)allocationPercent >= 1.00f / 8.00f))
616 						continue;
617 
618 					TestConfig config;
619 
620 					config.memoryPercentage			= (float)allocationPercent / 100.0f;
621 					config.order					= order;
622 
623 					if (allocationCount == -1)
624 					{
625 						config.memoryAllocationCount	= de::min((deUint32)((1.00f / 8.00f) / ((float)allocationPercent / 100.0f)), (deUint32)MAX_ALLOCATION_COUNT);
626 
627 						if (config.memoryAllocationCount == 0
628 							|| config.memoryAllocationCount == 1
629 							|| config.memoryAllocationCount == 10
630 							|| config.memoryAllocationCount == 100
631 							|| config.memoryAllocationCount == 1000)
632 						continue;
633 					}
634 					else
635 						config.memoryAllocationCount	= allocationCount;
636 
637 					orderGroup->addChild(new InstanceFactory1<AllocateFreeTestInstance, TestConfig>(testCtx, tcu::NODETYPE_SELF_VALIDATE, "count_" + de::toString(config.memoryAllocationCount), "", config));
638 				}
639 
640 				percentGroup->addChild(orderGroup.release());
641 			}
642 
643 			basicGroup->addChild(percentGroup.release());
644 		}
645 
646 		group->addChild(basicGroup.release());
647 	}
648 
649 	{
650 		const deUint32					caseCount	= 100;
651 		de::MovePtr<tcu::TestCaseGroup>	randomGroup	(new tcu::TestCaseGroup(testCtx, "random", "Random memory allocation tests."));
652 
653 		for (deUint32 caseNdx = 0; caseNdx < caseCount; caseNdx++)
654 		{
655 			const deUint32 seed = deInt32Hash(caseNdx ^ 32480);
656 
657 			randomGroup->addChild(new InstanceFactory1<RandomAllocFreeTestInstance, deUint32>(testCtx, tcu::NODETYPE_SELF_VALIDATE, de::toString(caseNdx), "Random case", seed));
658 		}
659 
660 		group->addChild(randomGroup.release());
661 	}
662 
663 	return group.release();
664 }
665 
666 } // memory
667 } // vkt
668