Browse Source

Further cleanup of exceptions, added API specific exception classes and created a shared struct for passing exception information.

cuda
Matthew Johnson 12 years ago
committed by Christoph Ruegg
parent
commit
43d7a794ab
  1. 96
      src/NativeProviders/CUDA/blas.cpp
  2. 25
      src/NativeProviders/CUDA/capabilities.cpp
  3. 9
      src/NativeProviders/CUDA/wrapper_cuda.h
  4. 4
      src/Numerics/Numerics.csproj
  5. 110
      src/Numerics/Providers/LinearAlgebra/Cuda/CuSolverException.cs
  6. 102
      src/Numerics/Providers/LinearAlgebra/Cuda/CublasException.cs
  7. 90
      src/Numerics/Providers/LinearAlgebra/Cuda/CudaException.cs
  8. 96
      src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.cs
  9. 58
      src/Numerics/Providers/LinearAlgebra/Cuda/CudaResults.cs
  10. 40
      src/Numerics/Providers/LinearAlgebra/Cuda/SafeNativeMethods.cs

96
src/NativeProviders/CUDA/blas.cpp

@ -93,88 +93,112 @@ exit:
extern "C" {
DLLEXPORT void s_axpy(const cublasHandle_t blasHandle, const int n, const float alpha, const float x[], float y[], cudaError_t *error, cublasStatus_t *blasStatus){
cuda_axpy(blasHandle, n, alpha, x, 1, y, 1, cublasSaxpy, error, blasStatus);
DLLEXPORT CudaResults s_axpy(const cublasHandle_t blasHandle, const int n, const float alpha, const float x[], float y[]){
CudaResults ret;
cuda_axpy(blasHandle, n, alpha, x, 1, y, 1, cublasSaxpy, &ret.error, &ret.blasStatus);
return ret;
}
DLLEXPORT void d_axpy(const cublasHandle_t blasHandle, const int n, const double alpha, const double x[], double y[], cudaError_t *error, cublasStatus_t *blasStatus){
cuda_axpy(blasHandle, n, alpha, x, 1, y, 1, cublasDaxpy, error, blasStatus);
DLLEXPORT CudaResults d_axpy(const cublasHandle_t blasHandle, const int n, const double alpha, const double x[], double y[]){
CudaResults ret;
cuda_axpy(blasHandle, n, alpha, x, 1, y, 1, cublasDaxpy, &ret.error, &ret.blasStatus);
return ret;
}
DLLEXPORT void c_axpy(const cublasHandle_t blasHandle, const int n, const cuComplex alpha, const cuComplex x[], cuComplex y[], cudaError_t *error, cublasStatus_t *blasStatus){
cuda_axpy(blasHandle, n, alpha, x, 1, y, 1, cublasCaxpy, error, blasStatus);
DLLEXPORT CudaResults c_axpy(const cublasHandle_t blasHandle, const int n, const cuComplex alpha, const cuComplex x[], cuComplex y[]){
CudaResults ret;
cuda_axpy(blasHandle, n, alpha, x, 1, y, 1, cublasCaxpy, &ret.error, &ret.blasStatus);
return ret;
}
DLLEXPORT void z_axpy(const cublasHandle_t blasHandle, const int n, const cuDoubleComplex alpha, const cuDoubleComplex x[], cuDoubleComplex y[], cudaError_t *error, cublasStatus_t *blasStatus){
cuda_axpy(blasHandle, n, alpha, x, 1, y, 1, cublasZaxpy, error, blasStatus);
DLLEXPORT CudaResults z_axpy(const cublasHandle_t blasHandle, const int n, const cuDoubleComplex alpha, const cuDoubleComplex x[], cuDoubleComplex y[]){
CudaResults ret;
cuda_axpy(blasHandle, n, alpha, x, 1, y, 1, cublasZaxpy, &ret.error, &ret.blasStatus);
return ret;
}
DLLEXPORT void s_scale(const cublasHandle_t blasHandle, const int n, const float alpha, float x[], cudaError_t *error, cublasStatus_t *blasStatus){
cuda_scal(blasHandle, n, alpha, x, 1, cublasSscal, error, blasStatus);
DLLEXPORT CudaResults s_scale(const cublasHandle_t blasHandle, const int n, const float alpha, float x[]){
CudaResults ret;
cuda_scal(blasHandle, n, alpha, x, 1, cublasSscal, &ret.error, &ret.blasStatus);
return ret;
}
DLLEXPORT void d_scale(const cublasHandle_t blasHandle, const int n, const double alpha, double x[], cudaError_t *error, cublasStatus_t *blasStatus){
cuda_scal(blasHandle, n, alpha, x, 1, cublasDscal, error, blasStatus);
DLLEXPORT CudaResults d_scale(const cublasHandle_t blasHandle, const int n, const double alpha, double x[]){
CudaResults ret;
cuda_scal(blasHandle, n, alpha, x, 1, cublasDscal, &ret.error, &ret.blasStatus);
return ret;
}
DLLEXPORT void c_scale(const cublasHandle_t blasHandle, const int n, const cuComplex alpha, cuComplex x[], cudaError_t *error, cublasStatus_t *blasStatus){
cuda_scal(blasHandle, n, alpha, x, 1, cublasCscal, error, blasStatus);
DLLEXPORT CudaResults c_scale(const cublasHandle_t blasHandle, const int n, const cuComplex alpha, cuComplex x[]){
CudaResults ret;
cuda_scal(blasHandle, n, alpha, x, 1, cublasCscal, &ret.error, &ret.blasStatus);
return ret;
}
DLLEXPORT void z_scale(const cublasHandle_t blasHandle, const int n, const cuDoubleComplex alpha, cuDoubleComplex x[], cudaError_t *error, cublasStatus_t *blasStatus){
cuda_scal(blasHandle, n, alpha, x, 1, cublasZscal, error, blasStatus);
DLLEXPORT CudaResults z_scale(const cublasHandle_t blasHandle, const int n, const cuDoubleComplex alpha, cuDoubleComplex x[]){
CudaResults ret;
cuda_scal(blasHandle, n, alpha, x, 1, cublasZscal, &ret.error, &ret.blasStatus);
return ret;
}
DLLEXPORT float s_dot_product(const cublasHandle_t blasHandle, const int n, const float x[], const float y[], cudaError_t *error, cublasStatus_t *blasStatus){
float ret;
cuda_dot(blasHandle, n, x, 1, y, 1, &ret, cublasSdot, error, blasStatus);
DLLEXPORT CudaResults s_dot_product(const cublasHandle_t blasHandle, const int n, const float x[], const float y[], float *result){
CudaResults ret;
cuda_dot(blasHandle, n, x, 1, y, 1, result, cublasSdot, &ret.error, &ret.blasStatus);
return ret;
}
DLLEXPORT double d_dot_product(const cublasHandle_t blasHandle, const int n, const double x[], const double y[], cudaError_t *error, cublasStatus_t *blasStatus){
double ret;
cuda_dot(blasHandle, n, x, 1, y, 1, &ret, cublasDdot, error, blasStatus);
DLLEXPORT CudaResults d_dot_product(const cublasHandle_t blasHandle, const int n, const double x[], const double y[], double *result){
CudaResults ret;
cuda_dot(blasHandle, n, x, 1, y, 1, result, cublasDdot, &ret.error, &ret.blasStatus);
return ret;
}
DLLEXPORT cuComplex c_dot_product(const cublasHandle_t blasHandle, const int n, const cuComplex x[], const cuComplex y[], cudaError_t *error, cublasStatus_t *blasStatus){
cuComplex ret;
cuda_dot(blasHandle, n, x, 1, y, 1, &ret, cublasCdotu, error, blasStatus);
DLLEXPORT CudaResults c_dot_product(const cublasHandle_t blasHandle, const int n, const cuComplex x[], const cuComplex y[], cuComplex *result){
CudaResults ret;
cuda_dot(blasHandle, n, x, 1, y, 1, result, cublasCdotu, &ret.error, &ret.blasStatus);
return ret;
}
DLLEXPORT cuDoubleComplex z_dot_product(const cublasHandle_t blasHandle, const int n, const cuDoubleComplex x[], const cuDoubleComplex y[], cudaError_t *error, cublasStatus_t *blasStatus){
cuDoubleComplex ret;
cuda_dot(blasHandle, n, x, 1, y, 1, &ret, cublasZdotu, error, blasStatus);
DLLEXPORT CudaResults z_dot_product(const cublasHandle_t blasHandle, const int n, const cuDoubleComplex x[], const cuDoubleComplex y[], cuDoubleComplex *result){
CudaResults ret;
cuda_dot(blasHandle, n, x, 1, y, 1, result, cublasZdotu, &ret.error, &ret.blasStatus);
return ret;
}
DLLEXPORT void s_matrix_multiply(const cublasHandle_t blasHandle, cublasOperation_t transA, cublasOperation_t transB, const int m, const int n, const int k, const float alpha, const float x[], const float y[], const float beta, float c[], cudaError_t *error, cublasStatus_t *blasStatus){
DLLEXPORT CudaResults s_matrix_multiply(const cublasHandle_t blasHandle, cublasOperation_t transA, cublasOperation_t transB, const int m, const int n, const int k, const float alpha, const float x[], const float y[], const float beta, float c[]){
CudaResults ret;
int lda = transA == CUBLAS_OP_N ? m : k;
int ldb = transB == CUBLAS_OP_N ? k : n;
cuda_gemm(blasHandle, transA, transB, m, n, k, alpha, x, lda, y, ldb, beta, c, m, cublasSgemm, error, blasStatus);
cuda_gemm(blasHandle, transA, transB, m, n, k, alpha, x, lda, y, ldb, beta, c, m, cublasSgemm, &ret.error, &ret.blasStatus);
return ret;
}
DLLEXPORT void d_matrix_multiply(const cublasHandle_t blasHandle, cublasOperation_t transA, cublasOperation_t transB, const int m, const int n, const int k, const double alpha, const double x[], const double y[], const double beta, double c[], cudaError_t *error, cublasStatus_t *blasStatus){
DLLEXPORT CudaResults d_matrix_multiply(const cublasHandle_t blasHandle, cublasOperation_t transA, cublasOperation_t transB, const int m, const int n, const int k, const double alpha, const double x[], const double y[], const double beta, double c[]){
CudaResults ret;
int lda = transA == CUBLAS_OP_N ? m : k;
int ldb = transB == CUBLAS_OP_N ? k : n;
cuda_gemm(blasHandle, transA, transB, m, n, k, alpha, x, lda, y, ldb, beta, c, m, cublasDgemm, error, blasStatus);
cuda_gemm(blasHandle, transA, transB, m, n, k, alpha, x, lda, y, ldb, beta, c, m, cublasDgemm, &ret.error, &ret.blasStatus);
return ret;
}
DLLEXPORT void c_matrix_multiply(const cublasHandle_t blasHandle, cublasOperation_t transA, cublasOperation_t transB, const int m, const int n, const int k, const cuComplex alpha, const cuComplex x[], const cuComplex y[], const cuComplex beta, cuComplex c[], cudaError_t *error, cublasStatus_t *blasStatus){
DLLEXPORT CudaResults c_matrix_multiply(const cublasHandle_t blasHandle, cublasOperation_t transA, cublasOperation_t transB, const int m, const int n, const int k, const cuComplex alpha, const cuComplex x[], const cuComplex y[], const cuComplex beta, cuComplex c[]){
CudaResults ret;
int lda = transA == CUBLAS_OP_N ? m : k;
int ldb = transB == CUBLAS_OP_N ? k : n;
cuda_gemm(blasHandle, transA, transB, m, n, k, alpha, x, lda, y, ldb, beta, c, m, cublasCgemm, error, blasStatus);
cuda_gemm(blasHandle, transA, transB, m, n, k, alpha, x, lda, y, ldb, beta, c, m, cublasCgemm, &ret.error, &ret.blasStatus);
return ret;
}
DLLEXPORT void z_matrix_multiply(const cublasHandle_t blasHandle, cublasOperation_t transA, cublasOperation_t transB, const int m, const int n, const int k, const cuDoubleComplex alpha, const cuDoubleComplex x[], const cuDoubleComplex y[], const cuDoubleComplex beta, cuDoubleComplex c[], cudaError_t *error, cublasStatus_t *blasStatus){
DLLEXPORT CudaResults z_matrix_multiply(const cublasHandle_t blasHandle, cublasOperation_t transA, cublasOperation_t transB, const int m, const int n, const int k, const cuDoubleComplex alpha, const cuDoubleComplex x[], const cuDoubleComplex y[], const cuDoubleComplex beta, cuDoubleComplex c[]){
CudaResults ret;
int lda = transA == CUBLAS_OP_N ? m : k;
int ldb = transB == CUBLAS_OP_N ? k : n;
cuda_gemm(blasHandle, transA, transB, m, n, k, alpha, x, lda, y, ldb, beta, c, m, cublasZgemm, error, blasStatus);
cuda_gemm(blasHandle, transA, transB, m, n, k, alpha, x, lda, y, ldb, beta, c, m, cublasZgemm, &ret.error, &ret.blasStatus);
return ret;
}
}

25
src/NativeProviders/CUDA/capabilities.cpp

@ -1,4 +1,5 @@
#include "wrapper_common.h"
#include "cuda_runtime.h"
#include "cublas_v2.h"
#include "cusolverDn.h"
@ -14,6 +15,24 @@ extern "C" {
*/
DLLEXPORT int query_capability(const int capability)
{
int count;
int device;
cudaDeviceProp prop;
if (cudaGetDeviceCount(&count))
return 0;
if (count == 0)
return 0;
if (cudaGetDevice(&device))
return 0;
if (cudaGetDeviceProperties(&prop, device))
return 0;
switch (capability)
{
@ -42,10 +61,12 @@ extern "C" {
#endif
// COMMON/SHARED
case 64: return 1; // revision
case 64:
return prop.major;
// LINEAR ALGEBRA
case 128: return 1; // basic dense linear algebra
case 128:
return prop.major >= 2;
// OPTIMIZATION
case 256: return 0; // basic optimization

9
src/NativeProviders/CUDA/wrapper_cuda.h

@ -2,7 +2,16 @@
#define WRAPPER_CUDA_H
#include "wrapper_common.h"
#include "cuda_runtime.h"
#include "cusolver_common.h"
#define SAFECUDACALL(error,call) {*error = call; if(*error){goto exit;}}
typedef struct
{
cudaError_t error;
cublasStatus_t blasStatus;
cusolverStatus_t solverStatus;
} CudaResults;
#endif

4
src/Numerics/Numerics.csproj

@ -159,12 +159,16 @@
<Compile Include="Providers\LinearAlgebra\Acml\AcmlLinearAlgebraProvider.Double.cs" />
<Compile Include="Providers\LinearAlgebra\Acml\AcmlLinearAlgebraProvider.Single.cs" />
<Compile Include="Providers\LinearAlgebra\Acml\SafeNativeMethods.cs" />
<Compile Include="Providers\LinearAlgebra\Cuda\CuBLASException.cs" />
<Compile Include="Providers\LinearAlgebra\Cuda\CudaException.cs" />
<Compile Include="Providers\LinearAlgebra\Cuda\CudaLinearAlgebraProvider.Complex.cs" />
<Compile Include="Providers\LinearAlgebra\Cuda\CudaLinearAlgebraProvider.Complex32.cs" />
<Compile Include="Providers\LinearAlgebra\Cuda\CudaLinearAlgebraProvider.cs" />
<Compile Include="Providers\LinearAlgebra\Cuda\CudaLinearAlgebraProvider.Double.cs" />
<Compile Include="Providers\LinearAlgebra\Cuda\CudaLinearAlgebraProvider.Single.cs" />
<Compile Include="Providers\LinearAlgebra\Cuda\CudaProviderCapabilities.cs" />
<Compile Include="Providers\LinearAlgebra\Cuda\CudaResults.cs" />
<Compile Include="Providers\LinearAlgebra\Cuda\CuSolverException.cs" />
<Compile Include="Providers\LinearAlgebra\Cuda\SafeNativeMethods.cs" />
<Compile Include="Providers\LinearAlgebra\Mkl\MklProviderCapabilities.cs" />
<Compile Include="Providers\LinearAlgebra\OpenBlas\OpenBlasLinearAlgebraProvider.cs" />

110
src/Numerics/Providers/LinearAlgebra/Cuda/CuSolverException.cs

@ -0,0 +1,110 @@
// <copyright file="CuSolverException.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com
//
// Copyright (c) 2009-2013 Math.NET
//
// 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.
// </copyright>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
{
/// <summary>
/// Exceptions thrown by the cuSolverDn API.
/// </summary>
public class CuSolverException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="CuSolverException"/> class.
/// </summary>
/// <param name="statusCode">The status code returned from the API</param>
public CuSolverException(int statusCode)
: base(CuSolverException.GetErrorMessage(statusCode))
{
this.StatusCode = statusCode;
}
/// <summary>
/// Gets the status code returned by the cuSolverDn API
/// </summary>
public int StatusCode { get; private set; }
/// <summary>
/// Returns the appropriate error message for each status code.
/// </summary>
/// <param name="code">The status code returned from the API</param>
/// <returns>The corresponding error message</returns>
private static string GetErrorMessage(int statusCode)
{
switch (statusCode)
{
case 0: // CUSOLVER_STATUS_SUCCESS
return "The operation completed successfully.";
case 1: // CUSOLVER_STATUS_NOT_INITIALIZED
return "The cuSolver library was not initialized. This is usually caused by the lack of a prior call, an error in the CUDA Runtime API called by the cuSolver routine, or an error in the hardware setup.";
case 2: // CUSOLVER_STATUS_ALLOC_FAILED
return "Resource allocation failed inside the cuSolver library. This is usually caused by a cudaMalloc() failure.";
case 3: // CUSOLVER_STATUS_INVALID_VALUE
return "An unsupported value or parameter was passed to the function (a negative vector size, for example).";
case 4: // CUSOLVER_STATUS_ARCH_MISMATCH
return "The function requires a feature absent from the device architecture; usually caused by the lack of support for atomic operations or double precision.";
case 5: // CUSOLVER_STATUS_MAPPING_ERROR
return "Mapping Error";
case 6: // CUSOLVER_STATUS_EXECUTION_FAILED
return "The GPU program failed to execute. This is often caused by a launch failure of the kernel on the GPU, which can be caused by multiple reasons.";
case 7: //CUSOLVER_STATUS_INTERNAL_ERROR
return "An internal cuSolver operation failed. This error is usually caused by a cudaMemcpyAsync() failure.";
case 8: // CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED
return "The matrix type is not supported by this function. This is usually caused by passing an invalid matrix descriptor to the function.";
case 9: // CUSOLVER_STATUS_NOT_SUPPORTED
return "The functionality requested is not supported";
case 10: // CUSOLVER_STATUS_ZERO_PIVOT
return "Zero Pivot";
case 11: //CUSOLVER_STATUS_INVALID_LICENSE
return "The functionality requested requires some license and an error was detected when trying to check the current licensing. This error can happen if the license is not present or is expired or if the environment variable NVIDIA_LICENSE_FILE is not set properly.";
default:
throw new Exception("Unrecognized cuSolverDn status code");
}
}
}
}

102
src/Numerics/Providers/LinearAlgebra/Cuda/CublasException.cs

@ -0,0 +1,102 @@
// <copyright file="CuBLASException.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com
//
// Copyright (c) 2009-2013 Math.NET
//
// 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.
// </copyright>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
{
/// <summary>
/// Exceptions thrown by the cuBLAS api.
/// </summary>
public class CuBLASException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="CuBLASException"/> class.
/// </summary>
/// <param name="statusCode">The status code returned from the API</param>
public CuBLASException(int statusCode)
: base(CuBLASException.GetErrorMessage(statusCode))
{
this.StatusCode = statusCode;
}
/// <summary>
/// Gets the status code returned by the cuBLAS API.
/// </summary>
public int StatusCode { get; private set; }
/// <summary>
/// Returns the appropriate error message for each status code.
/// </summary>
/// <param name="code">The status code returned from the API</param>
/// <returns>The corresponding error message</returns>
private static string GetErrorMessage(int statusCode)
{
switch (statusCode)
{
case 0: // CUBLAS_STATUS_SUCCESS
return "The operation completed successfully.";
case 1: // CUBLAS_STATUS_NOT_INITIALIZED
return "The cuBLAS library was not initialized. This is usually caused by the lack of a prior cublasCreate() call, an error in the CUDA Runtime API called by the cuBLAS routine, or an error in the hardware setup.";
case 2: // CUSOLVER_STATUS_ALLOC_FAILED
return "Resource allocation failed inside the cuBLAS library. This is usually caused by a cudaMalloc() failure.";
case 7: // CUBLAS_STATUS_INVALID_VALUE
return "An unsupported value or parameter was passed to the function (a negative vector size, for example).";
case 8: // CUBLAS_STATUS_ARCH_MISMATCH
return "The function requires a feature absent from the device architecture; usually caused by the lack of support for double precision.";
case 11: // CUBLAS_STATUS_MAPPING_ERROR
return "An access to GPU memory space failed, which is usually caused by a failure to bind a texture.";
case 13: // CUBLAS_STATUS_EXECUTION_FAILED
return "The GPU program failed to execute. This is often caused by a launch failure of the kernel on the GPU, which can be caused by multiple reasons.";
case 14: // CUBLAS_STATUS_INTERNAL_ERROR
return "An internal cuBLAS operation failed. This error is usually caused by a cudaMemcpyAsync() failure.";
case 15: // CUBLAS_STATUS_NOT_SUPPORTED
return "The functionality requested is not supported";
case 16: // CUBLAS_STATUS_LICENSE_ERROR
return "The functionality requested requires some license and an error was detected when trying to check the current licensing. This error can happen if the license is not present or is expired or if the environment variable NVIDIA_LICENSE_FILE is not set properly.";
default:
return "Unrecognized cuBLAS status code";
}
}
}
}

90
src/Numerics/Providers/LinearAlgebra/Cuda/CudaException.cs

@ -0,0 +1,90 @@
// <copyright file="CudaException.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com
//
// Copyright (c) 2009-2013 Math.NET
//
// 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.
// </copyright>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
{
/// <summary>
/// Exception thrown by the Cuda Runtime API
/// </summary>
public class CudaException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="CudaException"/> class.
/// </summary>
/// <param name="errorCode">The error code returned by the API</param>
public CudaException(int errorCode)
: base(CudaException.GetErrorMessage(errorCode))
{
this.ErrorCode = errorCode;
}
/// <summary>
/// Gets the error code returned by the Cuda Runtime API.
/// </summary>
public int ErrorCode { get; private set; }
/// <summary>
/// Gets the error message for a particular error code.
/// </summary>
/// <param name="errorCode">The error code returned by the API</param>
/// <returns>The corresponding error message</returns>
private static string GetErrorMessage(int errorCode)
{
switch (errorCode)
{
case 0: // cudaSuccess
return "The API call returned with no errors.";
case 2: // cudaErrorMemoryAllocation
return "The API call failed because it was unable to allocate enough memory to perform the requested operation.";
case 3: // cudaErrorInitializationError
return "The API call failed because the CUDA driver and runtime could not be initialized.";
case 11: // cudaErrorInvalidValue
return "This indicates that one or more of the parameters passed to the API call is not within an acceptable range of values.";
case 17: // cudaErrorInvalidDevicePointer
return "This indicates that at least one device pointer passed to the API call is not a valid device pointer. ";
case 21: // cudaErrorInvalidMemcpyDirection
return "This indicates that the direction of the memcpy passed to the API call is not one of the types specified by cudaMemcpyKind. ";
default:
return "Unknown Cuda Runtime error code";
}
}
}
}

96
src/Numerics/Providers/LinearAlgebra/Cuda/CudaLinearAlgebraProvider.cs

@ -83,95 +83,23 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
if (a != 0 || b != -1 || linearAlgebra <=0 || _nativeRevision < 1)
{
throw new NotSupportedException("Cuda Native Provider too old or not compatible. Consider upgrading to a newer version.");
throw new NotSupportedException("Cuda Native Provider not present, too old or not compatible. Consider upgrading to a newer version.");
}
BLAS(SafeNativeMethods.createBLASHandle(ref _blasHandle));
Solver(SafeNativeMethods.createSolverHandle(ref _solverHandle));
HandleResults(SafeNativeMethods.createBLASHandle(ref _blasHandle));
HandleResults(SafeNativeMethods.createSolverHandle(ref _solverHandle));
}
private void BLAS(int status)
private void HandleResults(CudaResults results)
{
switch (status)
{
case 0: // CUBLAS_STATUS_SUCCESS
return;
case 1: // CUBLAS_STATUS_NOT_INITIALIZED
throw new Exception("The CUDA Runtime initialization failed");
case 2: // CUSOLVER_STATUS_ALLOC_FAILED
throw new OutOfMemoryException("The resources could not be allocated");
case 7: // CUBLAS_STATUS_INVALID_VALUE
throw new ArgumentException("Invalid value");
case 8: // CUBLAS_STATUS_ARCH_MISMATCH
throw new NotSupportedException("The device does not support this opeation.");
case 11: // CUBLAS_STATUS_MAPPING_ERROR
throw new Exception("Mapping error.");
case 13: // CUBLAS_STATUS_EXECUTION_FAILED
throw new Exception("Execution failed");
if (results.Error != 0)
throw new CudaException(results.Error);
case 14: // CUBLAS_STATUS_INTERNAL_ERROR
throw new Exception("Internal error");
if (results.BlasStatus != 0)
throw new CuBLASException(results.BlasStatus);
case 15: // CUBLAS_STATUS_NOT_SUPPORTED
throw new NotSupportedException();
case 16: // CUBLAS_STATUS_LICENSE_ERROR
throw new Exception("License error");
default:
throw new Exception("Unrecognized cuBLAS status code: " + status);
}
}
private void Solver(int status)
{
switch (status)
{
case 0: // CUSOLVER_STATUS_SUCCESS
return;
case 1: // CUSOLVER_STATUS_NOT_INITIALIZED
throw new Exception("The library was not initialized");
case 2: // CUSOLVER_STATUS_ALLOC_FAILED
throw new OutOfMemoryException("The resources could not be allocated");
case 3: // CUSOLVER_STATUS_INVALID_VALUE
throw new ArgumentException("Invalid value");
case 4: // CUSOLVER_STATUS_ARCH_MISMATCH
throw new NotSupportedException("The device does not support compute capability 2.0 and above");
case 5: // CUSOLVER_STATUS_MAPPING_ERROR
throw new Exception("Mapping error");
case 6: // CUSOLVER_STATUS_EXECUTION_FAILED
throw new NonConvergenceException("Execution failed");
case 7: //CUSOLVER_STATUS_INTERNAL_ERROR
throw new Exception("Internal error");
case 8: // CUSOLVER_STATUS_MATRIX_TYPE_NOT_SUPPORTED
throw new ArgumentException("Matrix type not supported");
case 9: // CUSOLVER_STATUS_NOT_SUPPORTED
throw new NotSupportedException();
case 10: // CUSOLVER_STATUS_ZERO_PIVOT
throw new Exception("Zero pivot");
case 11: //CUSOLVER_STATUS_INVALID_LICENSE
throw new Exception("Invalid license");
default:
throw new Exception("Unrecognized cuSolverDn status code: " + status);
}
if (results.SolverStatus != 0)
throw new CuSolverException(results.SolverStatus);
}
public override string ToString()
@ -184,8 +112,8 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
public void Dispose()
{
BLAS(SafeNativeMethods.destroyBLASHandle(_blasHandle));
Solver(SafeNativeMethods.destroySolverHandle(_solverHandle));
HandleResults(SafeNativeMethods.destroyBLASHandle(_blasHandle));
HandleResults(SafeNativeMethods.destroySolverHandle(_solverHandle));
}
}
}

58
src/Numerics/Providers/LinearAlgebra/Cuda/CudaResults.cs

@ -0,0 +1,58 @@
// <copyright file="CudaResults.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
// http://mathnetnumerics.codeplex.com
//
// Copyright (c) 2009-2013 Math.NET
//
// 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.
// </copyright>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
{
/// <summary>
/// Struct containing the various results from different CUDA API calls.
/// </summary>
private struct CudaResults
{
/// <summary>
/// Maps to cudaError_t
/// </summary>
public int Error;
/// <summary>
/// Maps to cublasStatus_t
/// </summary>
public int BlasStatus;
/// <summary>
/// Maps to cusolverStatus_t
/// </summary>
public int SolverStatus;
}
}

40
src/Numerics/Providers/LinearAlgebra/Cuda/SafeNativeMethods.cs

@ -54,66 +54,66 @@ namespace MathNet.Numerics.Providers.LinearAlgebra.Cuda
internal static extern int query_capability(int capability);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern int createBLASHandle(ref IntPtr blasHandle);
internal static extern CudaResults createBLASHandle(ref IntPtr blasHandle);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern int destroyBLASHandle(IntPtr blasHandle);
internal static extern CudaResults destroyBLASHandle(IntPtr blasHandle);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern int createSolverHandle(ref IntPtr solverHandle);
internal static extern CudaResults createSolverHandle(ref IntPtr solverHandle);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern int destroySolverHandle(IntPtr solverHandle);
internal static extern CudaResults destroySolverHandle(IntPtr solverHandle);
#region BLAS
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern void s_axpy(IntPtr blasHandle, int n, float alpha, float[] x, [In, Out] float[] y);
internal static extern CudaResults s_axpy(IntPtr blasHandle, int n, float alpha, float[] x, [In, Out] float[] y);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern void d_axpy(IntPtr blasHandle, int n, double alpha, double[] x, [In, Out] double[] y);
internal static extern CudaResults d_axpy(IntPtr blasHandle, int n, double alpha, double[] x, [In, Out] double[] y);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern void c_axpy(IntPtr blasHandle, int n, Complex32 alpha, Complex32[] x, [In, Out] Complex32[] y);
internal static extern CudaResults c_axpy(IntPtr blasHandle, int n, Complex32 alpha, Complex32[] x, [In, Out] Complex32[] y);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern void z_axpy(IntPtr blasHandle, int n, Complex alpha, Complex[] x, [In, Out] Complex[] y);
internal static extern CudaResults z_axpy(IntPtr blasHandle, int n, Complex alpha, Complex[] x, [In, Out] Complex[] y);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern void s_scale(IntPtr blasHandle, int n, float alpha, [Out] float[] x);
internal static extern CudaResults s_scale(IntPtr blasHandle, int n, float alpha, [Out] float[] x);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern void d_scale(IntPtr blasHandle, int n, double alpha, [Out] double[] x);
internal static extern CudaResults d_scale(IntPtr blasHandle, int n, double alpha, [Out] double[] x);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern void c_scale(IntPtr blasHandle, int n, Complex32 alpha, [In, Out] Complex32[] x);
internal static extern CudaResults c_scale(IntPtr blasHandle, int n, Complex32 alpha, [In, Out] Complex32[] x);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern void z_scale(IntPtr blasHandle, int n, Complex alpha, [In, Out] Complex[] x);
internal static extern CudaResults z_scale(IntPtr blasHandle, int n, Complex alpha, [In, Out] Complex[] x);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern float s_dot_product(IntPtr blasHandle, int n, float[] x, float[] y);
internal static extern CudaResults s_dot_product(IntPtr blasHandle, int n, float[] x, float[] y, ref float result);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern double d_dot_product(IntPtr blasHandle, int n, double[] x, double[] y);
internal static extern CudaResults d_dot_product(IntPtr blasHandle, int n, double[] x, double[] y, ref double result);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern Complex32 c_dot_product(IntPtr blasHandle, int n, Complex32[] x, Complex32[] y);
internal static extern CudaResults c_dot_product(IntPtr blasHandle, int n, Complex32[] x, Complex32[] y, ref Complex32 result);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern Complex z_dot_product(IntPtr blasHandle, int n, Complex[] x, Complex[] y);
internal static extern CudaResults z_dot_product(IntPtr blasHandle, int n, Complex[] x, Complex[] y, ref Complex result);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern void s_matrix_multiply(IntPtr blasHandle, int transA, int transB, int m, int n, int k, float alpha, float[] x, float[] y, float beta, [In, Out] float[] c);
internal static extern CudaResults s_matrix_multiply(IntPtr blasHandle, int transA, int transB, int m, int n, int k, float alpha, float[] x, float[] y, float beta, [In, Out] float[] c);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern void d_matrix_multiply(IntPtr blasHandle, int transA, int transB, int m, int n, int k, double alpha, double[] x, double[] y, double beta, [In, Out] double[] c);
internal static extern CudaResults d_matrix_multiply(IntPtr blasHandle, int transA, int transB, int m, int n, int k, double alpha, double[] x, double[] y, double beta, [In, Out] double[] c);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern void c_matrix_multiply(IntPtr blasHandle, int transA, int transB, int m, int n, int k, Complex32 alpha, Complex32[] x, Complex32[] y, Complex32 beta, [In, Out] Complex32[] c);
internal static extern CudaResults c_matrix_multiply(IntPtr blasHandle, int transA, int transB, int m, int n, int k, Complex32 alpha, Complex32[] x, Complex32[] y, Complex32 beta, [In, Out] Complex32[] c);
[DllImport(_DllName, ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Cdecl)]
internal static extern void z_matrix_multiply(IntPtr blasHandle, int transA, int transB, int m, int n, int k, Complex alpha, Complex[] x, Complex[] y, Complex beta, [In, Out] Complex[] c);
internal static extern CudaResults z_matrix_multiply(IntPtr blasHandle, int transA, int transB, int m, int n, int k, Complex alpha, Complex[] x, Complex[] y, Complex beta, [In, Out] Complex[] c);
internal static int ToCUDA(this Transpose transpose)
{

Loading…
Cancel
Save