Commit 968fccb2 by Ian Elliott Committed by Commit Bot

Vulkan: Use VK_EXT_device_memory_report extension

This CL can enable and use the VK_EXT_device_memory_report extension. This is disabled by default. To enable, link with the required extension, enable one or both of two features, AND build with the following GN arg: angle_enable_trace = true The two added features are: - logMemoryReportStats provides per-swap statistics - logMemoryReportCallbacks provides per-callback logging If either or both of the features are enabled, if the VK_EXT_device_memory_report extension is available, it is enabled. Bug: b/173636655 Change-Id: Ic5cf6c06efdb34f2313ef143853b3cc90f55faa5 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2543506 Commit-Queue: Ian Elliott <ianelliott@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarCourtney Goeltzenleuchter <courtneygo@google.com>
parent abe96578
...@@ -300,6 +300,17 @@ struct FeaturesVk : FeatureSetBase ...@@ -300,6 +300,17 @@ struct FeaturesVk : FeatureSetBase
"Fill new allocations with non-zero values to flush out errors.", &members, "Fill new allocations with non-zero values to flush out errors.", &members,
"http://anglebug.com/4384"}; "http://anglebug.com/4384"};
// Whether to log each callback from the VK_EXT_device_memory_report extension. This feature is
// used for trying to debug GPU memory leaks.
Feature logMemoryReportCallbacks = {"logMemoryReportCallbacks", FeatureCategory::VulkanFeatures,
"Log each callback from VK_EXT_device_memory_report",
&members};
// Whether to log statistics from the VK_EXT_device_memory_report extension each eglSwapBuffer.
Feature logMemoryReportStats = {"logMemoryReportStats", FeatureCategory::VulkanFeatures,
"Log stats from VK_EXT_device_memory_report each swap",
&members};
// Allocate a "shadow" buffer for GL buffer objects. For GPU-read only buffers // Allocate a "shadow" buffer for GL buffer objects. For GPU-read only buffers
// glMap* latency can be reduced by maintaining a copy of the buffer which is // glMap* latency can be reduced by maintaining a copy of the buffer which is
// writeable only by the CPU. We then return this shadow buffer on glMap* calls. // writeable only by the CPU. We then return this shadow buffer on glMap* calls.
......
...@@ -163,8 +163,8 @@ void ScopedPerfEventHelper::begin(const char *format, ...) ...@@ -163,8 +163,8 @@ void ScopedPerfEventHelper::begin(const char *format, ...)
LogMessage::LogMessage(const char *file, const char *function, int line, LogSeverity severity) LogMessage::LogMessage(const char *file, const char *function, int line, LogSeverity severity)
: mFile(file), mFunction(function), mLine(line), mSeverity(severity) : mFile(file), mFunction(function), mLine(line), mSeverity(severity)
{ {
// EVENT() does not require additional function(line) info. // INFO() and EVENT() do not require additional function(line) info.
if (mSeverity != LOG_EVENT) if (mSeverity > LOG_INFO)
{ {
const char *slash = std::max(strrchr(mFile, '/'), strrchr(mFile, '\\')); const char *slash = std::max(strrchr(mFile, '/'), strrchr(mFile, '\\'));
mStream << (slash ? (slash + 1) : mFile) << ":" << mLine << " (" << mFunction << "): "; mStream << (slash ? (slash + 1) : mFile) << ":" << mLine << " (" << mFunction << "): ";
...@@ -179,7 +179,7 @@ LogMessage::~LogMessage() ...@@ -179,7 +179,7 @@ LogMessage::~LogMessage()
lock = std::unique_lock<std::mutex>(*g_debugMutex); lock = std::unique_lock<std::mutex>(*g_debugMutex);
} }
if (DebugAnnotationsInitialized() && (mSeverity >= LOG_INFO)) if (DebugAnnotationsInitialized() && (mSeverity > LOG_INFO))
{ {
g_debugAnnotator->logMessage(*this); g_debugAnnotator->logMessage(*this);
} }
......
...@@ -387,6 +387,13 @@ VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(VkDebugReportFlagsEXT flags, ...@@ -387,6 +387,13 @@ VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(VkDebugReportFlagsEXT flags,
return VK_FALSE; return VK_FALSE;
} }
VKAPI_ATTR void VKAPI_CALL
MemoryReportCallback(const VkDeviceMemoryReportCallbackDataEXT *callbackData, void *userData)
{
RendererVk *rendererVk = static_cast<RendererVk *>(userData);
rendererVk->processMemoryReportCallback(*callbackData);
}
bool ShouldUseValidationLayers(const egl::AttributeMap &attribs) bool ShouldUseValidationLayers(const egl::AttributeMap &attribs)
{ {
#if defined(ANGLE_ENABLE_VULKAN_VALIDATION_LAYERS_BY_DEFAULT) #if defined(ANGLE_ENABLE_VULKAN_VALIDATION_LAYERS_BY_DEFAULT)
...@@ -937,6 +944,10 @@ void RendererVk::queryDeviceExtensionFeatures(const vk::ExtensionNameList &devic ...@@ -937,6 +944,10 @@ void RendererVk::queryDeviceExtensionFeatures(const vk::ExtensionNameList &devic
mSubgroupProperties = {}; mSubgroupProperties = {};
mSubgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES; mSubgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
mMemoryReportFeatures = {};
mMemoryReportFeatures.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT;
mExternalMemoryHostProperties = {}; mExternalMemoryHostProperties = {};
mExternalMemoryHostProperties.sType = mExternalMemoryHostProperties.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT; VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT;
...@@ -1002,6 +1013,12 @@ void RendererVk::queryDeviceExtensionFeatures(const vk::ExtensionNameList &devic ...@@ -1002,6 +1013,12 @@ void RendererVk::queryDeviceExtensionFeatures(const vk::ExtensionNameList &devic
vk::AddToPNextChain(&deviceFeatures, &mIndexTypeUint8Features); vk::AddToPNextChain(&deviceFeatures, &mIndexTypeUint8Features);
} }
// Query memory report features
if (ExtensionFound(VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME, deviceExtensionNames))
{
vk::AddToPNextChain(&deviceFeatures, &mMemoryReportFeatures);
}
// Query external memory host properties // Query external memory host properties
if (ExtensionFound(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, deviceExtensionNames)) if (ExtensionFound(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, deviceExtensionNames))
{ {
...@@ -1056,6 +1073,7 @@ void RendererVk::queryDeviceExtensionFeatures(const vk::ExtensionNameList &devic ...@@ -1056,6 +1073,7 @@ void RendererVk::queryDeviceExtensionFeatures(const vk::ExtensionNameList &devic
// Clean up pNext chains // Clean up pNext chains
mLineRasterizationFeatures.pNext = nullptr; mLineRasterizationFeatures.pNext = nullptr;
mMemoryReportFeatures.pNext = nullptr;
mProvokingVertexFeatures.pNext = nullptr; mProvokingVertexFeatures.pNext = nullptr;
mVertexAttributeDivisorFeatures.pNext = nullptr; mVertexAttributeDivisorFeatures.pNext = nullptr;
mVertexAttributeDivisorProperties.pNext = nullptr; mVertexAttributeDivisorProperties.pNext = nullptr;
...@@ -1407,6 +1425,19 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF ...@@ -1407,6 +1425,19 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
enabledDeviceExtensions.push_back(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME); enabledDeviceExtensions.push_back(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
} }
if (mMemoryReportFeatures.deviceMemoryReport &&
(getFeatures().logMemoryReportCallbacks.enabled ||
getFeatures().logMemoryReportStats.enabled))
{
enabledDeviceExtensions.push_back(VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME);
mMemoryReportCallback = {};
mMemoryReportCallback.sType = VK_STRUCTURE_TYPE_DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT;
mMemoryReportCallback.pfnUserCallback = &MemoryReportCallback;
mMemoryReportCallback.pUserData = this;
vk::AddToPNextChain(&createInfo, &mMemoryReportCallback);
}
if (getFeatures().supportsExternalMemoryHost.enabled) if (getFeatures().supportsExternalMemoryHost.enabled)
{ {
enabledDeviceExtensions.push_back(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME); enabledDeviceExtensions.push_back(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME);
...@@ -1921,6 +1952,9 @@ void RendererVk::initFeatures(DisplayVk *displayVk, ...@@ -1921,6 +1952,9 @@ void RendererVk::initFeatures(DisplayVk *displayVk,
ANGLE_FEATURE_CONDITION(&mFeatures, persistentlyMappedBuffers, true); ANGLE_FEATURE_CONDITION(&mFeatures, persistentlyMappedBuffers, true);
ANGLE_FEATURE_CONDITION(&mFeatures, logMemoryReportCallbacks, false);
ANGLE_FEATURE_CONDITION(&mFeatures, logMemoryReportStats, false);
ANGLE_FEATURE_CONDITION( ANGLE_FEATURE_CONDITION(
&mFeatures, supportsExternalMemoryHost, &mFeatures, supportsExternalMemoryHost,
ExtensionFound(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, deviceExtensionNames)); ExtensionFound(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, deviceExtensionNames));
...@@ -2621,6 +2655,11 @@ VkResult RendererVk::queuePresent(vk::Context *context, ...@@ -2621,6 +2655,11 @@ VkResult RendererVk::queuePresent(vk::Context *context,
result = mCommandQueue.queuePresent(priority, presentInfo); result = mCommandQueue.queuePresent(priority, presentInfo);
} }
if (getFeatures().logMemoryReportStats.enabled)
{
mMemoryReport.logMemoryReportStats();
}
return result; return result;
} }
...@@ -2653,4 +2692,114 @@ void RendererVk::recycleCommandBufferHelper(vk::CommandBufferHelper *commandBuff ...@@ -2653,4 +2692,114 @@ void RendererVk::recycleCommandBufferHelper(vk::CommandBufferHelper *commandBuff
commandBuffer->markOpen(); commandBuffer->markOpen();
mCommandBufferHelperFreeList.push_back(commandBuffer); mCommandBufferHelperFreeList.push_back(commandBuffer);
} }
vk::MemoryReport::MemoryReport()
: mCurrentTotalAllocatedMemory(0),
mMaxTotalAllocatedMemory(0),
mCurrentTotalImportedMemory(0),
mMaxTotalImportedMemory(0)
{}
void vk::MemoryReport::processCallback(const VkDeviceMemoryReportCallbackDataEXT &callbackData,
bool logCallback)
{
std::lock_guard<std::mutex> lock(mMemoryReportMutex);
VkDeviceSize size = 0;
std::string reportType;
switch (callbackData.type)
{
case VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATE_EXT:
reportType = "Allocate";
if ((mUniqueIDCounts[callbackData.memoryObjectId] += 1) > 1)
{
break;
}
size = mSizesPerType[callbackData.objectType].allocatedMemory + callbackData.size;
mSizesPerType[callbackData.objectType].allocatedMemory = size;
if (mSizesPerType[callbackData.objectType].allocatedMemoryMax < size)
{
mSizesPerType[callbackData.objectType].allocatedMemoryMax = size;
}
mCurrentTotalAllocatedMemory += callbackData.size;
if (mMaxTotalAllocatedMemory < mCurrentTotalAllocatedMemory)
{
mMaxTotalAllocatedMemory = mCurrentTotalAllocatedMemory;
}
break;
case VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_FREE_EXT:
reportType = "Free";
ASSERT(mUniqueIDCounts[callbackData.memoryObjectId] > 0);
mUniqueIDCounts[callbackData.memoryObjectId] -= 1;
size = mSizesPerType[callbackData.objectType].allocatedMemory - callbackData.size;
mSizesPerType[callbackData.objectType].allocatedMemory = size;
mCurrentTotalAllocatedMemory -= callbackData.size;
break;
case VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_IMPORT_EXT:
reportType = "Import";
if ((mUniqueIDCounts[callbackData.memoryObjectId] += 1) > 1)
{
break;
}
size = mSizesPerType[callbackData.objectType].importedMemory + callbackData.size;
mSizesPerType[callbackData.objectType].importedMemory = size;
if (mSizesPerType[callbackData.objectType].importedMemoryMax < size)
{
mSizesPerType[callbackData.objectType].importedMemoryMax = size;
}
mCurrentTotalImportedMemory += callbackData.size;
if (mMaxTotalImportedMemory < mCurrentTotalImportedMemory)
{
mMaxTotalImportedMemory = mCurrentTotalImportedMemory;
}
break;
case VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_UNIMPORT_EXT:
reportType = "Un-Import";
ASSERT(mUniqueIDCounts[callbackData.memoryObjectId] > 0);
mUniqueIDCounts[callbackData.memoryObjectId] -= 1;
size = mSizesPerType[callbackData.objectType].importedMemory - callbackData.size;
mSizesPerType[callbackData.objectType].importedMemory = size;
mCurrentTotalImportedMemory -= callbackData.size;
break;
case VK_DEVICE_MEMORY_REPORT_EVENT_TYPE_ALLOCATION_FAILED_EXT:
reportType = "allocFail";
break;
default:
UNREACHABLE();
return;
}
if (logCallback)
{
INFO() << std::right << std::setw(9) << reportType << ": size=" << std::setw(10)
<< callbackData.size << "; type=" << std::setw(15) << std::left
<< GetVkObjectTypeName(callbackData.objectType)
<< "; heapIdx=" << callbackData.heapIndex << "; id=" << std::hex
<< callbackData.memoryObjectId << "; handle=" << std::hex
<< callbackData.objectHandle << ": Total=" << std::right << std::setw(10) << std::dec
<< size;
}
}
void vk::MemoryReport::logMemoryReportStats() const
{
std::lock_guard<std::mutex> lock(mMemoryReportMutex);
INFO() << std::right << "GPU Memory Totals: Allocated=" << std::setw(10)
<< mCurrentTotalAllocatedMemory << " (max=" << std::setw(10) << mMaxTotalAllocatedMemory
<< "); Imported=" << std::setw(10) << mCurrentTotalImportedMemory
<< " (max=" << std::setw(10) << mMaxTotalImportedMemory << ")";
INFO() << "Sub-Totals per type:";
for (const auto &it : mSizesPerType)
{
VkObjectType objectType = it.first;
MemorySizes memorySizes = it.second;
VkDeviceSize allocatedMemory = memorySizes.allocatedMemory;
VkDeviceSize allocatedMemoryMax = memorySizes.allocatedMemoryMax;
VkDeviceSize importedMemory = memorySizes.importedMemory;
VkDeviceSize importedMemoryMax = memorySizes.importedMemoryMax;
INFO() << std::right << "- Type=" << std::setw(15) << GetVkObjectTypeName(objectType)
<< ": Allocated=" << std::setw(10) << allocatedMemory << " (max=" << std::setw(10)
<< allocatedMemoryMax << "); Imported=" << std::setw(10) << importedMemory
<< " (max=" << std::setw(10) << importedMemoryMax << ")";
}
}
} // namespace rx } // namespace rx
...@@ -53,6 +53,31 @@ struct Format; ...@@ -53,6 +53,31 @@ struct Format;
static constexpr size_t kMaxExtensionNames = 200; static constexpr size_t kMaxExtensionNames = 200;
using ExtensionNameList = angle::FixedVector<const char *, kMaxExtensionNames>; using ExtensionNameList = angle::FixedVector<const char *, kMaxExtensionNames>;
// Process GPU memory reports
class MemoryReport final : angle::NonCopyable
{
public:
MemoryReport();
void processCallback(const VkDeviceMemoryReportCallbackDataEXT &callbackData, bool logCallback);
void logMemoryReportStats() const;
private:
struct MemorySizes
{
VkDeviceSize allocatedMemory;
VkDeviceSize allocatedMemoryMax;
VkDeviceSize importedMemory;
VkDeviceSize importedMemoryMax;
};
mutable std::mutex mMemoryReportMutex;
VkDeviceSize mCurrentTotalAllocatedMemory;
VkDeviceSize mMaxTotalAllocatedMemory;
angle::HashMap<VkObjectType, MemorySizes> mSizesPerType;
VkDeviceSize mCurrentTotalImportedMemory;
VkDeviceSize mMaxTotalImportedMemory;
angle::HashMap<uint64_t, int> mUniqueIDCounts;
};
} // namespace vk } // namespace vk
// Supports one semaphore from current surface, and one semaphore passed to // Supports one semaphore from current surface, and one semaphore passed to
...@@ -332,6 +357,13 @@ class RendererVk : angle::NonCopyable ...@@ -332,6 +357,13 @@ class RendererVk : angle::NonCopyable
vk::CommandBufferHelper *getCommandBufferHelper(bool hasRenderPass); vk::CommandBufferHelper *getCommandBufferHelper(bool hasRenderPass);
void recycleCommandBufferHelper(vk::CommandBufferHelper *commandBuffer); void recycleCommandBufferHelper(vk::CommandBufferHelper *commandBuffer);
// Process GPU memory reports
void processMemoryReportCallback(const VkDeviceMemoryReportCallbackDataEXT &callbackData)
{
bool logCallback = getFeatures().logMemoryReportCallbacks.enabled;
mMemoryReport.processCallback(callbackData, logCallback);
}
private: private:
angle::Result initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex); angle::Result initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex);
void ensureCapsInitialized() const; void ensureCapsInitialized() const;
...@@ -376,6 +408,8 @@ class RendererVk : angle::NonCopyable ...@@ -376,6 +408,8 @@ class RendererVk : angle::NonCopyable
VkPhysicalDeviceTransformFeedbackFeaturesEXT mTransformFeedbackFeatures; VkPhysicalDeviceTransformFeedbackFeaturesEXT mTransformFeedbackFeatures;
VkPhysicalDeviceIndexTypeUint8FeaturesEXT mIndexTypeUint8Features; VkPhysicalDeviceIndexTypeUint8FeaturesEXT mIndexTypeUint8Features;
VkPhysicalDeviceSubgroupProperties mSubgroupProperties; VkPhysicalDeviceSubgroupProperties mSubgroupProperties;
VkPhysicalDeviceDeviceMemoryReportFeaturesEXT mMemoryReportFeatures;
VkDeviceDeviceMemoryReportCreateInfoEXT mMemoryReportCallback;
VkPhysicalDeviceExternalMemoryHostPropertiesEXT mExternalMemoryHostProperties; VkPhysicalDeviceExternalMemoryHostPropertiesEXT mExternalMemoryHostProperties;
VkPhysicalDeviceShaderFloat16Int8FeaturesKHR mShaderFloat16Int8Features; VkPhysicalDeviceShaderFloat16Int8FeaturesKHR mShaderFloat16Int8Features;
VkPhysicalDeviceDepthStencilResolvePropertiesKHR mDepthStencilResolveProperties; VkPhysicalDeviceDepthStencilResolvePropertiesKHR mDepthStencilResolveProperties;
...@@ -453,6 +487,9 @@ class RendererVk : angle::NonCopyable ...@@ -453,6 +487,9 @@ class RendererVk : angle::NonCopyable
// Tracks resource serials. // Tracks resource serials.
vk::ResourceSerialFactory mResourceSerialFactory; vk::ResourceSerialFactory mResourceSerialFactory;
// Process GPU memory reports
vk::MemoryReport mMemoryReport;
}; };
} // namespace rx } // namespace rx
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment