Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "ae_kernel_lib_fwk.hpp"
12 : #include "securec.h"
13 : #include "aicpu_context.h"
14 : #include "aicpu_event_struct.h"
15 :
16 : namespace {
17 : // aicpu so root dir, must be absolute path.
18 : constexpr const char *AICPU_SO_ROOT_PATH = "/usr/lib64/aicpu_kernels/";
19 : // tf kernels so name
20 : constexpr const char *TF_SO_NAME = "libtf_kernels.so";
21 : // tensorflow so name
22 : constexpr const char *TENSORFLOW_SO_NAME = "libtensorflow.so";
23 : // tensorflow tar uncompress path
24 : constexpr const char *TENSORFLOW_SO_UNCOMPRESS_PAHT = "sand_box";
25 : // aicpu kernels tar uncompress path
26 : constexpr const char *AICPU_SO_UNCOMPRESS_PATH = "aicpu_kernels_device";
27 : constexpr const uint32_t MAX_SO_PATH = 4096U;
28 : const std::string THREAD_MODE_SO_PATH_FIX = "aicpu_kernels";
29 : }
30 :
31 : namespace cce {
32 : AIKernelsLibFWK *AIKernelsLibFWK::instance_ = nullptr;
33 : std::mutex AIKernelsLibFWK::mtx_;
34 :
35 9 : AIKernelsLibFWK *AIKernelsLibFWK::GetInstance()
36 : {
37 9 : const std::lock_guard<std::mutex> lockGuard(mtx_);
38 9 : if (instance_ != nullptr) {
39 5 : return instance_;
40 : } else {
41 4 : instance_ = new(std::nothrow) AIKernelsLibFWK();
42 4 : if (instance_ == nullptr) {
43 0 : return nullptr;
44 : }
45 4 : (void)instance_->Init();
46 4 : return instance_;
47 : }
48 9 : }
49 :
50 4 : void AIKernelsLibFWK::DestroyInstance()
51 : {
52 4 : const std::lock_guard<std::mutex> lockGuard(mtx_);
53 4 : if (instance_ == nullptr) {
54 0 : return;
55 : }
56 4 : delete instance_;
57 4 : instance_ = nullptr;
58 4 : }
59 :
60 4 : aeStatus_t AIKernelsLibFWK::Init()
61 : {
62 4 : return tfImpl_.Init();
63 : }
64 :
65 :
66 1 : aeStatus_t AIKernelsLibFWK::CloseSo(const char_t * const soName)
67 : {
68 : (void)soName;
69 1 : return AE_STATUS_SUCCESS;
70 : }
71 :
72 4 : int32_t AIKernelsLibFWK::CallKernelApi(const aicpu::KernelType kernelType, const void * const kernelBase)
73 : {
74 4 : const auto fwkKernel = reinterpret_cast<const aicpu::HwtsFwkKernel * const>(kernelBase);
75 4 : if (static_cast<bool>(unlikely(fwkKernel == nullptr))) {
76 1 : AE_ERR_LOG(AE_MODULE_ID, "Input param fwkKernelBase is NULL.");
77 1 : return AE_STATUS_BAD_PARAM;
78 : }
79 :
80 3 : const auto fwkOpKernelPtr = static_cast<const uintptr_t>(fwkKernel->kernel);
81 3 : const auto fwkOpKernel = reinterpret_cast<const STR_FWK_OP_KERNEL * const>(fwkOpKernelPtr);
82 3 : if (static_cast<bool>(unlikely(fwkOpKernel == nullptr))) {
83 0 : AE_ERR_LOG(AE_MODULE_ID, "Input param fwkOpKernel is NULL.");
84 0 : return AE_STATUS_BAD_PARAM;
85 : }
86 3 : AE_INFO_LOG(AE_MODULE_ID, "Current kernelType:%d, FWK op kernel kernel type:%d.",
87 : kernelType, fwkOpKernel->fwkKernelType);
88 :
89 : // Call different Implement method switch by kernel type.
90 3 : int32_t ret = AE_STATUS_SUCCESS;
91 3 : switch (static_cast<FwkkernelType_t>(fwkOpKernel->fwkKernelType)) {
92 3 : case FMK_KERNEL_TYPE_TF:
93 3 : ret = tfImpl_.CallKernelApi(PtrToValue(PtrToPtr<const ::aicpu::FWKAdapter::FWKOperateParam,
94 : const void>(&fwkOpKernel->fwkKernelBase.fwk_kernel)));
95 3 : break;
96 0 : default:
97 0 : AE_ERR_LOG(AE_MODULE_ID, "Input param fwkKernelType in STR_FWK_OP_KERNEL is invalid :%d",
98 : fwkOpKernel->fwkKernelType);
99 0 : ret = AE_STATUS_BAD_PARAM;
100 0 : break;
101 : }
102 3 : return ret;
103 : }
104 :
105 3 : aeStatus_t AIKernelsLibFWK::BatchLoadKernelSo(const aicpu::KernelType kernelType,
106 : std::vector<std::string> &soVec)
107 : {
108 3 : AE_INFO_LOG(AE_MODULE_ID, "Begin to batch load kernel so, kerelType:[%d].", kernelType);
109 3 : if (soVec.empty()) {
110 0 : return AE_STATUS_SUCCESS;
111 : }
112 : // only one tf so
113 3 : return tfImpl_.LoadTfSo();
114 : }
115 :
116 : // need refresh soFile_
117 24 : FWKKernelTfImpl::FWKKernelTfImpl() : kernelName_("TFOperateAPI"),
118 12 : funcAddr_(nullptr),
119 12 : soHandle_(nullptr),
120 12 : soTensorflowHandle_(nullptr)
121 : {
122 12 : }
123 :
124 4 : aeStatus_t FWKKernelTfImpl::Init()
125 : {
126 4 : std::string baseSoFile(AICPU_SO_ROOT_PATH);
127 4 : (void)baseSoFile.append(TF_SO_NAME);
128 4 : soFile_ = baseSoFile;
129 : aicpu::aicpuContext_t currentAicpuCtx;
130 4 : const aicpu::status_t status = aicpu::aicpuGetContext(¤tAicpuCtx);
131 4 : if (status == aicpu::AICPU_ERROR_NONE) {
132 4 : std::string soPath(AICPU_SO_ROOT_PATH);
133 8 : (void)soPath.append(std::to_string(aicpu::GetUniqueVfId()))
134 4 : .append("/")
135 4 : .append(AICPU_SO_UNCOMPRESS_PATH)
136 4 : .append("/");
137 4 : soFile_ = soPath + TF_SO_NAME;
138 4 : GetThreadModelSoPath(soPath);
139 : // check so file
140 4 : const aeStatus_t ret = SingleSoManager::CheckSoFile(soPath, soFile_);
141 4 : if (ret != AE_STATUS_SUCCESS) {
142 4 : soFile_ = baseSoFile;
143 4 : AE_RUN_INFO_LOG(AE_MODULE_ID, "So does not exist in path %s, use default soFile %s.",
144 : soPath.c_str(), baseSoFile.c_str());
145 : }
146 4 : }
147 4 : AE_INFO_LOG(AE_MODULE_ID, "FWKernelTfImpl init success, soFile_=%s.", soFile_.c_str());
148 4 : return AE_STATUS_SUCCESS;
149 4 : }
150 :
151 12 : FWKKernelTfImpl::~FWKKernelTfImpl()
152 : {
153 12 : AE_RW_LOCK_WR_LOCK(&rwLock_);
154 12 : funcAddr_ = nullptr;
155 12 : aeStatus_t ret = SingleSoManager::CloseSo(soHandle_);
156 12 : if (ret != AE_STATUS_SUCCESS) {
157 0 : AE_RUN_WARN_LOG(AE_MODULE_ID, "~FWKKernelTfImpl CloseSo failed, ret is[%d]", ret);
158 : }
159 12 : ret = SingleSoManager::CloseSo(soTensorflowHandle_);
160 12 : if (ret != AE_STATUS_SUCCESS) {
161 0 : AE_RUN_WARN_LOG(AE_MODULE_ID, "~FWKKernelTensorflowImpl CloseSo failed, ret is[%d]", ret);
162 : }
163 12 : soHandle_ = nullptr;
164 12 : soTensorflowHandle_ = nullptr;
165 12 : AE_RW_LOCK_UN_LOCK(&rwLock_);
166 12 : AE_RW_LOCK_DESTROY(&rwLock_);
167 12 : }
168 :
169 8 : void FWKKernelTfImpl::GetTfKernelThreadModeSoPath(std::string &soPath) const
170 : {
171 8 : (void)soPath.append(THREAD_MODE_SO_PATH_FIX)
172 8 : .append("/")
173 16 : .append(std::to_string(aicpu::GetUniqueVfId()))
174 8 : .append("/")
175 8 : .append(AICPU_SO_UNCOMPRESS_PATH)
176 8 : .append("/");
177 8 : return;
178 : }
179 :
180 0 : void FWKKernelTfImpl::GetTensorflowThreadModeSoPath(std::string soPath)
181 : {
182 0 : (void)soPath.append(THREAD_MODE_SO_PATH_FIX)
183 0 : .append("/")
184 0 : .append(std::to_string(aicpu::GetUniqueVfId()))
185 0 : .append("/")
186 0 : .append(AICPU_SO_UNCOMPRESS_PATH)
187 0 : .append("/")
188 0 : .append(TENSORFLOW_SO_UNCOMPRESS_PAHT)
189 0 : .append("/");
190 0 : tensorflowSoFile_ = soPath + TENSORFLOW_SO_NAME;
191 0 : return;
192 : }
193 :
194 9 : aeStatus_t FWKKernelTfImpl::GetTfThreadModeSoPath(std::string &soPath)
195 : {
196 9 : const char_t * const innerDirName = getenv("HOME");
197 9 : if (innerDirName != nullptr) {
198 8 : const std::string str = innerDirName;
199 8 : const size_t len = str.length();
200 8 : if ((len == 0U) || (len >= static_cast<size_t>(MAX_SO_PATH))) {
201 0 : AE_ERR_LOG(AE_MODULE_ID, "Length[%zu] of inner so dir is invalid.", len);
202 0 : return AE_STATUS_INNER_ERROR;
203 : }
204 8 : soPath = str;
205 8 : if (soPath[soPath.size() - 1UL] != '/') {
206 8 : (void)soPath.append("/");
207 : }
208 8 : GetTensorflowThreadModeSoPath(soPath);
209 8 : GetTfKernelThreadModeSoPath(soPath);
210 8 : return AE_STATUS_SUCCESS;
211 8 : } else {
212 1 : AE_RUN_WARN_LOG(AE_MODULE_ID, "Get HOME env failed, get tf thread mode so path failed.");
213 1 : return AE_STATUS_INNER_ERROR;
214 : }
215 : }
216 :
217 7 : void FWKKernelTfImpl::GetThreadModelSoPath(std::string &soPath)
218 : {
219 : uint32_t runMode;
220 7 : aicpu::status_t status = aicpu::GetAicpuRunMode(runMode);
221 7 : if (status != aicpu::AICPU_ERROR_NONE) {
222 1 : AE_ERR_LOG(AE_MODULE_ID, "Get current aicpu ctx failed.");
223 2 : return;
224 : }
225 6 : if (runMode != aicpu::AicpuRunMode::THREAD_MODE) {
226 0 : return;
227 : }
228 6 : std::string threadSoPath;
229 6 : if (GetTfThreadModeSoPath(threadSoPath) != AE_STATUS_SUCCESS) {
230 1 : AE_WARN_LOG(AE_MODULE_ID, "GetThreadModeSoPath failed.");
231 1 : return;
232 : }
233 5 : soPath = threadSoPath;
234 5 : soFile_ = threadSoPath + TF_SO_NAME;
235 6 : }
236 :
237 3 : int32_t FWKKernelTfImpl::CallKernelApi(const uint64_t fwkKernelParam)
238 : {
239 3 : void *theFuncAddr = nullptr;
240 3 : AE_RW_LOCK_RD_LOCK(&rwLock_);
241 3 : if (static_cast<bool>(unlikely(funcAddr_ != nullptr))) {
242 0 : theFuncAddr = funcAddr_;
243 : }
244 3 : AE_RW_LOCK_UN_LOCK(&rwLock_);
245 :
246 3 : if (static_cast<bool>(unlikely(theFuncAddr == nullptr))) {
247 3 : AE_RW_LOCK_WR_LOCK(&rwLock_);
248 3 : if (static_cast<bool>(unlikely(funcAddr_ == nullptr))) {
249 3 : AE_INFO_LOG(AE_MODULE_ID, "Begin to GetApi, soFile=%s, kernelName=%s.",
250 : GetSoFile().c_str(), GetKernelName().c_str());
251 :
252 3 : aeStatus_t retGetApi = AE_STATUS_SUCCESS;
253 3 : if (static_cast<bool>(unlikely(soHandle_ == nullptr))) {
254 3 : retGetApi = SingleSoManager::GetApi(GetSoFile().data(), GetKernelName().data(),
255 : &funcAddr_, &soHandle_);
256 : } else {
257 0 : retGetApi = SingleSoManager::GetFunc(soHandle_, GetKernelName().data(), &funcAddr_);
258 : }
259 3 : AE_INFO_LOG(AE_MODULE_ID, "End to GetApi, retGetApi=%d.", retGetApi);
260 :
261 3 : if (static_cast<bool>(unlikely((retGetApi == AE_STATUS_SUCCESS) && (funcAddr_ == nullptr)))) {
262 1 : AE_RW_LOCK_UN_LOCK(&rwLock_);
263 1 : AE_ERR_LOG(AE_MODULE_ID, "Get a NULL func addr, but status is success.");
264 1 : return AE_STATUS_INNER_ERROR;
265 2 : } else if (static_cast<bool>(unlikely(retGetApi != AE_STATUS_SUCCESS))) {
266 2 : AE_RW_LOCK_UN_LOCK(&rwLock_);
267 2 : AE_ERR_LOG(AE_MODULE_ID, "Get API or Func failed, ret[%d].", static_cast<int32_t>(retGetApi));
268 2 : return retGetApi;
269 : } else {
270 0 : AE_INFO_LOG(AE_MODULE_ID, "Get API or Func success.");
271 : }
272 : }
273 0 : theFuncAddr = funcAddr_;
274 0 : AE_RW_LOCK_UN_LOCK(&rwLock_);
275 : }
276 :
277 0 : const uint32_t tfRet = (reinterpret_cast<FwkTfOpFuncPtr>(theFuncAddr))(fwkKernelParam);
278 : // for tensorflow will should check the result.
279 0 : return static_cast<int32_t>(TransformKernelErrorCode(tfRet, fwkKernelParam));
280 : }
281 :
282 3 : aeStatus_t FWKKernelTfImpl::LoadTfSo()
283 : {
284 3 : AE_RW_LOCK_RD_LOCK(&rwLock_);
285 3 : if (soHandle_ != nullptr) {
286 0 : AE_RW_LOCK_UN_LOCK(&rwLock_);
287 0 : return AE_STATUS_SUCCESS;
288 : }
289 3 : AE_RW_LOCK_UN_LOCK(&rwLock_);
290 :
291 3 : AE_RW_LOCK_WR_LOCK(&rwLock_);
292 3 : if (soHandle_ != nullptr) {
293 0 : AE_RW_LOCK_UN_LOCK(&rwLock_);
294 0 : return AE_STATUS_SUCCESS;
295 : }
296 3 : aeStatus_t ret = SingleSoManager::OpenSo(tensorflowSoFile_, &soTensorflowHandle_);
297 3 : if (ret != AE_STATUS_SUCCESS) {
298 3 : AE_RUN_WARN_LOG(AE_MODULE_ID, "load tensorflow so failed, ret is[%d]", ret);
299 : }
300 3 : ret = SingleSoManager::OpenSo(soFile_, &soHandle_);
301 3 : if (ret != AE_STATUS_SUCCESS) {
302 3 : AE_RW_LOCK_UN_LOCK(&rwLock_);
303 3 : AE_RUN_WARN_LOG(AE_MODULE_ID, "LoadTfSo open so failed, soFile[%s], ret[%u].", soFile_.c_str(), ret);
304 3 : return ret;
305 : }
306 0 : AE_RW_LOCK_UN_LOCK(&rwLock_);
307 0 : return AE_STATUS_SUCCESS;
308 : }
309 :
310 3 : aeStatus_t FWKKernelTfImpl::TransformKernelErrorCode(const uint32_t errCode, const uint64_t fwkKernelParam)
311 : {
312 3 : if (errCode == 0U) {
313 1 : return AE_STATUS_SUCCESS;
314 : }
315 : // check tf end of sequence
316 2 : if (errCode == aicpu::FWKAdapter::FWK_ADPT_NATIVE_END_OF_SEQUENCE) {
317 1 : return AE_STATUS_END_OF_SEQUENCE;
318 : }
319 1 : uint32_t returnCode = errCode;
320 1 : if (errCode == aicpu::FWKAdapter::FWK_ADPT_NOT_SUPPORT_OPTYPE) {
321 0 : returnCode = AE_STATUS_BAD_PARAM;
322 : }
323 1 : AE_ERR_LOG(AE_MODULE_ID, "Call tf api return failed:%u, returncode:%u, input param to tf api:0x%lx",
324 : errCode, returnCode, fwkKernelParam);
325 : // other error code: transform to inner_error
326 1 : return static_cast<aeStatus_t>(returnCode);
327 : }
328 :
329 2 : const std::string &FWKKernelTfImpl::GetSoFile() const
330 : {
331 2 : return soFile_;
332 : }
333 :
334 6 : const std::string &FWKKernelTfImpl::GetKernelName() const
335 : {
336 6 : return kernelName_;
337 : }
338 : }
|