Skip to content

Commit a47376d

Browse files
committed
Add dynamic_accessibility_property to all memory resources
1 parent 788fe7c commit a47376d

8 files changed

Lines changed: 207 additions & 25 deletions

File tree

libcudacxx/include/cuda/__memory_resource/any_resource.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ template <class _Property>
8888
using __iproperty = typename __with_property<_Property>::template __iproperty<>;
8989

9090
template <class... _Properties>
91-
using __iproperty_set = ::cuda::__iset<__iproperty<_Properties>...>;
91+
using __iproperty_set =
92+
::cuda::__iset<__iproperty<_Properties>..., __iproperty<::cuda::mr::dynamic_accessibility_property>>;
9293

9394
// Wrap the calls of the allocate and deallocate member functions
9495
// because of NVBUG#4967486
@@ -359,6 +360,15 @@ struct _CCCL_DECLSPEC_EMPTY_BASES resource_ref
359360
}
360361
};
361362

363+
template <class... _Properties>
364+
inline constexpr bool __disable_default_dynamic_accessibility_property<any_resource<_Properties...>> = true;
365+
template <class... _Properties>
366+
inline constexpr bool __disable_default_dynamic_accessibility_property<resource_ref<_Properties...>> = true;
367+
template <class... _Properties>
368+
inline constexpr bool __disable_default_dynamic_accessibility_property<any_synchronous_resource<_Properties...>> = true;
369+
template <class... _Properties>
370+
inline constexpr bool __disable_default_dynamic_accessibility_property<synchronous_resource_ref<_Properties...>> = true;
371+
362372
_CCCL_TEMPLATE(class... _Properties, class _Resource)
363373
_CCCL_REQUIRES(mr::synchronous_resource_with<_Resource, _Properties...>)
364374
synchronous_resource_ref<_Properties...> __as_resource_ref(_Resource& __mr) noexcept

libcudacxx/include/cuda/__memory_resource/get_property.h

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#if _CCCL_HAS_CTK()
2525

26+
# include <cuda/__memory_resource/properties.h>
2627
# include <cuda/std/__concepts/same_as.h>
2728
# include <cuda/std/__type_traits/remove_const_ref.h>
2829
# include <cuda/std/__type_traits/void_t.h>
@@ -107,9 +108,19 @@ _CCCL_CONCEPT_FRAGMENT(
107108
__has_upstream_resource_,
108109
requires(const _Resource& __res)(
109110
requires(::cuda::std::same_as<::cuda::std::__remove_const_ref_t<decltype(__res.upstream_resource())>, _Upstream>)));
111+
112+
template <class _Resource, class _Upstream>
113+
_CCCL_CONCEPT_FRAGMENT(__has_get_resource_,
114+
requires(const _Resource& __res)(requires(
115+
::cuda::std::same_as<::cuda::std::__remove_const_ref_t<decltype(__res.get())>, _Upstream>)));
116+
template <class _Resource, class _Upstream>
117+
_CCCL_CONCEPT __has_get_resource = _CCCL_FRAGMENT(__has_get_resource_, _Resource, _Upstream);
118+
110119
# endif // ^^^ _CCCL_DOXYGEN_INVOKED ^^^
111120
template <class _Resource, class _Upstream>
112-
_CCCL_CONCEPT __has_upstream_resource = _CCCL_FRAGMENT(__has_upstream_resource_, _Resource, _Upstream);
121+
_CCCL_CONCEPT __has_forwarded_resource =
122+
_CCCL_FRAGMENT(__has_upstream_resource_, _Resource, _Upstream)
123+
|| _CCCL_FRAGMENT(__has_get_resource_, _Resource, _Upstream);
113124

114125
_CCCL_BEGIN_NAMESPACE_CPO(__forward_property)
115126
template <class _Derived, class _Upstream>
@@ -120,14 +131,35 @@ struct __fn
120131
_CCCL_REQUIRES((!property_with_value<_Property>) _CCCL_AND has_property<_Upstream, _Property>)
121132
_CCCL_API friend constexpr void get_property(const _Derived&, _Property) noexcept {}
122133

134+
_CCCL_EXEC_CHECK_DISABLE
135+
_CCCL_API friend constexpr auto
136+
get_property(const _Derived& __res, ::cuda::mr::dynamic_accessibility_property __prop) noexcept
137+
{
138+
if constexpr (_CCCL_FRAGMENT(__has_upstream_resource_, _Derived, _Upstream))
139+
{
140+
return get_property(__res.upstream_resource(), __prop);
141+
}
142+
else
143+
{
144+
return get_property(__res.get(), __prop);
145+
}
146+
}
147+
123148
// The indirection is needed, otherwise the compiler might believe that _Derived is an incomplete type
124149
_CCCL_EXEC_CHECK_DISABLE
125150
_CCCL_TEMPLATE(class _Property, class _Derived2 = _Derived)
126151
_CCCL_REQUIRES(property_with_value<_Property> _CCCL_AND has_property<_Upstream, _Property> _CCCL_AND
127-
__has_upstream_resource<_Derived2, _Upstream>)
152+
__has_forwarded_resource<_Derived2, _Upstream>)
128153
_CCCL_API friend constexpr __property_value_t<_Property> get_property(const _Derived& __res, _Property __prop)
129154
{
130-
return get_property(__res.upstream_resource(), __prop);
155+
if constexpr (_CCCL_FRAGMENT(__has_upstream_resource_, _Derived, _Upstream))
156+
{
157+
return get_property(__res.upstream_resource(), __prop);
158+
}
159+
else
160+
{
161+
return get_property(__res.get(), __prop);
162+
}
131163
}
132164
};
133165
_CCCL_END_NAMESPACE_CPO
@@ -145,15 +177,36 @@ _CCCL_END_NAMESPACE_CPO
145177
//!
146178
//! .. note::
147179
//!
148-
//! In order to forward stateful properties, a type needs do implement an `upstream_resource()` method that returns
149-
//! an instance of the upstream.
180+
//! In order to forward stateful properties, a type needs to implement either:
181+
//! - an `upstream_resource()` method returning the upstream resource, or
182+
//! - a `get()` method returning the upstream resource.
150183
//!
151184
//! @endrst
152185
template <class _Derived, class _Upstream>
153186
using forward_property = __forward_property::__fn<_Derived, _Upstream>;
154187

155188
_CCCL_END_NAMESPACE_CUDA
156189

190+
_CCCL_BEGIN_NAMESPACE_CUDA_MR
191+
192+
template <class _Tp>
193+
inline constexpr bool __disable_default_dynamic_accessibility_property = false;
194+
195+
//! Default implementation: infer from has_property<Resource, host_accessible> and
196+
//! has_property<Resource, device_accessible>. Resources can override by providing
197+
//! their own get_property(..., dynamic_accessibility_property).
198+
//! Excluded for type-erased wrappers (any_resource, resource_ref, etc.) so that
199+
//! get_property dispatches via their interface to the stored concrete resource.
200+
_CCCL_TEMPLATE(class _Resource)
201+
_CCCL_REQUIRES((!__disable_default_dynamic_accessibility_property<_Resource>) )
202+
_CCCL_API constexpr __memory_accessability
203+
get_property([[maybe_unused]] const _Resource& __res, dynamic_accessibility_property) noexcept
204+
{
205+
return __memory_accessability_from_static_properties<::cuda::has_property<_Resource, host_accessible>,
206+
::cuda::has_property<_Resource, device_accessible>>();
207+
}
208+
_CCCL_END_NAMESPACE_CUDA_MR
209+
157210
# include <cuda/std/__cccl/epilogue.h>
158211

159212
#endif // _CCCL_HAS_CTK()

libcudacxx/include/cuda/__memory_resource/properties.h

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,19 +110,35 @@ struct __copy_default_queries<_Resource, false>
110110

111111
enum class __memory_accessability
112112
{
113+
__unknown,
113114
__host,
114115
__device,
115116
__host_device,
116117
};
117118

119+
//! @brief The dynamic_accessibility_property reports the resource's memory accessibility at runtime.
120+
//! Compared to the static properties, it can be used to query the memory accessibility of a resource that is not known
121+
//! at compile time.
122+
struct dynamic_accessibility_property
123+
{
124+
using value_type = __memory_accessability;
125+
};
126+
127+
template <bool _HostAccessible, bool _DeviceAccessible>
128+
_CCCL_API constexpr __memory_accessability __memory_accessability_from_static_properties() noexcept
129+
{
130+
return _HostAccessible && _DeviceAccessible ? __memory_accessability::__host_device
131+
: _DeviceAccessible ? __memory_accessability::__device
132+
: _HostAccessible ? __memory_accessability::__host
133+
: __memory_accessability::__unknown;
134+
}
135+
118136
template <class... _Properties>
119137
struct __memory_accessability_from_properties
120138
{
121139
static constexpr __memory_accessability value =
122-
::cuda::mr::__is_host_device_accessible<_Properties...> ? __memory_accessability::__host_device
123-
: ::cuda::mr::__is_device_accessible<_Properties...>
124-
? __memory_accessability::__device
125-
: __memory_accessability::__host;
140+
__memory_accessability_from_static_properties<::cuda::mr::__is_host_accessible<_Properties...>,
141+
::cuda::mr::__is_device_accessible<_Properties...>>();
126142
};
127143

128144
_CCCL_END_NAMESPACE_CUDA_MR

libcudacxx/include/cuda/__memory_resource/shared_resource.h

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ _CCCL_BEGIN_NAMESPACE_CUDA_MR
5050
//! @tparam _Resource The resource type to hold.
5151
//! @endrst
5252
template <class _Resource>
53-
struct shared_resource : ::cuda::mr::__copy_default_queries<_Resource>
53+
struct shared_resource
54+
: ::cuda::mr::__copy_default_queries<_Resource>
55+
, ::cuda::forward_property<shared_resource<_Resource>, _Resource>
5456
{
5557
static_assert(::cuda::mr::synchronous_resource<_Resource>, "");
5658

@@ -255,19 +257,6 @@ struct shared_resource : ::cuda::mr::__copy_default_queries<_Resource>
255257
return !(__lhs == __rhs);
256258
}
257259

258-
//! @brief Forwards the stateless properties
259-
_CCCL_TEMPLATE(class _Property)
260-
_CCCL_REQUIRES((!property_with_value<_Property>) _CCCL_AND(has_property<_Resource, _Property>))
261-
friend void get_property(const shared_resource&, _Property) noexcept {}
262-
263-
//! @brief Forwards the stateful properties
264-
_CCCL_TEMPLATE(class _Property)
265-
_CCCL_REQUIRES(property_with_value<_Property> _CCCL_AND(has_property<_Resource, _Property>))
266-
[[nodiscard]] friend __property_value_t<_Property> get_property(const shared_resource& __self, _Property) noexcept
267-
{
268-
return get_property(__self.__control_block->__resource, _Property{});
269-
}
270-
271260
private:
272261
// Use a custom shared_ptr implementation because (a) we don't need to support weak_ptr so we only
273262
// need one pointer, not two, and (b) this implementation can work on device also.

libcudacxx/test/libcudacxx/cuda/memory_resource/any_resource/any_resource.cu

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,34 @@ struct host_device_resource
228228
static_assert(cuda::has_property<host_device_resource, cuda::mr::device_accessible>);
229229
static_assert(cuda::has_property<host_device_resource, cuda::mr::host_accessible>);
230230

231+
struct explicit_dynamic_resource
232+
{
233+
void* allocate(cuda::stream_ref, size_t, size_t)
234+
{
235+
return nullptr;
236+
}
237+
void deallocate(cuda::stream_ref, void*, size_t, size_t) noexcept {}
238+
void* allocate_sync(size_t, size_t)
239+
{
240+
return nullptr;
241+
}
242+
void deallocate_sync(void*, size_t, size_t) noexcept {}
243+
friend bool operator==(const explicit_dynamic_resource&, const explicit_dynamic_resource&) noexcept
244+
{
245+
return true;
246+
}
247+
friend bool operator!=(const explicit_dynamic_resource&, const explicit_dynamic_resource&) noexcept
248+
{
249+
return false;
250+
}
251+
friend constexpr void get_property(const explicit_dynamic_resource&, cuda::mr::host_accessible) noexcept {}
252+
friend constexpr cuda::mr::__memory_accessability
253+
get_property(const explicit_dynamic_resource&, cuda::mr::dynamic_accessibility_property) noexcept
254+
{
255+
return cuda::mr::__memory_accessability::__device;
256+
}
257+
};
258+
231259
void requires_host(cuda::mr::resource_ref<cuda::mr::host_accessible>) {}
232260
void requires_device(cuda::mr::resource_ref<cuda::mr::device_accessible>) {}
233261

@@ -265,6 +293,22 @@ TEST_CASE("resource_ref regression test for cccl#6839", "[container][resource]")
265293
CHECK(checks_device_runtime_resource_ref(ref)); // Test that we are device accessible
266294
}
267295

296+
TEST_CASE("dynamic_accessibility_property in type-erased wrappers", "[container][resource]")
297+
{
298+
cuda::mr::any_resource<cuda::mr::host_accessible> host_device_any{host_device_resource{}};
299+
CHECK(get_property(host_device_any, cuda::mr::dynamic_accessibility_property{})
300+
== cuda::mr::__memory_accessability::__host_device);
301+
302+
cuda::mr::any_resource<cuda::mr::host_accessible> explicit_any{explicit_dynamic_resource{}};
303+
CHECK(get_property(explicit_any, cuda::mr::dynamic_accessibility_property{})
304+
== cuda::mr::__memory_accessability::__device);
305+
306+
host_device_resource host_device_mr{};
307+
cuda::mr::resource_ref<cuda::mr::host_accessible> host_device_ref{host_device_mr};
308+
CHECK(get_property(host_device_ref, cuda::mr::dynamic_accessibility_property{})
309+
== cuda::mr::__memory_accessability::__host_device);
310+
}
311+
268312
TEMPLATE_TEST_CASE_METHOD(test_fixture, "Empty property set", "[container][resource]", big_resource, small_resource)
269313
{
270314
using TestResource = TestType;

libcudacxx/test/libcudacxx/cuda/memory_resource/properties/properties.pass.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,46 @@ static_assert(!cuda::mr::__is_host_device_accessible<cuda::mr::host_accessible>,
3636
static_assert(!cuda::mr::__is_host_device_accessible<cuda::mr::device_accessible>, "");
3737
static_assert(cuda::mr::__is_host_device_accessible<cuda::mr::host_accessible, cuda::mr::device_accessible>, "");
3838

39+
struct host_only_resource
40+
{
41+
friend constexpr void get_property(const host_only_resource&, cuda::mr::host_accessible) noexcept {}
42+
};
43+
44+
struct device_only_resource
45+
{
46+
friend constexpr void get_property(const device_only_resource&, cuda::mr::device_accessible) noexcept {}
47+
};
48+
49+
struct host_device_resource
50+
{
51+
friend constexpr void get_property(const host_device_resource&, cuda::mr::host_accessible) noexcept {}
52+
friend constexpr void get_property(const host_device_resource&, cuda::mr::device_accessible) noexcept {}
53+
};
54+
55+
struct explicit_dynamic_resource
56+
{
57+
friend constexpr void get_property(const explicit_dynamic_resource&, cuda::mr::host_accessible) noexcept {}
58+
friend constexpr cuda::mr::__memory_accessability
59+
get_property(const explicit_dynamic_resource&, cuda::mr::dynamic_accessibility_property) noexcept
60+
{
61+
return cuda::mr::__memory_accessability::__device;
62+
}
63+
};
64+
65+
static_assert(cuda::has_property<host_only_resource, cuda::mr::dynamic_accessibility_property>);
66+
static_assert(cuda::has_property<device_only_resource, cuda::mr::dynamic_accessibility_property>);
67+
static_assert(cuda::has_property<host_device_resource, cuda::mr::dynamic_accessibility_property>);
68+
static_assert(cuda::has_property<explicit_dynamic_resource, cuda::mr::dynamic_accessibility_property>);
69+
70+
static_assert(get_property(host_only_resource{}, cuda::mr::dynamic_accessibility_property{})
71+
== cuda::mr::__memory_accessability::__host);
72+
static_assert(get_property(device_only_resource{}, cuda::mr::dynamic_accessibility_property{})
73+
== cuda::mr::__memory_accessability::__device);
74+
static_assert(get_property(host_device_resource{}, cuda::mr::dynamic_accessibility_property{})
75+
== cuda::mr::__memory_accessability::__host_device);
76+
static_assert(get_property(explicit_dynamic_resource{}, cuda::mr::dynamic_accessibility_property{})
77+
== cuda::mr::__memory_accessability::__device);
78+
3979
int main(int, char**)
4080
{
4181
return 0;

libcudacxx/test/libcudacxx/cuda/memory_resource/shared_resource.cu

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,12 @@ TEMPLATE_TEST_CASE_METHOD(test_fixture, "shared_resource", "[container][resource
163163
CHECK(this->counts == expected);
164164
}
165165

166+
SECTION("dynamic_accessibility_property forwards through shared_resource")
167+
{
168+
cuda::mr::shared_resource mr{cuda::std::in_place_type<TestResource>, 42, this};
169+
CHECK(get_property(mr, cuda::mr::dynamic_accessibility_property{}) == cuda::mr::__memory_accessability::__host);
170+
}
171+
166172
// Reset the counters:
167173
this->counts = Counts();
168174

libcudacxx/test/libcudacxx/cuda/memory_resource/synchronous_adapter.cu

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,23 @@ constexpr bool passed_property =
2828
template <class Resource>
2929
constexpr bool same_properties =
3030
passed_property<Resource, cuda::mr::device_accessible> && passed_property<Resource, cuda::mr::host_accessible>
31-
&& passed_property<Resource, extra_property> && passed_property<Resource, get_data>;
31+
&& passed_property<Resource, extra_property> && passed_property<Resource, get_data>
32+
&& passed_property<Resource, cuda::mr::dynamic_accessibility_property>;
33+
34+
struct explicit_dynamic_resource
35+
{
36+
void* allocate_sync(size_t, size_t)
37+
{
38+
return nullptr;
39+
}
40+
void deallocate_sync(void*, size_t, size_t) noexcept {}
41+
friend constexpr void get_property(const explicit_dynamic_resource&, cuda::mr::host_accessible) noexcept {}
42+
friend constexpr cuda::mr::__memory_accessability
43+
get_property(const explicit_dynamic_resource&, cuda::mr::dynamic_accessibility_property) noexcept
44+
{
45+
return cuda::mr::__memory_accessability::__device;
46+
}
47+
};
3248

3349
C2H_CCCLRT_TEST("synchronous_resource_adapter", "[memory_resource]")
3450
{
@@ -70,4 +86,12 @@ C2H_CCCLRT_TEST("synchronous_resource_adapter", "[memory_resource]")
7086
STATIC_CHECK(same_default_queries<cuda::mr::legacy_pinned_memory_resource>);
7187
STATIC_CHECK(same_default_queries<small_resource>);
7288
}
89+
90+
SECTION("explicit dynamic_accessibility_property overrides template")
91+
{
92+
cuda::mr::synchronous_resource_adapter<explicit_dynamic_resource> adapter{explicit_dynamic_resource{}};
93+
STATIC_CHECK(cuda::has_property<decltype(adapter), cuda::mr::dynamic_accessibility_property>);
94+
CHECK(get_property(adapter, cuda::mr::dynamic_accessibility_property{})
95+
== cuda::mr::__memory_accessability::__device);
96+
}
7397
}

0 commit comments

Comments
 (0)