Skip to content

[AsyncAlloc][SYCL][ABI-BREAK] Use the SYCL properties extension for memory pool creation #17955

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

Merged
merged 12 commits into from
Jun 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 0 additions & 6 deletions sycl/include/sycl/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,12 +256,6 @@ class __SYCL_EXPORT context : public detail::OwnerLessBase<context> {
ext_oneapi_get_default_memory_pool(const device &dev,
sycl::usm::alloc kind) const;

/// Gets default memory pool associated with the context and allocation kind.
///
/// \return a memory pool associated with this context.
sycl::ext::oneapi::experimental::memory_pool
ext_oneapi_get_default_memory_pool(sycl::usm::alloc kind) const;

private:
/// Constructs a SYCL context object from a valid context_impl instance.
context(std::shared_ptr<detail::context_impl> Impl);
Expand Down
8 changes: 2 additions & 6 deletions sycl/include/sycl/detail/property_helper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,8 @@ enum DataLessPropKind {
GraphDependOnAllLeaves = 24,
GraphUpdatable = 25,
GraphEnableProfiling = 26,
MemPoolReadOnly = 27,
MemPoolZeroInit = 28,
// Indicates the last known dataless property.
LastKnownDataLessPropKind = 28,
LastKnownDataLessPropKind = 26,
// Exceeding 32 may cause ABI breaking change on some of OSes.
DataLessPropKindSize = 32
};
Expand All @@ -69,9 +67,7 @@ enum PropWithDataKind {
AccPropBufferLocation = 5,
QueueComputeIndex = 6,
GraphNodeDependencies = 7,
MemPoolInitialThreshold = 8,
MemPoolMaximumSize = 9,
PropWithDataKindSize = 10
PropWithDataKindSize = 8
};

// Base class for dataless properties, needed to check that the type of an
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,39 +24,21 @@ class memory_pool_impl;

/// Memory pool
class __SYCL_EXPORT memory_pool {

public:
// NOT SUPPORTED: Host side pools unsupported.
memory_pool(const sycl::context &, sycl::usm::alloc kind,
const property_list & = {}) {
if (kind == sycl::usm::alloc::device || kind == sycl::usm::alloc::shared)
throw sycl::exception(sycl::make_error_code(sycl::errc::invalid),
"Device and shared allocation kinds are disallowed "
"without specifying a device!");
if (kind == sycl::usm::alloc::unknown)
throw sycl::exception(sycl::make_error_code(sycl::errc::invalid),
"Unknown allocation kinds are disallowed!");

throw sycl::exception(
sycl::make_error_code(sycl::errc::feature_not_supported),
"Host allocated pools are unsupported!");
}

template <typename Properties = empty_properties_t,
typename = std::enable_if_t<
detail::all_are_properties_of_v<memory_pool, Properties>>>
memory_pool(const sycl::context &ctx, const sycl::device &dev,
sycl::usm::alloc kind, const property_list &props = {});
sycl::usm::alloc kind, Properties props = {})
: memory_pool(ctx, dev, kind, stripProps(props)) {}

template <typename Properties = empty_properties_t,
typename = std::enable_if_t<
detail::all_are_properties_of_v<memory_pool, Properties>>>
memory_pool(const sycl::queue &q, sycl::usm::alloc kind,
const property_list &props = {})
Properties props = {})
: memory_pool(q.get_context(), q.get_device(), kind, props) {}

// NOT SUPPORTED: Creating a pool from an existing allocation is unsupported.
memory_pool(const sycl::context &, void *, size_t,
const property_list & = {}) {
throw sycl::exception(
sycl::make_error_code(sycl::errc::feature_not_supported),
"Creating a pool from an existing allocation is unsupported!");
}

~memory_pool() = default;

// Copy constructible/assignable, move constructible/assignable.
Expand All @@ -79,20 +61,21 @@ class __SYCL_EXPORT memory_pool {

void increase_threshold_to(size_t newThreshold);

// Property getters.
template <typename PropertyT> bool has_property() const noexcept {
return getPropList().template has_property<PropertyT>();
}
template <typename PropertyT> PropertyT get_property() const {
return getPropList().template get_property<PropertyT>();
}

protected:
struct pool_properties {
size_t initial_threshold;
size_t maximum_size;
bool zero_init;
};

std::shared_ptr<detail::memory_pool_impl> impl;

memory_pool(std::shared_ptr<detail::memory_pool_impl> Impl)
: impl(std::move(Impl)) {}

memory_pool(const sycl::context &ctx, const sycl::device &dev,
sycl::usm::alloc kind, pool_properties props);

template <class Obj>
friend const decltype(Obj::impl) &
sycl::detail::getSyclObjImpl(const Obj &SyclObject);
Expand All @@ -104,7 +87,23 @@ class __SYCL_EXPORT memory_pool {
friend T sycl::detail::createSyclObjFromImpl(
std::add_lvalue_reference_t<const decltype(T::impl)> ImplObj);

const property_list &getPropList() const;
template <typename Properties> pool_properties stripProps(Properties props) {
pool_properties poolProps{};
if constexpr (decltype(props)::template has_property<initial_threshold>()) {
poolProps.initial_threshold =
props.template get_property<initial_threshold>().value;
}

if constexpr (decltype(props)::template has_property<maximum_size>()) {
poolProps.maximum_size =
props.template get_property<maximum_size>().value;
}

if constexpr (decltype(props)::template has_property<zero_init>()) {
poolProps.zero_init = true;
}
return poolProps;
}
};

} // namespace ext::oneapi::experimental
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
//===----------------------------------------------------------------------===//

#pragma once
#include <cstddef>
#include <sycl/properties/property_traits.hpp>
#include <sycl/ext/oneapi/properties/property.hpp>

namespace sycl {
inline namespace _V1 {
Expand All @@ -17,64 +16,64 @@ namespace ext::oneapi::experimental {
// Forward declare memory_pool.
class memory_pool;

namespace property::memory_pool {

// Property that determines the initial threshold of a memory pool.
struct initial_threshold : public sycl::detail::PropertyWithData<
sycl::detail::MemPoolInitialThreshold> {
initial_threshold(size_t initialThreshold)
: initialThreshold(initialThreshold) {};
size_t get_initial_threshold() { return initialThreshold; }

private:
size_t initialThreshold;
struct initial_threshold
: detail::run_time_property_key<initial_threshold,
detail::PropKind::InitialThreshold> {
initial_threshold(size_t initialThreshold) : value(initialThreshold) {}
size_t value;
};

using initial_threshold_key = initial_threshold;
inline bool operator==(const initial_threshold &lhs,
const initial_threshold &rhs) {
return lhs.value == rhs.value;
}
inline bool operator!=(const initial_threshold &lhs,
const initial_threshold &rhs) {
return !(lhs == rhs);
}

// Property that determines the maximum size of a memory pool.
struct maximum_size
: public sycl::detail::PropertyWithData<sycl::detail::MemPoolMaximumSize> {
maximum_size(size_t maxSize) : maxSize(maxSize) {};
size_t get_maximum_size() { return maxSize; }

private:
size_t maxSize;
: detail::run_time_property_key<maximum_size,
detail::PropKind::MaximumSize> {
maximum_size(size_t maxSize) : value(maxSize) {}
size_t value;
};

// Property that provides a performance hint that all allocations from this pool
// will only be read from within SYCL kernel functions.
struct read_only
: public sycl::detail::DataLessProperty<sycl::detail::MemPoolReadOnly> {
read_only() = default;
};
using maximum_size_key = maximum_size;
inline bool operator==(const maximum_size &lhs, const maximum_size &rhs) {
return lhs.value == rhs.value;
}
inline bool operator!=(const maximum_size &lhs, const maximum_size &rhs) {
return !(lhs == rhs);
}

// Property that initial allocations to a pool (not subsequent allocations
// from prior frees) are iniitialised to zero.
// Property that initial allocations to a pool (not subsequent allocations from
// prior frees) are iniitialised to zero.
// enum class zero_init_enum { none, zero_init };
struct zero_init
: public sycl::detail::DataLessProperty<sycl::detail::MemPoolZeroInit> {
zero_init() = default;
: detail::run_time_property_key<zero_init, detail::PropKind::ZeroInit> {
zero_init() {};
};
} // namespace property::memory_pool
} // namespace ext::oneapi::experimental

template <>
struct is_property<
sycl::ext::oneapi::experimental::property::memory_pool::initial_threshold>
: std::true_type {};
using zero_init_key = zero_init;
inline bool operator==(const zero_init &, const zero_init &) { return true; }
inline bool operator!=(const zero_init &lhs, const zero_init &rhs) {
return !(lhs == rhs);
}

template <>
struct is_property<
sycl::ext::oneapi::experimental::property::memory_pool::maximum_size>
: std::true_type {};
struct is_property_key_of<initial_threshold_key, memory_pool> : std::true_type {
};

template <>
struct is_property<
sycl::ext::oneapi::experimental::property::memory_pool::read_only>
: std::true_type {};
struct is_property_key_of<maximum_size_key, memory_pool> : std::true_type {};

template <>
struct is_property<
sycl::ext::oneapi::experimental::property::memory_pool::zero_init>
: std::true_type {};
struct is_property_key_of<zero_init_key, memory_pool> : std::true_type {};

} // namespace ext::oneapi::experimental
} // namespace _V1
} // namespace sycl
5 changes: 4 additions & 1 deletion sycl/include/sycl/ext/oneapi/properties/property.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,8 +225,11 @@ enum PropKind : uint32_t {
Unaliased = 80,
EventMode = 81,
NativeLocalBlockIO = 82,
InitialThreshold = 83,
MaximumSize = 84,
ZeroInit = 85,
// PropKindSize must always be the last value.
PropKindSize = 83,
PropKindSize = 86,
};

template <typename PropertyT> struct PropertyToKind {
Expand Down
19 changes: 0 additions & 19 deletions sycl/source/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,6 @@ const property_list &context::getPropList() const {
sycl::ext::oneapi::experimental::memory_pool
context::ext_oneapi_get_default_memory_pool(const device &dev,
sycl::usm::alloc kind) const {
if (kind == sycl::usm::alloc::host)
throw sycl::exception(
sycl::make_error_code(sycl::errc::invalid),
"Default host memory pool requested but device supplied!");
if (kind == sycl::usm::alloc::unknown)
throw sycl::exception(sycl::make_error_code(sycl::errc::invalid),
"Unknown allocation kinds are disallowed!");
Expand All @@ -153,20 +149,5 @@ context::ext_oneapi_get_default_memory_pool(const device &dev,
impl->get_default_memory_pool(*this, dev, kind));
}

sycl::ext::oneapi::experimental::memory_pool
context::ext_oneapi_get_default_memory_pool(sycl::usm::alloc kind) const {
if (kind == sycl::usm::alloc::device || kind == sycl::usm::alloc::shared)
throw sycl::exception(sycl::make_error_code(sycl::errc::invalid),
"Device and shared allocation kinds are disallowed "
"without specifying a device!");
if (kind == sycl::usm::alloc::unknown)
throw sycl::exception(sycl::make_error_code(sycl::errc::invalid),
"Unknown allocation kinds are disallowed!");

throw sycl::exception(
sycl::make_error_code(sycl::errc::feature_not_supported),
"Host allocated pools are unsupported!");
}

} // namespace _V1
} // namespace sycl
4 changes: 3 additions & 1 deletion sycl/source/detail/context_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
#include <detail/context_impl.hpp>
#include <detail/context_info.hpp>
#include <detail/event_info.hpp>
#include <detail/memory_pool_impl.hpp>
#include <detail/platform_impl.hpp>
#include <detail/queue_impl.hpp>
#include <sycl/detail/common.hpp>
#include <sycl/detail/ur.hpp>
#include <sycl/device.hpp>
#include <sycl/exception.hpp>
#include <sycl/exception_list.hpp>
#include <sycl/ext/oneapi/experimental/async_alloc/memory_pool.hpp>
#include <sycl/info/info_desc.hpp>
#include <sycl/platform.hpp>
#include <sycl/property_list.hpp>
Expand Down Expand Up @@ -590,7 +592,7 @@ context_impl::get_default_memory_pool(const context &Context,
auto MemPoolImplPtr = std::make_shared<
sycl::ext::oneapi::experimental::detail::memory_pool_impl>(
Context, Device, sycl::usm::alloc::device, PoolHandle,
true /*Default pool*/, property_list{});
true /*Default pool*/);

// Hold onto a weak_ptr of the memory_pool_impl. Prevents circular
// dependencies between the context_impl and memory_pool_impl.
Expand Down
7 changes: 2 additions & 5 deletions sycl/source/detail/graph_memory_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,10 @@ graph_mem_pool::malloc(size_t Size, usm::alloc AllocType,
AllocInfo.Kind = AllocType;
// Collect relevant properties from memory pool
if (MemPool) {
const auto &PropList = MemPool->getPropList();
if (PropList.has_property<property::memory_pool::zero_init>()) {
auto Props = MemPool->getProps();
if (Props.zero_init) {
AllocInfo.ZeroInit = true;
}
if (PropList.has_property<property::memory_pool::read_only>()) {
AllocInfo.ReadOnly = true;
}
}

switch (AllocType) {
Expand Down
21 changes: 6 additions & 15 deletions sycl/source/detail/memory_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ __SYCL_EXPORT size_t memory_pool::get_threshold() const {
return impl->get_threshold();
}

const property_list &memory_pool::getPropList() const {
return impl->getPropList();
}

__SYCL_EXPORT size_t memory_pool::get_reserved_size_current() const {
return impl->get_reserved_size_current();
}
Expand All @@ -45,22 +41,17 @@ __SYCL_EXPORT void memory_pool::increase_threshold_to(size_t newThreshold) {
impl->set_new_threshold(newThreshold);
}

__SYCL_EXPORT memory_pool::memory_pool(const sycl::context &ctx,
const sycl::device &dev,
sycl::usm::alloc kind,
const property_list &props) {

if (kind == sycl::usm::alloc::host)
throw sycl::exception(
sycl::make_error_code(sycl::errc::invalid),
"Host allocated memory pools selected but device supplied!");

memory_pool::memory_pool(const sycl::context &ctx, const sycl::device &dev,
sycl::usm::alloc kind,
memory_pool::pool_properties props) {
if (kind != sycl::usm::alloc::device)
throw sycl::exception(
sycl::make_error_code(sycl::errc::feature_not_supported),
"Only device allocated memory pools are supported!");

impl = std::make_shared<detail::memory_pool_impl>(ctx, dev, kind, props);
detail::pool_properties poolProps{props.initial_threshold, props.maximum_size,
props.zero_init};
impl = std::make_shared<detail::memory_pool_impl>(ctx, dev, kind, poolProps);
}

} // namespace ext::oneapi::experimental
Expand Down
Loading