#include "tcuMaybe.hpp"
#include "tcuResultCollector.hpp"
#include "tcuTestLog.hpp"
+#include "tcuPlatform.hpp"
#include "vkPlatform.hpp"
#include "vkStrUtil.hpp"
#include "vkRef.hpp"
#include "vkDeviceUtil.hpp"
#include "vkQueryUtil.hpp"
+#include "vkRefUtil.hpp"
+#include "vkAllocationCallbackUtil.hpp"
#include "deUniquePtr.hpp"
#include "deStringUtil.hpp"
{
namespace
{
+
enum
{
// The min max for allocation count is 4096. Use 4000 to take into account
return tcu::TestStatus(m_result.getResult(), m_result.getMessage());
}
+size_t computeDeviceMemorySystemMemFootprint (const DeviceInterface& vk, VkDevice device)
+{
+ AllocationCallbackRecorder callbackRecorder (getSystemAllocator());
+
+ {
+ // 1 B allocation from memory type 0
+ const VkMemoryAllocateInfo allocInfo =
+ {
+ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ DE_NULL,
+ 1u,
+ 0u,
+ };
+ const Unique<VkDeviceMemory> memory (allocateMemory(vk, device, &allocInfo));
+ AllocationCallbackValidationResults validateRes;
+
+ validateAllocationCallbacks(callbackRecorder, &validateRes);
+
+ TCU_CHECK(validateRes.violations.empty());
+
+ return getLiveSystemAllocationTotal(validateRes)
+ + sizeof(void*)*validateRes.liveAllocations.size(); // allocation overhead
+ }
+}
+
struct MemoryType
{
deUint32 index;
class RandomAllocFreeTestInstance : public TestInstance
{
public:
- RandomAllocFreeTestInstance (Context& context, deUint32 seed);
- ~RandomAllocFreeTestInstance (void);
+ RandomAllocFreeTestInstance (Context& context, deUint32 seed);
+ ~RandomAllocFreeTestInstance (void);
- tcu::TestStatus iterate (void);
+ tcu::TestStatus iterate (void);
private:
- const size_t m_opCount;
- deUint32 m_memoryObjectCount;
- size_t m_opNdx;
- de::Random m_rng;
- vector<Heap> m_heaps;
- vector<size_t> m_nonFullHeaps;
- vector<size_t> m_nonEmptyHeaps;
+ const size_t m_opCount;
+ const size_t m_allocSysMemSize;
+ const PlatformMemoryLimits m_memoryLimits;
+
+ deUint32 m_memoryObjectCount;
+ size_t m_opNdx;
+ de::Random m_rng;
+ vector<Heap> m_heaps;
+ VkDeviceSize m_totalSystemMem;
+ VkDeviceSize m_totalDeviceMem;
};
-RandomAllocFreeTestInstance::RandomAllocFreeTestInstance (Context& context, deUint32 seed)
+RandomAllocFreeTestInstance::RandomAllocFreeTestInstance (Context& context, deUint32 seed)
: TestInstance (context)
, m_opCount (128)
+ , m_allocSysMemSize (computeDeviceMemorySystemMemFootprint(context.getDeviceInterface(), context.getDevice())
+ + sizeof(MemoryObject))
+ , m_memoryLimits (getMemoryLimits(context.getTestContext().getPlatform().getVulkanPlatform()))
, m_memoryObjectCount (0)
, m_opNdx (0)
, m_rng (seed)
+ , m_totalSystemMem (0)
+ , m_totalDeviceMem (0)
{
const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
const InstanceInterface& vki = context.getInstanceInterface();
m_heaps.resize(memoryProperties.memoryHeapCount);
- m_nonFullHeaps.reserve(m_heaps.size());
- m_nonEmptyHeaps.reserve(m_heaps.size());
-
for (deUint32 heapNdx = 0; heapNdx < memoryProperties.memoryHeapCount; heapNdx++)
{
m_heaps[heapNdx].heap = memoryProperties.memoryHeaps[heapNdx];
m_heaps[heapNdx].memoryUsage = 0;
- m_heaps[heapNdx].maxMemoryUsage = m_heaps[heapNdx].heap.size / 8;
+ m_heaps[heapNdx].maxMemoryUsage = m_heaps[heapNdx].heap.size / 2; /* Use at maximum 50% of heap */
m_heaps[heapNdx].objects.reserve(100);
-
- m_nonFullHeaps.push_back((size_t)heapNdx);
}
for (deUint32 memoryTypeNdx = 0; memoryTypeNdx < memoryProperties.memoryTypeCount; memoryTypeNdx++)
const VkDevice device = m_context.getDevice();
const DeviceInterface& vkd = m_context.getDeviceInterface();
TestLog& log = m_context.getTestContext().getLog();
+ const bool isUMA = m_memoryLimits.totalDeviceLocalMemory == 0;
+ const VkDeviceSize usedSysMem = isUMA ? (m_totalDeviceMem+m_totalSystemMem) : m_totalSystemMem;
+ const bool canAllocateSys = usedSysMem + m_allocSysMemSize + 1024 < m_memoryLimits.totalSystemMemory; // \note Always leave room for 1 KiB sys mem alloc
+ const bool canAllocateDev = isUMA ? canAllocateSys : (m_totalDeviceMem + 16 < m_memoryLimits.totalDeviceLocalMemory);
+ vector<size_t> nonFullHeaps;
+ vector<size_t> nonEmptyHeaps;
bool allocateMore;
if (m_opNdx == 0)
log << TestLog::Message << "Using max 1/8 of the memory in each memory heap." << TestLog::EndMessage;
}
+ // Sort heaps based on whether allocations or frees are possible
+ for (size_t heapNdx = 0; heapNdx < m_heaps.size(); ++heapNdx)
+ {
+ const bool isDeviceLocal = (m_heaps[heapNdx].heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0;
+ const bool isHeapFull = m_heaps[heapNdx].memoryUsage >= m_heaps[heapNdx].maxMemoryUsage;
+ const bool isHeapEmpty = m_heaps[heapNdx].memoryUsage == 0;
+
+ if (!isHeapEmpty)
+ nonEmptyHeaps.push_back(heapNdx);
+
+ if (!isHeapFull && ((isUMA && canAllocateSys) ||
+ (!isUMA && isDeviceLocal && canAllocateDev) ||
+ (!isUMA && !isDeviceLocal && canAllocateSys)))
+ nonFullHeaps.push_back(heapNdx);
+ }
+
if (m_opNdx >= m_opCount)
{
- if (m_nonEmptyHeaps.empty())
+ if (nonEmptyHeaps.empty())
return tcu::TestStatus::pass("Pass");
else
allocateMore = false;
}
- else if (!m_nonEmptyHeaps.empty() && !m_nonFullHeaps.empty() && (m_memoryObjectCount < MAX_ALLOCATION_COUNT))
+ else if (!nonEmptyHeaps.empty() &&
+ !nonFullHeaps.empty() &&
+ (m_memoryObjectCount < MAX_ALLOCATION_COUNT) &&
+ canAllocateSys)
allocateMore = m_rng.getBool(); // Randomize if both operations are doable.
- else if (m_nonEmptyHeaps.empty())
+ else if (nonEmptyHeaps.empty())
+ {
+ DE_ASSERT(canAllocateSys);
allocateMore = true; // Allocate more if there are no objects to free.
- else if (m_nonFullHeaps.empty())
+ }
+ else if (nonFullHeaps.empty() || !canAllocateSys)
allocateMore = false; // Free objects if there is no free space for new objects.
else
{
if (allocateMore)
{
- const size_t nonFullHeapNdx = (size_t)(m_rng.getUint32() % (deUint32)m_nonFullHeaps.size());
- const size_t heapNdx = m_nonFullHeaps[nonFullHeapNdx];
+ const size_t nonFullHeapNdx = (size_t)(m_rng.getUint32() % (deUint32)nonFullHeaps.size());
+ const size_t heapNdx = nonFullHeaps[nonFullHeapNdx];
Heap& heap = m_heaps[heapNdx];
const MemoryType& memoryType = m_rng.choose<MemoryType>(heap.types.begin(), heap.types.end());
- const VkDeviceSize allocationSize = 1 + (m_rng.getUint64() % (deUint64)(heap.maxMemoryUsage - heap.memoryUsage));
-
+ const bool isDeviceLocal = (heap.heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0;
+ const VkDeviceSize maxAllocSize = (isDeviceLocal && !isUMA)
+ ? de::min(heap.maxMemoryUsage - heap.memoryUsage, (VkDeviceSize)m_memoryLimits.totalDeviceLocalMemory - m_totalDeviceMem)
+ : de::min(heap.maxMemoryUsage - heap.memoryUsage, (VkDeviceSize)m_memoryLimits.totalSystemMemory - usedSysMem - m_allocSysMemSize);
+ const VkDeviceSize allocationSize = 1 + (m_rng.getUint64() % maxAllocSize);
if ((allocationSize > (deUint64)(heap.maxMemoryUsage - heap.memoryUsage)) && (allocationSize != 1))
TCU_THROW(InternalError, "Test Error: trying to allocate memory more than the available heap size.");
-
const MemoryObject object =
{
(VkDeviceMemory)0,
TCU_CHECK(!!heap.objects.back().memory);
m_memoryObjectCount++;
- // If heap was empty add to the non empty heaps.
- if (heap.memoryUsage == 0)
- {
- DE_ASSERT(heap.objects.size() == 1);
- m_nonEmptyHeaps.push_back(heapNdx);
- }
- else
- DE_ASSERT(heap.objects.size() > 1);
-
- heap.memoryUsage += allocationSize;
-
- // If heap became full, remove from non full heaps.
- if (heap.memoryUsage >= heap.maxMemoryUsage)
- {
- m_nonFullHeaps[nonFullHeapNdx] = m_nonFullHeaps.back();
- m_nonFullHeaps.pop_back();
- }
+ heap.memoryUsage += allocationSize;
+ (isDeviceLocal ? m_totalDeviceMem : m_totalSystemMem) += allocationSize;
+ m_totalSystemMem += m_allocSysMemSize;
}
else
{
- const size_t nonEmptyHeapNdx = (size_t)(m_rng.getUint32() % (deUint32)m_nonEmptyHeaps.size());
- const size_t heapNdx = m_nonEmptyHeaps[nonEmptyHeapNdx];
+ const size_t nonEmptyHeapNdx = (size_t)(m_rng.getUint32() % (deUint32)nonEmptyHeaps.size());
+ const size_t heapNdx = nonEmptyHeaps[nonEmptyHeapNdx];
Heap& heap = m_heaps[heapNdx];
const size_t memoryObjectNdx = m_rng.getUint32() % heap.objects.size();
MemoryObject& memoryObject = heap.objects[memoryObjectNdx];
+ const bool isDeviceLocal = (heap.heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0;
vkd.freeMemory(device, memoryObject.memory, (const VkAllocationCallbacks*)DE_NULL);
memoryObject.memory = (VkDeviceMemory)0;
m_memoryObjectCount--;
- if (heap.memoryUsage >= heap.maxMemoryUsage && heap.memoryUsage - memoryObject.size < heap.maxMemoryUsage)
- m_nonFullHeaps.push_back(heapNdx);
-
- heap.memoryUsage -= memoryObject.size;
+ heap.memoryUsage -= memoryObject.size;
+ (isDeviceLocal ? m_totalDeviceMem : m_totalSystemMem) -= memoryObject.size;
+ m_totalSystemMem -= m_allocSysMemSize;
heap.objects[memoryObjectNdx] = heap.objects.back();
heap.objects.pop_back();
- if (heap.memoryUsage == 0)
- {
- DE_ASSERT(heap.objects.empty());
-
- m_nonEmptyHeaps[nonEmptyHeapNdx] = m_nonEmptyHeaps.back();
- m_nonEmptyHeaps.pop_back();
- }
- else
- DE_ASSERT(!heap.objects.empty());
+ DE_ASSERT(heap.memoryUsage == 0 || !heap.objects.empty());
}
m_opNdx++;
#include "tcuMaybe.hpp"
#include "tcuResultCollector.hpp"
#include "tcuTestLog.hpp"
+#include "tcuPlatform.hpp"
#include "vkDeviceUtil.hpp"
#include "vkPlatform.hpp"
#include "vkQueryUtil.hpp"
#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
#include "vkStrUtil.hpp"
+#include "vkAllocationCallbackUtil.hpp"
#include "deRandom.hpp"
#include "deSharedPtr.hpp"
#include "deStringUtil.hpp"
#include "deUniquePtr.hpp"
+#include "deSTLUtil.hpp"
#include <string>
#include <vector>
+#include <algorithm>
using tcu::Maybe;
using tcu::TestLog;
{
namespace memory
{
+
namespace
{
+
+size_t computeDeviceMemorySystemMemFootprint (const DeviceInterface& vk, VkDevice device)
+{
+ AllocationCallbackRecorder callbackRecorder (getSystemAllocator());
+
+ {
+ // 1 B allocation from memory type 0
+ const VkMemoryAllocateInfo allocInfo =
+ {
+ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+ DE_NULL,
+ 1u,
+ 0u,
+ };
+ const Unique<VkDeviceMemory> memory (allocateMemory(vk, device, &allocInfo));
+ AllocationCallbackValidationResults validateRes;
+
+ validateAllocationCallbacks(callbackRecorder, &validateRes);
+
+ TCU_CHECK(validateRes.violations.empty());
+
+ return getLiveSystemAllocationTotal(validateRes)
+ + sizeof(void*)*validateRes.liveAllocations.size(); // allocation overhead
+ }
+}
+
Move<VkDeviceMemory> allocMemory (const DeviceInterface& vk, VkDevice device, VkDeviceSize pAllocInfo_allocationSize, deUint32 pAllocInfo_memoryTypeIndex)
{
- VkDeviceMemory object = 0;
const VkMemoryAllocateInfo pAllocInfo =
{
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
pAllocInfo_allocationSize,
pAllocInfo_memoryTypeIndex,
};
- VK_CHECK(vk.allocateMemory(device, &pAllocInfo, (const VkAllocationCallbacks*)DE_NULL, &object));
- return Move<VkDeviceMemory>(check<VkDeviceMemory>(object), Deleter<VkDeviceMemory>(vk, device, (const VkAllocationCallbacks*)DE_NULL));
+ return allocateMemory(vk, device, &pAllocInfo);
}
struct MemoryRange
enum
{
- // Use only 1/16 of each memory heap.
- MAX_MEMORY_USAGE_DIV = 16
+ // Use only 1/2 of each memory heap.
+ MAX_MEMORY_USAGE_DIV = 2
};
template<typename T>
}
}
+enum MemoryClass
+{
+ MEMORY_CLASS_SYSTEM = 0,
+ MEMORY_CLASS_DEVICE,
+
+ MEMORY_CLASS_LAST
+};
+
+// \todo [2016-04-20 pyry] Consider estimating memory fragmentation
+class TotalMemoryTracker
+{
+public:
+ TotalMemoryTracker (void)
+ {
+ std::fill(DE_ARRAY_BEGIN(m_usage), DE_ARRAY_END(m_usage), 0);
+ }
+
+ void allocate (MemoryClass memClass, VkDeviceSize size)
+ {
+ m_usage[memClass] += size;
+ }
+
+ void free (MemoryClass memClass, VkDeviceSize size)
+ {
+ DE_ASSERT(size <= m_usage[memClass]);
+ m_usage[memClass] -= size;
+ }
+
+ VkDeviceSize getUsage (MemoryClass memClass) const
+ {
+ return m_usage[memClass];
+ }
+
+ VkDeviceSize getTotalUsage (void) const
+ {
+ VkDeviceSize total = 0;
+ for (int ndx = 0; ndx < MEMORY_CLASS_LAST; ++ndx)
+ total += getUsage((MemoryClass)ndx);
+ return total;
+ }
+
+private:
+ VkDeviceSize m_usage[MEMORY_CLASS_LAST];
+};
+
class MemoryHeap
{
public:
MemoryHeap (const VkMemoryHeap& heap,
- const vector<deUint32>& memoryTypes)
- : m_heap (heap)
- , m_memoryTypes (memoryTypes)
- , m_usage (0)
+ const vector<deUint32>& memoryTypes,
+ const PlatformMemoryLimits& memoryLimits,
+ TotalMemoryTracker& totalMemTracker)
+ : m_heap (heap)
+ , m_memoryTypes (memoryTypes)
+ , m_limits (memoryLimits)
+ , m_totalMemTracker (totalMemTracker)
+ , m_usage (0)
{
}
delete *iter;
}
- bool full (void) const { return m_usage * MAX_MEMORY_USAGE_DIV >= m_heap.size; }
- bool empty (void) const { return m_usage == 0; }
+ bool full (void) const { return getAvailableMem() == 0; }
+ bool empty (void) const { return m_usage == 0; }
MemoryObject* allocateRandom (const DeviceInterface& vkd, VkDevice device, de::Random& rng)
{
- const VkDeviceSize size = 1 + (rng.getUint64() % (de::max((deInt64)((m_heap.size / MAX_MEMORY_USAGE_DIV) - m_usage - 1ull), (deInt64)1)));
- const deUint32 type = rng.choose<deUint32>(m_memoryTypes.begin(), m_memoryTypes.end());
+ const VkDeviceSize availableMem = getAvailableMem();
+
+ DE_ASSERT(availableMem > 0);
- if ( (size > (VkDeviceSize)((m_heap.size / MAX_MEMORY_USAGE_DIV) - m_usage)) && (size != 1))
- TCU_THROW(InternalError, "Test Error: trying to allocate memory more than the available heap size.");
+ const VkDeviceSize size = 1ull + (rng.getUint64() % availableMem);
+ const deUint32 type = rng.choose<deUint32>(m_memoryTypes.begin(), m_memoryTypes.end());
+
+ DE_ASSERT(size <= availableMem);
MemoryObject* const object = new MemoryObject(vkd, device, size, type);
m_usage += size;
+ m_totalMemTracker.allocate(getMemoryClass(), size);
m_objects.push_back(object);
return object;
{
removeFirstEqual(m_objects, object);
m_usage -= object->getSize();
+ m_totalMemTracker.free(getMemoryClass(), object->getSize());
delete object;
}
private:
- VkMemoryHeap m_heap;
- vector<deUint32> m_memoryTypes;
+ MemoryClass getMemoryClass (void) const
+ {
+ if ((m_heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
+ return MEMORY_CLASS_DEVICE;
+ else
+ return MEMORY_CLASS_SYSTEM;
+ }
- VkDeviceSize m_usage;
- vector<MemoryObject*> m_objects;
+ VkDeviceSize getAvailableMem (void) const
+ {
+ DE_ASSERT(m_usage <= m_heap.size/MAX_MEMORY_USAGE_DIV);
+
+ const VkDeviceSize availableInHeap = m_heap.size/MAX_MEMORY_USAGE_DIV - m_usage;
+ const bool isUMA = m_limits.totalDeviceLocalMemory == 0;
+
+ if (isUMA)
+ {
+ const VkDeviceSize totalUsage = m_totalMemTracker.getTotalUsage();
+ const VkDeviceSize totalSysMem = (VkDeviceSize)m_limits.totalSystemMemory;
+
+ DE_ASSERT(totalUsage <= totalSysMem);
+
+ return de::min(availableInHeap, totalSysMem-totalUsage);
+ }
+ else
+ {
+ const MemoryClass memClass = getMemoryClass();
+ const VkDeviceSize totalMemClass = memClass == MEMORY_CLASS_SYSTEM
+ ? (VkDeviceSize)m_limits.totalSystemMemory
+ : m_limits.totalDeviceLocalMemory;
+ const VkDeviceSize usedMemClass = m_totalMemTracker.getUsage(memClass);
+
+ DE_ASSERT(usedMemClass <= totalMemClass);
+
+ return de::min(availableInHeap, totalMemClass-usedMemClass);
+ }
+ }
+
+ const VkMemoryHeap m_heap;
+ const vector<deUint32> m_memoryTypes;
+ const PlatformMemoryLimits& m_limits;
+ TotalMemoryTracker& m_totalMemTracker;
+
+ VkDeviceSize m_usage;
+ vector<MemoryObject*> m_objects;
};
+size_t getMemoryObjectSystemSize (Context& context)
+{
+ return computeDeviceMemorySystemMemFootprint(context.getDeviceInterface(), context.getDevice())
+ + sizeof(MemoryObject)
+ + sizeof(de::SharedPtr<MemoryObject>);
+}
+
+size_t getMemoryMappingSystemSize (void)
+{
+ return sizeof(MemoryMapping) + sizeof(de::SharedPtr<MemoryMapping>);
+}
+
class RandomMemoryMappingInstance : public TestInstance
{
public:
RandomMemoryMappingInstance (Context& context, deUint32 seed)
- : TestInstance (context)
- , m_rng (seed)
- , m_opNdx (0)
+ : TestInstance (context)
+ , m_memoryObjectSysMemSize (getMemoryObjectSystemSize(context))
+ , m_memoryMappingSysMemSize (getMemoryMappingSystemSize())
+ , m_memoryLimits (getMemoryLimits(context.getTestContext().getPlatform().getVulkanPlatform()))
+ , m_rng (seed)
+ , m_opNdx (0)
{
const VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
const InstanceInterface& vki = context.getInstanceInterface();
if (!memoryTypes[heapIndex].empty())
{
- const de::SharedPtr<MemoryHeap> heap (new MemoryHeap(heapInfo, memoryTypes[heapIndex]));
+ const de::SharedPtr<MemoryHeap> heap (new MemoryHeap(heapInfo, memoryTypes[heapIndex], m_memoryLimits, m_totalMemTracker));
- if (!heap->full())
- m_nonFullHeaps.push_back(heap);
+ TCU_CHECK_INTERNAL(!heap->full());
+
+ m_memoryHeaps.push_back(heap);
}
}
}
const VkDevice device = m_context.getDevice();
const DeviceInterface& vkd = m_context.getDeviceInterface();
- if (m_opNdx < opCount)
+ const VkDeviceSize sysMemUsage = (m_memoryLimits.totalDeviceLocalMemory == 0)
+ ? m_totalMemTracker.getTotalUsage()
+ : m_totalMemTracker.getUsage(MEMORY_CLASS_SYSTEM);
+
+ if (!m_memoryMappings.empty() && m_rng.getFloat() < memoryOpProbability)
{
- if (!m_memoryMappings.empty() && m_rng.getFloat() < memoryOpProbability)
- {
- // Perform operations on mapped memory
- MemoryMapping* const mapping = m_rng.choose<MemoryMapping*>(m_memoryMappings.begin(), m_memoryMappings.end());
+ // Perform operations on mapped memory
+ MemoryMapping* const mapping = m_rng.choose<MemoryMapping*>(m_memoryMappings.begin(), m_memoryMappings.end());
- enum Op
- {
- OP_READ = 0,
- OP_WRITE,
- OP_MODIFY,
- OP_LAST
- };
+ enum Op
+ {
+ OP_READ = 0,
+ OP_WRITE,
+ OP_MODIFY,
+ OP_LAST
+ };
- const Op op = (Op)(m_rng.getUint32() % OP_LAST);
+ const Op op = (Op)(m_rng.getUint32() % OP_LAST);
- switch (op)
- {
- case OP_READ:
- mapping->randomRead(m_rng);
- break;
+ switch (op)
+ {
+ case OP_READ:
+ mapping->randomRead(m_rng);
+ break;
- case OP_WRITE:
- mapping->randomWrite(m_rng);
- break;
+ case OP_WRITE:
+ mapping->randomWrite(m_rng);
+ break;
- case OP_MODIFY:
- mapping->randomModify(m_rng);
- break;
+ case OP_MODIFY:
+ mapping->randomModify(m_rng);
+ break;
- default:
- DE_FATAL("Invalid operation");
- }
+ default:
+ DE_FATAL("Invalid operation");
}
- else if (!m_mappedMemoryObjects.empty() && m_rng.getFloat() < flushInvalidateProbability)
- {
- MemoryObject* const object = m_rng.choose<MemoryObject*>(m_mappedMemoryObjects.begin(), m_mappedMemoryObjects.end());
+ }
+ else if (!m_mappedMemoryObjects.empty() && m_rng.getFloat() < flushInvalidateProbability)
+ {
+ MemoryObject* const object = m_rng.choose<MemoryObject*>(m_mappedMemoryObjects.begin(), m_mappedMemoryObjects.end());
- if (m_rng.getBool())
- object->randomFlush(vkd, device, m_rng);
- else
- object->randomInvalidate(vkd, device, m_rng);
- }
- else if (!m_mappedMemoryObjects.empty() && m_rng.getFloat() < unmapProbability)
- {
- // Unmap memory object
- MemoryObject* const object = m_rng.choose<MemoryObject*>(m_mappedMemoryObjects.begin(), m_mappedMemoryObjects.end());
+ if (m_rng.getBool())
+ object->randomFlush(vkd, device, m_rng);
+ else
+ object->randomInvalidate(vkd, device, m_rng);
+ }
+ else if (!m_mappedMemoryObjects.empty() && m_rng.getFloat() < unmapProbability)
+ {
+ // Unmap memory object
+ MemoryObject* const object = m_rng.choose<MemoryObject*>(m_mappedMemoryObjects.begin(), m_mappedMemoryObjects.end());
- // Remove mapping
- removeFirstEqual(m_memoryMappings, object->getMapping());
+ // Remove mapping
+ removeFirstEqual(m_memoryMappings, object->getMapping());
- object->unmap();
- removeFirstEqual(m_mappedMemoryObjects, object);
- m_nonMappedMemoryObjects.push_back(object);
- }
- else if (!m_nonMappedMemoryObjects.empty() && m_rng.getFloat() < mapProbability)
+ object->unmap();
+ removeFirstEqual(m_mappedMemoryObjects, object);
+ m_nonMappedMemoryObjects.push_back(object);
+
+ m_totalMemTracker.free(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryMappingSysMemSize);
+ }
+ else if (!m_nonMappedMemoryObjects.empty() &&
+ (m_rng.getFloat() < mapProbability) &&
+ (sysMemUsage+m_memoryMappingSysMemSize <= (VkDeviceSize)m_memoryLimits.totalSystemMemory))
+ {
+ // Map memory object
+ MemoryObject* const object = m_rng.choose<MemoryObject*>(m_nonMappedMemoryObjects.begin(), m_nonMappedMemoryObjects.end());
+ MemoryMapping* mapping = object->mapRandom(vkd, device, m_rng);
+
+ m_memoryMappings.push_back(mapping);
+ m_mappedMemoryObjects.push_back(object);
+ removeFirstEqual(m_nonMappedMemoryObjects, object);
+
+ m_totalMemTracker.allocate(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryMappingSysMemSize);
+ }
+ else
+ {
+ // Sort heaps based on capacity (full or not)
+ vector<MemoryHeap*> nonFullHeaps;
+ vector<MemoryHeap*> nonEmptyHeaps;
+
+ if (sysMemUsage+m_memoryObjectSysMemSize <= (VkDeviceSize)m_memoryLimits.totalSystemMemory)
{
- // Map memory object
- MemoryObject* const object = m_rng.choose<MemoryObject*>(m_nonMappedMemoryObjects.begin(), m_nonMappedMemoryObjects.end());
- MemoryMapping* mapping = object->mapRandom(vkd, device, m_rng);
+ // For the duration of sorting reserve MemoryObject space from system memory
+ m_totalMemTracker.allocate(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryObjectSysMemSize);
- m_memoryMappings.push_back(mapping);
- m_mappedMemoryObjects.push_back(object);
- removeFirstEqual(m_nonMappedMemoryObjects, object);
+ for (vector<de::SharedPtr<MemoryHeap> >::const_iterator heapIter = m_memoryHeaps.begin();
+ heapIter != m_memoryHeaps.end();
+ ++heapIter)
+ {
+ if (!(*heapIter)->full())
+ nonFullHeaps.push_back(heapIter->get());
+
+ if (!(*heapIter)->empty())
+ nonEmptyHeaps.push_back(heapIter->get());
+ }
+
+ m_totalMemTracker.free(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryObjectSysMemSize);
}
else
{
- if (!m_nonFullHeaps.empty() && (m_nonEmptyHeaps.empty() || m_rng.getFloat() < allocProbability))
+ // Not possible to even allocate MemoryObject from system memory, look for non-empty heaps
+ for (vector<de::SharedPtr<MemoryHeap> >::const_iterator heapIter = m_memoryHeaps.begin();
+ heapIter != m_memoryHeaps.end();
+ ++heapIter)
{
- // Allocate more memory objects
- de::SharedPtr<MemoryHeap> const heap = m_rng.choose<de::SharedPtr<MemoryHeap> >(m_nonFullHeaps.begin(), m_nonFullHeaps.end());
+ if (!(*heapIter)->empty())
+ nonEmptyHeaps.push_back(heapIter->get());
+ }
+ }
- if (heap->empty())
- m_nonEmptyHeaps.push_back(heap);
+ if (!nonFullHeaps.empty() && (nonEmptyHeaps.empty() || m_rng.getFloat() < allocProbability))
+ {
+ // Reserve MemoryObject from sys mem first
+ m_totalMemTracker.allocate(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryObjectSysMemSize);
- {
- MemoryObject* const object = heap->allocateRandom(vkd, device, m_rng);
+ // Allocate more memory objects
+ MemoryHeap* const heap = m_rng.choose<MemoryHeap*>(nonFullHeaps.begin(), nonFullHeaps.end());
+ MemoryObject* const object = heap->allocateRandom(vkd, device, m_rng);
- if (heap->full())
- removeFirstEqual(m_nonFullHeaps, heap);
+ m_nonMappedMemoryObjects.push_back(object);
+ }
+ else
+ {
+ // Free memory objects
+ MemoryHeap* const heap = m_rng.choose<MemoryHeap*>(nonEmptyHeaps.begin(), nonEmptyHeaps.end());
+ MemoryObject* const object = heap->getRandomObject(m_rng);
- m_nonMappedMemoryObjects.push_back(object);
- }
- }
- else
+ // Remove mapping
+ if (object->getMapping())
{
- // Free memory objects
- de::SharedPtr<MemoryHeap> const heap = m_rng.choose<de::SharedPtr<MemoryHeap> >(m_nonEmptyHeaps.begin(), m_nonEmptyHeaps.end());
- MemoryObject* const object = heap->getRandomObject(m_rng);
-
- // Remove mapping
- if (object->getMapping())
- removeFirstEqual(m_memoryMappings, object->getMapping());
-
- removeFirstEqual(m_mappedMemoryObjects, object);
- removeFirstEqual(m_nonMappedMemoryObjects, object);
-
- if (heap->full())
- m_nonFullHeaps.push_back(heap);
+ removeFirstEqual(m_memoryMappings, object->getMapping());
+ m_totalMemTracker.free(MEMORY_CLASS_SYSTEM, m_memoryMappingSysMemSize);
+ }
- heap->free(object);
+ removeFirstEqual(m_mappedMemoryObjects, object);
+ removeFirstEqual(m_nonMappedMemoryObjects, object);
- if (heap->empty())
- removeFirstEqual(m_nonEmptyHeaps, heap);
- }
+ heap->free(object);
+ m_totalMemTracker.free(MEMORY_CLASS_SYSTEM, (VkDeviceSize)m_memoryObjectSysMemSize);
}
-
- m_opNdx++;
- return tcu::TestStatus::incomplete();
}
- else
+
+ m_opNdx += 1;
+ if (m_opNdx == opCount)
return tcu::TestStatus::pass("Pass");
+ else
+ return tcu::TestStatus::incomplete();
}
private:
+ const size_t m_memoryObjectSysMemSize;
+ const size_t m_memoryMappingSysMemSize;
+ const PlatformMemoryLimits m_memoryLimits;
+
de::Random m_rng;
size_t m_opNdx;
- vector<de::SharedPtr<MemoryHeap> > m_nonEmptyHeaps;
- vector<de::SharedPtr<MemoryHeap> > m_nonFullHeaps;
+ TotalMemoryTracker m_totalMemTracker;
+ vector<de::SharedPtr<MemoryHeap> > m_memoryHeaps;
vector<MemoryObject*> m_mappedMemoryObjects;
vector<MemoryObject*> m_nonMappedMemoryObjects;