ningshuxia
2022-12-12 e78f5936fee9ab4fff600515bb20a41a28f329c4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
// <copyright file="CudaLinearAlgebraProvider.cs" company="Math.NET">
// Math.NET Numerics, part of the Math.NET Project
// http://numerics.mathdotnet.com
// http://github.com/mathnet/mathnet-numerics
//
// Copyright (c) 2009-2018 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>
 
#if NATIVE
 
using System;
using IStation.Numerics.Providers.Common.Cuda;
 
namespace IStation.Numerics.Providers.LinearAlgebra.Cuda
{
    /// <summary>
    /// NVidia's CUDA Toolkit linear algebra provider.
    /// </summary>
    internal partial class CudaLinearAlgebraProvider : Managed.ManagedLinearAlgebraProvider, IDisposable
    {
        const int MinimumCompatibleRevision = 1;
 
        readonly string _hintPath;
        IntPtr _blasHandle;
        IntPtr _solverHandle;
 
        /// <param name="hintPath">Hint path where to look for the native binaries</param>
        internal CudaLinearAlgebraProvider(string hintPath)
        {
            _hintPath = hintPath;
        }
 
        /// <summary>
        /// Try to find out whether the provider is available, at least in principle.
        /// Verification may still fail if available, but it will certainly fail if unavailable.
        /// </summary>
        public override bool IsAvailable()
        {
            return CudaProvider.IsAvailable(hintPath: _hintPath);
        }
 
        /// <summary>
        /// Initialize and verify that the provided is indeed available.
        /// If calling this method fails, consider to fall back to alternatives like the managed provider.
        /// </summary>
        public override void InitializeVerify()
        {
            int revision = CudaProvider.Load(hintPath: _hintPath);
            if (revision < MinimumCompatibleRevision)
            {
                throw new NotSupportedException(FormattableString.Invariant($"Cuda Native Provider revision r{revision} is too old. Consider upgrading to a newer version. Revision r{MinimumCompatibleRevision} and newer are supported."));
            }
 
            int linearAlgebra = SafeNativeMethods.query_capability((int)ProviderCapability.LinearAlgebraMajor);
 
            // we only support exactly one major version, since major version changes imply a breaking change.
            if (linearAlgebra != 1)
            {
                throw new NotSupportedException(FormattableString.Invariant($"Cuda Native Provider not compatible. Expecting linear algebra v1 but provider implements v{linearAlgebra}."));
            }
 
            BLAS(SafeNativeMethods.createBLASHandle(ref _blasHandle));
            Solver(SafeNativeMethods.createSolverHandle(ref _solverHandle));
        }
 
        /// <summary>
        /// Frees memory buffers, caches and handles allocated in or to the provider.
        /// Does not unload the provider itself, it is still usable afterwards.
        /// </summary>
        public override void FreeResources()
        {
            CudaProvider.FreeResources();
        }
 
        private void BLAS(int status)
        {
            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 operation.");
 
                case 11: // CUBLAS_STATUS_MAPPING_ERROR
                    throw new Exception("Mapping error.");
 
                case 13: // CUBLAS_STATUS_EXECUTION_FAILED
                    throw new Exception("Execution failed");
 
                case 14: // CUBLAS_STATUS_INTERNAL_ERROR
                    throw new Exception("Internal error");
 
                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);
            }
        }
 
        public override string ToString()
        {
            return CudaProvider.Describe();
        }
 
        public void Dispose()
        {
            BLAS(SafeNativeMethods.destroyBLASHandle(_blasHandle));
            Solver(SafeNativeMethods.destroySolverHandle(_solverHandle));
            FreeResources();
        }
    }
}
 
#endif