OpenCLNet/UnitTests/Form1.cs

556 lines
22 KiB
C#
Raw Normal View History

2015-11-15 23:13:50 +01:00
/*
* Copyright (c) 2009 Olav Kalgraf(olav.kalgraf@gmail.com)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using OpenCLNet;
namespace UnitTests
{
public partial class Form1 : Form
{
Platform[] Platforms;
Regex ParseOpenCLVersion = new Regex(@"OpenCL (?<MajorVersion>\d+)\.(?<MinorVersion>\d+).*");
public Form1()
{
InitializeComponent();
}
private void startToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
listBoxErrors.Items.Clear();
listBoxWarnings.Items.Clear();
listBoxOutput.Items.Clear();
RunTests();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Test terminated with a fatal exception.");
}
}
private void RunTests()
{
TestOpenCLClass();
}
private void TestOpenCLClass()
{
if (OpenCL.NumberOfPlatforms <= 0)
{
listBoxOutput.Items.Add("OpenCL.NumberOfPlatforms=" + OpenCL.NumberOfPlatforms);
throw new Exception("TestOpenCLClass: NumberOfPlatforms<0. Is the API available at all?");
}
Platforms = OpenCL.GetPlatforms();
if (Platforms.Length != OpenCL.NumberOfPlatforms)
Error("OpenCL.NumberOfPlatforms!=Length of openCL.GetPlatforms()" + OpenCL.NumberOfPlatforms);
for (int platformIndex = 0; platformIndex < Platforms.Length; platformIndex++)
{
if (OpenCL.GetPlatform(platformIndex) != Platforms[platformIndex])
Error("openCL.GetPlatform(platformIndex)!=Platforms[platformIndex]");
Output("Testing Platform " + platformIndex);
TestPlatform(Platforms[platformIndex]);
}
}
private void TestPlatform(Platform p)
{
Device[] allDevices;
Device[] cpuDevices;
Device[] gpuDevices;
Device[] acceleratorDevices;
Output("Name: " + p.Name);
Output("Vendor:" + p.Vendor);
Output("Version:" + p.Version);
// Check format of version string
Match m = ParseOpenCLVersion.Match(p.Version);
if (!m.Success)
Warning("Platform " + p.Name + " has an invalid version string");
else
{
if (m.Groups["MajorVersion"].Value != "1" && m.Groups["MinorVersion"].Value != "0")
Warning("Platform " + p.Name + " has a version number!=1.0(Not really a problem, but this test is written for 1.0)");
}
// Check format of profile
Output("Profile:" + p.Profile);
if (p.Profile == "FULL_PROFILE" || p.Profile == "EMBEDDED_PROFILE")
Output("Profile:" + p.Profile);
else
Warning("Platform " + p.Name + " has unknown profile "+p.Profile);
Output("Extensions: " + p.Extensions);
// Test whether number of devices is consistent
allDevices = p.QueryDevices(DeviceType.ALL);
if( allDevices.Length<=0 )
Warning( "Platform "+p.Name+" has no devices" );
cpuDevices = p.QueryDevices(DeviceType.CPU);
gpuDevices = p.QueryDevices(DeviceType.GPU);
acceleratorDevices = p.QueryDevices(DeviceType.ACCELERATOR);
if( allDevices.Length!=cpuDevices.Length+gpuDevices.Length+acceleratorDevices.Length )
Warning( "QueryDevices( DeviceType.ALL ) return length inconsistent with sum of special purpose queries" );
// Create a few contexts and test them
Output( "Testing Platform.CreateDefaultContext()" );
using (Context c = p.CreateDefaultContext())
{
Output("Testing context"+c);
TestContext(c);
}
Output("");
Output("");
if (cpuDevices.Length > 0)
{
Output("Testing Platform.CreateContext()");
using (Context c = p.CreateContext(null, cpuDevices, new ContextNotify(ContextNotifyFunc), (IntPtr)0x01234567))
{
Output("Testing context" + c);
TestContext(c);
}
Output("");
Output("");
}
if (gpuDevices.Length > 0)
{
Output("Testing Platform.CreateContext()");
using (Context c = p.CreateContext(null, gpuDevices, new ContextNotify(ContextNotifyFunc), (IntPtr)0x01234567))
{
Output("Testing context" + c);
TestContext(c);
}
Output("");
Output("");
}
if (cpuDevices.Length > 0)
{
Output("Testing Platform.CreateContextFromType()");
IntPtr[] contextProperties = new IntPtr[]
{
(IntPtr)ContextProperties.PLATFORM, p.PlatformID,
IntPtr.Zero
};
using (Context c = p.CreateContextFromType(contextProperties, DeviceType.CPU, new ContextNotify(ContextNotifyFunc), (IntPtr)0x01234567))
{
Output("Testing context" + c);
TestContext(c);
}
}
if (gpuDevices.Length > 0)
{
Output("Testing Platform.CreateContextFromType()");
IntPtr[] contextProperties = new IntPtr[]
{
(IntPtr)ContextProperties.PLATFORM, p.PlatformID,
IntPtr.Zero
};
using (Context c = p.CreateContextFromType(contextProperties, DeviceType.GPU, new ContextNotify(ContextNotifyFunc), (IntPtr)0x01234567))
{
Output("Testing context" + c);
TestContext(c);
}
}
}
private void ContextNotifyFunc( string errInfo, byte[] privateInfo, IntPtr cb, IntPtr userData )
{
Error(errInfo);
}
int NativeKernelCalled = 0;
NativeKernel NativeKernelCallRef;
private void TestContext(Context c)
{
Device[] devices = c.Devices;
OpenCLNet.Program p = c.CreateProgramFromFile("MemoryTests.cl");
Dictionary<string, Kernel> kernelDictionary;
try
{
p.Build();
}
catch (OpenCLException ocle)
{
throw ocle;
}
kernelDictionary = p.CreateKernelDictionary();
NativeKernelCallRef = new NativeKernel(NativeKernelTest);
for (int deviceIndex = 0; deviceIndex < devices.Length; deviceIndex++)
{
Device d;
d = devices[deviceIndex];
using (CommandQueue cq = c.CreateCommandQueue(d))
{
if ( (d.ExecutionCapabilities & (ulong)DeviceExecCapabilities.NATIVE_KERNEL)!=0 )
{
Output("Testing native kernel execution");
cq.EnqueueNativeKernel(NativeKernelCallRef);
cq.EnqueueBarrier();
if (NativeKernelCalled != 1)
Error("EnqueueNativeKernel failed");
Interlocked.Decrement(ref NativeKernelCalled);
}
else
{
Output("Testing native kernel execution: Not supported");
}
TestMem(c, cq, kernelDictionary);
TestDevice(d);
TestCommandQueue(c, cq);
TestKernel(c, cq, kernelDictionary["ArgIO"]);
}
}
}
public unsafe void NativeKernelTest(IntPtr args)
{
Interlocked.Increment(ref NativeKernelCalled);
}
[StructLayout(LayoutKind.Sequential, Pack=1)]
internal struct IOKernelArgs
{
internal long outLong;
internal int outInt;
internal float outSingle;
internal IntPtr outIntPtr;
}
private unsafe void TestKernel(Context c, CommandQueue cq, Kernel argIOKernel)
{
Mem outArgBuffer = c.CreateBuffer(MemFlags.WRITE_ONLY, sizeof(IOKernelArgs), IntPtr.Zero);
Output("Testing kernel - Argument return");
argIOKernel.SetIntArg(0, 1);
argIOKernel.SetLongArg(1, 65);
argIOKernel.SetSingleArg(2, 38.4f);
argIOKernel.SetIntPtrArg(3, new IntPtr(0x01234567));
argIOKernel.SetIntPtrArg(4, outArgBuffer.MemID);
cq.EnqueueTask(argIOKernel);
IntPtr outArgPtr = cq.EnqueueMapBuffer( outArgBuffer, true, MapFlags.READ, IntPtr.Zero, (IntPtr)sizeof(IOKernelArgs) );
IOKernelArgs args = (IOKernelArgs)Marshal.PtrToStructure(outArgPtr, typeof(IOKernelArgs));
cq.EnqueueUnmapMemObject(outArgBuffer, outArgPtr);
if (args.outInt != 1)
Error("argIOKernel failed to return correct arguments");
if (args.outLong != 65)
Error("argIOKernel failed to return correct arguments");
if (args.outSingle != 38.4f)
Error("argIOKernel failed to return correct arguments");
if (args.outIntPtr != new IntPtr(0x01234567))
Error("argIOKernel failed to return correct arguments");
}
private void TestMem(Context c, CommandQueue cq, Dictionary<string, Kernel> kernelDictionary )
{
long size = 8192;
Output( "Testing Mem class" );
Output( "Allocating "+size+" bytes of READ_WRITE memory" );
using (Mem buffer = c.CreateBuffer(MemFlags.READ_WRITE, size, IntPtr.Zero))
{
Output("Mem.MemSize=" + size);
if (buffer.MemSize.ToInt64() != size)
Error("Mem.Size!=input size");
Output("Mem.MemType=" + buffer.MemType);
if (buffer.MemType != MemObjectType.BUFFER)
Error("Mem.MemType!=MemObjectType.BUFFER");
Output("Mem.MapCount=" + buffer.MapCount);
if (buffer.MapCount != 0)
Error("Mem.MapCount!=0");
Kernel k = kernelDictionary["TestReadWriteMemory"];
k.SetArg(0, buffer);
k.SetArg(1, (IntPtr)size);
cq.EnqueueTask(k);
cq.EnqueueBarrier();
}
Output("Allocating " + size + " bytes of READ memory");
using (Mem buffer = c.CreateBuffer(MemFlags.READ_ONLY, size, IntPtr.Zero))
{
Output("Mem.MemSize=" + size);
if (buffer.MemSize.ToInt64() != size)
Error("Mem.Size!=input size");
Output("Mem.MemType=" + buffer.MemType);
if (buffer.MemType != MemObjectType.BUFFER)
Error("Mem.MemType!=MemObjectType.BUFFER");
Output("Mem.MapCount=" + buffer.MapCount);
if (buffer.MapCount != 0)
Error("Mem.MapCount!=0");
Kernel k = kernelDictionary["TestReadMemory"];
k.SetArg(0, buffer);
k.SetArg(1, (IntPtr)size);
cq.EnqueueTask(k);
cq.EnqueueBarrier();
}
Output("Allocating " + size + " bytes of WRITE memory");
using (Mem buffer = c.CreateBuffer(MemFlags.WRITE_ONLY, size, IntPtr.Zero))
{
Output("Mem.MemSize=" + size);
if (buffer.MemSize.ToInt64() != size)
Error("Mem.Size!=input size");
Output("Mem.MemType=" + buffer.MemType);
if (buffer.MemType != MemObjectType.BUFFER)
Error("Mem.MemType!=MemObjectType.BUFFER");
Output("Mem.MapCount=" + buffer.MapCount);
if (buffer.MapCount != 0)
Error("Mem.MapCount!=0");
Kernel k = kernelDictionary["TestWriteMemory"];
k.SetArg(0, buffer);
k.SetArg(1, (IntPtr)size);
cq.EnqueueTask(k);
cq.EnqueueBarrier();
}
}
private void TestDevice( Device d )
{
Output("Testing device: " + d.Name);
// d.ToString() is overloaded to output all properties as a string, so every property will be used that way
Output(d.ToString());
}
private void TestCommandQueue(Context c, CommandQueue cq )
{
string programName = @"MemoryTests.cl";
Output("Testing compilation of: " + programName);
OpenCLNet.Program p0 = c.CreateProgramWithSource(File.ReadAllLines(programName));
OpenCLNet.Program p = c.CreateProgramWithSource(File.ReadAllText(programName));
p0.Build();
p.Build();
Kernel k = p.CreateKernel(@"LoopAndDoNothing");
TestCommandQueueMemCopy(c, cq);
TestCommandQueueAsync(c, cq, k );
}
#region TestCommandQueue helper functions
private void TestCommandQueueAsync(Context c, CommandQueue cq, Kernel kernel )
{
List<Event> events = new List<Event>();
Event clEvent;
Output("Testing asynchronous task issuing (clEnqueueTask) and waiting for events");
// Issue a bunch of slow operations
kernel.SetArg(0, 5000000);
for (int i = 0; i < 10; i++)
{
cq.EnqueueTask(kernel, 0, null, out clEvent);
events.Add(clEvent);
}
// Issue a bunch of fast operations
kernel.SetArg(0, 500);
for (int i = 0; i < 1000; i++)
{
cq.EnqueueTask(kernel, 0, null, out clEvent);
events.Add(clEvent);
}
Event[] eventList = events.ToArray();
cq.EnqueueWaitForEvents(eventList.Length, eventList);
while (events.Count > 0)
{
events[0].Dispose();
events.RemoveAt(0);
}
}
private void TestCommandQueueMemCopy(Context c, CommandQueue cq)
{
AlignedArrayFloat aafSrc = new AlignedArrayFloat(1024 * 1024, 64);
AlignedArrayFloat aafDst = new AlignedArrayFloat(1024 * 1024, 64);
SetAAF(aafSrc, 0.0f);
SetAAF(aafDst, 1.0f);
/// Test HOST_PTR -> HOST_PTR copy
/// The call to EnqueueMapBuffer synchronizes caches before testing the result
Output("Testing synchronous host memory->memory copy(clEnqueueCopyBuffer)");
using (Mem memSrc = c.CreateBuffer(MemFlags.USE_HOST_PTR, aafSrc.ByteLength, aafSrc))
{
using (Mem memDst = c.CreateBuffer(MemFlags.USE_HOST_PTR, aafDst.ByteLength, aafDst))
{
cq.EnqueueCopyBuffer(memSrc, memDst, IntPtr.Zero, IntPtr.Zero, (IntPtr)aafSrc.ByteLength);
cq.EnqueueBarrier();
IntPtr mappedPtr = cq.EnqueueMapBuffer(memDst, true, MapFlags.READ, (IntPtr)0, (IntPtr)aafDst.ByteLength);
if (!TestAAF(aafDst, 0.0f))
Error("EnqueueCopyBuffer failed, destination is invalid");
cq.EnqueueUnmapMemObject(memDst, mappedPtr);
cq.EnqueueBarrier();
}
}
/// Test COPY_HOST_PTR -> COPY_HOST_PTR copy
/// Verify that original source buffers are intact and that the copy was successful
Output("Testing synchronous host memory->memory copy(clEnqueueCopyBuffer)");
SetAAF(aafSrc, 0.0f);
SetAAF(aafDst, 1.0f);
using (Mem memSrc = c.CreateBuffer(MemFlags.COPY_HOST_PTR, aafSrc.ByteLength, aafSrc))
{
using (Mem memDst = c.CreateBuffer(MemFlags.COPY_HOST_PTR, aafSrc.ByteLength, aafDst))
{
SetAAF(aafSrc, 2.0f);
SetAAF(aafDst, 3.0f);
cq.EnqueueCopyBuffer(memSrc, memDst, IntPtr.Zero, IntPtr.Zero, (IntPtr)aafSrc.ByteLength);
cq.Finish();
if (!TestAAF(aafSrc, 2.0f))
Error("Memory copy destroyed src buffer");
if (!TestAAF(aafDst, 3.0f))
Error("Memory copy destroyed dst buffer");
cq.EnqueueReadBuffer(memDst, true, IntPtr.Zero, (IntPtr)aafDst.ByteLength, aafDst);
cq.Finish();
if (!TestAAF(aafDst, 0.0f))
Error("Memory copy failed");
}
}
/// Test ALLOC_HOST_PTR -> ALLOC_HOST_PTR copy
Output("Testing synchronous host memory->memory copy(clEnqueueCopyBuffer)");
SetAAF(aafSrc, 0.0f);
SetAAF(aafDst, 1.0f);
using (Mem memSrc = c.CreateBuffer((MemFlags)((ulong)MemFlags.ALLOC_HOST_PTR + (ulong)MemFlags.READ_WRITE), aafSrc.ByteLength, IntPtr.Zero))
{
using (Mem memDst = c.CreateBuffer((MemFlags)((ulong)MemFlags.ALLOC_HOST_PTR + (ulong)MemFlags.WRITE_ONLY), aafSrc.ByteLength, IntPtr.Zero))
{
cq.EnqueueWriteBuffer(memSrc, false, (IntPtr)0, (IntPtr)aafSrc.ByteLength, aafSrc);
cq.EnqueueWriteBuffer(memDst, false, (IntPtr)0, (IntPtr)aafSrc.ByteLength, aafSrc);
cq.EnqueueBarrier();
cq.EnqueueCopyBuffer(memSrc, memDst, IntPtr.Zero, IntPtr.Zero, (IntPtr)aafSrc.ByteLength);
cq.EnqueueBarrier();
cq.EnqueueReadBuffer(memDst, true, IntPtr.Zero, (IntPtr)aafDst.ByteLength, aafDst);
if (!TestAAF(aafDst, 0.0f))
Error("Memory copy failed");
}
}
/// Test DEFAULT -> DEFAULT copy
Output("Testing synchronous host memory->memory copy(clEnqueueCopyBuffer)");
SetAAF(aafSrc, 0.0f);
SetAAF(aafDst, 1.0f);
using (Mem memSrc = c.CreateBuffer((MemFlags)((ulong)MemFlags.ALLOC_HOST_PTR + (ulong)MemFlags.READ_ONLY), aafSrc.ByteLength, IntPtr.Zero))
{
using (Mem memDst = c.CreateBuffer((MemFlags)((ulong)MemFlags.ALLOC_HOST_PTR + (ulong)MemFlags.WRITE_ONLY), aafSrc.ByteLength, IntPtr.Zero))
{
cq.EnqueueWriteBuffer(memSrc, false, (IntPtr)0, (IntPtr)aafSrc.ByteLength, aafSrc);
cq.EnqueueWriteBuffer(memDst, false, (IntPtr)0, (IntPtr)aafSrc.ByteLength, aafSrc);
cq.EnqueueBarrier();
cq.EnqueueCopyBuffer(memSrc, memDst, IntPtr.Zero, IntPtr.Zero, (IntPtr)aafSrc.ByteLength);
cq.EnqueueBarrier();
cq.EnqueueReadBuffer(memDst, true, IntPtr.Zero, (IntPtr)aafDst.ByteLength, aafDst);
if (!TestAAF(aafDst, 0.0f))
Error("Memory copy failed");
}
}
}
private bool TestAAF(AlignedArrayFloat aaf, float c)
{
for (int i = 0; i < aaf.Length; i++)
if (aaf[i] != c)
return false;
return true;
}
private void SetAAF(AlignedArrayFloat aaf, float c)
{
for (int i = 0; i < aaf.Length; i++)
aaf[i] = c;
}
private void SetAAFLinear(AlignedArrayFloat aaf)
{
for (int i = 0; i < aaf.Length; i++)
aaf[i] = (float)i;
}
#endregion
private void Output(string s)
{
listBoxOutput.Items.Add(s);
Application.DoEvents();
}
private void Warning(string s)
{
listBoxWarnings.Items.Add(s);
Application.DoEvents();
}
private void Error(string s)
{
listBoxErrors.Items.Add(s);
Application.DoEvents();
}
}
}