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, ¶ms[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