Oh, I see. Regarding use of the allocator you are correct that the allocate method will obtain a buffer from the pool. When you pass the pointer returned by allocate to the free method of the buffer, it would be freed.
In the GXF level there is a nvidia::gxf::MemoryBuffer class which provides an interface to more easily manage the lifetime of such a memory buffer (gxf/std/memory_buffer.hpp). That class is fully defined in that memory_buffer.hpp header, so you can see full details there. You would declare a MemoryBuffer object, then use the resize method that takes an allocator as an argument to allocate memory of the requested size. The destructor of the MemoryBuffer class would take care of freeing that allocated buffer. That MemoryBuffer class is what is used internally in the implementation of nvidia::gxf::Tensor to handle the lifetime of the memory.
I have allocator_ declared as Parameter<std::shared_ptr>allocator_. In the compute routine of the operator I have allocator_.allocate(some_size,MemoryStorageType::kHost), but the compiler is not able to resolve allocate.
I think the compiler issue you are seeing is likely that allocator_ is of type Parameter so you need to call the method on the contained Allocator and not the Parameter class itself. I think that can be done by either allocator_->allocate(some_size,MemoryStorageType::kHost) or allocator_.get().allocate(some_size,MemoryStorageType::kHost).
However the above is likely still not what you want depending on the use case. Note that the holoscan::Allocator classes like holoscan::BlockMemoryPool provide a wrapper representing an underlying GXF component. If you intend to use the allocator with any of the underlying GXF APIs like the Tensor-related ones described in the previous message or the MemoryBuffer described above then you will want to retrieve the actual underlying GXF component (i.e. an nvidia::gxf::Allocator). To do that you can reference how it is done in the provided FormatConverterOp, for example. In the linked code pool_ is declared as Parameter<Allocator> pool_ in the header so it should be the same as your case;
The GXF code in the lines below takes the GXF context and the component ID and returns a GXF Handle to the allocator. The GXF Handle class as kind of like a std::shared_ptr, so you would use pool->allocate(...), etc. to call methods on the GXF component.
// get Handle to underlying nvidia::gxf::Allocator from std::shared_ptr<holoscan::Allocator>
auto pool =
nvidia::gxf::Handle<nvidia::gxf::Allocator>::Create(context.context(), pool_->gxf_cid());
that start method of that same operator also creates a MemoryBuffer (the class I had described above)
// line 191
device_scratch_buffer_ = std::make_unique<nvidia::gxf::MemoryBuffer>();
(the header defines a few memory buffers, such as device_scratch_buffer_ used by that operator)
The compute method uses the resize method on that buffer to allocate memory from the “pool” allocator
// lines 351-359
size_t buffer_size = static_cast<size_t>(rows) * columns * in_channels * element_size;
if (buffer_size > device_scratch_buffer_->size()) {
device_scratch_buffer_->resize(
pool.value(), buffer_size, nvidia::gxf::MemoryStorageType::kDevice);
if (!device_scratch_buffer_->pointer()) {
throw std::runtime_error(
fmt::format("Failed to allocate device scratch buffer ({} bytes)", buffer_size));
}
}
Note that for the FormatConverterOp, since it is managing its own buffers created during start the stop method needs to free these.