Search code examples
c#cudamanaged-cuda

ManagedCUDA: Pass struct parameter to kernel


Today, I'm trying to launch my CUDA C/C++ program from a C# application.

So, I did some research on the web, but I didn't found that much information. I only saw the "GitHub" but, no...

So I've got a Kernel defined like follow : (that's an example)

__global__ void kernel(Cartesian a, Cartesian b, Cartesian *c)

With "Cartesian" :

class Cartesian
{
public:
    double x;
    double y;
    double z;
};

With what I understand from managedCUDA. It's like replacing the main function of a CUDA C/C++ program. Using a lib that "do the work for us"

So i followed an example from this page :

https://algoslaves.wordpress.com/2013/08/25/nvidia-cuda-hello-world-in-managed-c-and-f-with-use-of-managedcuda/

And write my C# program like this :

The part that create the context : (dont really get this "notion")

    static void InitKernels()
    {
        CudaContext cntxt = new CudaContext();
        CUmodule cumodule = cntxt.LoadModule(@"C:\Users\stage\Documents\Visual Studio 2013\Projects\Cs_link_test\Cs_link_test\x64\Release\kernel.ptx");
        addWithCuda = new CudaKernel("kernel", cumodule, cntxt);
    }

The part that launch (I guess) the function and get back the modification made by the kernel :

    static Func<Cartesian, Cartesian, Cartesian> cudaAdd = (a, b) =>
    {
        CudaDeviceVariable<Cartesian> result_dev;
        Cartesian result_host;
        addWithCuda.Run(a, b, result_dev.DevicePointer);
        result_dev.CopyToHost(ref result_host);
        return result_host;
    };

And from this part I don't understand anything from the line :

static Func<Cartesian, Cartesian, Cartesian> cudaAdd = (a, b) =>

I'm not familiar with C# (just saying)

So my problem come from the error caused by result_dev and result_host;

The error says :

Use of unassigned local variable 'result_*'

So, is it because they arren't initialized ?

If so, why result_host cause an error ? It must get the data from result_dev which must be modified by the kernel..

If not, how to fix this ?

And I also wanted to know, is it possible to passe Class parameter through a kernel function ? If so, how to set a CudaDeviceVariable, cause it says that the type must be non-nullable. It's why I change class with struct.


Solution

  • Ok so.. I just figured out how to solve my problem. Read the "discussion" section on https://managedcuda.codeplex.com/discussions/659183 help me to do it. So how to proceed to pass struct parameter to a kernel using managedCUDA ?

    First thing I did wrong (I guess) is to use the Func<T, T, T>part. You must declare your class in your .cu file like follow :

    class Cartesian
    {
    public:
      double x;
      double y;
      double z;
    }
    

    And the same in your .cs file like follow :

    [StructLayout(LayoutKind.Sequential)]
    struct Cartesian
    {
       public double x;
       public double y;
       public double z;
       public Cartesian(double x, double y, double z) { this.x = x; this.y = y; this.z = z; }
    };
    

    Then you can initialize your kernel as you want, I do it like this :

        static void InitKernels()
        {
            CudaContext ctx = new CudaContext();
            CUmodule cumodule = ctx.LoadModule(@"C:\Users\stage\Documents\Visual Studio 2013\Projects\Cs_link_test\Cs_link_test\x64\Release\kernel.ptx");
            kernel = new CudaKernel("kernelPosGeo", cumodule, ctx);
            kernel.BlockDimensions = 1024;
            kernel.GridDimensions = 614;
        }
    

    And what you need to do is simply call your kernel with the parameters you want.

    Cartesian a = new Cartesian(1, 2, 3);
    kernel.Run(a);
    

    I guess I had a problem because I used Func<T, T,T> but till I don't use it anymore, it seems easier. And the declaration of Func had at maximum 2 parameter in and 1 out. So I've got a Kernel that have 4 or 5 parameters and I was limited here... But right now, do not have any problem.