794bcfdb1a19e9fc01bbf33721e07adee614d73c
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / memory / vktMemoryAllocationTests.cpp
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 / 8; /* Use at maximum 12.5% 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