Skip to content

Commit c2686ab

Browse files
authored
[webgpu] fixes buffer handle leak in cache manager (microsoft#23655)
### Description There is a bug in the buffer cache manager that causes a buffer handle leak. When the default GPU device is destroyed, - in native, the underlying buffers are destroyed, but the handle (specifically, the `BaseBuffer` class instance in Dawn) is not released. This may cause small memory leaks. - in WebAssembly, this will cause the buffers to be leaked. Both handle (specifically, the `WGPUBufferImpl` class in emgpu) and memory will be leaked. This change fixes this bug by correctly assigning ownership of the buffers using the C++ wrapper class. Destructors will be correctly called correspondingly.
1 parent 1e5da57 commit c2686ab

File tree

1 file changed

+14
-19
lines changed

1 file changed

+14
-19
lines changed

onnxruntime/core/providers/webgpu/buffer_manager.cc

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,14 @@ class LazyReleaseCacheManager : public IBufferCacheManager {
4646
}
4747

4848
void ReleaseBuffer(WGPUBuffer buffer) override {
49-
pending_buffers_.emplace_back(buffer);
49+
pending_buffers_.emplace_back(wgpu::Buffer::Acquire(buffer));
5050
}
5151

5252
void OnRefresh() override {
53-
for (auto& buffer : pending_buffers_) {
54-
wgpuBufferRelease(buffer);
55-
}
5653
pending_buffers_.clear();
5754
}
5855

59-
std::vector<WGPUBuffer> pending_buffers_;
56+
std::vector<wgpu::Buffer> pending_buffers_;
6057
};
6158

6259
class SimpleCacheManager : public IBufferCacheManager {
@@ -67,7 +64,7 @@ class SimpleCacheManager : public IBufferCacheManager {
6764
WGPUBuffer TryAcquireCachedBuffer(size_t buffer_size) override {
6865
auto it = buffers_.find(buffer_size);
6966
if (it != buffers_.end() && !it->second.empty()) {
70-
auto buffer = it->second.back();
67+
auto buffer = it->second.back().MoveToCHandle();
7168
it->second.pop_back();
7269
return buffer;
7370
}
@@ -80,18 +77,18 @@ class SimpleCacheManager : public IBufferCacheManager {
8077
}
8178

8279
void ReleaseBuffer(WGPUBuffer buffer) override {
83-
pending_buffers_.emplace_back(buffer);
80+
pending_buffers_.emplace_back(wgpu::Buffer::Acquire(buffer));
8481
}
8582

8683
void OnRefresh() override {
8784
for (auto& buffer : pending_buffers_) {
88-
buffers_[static_cast<size_t>(wgpuBufferGetSize(buffer))].push_back(buffer);
85+
buffers_[static_cast<size_t>(buffer.GetSize())].emplace_back(std::move(buffer));
8986
}
9087
pending_buffers_.clear();
9188
}
9289

93-
std::map<size_t, std::vector<WGPUBuffer>> buffers_;
94-
std::vector<WGPUBuffer> pending_buffers_;
90+
std::map<size_t, std::vector<wgpu::Buffer>> buffers_;
91+
std::vector<wgpu::Buffer> pending_buffers_;
9592
};
9693

9794
// TODO: maybe use different bucket size for storage and uniform buffers?
@@ -148,7 +145,7 @@ class BucketCacheManager : public IBufferCacheManager {
148145
WGPUBuffer TryAcquireCachedBuffer(size_t buffer_size) override {
149146
auto it = buckets_.find(buffer_size);
150147
if (it != buckets_.end() && !it->second.empty()) {
151-
auto buffer = it->second.back();
148+
auto buffer = it->second.back().MoveToCHandle();
152149
it->second.pop_back();
153150
return buffer;
154151
}
@@ -160,20 +157,18 @@ class BucketCacheManager : public IBufferCacheManager {
160157
}
161158

162159
void ReleaseBuffer(WGPUBuffer buffer) override {
163-
pending_buffers_.emplace_back(buffer);
160+
pending_buffers_.emplace_back(wgpu::Buffer::Acquire(buffer));
164161
}
165162

166163
void OnRefresh() override {
167164
// TODO: consider graph capture. currently not supported
168165

169166
for (auto& buffer : pending_buffers_) {
170-
auto buffer_size = static_cast<size_t>(wgpuBufferGetSize(buffer));
167+
auto buffer_size = static_cast<size_t>(buffer.GetSize());
171168

172169
auto it = buckets_.find(buffer_size);
173170
if (it != buckets_.end() && it->second.size() < buckets_limit_[buffer_size]) {
174-
it->second.push_back(buffer);
175-
} else {
176-
wgpuBufferRelease(buffer);
171+
it->second.emplace_back(std::move(buffer));
177172
}
178173
}
179174

@@ -186,7 +181,7 @@ class BucketCacheManager : public IBufferCacheManager {
186181
buckets_.reserve(buckets_limit_.size());
187182
for (const auto& pair : buckets_limit_) {
188183
buckets_keys_.push_back(pair.first);
189-
buckets_.emplace(pair.first, std::vector<WGPUBuffer>());
184+
buckets_.emplace(pair.first, std::vector<wgpu::Buffer>());
190185
}
191186
std::sort(buckets_keys_.begin(), buckets_keys_.end());
192187

@@ -200,8 +195,8 @@ class BucketCacheManager : public IBufferCacheManager {
200195
#endif
201196
}
202197
std::unordered_map<size_t, size_t> buckets_limit_;
203-
std::unordered_map<size_t, std::vector<WGPUBuffer>> buckets_;
204-
std::vector<WGPUBuffer> pending_buffers_;
198+
std::unordered_map<size_t, std::vector<wgpu::Buffer>> buckets_;
199+
std::vector<wgpu::Buffer> pending_buffers_;
205200
std::vector<size_t> buckets_keys_;
206201
};
207202

0 commit comments

Comments
 (0)