Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
a9d8b42
adding fixed_sized_host_buffer
nirandaperera Feb 13, 2026
b9363cb
adding tests
nirandaperera Feb 13, 2026
9948837
adding more tests
nirandaperera Feb 13, 2026
a999ef2
private ctr
nirandaperera Feb 13, 2026
ee58be4
addressing PR comments
nirandaperera Feb 18, 2026
48091b1
addressing PR comments
nirandaperera Feb 18, 2026
566ef1a
Merge branch 'main' of github.com:rapidsai/rapidsmpf into fixed_sized…
nirandaperera Feb 18, 2026
8e7e7e6
simplifying logic
nirandaperera Feb 18, 2026
d055b34
fixing bounds block_data
nirandaperera Feb 18, 2026
ebdb514
Apply suggestions from code review
nirandaperera Feb 18, 2026
c810e13
adding copy to
nirandaperera Mar 5, 2026
fba90d6
bypass batchcpy from default stream
nirandaperera Mar 5, 2026
1f5e3e4
temp test fixes
nirandaperera Mar 5, 2026
b52c4e6
hack size
nirandaperera Mar 5, 2026
d152fed
Merge branch 'main' of github.com:rapidsai/rapidsmpf into fixed_sized…
nirandaperera Mar 5, 2026
fd17f5e
API changes
nirandaperera Mar 5, 2026
9a17f9e
Merge branch 'main' of github.com:rapidsai/rapidsmpf into fixed_sized…
nirandaperera Mar 5, 2026
6075dfb
API change
nirandaperera Mar 6, 2026
67c61c5
minor change
nirandaperera Mar 9, 2026
1c9f08b
Merge branch 'main' of github.com:rapidsai/rapidsmpf into fixed_sized…
nirandaperera Mar 9, 2026
a9a6ad2
fix cucascade build
nirandaperera Mar 9, 2026
08d4ccb
use fixed buffers in tablechunk copy
nirandaperera Mar 11, 2026
0df229f
Merge branch 'main' of github.com:rapidsai/rapidsmpf into fixed_sized…
nirandaperera Mar 11, 2026
c585aa7
fsmr from options
nirandaperera Mar 11, 2026
a1aa601
dask fro options
nirandaperera Mar 11, 2026
dbaf1d9
fix size descrepency
nirandaperera Mar 11, 2026
8657337
estimate size usage
nirandaperera Mar 11, 2026
355e7c5
Merge branch 'main' of github.com:rapidsai/rapidsmpf into fixed_sized…
nirandaperera Mar 11, 2026
d447a88
correctness fix
nirandaperera Mar 11, 2026
168ee3a
possible fix
nirandaperera Mar 11, 2026
6975951
minor change
nirandaperera Mar 12, 2026
5322bc9
minor change2
nirandaperera Mar 12, 2026
93f606a
investigation
nirandaperera Mar 12, 2026
5012417
MINOR FIX
nirandaperera Mar 12, 2026
9e7c0d7
fix danglingref
nirandaperera Mar 12, 2026
3dc7550
minor change
nirandaperera Mar 12, 2026
0d8233e
revert
nirandaperera Mar 12, 2026
2ea4806
fix block bounds
nirandaperera Mar 13, 2026
8cd7046
Merge branch 'main' of github.com:rapidsai/rapidsmpf into fixed_sized…
nirandaperera Mar 13, 2026
77bf023
revert change
nirandaperera Mar 13, 2026
fdb9d47
trying with host mr
nirandaperera Mar 13, 2026
5c32c78
switch to host mr
nirandaperera Mar 13, 2026
5d4370b
Merge branch 'main' of github.com:rapidsai/rapidsmpf into fixed_sized…
nirandaperera Mar 18, 2026
20413cc
minor bu
nirandaperera Mar 18, 2026
5bf25a9
minor fix
nirandaperera Mar 18, 2026
e90841d
set size
nirandaperera Mar 18, 2026
ec6e36e
Revert "set size"
nirandaperera Mar 18, 2026
5182515
investgation
nirandaperera Mar 18, 2026
67fcd02
investigation 2
nirandaperera Mar 18, 2026
8087c49
investigation 3
nirandaperera Mar 18, 2026
734d5a7
better errors
nirandaperera Mar 18, 2026
f88d605
trying to fix the pack error
nirandaperera Mar 18, 2026
4b743e3
reenable batchcpy
nirandaperera Mar 19, 2026
719d21d
using batch cpy
nirandaperera Mar 19, 2026
ee85b95
use sequential
nirandaperera Mar 19, 2026
ef71eab
minor
nirandaperera Mar 19, 2026
eb47413
Revert "use sequential"
nirandaperera Mar 19, 2026
7e5c857
Merge branch 'main' of github.com:rapidsai/rapidsmpf into fixed_sized…
nirandaperera Mar 19, 2026
882bf76
precommit
nirandaperera Mar 19, 2026
579e1df
dask cluster bootstrap from options
nirandaperera Mar 21, 2026
145a622
enable pinned memory by default
nirandaperera Mar 21, 2026
68844d6
fix tests
nirandaperera Mar 23, 2026
647bbf7
cython fix
nirandaperera Mar 23, 2026
e6c1161
fix dask test
nirandaperera Mar 23, 2026
cd5f989
fix test
nirandaperera Mar 24, 2026
8fa078a
add custom options
nirandaperera Mar 24, 2026
be1ac13
Merge branch 'main' of github.com:rapidsai/rapidsmpf into dask_cluste…
nirandaperera Mar 24, 2026
5a7653a
reset tests
nirandaperera Mar 24, 2026
ef80ef3
attempting to fix exception
nirandaperera Mar 24, 2026
4c816bb
Apply suggestion from @madsbk
nirandaperera Mar 24, 2026
8abe390
fix error
nirandaperera Mar 24, 2026
b2d6fca
Merge branch 'dask_cluster_bootstrap_with_options' of github.com:nira…
nirandaperera Mar 24, 2026
474e6d0
precommit
nirandaperera Mar 24, 2026
030b198
Merge branch 'main' of github.com:rapidsai/rapidsmpf into fixed_sized…
nirandaperera Mar 24, 2026
10db289
skipping for default stream
nirandaperera Mar 24, 2026
5a8613d
docs fix
nirandaperera Mar 24, 2026
91dbe8c
Apply suggestions from code review
nirandaperera Mar 25, 2026
861b212
precommit
nirandaperera Mar 25, 2026
90df014
Merge remote-tracking branch 'nira/dask_cluster_bootstrap_with_option…
nirandaperera Mar 25, 2026
6b0b4f4
adding bench
nirandaperera Mar 25, 2026
eb1d3f0
bench
nirandaperera Mar 25, 2026
30bea79
limit pinned mem
nirandaperera Mar 30, 2026
3a995a3
Merge branch 'main' of github.com:rapidsai/rapidsmpf into fixed_sized…
nirandaperera Mar 30, 2026
2b0b47b
extending bench
nirandaperera Apr 7, 2026
5178878
Merge branch 'main' of github.com:rapidsai/rapidsmpf into fixed_sized…
nirandaperera Apr 7, 2026
a26fc03
merge conflicts
nirandaperera Apr 8, 2026
822a247
adding stream pool
nirandaperera Apr 8, 2026
94ae1b2
adding threads
nirandaperera Apr 8, 2026
93ede18
extending bench
nirandaperera Apr 9, 2026
0152761
adding second bench
nirandaperera Apr 14, 2026
0343712
standalone reproducer for cccl team
nirandaperera Apr 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ add_library(
src/integrations/cudf/utils.cpp
src/memory/buffer.cpp
src/memory/buffer_resource.cpp
src/memory/fixed_sized_host_buffer.cpp
src/memory/host_buffer.cpp
src/memory/host_memory_resource.cpp
src/memory/memory_reservation.cpp
Expand Down
202 changes: 202 additions & 0 deletions cpp/include/rapidsmpf/memory/fixed_sized_host_buffer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
/**
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
Comment thread
nirandaperera marked this conversation as resolved.
Outdated
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once

#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <span>
#include <stdexcept>
#include <utility>
#include <vector>

#include <cucascade/memory/fixed_size_host_memory_resource.hpp>

namespace rapidsmpf {

/**
* @brief Buffer of fixed-size host memory blocks with type-erased storage.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Nothing about this object requires that the memory is host memory. Do we need to it to be?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't really. Since we discussed that we won't be needing a fixed-sized buffers in device memory, I thought limiting this to host.

*
* Holds a total size in bytes, a block size, and a span of block start pointers.
* Storage is type-erased via `unique_ptr<void, deleter>`, so different backends
* can be used: a single vector (split into blocks), a vector of vectors, or
* e.g. cucascade's multiple_blocks_allocation.
*/
class FixedSizedHostBuffer {
public:
/// Type-erased deleter invoked with the storage pointer on destruction.
using storage_deleter_type = std::function<void(void*)>;

/// @brief Default block size of 1 MiB.
static constexpr size_t default_block_size = size_t(1) << 20;

/**
* @brief Construct an empty buffer with a given block size.
* @param block_size Size of each block in bytes.
*/
explicit FixedSizedHostBuffer(size_t block_size = default_block_size)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good to avoid a default block size.

Suggested change
explicit FixedSizedHostBuffer(size_t block_size = default_block_size)
explicit FixedSizedHostBuffer(size_t block_size)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Why is this a useful ctor? We can't set up a buffer with a block size and then later add the storage, so it seems like the object you get back here is not useful.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! This was to handle empty data cases. I thought it should be valid to pass empty containers to the factory methods. So, at that point, we need a "default state" for the buffer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this now to use the default constructor and overloaded the equality operator. I think that can achieve the same effect

: block_size_(block_size) {}

/**
* @brief Construct from a single contiguous vector split into fixed-size blocks.
*
* Takes ownership of @p vec by moving it into internal storage.
*
* @param vec Contiguous bytes (moved from).
* @param block_size Size of each block in bytes.
* @return A buffer with blocks covering the vector.
*/
static FixedSizedHostBuffer from_vector(
std::vector<std::byte> vec, std::size_t block_size
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::vector<std::byte> vec, std::size_t block_size
std::vector<std::byte> && vec, std::size_t block_size

);

/**
* @brief Construct from a vector of vectors (one block per inner vector).
*
* Takes ownership of @p vecs. Each inner vector becomes one block; all must
* have the same size.
*
* @param vecs Vector of byte vectors (moved from).
* @return A buffer with one block per inner vector.
*/
static FixedSizedHostBuffer from_vectors(std::vector<std::vector<std::byte>> vecs);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static FixedSizedHostBuffer from_vectors(std::vector<std::vector<std::byte>> vecs);
static FixedSizedHostBuffer from_vectors(std::vector<std::vector<std::byte>>&& vecs);


/**
* @brief Construct from a cucascade multiple_blocks_allocation.
*
* Takes ownership of @p allocation. When the buffer is destroyed, blocks are
* returned to the memory resource via the allocation's destructor.
*
* @param allocation Unique pointer to the allocation (moved from).
* @return A buffer backed by the allocation's blocks.
*/
static FixedSizedHostBuffer from_multi_blocks_alloc(
cucascade::memory::fixed_multiple_blocks_allocation allocation
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cucascade::memory::fixed_multiple_blocks_allocation allocation
cucascade::memory::fixed_multiple_blocks_allocation && allocation

);

FixedSizedHostBuffer(FixedSizedHostBuffer const&) = delete;
FixedSizedHostBuffer& operator=(FixedSizedHostBuffer const&) = delete;

/**
* @brief Move constructor; the moved-from buffer is left empty.
* @param other Buffer to move from.
*/
FixedSizedHostBuffer(FixedSizedHostBuffer&& other) noexcept;

/**
* @brief Move assignment; the moved-from buffer is left empty.
* @param other Buffer to move from.
* @return Reference to this buffer.
*/
FixedSizedHostBuffer& operator=(FixedSizedHostBuffer&& other) noexcept;

/**
* @brief Total size in bytes across all blocks.
* @return Total number of bytes.
*/
[[nodiscard]] constexpr std::size_t total_size() const noexcept {
return total_size_;
}

/**
* @brief Size of each block in bytes.
* @return Block size in bytes.
*/
[[nodiscard]] constexpr std::size_t block_size() const noexcept {
return block_size_;
}

/**
* @brief Number of blocks.
* @return Number of blocks.
*/
[[nodiscard]] constexpr std::size_t num_blocks() const noexcept {
return block_ptrs_.size();
}

/**
* @brief Span of block start pointers (mutable).
* @return Span of block start pointers.
*/
[[nodiscard]] constexpr std::span<std::byte*> blocks() noexcept {
return block_ptrs_;
}

/**
* @brief Span of block start pointers (const).
* @return Span of block start pointers.
*/
[[nodiscard]] constexpr std::span<std::byte* const> blocks() const noexcept {
return block_ptrs_;
}

/**
* @brief True if there are no blocks.
* @return True if empty, false otherwise.
*/
[[nodiscard]] constexpr bool empty() const noexcept {
return block_ptrs_.empty();
}

/**
* @brief Reset to empty state (release storage, zero sizes, clear block span).
*/
void reset() noexcept;

/**
* @brief The i-th block as a span of bytes.
*
* @param i Block index in [0, num_blocks()).
* @return Span of length block_size() over the block's bytes.
* @throws std::out_of_range if i >= num_blocks().
*/
[[nodiscard]] std::span<std::byte> block_data(std::size_t i);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: cuda::std::span in case we want it usable both on host and as an argument to a kernel?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we can do that. If we decide to remove Host from the name, then, let's use cuda::std::span. WDYT?


/**
* @brief The i-th block as a span of bytes.
*
* @param i Block index in [0, num_blocks()).
* @return Span of length block_size() over the block's bytes.
* @throws std::out_of_range if i >= num_blocks().
*/
[[nodiscard]] std::span<std::byte const> block_data(std::size_t i) const;

private:
/**
* @brief Type-erased constructor: take ownership of storage and block metadata.
*
* The deleter is invoked with the storage pointer when this buffer is destroyed.
* @p block_ptrs must refer to memory that remains valid for the lifetime of this
* buffer (typically inside the storage), e.g. from get_blocks() on
* multiple_blocks_allocation.
*
* @param size Total size in bytes.
* @param block_size Size of each block in bytes.
* @param block_ptrs View of block start pointers (not copied; must outlive this
* buffer).
* @param storage Type-erased pointer to the storage (e.g. vector, allocation
* wrapper).
* @param deleter Called with @p storage on destruction.
*/
FixedSizedHostBuffer(
std::size_t size,
std::size_t block_size,
std::span<std::byte*> block_ptrs,
void* storage,
storage_deleter_type deleter
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use rapidsmpf::OwningWrapper.

)
: storage_(storage, std::move(deleter)),
total_size_(size),
block_size_(block_size),
block_ptrs_(block_ptrs) {}

std::unique_ptr<void, storage_deleter_type> storage_{};
std::size_t total_size_{0};
std::size_t block_size_{default_block_size};
std::span<std::byte*> block_ptrs_{};
};

} // namespace rapidsmpf
146 changes: 146 additions & 0 deletions cpp/src/memory/fixed_sized_host_buffer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/**
* SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
Comment thread
nirandaperera marked this conversation as resolved.
Outdated
* SPDX-License-Identifier: Apache-2.0
*/


#include <algorithm>
#include <ranges>

#include <rapidsmpf/error.hpp>
#include <rapidsmpf/memory/fixed_sized_host_buffer.hpp>

#include <cucascade/memory/fixed_size_host_memory_resource.hpp>

namespace {

template <typename T>
struct VectorStorage {
std::vector<std::byte*> block_ptrs;
T storage;
};
} // namespace

namespace rapidsmpf {

FixedSizedHostBuffer FixedSizedHostBuffer::from_vector(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I am not sure I like this name. FixedSizeXXXBuffer suggests that the buffer is of a fixed size (i.e. not resizeable). But none of our buffers are resizeable.

I cannot immediately think of a good name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about BlockedBuffer? I'm pretty bad with names 😇 Open for suggestions

std::vector<std::byte> vec, std::size_t block_size
) {
if (vec.empty()) {
return FixedSizedHostBuffer(0, block_size, {}, nullptr, {});
}

std::size_t total_size = vec.size();
auto shared = std::make_shared<VectorStorage<std::vector<std::byte>>>();
shared->block_ptrs.reserve((total_size + block_size - 1) / block_size);
for (std::size_t i = 0; i < total_size; i += block_size) {
shared->block_ptrs.push_back(vec.data() + i);
}
shared->storage = std::move(vec);
std::span<std::byte*> blocks_span(shared->block_ptrs);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With OwningWrapper I think this could be:

auto owner = OwningWrapper(new VectorStorage<std::vector<std::byte>>(), std::default_delete);
...

?

return FixedSizedHostBuffer(
total_size,
block_size,
blocks_span,
shared.get(),
[shared_ = std::move(shared)](void*) mutable { shared_.reset(); }
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Why do you need a shared ptr for the storage?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its because std::function needs to copyable (maybe in c++23 we can use a move_only_function :-) )

}

FixedSizedHostBuffer FixedSizedHostBuffer::from_multi_blocks_alloc(
cucascade::memory::fixed_multiple_blocks_allocation allocation
) {
if (!allocation || allocation->size() == 0) {
return FixedSizedHostBuffer(
allocation && allocation->block_size() > 0 ? allocation->block_size()
: default_block_size
);
}
auto shared = std::shared_ptr<
cucascade::memory::fixed_size_host_memory_resource::multiple_blocks_allocation>(
std::move(allocation)
);
std::span<std::byte*> blocks = shared->get_blocks();
std::size_t total_bytes = shared->size_bytes();
std::size_t block_sz = shared->block_size();
return FixedSizedHostBuffer(
total_bytes,
block_sz,
blocks,
shared.get(),
[shared_ = std::move(shared)](void*) mutable { shared_.reset(); }
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, use OwningWrapper and no need for shared_ptr I think.

}

FixedSizedHostBuffer FixedSizedHostBuffer::from_vectors(
std::vector<std::vector<std::byte>> vecs
) {
if (vecs.empty()) {
return FixedSizedHostBuffer();
}

size_t const block_sz = vecs[0].size();
size_t const total_size = block_sz * vecs.size();
RAPIDSMPF_EXPECTS(
std::ranges::all_of(vecs, [&](auto const& v) { return v.size() == block_sz; }),
"all vectors must be of the same size"
);

auto shared = std::make_shared<VectorStorage<std::vector<std::vector<std::byte>>>>();

shared->block_ptrs.reserve(shared->storage.size());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
shared->block_ptrs.reserve(shared->storage.size());
shared->block_ptrs.reserve(vecs.size());

std::ranges::transform(vecs, std::back_inserter(shared->block_ptrs), [](auto& v) {
return v.data();
});
shared->storage = std::move(vecs);
std::span<std::byte*> blocks_span(shared->block_ptrs);
return FixedSizedHostBuffer(
total_size,
block_sz,
std::move(blocks_span),
shared.get(),
[shared_ = std::move(shared)](void*) mutable { shared_.reset(); }
);
}

void FixedSizedHostBuffer::reset() noexcept {
storage_.reset();
total_size_ = 0;
block_size_ = default_block_size;
block_ptrs_ = {};
}

FixedSizedHostBuffer::FixedSizedHostBuffer(FixedSizedHostBuffer&& other) noexcept
: storage_(std::move(other.storage_)),
total_size_(other.total_size_),
block_size_(other.block_size_),
block_ptrs_(other.block_ptrs_) {
other.reset();
}

FixedSizedHostBuffer& FixedSizedHostBuffer::operator=(
FixedSizedHostBuffer&& other
) noexcept {
storage_ = std::move(other.storage_);
total_size_ = other.total_size_;
block_size_ = other.block_size_;
block_ptrs_ = other.block_ptrs_;
other.reset();
return *this;
}

std::span<std::byte> FixedSizedHostBuffer::block_data(std::size_t i) {
RAPIDSMPF_EXPECTS(
i < num_blocks(), "FixedSizedHostBuffer::block_data", std::out_of_range
);
return std::span<std::byte>{block_ptrs_[i], block_size_};
}

std::span<std::byte const> FixedSizedHostBuffer::block_data(std::size_t i) const {
RAPIDSMPF_EXPECTS(
i < num_blocks(), "FixedSizedHostBuffer::block_data", std::out_of_range
);
return std::span<std::byte const>{block_ptrs_[i], block_size_};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: If the size of the owned data is not evenly divisible by the block size then, depending on the backing storage, the end pointer of this span is not valid (-> UB if accessed) for the last block.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I intentionally did this TBH. I thought callers can unwrap num_blocks() - 1 blocks with block_size() and clean up the last one with the remainder. This removes the std::min for each block_data() call.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway, since you brought it up, I reverted it. Maybe its best to keep the API simple

}

} // namespace rapidsmpf
2 changes: 1 addition & 1 deletion cpp/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ target_compile_options(
)
target_link_libraries(
test_sources
PRIVATE rapidsmpf::rapidsmpf cudf::cudftestutil cudf::cudftestutil_impl
PRIVATE rapidsmpf::rapidsmpf cuCascade::cucascade cudf::cudftestutil cudf::cudftestutil_impl
$<$<BOOL:${RAPIDSMPF_HAVE_NUMA}>:numa>
PUBLIC GTest::gmock GTest::gtest
)
Expand Down
Loading