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_aicpu_kfc.h"
12 : #include <sstream>
13 : #include <string>
14 : #include <memory>
15 : #include <dlfcn.h>
16 : #include "securec.h"
17 : #include "aicpu_event_struct.h"
18 : #ifdef AICPU_PROFILING
19 : #include "aicpu_prof/profiling_adp.h"
20 : #endif
21 : namespace cce {
22 : AIKernelsLibAiCpuKFC *AIKernelsLibAiCpuKFC::instance_ = nullptr;
23 :
24 : // SINGLETON object get interface
25 9 : AIKernelsLibAiCpuKFC *AIKernelsLibAiCpuKFC::GetInstance()
26 : {
27 : static std::once_flag flag;
28 9 : std::call_once(flag, []() {
29 1 : instance_ = new(std::nothrow) AIKernelsLibAiCpuKFC();
30 1 : if ((instance_ != nullptr) && (instance_->Init() != AE_STATUS_SUCCESS)) {
31 0 : AE_RUN_WARN_LOG(AE_MODULE_ID, "AIKernelsLibAiCpuKFC init failed.");
32 0 : delete instance_;
33 0 : instance_ = nullptr;
34 : }
35 1 : AE_RUN_INFO_LOG(AE_MODULE_ID, "AIKernelsLibAiCpuKFC init finish.");
36 1 : });
37 9 : return instance_;
38 : }
39 :
40 1 : aeStatus_t AIKernelsLibAiCpuKFC::Init()
41 : {
42 1 : apiCacher_.clear();
43 1 : return AIKernelsLibBase::Init();
44 : }
45 :
46 : // SINGLETON object destroy interface
47 5 : void AIKernelsLibAiCpuKFC::DestroyInstance()
48 : {
49 5 : if (instance_ == nullptr) {
50 4 : return;
51 : }
52 1 : delete instance_;
53 1 : instance_ = nullptr;
54 : }
55 :
56 12 : aeStatus_t AIKernelsLibAiCpuKFC::GetKernelName(char_t *&kernelName, const aicpu::HwtsCceKernel *cceKernelBase) const
57 : {
58 12 : kernelName = PtrToPtr<void, char_t>(ValueToPtr(cceKernelBase->kernelName));
59 12 : if (static_cast<bool>(unlikely(kernelName == nullptr))) {
60 1 : AE_ERR_LOG(AE_MODULE_ID, "Input param kernelName is null.");
61 1 : return AE_STATUS_BAD_PARAM;
62 : }
63 11 : uint32_t len = strnlen(kernelName, AE_MAX_KERNEL_NAME + 1);
64 11 : if (static_cast<bool>(unlikely(len > AE_MAX_KERNEL_NAME))) {
65 1 : AE_ERR_LOG(AE_MODULE_ID, "KernelName length is not supported, len=%d.", len);
66 1 : kernelName = nullptr;
67 1 : return AE_STATUS_INNER_ERROR;
68 : }
69 10 : return AE_STATUS_SUCCESS;
70 : }
71 :
72 8 : int32_t AIKernelsLibAiCpuKFC::GetApiGlobal(AicpuKFCOpFuncPtr &opFuncPtr, const char_t *kernelName) const
73 : {
74 8 : opFuncPtr = PtrToFunctionPtr<void, AicpuKFCOpFuncPtr>(dlsym(RTLD_DEFAULT, kernelName));
75 8 : if (static_cast<bool>(unlikely(opFuncPtr == nullptr))) {
76 7 : AE_ERR_LOG(AE_MODULE_ID, "Get KFC api by global failed, func is nullptr, kernelName[%s], dlerror[%s]",
77 : kernelName, dlerror());
78 7 : return static_cast<int32_t>(AE_STATUS_INNER_ERROR);
79 : }
80 1 : return AE_STATUS_SUCCESS;
81 : }
82 :
83 7 : int32_t AIKernelsLibAiCpuKFC::GetApiWhenSonameNotEmpty(const aicpu::KernelType kernelType, const uint32_t soNameLen,
84 : const char_t *kernelSoName, const char_t *kernelName, void* &funcAddr)
85 : {
86 7 : if (static_cast<bool>(unlikely(soNameLen > AE_MAX_SO_NAME))) {
87 2 : AE_RUN_WARN_LOG(AE_MODULE_ID, "kernelSoName length is not supported, len=%d.", soNameLen);
88 2 : return static_cast<int32_t>(AE_STATUS_INNER_ERROR);
89 : }
90 :
91 5 : const auto ret = soMngr_.GetApi(kernelType, kernelSoName, kernelName, &funcAddr);
92 5 : if (static_cast<bool>(unlikely(ret != AE_STATUS_SUCCESS))) {
93 3 : AE_RUN_WARN_LOG(AE_MODULE_ID, "Get %s api from %s unsuccessfully.", kernelName, kernelSoName);
94 3 : return static_cast<int32_t>(AE_STATUS_INNER_ERROR);
95 : }
96 :
97 2 : if (static_cast<bool>(unlikely(funcAddr == nullptr))) {
98 1 : AE_RUN_WARN_LOG(AE_MODULE_ID, "Get %s api from %s success, but func is nullptr",
99 : kernelName, kernelSoName);
100 1 : return static_cast<int32_t>(AE_STATUS_INNER_ERROR);
101 : }
102 :
103 1 : return AE_STATUS_SUCCESS;
104 : }
105 :
106 9 : int32_t AIKernelsLibAiCpuKFC::GetApiBySoname(const aicpu::KernelType kernelType, const char_t *kernelSoName,
107 : AicpuKFCOpFuncPtr &opFuncPtr, const char_t *kernelName)
108 : {
109 9 : const uint32_t soNameLen = strnlen(kernelSoName, AE_MAX_SO_NAME + 1);
110 9 : if (soNameLen == 0) {
111 2 : if (GetApiGlobal(opFuncPtr, kernelName) != AE_STATUS_SUCCESS) {
112 1 : AE_ERR_LOG(AE_MODULE_ID, "Get KFC api by global failed, kernelSoName[%s], soNameLen[%u], kernelName[%s].",
113 : kernelSoName, soNameLen, kernelName);
114 1 : return static_cast<int32_t>(AE_STATUS_INNER_ERROR);
115 : }
116 : } else {
117 7 : void *funcAddr = nullptr;
118 7 : if (GetApiWhenSonameNotEmpty(kernelType, soNameLen, kernelSoName, kernelName, funcAddr) == AE_STATUS_SUCCESS) {
119 1 : opFuncPtr = PtrToFunctionPtr<void, AicpuKFCOpFuncPtr>(funcAddr);
120 : } else {
121 6 : if (GetApiGlobal(opFuncPtr, kernelName) != AE_STATUS_SUCCESS) {
122 6 : AE_ERR_LOG(AE_MODULE_ID,
123 : "Get KFC api by soname and global both failed, kernelSoName[%s], soNameLen[%u], kernelName[%s].",
124 : kernelSoName, soNameLen, kernelName);
125 6 : return static_cast<int32_t>(AE_STATUS_INNER_ERROR);
126 : }
127 : }
128 : }
129 :
130 2 : return AE_STATUS_SUCCESS;
131 : }
132 :
133 :
134 : // Implement call a aicpu op kernel interface
135 12 : int32_t AIKernelsLibAiCpuKFC::CallKernelApi(const aicpu::KernelType kernelType, const void * const kernelBase)
136 : {
137 : (void)kernelType;
138 12 : const aicpu::HwtsCceKernel *cceKernelBase = static_cast<const aicpu::HwtsCceKernel *>(kernelBase);
139 12 : if (static_cast<bool>(unlikely(cceKernelBase == nullptr))) {
140 1 : AE_ERR_LOG(AE_MODULE_ID, "Input param KFC kernelBase is nullptr.");
141 1 : return static_cast<int32_t>(AE_STATUS_BAD_PARAM);
142 : }
143 :
144 11 : char_t *kernelName = nullptr;
145 11 : aeStatus_t ret = GetKernelName(kernelName, cceKernelBase);
146 11 : if (static_cast<bool>(unlikely((ret != AE_STATUS_SUCCESS)))) {
147 1 : AE_ERR_LOG(AE_MODULE_ID, "get KFC kernelName failed, ret=%u.", ret);
148 1 : return static_cast<int32_t>(ret);
149 : }
150 10 : AicpuKFCOpFuncPtr opFuncPtr = nullptr;
151 10 : AE_RW_LOCK_RD_LOCK(&rwLock_);
152 20 : auto apiIter = apiCacher_.find(kernelName);
153 10 : if (apiIter != apiCacher_.end()) {
154 1 : opFuncPtr = apiIter->second;
155 : } else {
156 9 : AE_RW_LOCK_UN_LOCK(&rwLock_);
157 9 : AE_RW_LOCK_WR_LOCK(&rwLock_);
158 18 : apiIter = apiCacher_.find(kernelName);
159 9 : if (apiIter != apiCacher_.end()) {
160 0 : opFuncPtr = apiIter->second;
161 : } else {
162 9 : char_t *kernelSoName = PtrToPtr<void, char_t>(ValueToPtr(cceKernelBase->kernelSo));
163 9 : if (GetApiBySoname(kernelType, kernelSoName, opFuncPtr, kernelName) != AE_STATUS_SUCCESS) {
164 7 : AE_RW_LOCK_UN_LOCK(&rwLock_);
165 7 : AE_ERR_LOG(AE_MODULE_ID, "Get KFC kernel api failed, kernelSoName[%s], kernelName[%s].",
166 : kernelSoName, kernelName);
167 7 : return static_cast<int32_t>(AE_STATUS_INNER_ERROR);
168 : }
169 6 : apiCacher_[kernelName] = opFuncPtr;
170 : }
171 : }
172 :
173 3 : AE_RW_LOCK_UN_LOCK(&rwLock_);
174 3 : AE_INFO_LOG(AE_MODULE_ID, "Get KFC kernelname[%s] func success", kernelName);
175 3 : const uint32_t result = RunAicpuFunc(kernelBase, opFuncPtr);
176 3 : return static_cast<int32_t>(TransformKernelErrorCode(result, kernelName));
177 : }
178 :
179 4 : uint32_t AIKernelsLibAiCpuKFC::RunAicpuFunc(const void* const kernelBase,
180 : AicpuKFCOpFuncPtr &opFuncPtr) const
181 : {
182 4 : const auto cceKernelBase = static_cast<const aicpu::HwtsCceKernel *>(kernelBase);
183 4 : void * const param = ValueToPtr(static_cast<const uintptr_t>(cceKernelBase->paramBase));
184 4 : uint32_t result = 0U;
185 4 : if (&aicpu::SetBlockIdxAndBlockNum != nullptr) {
186 0 : (void)aicpu::SetBlockIdxAndBlockNum(cceKernelBase->blockId, cceKernelBase->blockNum);
187 : }
188 : #ifdef AICPU_PROFILING
189 : uint64_t runStartTick;
190 : uint64_t runStartTime;
191 : const std::shared_ptr<aicpu::ProfMessage> profHandle = aicpu::GetProfHandle();
192 : if (static_cast<bool>(unlikely(profHandle != nullptr))) {
193 : aicpu::GetMicrosAndSysTick(runStartTime, runStartTick);
194 : }
195 : #endif
196 4 : result = opFuncPtr(param);
197 : #ifdef AICPU_PROFILING
198 : if (static_cast<bool>(unlikely(profHandle != nullptr))) {
199 : uint64_t runEndTick;
200 : uint64_t runEndTime;
201 : aicpu::GetMicrosAndSysTick(runEndTime, runEndTick);
202 : (void)profHandle->SetRunStartTime(runStartTime)
203 : ->SetRunStartTick(runStartTick)
204 : ->SetRunEndTime(runEndTime)
205 : ->SetRunEndTick(runEndTick);
206 : }
207 : #endif
208 4 : return result;
209 : }
210 :
211 6 : int32_t AIKernelsLibAiCpuKFC::TransformKernelErrorCode(const uint32_t errCode,
212 : const char_t * const kernelName) const
213 : {
214 6 : if (likely(errCode == 0U)) {
215 2 : return AE_STATUS_SUCCESS;
216 : }
217 :
218 4 : if (errCode == static_cast<uint32_t>(AicpuOpErrorCode::AICPU_TASK_ABORT)) {
219 1 : AE_INFO_LOG(AE_MODULE_ID, "Get kfc task abort flag");
220 1 : return AE_STATUS_TASK_ABORT;
221 : }
222 :
223 3 : if ((errCode >= static_cast<uint32_t>(AicpuOpErrorCode::AICPU_KFC_PASSTHROUGH_START)) &&
224 : (errCode <= static_cast<uint32_t>(AicpuOpErrorCode::AICPU_KFC_PASSTHROUGH_END))) {
225 1 : AE_INFO_LOG(AE_MODULE_ID, "KFC %s run passthrough ret[%u]", kernelName, errCode);
226 1 : return static_cast<int32_t>(errCode);
227 : }
228 :
229 2 : AE_ERR_LOG(AE_MODULE_ID, "KFC %s run failed ret[%u]", kernelName, errCode);
230 2 : return AE_STATUS_TASK_FAIL;
231 : }
232 : }
|