New test for you

Sep 17, 2010 at 7:06 PM

Here's a test that actually runs add_array and verifies that the returned result is correct. It's been partially converted from a demo in OpenTK, but I'm guessing the OpenTK demo is taken from somewhere else.


[Test] // Partially from OpenTK demo public void AddArrayAddsCorrectly() { const string correctSource = @" // Simple test; c[i] = a[i] + b[i] __kernel void add_array(__global float *a, __global float *b, __global float *c) { int xid = get_global_id(0); c[xid] = a[xid] + b[xid]; } __kernel void sub_array(__global float *a, __global float *b, __global float *c) { int xid = get_global_id(0); c[xid] = a[xid] - b[xid]; } "; Cl.ErrorCode error; using (Cl.Program program = Cl.CreateProgramWithSource(_context, 1, new[] { correctSource }, null, out error)) { Assert.AreEqual(error, Cl.ErrorCode.Success); error = Cl.BuildProgram(program, 1, new[] { _device }, string.Empty, null, IntPtr.Zero); Assert.AreEqual(Cl.ErrorCode.Success, error); Assert.AreEqual(Cl.GetProgramBuildInfo(program, _device, Cl.ProgramBuildInfo.Status, out error).CastTo<Cl.BuildStatus>(), Cl.BuildStatus.Success); Cl.Kernel kernel = Cl.CreateKernel(program, "add_array", out error); kernel.Dispose(); Cl.Kernel[] kernels = Cl.CreateKernelsInProgram(program, out error); const int cnBlockSize = 4; const int cnBlocks = 3; IntPtr cnDimension = new IntPtr(cnBlocks * cnBlockSize); // allocate host vectors float[] A = new float[cnDimension.ToInt32()]; float[] B = new float[cnDimension.ToInt32()]; float[] C = new float[cnDimension.ToInt32()]; // initialize host memory Random rand = new Random(); for (int i = 0; i < A.Length; i++) { A[i] = rand.Next() % 256; B[i] = rand.Next() % 256; } Cl.Mem hDeviceMemA = Cl.CreateBuffer(_context, Cl.MemFlags.CopyHostPtr | Cl.MemFlags.ReadOnly, (IntPtr)(sizeof(float) * cnDimension.ToInt32()), A, out error); Assert.AreEqual(Cl.ErrorCode.Success, error); Cl.Mem hDeviceMemB = Cl.CreateBuffer(_context, Cl.MemFlags.CopyHostPtr | Cl.MemFlags.ReadOnly, (IntPtr)(sizeof(float) * cnDimension.ToInt32()), B, out error); Assert.AreEqual(Cl.ErrorCode.Success, error); Cl.Mem hDeviceMemC = Cl.CreateBuffer(_context, Cl.MemFlags.CopyHostPtr | Cl.MemFlags.WriteOnly, (IntPtr)(sizeof(float) * cnDimension.ToInt32()), IntPtr.Zero, out error); Assert.AreEqual(Cl.ErrorCode.Success, error); Cl.CommandQueue cmdQueue = Cl.CreateCommandQueue(_context, _device, (Cl.CommandQueueProperties)0, out error); Cl.Event clevent; int inPtrSize = 0; unsafe { inPtrSize= sizeof(IntPtr); } // setup parameter values error = Cl.SetKernelArg(kernel, 0, new IntPtr(inPtrSize), hDeviceMemA); Assert.AreEqual(Cl.ErrorCode.Success, error); error = Cl.SetKernelArg(kernel, 1, new IntPtr(inPtrSize), hDeviceMemB); Assert.AreEqual(Cl.ErrorCode.Success, error); error = Cl.SetKernelArg(kernel, 2, new IntPtr(inPtrSize), hDeviceMemC); Assert.AreEqual(Cl.ErrorCode.Success, error); // write data from host to device error = Cl.EnqueueWriteBuffer(cmdQueue, hDeviceMemA, Cl.Bool.True, IntPtr.Zero, new IntPtr(cnDimension.ToInt32() * sizeof(float)), A, 0, null, out clevent); Assert.AreEqual(Cl.ErrorCode.Success, error); error = Cl.EnqueueWriteBuffer(cmdQueue, hDeviceMemB, Cl.Bool.True, IntPtr.Zero, new IntPtr(cnDimension.ToInt32() * sizeof(float)), B, 0, null, out clevent); Assert.AreEqual(Cl.ErrorCode.Success, error); // execute kernel error = Cl.EnqueueNDRangeKernel(cmdQueue, kernel, 1, null, new IntPtr[] { cnDimension }, null, 0, null, out clevent); Assert.AreEqual(Cl.ErrorCode.Success, error, error.ToString()); // copy results from device back to host IntPtr event_handle = IntPtr.Zero; error = Cl.EnqueueReadBuffer( cmdQueue, hDeviceMemC, Cl.Bool.True, IntPtr.Zero, new IntPtr(cnDimension.ToInt32() * sizeof(float)), C, 0, null, out clevent); Assert.AreEqual(Cl.ErrorCode.Success, error, error.ToString()); for (int i = 0; i < A.Length; i++) { Assert.That(A[i] + B[i], Is.EqualTo(C[i])); } Cl.Finish(cmdQueue); Cl.ReleaseMemObject(hDeviceMemA); Cl.ReleaseMemObject(hDeviceMemB); Cl.ReleaseMemObject(hDeviceMemC); } }

Sep 17, 2010 at 7:16 PM

Ouch, there's a bug in the test but it works anyway - the kernel has been disposed!

                Cl.Kernel kernel = Cl.CreateKernel(program, "add_array", out error);

                kernel.Dispose();

                Cl.Kernel[] kernels = Cl.CreateKernelsInProgram(program, out error);

can be replaced with

                Cl.Kernel[] kernels = Cl.CreateKernelsInProgram(program, out error);
                Cl.Kernel kernel = kernels[0];


Coordinator
Sep 23, 2010 at 5:08 PM

Thank you for submitting the bug and the sample that reproduces it. I will check it out and get back to you shortly.

Coordinator
Sep 23, 2010 at 7:42 PM

The test actually ran fine for me. Is there a problem it's supposed to demonstrate? I'm confused :S

-A.

Sep 24, 2010 at 4:49 AM

When you set the application target platform to .NET Framework 4.0 it fails while complaining about marshalling issues?

With regards,

mattis

From: ananth [mailto:notifications@codeplex.com]
Sent: den 23 september 2010 21:43
To: Mattias Fagerlund
Subject: Re: New test for you [openclnet:227665]

From: ananth

The test actually ran fine for me. Is there a problem it's supposed to demonstrate? I'm confused :S

-A.

Read the full discussion online.

To add a post to this discussion, reply to this email (openclnet@discussions.codeplex.com)

To start a new discussion for this project, email openclnet@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on CodePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at CodePlex.com

Sep 24, 2010 at 5:14 AM

Yep, I can confirm that my test fails as soon as you set the .NET framework to 4.0 – with a fresh download from CodePlex.

 Thanks, btw, for a nice import of OpenCL, I’m hoping to use it to train neural-networks for this project http://sharprbm.codeplex.com/ / http://lotsacode.wordpress.com/2010/09/14/sharprbm-restricted-boltzmann-machines-in-c-net/

 With regards,
mattias

Coordinator
Sep 24, 2010 at 7:18 PM

You're right! Apparently if I marshal the Cl.Event structure (which only contains an IntPtr) with

...[Out] [MarshalAs(UnmanagedType.Struct)] out Event e);

It works on .NET 4.0 but 3.5 (and below) gives me the error "Cannot marshal 'parameter #9': Invalid managed/unmanaged type combination (Int/UInt must be paired with SysInt or SysUInt)" - which is what I had there before.

So while I can fix it, looks like 4.0 is doing something different from (3.5 and all preceding versions). I will ask someone at Microsoft about this problem, and see if they can help me figure out what to do. Good catch! I can only recommend that you use it with either depending on your need for a specific target framework.

If no solution presents itself, I suppose I could use DefineConstants and project property examination (http://msdn.microsoft.com/en-us/library/ms228952.aspx) to perform some sort of conditional compilation? Terribly ugly, though.