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.hpp"
12 : #include <sstream>
13 : #include <string>
14 : #include <memory>
15 : #include "securec.h"
16 : #include "aicpu_event_struct.h"
17 : #ifdef AICPU_PROFILING
18 : #include "aicpu_prof/profiling_adp.h"
19 : #endif
20 :
21 : namespace cce {
22 : namespace {
23 : // aicpu device side blockdim entry function name
24 : constexpr char const *kRunFuncName = "RunCpuKernelWithBlock";
25 : // 动态白名单
26 : constexpr size_t MAX_WHITE_LIST_SIZE = 100UL;
27 : // The interface to call a aicpu kernel api
28 : using AicpuOpFuncPtr = uint32_t(*)(void *);
29 : // The interface to call a aicpu kernel api with blockdim
30 : using AicpuOpFuncPtrWithBlockDim = uint32_t(*)(void *, void *);
31 :
32 : struct BlkDimInfo {
33 : uint32_t blockNum; // blockdim number
34 : uint32_t blockId; // block id
35 : };
36 : }
37 :
38 : AIKernelsLibAiCpu *AIKernelsLibAiCpu::instance_ = nullptr;
39 : std::mutex AIKernelsLibAiCpu::mtx_;
40 :
41 : // SINGLETON object get interface
42 136 : AIKernelsLibAiCpu *AIKernelsLibAiCpu::GetInstance()
43 : {
44 136 : const std::lock_guard<std::mutex> lockGuard(mtx_);
45 136 : if (instance_ != nullptr) {
46 129 : return instance_;
47 : } else {
48 7 : instance_ = new(std::nothrow) AIKernelsLibAiCpu();
49 7 : if (instance_ == nullptr) {
50 0 : return nullptr;
51 : }
52 7 : if (instance_->Init() != AE_STATUS_SUCCESS) {
53 2 : AE_RUN_WARN_LOG(AE_MODULE_ID, "AIKernelsLibAiCpu init failed.");
54 2 : delete instance_;
55 2 : instance_ = nullptr;
56 2 : return nullptr;
57 : }
58 5 : return instance_;
59 : }
60 136 : }
61 :
62 : // SINGLETON object destroy interface
63 9 : void AIKernelsLibAiCpu::DestroyInstance()
64 : {
65 9 : const std::lock_guard<std::mutex> lockGuard(mtx_);
66 9 : if (instance_ == nullptr) {
67 5 : return;
68 : }
69 4 : delete instance_;
70 4 : instance_ = nullptr;
71 9 : }
72 :
73 121 : aeStatus_t AIKernelsLibAiCpu::GetKernelNameAndKernelSoName(char_t *kernelName, char_t *kernelSoName,
74 : const char_t *paramKernelSo,
75 : const aicpu::HwtsCceKernel *cceKernelBase) const
76 : {
77 121 : const auto paramKernelName = PtrToPtr<const void, const char_t>(ValueToPtr(cceKernelBase->kernelName));
78 : // A nullptr kernel op name is not supported.
79 121 : if (paramKernelName == nullptr) {
80 0 : AE_ERR_LOG(AE_MODULE_ID, "Input param kernelName is null.");
81 0 : return AE_STATUS_BAD_PARAM;
82 : }
83 121 : errno_t retCpy = strncpy_s(&kernelName[0], AE_MAX_KERNEL_NAME + 1U, paramKernelName, AE_MAX_KERNEL_NAME);
84 121 : if (retCpy != EOK) {
85 0 : AE_ERR_LOG(AE_MODULE_ID, "copy paramKernelName failed, retCpy=%d.", retCpy);
86 0 : return AE_STATUS_INNER_ERROR;
87 : }
88 :
89 121 : retCpy = strncpy_s(&kernelSoName[0], AE_MAX_SO_NAME + 1U, paramKernelSo, AE_MAX_SO_NAME);
90 121 : if (retCpy != EOK) {
91 0 : AE_ERR_LOG(AE_MODULE_ID, "copy paramKernelSo failed, retCpy=%d.", retCpy);
92 0 : return AE_STATUS_INNER_ERROR;
93 : }
94 121 : return AE_STATUS_SUCCESS;
95 : }
96 :
97 : // Implement call a aicpu op kernel interface
98 121 : int32_t AIKernelsLibAiCpu::CallKernelApi(const aicpu::KernelType kernelType, const void * const kernelBase)
99 : {
100 121 : const aicpu::HwtsCceKernel *cceKernelBase = static_cast<const aicpu::HwtsCceKernel *>(kernelBase);
101 121 : if (cceKernelBase == nullptr) {
102 0 : AE_ERR_LOG(AE_MODULE_ID, "Input param kernelBase is nullptr.");
103 0 : return AE_STATUS_BAD_PARAM;
104 : }
105 :
106 121 : char_t *paramKernelSo = PtrToPtr<void, char_t>(ValueToPtr(cceKernelBase->kernelSo));
107 : // Finding a cce op kernel from the whole process space is not supported.
108 : // Only get aicpu op kernel a specific so lib.so, kernelSo should not be NULL.
109 121 : if (paramKernelSo == nullptr) {
110 0 : AE_ERR_LOG(AE_MODULE_ID, "Input param kernelSo is NULL.");
111 0 : return AE_STATUS_BAD_PARAM;
112 : }
113 121 : char_t kernelName[AE_MAX_KERNEL_NAME + 1U] = {};
114 121 : char_t kernelSoName[AE_MAX_SO_NAME + 1U] = {};
115 121 : aeStatus_t ret = AE_STATUS_SUCCESS;
116 121 : ret = GetKernelNameAndKernelSoName(kernelName, kernelSoName, paramKernelSo, cceKernelBase);
117 121 : if (ret != AE_STATUS_SUCCESS) {
118 0 : AE_ERR_LOG(AE_MODULE_ID, "get kernelName and kernelSoName failed, ret=%u.", ret);
119 0 : return ret;
120 : }
121 121 : void *funcAddr = nullptr;
122 121 : ret = soMngr_.GetApi(kernelType, &kernelSoName[0], &kernelName[0], &funcAddr);
123 121 : if (ret != AE_STATUS_SUCCESS) {
124 0 : AE_ERR_LOG(AE_MODULE_ID, "Get %s api from %s failed.", &kernelName[0], &kernelSoName[0]);
125 0 : return ret;
126 : }
127 121 : if (funcAddr == nullptr) {
128 0 : AE_ERR_LOG(AE_MODULE_ID, "Get %s api from %s success, but func is nullptr",
129 : &kernelName[0], &kernelSoName[0]);
130 0 : return AE_STATUS_INNER_ERROR;
131 : }
132 :
133 121 : (void)aicpu::SetOpname(kernelName);
134 :
135 120 : const uint32_t result = RunAicpuFunc(kernelBase, funcAddr, &kernelName[0]);
136 119 : return static_cast<int32_t>(TransformKernelErrorCode(result, &kernelName[0], &kernelSoName[0]));
137 : }
138 :
139 120 : uint32_t AIKernelsLibAiCpu::RunAicpuFunc(const void* const kernelBase,
140 : void* const funcAddr,
141 : const char_t* const funcName) const
142 : {
143 120 : uint32_t result = 0U;
144 120 : const auto cceKernelBase = static_cast<const aicpu::HwtsCceKernel *>(kernelBase);
145 120 : void * const param = ValueToPtr(cceKernelBase->paramBase);
146 : #ifdef AICPU_PROFILING
147 : uint64_t runStartTime;
148 : uint64_t runStartTick;
149 : aicpu::GetMicrosAndSysTick(runStartTime, runStartTick);
150 : #endif
151 120 : (void)aicpu::SetBlockIdxAndBlockNum(cceKernelBase->blockId, cceKernelBase->blockNum);
152 120 : if (strcmp(funcName, kRunFuncName) == 0) {
153 0 : AE_INFO_LOG(AE_MODULE_ID, "opFuncPtr is RunCpuKernelWithBlockDim.");
154 0 : struct BlkDimInfo blkInfo = {};
155 0 : blkInfo.blockId = cceKernelBase->blockId;
156 0 : blkInfo.blockNum = cceKernelBase->blockNum;
157 0 : const auto opFuncPtr = PtrToFunctionPtr<void, AicpuOpFuncPtrWithBlockDim>(funcAddr);
158 0 : result = opFuncPtr(param, &blkInfo);
159 : } else {
160 120 : const auto opFuncPtr = PtrToFunctionPtr<void, AicpuOpFuncPtr>(funcAddr);
161 120 : result = opFuncPtr(param);
162 : }
163 :
164 : #ifdef AICPU_PROFILING
165 : uint64_t runEndTime;
166 : uint64_t runEndTick;
167 : aicpu::GetMicrosAndSysTick(runEndTime, runEndTick);
168 :
169 : const std::shared_ptr<aicpu::ProfMessage> profHandle = aicpu::GetProfHandle();
170 : if (profHandle != nullptr) {
171 : std::string opName = "null";
172 : (void)aicpu::GetOpname(aicpu::GetAicpuThreadIndex(), opName);
173 : (void)profHandle->SetRunStartTime(runStartTime)->SetRunStartTick(runStartTick)
174 : ->SetRunEndTime(runEndTime)->SetRunEndTick(runEndTick);
175 : }
176 : #endif
177 120 : return result;
178 : }
179 :
180 6 : aeStatus_t AIKernelsLibAiCpu::BatchLoadKernelSo(const aicpu::KernelType kernelType,
181 : std::vector<std::string> &soVec)
182 : {
183 6 : if (soVec.empty()) {
184 1 : AE_ERR_LOG(AE_MODULE_ID, "so vec is empty.");
185 1 : return AE_STATUS_SUCCESS;
186 : }
187 12 : for (auto &soName : soVec) {
188 7 : const aeStatus_t ret = soMngr_.LoadSo(kernelType, soName);
189 7 : if (ret != AE_STATUS_SUCCESS) {
190 5 : AE_RUN_WARN_LOG(AE_MODULE_ID, "Load so %s failed.", soName.c_str());
191 5 : continue;
192 : }
193 : }
194 5 : return AE_STATUS_SUCCESS;
195 : }
196 :
197 2 : aeStatus_t AIKernelsLibAiCpu::CloseSo(const char_t * const soName)
198 : {
199 2 : if (soName == nullptr) {
200 1 : AE_ERR_LOG(AE_MODULE_ID, "soName is null.");
201 1 : return AE_STATUS_BAD_PARAM;
202 : }
203 1 : const std::string kernelSoName(soName);
204 1 : return soMngr_.CloseSo(kernelSoName);
205 1 : }
206 :
207 120 : aeStatus_t AIKernelsLibAiCpu::TransformKernelErrorCode(const uint32_t errCode,
208 : const char_t * const kernelName,
209 : const char_t * const soName) const
210 : {
211 120 : if (likely(errCode == 0U)) {
212 110 : return AE_STATUS_SUCCESS;
213 : }
214 :
215 10 : if (errCode == static_cast<uint32_t>(AicpuOpErrorCode::AICPU_END_OF_SEQUENCE_FLAG)) {
216 0 : AE_INFO_LOG(AE_MODULE_ID, "Get aicpu end of sequence flag.");
217 0 : return AE_STATUS_END_OF_SEQUENCE;
218 : }
219 10 : if (errCode == static_cast<uint32_t>(AicpuOpErrorCode::AICPU_TASK_WATI_FLAG)) {
220 0 : AE_INFO_LOG(AE_MODULE_ID, "Get aicpu task wait flag.");
221 0 : return AE_STATUS_TASK_WAIT;
222 : }
223 :
224 10 : if (!aicpu::IsCustAicpuSd()) {
225 10 : if (errCode == static_cast<uint32_t>(AicpuOpErrorCode::AICPU_SILENT_FAULT)) {
226 0 : AE_INFO_LOG(AE_MODULE_ID, "Get aicpu silent fault flag");
227 0 : return AE_STATUS_SILENT_FAULT;
228 : }
229 10 : if (errCode == static_cast<uint32_t>(AicpuOpErrorCode::AICPU_DETECT_FAULT)) {
230 0 : AE_INFO_LOG(AE_MODULE_ID, "Get aicpu detect fault flag");
231 0 : return AE_STATUS_DETECT_FAULT;
232 : }
233 :
234 10 : if (errCode == static_cast<uint32_t>(AicpuOpErrorCode::AICPU_DETECT_FAULT_NORAS)) {
235 0 : AE_INFO_LOG(AE_MODULE_ID, "Get aicpu detect fault no Ras flag");
236 0 : return AE_STATUS_DETECT_FAULT_NORAS;
237 : }
238 :
239 10 : if (errCode == static_cast<uint32_t>(AicpuOpErrorCode::AICPU_DETECT_LOW_BIT_FAULT)) {
240 0 : AE_INFO_LOG(AE_MODULE_ID, "Get aicpu detect low-bit fault flag");
241 0 : return AE_STATUS_DETECT_LOW_BIT_FAULT;
242 : }
243 :
244 10 : if (errCode == static_cast<uint32_t>(AicpuOpErrorCode::AICPU_DETECT_LOW_BIT_FAULT_NORAS)) {
245 0 : AE_INFO_LOG(AE_MODULE_ID, "Get aicpu detect low-bit fault no Ras flag");
246 0 : return AE_STATUS_DETECT_LOW_BIT_FAULT_NORAS;
247 : }
248 : }
249 :
250 10 : AE_ERR_LOG(AE_MODULE_ID, "call aicpu api %s in %s failed, ret:%u.", kernelName, soName, errCode);
251 : // other error code: transform to inner_error
252 10 : return static_cast<aeStatus_t>(errCode);
253 : }
254 :
255 2 : void AIKernelsLibAiCpu::DeleteSoInWhiteList(const std::string &soName)
256 : {
257 2 : const std::lock_guard<std::mutex> lk(soWhiteListMtx_);
258 2 : if (soWhiteList_.empty()) {
259 1 : AE_INFO_LOG(AE_MODULE_ID, "so white list is empty");
260 1 : return;
261 : }
262 1 : auto iter = soWhiteList_.find(soName);
263 1 : if (iter != soWhiteList_.end()) {
264 0 : soWhiteList_.erase(iter);
265 0 : AE_INFO_LOG(AE_MODULE_ID, "erase so:%s in white list", soName.c_str());
266 : } else {
267 1 : AE_INFO_LOG(AE_MODULE_ID, "so:%s not in white list", soName.c_str());
268 : }
269 2 : }
270 :
271 2 : aeStatus_t AIKernelsLibAiCpu::AddSoInWhiteList(const std::string &soName)
272 : {
273 2 : const std::lock_guard<std::mutex> lk(soWhiteListMtx_);
274 2 : if (soWhiteList_.size() >= MAX_WHITE_LIST_SIZE) {
275 0 : AE_ERR_LOG(AE_MODULE_ID, "white list is full");
276 0 : return AE_STATUS_INNER_ERROR;
277 : }
278 2 : auto iter = soWhiteList_.find(soName);
279 2 : if (iter == soWhiteList_.end()) {
280 2 : soWhiteList_[soName] = soName;
281 2 : AE_INFO_LOG(AE_MODULE_ID, "add so:%s in white list, list size:%zu", soName.c_str(), soWhiteList_.size());
282 : } else {
283 0 : AE_INFO_LOG(AE_MODULE_ID, "so:%s already in white list, size:%zu", soName.c_str(), soWhiteList_.size());
284 : }
285 2 : return AE_STATUS_SUCCESS;
286 2 : }
287 : }
|