[FEA]: provide a type erased owning resource wrapper
Is this a duplicate?
- [X] I confirmed there appear to be no duplicate issues for this request and that I agree to the Code of Conduct
Area
libcu++
Is your feature request related to a problem? Please describe.
libcu++ currently provides the {async_}resource_ref wrapper that provides type erased access to an existing memory resource.
However, often we want to also store a type erased memory resource to then pass around through a {async_}resource_ref
Describe the solution you'd like
Following convention, I would propose to name it any_resource. Obvious use cases are testing frameworks which usually test APIs against a host of different resources and also certain resource adaptors that want to adopt a memory resource.
Finally this would also allow it to create something similar to rmm:{get,set}_current_device_resource.
Just throwing ideas around I believe it would be sufficient to only store few methods in an external vtable
destroywe need to redirect to the correct destructor during destruction ofany_resourceto_resource_refwe need to have a static method that creates a{async_}resource_refwith the right member functions. We can use this throughoperator->oroperator*
Describe alternatives you've considered
Just using a std::any does not work, because we need a good way to actually create a {async_}resource_ref from the stored type erased resource.
Additional context
No response
@harrism Would love to get your input here
Can you provide a sketch of what using any_resource would look like?
Regarding the mentioned two use cases
A way to store the memory resource used per device (shamelessly stolen from rmm)
using namespace cuda::mr;
inline auto& get_map()
{
static std::map<cuda_device_id::value_type, any_resource_with<device_accessible>> device_id_to_resource;
return device_id_to_resource;
}
async_resource_ref<device_accessible> get_per_device_resource(cuda_device_id device_id)
{
std::lock_guard<std::mutex> lock{detail::map_lock()};
auto& map = detail::get_map();
// If a resource was never set for `id`, set to the initial resource
auto const found = map.find(device_id.value());
return (found == map.end()) ? (map[device_id.value()] = detail::initial_resource())
: found->second;
}
A test framework for different memory resources again stolen from rmm
using MRFactoryFunc = std::function<std::shared_ptr<any_resource_with<device_accessible>>()>;
A container that actually stores a memory resource
class my_container {
private:
any_resource_with<...> mr_;
void* __ptr;
....
};
In general any RAII type memory functionality kind of wants to actually store the used memory resource and not rely on get_current_device_resource because that could have actually changed since it was constructed
In general any RAII type memory functionality kind of wants to actually store the used memory resource
Specifically, you mean storing an owning reference to the resource? Because otherwise, you could simply store a resource_ref.
Yeah this is explicitly about owning a resource
Would any_resource be a shared ownership model? Or exclusive ownership?
What would it look like to construct an any_resource from an instance of an arbitrary type R that satisfies the resource<R> concept?
Following convention, I would propose to name it any_resource.
I'm not familiar with this convention. Can you provide references?
Why don't C++ smart pointers (std::unique_pointer) work for this?
Final question: would it be better to try this out in RMM first to work out the kinks before canonizing it in CCCL? After all the use cases are in RMM...
The convention is that std::any is a type erased thing and resource is what we want, so combining them would yield any_resource
Regarding the question about unique_ptr, that should be doable, but what we also want is something that lives on the stack and not the heap
Regarding the question about unique_ptr, that should be doable, but what we also want is something that lives on the stack and not the heap
Can you add this point (and a reason why) to the issue description?
I'm not familiar with this convention. Can you provide references?
std::any is a standard polymorphic abstraction that can be "any" type. It's an owning object.
resource_ref is a reference to an object that is a resource.
any_resource is an instance of an object that is a resource.
Why don't C++ smart pointers (
std::unique_pointer) work for this?
unique_ptr is a pointer to an instance of a heap allocated object. any_resource would be an instance of the object.
Yep, I think that's what Michael said already. :) Just asking for it to be all documented in the issue description.
We will need this implemented in order to move forward with removing RMM's MR base classes.
Couple more questions.
- I'd like to see the answers to these questions from @jrhemstad above:
Would
any_resourcebe a shared ownership model? Or exclusive ownership?What would it look like to construct an
any_resourcefrom an instance of an arbitrary typeRthat satisfies theresource<R>concept?
-
I recall that
any_resource_refwas the original planned name for what is nowresource_ref. Why wasanydropped from that? -
The naming is a bit confusing:
resource_ref: non-owning type-erased wrapper with specified template propertiesany_resource_with: owning type-erased wrapper with specified template propertiesresource_with: a concept with specified template properties
So:
ref== non-owning, type-erasedwith== specified template properties
To me, it seems like for consistency resource_ref should be resource_ref_with, or any_resource should not have _with.