Nico Wadel Nico Wadel - 28 days ago 17
C# Question

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.

Answer

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.