Add ComputeEstimatedMemoryUsage
For Chrome background memory tracing, we need a method to retrieve total
memory usage from Dawn without the overhead of generating a detailed
memory dump. Add ComputeEstimatedMemoryUsage method for that.
Also contains a change to how we report textures in memory dumps -
shared and memoryless textures will be present in the dump but with zero
size so the totals don't change, but we still have useful information
for profiling/debugging.
Bug: 330806170
Change-Id: Ib28a3f69f40fffedbc7ab879e94468aa8c0461a5
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/201794
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Brandon Jones <bajones@chromium.org>
Auto-Submit: Sunny Sachanandani <sunnyps@chromium.org>
Commit-Queue: Sunny Sachanandani <sunnyps@chromium.org>
diff --git a/include/dawn/native/DawnNative.h b/include/dawn/native/DawnNative.h
index c910f50..594c387 100644
--- a/include/dawn/native/DawnNative.h
+++ b/include/dawn/native/DawnNative.h
@@ -298,6 +298,10 @@
};
DAWN_NATIVE_EXPORT void DumpMemoryStatistics(WGPUDevice device, MemoryDump* dump);
+// Unlike memory dumps which include detailed information about allocations, this only returns the
+// total estimated memory usage, and is intended for background tracing for UMA.
+DAWN_NATIVE_EXPORT uint64_t ComputeEstimatedMemoryUsage(WGPUDevice device);
+
} // namespace dawn::native
#endif // INCLUDE_DAWN_NATIVE_DAWNNATIVE_H_
diff --git a/src/dawn/native/Buffer.cpp b/src/dawn/native/Buffer.cpp
index e2bd22d..db7a0b4 100644
--- a/src/dawn/native/Buffer.cpp
+++ b/src/dawn/native/Buffer.cpp
@@ -1127,10 +1127,7 @@
}
void BufferBase::DumpMemoryStatistics(MemoryDump* dump, const char* prefix) const {
- // Do not emit for destroyed buffers.
- if (!IsAlive()) {
- return;
- }
+ DAWN_ASSERT(IsAlive() && !IsError());
std::string name = absl::StrFormat("%s/buffer_%p", prefix, static_cast<const void*>(this));
dump->AddScalar(name.c_str(), MemoryDump::kNameSize, MemoryDump::kUnitsBytes,
GetAllocatedSize());
diff --git a/src/dawn/native/DawnNative.cpp b/src/dawn/native/DawnNative.cpp
index 699dde0..885e62c 100644
--- a/src/dawn/native/DawnNative.cpp
+++ b/src/dawn/native/DawnNative.cpp
@@ -309,4 +309,8 @@
FromAPI(device)->DumpMemoryStatistics(dump);
}
+uint64_t ComputeEstimatedMemoryUsage(WGPUDevice device) {
+ return FromAPI(device)->ComputeEstimatedMemoryUsage();
+}
+
} // namespace dawn::native
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp
index d020b97e..3a604dc 100644
--- a/src/dawn/native/Device.cpp
+++ b/src/dawn/native/Device.cpp
@@ -2613,6 +2613,17 @@
});
}
+uint64_t DeviceBase::ComputeEstimatedMemoryUsage() const {
+ uint64_t size = 0;
+ GetObjectTrackingList(ObjectType::Texture)->ForEach([&](const ApiObjectBase* texture) {
+ size += static_cast<const TextureBase*>(texture)->ComputeEstimatedByteSize();
+ });
+ GetObjectTrackingList(ObjectType::Buffer)->ForEach([&](const ApiObjectBase* buffer) {
+ size += static_cast<const BufferBase*>(buffer)->GetAllocatedSize();
+ });
+ return size;
+}
+
ResultOrError<Ref<BufferBase>> DeviceBase::GetOrCreateTemporaryUniformBuffer(size_t size) {
if (!mTemporaryUniformBuffer || mTemporaryUniformBuffer->GetSize() != size) {
BufferDescriptor desc;
diff --git a/src/dawn/native/Device.h b/src/dawn/native/Device.h
index 183ce56..1c5122c 100644
--- a/src/dawn/native/Device.h
+++ b/src/dawn/native/Device.h
@@ -457,6 +457,7 @@
Ref<RenderPipelineBase> AddOrGetCachedRenderPipeline(Ref<RenderPipelineBase> renderPipeline);
void DumpMemoryStatistics(dawn::native::MemoryDump* dump) const;
+ uint64_t ComputeEstimatedMemoryUsage() const;
ResultOrError<Ref<BufferBase>> GetOrCreateTemporaryUniformBuffer(size_t size);
diff --git a/src/dawn/native/Texture.cpp b/src/dawn/native/Texture.cpp
index 978fd78..8d929f5 100644
--- a/src/dawn/native/Texture.cpp
+++ b/src/dawn/native/Texture.cpp
@@ -1225,12 +1225,6 @@
}
void TextureBase::DumpMemoryStatistics(dawn::native::MemoryDump* dump, const char* prefix) const {
- // Do not emit for destroyed textures, textures that wrap external shared texture memory, or
- // textures used as transient (memoryless) attachments.
- if (!IsAlive() || GetSharedResourceMemoryContents() != nullptr ||
- (GetInternalUsage() & wgpu::TextureUsage::TransientAttachment) != 0) {
- return;
- }
std::string name = absl::StrFormat("%s/texture_%p", prefix, static_cast<const void*>(this));
dump->AddScalar(name.c_str(), MemoryDump::kNameSize, MemoryDump::kUnitsBytes,
ComputeEstimatedByteSize());
@@ -1243,7 +1237,13 @@
}
uint64_t TextureBase::ComputeEstimatedByteSize() const {
- DAWN_ASSERT(!IsError());
+ DAWN_ASSERT(IsAlive() && !IsError());
+ // Do not emit a non-zero size for textures that wrap external shared texture memory, or
+ // textures used as transient (memoryless) attachments.
+ if (GetSharedResourceMemoryContents() != nullptr ||
+ (GetInternalUsage() & wgpu::TextureUsage::TransientAttachment) != 0) {
+ return 0;
+ }
uint64_t byteSize = 0;
for (Aspect aspect : IterateEnumMask(SelectFormatAspects(*mFormat, wgpu::TextureAspect::All))) {
const AspectInfo& info = mFormat->GetAspectInfo(aspect);
diff --git a/src/dawn/native/Texture.h b/src/dawn/native/Texture.h
index 2e0cd3e..caad0e2 100644
--- a/src/dawn/native/Texture.h
+++ b/src/dawn/native/Texture.h
@@ -157,6 +157,8 @@
void DumpMemoryStatistics(dawn::native::MemoryDump* dump, const char* prefix) const;
+ uint64_t ComputeEstimatedByteSize() const;
+
// Dawn API
TextureViewBase* APICreateView(const TextureViewDescriptor* descriptor = nullptr);
TextureViewBase* APICreateErrorView(const TextureViewDescriptor* descriptor = nullptr);
@@ -194,8 +196,6 @@
std::string GetSizeLabel() const;
- uint64_t ComputeEstimatedByteSize() const;
-
wgpu::TextureDimension mDimension;
// Only used for compatibility mode
wgpu::TextureViewDimension mCompatibilityTextureBindingViewDimension =
diff --git a/src/dawn/tests/unittests/native/MemoryInstrumentationTests.cpp b/src/dawn/tests/unittests/native/MemoryInstrumentationTests.cpp
index dbf4592..ceb9a5e 100644
--- a/src/dawn/tests/unittests/native/MemoryInstrumentationTests.cpp
+++ b/src/dawn/tests/unittests/native/MemoryInstrumentationTests.cpp
@@ -40,6 +40,7 @@
namespace {
using ::testing::ByMove;
+using ::testing::DoDefault;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::StrEq;
@@ -155,12 +156,12 @@
EXPECT_CALL(memoryDumpMock, AddScalar(StrEq(textureLabel(etc2Texture)), MemoryDump::kNameSize,
MemoryDump::kUnitsBytes, kETC2TextureSize));
- // Create a texture and destroy it and check that its size is not counted.
+ // Create a texture and destroy it and check that its info is not emitted.
wgpu::Texture destroyedTexture = device.CreateTexture(&kMipmappedTextureDesc);
EXPECT_TRUE(destroyedTexture);
destroyedTexture.Destroy();
- // Create a shared resourc memory texture and check that its size is not counted.
+ // Create a shared resource memory texture and check that its size is not counted.
constexpr wgpu::TextureFormat kRGBA8UnormTextureFormat = wgpu::TextureFormat::RGBA8Unorm;
const wgpu::TextureDescriptor kSharedTextureDesc = {
.usage = wgpu::TextureUsage::TextureBinding,
@@ -169,17 +170,41 @@
.viewFormatCount = 1,
.viewFormats = &kRGBA8UnormTextureFormat,
};
- Ref<TextureMock> textureMock =
+ Ref<TextureMock> sharedTextureMock =
AcquireRef(new NiceMock<TextureMock>(mDeviceMock, FromCppAPI(&kSharedTextureDesc)));
- textureMock->SetSharedResourceMemoryContentsForTesting(
+ sharedTextureMock->SetSharedResourceMemoryContentsForTesting(
AcquireRef(new SharedResourceMemoryContents(nullptr)));
- EXPECT_CALL(*mDeviceMock, CreateTextureImpl).WillOnce(Return(ByMove(std::move(textureMock))));
+ EXPECT_CALL(*mDeviceMock, CreateTextureImpl)
+ .WillOnce(Return(ByMove(std::move(sharedTextureMock))))
+ .WillRepeatedly(DoDefault());
wgpu::Texture sharedTexture = device.CreateTexture(&kSharedTextureDesc);
+ EXPECT_CALL(memoryDumpMock, AddScalar(StrEq(textureLabel(sharedTexture)), MemoryDump::kNameSize,
+ MemoryDump::kUnitsBytes, /*size=*/0));
+
+ // Create a transient attachment (memoryless) texture and check that its size is not counted.
+ mDeviceMock->ForceEnableFeatureForTesting(Feature::TransientAttachments);
+ const wgpu::TextureDescriptor kTransientAttachmentTextureDesc = {
+ .usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TransientAttachment,
+ .size = {.width = 30, .height = 20},
+ .format = kRGBA8UnormTextureFormat,
+ .viewFormatCount = 1,
+ .viewFormats = &kRGBA8UnormTextureFormat,
+ };
+ wgpu::Texture transientAttachmentTexture =
+ device.CreateTexture(&kTransientAttachmentTextureDesc);
+ EXPECT_CALL(memoryDumpMock,
+ AddScalar(StrEq(textureLabel(transientAttachmentTexture)), MemoryDump::kNameSize,
+ MemoryDump::kUnitsBytes, /*size=*/0));
DumpMemoryStatistics(device.Get(), &memoryDumpMock);
EXPECT_EQ(memoryDumpMock.GetTotalSize(), kBufferAllocatedSize + kMipmappedTextureSize +
kMultisampleTextureSize + kETC2TextureSize);
+
+ // Check that ComputeEstimatedMemoryUsage() matches the memory dump total size.
+ EXPECT_EQ(
+ ComputeEstimatedMemoryUsage(device.Get()),
+ kBufferAllocatedSize + kMipmappedTextureSize + kMultisampleTextureSize + kETC2TextureSize);
}
} // namespace