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 : } // namespace
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() { return tfImpl_.Init(); }
61 :
62 1 : aeStatus_t AIKernelsLibFWK::CloseSo(const char_t* const soName)
63 : {
64 : (void)soName;
65 1 : return AE_STATUS_SUCCESS;
66 : }
67 :
68 4 : int32_t AIKernelsLibFWK::CallKernelApi(const aicpu::KernelType kernelType, const void* const kernelBase)
69 : {
70 4 : const auto fwkKernel = reinterpret_cast<const aicpu::HwtsFwkKernel* const>(kernelBase);
71 4 : if (static_cast<bool>(unlikely(fwkKernel == nullptr))) {
72 1 : AE_ERR_LOG(AE_MODULE_ID, "Input param fwkKernelBase is NULL.");
73 1 : return AE_STATUS_BAD_PARAM;
74 : }
75 :
76 3 : const auto fwkOpKernelPtr = static_cast<const uintptr_t>(fwkKernel->kernel);
77 3 : const auto fwkOpKernel = reinterpret_cast<const STR_FWK_OP_KERNEL* const>(fwkOpKernelPtr);
78 3 : if (static_cast<bool>(unlikely(fwkOpKernel == nullptr))) {
79 0 : AE_ERR_LOG(AE_MODULE_ID, "Input param fwkOpKernel is NULL.");
80 0 : return AE_STATUS_BAD_PARAM;
81 : }
82 3 : AE_INFO_LOG(
83 : AE_MODULE_ID, "Current kernelType:%d, FWK op kernel kernel type:%d.", kernelType, fwkOpKernel->fwkKernelType);
84 :
85 : // Call different Implement method switch by kernel type.
86 3 : int32_t ret = AE_STATUS_SUCCESS;
87 3 : switch (static_cast<FwkkernelType_t>(fwkOpKernel->fwkKernelType)) {
88 3 : case FMK_KERNEL_TYPE_TF:
89 3 : ret = tfImpl_.CallKernelApi(PtrToValue(PtrToPtr<const ::aicpu::FWKAdapter::FWKOperateParam, const void>(
90 : &fwkOpKernel->fwkKernelBase.fwk_kernel)));
91 3 : break;
92 0 : default:
93 0 : AE_ERR_LOG(
94 : AE_MODULE_ID, "Input param fwkKernelType in STR_FWK_OP_KERNEL is invalid :%d",
95 : fwkOpKernel->fwkKernelType);
96 0 : ret = AE_STATUS_BAD_PARAM;
97 0 : break;
98 : }
99 3 : return ret;
100 : }
101 :
102 3 : aeStatus_t AIKernelsLibFWK::BatchLoadKernelSo(const aicpu::KernelType kernelType, std::vector<std::string>& soVec)
103 : {
104 3 : AE_INFO_LOG(AE_MODULE_ID, "Begin to batch load kernel so, kerelType:[%d].", kernelType);
105 3 : if (soVec.empty()) {
106 0 : return AE_STATUS_SUCCESS;
107 : }
108 : // only one tf so
109 3 : return tfImpl_.LoadTfSo();
110 : }
111 :
112 : // need refresh soFile_
113 12 : FWKKernelTfImpl::FWKKernelTfImpl()
114 24 : : kernelName_("TFOperateAPI"), funcAddr_(nullptr), soHandle_(nullptr), soTensorflowHandle_(nullptr)
115 12 : {}
116 :
117 4 : aeStatus_t FWKKernelTfImpl::Init()
118 : {
119 4 : std::string baseSoFile(AICPU_SO_ROOT_PATH);
120 4 : (void)baseSoFile.append(TF_SO_NAME);
121 4 : soFile_ = baseSoFile;
122 : aicpu::aicpuContext_t currentAicpuCtx;
123 4 : const aicpu::status_t status = aicpu::aicpuGetContext(¤tAicpuCtx);
124 4 : if (status == aicpu::AICPU_ERROR_NONE) {
125 4 : std::string soPath(AICPU_SO_ROOT_PATH);
126 8 : (void)soPath.append(std::to_string(aicpu::GetUniqueVfId()))
127 4 : .append("/")
128 4 : .append(AICPU_SO_UNCOMPRESS_PATH)
129 4 : .append("/");
130 4 : soFile_ = soPath + TF_SO_NAME;
131 4 : GetThreadModelSoPath(soPath);
132 : // check so file
133 4 : const aeStatus_t ret = SingleSoManager::CheckSoFile(soPath, soFile_);
134 4 : if (ret != AE_STATUS_SUCCESS) {
135 4 : soFile_ = baseSoFile;
136 4 : AE_RUN_INFO_LOG(
137 : AE_MODULE_ID, "So does not exist in path %s, use default soFile %s.", soPath.c_str(),
138 : baseSoFile.c_str());
139 : }
140 4 : }
141 4 : AE_INFO_LOG(AE_MODULE_ID, "FWKernelTfImpl init success, soFile_=%s.", soFile_.c_str());
142 4 : return AE_STATUS_SUCCESS;
143 4 : }
144 :
145 12 : FWKKernelTfImpl::~FWKKernelTfImpl()
146 : {
147 12 : AE_RW_LOCK_WR_LOCK(&rwLock_);
148 12 : funcAddr_ = nullptr;
149 12 : aeStatus_t ret = SingleSoManager::CloseSo(soHandle_);
150 12 : if (ret != AE_STATUS_SUCCESS) {
151 0 : AE_RUN_WARN_LOG(AE_MODULE_ID, "~FWKKernelTfImpl CloseSo failed, ret is[%d]", ret);
152 : }
153 12 : ret = SingleSoManager::CloseSo(soTensorflowHandle_);
154 12 : if (ret != AE_STATUS_SUCCESS) {
155 0 : AE_RUN_WARN_LOG(AE_MODULE_ID, "~FWKKernelTensorflowImpl CloseSo failed, ret is[%d]", ret);
156 : }
157 12 : soHandle_ = nullptr;
158 12 : soTensorflowHandle_ = nullptr;
159 12 : AE_RW_LOCK_UN_LOCK(&rwLock_);
160 12 : AE_RW_LOCK_DESTROY(&rwLock_);
161 12 : }
162 :
163 8 : void FWKKernelTfImpl::GetTfKernelThreadModeSoPath(std::string& soPath) const
164 : {
165 8 : (void)soPath.append(THREAD_MODE_SO_PATH_FIX)
166 8 : .append("/")
167 16 : .append(std::to_string(aicpu::GetUniqueVfId()))
168 8 : .append("/")
169 8 : .append(AICPU_SO_UNCOMPRESS_PATH)
170 8 : .append("/");
171 8 : return;
172 : }
173 :
174 0 : void FWKKernelTfImpl::GetTensorflowThreadModeSoPath(std::string soPath)
175 : {
176 0 : (void)soPath.append(THREAD_MODE_SO_PATH_FIX)
177 0 : .append("/")
178 0 : .append(std::to_string(aicpu::GetUniqueVfId()))
179 0 : .append("/")
180 0 : .append(AICPU_SO_UNCOMPRESS_PATH)
181 0 : .append("/")
182 0 : .append(TENSORFLOW_SO_UNCOMPRESS_PAHT)
183 0 : .append("/");
184 0 : tensorflowSoFile_ = soPath + TENSORFLOW_SO_NAME;
185 0 : return;
186 : }
187 :
188 9 : aeStatus_t FWKKernelTfImpl::GetTfThreadModeSoPath(std::string& soPath)
189 : {
190 9 : const char_t* const innerDirName = getenv("HOME");
191 9 : if (innerDirName != nullptr) {
192 8 : const std::string str = innerDirName;
193 8 : const size_t len = str.length();
194 8 : if ((len == 0U) || (len >= static_cast<size_t>(MAX_SO_PATH))) {
195 0 : AE_ERR_LOG(AE_MODULE_ID, "Length[%zu] of inner so dir is invalid.", len);
196 0 : return AE_STATUS_INNER_ERROR;
197 : }
198 8 : soPath = str;
199 8 : if (soPath[soPath.size() - 1UL] != '/') {
200 8 : (void)soPath.append("/");
201 : }
202 8 : GetTensorflowThreadModeSoPath(soPath);
203 8 : GetTfKernelThreadModeSoPath(soPath);
204 8 : return AE_STATUS_SUCCESS;
205 8 : } else {
206 1 : AE_RUN_WARN_LOG(AE_MODULE_ID, "Get HOME env failed, get tf thread mode so path failed.");
207 1 : return AE_STATUS_INNER_ERROR;
208 : }
209 : }
210 :
211 7 : void FWKKernelTfImpl::GetThreadModelSoPath(std::string& soPath)
212 : {
213 : uint32_t runMode;
214 7 : aicpu::status_t status = aicpu::GetAicpuRunMode(runMode);
215 7 : if (status != aicpu::AICPU_ERROR_NONE) {
216 1 : AE_ERR_LOG(AE_MODULE_ID, "Get current aicpu ctx failed.");
217 2 : return;
218 : }
219 6 : if (runMode != aicpu::AicpuRunMode::THREAD_MODE) {
220 0 : return;
221 : }
222 6 : std::string threadSoPath;
223 6 : if (GetTfThreadModeSoPath(threadSoPath) != AE_STATUS_SUCCESS) {
224 1 : AE_WARN_LOG(AE_MODULE_ID, "GetThreadModeSoPath failed.");
225 1 : return;
226 : }
227 5 : soPath = threadSoPath;
228 5 : soFile_ = threadSoPath + TF_SO_NAME;
229 6 : }
230 :
231 3 : int32_t FWKKernelTfImpl::CallKernelApi(const uint64_t fwkKernelParam)
232 : {
233 3 : void* theFuncAddr = nullptr;
234 3 : AE_RW_LOCK_RD_LOCK(&rwLock_);
235 3 : if (static_cast<bool>(unlikely(funcAddr_ != nullptr))) {
236 0 : theFuncAddr = funcAddr_;
237 : }
238 3 : AE_RW_LOCK_UN_LOCK(&rwLock_);
239 :
240 3 : if (static_cast<bool>(unlikely(theFuncAddr == nullptr))) {
241 3 : AE_RW_LOCK_WR_LOCK(&rwLock_);
242 3 : if (static_cast<bool>(unlikely(funcAddr_ == nullptr))) {
243 3 : AE_INFO_LOG(
244 : AE_MODULE_ID, "Begin to GetApi, soFile=%s, kernelName=%s.", GetSoFile().c_str(),
245 : GetKernelName().c_str());
246 :
247 3 : aeStatus_t retGetApi = AE_STATUS_SUCCESS;
248 3 : if (static_cast<bool>(unlikely(soHandle_ == nullptr))) {
249 3 : retGetApi = SingleSoManager::GetApi(GetSoFile().data(), GetKernelName().data(), &funcAddr_, &soHandle_);
250 : } else {
251 0 : retGetApi = SingleSoManager::GetFunc(soHandle_, GetKernelName().data(), &funcAddr_);
252 : }
253 3 : AE_INFO_LOG(AE_MODULE_ID, "End to GetApi, retGetApi=%d.", retGetApi);
254 :
255 3 : if (static_cast<bool>(unlikely((retGetApi == AE_STATUS_SUCCESS) && (funcAddr_ == nullptr)))) {
256 1 : AE_RW_LOCK_UN_LOCK(&rwLock_);
257 1 : AE_ERR_LOG(AE_MODULE_ID, "Get a NULL func addr, but status is success.");
258 1 : return AE_STATUS_INNER_ERROR;
259 2 : } else if (static_cast<bool>(unlikely(retGetApi != AE_STATUS_SUCCESS))) {
260 2 : AE_RW_LOCK_UN_LOCK(&rwLock_);
261 2 : AE_ERR_LOG(AE_MODULE_ID, "Get API or Func failed, ret[%d].", static_cast<int32_t>(retGetApi));
262 2 : return retGetApi;
263 : } else {
264 0 : AE_INFO_LOG(AE_MODULE_ID, "Get API or Func success.");
265 : }
266 : }
267 0 : theFuncAddr = funcAddr_;
268 0 : AE_RW_LOCK_UN_LOCK(&rwLock_);
269 : }
270 :
271 0 : const uint32_t tfRet = (reinterpret_cast<FwkTfOpFuncPtr>(theFuncAddr))(fwkKernelParam);
272 : // for tensorflow will should check the result.
273 0 : return static_cast<int32_t>(TransformKernelErrorCode(tfRet, fwkKernelParam));
274 : }
275 :
276 3 : aeStatus_t FWKKernelTfImpl::LoadTfSo()
277 : {
278 3 : AE_RW_LOCK_RD_LOCK(&rwLock_);
279 3 : if (soHandle_ != nullptr) {
280 0 : AE_RW_LOCK_UN_LOCK(&rwLock_);
281 0 : return AE_STATUS_SUCCESS;
282 : }
283 3 : AE_RW_LOCK_UN_LOCK(&rwLock_);
284 :
285 3 : AE_RW_LOCK_WR_LOCK(&rwLock_);
286 3 : if (soHandle_ != nullptr) {
287 0 : AE_RW_LOCK_UN_LOCK(&rwLock_);
288 0 : return AE_STATUS_SUCCESS;
289 : }
290 3 : aeStatus_t ret = SingleSoManager::OpenSo(tensorflowSoFile_, &soTensorflowHandle_);
291 3 : if (ret != AE_STATUS_SUCCESS) {
292 3 : AE_RUN_WARN_LOG(AE_MODULE_ID, "load tensorflow so failed, ret is[%d]", ret);
293 : }
294 3 : ret = SingleSoManager::OpenSo(soFile_, &soHandle_);
295 3 : if (ret != AE_STATUS_SUCCESS) {
296 3 : AE_RW_LOCK_UN_LOCK(&rwLock_);
297 3 : AE_RUN_WARN_LOG(AE_MODULE_ID, "LoadTfSo open so failed, soFile[%s], ret[%u].", soFile_.c_str(), ret);
298 3 : return ret;
299 : }
300 0 : AE_RW_LOCK_UN_LOCK(&rwLock_);
301 0 : return AE_STATUS_SUCCESS;
302 : }
303 :
304 3 : aeStatus_t FWKKernelTfImpl::TransformKernelErrorCode(const uint32_t errCode, const uint64_t fwkKernelParam)
305 : {
306 3 : if (errCode == 0U) {
307 1 : return AE_STATUS_SUCCESS;
308 : }
309 : // check tf end of sequence
310 2 : if (errCode == aicpu::FWKAdapter::FWK_ADPT_NATIVE_END_OF_SEQUENCE) {
311 1 : return AE_STATUS_END_OF_SEQUENCE;
312 : }
313 1 : uint32_t returnCode = errCode;
314 1 : if (errCode == aicpu::FWKAdapter::FWK_ADPT_NOT_SUPPORT_OPTYPE) {
315 0 : returnCode = AE_STATUS_BAD_PARAM;
316 : }
317 1 : AE_ERR_LOG(
318 : AE_MODULE_ID, "Call tf api return failed:%u, returncode:%u, input param to tf api:0x%lx", errCode, returnCode,
319 : fwkKernelParam);
320 : // other error code: transform to inner_error
321 1 : return static_cast<aeStatus_t>(returnCode);
322 : }
323 :
324 2 : const std::string& FWKKernelTfImpl::GetSoFile() const { return soFile_; }
325 :
326 6 : const std::string& FWKKernelTfImpl::GetKernelName() const { return kernelName_; }
327 : } // namespace cce
|