Skip to content

Commit f1871a4

Browse files
authored
[EM] Small fixes for hardware decompression. (#11512)
- Use a memory pool for result allocation. - Copy the parameters.
1 parent aeaf15a commit f1871a4

7 files changed

Lines changed: 66 additions & 27 deletions

File tree

src/common/cuda_rt_utils.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ std::int32_t CurrentDevice(bool raise) {
4242
}
4343

4444
// alternatively: `nvidia-smi -q | grep Addressing`
45-
bool SupportsPageableMem() {
45+
[[nodiscard]] bool SupportsPageableMem() {
4646
std::int32_t res{0};
4747
dh::safe_cuda(cudaDeviceGetAttribute(&res, cudaDevAttrPageableMemoryAccess, CurrentDevice()));
4848
return res == 1;
4949
}
5050

51-
bool SupportsAts() {
51+
[[nodiscard]] bool SupportsAts() {
5252
std::int32_t res{0};
5353
dh::safe_cuda(cudaDeviceGetAttribute(&res, cudaDevAttrPageableMemoryAccessUsesHostPageTables,
5454
CurrentDevice()));
@@ -106,7 +106,7 @@ void DrVersion(std::int32_t* major, std::int32_t* minor) {
106106

107107
[[nodiscard]] std::int32_t GetNumaId() {
108108
std::int32_t numa_id = -1;
109-
dh::safe_cuda(cudaDeviceGetAttribute(&numa_id, cudaDevAttrNumaId, curt::CurrentDevice()));
109+
dh::safe_cuda(cudaDeviceGetAttribute(&numa_id, cudaDevAttrHostNumaId, curt::CurrentDevice()));
110110
numa_id = std::max(numa_id, 0);
111111
return numa_id;
112112
}

src/common/cuda_rt_utils.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ std::int32_t CurrentDevice(bool raise = true);
1515

1616
// Whether the device supports coherently accessing pageable memory without calling
1717
// `cudaHostRegister` on it
18-
bool SupportsPageableMem();
18+
[[nodiscard]] bool SupportsPageableMem();
1919

2020
// Address Translation Service (ATS)
21-
bool SupportsAts();
21+
[[nodiscard]] bool SupportsAts();
2222

2323
void CheckComputeCapability();
2424

src/common/device_compression.cu

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,9 @@
2525
#include <mutex> // for once_flag, call_once
2626
#include <vector> // for vector
2727

28-
#include "compressed_iterator.h" // for CompressedByteT
29-
#include "cuda_context.cuh" // for CUDAContext
30-
#include "cuda_dr_utils.h" // for GetGlobalCuDriverApi
31-
#include "cuda_pinned_allocator.h" // for HostPinnedMemPool
28+
#include "compressed_iterator.h" // for CompressedByteT
29+
#include "cuda_context.cuh" // for CUDAContext
30+
#include "cuda_dr_utils.h" // for GetGlobalCuDriverApi
3231
#include "device_compression.h"
3332
#include "device_vector.cuh" // for DeviceUVector
3433
#include "nvtx_utils.h" // for xgboost_NVTX_FN_RANGE
@@ -154,9 +153,11 @@ void SafeNvComp(nvcompStatus_t status) {
154153
return de;
155154
}
156155

157-
SnappyDecomprMgrImpl::SnappyDecomprMgrImpl(
158-
dh::CUDAStreamView s, std::shared_ptr<common::cuda_impl::HostPinnedMemPool> pool,
159-
CuMemParams params, common::Span<std::uint8_t const> in_compressed_data) {
156+
SnappyDecomprMgrImpl::SnappyDecomprMgrImpl(dh::CUDAStreamView s,
157+
std::shared_ptr<HostPinnedMemPool> pool,
158+
CuMemParams params,
159+
common::Span<std::uint8_t const> in_compressed_data)
160+
: n_dst_bytes{params.TotalDstBytes()} {
160161
std::size_t n_chunks = params.size();
161162
if (n_chunks == 0) {
162163
return;
@@ -177,6 +178,7 @@ SnappyDecomprMgrImpl::SnappyDecomprMgrImpl(
177178
last_in += params[i].src_nbytes;
178179
last_out += params[i].dst_nbytes;
179180
}
181+
CHECK_EQ(this->n_dst_bytes, last_out);
180182

181183
// copy to d
182184
dh::CopyTo(in_chunk_ptrs, &this->d_in_chunk_ptrs, s);
@@ -210,6 +212,7 @@ SnappyDecomprMgrImpl::SnappyDecomprMgrImpl(
210212

211213
common::Span<CUmemDecompressParams> SnappyDecomprMgrImpl::GetParams(
212214
common::Span<common::CompressedByteT> out) {
215+
xgboost_NVTX_FN_RANGE_C(3, 252, 198);
213216
if (this->de_params.empty()) {
214217
return {};
215218
}
@@ -218,19 +221,34 @@ common::Span<CUmemDecompressParams> SnappyDecomprMgrImpl::GetParams(
218221
// Set the output buffers.
219222
std::size_t last_out = 0;
220223
for (std::size_t i = 0; i < n_chunks; ++i) {
224+
this->de_params_copy[i] = this->de_params[i];
221225
this->de_params_copy[i].dst = out.subspan(last_out, de_params[i].dstNumBytes).data();
222226
last_out += de_params[i].dstNumBytes;
223227
}
224228

225229
return this->de_params_copy.ToSpan();
226230
}
227231

232+
[[nodiscard]] bool SnappyDecomprMgrImpl::Empty() const {
233+
#if defined(CUDA_HW_DECOM_AVAILABLE)
234+
return this->de_params.empty();
235+
#else
236+
return true;
237+
#endif
238+
}
239+
228240
SnappyDecomprMgr::SnappyDecomprMgr() : pimpl_{std::make_unique<SnappyDecomprMgrImpl>()} {}
229241
SnappyDecomprMgr::SnappyDecomprMgr(SnappyDecomprMgr&& that) = default;
230242
SnappyDecomprMgr& SnappyDecomprMgr::operator=(SnappyDecomprMgr&& that) = default;
231243

232244
SnappyDecomprMgr::~SnappyDecomprMgr() = default;
233245

246+
[[nodiscard]] bool SnappyDecomprMgr::Empty() const { return this->Impl()->Empty(); }
247+
248+
[[nodiscard]] std::size_t SnappyDecomprMgr::DecompressedBytes() const {
249+
return this->Impl()->n_dst_bytes;
250+
}
251+
234252
SnappyDecomprMgrImpl* SnappyDecomprMgr::Impl() const { return this->pimpl_.get(); }
235253

236254
void DecompressSnappy(dh::CUDAStreamView stream, SnappyDecomprMgr const& mgr,
@@ -272,7 +290,7 @@ void DecompressSnappy(dh::CUDAStreamView stream, SnappyDecomprMgr const& mgr,
272290
dh::device_vector<void*> d_out_ptrs(n_chunks);
273291
dh::safe_cuda(cudaMemcpyAsync(d_out_ptrs.data().get(), h_out_ptrs.data(),
274292
dh::ToSpan(d_out_ptrs).size_bytes(), cudaMemcpyDefault, stream));
275-
293+
CHECK(curt::SupportsPageableMem() || curt::SupportsAts());
276294
// Run nvcomp
277295
SafeNvComp(nvcompBatchedSnappyDecompressAsync(
278296
mgr_impl->d_in_chunk_ptrs.data().get(), mgr_impl->d_in_chunk_sizes.data().get(),
@@ -387,8 +405,9 @@ void DecompressSnappy(dh::CUDAStreamView stream, SnappyDecomprMgr const& mgr,
387405
}
388406

389407
[[nodiscard]] common::RefResourceView<std::uint8_t> CoalesceCompressedBuffersToHost(
390-
dh::CUDAStreamView stream, CuMemParams const& in_params,
391-
dh::DeviceUVector<std::uint8_t> const& in_buf, CuMemParams* p_out) {
408+
dh::CUDAStreamView stream, std::shared_ptr<HostPinnedMemPool> pool,
409+
CuMemParams const& in_params, dh::DeviceUVector<std::uint8_t> const& in_buf,
410+
CuMemParams* p_out) {
392411
std::size_t n_total_act_bytes = in_params.TotalSrcActBytes();
393412
std::size_t n_total_bytes = in_params.TotalSrcBytes();
394413
if (n_total_bytes == 0) {
@@ -399,8 +418,8 @@ void DecompressSnappy(dh::CUDAStreamView stream, SnappyDecomprMgr const& mgr,
399418
// copy from device buffer to the host cache.
400419
CHECK_EQ(n_total_bytes, in_buf.size());
401420
auto c_page =
402-
common::MakeFixedVecWithPinnedMalloc<std::remove_reference_t<decltype(in_buf)>::value_type>(
403-
n_total_act_bytes);
421+
common::MakeFixedVecWithPinnedMemPool<std::remove_reference_t<decltype(in_buf)>::value_type>(
422+
pool, n_total_act_bytes, stream);
404423
std::vector<std::uint8_t const*> srcs(in_params.size());
405424
std::vector<std::uint8_t*> dsts(in_params.size());
406425
std::vector<std::size_t> sizes(in_params.size());
@@ -450,6 +469,12 @@ SnappyDecomprMgr& SnappyDecomprMgr::operator=(SnappyDecomprMgr&& that) = default
450469
SnappyDecomprMgr::~SnappyDecomprMgr() = default;
451470
SnappyDecomprMgrImpl* SnappyDecomprMgr::Impl() const { return nullptr; }
452471

472+
[[nodiscard]] bool SnappyDecomprMgr::Empty() const { return true; }
473+
[[nodiscard]] std::size_t SnappyDecomprMgr::DecompressedBytes() const {
474+
common::AssertNvCompSupport();
475+
return 0;
476+
}
477+
453478
// Round-trip compression
454479
void DecompressSnappy(dh::CUDAStreamView, SnappyDecomprMgr const&,
455480
common::Span<common::CompressedByteT>, bool) {
@@ -464,7 +489,8 @@ void DecompressSnappy(dh::CUDAStreamView, SnappyDecomprMgr const&,
464489
}
465490

466491
[[nodiscard]] common::RefResourceView<std::uint8_t> CoalesceCompressedBuffersToHost(
467-
dh::CUDAStreamView, CuMemParams const&, dh::DeviceUVector<std::uint8_t> const&, CuMemParams*) {
492+
dh::CUDAStreamView, std::shared_ptr<HostPinnedMemPool>, CuMemParams const&,
493+
dh::DeviceUVector<std::uint8_t> const&, CuMemParams*) {
468494
common::AssertNvCompSupport();
469495
return {};
470496
}

src/common/device_compression.cuh

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
#include "xgboost/span.h" // for Span
1616

1717
namespace xgboost::dc {
18+
19+
using HostPinnedMemPool = common::cuda_impl::HostPinnedMemPool;
20+
1821
/**
1922
* @brief Use nvcomp to compress the data.
2023
*
@@ -44,19 +47,22 @@ void DecompressSnappy(dh::CUDAStreamView stream, SnappyDecomprMgr const& mgr,
4447
* @brief Coalesce the compressed chunks into a contiguous host pinned buffer.
4548
*
4649
* @param stream CUDA stream.
50+
* @param pool Pinned memory pool for storing the results.
4751
* @param in_params Params from @ref CompressSnappy, specifies the chunks.
4852
* @param in_buf The buffer storing compressed chunks.
4953
* @param p_out Re-newed parameters to keep track of the buffers.
5054
*/
5155
[[nodiscard]] common::RefResourceView<std::uint8_t> CoalesceCompressedBuffersToHost(
52-
dh::CUDAStreamView stream, CuMemParams const& in_params,
53-
dh::DeviceUVector<std::uint8_t> const& in_buf, CuMemParams* p_out);
56+
dh::CUDAStreamView stream, std::shared_ptr<HostPinnedMemPool> pool,
57+
CuMemParams const& in_params, dh::DeviceUVector<std::uint8_t> const& in_buf,
58+
CuMemParams* p_out);
5459

5560
// We store decompression parameters in struct of vectors. This is due to nvcomp works
5661
// with this format. But the CUDA driver works with vector of structs. We can optimize
5762
// toward the driver decompression function if the overhead is significant (too many
5863
// chunks).
5964
struct SnappyDecomprMgrImpl {
65+
std::size_t n_dst_bytes{0};
6066
// src of the CUmemDecompressParams
6167
dh::device_vector<void const*> d_in_chunk_ptrs;
6268
// srcNumBytes of the CUmemDecompressParams
@@ -81,8 +87,7 @@ struct SnappyDecomprMgrImpl {
8187
#endif // defined(CUDA_HW_DECOM_AVAILABLE)
8288
}
8389

84-
SnappyDecomprMgrImpl(dh::CUDAStreamView s,
85-
std::shared_ptr<common::cuda_impl::HostPinnedMemPool> pool,
90+
SnappyDecomprMgrImpl(dh::CUDAStreamView s, std::shared_ptr<HostPinnedMemPool> pool,
8691
CuMemParams params, common::Span<std::uint8_t const> in_compressed_data);
8792

8893
#if defined(CUDA_HW_DECOM_AVAILABLE) && defined(XGBOOST_USE_NVCOMP)
@@ -95,10 +100,11 @@ struct SnappyDecomprMgrImpl {
95100
SnappyDecomprMgrImpl(SnappyDecomprMgrImpl&& that) = default;
96101
SnappyDecomprMgrImpl& operator=(SnappyDecomprMgrImpl const&) = delete;
97102
SnappyDecomprMgrImpl& operator=(SnappyDecomprMgrImpl&&) = default;
103+
104+
[[nodiscard]] bool Empty() const;
98105
};
99106

100-
inline auto MakeSnappyDecomprMgr(dh::CUDAStreamView s,
101-
std::shared_ptr<common::cuda_impl::HostPinnedMemPool> pool,
107+
inline auto MakeSnappyDecomprMgr(dh::CUDAStreamView s, std::shared_ptr<HostPinnedMemPool> pool,
102108
CuMemParams params,
103109
common::Span<std::uint8_t const> in_compressed_data) {
104110
SnappyDecomprMgr mgr;

src/common/device_compression.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ class SnappyDecomprMgr {
112112

113113
SnappyDecomprMgrImpl* Impl() const;
114114

115+
[[nodiscard]] bool Empty() const;
116+
/**
117+
* @brief The number of bytes of the uncompressed data.
118+
*/
119+
[[nodiscard]] std::size_t DecompressedBytes() const;
120+
115121
private:
116122
// Hide the CUDA API calls.
117123
#if defined(XGBOOST_USE_NVCOMP)

src/data/sparse_page_source.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ class SparsePageSourceImpl : public BatchIteratorImpl<S>, public FormatStreamPol
362362

363363
timer.Stop();
364364
if (bytes != InvalidPageSize()) {
365-
// Not entirely accurate, the kernels doesn't have to flush the data.
365+
// Not entirely accurate, the kernel doesn't have to flush the data.
366366
LOG(INFO) << common::HumanMemUnit(bytes) << " written in " << timer.ElapsedSeconds()
367367
<< " seconds.";
368368
cache_info_->Push(bytes);

tests/cpp/common/test_device_compression.cu

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,12 @@ class TestNvComp : public ::testing::TestWithParam<std::tuple<std::size_t, std::
7171
ASSERT_GE(params.size(), n_bytes / n_chunk_bytes);
7272
}
7373

74+
auto pool = std::make_shared<common::cuda_impl::HostPinnedMemPool>();
75+
7476
CuMemParams out_params;
75-
auto page = CoalesceCompressedBuffersToHost(cuctx->Stream(), params, compr, &out_params);
77+
auto page = CoalesceCompressedBuffersToHost(cuctx->Stream(), pool, params, compr, &out_params);
7678

7779
dh::device_vector<common::CompressedByteT> dout(in.size(), 0);
78-
auto pool = std::make_shared<common::cuda_impl::HostPinnedMemPool>();
7980
auto mgr = MakeSnappyDecomprMgr(cuctx->Stream(), pool, out_params, page.ToSpan());
8081
DecompressSnappy(cuctx->Stream(), mgr, dh::ToSpan(dout), true);
8182

0 commit comments

Comments
 (0)