Skip to content

Commit d46abbe

Browse files
authored
Make the grow-only resource stream ordered. (#12185)
1 parent 534b391 commit d46abbe

4 files changed

Lines changed: 18 additions & 13 deletions

File tree

src/common/device_vector.cu

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2017-2024, XGBoost contributors
2+
* Copyright 2017-2026, XGBoost contributors
33
*/
44
#include <numeric> // for accumulate
55

@@ -59,7 +59,7 @@ void ThrowOOMError(std::string const &err, std::size_t bytes) {
5959
return std::accumulate(it, it + this->handles_.size(), static_cast<std::size_t>(0));
6060
}
6161

62-
void GrowOnlyVirtualMemVec::Reserve(std::size_t new_size) {
62+
void GrowOnlyVirtualMemVec::Reserve(std::size_t new_size, xgboost::curt::StreamRef stream) {
6363
auto va_capacity = this->Capacity();
6464
if (new_size < va_capacity) {
6565
return;
@@ -83,6 +83,9 @@ void GrowOnlyVirtualMemVec::Reserve(std::size_t new_size) {
8383
// New allocation is successful. Map the pyhsical address to the virtual address.
8484
// First unmap the existing ptr.
8585
if (this->DevPtr() != 0) {
86+
// Slow-path growth invalidates the existing virtual address. Wait for prior users on the
87+
// caller's stream before changing the mapping.
88+
stream.Sync();
8689
// Unmap the existing ptr.
8790
safe_cu(cu_.cuMemUnmap(this->DevPtr(), this->PhyCapacity()));
8891

src/common/device_vector.cuh

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,20 +204,21 @@ class GrowOnlyVirtualMemVec {
204204
safe_cu(this->cu_.cuMemCreate(&alloc_handle, padded_size, &this->prop_, 0));
205205
return alloc_handle;
206206
}
207-
void Reserve(std::size_t new_size);
207+
void Reserve(std::size_t new_size, xgboost::curt::StreamRef stream);
208208

209209
public:
210210
explicit GrowOnlyVirtualMemVec(CUmemLocationType type);
211211

212-
void GrowTo(std::size_t n_bytes) {
212+
void GrowTo(std::size_t n_bytes,
213+
xgboost::curt::StreamRef stream = xgboost::curt::DefaultStream()) {
213214
auto alloc_size = this->PhyCapacity();
214215
if (n_bytes <= alloc_size) {
215216
return;
216217
}
217218

218219
std::size_t delta = n_bytes - alloc_size;
219220
auto const padded_delta = RoundUp(delta, this->granularity_);
220-
this->Reserve(alloc_size + padded_delta);
221+
this->Reserve(alloc_size + padded_delta, stream);
221222

222223
this->handles_.emplace_back(
223224
std::unique_ptr<PhyAddrHandle, std::function<void(PhyAddrHandle *)>>{

src/common/resource.cuh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2024-2025, XGBoost Contributors
2+
* Copyright 2024-2026, XGBoost Contributors
33
*/
44
#pragma once
55
#include <cstddef> // for size_t
@@ -48,8 +48,8 @@ class CudaGrowOnlyResource : public ResourceHandler {
4848
: ResourceHandler{kCudaGrowOnly}, alloc_{MakeNew()} {
4949
this->Resize(n_bytes);
5050
}
51-
void Resize(std::size_t n_bytes) {
52-
this->alloc_->GrowTo(n_bytes);
51+
void Resize(std::size_t n_bytes, curt::StreamRef stream = curt::DefaultStream()) {
52+
this->alloc_->GrowTo(n_bytes, stream);
5353
this->n_bytes_ = n_bytes;
5454
}
5555
void Clear() {

tests/cpp/common/test_ref_resource_view.cu

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Copyright 2024-2025, XGBoost Contributors
2+
* Copyright 2024-2026, XGBoost Contributors
33
*/
44
#if defined(__linux__)
55

@@ -25,15 +25,17 @@ class TestCudaGrowOnly : public ::testing::TestWithParam<std::size_t> {
2525
thrust::sequence(ctx.CUDACtx()->CTP(), ref.begin(), ref.end(), 0.0);
2626
auto res = std::dynamic_pointer_cast<common::CudaGrowOnlyResource>(ref.Resource());
2727
CHECK(res);
28-
res->Resize(n * sizeof(double));
28+
res->Resize(n * sizeof(double), ctx.CUDACtx()->Stream());
2929

3030
auto ref1 = RefResourceView<double>(res->DataAs<double>(), res->Size() / sizeof(double),
3131
ref.Resource());
3232
ASSERT_EQ(res->Size(), n * sizeof(double));
3333
ASSERT_EQ(ref1.size(), n);
3434
thrust::sequence(ctx.CUDACtx()->CTP(), ref1.begin(), ref1.end(), static_cast<double>(0.0));
3535
std::vector<double> h_vec(ref1.size());
36-
dh::safe_cuda(cudaMemcpyAsync(h_vec.data(), ref1.data(), ref1.size_bytes(), cudaMemcpyDefault));
36+
dh::safe_cuda(cudaMemcpyAsync(h_vec.data(), ref1.data(), ref1.size_bytes(), cudaMemcpyDefault,
37+
ctx.CUDACtx()->Stream()));
38+
ctx.CUDACtx()->Stream().Sync();
3739
for (std::size_t i = 0; i < h_vec.size(); ++i) {
3840
ASSERT_EQ(h_vec[i], i);
3941
}
@@ -64,8 +66,7 @@ TEST(HostPinnedMemPool, Alloc) {
6466

6567
// Thread safety.
6668
auto n_threads = static_cast<std::int32_t>(std::thread::hardware_concurrency());
67-
common::ThreadPool workers{"tmempool", n_threads, [] {
68-
}};
69+
common::ThreadPool workers{"tmempool", n_threads, [] {}};
6970
std::vector<std::future<RefResourceView<double>>> alloc_futs;
7071
for (std::int32_t i = 0, n = n_threads * 4; i < n; ++i) {
7172
auto fut = workers.Submit([i, pool] {

0 commit comments

Comments
 (0)