From: Mika Isojärvi Date: Tue, 7 Jun 2016 19:39:37 +0000 (-0700) Subject: Improve memory tracking in vulkan memory mapping tests X-Git-Tag: upstream/0.1.0~783^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=99dd4eb6207dcdbe322319e89ee12aa2d047f4a5;p=platform%2Fupstream%2FVK-GL-CTS.git Improve memory tracking in vulkan memory mapping tests - Round up allocation size to multiple of page size for memory usage tracking. - Update reference memory usage tracking to follow new reference memory implementation. Change-Id: I219c2b3abe0ee0731f5a7e2bb44492e5b85b95c2 --- diff --git a/external/vulkancts/modules/vulkan/memory/vktMemoryMappingTests.cpp b/external/vulkancts/modules/vulkan/memory/vktMemoryMappingTests.cpp index 6b6e546..74aee73 100644 --- a/external/vulkancts/modules/vulkan/memory/vktMemoryMappingTests.cpp +++ b/external/vulkancts/modules/vulkan/memory/vktMemoryMappingTests.cpp @@ -55,6 +55,7 @@ using de::SharedPtr; using std::string; using std::vector; +using std::pair; using namespace vk; @@ -64,11 +65,6 @@ namespace memory { namespace { -enum -{ - REFERENCE_BYTES_PER_BYTE = 2 -}; - template T divRoundUp (const T& a, const T& b) { @@ -81,6 +77,12 @@ T roundDownToMultiple (const T& a, const T& b) return b * (a / b); } +template +T roundUpToMultiple (const T& a, const T& b) +{ + return b * (a / b + (a % b != 0 ? 1 : 0)); +} + // \note Bit vector that guarantees that each value takes only one bit. // std::vector is often optimized to only take one bit for each bool, but // that is implementation detail and in this case we really need to known how much @@ -671,23 +673,27 @@ void randomRanges (de::Random& rng, vector& ranges, size_t class MemoryObject { public: - MemoryObject (const DeviceInterface& vkd, - VkDevice device, - VkDeviceSize size, - deUint32 memoryTypeIndex, - VkDeviceSize atomSize); + MemoryObject (const DeviceInterface& vkd, + VkDevice device, + VkDeviceSize size, + deUint32 memoryTypeIndex, + VkDeviceSize atomSize, + VkDeviceSize memoryUsage, + VkDeviceSize referenceMemoryUsage); - ~MemoryObject (void); + ~MemoryObject (void); - MemoryMapping* mapRandom (const DeviceInterface& vkd, VkDevice device, de::Random& rng); - void unmap (void); + MemoryMapping* mapRandom (const DeviceInterface& vkd, VkDevice device, de::Random& rng); + void unmap (void); - void randomFlush (const DeviceInterface& vkd, VkDevice device, de::Random& rng); - void randomInvalidate (const DeviceInterface& vkd, VkDevice device, de::Random& rng); + void randomFlush (const DeviceInterface& vkd, VkDevice device, de::Random& rng); + void randomInvalidate (const DeviceInterface& vkd, VkDevice device, de::Random& rng); - VkDeviceSize getSize (void) const { return m_size; } - MemoryMapping* getMapping (void) { return m_mapping; } + VkDeviceSize getSize (void) const { return m_size; } + MemoryMapping* getMapping (void) { return m_mapping; } + VkDeviceSize getMemoryUsage (void) const { return m_memoryUsage; } + VkDeviceSize getReferenceMemoryUsage (void) const { return m_referenceMemoryUsage; } private: const DeviceInterface& m_vkd; const VkDevice m_device; @@ -695,6 +701,8 @@ private: const deUint32 m_memoryTypeIndex; const VkDeviceSize m_size; const VkDeviceSize m_atomSize; + const VkDeviceSize m_memoryUsage; + const VkDeviceSize m_referenceMemoryUsage; Move m_memory; @@ -706,14 +714,18 @@ MemoryObject::MemoryObject (const DeviceInterface& vkd, VkDevice device, VkDeviceSize size, deUint32 memoryTypeIndex, - VkDeviceSize atomSize) - : m_vkd (vkd) - , m_device (device) - , m_memoryTypeIndex (memoryTypeIndex) - , m_size (size) - , m_atomSize (atomSize) - , m_mapping (DE_NULL) - , m_referenceMemory ((size_t)size, (size_t)m_atomSize) + VkDeviceSize atomSize, + VkDeviceSize memoryUsage, + VkDeviceSize referenceMemoryUsage) + : m_vkd (vkd) + , m_device (device) + , m_memoryTypeIndex (memoryTypeIndex) + , m_size (size) + , m_atomSize (atomSize) + , m_memoryUsage (memoryUsage) + , m_referenceMemoryUsage (referenceMemoryUsage) + , m_mapping (DE_NULL) + , m_referenceMemory ((size_t)size, (size_t)m_atomSize) { m_memory = allocMemory(m_vkd, m_device, m_size, m_memoryTypeIndex); } @@ -837,6 +849,22 @@ private: VkDeviceSize m_usage[MEMORY_CLASS_LAST]; }; +VkDeviceSize getHostPageSize (void) +{ + return 4096; +} + +VkDeviceSize getMinAtomSize (VkDeviceSize nonCoherentAtomSize, const vector& memoryTypes) +{ + for (size_t ndx = 0; ndx < memoryTypes.size(); ndx++) + { + if ((memoryTypes[ndx].type.propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0) + return 1; + } + + return nonCoherentAtomSize; +} + class MemoryHeap { public: @@ -849,6 +877,7 @@ public: , m_memoryTypes (memoryTypes) , m_limits (memoryLimits) , m_nonCoherentAtomSize (nonCoherentAtomSize) + , m_minAtomSize (getMinAtomSize(nonCoherentAtomSize, memoryTypes)) , m_totalMemTracker (totalMemTracker) , m_usage (0) { @@ -860,33 +889,14 @@ public: delete *iter; } - bool full (void) const { return getAvailableMem() < m_nonCoherentAtomSize * (1 + REFERENCE_BYTES_PER_BYTE); } - bool empty (void) const { return m_usage == 0; } - - MemoryObject* allocateRandom (const DeviceInterface& vkd, VkDevice device, de::Random& rng) + bool full (void) const; + bool empty (void) const { - const VkDeviceSize availableMem = getAvailableMem(); - - DE_ASSERT(availableMem > 0); - - const MemoryType type = rng.choose(m_memoryTypes.begin(), m_memoryTypes.end()); - const VkDeviceSize atomSize = (type.type.propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0 - ? 1 - : m_nonCoherentAtomSize; - const VkDeviceSize size = randomSize(rng, atomSize, availableMem); - - DE_ASSERT(size <= availableMem); - - MemoryObject* const object = new MemoryObject(vkd, device, size, type.index, atomSize); - - m_usage += size; - m_totalMemTracker.allocate(getMemoryClass(), size); - m_totalMemTracker.allocate(MEMORY_CLASS_SYSTEM, size * REFERENCE_BYTES_PER_BYTE); - m_objects.push_back(object); - - return object; + return m_usage == 0 && !full(); } + MemoryObject* allocateRandom (const DeviceInterface& vkd, VkDevice device, de::Random& rng); + MemoryObject* getRandomObject (de::Random& rng) const { return rng.choose(m_objects.begin(), m_objects.end()); @@ -895,9 +905,9 @@ public: void free (MemoryObject* object) { removeFirstEqual(m_objects, object); - m_usage -= object->getSize(); - m_totalMemTracker.free(MEMORY_CLASS_SYSTEM, object->getSize() * REFERENCE_BYTES_PER_BYTE); - m_totalMemTracker.free(getMemoryClass(), object->getSize()); + m_usage -= object->getMemoryUsage(); + m_totalMemTracker.free(MEMORY_CLASS_SYSTEM, object->getReferenceMemoryUsage()); + m_totalMemTracker.free(getMemoryClass(), object->getMemoryUsage()); delete object; } @@ -910,48 +920,173 @@ private: return MEMORY_CLASS_SYSTEM; } - VkDeviceSize getAvailableMem (void) const + const VkMemoryHeap m_heap; + const vector m_memoryTypes; + const PlatformMemoryLimits& m_limits; + const VkDeviceSize m_nonCoherentAtomSize; + const VkDeviceSize m_minAtomSize; + TotalMemoryTracker& m_totalMemTracker; + + VkDeviceSize m_usage; + vector m_objects; +}; + +// Heap is full if there is not enough memory to allocate minimal memory object. +bool MemoryHeap::full (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; + const MemoryClass memClass = getMemoryClass(); + const VkDeviceSize minAllocationSize = de::max(m_minAtomSize, memClass == MEMORY_CLASS_DEVICE ? m_limits.devicePageSize : getHostPageSize()); + // Memory required for reference. One byte and one bit for each byte and one bit per each m_atomSize. + const VkDeviceSize minReferenceSize = minAllocationSize + + divRoundUp(minAllocationSize, 8) + + divRoundUp(minAllocationSize, m_minAtomSize * 8); + + if (isUMA) { - DE_ASSERT(m_usage <= m_heap.size/MAX_MEMORY_USAGE_DIV); + const VkDeviceSize totalUsage = m_totalMemTracker.getTotalUsage(); + const VkDeviceSize totalSysMem = (VkDeviceSize)m_limits.totalSystemMemory; - const VkDeviceSize availableInHeap = m_heap.size/MAX_MEMORY_USAGE_DIV - m_usage; - const bool isUMA = m_limits.totalDeviceLocalMemory == 0; + DE_ASSERT(totalUsage <= totalSysMem); - if (isUMA) - { - const VkDeviceSize totalUsage = m_totalMemTracker.getTotalUsage(); - const VkDeviceSize totalSysMem = (VkDeviceSize)m_limits.totalSystemMemory; + return (minAllocationSize + minReferenceSize) > (totalSysMem - totalUsage) + || minAllocationSize > availableInHeap; + } + else + { + const VkDeviceSize totalUsage = m_totalMemTracker.getTotalUsage(); + const VkDeviceSize totalSysMem = (VkDeviceSize)m_limits.totalSystemMemory; - DE_ASSERT(totalUsage <= totalSysMem); + const VkDeviceSize totalMemClass = memClass == MEMORY_CLASS_SYSTEM + ? m_limits.totalSystemMemory + : m_limits.totalDeviceLocalMemory; + const VkDeviceSize usedMemClass = m_totalMemTracker.getUsage(memClass); - return de::min(availableInHeap, (totalSysMem-totalUsage) / (1 + REFERENCE_BYTES_PER_BYTE)); - } - else - { - const VkDeviceSize totalUsage = m_totalMemTracker.getTotalUsage(); - const VkDeviceSize totalSysMem = (VkDeviceSize)m_limits.totalSystemMemory; + DE_ASSERT(usedMemClass <= totalMemClass); - const MemoryClass memClass = getMemoryClass(); - const VkDeviceSize totalMemClass = memClass == MEMORY_CLASS_SYSTEM - ? (VkDeviceSize)(m_limits.totalSystemMemory / (1 + REFERENCE_BYTES_PER_BYTE)) - : m_limits.totalDeviceLocalMemory; - const VkDeviceSize usedMemClass = m_totalMemTracker.getUsage(memClass); + return minAllocationSize > availableInHeap + || minAllocationSize > (totalMemClass - usedMemClass) + || minReferenceSize > (totalSysMem - totalUsage); + } +} - DE_ASSERT(usedMemClass <= totalMemClass); +MemoryObject* MemoryHeap::allocateRandom (const DeviceInterface& vkd, VkDevice device, de::Random& rng) +{ + pair memoryTypeMaxSizePair; - return de::min(de::min(availableInHeap, totalMemClass-usedMemClass), (totalSysMem - totalUsage) / REFERENCE_BYTES_PER_BYTE); + // Pick random memory type + { + vector > memoryTypes; + + const VkDeviceSize availableInHeap = m_heap.size/MAX_MEMORY_USAGE_DIV - m_usage; + const bool isUMA = m_limits.totalDeviceLocalMemory == 0; + const MemoryClass memClass = getMemoryClass(); + + // Collect memory types that can be allocated and the maximum size of allocation. + // Memory type can be only allocated if minimal memory allocation is less than available memory. + for (size_t memoryTypeNdx = 0; memoryTypeNdx < m_memoryTypes.size(); memoryTypeNdx++) + { + const MemoryType type = m_memoryTypes[memoryTypeNdx]; + const VkDeviceSize atomSize = (type.type.propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0 + ? 1 + : m_nonCoherentAtomSize; + const VkDeviceSize allocationSizeGranularity = de::max(atomSize, memClass == MEMORY_CLASS_DEVICE ? m_limits.devicePageSize : getHostPageSize()); + const VkDeviceSize minAllocationSize = allocationSizeGranularity; + const VkDeviceSize minReferenceSize = minAllocationSize + + divRoundUp(minAllocationSize, 8) + + divRoundUp(minAllocationSize, atomSize * 8); + + if (isUMA) + { + // Max memory size calculation is little tricky since reference memory requires 1/n bits per byte. + const VkDeviceSize totalUsage = m_totalMemTracker.getTotalUsage(); + const VkDeviceSize totalSysMem = (VkDeviceSize)m_limits.totalSystemMemory; + const VkDeviceSize availableBits = (totalSysMem - totalUsage) * 8; + // availableBits == maxAllocationSizeBits + maxAllocationReferenceSizeBits + // maxAllocationReferenceSizeBits == maxAllocationSizeBits + (maxAllocationSizeBits / 8) + (maxAllocationSizeBits / atomSizeBits) + // availableBits == maxAllocationSizeBits + maxAllocationSizeBits + (maxAllocationSizeBits / 8) + (maxAllocationSizeBits / atomSizeBits) + // availableBits == 2 * maxAllocationSizeBits + (maxAllocationSizeBits / 8) + (maxAllocationSizeBits / atomSizeBits) + // availableBits == (2 + 1/8 + 1/atomSizeBits) * maxAllocationSizeBits + // 8 * availableBits == (16 + 1 + 8/atomSizeBits) * maxAllocationSizeBits + // atomSizeBits * 8 * availableBits == (17 * atomSizeBits + 8) * maxAllocationSizeBits + // maxAllocationSizeBits == atomSizeBits * 8 * availableBits / (17 * atomSizeBits + 8) + // maxAllocationSizeBytes == maxAllocationSizeBits / 8 + // maxAllocationSizeBytes == atomSizeBits * availableBits / (17 * atomSizeBits + 8) + // atomSizeBits = atomSize * 8 + // maxAllocationSizeBytes == atomSize * 8 * availableBits / (17 * atomSize * 8 + 8) + // maxAllocationSizeBytes == atomSize * availableBits / (17 * atomSize + 1) + const VkDeviceSize maxAllocationSize = roundDownToMultiple(((atomSize * availableBits) / (17 * atomSize + 1)), allocationSizeGranularity); + + DE_ASSERT(totalUsage <= totalSysMem); + DE_ASSERT(maxAllocationSize <= totalSysMem); + + if (minAllocationSize + minReferenceSize <= (totalSysMem - totalUsage) && minAllocationSize <= availableInHeap) + { + DE_ASSERT(maxAllocationSize >= minAllocationSize); + memoryTypes.push_back(std::make_pair(type, maxAllocationSize)); + } + } + else + { + // Max memory size calculation is little tricky since reference memory requires 1/n bits per byte. + const VkDeviceSize totalUsage = m_totalMemTracker.getTotalUsage(); + const VkDeviceSize totalSysMem = (VkDeviceSize)m_limits.totalSystemMemory; + + const VkDeviceSize totalMemClass = memClass == MEMORY_CLASS_SYSTEM + ? m_limits.totalSystemMemory + : m_limits.totalDeviceLocalMemory; + const VkDeviceSize usedMemClass = m_totalMemTracker.getUsage(memClass); + // availableRefBits = maxRefBits + maxRefBits/8 + maxRefBits/atomSizeBits + // availableRefBits = maxRefBits * (1 + 1/8 + 1/atomSizeBits) + // 8 * availableRefBits = maxRefBits * (8 + 1 + 8/atomSizeBits) + // 8 * atomSizeBits * availableRefBits = maxRefBits * (9 * atomSizeBits + 8) + // maxRefBits = 8 * atomSizeBits * availableRefBits / (9 * atomSizeBits + 8) + // atomSizeBits = atomSize * 8 + // maxRefBits = 8 * atomSize * 8 * availableRefBits / (9 * atomSize * 8 + 8) + // maxRefBits = atomSize * 8 * availableRefBits / (9 * atomSize + 1) + // maxRefBytes = atomSize * availableRefBits / (9 * atomSize + 1) + const VkDeviceSize maxAllocationSize = roundDownToMultiple(de::min(totalMemClass - usedMemClass, (atomSize * 8 * (totalSysMem - totalUsage)) / (9 * atomSize + 1)), allocationSizeGranularity); + + DE_ASSERT(usedMemClass <= totalMemClass); + + if (minAllocationSize <= availableInHeap + && minAllocationSize <= (totalMemClass - usedMemClass) + && minReferenceSize <= (totalSysMem - totalUsage)) + { + DE_ASSERT(maxAllocationSize >= minAllocationSize); + memoryTypes.push_back(std::make_pair(type, maxAllocationSize)); + } + + } } + + memoryTypeMaxSizePair = rng.choose >(memoryTypes.begin(), memoryTypes.end()); } - const VkMemoryHeap m_heap; - const vector m_memoryTypes; - const PlatformMemoryLimits& m_limits; - const VkDeviceSize m_nonCoherentAtomSize; - TotalMemoryTracker& m_totalMemTracker; + const MemoryType type = memoryTypeMaxSizePair.first; + const VkDeviceSize maxAllocationSize = memoryTypeMaxSizePair.second; + const VkDeviceSize atomSize = (type.type.propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0 + ? 1 + : m_nonCoherentAtomSize; + const VkDeviceSize allocationSizeGranularity = de::max(atomSize, getMemoryClass() == MEMORY_CLASS_DEVICE ? m_limits.devicePageSize : getHostPageSize()); + const VkDeviceSize size = randomSize(rng, atomSize, maxAllocationSize); + const VkDeviceSize memoryUsage = roundUpToMultiple(size, allocationSizeGranularity); + const VkDeviceSize referenceMemoryUsage = size + divRoundUp(size, 8) + divRoundUp(size, atomSize); - VkDeviceSize m_usage; - vector m_objects; -}; + DE_ASSERT(size <= maxAllocationSize); + + MemoryObject* const object = new MemoryObject(vkd, device, size, type.index, atomSize, memoryUsage, referenceMemoryUsage); + + m_usage += memoryUsage; + m_totalMemTracker.allocate(getMemoryClass(), memoryUsage); + m_totalMemTracker.allocate(MEMORY_CLASS_SYSTEM, referenceMemoryUsage); + m_objects.push_back(object); + + return object; +} size_t getMemoryObjectSystemSize (Context& context) {