1 /*
2  *            Copyright 2009-2020 The VOTCA Development Team
3  *                       (http://www.votca.org)
4  *
5  *      Licensed under the Apache License, Version 2.0 (the "License")
6  *
7  * You may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *              http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19 
20 // Local VOTCA includes
21 #include "votca/xtp/cudamatrix.h"
22 
23 namespace votca {
24 namespace xtp {
checkCuda(cudaError_t result)25 void checkCuda(cudaError_t result) {
26   if (result != cudaSuccess) {
27     throw std::runtime_error(std::string("CUDA Runtime Error: ") +
28                              cudaGetErrorString(result));
29   }
30 }
31 
checkCublas(cublasStatus_t result)32 void checkCublas(cublasStatus_t result) {
33   if (result != CUBLAS_STATUS_SUCCESS) {
34     throw std::runtime_error(std::string("CUBLAS Runtime Error: ") +
35                              cudaGetErrorEnum(result));
36   }
37 }
38 
cudaGetErrorEnum(cublasStatus_t error)39 std::string cudaGetErrorEnum(cublasStatus_t error) {
40   switch (error) {
41     case CUBLAS_STATUS_SUCCESS:
42       return "CUBLAS_STATUS_SUCCESS";
43     case CUBLAS_STATUS_NOT_INITIALIZED:
44       return "CUBLAS_STATUS_NOT_INITIALIZED";
45     case CUBLAS_STATUS_ALLOC_FAILED:
46       return "CUBLAS_STATUS_ALLOC_FAILED";
47     case CUBLAS_STATUS_INVALID_VALUE:
48       return "CUBLAS_STATUS_INVALID_VALUE";
49     case CUBLAS_STATUS_ARCH_MISMATCH:
50       return "CUBLAS_STATUS_ARCH_MISMATCH";
51     case CUBLAS_STATUS_MAPPING_ERROR:
52       return "CUBLAS_STATUS_MAPPING_ERROR";
53     case CUBLAS_STATUS_EXECUTION_FAILED:
54       return "CUBLAS_STATUS_EXECUTION_FAILED";
55     case CUBLAS_STATUS_INTERNAL_ERROR:
56       return "CUBLAS_STATUS_INTERNAL_ERROR";
57     case CUBLAS_STATUS_NOT_SUPPORTED:
58       return "CUBLAS_STATUS_NOT_SUPPORTED";
59     case CUBLAS_STATUS_LICENSE_ERROR:
60       return "CUBLAS_STATUS_LICENSE_ERROR";
61   }
62   return "<unknown>";
63 }
64 
count_available_gpus()65 Index count_available_gpus() {
66   int count;
67   cudaError_t err = cudaGetDeviceCount(&count);
68   return (err != cudaSuccess) ? 0 : Index(count);
69 }
70 
CudaMatrix(Index nrows,Index ncols,const cudaStream_t & stream)71 CudaMatrix::CudaMatrix(Index nrows, Index ncols, const cudaStream_t& stream)
72     : ld_(nrows), cols_(ncols) {
73   data_ = alloc_matrix_in_gpu(size_matrix());
74   stream_ = stream;
75 }
76 
operator Eigen::MatrixXd() const77 CudaMatrix::operator Eigen::MatrixXd() const {
78   Eigen::MatrixXd result = Eigen::MatrixXd::Zero(this->rows(), this->cols());
79   checkCuda(cudaMemcpyAsync(result.data(), this->data(), this->size_matrix(),
80                             cudaMemcpyDeviceToHost, this->stream_));
81   checkCuda(cudaStreamSynchronize(this->stream_));
82   return result;
83 }
84 
setZero()85 void CudaMatrix::setZero() { cudaMemset(data_.get(), 0, size_matrix()); }
86 
alloc_matrix_in_gpu(size_t size_arr) const87 CudaMatrix::Unique_ptr_to_GPU_data CudaMatrix::alloc_matrix_in_gpu(
88     size_t size_arr) const {
89   double* dmatrix;
90   throw_if_not_enough_memory_in_gpu(size_arr);
91   checkCuda(cudaMalloc(&dmatrix, size_arr));
92   Unique_ptr_to_GPU_data dev_ptr(dmatrix,
93                                  [](double* x) { checkCuda(cudaFree(x)); });
94   return dev_ptr;
95 }
96 
throw_if_not_enough_memory_in_gpu(size_t requested_memory) const97 void CudaMatrix::throw_if_not_enough_memory_in_gpu(
98     size_t requested_memory) const {
99   size_t free, total;
100   checkCuda(cudaMemGetInfo(&free, &total));
101 
102   std::ostringstream oss;
103   oss << "There were requested : " << requested_memory
104       << "bytes Index the device\n";
105   oss << "Device Free memory (bytes): " << free
106       << "\nDevice total Memory (bytes): " << total << "\n";
107 
108   // Raise an error if there is not enough total or free memory in the device
109   if (requested_memory > free) {
110     oss << "There is not enough memory in the Device!\n";
111     throw std::runtime_error(oss.str());
112   }
113 }
114 
operator <<(std::ostream & out,const CudaMatrix & m)115 std::ostream& operator<<(std::ostream& out, const CudaMatrix& m) {
116   Eigen::MatrixXd temp = m;
117   out << temp;
118   return out;
119 }
120 
121 }  // namespace xtp
122 }  // namespace votca
123