cccl icon indicating copy to clipboard operation
cccl copied to clipboard

[FEA]: provide a type erased owning resource wrapper

Open miscco opened this issue 1 year ago • 16 comments

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

  • destroy we need to redirect to the correct destructor during destruction of any_resource
  • to_resource_ref we need to have a static method that creates a {async_}resource_ref with the right member functions. We can use this through operator-> or operator*

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

miscco avatar Feb 22 '24 13:02 miscco

@harrism Would love to get your input here

miscco avatar Feb 22 '24 13:02 miscco

Can you provide a sketch of what using any_resource would look like?

jrhemstad avatar Feb 22 '24 13:02 jrhemstad

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;
  ....
};

miscco avatar Feb 22 '24 14:02 miscco

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

miscco avatar Feb 22 '24 14:02 miscco

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.

jrhemstad avatar Feb 22 '24 15:02 jrhemstad

Yeah this is explicitly about owning a resource

miscco avatar Feb 22 '24 17:02 miscco

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?

jrhemstad avatar Feb 22 '24 17:02 jrhemstad

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?

harrism avatar Feb 26 '24 20:02 harrism

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...

harrism avatar Feb 26 '24 20:02 harrism

The convention is that std::any is a type erased thing and resource is what we want, so combining them would yield any_resource

miscco avatar Feb 26 '24 20:02 miscco

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

miscco avatar Feb 26 '24 20:02 miscco

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?

harrism avatar Feb 26 '24 20:02 harrism

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.

jrhemstad avatar Feb 27 '24 00:02 jrhemstad

Yep, I think that's what Michael said already. :) Just asking for it to be all documented in the issue description.

harrism avatar Feb 27 '24 01:02 harrism

We will need this implemented in order to move forward with removing RMM's MR base classes.

harrism avatar Apr 23 '24 21:04 harrism

Couple more questions.

  1. I'd like to see the answers to these questions from @jrhemstad above:

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?

  1. I recall that any_resource_ref was the original planned name for what is now resource_ref. Why was any dropped from that?

  2. The naming is a bit confusing:

  • resource_ref: non-owning type-erased wrapper with specified template properties
  • any_resource_with: owning type-erased wrapper with specified template properties
  • resource_with: a concept with specified template properties

So:

  • ref == non-owning, type-erased
  • with == specified template properties

To me, it seems like for consistency resource_ref should be resource_ref_with, or any_resource should not have _with.

harrism avatar May 07 '24 06:05 harrism