ComputationalRadiationPhysics / liFFT

library for Library-independent FFTs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Integration of transform-agnostic memory objects (cl_mem, clfft)

tdd11235813 opened this issue · comments

Hi,
just need to write down some ongoing developments.
For the testOpenCL.cpp from PR #22 I tried to test liFFT together with cl_mem.
cl_mem encapsulates OpenCL data and does not offer an accessor and type interface.
As far as I know, the existing liFFT interfaces cannot deal with transform-agnostic memory objects.
cl_mem is not an array like type and not an integral type, so liFFT requires meta-data wrapped around cl_mem.

Test scheme, which I want to use:

cl_mem dat1 = clCreateBuffer(...);
cl_mem dat2 = clCreateBuffer(...);
using FFT = LiFFT::FFT_2D_C2C<TestPrecision>;
auto inWrapped  = FFT::wrapInput(  LiFFT::mem::wrapLibPtr<FFT::isComplexInput> 
                                   (dat1, TestExtents(testSize, testSize)) );  
auto outWrapped = FFT::wrapOutput( LiFFT::mem::wrapLibPtr<FFT::isComplexOutput>
                                   (dat2, TestExtents(testSize, testSize)) );  
auto fft = LiFFT::makeFFT<TestLibrary>(inWrapped, outWrapped);
fft(inWrapped, outWrapped);
LiFFT::policies::copy(inWrapped, baseR2CInput);

wrapLibPtr should wrap the cl_mem (_cl_mem*) in order to return a DataContainer like PlainPtrWrapper. Latter one cannot be used due to validating against Real and Complex types.

// Generally, in the liFFT backend non-integral types are required to be wrapped containing FFT properties. FFT_Definition type also contains all the FFT properties. It is used to validate those data objects given to liFFT. Giving raw pointer to liFFT would work for floats or doubles, however for complex numbers a raw float array would fail to compile.

Anyway, cl_mem needs a wrapper class. I would call it LibPtr for now.
I would mimic the Real or Complex type containing proper meta data, but they only would return the pointer itself.
I would mark it as device pointer, where CPU also is a device, namely an OpenCL device.
Since, PlainPtrWrapper is too specific about transform types, it would require an own DataContainer type, but I dont know if this would work in the end.

Am I on the right path or do you see better way of integration for this use case?

Giving raw pointer to liFFT would work for floats or doubles, however for complex numbers a raw float array would fail to compile. Right. This needs to be a complex type so e.g. reinterpret_cast<Complex<float>>

cl_mem is a very difficult special case. It might turn out to be a problem as e.g. liFFT does some shape validation. wrapLibPtr might be a good idea. It might be a good idea to use this for device pointers in general and disallow direct access which removes some of the cool features. Then copy can be specialized by the backends for a specific type of LibPtr for the common operations: Device<->Device, Host<->Device.
Hm,... I see the whole design break in the context of device pointers/handles. This might require quite some effort to get this done appropriately.

ok, so it would not be only the code of a new DataContainer for LibPtr, but also other parts of liFFT, which would be affected?
Direct access of a LibPtr based DataContainer would throw a compiler-error. If I use liFFT for a device-centric FFT pipeline, then several features probably are not needed anyway. Probably removing a DataContainer layer makes sense, since cl_mem already is a data container.
Have to look deeper next time, but maybe a second path of FFT factory method is possible...