• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2021-2024 Huawei Technologies Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef MINDSPORE_CCSRC_PLUGIN_DEVICE_GPU_KERNEL_CUSTOM_CUSTOM_AOT_GPU_KERNEL_H
18 #define MINDSPORE_CCSRC_PLUGIN_DEVICE_GPU_KERNEL_CUSTOM_CUSTOM_AOT_GPU_KERNEL_H
19 
20 #ifdef _MSC_VER
21 #include <windows.h>
22 #else
23 #include <dlfcn.h>
24 #endif
25 #include <vector>
26 #include <string>
27 #include <map>
28 #include <algorithm>
29 #include <functional>
30 #include "plugin/device/gpu/kernel/gpu_kernel.h"
31 #include "plugin/device/gpu/kernel/gpu_kernel_factory.h"
32 #include "kernel/common_utils.h"
33 #include "utils/custom_aot_extra.h"
34 #include "utils/file_utils.h"
35 
36 namespace mindspore {
37 namespace kernel {
38 class CustomAOTGpuKernelMod : public NativeGpuKernelMod {
39  public:
CustomAOTGpuKernelMod()40   CustomAOTGpuKernelMod() : handle_(nullptr), aot_func_(nullptr) {}
~CustomAOTGpuKernelMod()41   ~CustomAOTGpuKernelMod() override {
42     attrs_.DestructKernelData();
43 
44     if (handle_ != nullptr) {
45 #ifdef _MSC_VER
46       FreeLibrary(handle_);
47 #else
48       dlclose(handle_);
49 #endif
50     }
51   }
52 
Launch(const std::vector<KernelTensor * > & inputs,const std::vector<KernelTensor * > & workspace,const std::vector<KernelTensor * > & outputs,void * stream_ptr)53   bool Launch(const std::vector<KernelTensor *> &inputs, const std::vector<KernelTensor *> &workspace,
54               const std::vector<KernelTensor *> &outputs, void *stream_ptr) override {
55     std::vector<void *> params;
56 
57     for (size_t i = 0; i < inputs.size(); i++) {
58       params.push_back(static_cast<void *>(inputs[i]->device_ptr()));
59     }
60     for (size_t i = 0; i < outputs.size(); i++) {
61       params.push_back(static_cast<void *>(outputs[i]->device_ptr()));
62     }
63     for (size_t i = 0; i < workspace.size(); i++) {
64       params.push_back(static_cast<void *>(workspace[i]->device_ptr()));
65     }
66     if (!handle_) {
67 #ifdef _MSC_VER
68       MS_LOG(ERROR) << "For '" << kernel_name_ << "' on GPU, dlopen file '" << file_path_
69                     << "' should be successful, but error occurs! ";
70 #else
71       MS_LOG(ERROR) << "For '" << kernel_name_ << "' on GPU, dlopen file '" << file_path_
72                     << "' should be successful, but error occurs! Error message is: " << dlerror();
73 #endif
74       return false;
75     }
76 
77     if (!aot_func_) {
78 #ifdef _MSC_VER
79       aot_func_ =
80         reinterpret_cast<std::add_pointer<int(int, void **, int *, int64_t **, const char **, void *, void *)>::type>(
81           GetProcAddress(handle_, func_name_.c_str()));
82       if (aot_func_ == nullptr) {
83         MS_LOG(ERROR) << "For '" << kernel_name_ << "' on GPU, error occurs when fetching function '" << func_name_;
84         return false;
85       }
86 #else
87       aot_func_ =
88         reinterpret_cast<std::add_pointer<int(int, void **, int *, int64_t **, const char **, void *, void *)>::type>(
89           dlsym(handle_, func_name_.c_str()));
90       if (auto error_info = dlerror(); error_info != nullptr) {
91         MS_LOG(ERROR) << "For '" << kernel_name_ << "' on GPU, error occurs when fetching function '" << func_name_
92                       << "'. Error info: " << error_info;
93         return false;
94       }
95 #endif
96     }
97 
98     int nparam = SizeToInt(params.size());
99     int ret = 0;
100     try {
101       if (nparam == 0) {
102         ret = aot_func_(0, nullptr, nullptr, nullptr, nullptr, stream_ptr, nullptr);
103       } else {
104         ret = aot_func_(nparam, &params[0], &ndims_[0], &shapes_[0], &type_pointer_list_[0], stream_ptr,
105                         reinterpret_cast<void *>(&attrs_));
106       }
107     } catch (const std::exception &e) {
108       MS_LOG(ERROR) << "For '" << kernel_name_ << "' on GPU, operator failed when executing user defined file "
109                     << file_path_ << "! "
110                     << "Error message is " << e.what();
111       return false;
112     }
113 
114     if (ret != 0) {
115       MS_LOG(EXCEPTION) << "Return value from GPU AOT kernel(" << file_path_ << ")'s function(" << func_name_ << ") is "
116                         << ret << ". "
117                         << "Any return value not equal to 0 will be treated as user defined error code and we will "
118                            "terminate execution. If termination is not your purpose, please set return value to 0.";
119     }
120 
121     return true;
122   }
123 
Init(const std::vector<KernelTensor * > & inputs,const std::vector<KernelTensor * > & outputs)124   bool Init(const std::vector<KernelTensor *> &inputs, const std::vector<KernelTensor *> &outputs) override {
125     const auto &exec_info = GetValue<std::string>(primitive_->GetAttr("func_name"));
126     if (auto pos = exec_info.find(":"); pos != std::string::npos) {
127       auto path = exec_info.substr(0, pos);
128       if (primitive_->HasAttr("path_from_env") && GetValue<bool>(primitive_->GetAttr("path_from_env"))) {
129         const char *path_in_env = std::getenv(path.c_str());
130         if (path_in_env == nullptr) {
131           MS_LOG(WARNING) << "For '" << kernel_name_ << "' on GPU, the attr path_from_env is set but the env var ["
132                           << path << "] is empty. Use [" << path << "] as the path to the library instead.";
133 
134         } else {
135           path = std::string(path_in_env);
136         }
137       }
138       auto real_path = FileUtils::GetRealPath(path.c_str());
139       if (!real_path.has_value()) {
140         MS_LOG(EXCEPTION) << "For '" << kernel_name_ << "' on GPU, couldn't find the AOT binary file: " << path;
141       }
142       file_path_ = real_path.value();
143       func_name_ = exec_info.substr(pos + 1);
144       PathChecking();
145     } else {
146       MS_LOG(EXCEPTION)
147         << "For '" << kernel_name_ << "' on GPU, user defined function path '" << exec_info
148         << "' is illegal. Proper function path should follow the format of 'dir_path/file_name:func_name'";
149     }
150 
151     for (size_t i = 0; i < inputs.size(); i++) {
152       auto in_shape = inputs[i]->GetShapeVector();
153       auto dtype = inputs[i]->dtype_id();
154       (void)type_list_.emplace_back(TypeIdToString(dtype, true));
155       ndims_.push_back(SizeToInt(in_shape.size()));
156       (void)shape_list_.emplace_back(in_shape);
157     }
158 
159     for (size_t i = 0; i < outputs.size(); i++) {
160       auto out_shape = outputs[i]->GetShapeVector();
161       auto dtype = outputs[i]->dtype_id();
162       (void)shape_list_.emplace_back(out_shape);
163       ndims_.push_back(SizeToInt(out_shape.size()));
164       (void)type_list_.emplace_back(TypeIdToString(dtype, true));
165     }
166 
167     std::transform(std::begin(shape_list_), std::end(shape_list_), std::back_inserter(shapes_),
168                    [](auto &v) { return &v[0]; });
169     std::transform(std::begin(type_list_), std::end(type_list_), std::back_inserter(type_pointer_list_),
170                    [](auto &str) { return str.c_str(); });
171 
172     attrs_.SetKernelPrim(primitive_);
173 
174     if (!handle_) {
175 #ifdef _MSC_VER
176       handle_ = LoadLibrary(file_path_.c_str());
177       if (!handle_) {
178         MS_LOG(ERROR) << "For '" << kernel_name_ << "' on GPU, dlopen file '" << file_path_
179                       << "' should be successful, but error occurs! ";
180         return false;
181       }
182 #else
183       handle_ = dlopen(file_path_.c_str(), RTLD_LAZY | RTLD_LOCAL);
184       if (!handle_) {
185         MS_LOG(ERROR) << "For '" << kernel_name_ << "' on GPU, dlopen file '" << file_path_
186                       << "' should be successful, but error occurs! Error message is: " << dlerror();
187         return false;
188       }
189 #endif
190     }
191 #ifdef _MSC_VER
192     init_func_ = reinterpret_cast<std::add_pointer<int(int *, int64_t **, const char **, AotExtra *)>::type>(
193       GetProcAddress(handle_, (func_name_ + "Init").c_str()));
194 #else
195     init_func_ = reinterpret_cast<std::add_pointer<int(int *, int64_t **, const char **, AotExtra *)>::type>(
196       dlsym(handle_, (func_name_ + "Init").c_str()));
197 #endif
198     if (init_func_ != nullptr) {
199       // Init func exist in the custom aot file
200       // Call this init func to set custom op attrs
201       int ret = 0;
202       try {
203         ret = init_func_(&ndims_[0], &shapes_[0], &type_pointer_list_[0], (&attrs_));
204       } catch (const std::exception &e) {
205         MS_LOG(ERROR) << "For '" << kernel_name_ << "' on GPU, operator failed when executing user defined file "
206                       << file_path_ << "! "
207                       << "Error message is " << e.what();
208         return false;
209       }
210 
211       if (ret != 0) {
212         MS_LOG(EXCEPTION) << "Return value from GPU AOT kernel(" << file_path_ << ")'s function(" << func_name_
213                           << ") is " << ret << ". "
214                           << "Any return value not equal to 0 will be treated as user defined error code and we will "
215                              "terminate execution. If termination is not your purpose, please set return value to 0.";
216       }
217     }
218     return true;
219   }
220 
Resize(const std::vector<KernelTensor * > & inputs,const std::vector<KernelTensor * > & outputs)221   int Resize(const std::vector<KernelTensor *> &inputs, const std::vector<KernelTensor *> &outputs) override {
222     int ret = KernelMod::Resize(inputs, outputs);
223     if (ret != 0) {
224       return ret;
225     }
226 
227     shapes_.clear();
228     shape_list_.clear();
229     ndims_.clear();
230 
231     for (size_t i = 0; i < inputs.size(); i++) {
232       auto in_shape = inputs[i]->GetShapeVector();
233       (void)shape_list_.emplace_back(in_shape);
234       ndims_.push_back(SizeToInt(in_shape.size()));
235     }
236 
237     for (size_t i = 0; i < outputs.size(); i++) {
238       auto out_shape = outputs[i]->GetShapeVector();
239       (void)shape_list_.emplace_back(out_shape);
240       ndims_.push_back(SizeToInt(out_shape.size()));
241     }
242 
243     (void)std::transform(std::begin(shape_list_), std::end(shape_list_), std::back_inserter(shapes_),
244                          [](auto &v) { return &v[0]; });
245 
246     workspace_size_list_ = attrs_.WorkSpace();
247     return static_cast<int>(KRET_OK);
248   }
249 
250  private:
251   std::string file_path_;
252   std::string func_name_;
253 #ifdef _MSC_VER
254   HMODULE handle_{nullptr};
255 #else
256   void *handle_{nullptr};
257 #endif
258   int (*init_func_)(int *, int64_t **, const char **, AotExtra *);
259   int (*aot_func_)(int, void **, int *, int64_t **, const char **, void *, void *);
260 
261   std::vector<std::vector<int64_t>> shape_list_;
262   std::vector<int> ndims_;
263   std::vector<std::string> type_list_;
264 
265   std::vector<int64_t *> shapes_;
266   std::vector<const char *> type_pointer_list_;
267 
268   AotExtraImpl attrs_;
269 
PathChecking()270   void PathChecking() {
271     constexpr auto kWhiteList = "MS_CUSTOM_AOT_WHITE_LIST";
272     const char *value = std::getenv(kWhiteList);
273     if (value == nullptr) {
274       static bool print_gpu_warning_once = true;
275       if (print_gpu_warning_once) {
276         MS_LOG(INFO) << "For '" << kernel_name_ << "' on GPU, no white list is set and it might cause problems. "
277                      << "Set the legal path of the file in MS_CUSTOM_AOT_WHITE_LIST.";
278         print_gpu_warning_once = false;
279       }
280     } else {
281       auto white_list = FileUtils::GetRealPath(value);
282       if (!white_list.has_value()) {
283         MS_LOG(EXCEPTION) << "Illegal white list path in MS_CUSTOM_AOT_WHITE_LIST: " << std::string(value);
284       }
285       constexpr auto kKernelMeta = "akg_kernel_meta";
286       if (file_path_.find(white_list.value()) == std::string::npos &&
287           file_path_.find(kKernelMeta) == std::string::npos) {
288         MS_LOG(EXCEPTION)
289           << "For '" << kernel_name_
290           << "' on GPU, the file is not place in the legal path file defined by MS_CUSTOM_AOT_WHITE_LIST: "
291           << white_list.value() << ". The file path is: " << file_path_;
292       }
293     }
294   }
295 };
296 }  // namespace kernel
297 }  // namespace mindspore
298 
299 #endif  // MINDSPORE_CCSRC_PLUGIN_DEVICE_GPU_KERNEL_CUSTOM_CUSTOM_AOT_GPU_KERNEL_H
300