Hedgehog  0.0.0
A library to generate hybrid pipeline workflow systems
abstract_cuda_task.h
1 // NIST-developed software is provided by NIST as a public service. You may use, copy and distribute copies of the
2 // software in any medium, provided that you keep intact this entire notice. You may improve, modify and create
3 // derivative works of the software or any portion of the software, and you may copy and distribute such modifications
4 // or works. Modified works should carry a notice stating that you changed the software and should note the date and
5 // nature of any such change. Please explicitly acknowledge the National Institute of Standards and Technology as the
6 // source of the software. NIST-developed software is expressly provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND,
7 // EXPRESS, IMPLIED, IN FACT OR ARISING BY OPERATION OF LAW, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
8 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT AND DATA ACCURACY. NIST NEITHER REPRESENTS NOR
9 // WARRANTS THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT ANY DEFECTS WILL BE
10 // CORRECTED. NIST DOES NOT WARRANT OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF THE SOFTWARE OR THE RESULTS
11 // THEREOF, INCLUDING BUT NOT LIMITED TO THE CORRECTNESS, ACCURACY, RELIABILITY, OR USEFULNESS OF THE SOFTWARE. You
12 // are solely responsible for determining the appropriateness of using and distributing the software and you assume
13 // all risks associated with its use, including but not limited to the risks and costs of program errors, compliance
14 // with applicable laws, damage to or loss of data, programs or equipment, and the unavailability or interruption of
15 // operation. This software is not intended to be used in any situation where a failure could cause risk of injury or
16 // damage to property. The software developed by NIST employees is not subject to copyright protection within the
17 // United States.
21 //
22 
23 #ifndef HEDGEHOG_ABSTRACT_CUDA_TASK_H
24 #define HEDGEHOG_ABSTRACT_CUDA_TASK_H
25 //#ifdef HH_USE_CUDA
26 #include <unordered_set>
27 #include <cublas.h>
28 #include <cuda_runtime.h>
29 #include "abstract_task.h"
30 
32 namespace hh {
33 #ifndef checkCudaErrors
34 inline void __checkCudaErrors(cudaError_t err, const char *file, const int line) {
40  if (cudaSuccess != err) {
41  std::cerr << "checkCudaErrors() Cuda error = "
42  << err
43  << "\"" << cudaGetErrorString(err) << " \" from "
44  << file << ":" << line << std::endl;
45  exit(43);
46  }
47 }
48 
54 inline void __checkCudaErrors(cublasStatus_t status, const char *file, const int line) {
55  if (CUBLAS_STATUS_SUCCESS != status) {
56  std::cerr << "checkCudaErrors() Status Error = "
57  << status << " from "
58  << file << ":" << line << std::endl;
59  exit(44);
60  }
61 }
62 #define checkCudaErrors(err) __checkCudaErrors(err, __FILE__, __LINE__)
63 #endif
64 
77 template<class TaskOutput, class ... TaskInputs>
78 class AbstractCUDATask : public AbstractTask<TaskOutput, TaskInputs...> {
79  static_assert(traits::isUnique < TaskInputs...>, "A Task can't accept multiple inputs with the same type.");
80  static_assert(sizeof... (TaskInputs) >= 1, "A node need to have one output type and at least one output type.");
81 
82  private:
83  bool enablePeerAccess_ = false;
84  std::unordered_set<int> peerDeviceIds_ = {};
85  cudaStream_t stream_ = {};
86 
87  public:
92  explicit AbstractCUDATask(size_t numberThreads = 1)
93  : AbstractTask<TaskOutput, TaskInputs...>("CudaTask", numberThreads, false),
94  enablePeerAccess_(true) {
95  this->core()->isCudaRelated(true);
96  }
97 
103  explicit AbstractCUDATask(std::string_view const &name, size_t numberThreads = 1)
104  : AbstractTask<TaskOutput, TaskInputs...>(name, numberThreads, false),
105  enablePeerAccess_(true) {
106  this->core()->isCudaRelated(true);
107  }
108 
115  AbstractCUDATask(std::string_view const &name, size_t numberThreads, bool automaticStart, bool enablePeerAccess)
116  : AbstractTask<TaskOutput, TaskInputs...>(name, numberThreads, automaticStart),
117  enablePeerAccess_(enablePeerAccess) {
118  this->core()->isCudaRelated(true);
119  }
120 
123  void initialize() final {
124  int numGpus = 0;
125  int canAccess = 0;
126  checkCudaErrors(cudaGetDeviceCount(&numGpus));
127  assert(this->deviceId() < numGpus);
128  checkCudaErrors(cudaSetDevice(this->deviceId()));
129  checkCudaErrors(cudaStreamCreate(&stream_));
130 
131  if (enablePeerAccess_) {
132  for (int i = 0; i < numGpus; ++i) {
133  if (i != this->deviceId()) {
134  checkCudaErrors(cudaDeviceCanAccessPeer(&canAccess, this->deviceId(), i));
135 
136  if (canAccess) {
137  auto ret = cudaDeviceEnablePeerAccess(i, 0);
138  if (ret != cudaErrorPeerAccessAlreadyEnabled) {
139  checkCudaErrors(ret);
140  }
141  peerDeviceIds_.insert(i);
142  }
143  }
144  }
145  }
146  auto ret = cudaGetLastError();
147  if (ret != cudaErrorPeerAccessAlreadyEnabled) {
148  checkCudaErrors(ret);
149  }
150  this->initializeCuda();
151  }
152 
156  void shutdown() final {
157  this->shutdownCuda();
158  checkCudaErrors(cudaStreamDestroy(stream_));
159  }
160 
162  virtual void initializeCuda() {}
163 
165  virtual void shutdownCuda() {}
166 
169  bool enablePeerAccess() const { return enablePeerAccess_; }
170 
173  cudaStream_t stream() const { return stream_; }
174 
178  bool hasPeerAccess(int peerDeviceId) { return peerDeviceIds_.find(peerDeviceId) != peerDeviceIds_.end(); }
179 };
180 }
181 
182 //#endif //HH_USE_CUDA
183 
184 #endif //HEDGEHOG_ABSTRACT_CUDA_TASK_H
bool enablePeerAccess_
Enable CUDA Peer Access through all CUDA devices available.
void shutdown() final
Shutdown an AbstractCUDATask to destroy the task&#39;s CUDA stream created during AbstractCUDATask::initi...
Base node for computation.
Definition: abstract_task.h:76
AbstractCUDATask(std::string_view const &name, size_t numberThreads=1)
Constructor for an AbstractCUDATask with name as mandatory parameter and the number of threads as opt...
int deviceId()
Task&#39;s device ID accessor.
virtual void shutdownCuda()
Virtual shutdown step, where user defined data structure can be destroyed.
Hedgehog main namespace.
bool enablePeerAccess() const
Accessor for peer access choice.
std::unordered_set< int > peerDeviceIds_
Sparse matrix of linked CUDA devices.
cudaStream_t stream_
CUDA stream linked to the task.
std::shared_ptr< core::CoreNode > core() final
Task&#39;s core accessor.
void initialize() final
Initialize an AbstractCUDATask to bound it to a CUDA device, and do the peer access if enabled...
void __checkCudaErrors(cudaError_t err, const char *file, const int line)
Inline helper function for all of the SDK helper functions, to catch and show CUDA Error...
AbstractCUDATask(size_t numberThreads=1)
Default constructor for an AbstractCUDATask.
cudaStream_t stream() const
Getter for CUDA task&#39;s stream.
bool hasPeerAccess(int peerDeviceId)
Accessor for peer access enabled for a specific device id.
virtual void initializeCuda()
Virtual initialization step, where user defined data structure can be initialized.
std::string_view name()
Task&#39;s name accessor.
bool automaticStart()
Task&#39;s automatic start accessor.
size_t numberThreads()
Task&#39;s number of threads accessor.
Abstract Task specialized for CUDA computation.
AbstractCUDATask(std::string_view const &name, size_t numberThreads, bool automaticStart, bool enablePeerAccess)
Constructor for an AbstractCUDATask with name, number of threads, automaticStart and enablePeerAccess...