CUDNN API  8
cudnn_frontend_ExecutionPlan.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #pragma once
24 
25 #include <algorithm>
26 #include <array>
27 #include <functional>
28 #include <memory>
29 #include <sstream>
30 #include <utility>
31 
32 #include <cudnn.h>
33 #include <cudnn_backend.h>
34 
35 #include "cudnn_frontend_Engine.h"
36 #include "cudnn_frontend_utils.h"
37 
38 namespace cudnn_frontend {
52  public:
54 
56  : BackendDescriptor(from.get_desc(), from.get_status(), from.get_error()),
57  handle(from.handle),
59  planTag(from.planTag) {}
60  ~ExecutionPlan_v8() = default;
65  auto
67  getWorkspaceSize(void) const -> int64_t {
68  uint64_t workSpaceSize = 0;
69  auto status = cudnnBackendGetAttribute(pointer->get_backend_descriptor(),
70  CUDNN_ATTR_EXECUTION_PLAN_WORKSPACE_SIZE,
71  CUDNN_TYPE_INT64,
72  1,
73  NULL,
74  &workSpaceSize);
75  if (status != CUDNN_STATUS_SUCCESS) {
77  status,
78  "CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: GetAttribute "
79  "CUDNN_ATTR_EXECUTION_PLAN_WORKSPACE_SIZE Failed");
80  return workSpaceSize;
81  }
82  if (workSpaceSize < 0) {
84  this, status, "CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: GetAttribute Workspace Size Invalid");
85  return workSpaceSize;
86  }
87  return workSpaceSize;
88  }
89 
90  std::string
91  describe() const override {
92  std::stringstream ss;
93  ss << "CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR :";
94  return ss.str();
95  }
96 
97  std::string const &
98  getTag() const {
99  return planTag;
100  }
101 
102  private:
103  void
105  // Compute a unique tag for execution plan:
106  auto status = CUDNN_STATUS_SUCCESS;
107  std::stringstream tag{""};
108  int64_t elemCount = 0, engineId = 0, numKnobs = 0;
109 
110  ManagedOpaqueDescriptor extractedEngine = make_shared_backend_pointer(CUDNN_BACKEND_ENGINE_DESCRIPTOR);
111  status = extractedEngine->get_status();
112  std::array<ManagedOpaqueDescriptor, CUDNN_KNOB_TYPE_COUNTS> extractedKnobs{{nullptr}};
113  if (status != CUDNN_STATUS_SUCCESS) {
115  this, status, "CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: cudnnCreate Failed when compute tag");
116  }
117 
118  for (auto &knob : extractedKnobs) {
119  knob = make_shared_backend_pointer(CUDNN_BACKEND_KNOB_CHOICE_DESCRIPTOR);
120  status = knob->get_status();
121  if (status != CUDNN_STATUS_SUCCESS) {
123  this, status, "CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: cudnnCreate Failed when compute tag");
124  }
125  }
126 
127  cudnnBackendDescriptor_t extractedEngine_ = extractedEngine->get_backend_descriptor();
128  std::array<cudnnBackendDescriptor_t, CUDNN_KNOB_TYPE_COUNTS> extractedKnobs_{{nullptr}};
129  for (auto i = 0; i < extractedKnobs.size(); i++) {
130  extractedKnobs_[i] = extractedKnobs[i]->get_backend_descriptor();
131  }
132 
133  status = cudnnBackendGetAttribute(engine_config->get_backend_descriptor(),
134  CUDNN_ATTR_ENGINECFG_ENGINE,
135  CUDNN_TYPE_BACKEND_DESCRIPTOR,
136  1,
137  &elemCount,
138  &extractedEngine_);
139  if (status != CUDNN_STATUS_SUCCESS) {
141  status,
142  "CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: GetAttribute "
143  "CUDNN_ATTR_ENGINECFG_ENGINE Failed");
144  }
145  status = cudnnBackendGetAttribute(
146  extractedEngine_, CUDNN_ATTR_ENGINE_GLOBAL_INDEX, CUDNN_TYPE_INT64, 1, &elemCount, &engineId);
147  if (status != CUDNN_STATUS_SUCCESS) {
149  status,
150  "CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: GetAttribute "
151  "CUDNN_ATTR_ENGINE_GLOBAL_INDEX Failed");
152  }
153  tag << "eng" << engineId;
154 
155  status = cudnnBackendGetAttribute(engine_config->get_backend_descriptor(),
156  CUDNN_ATTR_ENGINECFG_KNOB_CHOICES,
157  CUDNN_TYPE_BACKEND_DESCRIPTOR,
158  CUDNN_KNOB_TYPE_COUNTS,
159  &numKnobs,
160  &(extractedKnobs_[0]));
161  if (status != CUDNN_STATUS_SUCCESS) {
163  status,
164  "CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: GetAttribute "
165  "CUDNN_ATTR_ENGINECFG_KNOB_CHOICES Failed");
166  }
167  if (numKnobs > CUDNN_KNOB_TYPE_COUNTS) {
169  status,
170  "CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: GetAttribute "
171  "numKnobs exceed the CUDNN_KNOB_TYPE_COUNTS");
172  }
173  for (int64_t idx = 0; idx < numKnobs; ++idx) {
174  const cudnnBackendDescriptor_t &knob = extractedKnobs_[idx];
175  cudnnBackendKnobType_t type = CUDNN_KNOB_TYPE_COUNTS;
176  int64_t choice = -2;
177  status = cudnnBackendGetAttribute(
178  knob, CUDNN_ATTR_KNOB_CHOICE_KNOB_TYPE, CUDNN_TYPE_KNOB_TYPE, 1, nullptr, &type);
179  if (status != CUDNN_STATUS_SUCCESS) {
181  status,
182  "computeTag CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: GetAttribute "
183  "CUDNN_ATTR_KNOB_CHOICE_KNOB_TYPE Failed");
184  }
185  status = cudnnBackendGetAttribute(
186  knob, CUDNN_ATTR_KNOB_CHOICE_KNOB_VALUE, CUDNN_TYPE_INT64, 1, nullptr, &choice);
187  if (status != CUDNN_STATUS_SUCCESS) {
189  status,
190  "CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: GetAttribute "
191  "CUDNN_ATTR_KNOB_CHOICE_KNOB_VALUE Failed");
192  }
193  tag << "_k" << type << "(" << choice << ")";
194  }
195  planTag += tag.str();
196  }
197 
198  ExecutionPlan_v8() = default;
199  ExecutionPlan_v8(ExecutionPlan_v8 const &) = delete;
201  operator=(ExecutionPlan_v8 const &) = delete;
202 
204  cudnnHandle_t handle = nullptr;
205  std::string planTag;
206 };
207 
212  public:
217  auto
219  setHandle(cudnnHandle_t handle_) -> ExecutionPlanBuilder_v8 & {
220  m_execution_plan.handle = handle_;
221  return *this;
222  }
224  auto
226  m_execution_plan.engine_config = engine_config_.get_desc();
227  m_execution_plan.planTag = engine_config_.getTag();
228  return *this;
229  }
230  auto
231  setEngineConfig(cudnnBackendDescriptor_t &desc, std::string const &opGraphTag_ = "") -> ExecutionPlanBuilder_v8 & {
232  // TBD
233  return *this;
234  }
236  auto
237  setEngineConfig(ManagedOpaqueDescriptor &desc, std::string const &opGraphTag_ = "") -> ExecutionPlanBuilder_v8 & {
238  m_execution_plan.engine_config = desc;
239  m_execution_plan.planTag = opGraphTag_;
240  return *this;
241  }
247  build() {
248  if (m_execution_plan.handle == nullptr) {
250  &m_execution_plan,
251  CUDNN_STATUS_BAD_PARAM,
252  "CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: Check and Set the CUDNN_ATTR_EXECUTION_PLAN_HANDLE");
253  return std::move(m_execution_plan);
254  };
255  if (m_execution_plan.engine_config == nullptr) {
257  &m_execution_plan,
258  CUDNN_STATUS_BAD_PARAM,
259  "CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: Check and Set the CUDNN_ATTR_EXECUTION_PLAN_ENGINE_CONFIG");
260  return std::move(m_execution_plan);
261  };
262 
263  // Create a descriptor. Memory allocation happens here.
264  auto status = m_execution_plan.initialize_managed_backend_pointer(CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR);
265  if (status != CUDNN_STATUS_SUCCESS) {
267  &m_execution_plan, status, "CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: cudnnCreate Failed");
268  return std::move(m_execution_plan);
269  }
270 
271  status = cudnnBackendSetAttribute(m_execution_plan.pointer->get_backend_descriptor(),
272  CUDNN_ATTR_EXECUTION_PLAN_ENGINE_CONFIG,
273  CUDNN_TYPE_BACKEND_DESCRIPTOR,
274  1,
275  &(m_execution_plan.engine_config->get_backend_descriptor()));
276  if (status != CUDNN_STATUS_SUCCESS) {
278  &m_execution_plan,
279  status,
280  "CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: SetAttribute CUDNN_ATTR_EXECUTION_PLAN_ENGINE_CONFIG Failed");
281  return std::move(m_execution_plan);
282  }
283  status = cudnnBackendSetAttribute(m_execution_plan.pointer->get_backend_descriptor(),
284  CUDNN_ATTR_EXECUTION_PLAN_HANDLE,
285  CUDNN_TYPE_HANDLE,
286  1,
287  &m_execution_plan.handle);
288  if (status != CUDNN_STATUS_SUCCESS) {
290  &m_execution_plan,
291  status,
292  "CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: SetAttribute CUDNN_ATTR_EXECUTION_PLAN_HANDLE Failed");
293  return std::move(m_execution_plan);
294  }
295  // Finalizing the descriptor
296  status = cudnnBackendFinalize(m_execution_plan.pointer->get_backend_descriptor());
297  if (status != CUDNN_STATUS_SUCCESS) {
299  &m_execution_plan, status, "CUDNN_BACKEND_EXECUTION_PLAN_DESCRIPTOR: cudnnFinalize Descriptor Failed");
300  return std::move(m_execution_plan);
301  }
302 
303  m_execution_plan.computeTag();
304 
305  return std::move(m_execution_plan);
306  }
307 
308  explicit ExecutionPlanBuilder_v8() = default;
309  ~ExecutionPlanBuilder_v8() = default;
313  operator=(ExecutionPlanBuilder_v8 const &) = delete;
314 
315  private:
317 };
318 }
auto setEngineConfig(EngineConfig_v8 const &engine_config_) -> ExecutionPlanBuilder_v8 &
Set engine Config for the Plan.
static void set_error_and_throw_exception(BackendDescriptor const *desc, cudnnStatus_t status, const char *message)
static ManagedOpaqueDescriptor make_shared_backend_pointer(cudnnBackendDescriptorType_t type)
ExecutionPlan_v8 & operator=(ExecutionPlan_v8 const &)=delete
ManagedOpaqueDescriptor get_desc() const
Returns a copy of underlying managed descriptor.
auto setEngineConfig(ManagedOpaqueDescriptor &desc, std::string const &opGraphTag_="") -> ExecutionPlanBuilder_v8 &
Set engine Config for the Plan.
cudnnStatus_t get_status() const
Current status of the descriptor.
auto setHandle(cudnnHandle_t handle_) -> ExecutionPlanBuilder_v8 &
Set engine for the ExecutionPlan_v8.
std::shared_ptr< OpaqueBackendPointer > ManagedOpaqueDescriptor
auto setEngineConfig(cudnnBackendDescriptor_t &desc, std::string const &opGraphTag_="") -> ExecutionPlanBuilder_v8 &
std::string describe() const override
Return a string describing the backend Descriptor.
const char * get_error() const
Diagonistic error message if any.
cudnnStatus_t status
Shared pointer of the OpaqueBackendPointer.
auto getWorkspaceSize(void) const -> int64_t
Query the workspace requirement for the given plan.