Runtime Parameters

Apr 4, 2014 at 11:07 AM
Hi,

I'm trying to create an array of variables that I can set at runtime, pass to a CudaKernal then get the return values. Is there an easy way to do this?

Thanks,
Darren
Apr 4, 2014 at 12:34 PM
Doh! I think I got it.
Apr 5, 2014 at 12:10 AM
Edited Apr 5, 2014 at 1:53 AM
Okay no... LOL

This is what I tried:
    public class Parameters
    {
        List<Type> types = null;
        List<string> names = null;
        List<bool> isArrays = null;
        List<object> values = null;
        List<bool> outputs = null;
        List<object> cdvs = null;

        public Parameters()
        {
            types = new List<Type>();
            names = new List<string>();
            isArrays = new List<bool>();
            values = new List<object>();
            outputs = new List<bool>();
            cdvs = new List<object>();
        }

        public object[] ToObjectArray()
        {
            object[] array = new object[names.Count];
            for (int i = 0; i < names.Count; i++)
            {
                Type type = types[i];
                if (type == typeof(int))
                    if (isArrays[i])
                        array[i] = ((CudaDeviceVariable<int>)cdvs[i]).DevicePointer;
                    else
                        array[i] = values[i];
                else if (type == typeof(float))
                    array[i] = ((CudaDeviceVariable<float>)cdvs[i]).DevicePointer;
            }

            return array;
        }

        public void Add(bool output, int value, string name, bool isArray)
        {
            outputs.Add(output);
            types.Add(typeof(int));
            names.Add(name);
            isArrays.Add(isArray);
            values.Add(value);
            cdvs.Add(null);
        }

        public void Add(bool output, float[] value, string name, bool isArray)
        {
            outputs.Add(output);
            types.Add(typeof(float));
            names.Add(name);
            isArrays.Add(isArray);
            values.Add(value);
            CudaDeviceVariable<float> cdv;
            if (output)
                cdv = new CudaDeviceVariable<float>(value.Length);
            cdv = value;
            cdvs.Add(cdv);
        }

        public object Value(string name)
        {
            object value = null;

            for (int i = 0; i < names.Count; i++)
            {
                if (names[i] == name)
                {
                    Type type = types[i];
                    if (type == typeof(int))
                        if (isArrays[i])
                            value = cdvs[i];
                    else if (type == typeof(float))
                        if (isArrays[i])
                            value = cdvs[i];
                }
            }

            return value;
        }
    }
This is what I get.

ManagedCuda.CudaException was unhandled by user code
HResult=-2146233088
Message=ErrorInvalidValue: This indicates that one or more of the parameters passed to the API call is not within an acceptable range of values.
Source=ManagedCuda
StackTrace:
   at ManagedCuda.CudaKernel.Run(Object[] parameters) in C:\Users\*****\Documents\Visual Studio 2010\HG-Projects\ManagedCUDA5x\ManagedCUDA\CudaKernel.cs:line 2264

Coordinator
Apr 5, 2014 at 11:36 AM
The error you get indicates that the parameters you call the kernel with, don't match the kernel definition. Can you check the object-array you get that it really fits the arguments of your kernel?

Then there's an "else"-case missing in your sample:
if (output)
     cdv = new CudaDeviceVariable<float>(value.Length);
cdv = value;
the case "output == true" has now influence...

Further you should be more careful with respect of allocated device memory: In your sample you allocate device memory using CudaDeviceVariables, but you don't have any possibility to call Dispose() on them. As long as you don't dispose a CudaDeviceVariable, memory stays allocated! We don't have garbage collection for device memory ;-)

-Michael
Apr 5, 2014 at 3:35 PM
Edited Apr 5, 2014 at 7:00 PM
Thanks very much for your help.

I fixed the missing "else" and implemented IDisposable. It still doesn't work. I printed a screenshot of the QuickWatch and compared it with VectorAdd sample and I don't see the problem. Sigh...

Edit:
There must be something in my kernel that is wrong. I get the same error when I use "real" variables...

Edit Again:
I did it. It's working! My unit test has no references to ManagedCuda now! Thanks Michael!