Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a host-pinned memory resource that can be used as upstream for pool_memory_resource. #1392

Merged
merged 50 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
fae33fa
Add host_pinned_memory_resource and tests.
harrism Nov 28, 2023
15be572
Add missing maybe_unused alignment parameter and fix briefreturn
harrism Nov 28, 2023
e8c227b
Merge branch 'branch-24.02' into fea-host-pinned-mr
harrism Dec 5, 2023
2b37372
Respond to review feedback:
harrism Dec 6, 2023
c43a8c1
Add new util to get a fraction of available device mem, move availabl…
harrism Dec 19, 2023
d238daa
Deprecate old pool_mr ctors (optional initial size) and add new ctors…
harrism Dec 19, 2023
3d65d4c
Update all tests and resources to use new pool ctors and util
harrism Dec 19, 2023
66d85b4
Rename fraction_of_free_device_memory to percent_of_free_device_memory
harrism Dec 20, 2023
265de9b
clang-tidy Ignore 50 and 100 magic numbers
harrism Dec 20, 2023
0be364b
Remove straggler includes of removed file.
harrism Dec 20, 2023
266afa9
Merge branch 'branch-24.02' into fea-explicit-initial-pool-size
harrism Dec 20, 2023
5d66f40
Another missed include.
harrism Dec 20, 2023
fae5b73
Add detail::available_device_memory back as an alias of rmm::availabl…
harrism Jan 9, 2024
92c0653
merge branch 24.02
harrism Jan 9, 2024
2acf759
copyright
harrism Jan 9, 2024
a70b24e
Merge branch 'fea-explicit-initial-pool-size' into fea-host-pinned-mr
harrism Jan 9, 2024
b6edcd1
Rename file to match class and remove default alignment from some all…
harrism Jan 9, 2024
782ff55
document (and deprecate) available_device_memory alias
harrism Jan 9, 2024
4ef844a
Merge branch 'fea-explicit-initial-pool-size' into fea-host-pinned-mr
harrism Jan 9, 2024
ce58ff5
Add documentation for alignment params
harrism Jan 9, 2024
0b4c968
Respond to feedback from @wence-
harrism Jan 9, 2024
2f827a5
Merge branch 'fea-explicit-initial-pool-size' into fea-host-pinned-mr
harrism Jan 9, 2024
4f91478
Include doxygen deprecated output in docs
wence- Jan 9, 2024
f581809
Minor docstring fixes
wence- Jan 9, 2024
bafd70a
Don't use zero for default size in test.
harrism Jan 10, 2024
a77d215
Add non-detail alignment utilities
harrism Jan 10, 2024
07dffa3
Duplicate (for now) alignment utilities in rmm:: namespace since outs…
harrism Jan 10, 2024
8afff2d
Don't deprecate anything just yet (until cuDF/cuGraph updated)
harrism Jan 10, 2024
0140bd4
Merge branch 'fea-explicit-initial-pool-size' of github.com:harrism/r…
harrism Jan 10, 2024
91752c8
Make percent_of_free_device_memory do what it says on the tin.
harrism Jan 10, 2024
baf429c
Fix remaining uses of pool ctor in docs and code
harrism Jan 10, 2024
c90e81c
Fix overflow in percent_of_free_device_memory
harrism Jan 10, 2024
c2843be
Fix Cython to provide explicit initial size
harrism Jan 10, 2024
6e0aeaa
Respond to review suggestions in aligned.hpp
harrism Jan 10, 2024
c3c61e1
Fix quoted auto includes
harrism Jan 10, 2024
014ac5b
missed file for detail changes
harrism Jan 10, 2024
909b733
Add utilities doxygen group
harrism Jan 11, 2024
0fc3fba
Add utilities to sphinx docs
harrism Jan 11, 2024
9a876b5
Merge branch 'fea-explicit-initial-pool-size' into fea-host-pinned-mr
harrism Jan 11, 2024
b819738
Merge branch 'branch-24.02' into fea-host-pinned-mr
harrism Jan 15, 2024
27fe52c
Some cleanup of aligned_allocate/deallocate
harrism Jan 17, 2024
da934ba
Implement aligned alloc/dealloc and fix tests.
harrism Jan 17, 2024
7d51fea
Merge branch 'branch-24.02' into fea-host-pinned-mr
harrism Jan 17, 2024
85286b0
copyright year
harrism Jan 17, 2024
f7b0ca5
static_assert MR properties.
harrism Jan 18, 2024
52fc2f1
I don't know how those deprecated calls snuck back in.
harrism Jan 18, 2024
6162699
Rename aligned_[de]allocate to aligned_host_[de]allocate and clarify …
harrism Jan 18, 2024
fa140ae
Fix docs per feedback
harrism Jan 18, 2024
aafa18a
Factor out mr test utilities.
harrism Jan 18, 2024
92c8e23
Fix docstring for operator==
harrism Jan 18, 2024
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
10 changes: 5 additions & 5 deletions include/rmm/aligned.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ static constexpr std::size_t CUDA_ALLOCATION_ALIGNMENT{256};
/**
* @brief Returns whether or not `value` is a power of 2.
*
* @param[in] value to check.
* @param[in] value value to check.
*
* @return Whether the input a power of two with non-negative exponent
* @return True if the input is a power of two with non-negative integer exponent, false otherwise.
*/
[[nodiscard]] constexpr bool is_pow2(std::size_t value) noexcept
{
Expand All @@ -57,7 +57,7 @@ static constexpr std::size_t CUDA_ALLOCATION_ALIGNMENT{256};
*
* @param[in] alignment to check
*
* @return Whether the alignment is valid
* @return True if the alignment is valid, false otherwise.
*/
[[nodiscard]] constexpr bool is_supported_alignment(std::size_t alignment) noexcept
{
Expand All @@ -70,7 +70,7 @@ static constexpr std::size_t CUDA_ALLOCATION_ALIGNMENT{256};
* @param[in] value value to align
* @param[in] alignment amount, in bytes, must be a power of 2
*
* @return Return the aligned value, as one would expect
* @return the aligned value
*/
[[nodiscard]] constexpr std::size_t align_up(std::size_t value, std::size_t alignment) noexcept
{
Expand All @@ -84,7 +84,7 @@ static constexpr std::size_t CUDA_ALLOCATION_ALIGNMENT{256};
* @param[in] value value to align
* @param[in] alignment amount, in bytes, must be a power of 2
*
* @return Return the aligned value, as one would expect
* @return the aligned value
*/
[[nodiscard]] constexpr std::size_t align_down(std::size_t value, std::size_t alignment) noexcept
{
Expand Down
55 changes: 28 additions & 27 deletions include/rmm/detail/aligned.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,36 +108,35 @@ namespace rmm::detail {
}

/**
* @brief Allocates sufficient memory to satisfy the requested size `bytes` with
* @brief Allocates sufficient host-accessible memory to satisfy the requested size `bytes` with
* alignment `alignment` using the unary callable `alloc` to allocate memory.
*
* Given a pointer `p` to an allocation of size `n` returned from the unary
* callable `alloc`, the pointer `q` returned from `aligned_alloc` points to a
* location within the `n` bytes with sufficient space for `bytes` that
* satisfies `alignment`.
* Given a pointer `p` to an allocation of size `n` returned from the unary callable `alloc`, the
* pointer `q` returned from `aligned_alloc` points to a location within the `n` bytes with
* sufficient space for `bytes` that satisfies `alignment`.
*
* In order to retrieve the original allocation pointer `p`, the offset
* between `p` and `q` is stored at `q - sizeof(std::ptrdiff_t)`.
* In order to retrieve the original allocation pointer `p`, the offset between `p` and `q` is
* stored at `q - sizeof(std::ptrdiff_t)`.
*
* Allocations returned from `aligned_allocate` *MUST* be freed by calling
* `aligned_deallocate` with the same arguments for `bytes` and `alignment` with
* a compatible unary `dealloc` callable capable of freeing the memory returned
* from `alloc`.
* Allocations returned from `aligned_host_allocate` *MUST* be freed by calling
* `aligned_host_deallocate` with the same arguments for `bytes` and `alignment` with a compatible
* unary `dealloc` callable capable of freeing the memory returned from `alloc`.
*
* If `alignment` is not a power of 2, behavior is undefined.
* If `Alloc` does not allocate host-accessible memory, behavior is undefined.
wence- marked this conversation as resolved.
Show resolved Hide resolved
*
* @param bytes The desired size of the allocation
* @param alignment Desired alignment of allocation
* @param alloc Unary callable given a size `n` will allocate at least `n` bytes
* of host memory.
* @tparam Alloc a unary callable type that allocates memory.
* of host-accessible memory.
* @tparam Alloc a unary callable type that allocates host-accessible memory.
* @return void* Pointer into allocation of at least `bytes` with desired
* `alignment`.
*/
template <typename Alloc>
void* aligned_allocate(std::size_t bytes, std::size_t alignment, Alloc alloc)
void* aligned_host_allocate(std::size_t bytes, std::size_t alignment, Alloc alloc)
{
assert(rmm::is_pow2(alignment));
assert(rmm::is_supported_alignment(alignment));

// allocate memory for bytes, plus potential alignment correction,
// plus store of the correction offset
Expand All @@ -163,25 +162,27 @@ void* aligned_allocate(std::size_t bytes, std::size_t alignment, Alloc alloc)
}

/**
* @brief Frees an allocation returned from `aligned_allocate`.
* @brief Frees an allocation of host-accessible returned from `aligned_host_allocate`.
*
* Allocations returned from `aligned_allocate` *MUST* be freed by calling
* `aligned_deallocate` with the same arguments for `bytes` and `alignment`
* with a compatible unary `dealloc` callable capable of freeing the memory
* returned from `alloc`.
* Allocations returned from `aligned_host_allocate` *MUST* be freed by calling
* `aligned_host_deallocate` with the same arguments for `bytes` and `alignment` with a compatible
* unary `dealloc` callable capable of freeing the memory returned from `alloc`.
*
* @param p The aligned pointer to deallocate
* @param bytes The number of bytes requested from `aligned_allocate`
* @param alignment The alignment required from `aligned_allocate`
* @param dealloc A unary callable capable of freeing memory returned from
* `alloc` in `aligned_allocate`.
* @tparam Dealloc A unary callable type that deallocates memory.
* @param bytes The number of bytes requested from `aligned_host_allocate`
* @param alignment The alignment required from `aligned_host_allocate`
* @param dealloc A unary callable capable of freeing host-accessible memory returned from `alloc`
* in `aligned_host_allocate`.
* @tparam Dealloc A unary callable type that deallocates host-accessible memory.
*/
template <typename Dealloc>
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
void aligned_deallocate(void* ptr, std::size_t bytes, std::size_t alignment, Dealloc dealloc)
void aligned_host_deallocate(void* ptr,
[[maybe_unused]] std::size_t bytes,
[[maybe_unused]] std::size_t alignment,
Dealloc dealloc) noexcept
{
(void)alignment;
assert(rmm::is_supported_alignment(alignment));

// Get offset from the location immediately prior to the aligned pointer
// NOLINTNEXTLINE
Expand Down
4 changes: 2 additions & 2 deletions include/rmm/mr/host/new_delete_resource.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class new_delete_resource final : public host_memory_resource {
alignment =
(rmm::is_supported_alignment(alignment)) ? alignment : rmm::RMM_DEFAULT_HOST_ALIGNMENT;

return rmm::detail::aligned_allocate(
return rmm::detail::aligned_host_allocate(
bytes, alignment, [](std::size_t size) { return ::operator new(size); });
}

Expand All @@ -86,7 +86,7 @@ class new_delete_resource final : public host_memory_resource {
std::size_t bytes,
std::size_t alignment = rmm::RMM_DEFAULT_HOST_ALIGNMENT) override
{
rmm::detail::aligned_deallocate(
rmm::detail::aligned_host_deallocate(
ptr, bytes, alignment, [](void* ptr) { ::operator delete(ptr); });
}
};
Expand Down
4 changes: 2 additions & 2 deletions include/rmm/mr/host/pinned_memory_resource.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ class pinned_memory_resource final : public host_memory_resource {
alignment =
(rmm::is_supported_alignment(alignment)) ? alignment : rmm::RMM_DEFAULT_HOST_ALIGNMENT;

return rmm::detail::aligned_allocate(bytes, alignment, [](std::size_t size) {
return rmm::detail::aligned_host_allocate(bytes, alignment, [](std::size_t size) {
void* ptr{nullptr};
auto status = cudaMallocHost(&ptr, size);
if (cudaSuccess != status) { throw std::bad_alloc{}; }
Expand All @@ -173,7 +173,7 @@ class pinned_memory_resource final : public host_memory_resource {
std::size_t alignment = alignof(std::max_align_t)) override
{
if (nullptr == ptr) { return; }
rmm::detail::aligned_deallocate(
rmm::detail::aligned_host_deallocate(
ptr, bytes, alignment, [](void* ptr) { RMM_ASSERT_CUDA_SUCCESS(cudaFreeHost(ptr)); });
}
};
Expand Down
222 changes: 222 additions & 0 deletions include/rmm/mr/pinned_host_memory_resource.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
/*
* Copyright (c) 2024, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once

#include <rmm/aligned.hpp>
#include <rmm/detail/aligned.hpp>
#include <rmm/detail/error.hpp>

#include <cuda/memory_resource>
#include <cuda/stream_ref>

#include <cuda_runtime_api.h>

#include <cstddef>
#include <utility>

namespace rmm::mr {

/**
* @brief Memory resource class for allocating pinned host memory.
*
* This class uses CUDA's `cudaHostAlloc` to allocate pinned host memory. It implements the
* `cuda::mr::memory_resource` and `cuda::mr::device_memory_resource` concepts, and
* the `cuda::mr::host_accessible` and `cuda::mr::device_accessible` properties.
*/
class pinned_host_memory_resource {
public:
// Disable clang-tidy complaining about the easily swappable size and alignment parameters
// of allocate and deallocate
// NOLINTBEGIN(bugprone-easily-swappable-parameters)

/**
* @brief Allocates pinned host memory of size at least \p bytes bytes.
*
* @throws `rmm::out_of_memory` if the requested allocation could not be fulfilled due to to a
* CUDA out of memory error.
* @throws `rmm::bad_alloc` if the requested allocation could not be fulfilled due to any other
* reason.
*
* @param bytes The size, in bytes, of the allocation.
* @param alignment Alignment in bytes. Default alignment is used if unspecified.
*
* @return Pointer to the newly allocated memory.
*/
static void* allocate(std::size_t bytes,
[[maybe_unused]] std::size_t alignment = rmm::RMM_DEFAULT_HOST_ALIGNMENT)
{
// don't allocate anything if the user requested zero bytes
if (0 == bytes) { return nullptr; }

return rmm::detail::aligned_host_allocate(bytes, alignment, [](std::size_t size) {
void* ptr{nullptr};
RMM_CUDA_TRY_ALLOC(cudaHostAlloc(&ptr, size, cudaHostAllocDefault));
return ptr;
});
}

/**
* @brief Deallocate memory pointed to by \p ptr of size \p bytes bytes.
*
* @throws Nothing.
*
* @param ptr Pointer to be deallocated.
* @param bytes Size of the allocation.
* @param alignment Alignment in bytes. Default alignment is used if unspecified.
*/
static void deallocate(void* ptr,
std::size_t bytes,
std::size_t alignment = rmm::RMM_DEFAULT_HOST_ALIGNMENT) noexcept
{
rmm::detail::aligned_host_deallocate(
ptr, bytes, alignment, [](void* ptr) { RMM_ASSERT_CUDA_SUCCESS(cudaFreeHost(ptr)); });
}

/**
* @brief Allocates pinned host memory of size at least \p bytes bytes.
*
* @note Stream argument is ignored and behavior is identical to allocate.
*
* @throws `rmm::out_of_memory` if the requested allocation could not be fulfilled due to to a
* CUDA out of memory error.
* @throws `rmm::bad_alloc` if the requested allocation could not be fulfilled due to any other
* error.
*
* @param bytes The size, in bytes, of the allocation.
* @param stream CUDA stream on which to perform the allocation (ignored).
* @return Pointer to the newly allocated memory.
*/
static void* allocate_async(std::size_t bytes, [[maybe_unused]] cuda::stream_ref stream)
{
return allocate(bytes);
}

/**
* @brief Allocates pinned host memory of size at least \p bytes bytes and alignment \p alignment.
*
* @note Stream argument is ignored and behavior is identical to allocate.
*
* @throws `rmm::out_of_memory` if the requested allocation could not be fulfilled due to to a
* CUDA out of memory error.
* @throws `rmm::bad_alloc` if the requested allocation could not be fulfilled due to any other
* error.
*
* @param bytes The size, in bytes, of the allocation.
* @param alignment Alignment in bytes.
* @param stream CUDA stream on which to perform the allocation (ignored).
* @return Pointer to the newly allocated memory.
*/
static void* allocate_async(std::size_t bytes,
std::size_t alignment,
[[maybe_unused]] cuda::stream_ref stream)
{
return allocate(bytes, alignment);
}

/**
* @brief Deallocate memory pointed to by \p ptr of size \p bytes bytes.
*
* @note Stream argument is ignored and behavior is identical to deallocate.
*
* @throws Nothing.
*
* @param ptr Pointer to be deallocated.
* @param bytes Size of the allocation.
* @param stream CUDA stream on which to perform the deallocation (ignored).
*/
static void deallocate_async(void* ptr,
std::size_t bytes,
[[maybe_unused]] cuda::stream_ref stream) noexcept
{
return deallocate(ptr, bytes);
}

/**
* @brief Deallocate memory pointed to by \p ptr of size \p bytes bytes and alignment \p
* alignment bytes.
*
* @note Stream argument is ignored and behavior is identical to deallocate.
*
* @throws Nothing.
*
* @param ptr Pointer to be deallocated.
* @param bytes Size of the allocation.
* @param alignment Alignment in bytes.
* @param stream CUDA stream on which to perform the deallocation (ignored).
*/
static void deallocate_async(void* ptr,
std::size_t bytes,
std::size_t alignment,
[[maybe_unused]] cuda::stream_ref stream) noexcept
{
return deallocate(ptr, bytes, alignment);
}
// NOLINTEND(bugprone-easily-swappable-parameters)

/**
* @briefreturn{true if the specified resource is the same type as this resource.}
*/
bool operator==(const pinned_host_memory_resource&) const { return true; }

/**
* @briefreturn{true if the specified resource is not the same type as this resource, otherwise
* false.}
*/
bool operator!=(const pinned_host_memory_resource&) const { return false; }

/**
* @brief Query whether the resource supports reporting free and available memory.
*
* @return false
*/
static bool supports_get_mem_info() { return false; }

/**
* @brief Query the total amount of memory and free memory available for allocation by this
* resource.
*
* @throws nothing
*
* @return std::pair containing 0 for both total and free memory.
*/
[[nodiscard]] static std::pair<std::size_t, std::size_t> get_mem_info(cuda::stream_ref) noexcept
{
return {0, 0};
}

/**
* @brief Enables the `cuda::mr::device_accessible` property
*
* This property declares that a `pinned_host_memory_resource` provides device accessible memory
*/
friend void get_property(pinned_host_memory_resource const&, cuda::mr::device_accessible) noexcept
{
}

/**
* @brief Enables the `cuda::mr::host_accessible` property
*
* This property declares that a `pinned_host_memory_resource` provides host accessible memory
*/
friend void get_property(pinned_host_memory_resource const&, cuda::mr::host_accessible) noexcept
{
}
};

harrism marked this conversation as resolved.
Show resolved Hide resolved
static_assert(cuda::mr::async_resource_with<pinned_host_memory_resource,
cuda::mr::device_accessible,
cuda::mr::host_accessible>);
} // namespace rmm::mr
Loading