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 : } // namespace
37 :
38 : AIKernelsLibAiCpu* AIKernelsLibAiCpu::instance_ = nullptr;
39 : std::mutex AIKernelsLibAiCpu::mtx_;
40 :
41 : // SINGLETON object get interface
42 135 : AIKernelsLibAiCpu* AIKernelsLibAiCpu::GetInstance()
43 : {
44 135 : 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(
74 : char_t* kernelName, char_t* kernelSoName, 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 120 : 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 120 : errno_t retCpy = strncpy_s(&kernelName[0], AE_MAX_KERNEL_NAME + 1U, paramKernelName, AE_MAX_KERNEL_NAME);
84 120 : 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 120 : retCpy = strncpy_s(&kernelSoName[0], AE_MAX_SO_NAME + 1U, paramKernelSo, AE_MAX_SO_NAME);
90 120 : 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 120 : 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 120 : 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 120 : void* funcAddr = nullptr;
122 120 : 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", &kernelName[0], &kernelSoName[0]);
129 0 : return AE_STATUS_INNER_ERROR;
130 : }
131 :
132 121 : (void)aicpu::SetOpname(kernelName);
133 :
134 121 : const uint32_t result = RunAicpuFunc(kernelBase, funcAddr, &kernelName[0]);
135 119 : return static_cast<int32_t>(TransformKernelErrorCode(result, &kernelName[0], &kernelSoName[0]));
136 : }
137 :
138 120 : uint32_t AIKernelsLibAiCpu::RunAicpuFunc(
139 : const void* const kernelBase, void* const funcAddr, const char_t* const funcName) const
140 : {
141 120 : uint32_t result = 0U;
142 120 : const auto cceKernelBase = static_cast<const aicpu::HwtsCceKernel*>(kernelBase);
143 120 : void* const param = ValueToPtr(cceKernelBase->paramBase);
144 : #ifdef AICPU_PROFILING
145 : uint64_t runStartTime;
146 : uint64_t runStartTick;
147 : aicpu::GetMicrosAndSysTick(runStartTime, runStartTick);
148 : #endif
149 119 : (void)aicpu::SetBlockIdxAndBlockNum(cceKernelBase->blockId, cceKernelBase->blockNum);
150 119 : if (strcmp(funcName, kRunFuncName) == 0) {
151 0 : AE_INFO_LOG(AE_MODULE_ID, "opFuncPtr is RunCpuKernelWithBlockDim.");
152 0 : struct BlkDimInfo blkInfo = {};
153 0 : blkInfo.blockId = cceKernelBase->blockId;
154 0 : blkInfo.blockNum = cceKernelBase->blockNum;
155 0 : const auto opFuncPtr = PtrToFunctionPtr<void, AicpuOpFuncPtrWithBlockDim>(funcAddr);
156 0 : result = opFuncPtr(param, &blkInfo);
157 : } else {
158 119 : const auto opFuncPtr = PtrToFunctionPtr<void, AicpuOpFuncPtr>(funcAddr);
159 119 : result = opFuncPtr(param);
160 : }
161 :
162 : #ifdef AICPU_PROFILING
163 : uint64_t runEndTime;
164 : uint64_t runEndTick;
165 : aicpu::GetMicrosAndSysTick(runEndTime, runEndTick);
166 :
167 : const std::shared_ptr<aicpu::ProfMessage> profHandle = aicpu::GetProfHandle();
168 : if (profHandle != nullptr) {
169 : std::string opName = "null";
170 : (void)aicpu::GetOpname(aicpu::GetAicpuThreadIndex(), opName);
171 : (void)profHandle->SetRunStartTime(runStartTime)
172 : ->SetRunStartTick(runStartTick)
173 : ->SetRunEndTime(runEndTime)
174 : ->SetRunEndTick(runEndTick);
175 : }
176 : #endif
177 119 : return result;
178 : }
179 :
180 6 : aeStatus_t AIKernelsLibAiCpu::BatchLoadKernelSo(const aicpu::KernelType kernelType, std::vector<std::string>& soVec)
181 : {
182 6 : if (soVec.empty()) {
183 1 : AE_ERR_LOG(AE_MODULE_ID, "so vec is empty.");
184 1 : return AE_STATUS_SUCCESS;
185 : }
186 12 : for (auto& soName : soVec) {
187 7 : const aeStatus_t ret = soMngr_.LoadSo(kernelType, soName);
188 7 : if (ret != AE_STATUS_SUCCESS) {
189 5 : AE_RUN_WARN_LOG(AE_MODULE_ID, "Load so %s failed.", soName.c_str());
190 5 : continue;
191 : }
192 : }
193 5 : return AE_STATUS_SUCCESS;
194 : }
195 :
196 2 : aeStatus_t AIKernelsLibAiCpu::CloseSo(const char_t* const soName)
197 : {
198 2 : if (soName == nullptr) {
199 1 : AE_ERR_LOG(AE_MODULE_ID, "soName is null.");
200 1 : return AE_STATUS_BAD_PARAM;
201 : }
202 1 : const std::string kernelSoName(soName);
203 1 : return soMngr_.CloseSo(kernelSoName);
204 1 : }
205 :
206 119 : aeStatus_t AIKernelsLibAiCpu::TransformKernelErrorCode(
207 : const uint32_t errCode, const char_t* const kernelName, const char_t* const soName) const
208 : {
209 119 : if (likely(errCode == 0U)) {
210 109 : return AE_STATUS_SUCCESS;
211 : }
212 :
213 10 : if (errCode == static_cast<uint32_t>(AicpuOpErrorCode::AICPU_END_OF_SEQUENCE_FLAG)) {
214 0 : AE_INFO_LOG(AE_MODULE_ID, "Get aicpu end of sequence flag.");
215 0 : return AE_STATUS_END_OF_SEQUENCE;
216 : }
217 10 : if (errCode == static_cast<uint32_t>(AicpuOpErrorCode::AICPU_TASK_WATI_FLAG)) {
218 0 : AE_INFO_LOG(AE_MODULE_ID, "Get aicpu task wait flag.");
219 0 : return AE_STATUS_TASK_WAIT;
220 : }
221 :
222 10 : if (!aicpu::IsCustAicpuSd()) {
223 10 : if (errCode == static_cast<uint32_t>(AicpuOpErrorCode::AICPU_SILENT_FAULT)) {
224 0 : AE_INFO_LOG(AE_MODULE_ID, "Get aicpu silent fault flag");
225 0 : return AE_STATUS_SILENT_FAULT;
226 : }
227 10 : if (errCode == static_cast<uint32_t>(AicpuOpErrorCode::AICPU_DETECT_FAULT)) {
228 0 : AE_INFO_LOG(AE_MODULE_ID, "Get aicpu detect fault flag");
229 0 : return AE_STATUS_DETECT_FAULT;
230 : }
231 :
232 10 : if (errCode == static_cast<uint32_t>(AicpuOpErrorCode::AICPU_DETECT_FAULT_NORAS)) {
233 0 : AE_INFO_LOG(AE_MODULE_ID, "Get aicpu detect fault no Ras flag");
234 0 : return AE_STATUS_DETECT_FAULT_NORAS;
235 : }
236 :
237 10 : if (errCode == static_cast<uint32_t>(AicpuOpErrorCode::AICPU_DETECT_LOW_BIT_FAULT)) {
238 0 : AE_INFO_LOG(AE_MODULE_ID, "Get aicpu detect low-bit fault flag");
239 0 : return AE_STATUS_DETECT_LOW_BIT_FAULT;
240 : }
241 :
242 10 : if (errCode == static_cast<uint32_t>(AicpuOpErrorCode::AICPU_DETECT_LOW_BIT_FAULT_NORAS)) {
243 0 : AE_INFO_LOG(AE_MODULE_ID, "Get aicpu detect low-bit fault no Ras flag");
244 0 : return AE_STATUS_DETECT_LOW_BIT_FAULT_NORAS;
245 : }
246 : }
247 :
248 10 : AE_ERR_LOG(AE_MODULE_ID, "call aicpu api %s in %s failed, ret:%u.", kernelName, soName, errCode);
249 : // other error code: transform to inner_error
250 10 : return static_cast<aeStatus_t>(errCode);
251 : }
252 :
253 2 : void AIKernelsLibAiCpu::DeleteSoInWhiteList(const std::string& soName)
254 : {
255 2 : const std::lock_guard<std::mutex> lk(soWhiteListMtx_);
256 2 : if (soWhiteList_.empty()) {
257 1 : AE_INFO_LOG(AE_MODULE_ID, "so white list is empty");
258 1 : return;
259 : }
260 1 : auto iter = soWhiteList_.find(soName);
261 1 : if (iter != soWhiteList_.end()) {
262 0 : soWhiteList_.erase(iter);
263 0 : AE_INFO_LOG(AE_MODULE_ID, "erase so:%s in white list", soName.c_str());
264 : } else {
265 1 : AE_INFO_LOG(AE_MODULE_ID, "so:%s not in white list", soName.c_str());
266 : }
267 2 : }
268 :
269 2 : aeStatus_t AIKernelsLibAiCpu::AddSoInWhiteList(const std::string& soName)
270 : {
271 2 : const std::lock_guard<std::mutex> lk(soWhiteListMtx_);
272 2 : if (soWhiteList_.size() >= MAX_WHITE_LIST_SIZE) {
273 0 : AE_ERR_LOG(AE_MODULE_ID, "white list is full");
274 0 : return AE_STATUS_INNER_ERROR;
275 : }
276 2 : auto iter = soWhiteList_.find(soName);
277 2 : if (iter == soWhiteList_.end()) {
278 2 : soWhiteList_[soName] = soName;
279 2 : AE_INFO_LOG(AE_MODULE_ID, "add so:%s in white list, list size:%zu", soName.c_str(), soWhiteList_.size());
280 : } else {
281 0 : AE_INFO_LOG(AE_MODULE_ID, "so:%s already in white list, size:%zu", soName.c_str(), soWhiteList_.size());
282 : }
283 2 : return AE_STATUS_SUCCESS;
284 2 : }
285 : } // namespace cce
|