diff --git a/src/Mathematics.NET/GPU/OpenCL/Context.cs b/src/Mathematics.NET/GPU/OpenCL/Context.cs index bac80cdd..b4cbe41f 100644 --- a/src/Mathematics.NET/GPU/OpenCL/Context.cs +++ b/src/Mathematics.NET/GPU/OpenCL/Context.cs @@ -33,7 +33,7 @@ namespace Mathematics.NET.GPU.OpenCL; /// Represents an OpenCL context. -public sealed class Context : IOpenCLObject +public sealed partial class Context : IOpenCLObject { // Api. private readonly CL _cl; @@ -44,18 +44,24 @@ public unsafe Context(ILogger logger, CL cl, Platform platform) _cl = cl; _logger = logger; - // Attempt to create a GPU context. If that does not work, attempt to create a CPU context. - var contextProperties = stackalloc nint[3] { (nint)ContextProperties.Platform, platform.Handle, 0 }; - Handle = _cl.CreateContextFromType(contextProperties, DeviceType.Gpu, null, null, out var error); - if (error != (int)ErrorCodes.Success) + try { - _logger.LogDebug("Unable to create GPU context; attempting to create CPU context instead."); - Handle = _cl.CreateContextFromType(contextProperties, DeviceType.Cpu, null, null, out error); + // Attempt to create a GPU context. If that does not work, attempt to create a CPU context. + var contextProperties = stackalloc nint[3] { (nint)ContextProperties.Platform, platform.Handle, 0 }; + Handle = _cl.CreateContextFromType(contextProperties, DeviceType.Gpu, null, null, out var error); if (error != (int)ErrorCodes.Success) { - throw new Exception("Unable to create context on either the GPU or CPU."); + CouldNotCreateGPUContext(); + Handle = _cl.CreateContextFromType(contextProperties, DeviceType.Cpu, null, null, out error); + if (error != (int)ErrorCodes.Success) + throw new Exception("Unable to create context on either the GPU or CPU."); } } + catch (Exception ex) + { + CouldNotCreateContext(ex); + throw; + } } public void Dispose() @@ -67,6 +73,12 @@ public void Dispose() } } + [LoggerMessage(LogLevel.Warning, "Unable to create a GPU context; attempting to create a CPU context instead.")] + private partial void CouldNotCreateGPUContext(); + + [LoggerMessage(LogLevel.Error, "Unable to create a context on either the GPU or CPU.")] + private partial void CouldNotCreateContext(Exception ex); + public nint Handle { get; private set; } public bool IsValidInstance => Handle != 0; diff --git a/src/Mathematics.NET/GPU/OpenCL/Kernel.cs b/src/Mathematics.NET/GPU/OpenCL/Kernel.cs index 7a3e50d0..311009df 100644 --- a/src/Mathematics.NET/GPU/OpenCL/Kernel.cs +++ b/src/Mathematics.NET/GPU/OpenCL/Kernel.cs @@ -33,7 +33,7 @@ namespace Mathematics.NET.GPU.OpenCL; /// Represents an OpenCL kernel. -public sealed class Kernel : IOpenCLObject +public sealed partial class Kernel : IOpenCLObject { private CL _cl; private ILogger _logger; @@ -46,14 +46,10 @@ public unsafe Kernel(ILogger logger, CL cl, Program program, stri _logger = logger; Name = name; - Handle = _cl.CreateKernel(program.Handle, name, out var error); -#if DEBUG + if (error != (int)ErrorCodes.Success) - { - _logger.LogDebug("Unable to create kernel."); - } -#endif + CouldNotCreateKernel(name); } public void Dispose() @@ -65,6 +61,9 @@ public void Dispose() } } + [LoggerMessage(LogLevel.Error, "Unable to create the kernel {Kernel}.")] + private partial void CouldNotCreateKernel(string kernel); + public nint Handle { get; private set; } public bool IsValidInstance => Handle != 0; diff --git a/src/Mathematics.NET/GPU/OpenCL/OpenCLService.cs b/src/Mathematics.NET/GPU/OpenCL/OpenCLService.cs index 5aa9c18b..a6190072 100644 --- a/src/Mathematics.NET/GPU/OpenCL/OpenCLService.cs +++ b/src/Mathematics.NET/GPU/OpenCL/OpenCLService.cs @@ -26,6 +26,7 @@ // #pragma warning disable IDE0032 +#pragma warning disable IDE0058 using System.Runtime.InteropServices; using Microsoft.Extensions.Logging; @@ -34,7 +35,7 @@ namespace Mathematics.NET.GPU.OpenCL; /// Represents an Mathematics.NET OpenCL service. -public sealed class OpenCLService : IComputeService +public sealed partial class OpenCLService : IComputeService { /// A class containing names of common vendors. public static class Vendors @@ -44,9 +45,6 @@ public static class Vendors public const string NVIDIA = "NVIDIA Corporation"; } - private const string s_setKernelArgError = "Unable to set arguments for the kernel {Kernel}."; - private const string s_enqueueNDRangeKernelError = "Problem enqueueing NDRange kernel."; - private ILogger _logger; private CL _cl; @@ -85,9 +83,7 @@ public unsafe OpenCLService(ILogger logger, string vendor, Func x.Vendor == vendor) is Platform platform) { _platform = platform; -#if DEBUG - _logger.LogDebug("Platform vendor: {Vendor}.", _platform.Vendor); -#endif + LogPlatformVendor(_platform.Vendor); } else { @@ -101,12 +97,11 @@ public unsafe OpenCLService(ILogger logger, string vendor, Func Devices => _devices.Span; public Program Program => _program; @@ -161,18 +168,15 @@ public unsafe void CompVecMulScalar(Device device, nuint globalWorkSize, nuint l var kernel = _program.Kernels["comp_vec_mul_scalar_overwrite"].Handle; var error = _cl.SetKernelArg(kernel, 0, (nuint)sizeof(nint), &vectorBuffer); error |= _cl.SetKernelArg(kernel, 1, (nuint)sizeof(Complex), in scalar); -#if DEBUG if (error != (int)ErrorCodes.Success) - _logger.LogDebug(s_setKernelArgError, _program.Kernels["comp_vec_mul_scalar_overwrite"].Name); -#endif + CouldNotSetKernelArguments("comp_vec_mul_scalar_overwrite"); // Enqueue NDRange kernel. using var commandQueue = _context.CreateCommandQueue(device, CommandQueueProperties.None); error = _cl.EnqueueNdrangeKernel(commandQueue.Handle, kernel, 1, null, &globalWorkSize, &localWorkSize, 0, null, null); -#if DEBUG if (error != (int)ErrorCodes.Success) - _logger.LogDebug(s_enqueueNDRangeKernelError); -#endif + CouldNotEnqueueNDRangeKernel("comp_vec_mul_scalar_overwrite"); + // Enqueue read buffer. _cl.EnqueueReadBuffer(commandQueue.Handle, vectorBuffer, true, 0, (nuint)(sizeof(Complex) * vector.Length), pVector, 0, null, null); @@ -200,18 +204,15 @@ public unsafe ReadOnlySpan CompVecMulScalar(Device device, nuint global var error = _cl.SetKernelArg(kernel, 0, (nuint)sizeof(nint), &vectorBuffer); error |= _cl.SetKernelArg(kernel, 1, (nuint)sizeof(Complex), in scalar); error |= _cl.SetKernelArg(kernel, 2, (nuint)sizeof(nint), &resultBuffer); -#if DEBUG if (error != (int)ErrorCodes.Success) - _logger.LogDebug(s_setKernelArgError, _program.Kernels["comp_vec_mul_scalar"].Name); -#endif + CouldNotSetKernelArguments("comp_vec_mul_scalar"); // Enqueue NDRange kernel. using var commandQueue = _context.CreateCommandQueue(device, CommandQueueProperties.None); error = _cl.EnqueueNdrangeKernel(commandQueue.Handle, kernel, 1, null, &globalWorkSize, &localWorkSize, 0, null, null); -#if DEBUG if (error != (int)ErrorCodes.Success) - _logger.LogDebug(s_enqueueNDRangeKernelError); -#endif + CouldNotEnqueueNDRangeKernel("comp_vec_mul_scalar"); + // Enqueue read buffer. _cl.EnqueueReadBuffer(commandQueue.Handle, resultBuffer, true, 0, (nuint)(sizeof(Complex) * length), pResult, 0, null, null); @@ -250,18 +251,15 @@ public unsafe ReadOnlySpan2D CompMatMul(Device device, WorkSize2D globa error |= _cl.SetKernelArg(kernel, 1, (nuint)sizeof(nint), &rightBuffer); error |= _cl.SetKernelArg(kernel, 2, sizeof(int), &k); error |= _cl.SetKernelArg(kernel, 3, (nuint)sizeof(nint), &resultBuffer); -#if DEBUG if (error != (int)ErrorCodes.Success) - _logger.LogDebug(s_setKernelArgError, _program.Kernels["comp_mat_mul"].Name); -#endif + CouldNotSetKernelArguments("comp_mat_mul"); // Enqueue NDRange kernel. using var commandQueue = _context.CreateCommandQueue(device, CommandQueueProperties.None); error = _cl.EnqueueNdrangeKernel(commandQueue.Handle, kernel, 2, null, (nuint*)&globalWorkSize, (nuint*)&localWorkSize, 0, null, null); -#if DEBUG if (error != (int)ErrorCodes.Success) - _logger.LogDebug(s_enqueueNDRangeKernelError); -#endif + CouldNotEnqueueNDRangeKernel("comp_mat_mul"); + // Enqueue read buffer. _cl.EnqueueReadBuffer(commandQueue.Handle, resultBuffer, true, 0, (nuint)(sizeof(Complex) * result.Length), pResult, 0, null, null); @@ -302,18 +300,15 @@ public unsafe ReadOnlySpan2D MatMul(Device device, WorkSize2D globalWorkSi error |= _cl.SetKernelArg(kernel, 1, (nuint)sizeof(nint), &rightBuffer); error |= _cl.SetKernelArg(kernel, 2, sizeof(int), &k); error |= _cl.SetKernelArg(kernel, 3, (nuint)sizeof(nint), &resultBuffer); -#if DEBUG if (error != (int)ErrorCodes.Success) - _logger.LogDebug(s_setKernelArgError, _program.Kernels["mat_mul"].Name); -#endif + CouldNotSetKernelArguments("mat_mul"); // Enqueue NDRange kernel. using var commandQueue = _context.CreateCommandQueue(device, CommandQueueProperties.None); error = _cl.EnqueueNdrangeKernel(commandQueue.Handle, kernel, 2, null, (nuint*)&globalWorkSize, (nuint*)&localWorkSize, 0, null, null); -#if DEBUG if (error != (int)ErrorCodes.Success) - _logger.LogDebug(s_enqueueNDRangeKernelError); -#endif + CouldNotEnqueueNDRangeKernel("mat_mul"); + // Enqueue read buffer. _cl.EnqueueReadBuffer(commandQueue.Handle, resultBuffer, true, 0, (nuint)(sizeof(Real) * result.Length), pResult, 0, null, null); @@ -339,18 +334,15 @@ public unsafe void VecMulScalar(Device device, nuint globalWorkSize, nuint local var kernel = _program.Kernels["vec_mul_scalar_overwrite"].Handle; var error = _cl.SetKernelArg(kernel, 0, (nuint)sizeof(nint), &vectorBuffer); error |= _cl.SetKernelArg(kernel, 1, (nuint)sizeof(Real), in scalar); -#if DEBUG if (error != (int)ErrorCodes.Success) - _logger.LogDebug(s_setKernelArgError, _program.Kernels["vec_mul_scalar_overwrite"].Name); -#endif + CouldNotSetKernelArguments("vec_mul_scalar_overwrite"); // Enqueue NDRange kernel. using var commandQueue = _context.CreateCommandQueue(device, CommandQueueProperties.None); error = _cl.EnqueueNdrangeKernel(commandQueue.Handle, kernel, 1, null, &globalWorkSize, &localWorkSize, 0, null, null); -#if DEBUG if (error != (int)ErrorCodes.Success) - _logger.LogDebug(s_enqueueNDRangeKernelError); -#endif + CouldNotEnqueueNDRangeKernel("vec_mul_scalar_overwrite"); + // Enqueue read buffer. _cl.EnqueueReadBuffer(commandQueue.Handle, vectorBuffer, true, 0, (nuint)(sizeof(Real) * vector.Length), pVector, 0, null, null); @@ -378,18 +370,15 @@ public unsafe ReadOnlySpan VecMulScalar(Device device, nuint globalWorkSiz var error = _cl.SetKernelArg(kernel, 0, (nuint)sizeof(nint), &vectorBuffer); error |= _cl.SetKernelArg(kernel, 1, (nuint)sizeof(Real), &scalar); error |= _cl.SetKernelArg(kernel, 2, (nuint)sizeof(nint), &resultBuffer); -#if DEBUG if (error != (int)ErrorCodes.Success) - _logger.LogDebug(s_setKernelArgError, _program.Kernels["vec_mul_scalar"].Name); -#endif + CouldNotSetKernelArguments("vec_mul_scalar"); // Enqueue NDRange kernel. using var commandQueue = _context.CreateCommandQueue(device, CommandQueueProperties.None); error = _cl.EnqueueNdrangeKernel(commandQueue.Handle, kernel, 1, null, &globalWorkSize, &localWorkSize, 0, null, null); -#if DEBUG if (error != (int)ErrorCodes.Success) - _logger.LogDebug(s_enqueueNDRangeKernelError); -#endif + CouldNotEnqueueNDRangeKernel("vec_mul_scalar"); + // Enqueue read buffer. _cl.EnqueueReadBuffer(commandQueue.Handle, resultBuffer, true, 0, (nuint)(sizeof(Real) * length), pResult, 0, null, null); diff --git a/src/Mathematics.NET/GPU/OpenCL/Program.cs b/src/Mathematics.NET/GPU/OpenCL/Program.cs index fe870eb9..40eef756 100644 --- a/src/Mathematics.NET/GPU/OpenCL/Program.cs +++ b/src/Mathematics.NET/GPU/OpenCL/Program.cs @@ -34,7 +34,7 @@ namespace Mathematics.NET.GPU.OpenCL; /// Represents an OpenCL program. -public sealed class Program : IOpenCLObject +public sealed partial class Program : IOpenCLObject { private readonly CL _cl; private readonly ILogger _logger; @@ -72,10 +72,8 @@ public unsafe Program(ILogger logger, CL cl, Context context, Rea fixed (nuint* pCodeLengths = codeLengths) { Handle = _cl.CreateProgramWithSource(context.Handle, (uint)code.Length, code, pCodeLengths, out var error); -#if DEBUG if (error != (int)ErrorCodes.Success) - _logger.LogDebug("Unable to create the program from source."); -#endif + CouldNotCreateProgram(); } fixed (nint* pDevices = devices.ToArray().Select(x => x.Handle).ToArray()) @@ -115,6 +113,9 @@ public void Dispose() } } + [LoggerMessage(LogLevel.Error, "Unable to create the program from source.")] + private partial void CouldNotCreateProgram(); + public nint Handle { get; private set; } public bool IsValidInstance => Handle != 0;