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(
77 : AE_MODULE_ID, "Get KFC api by global failed, func is nullptr, kernelName[%s], dlerror[%s]", kernelName,
78 : dlerror());
79 7 : return static_cast<int32_t>(AE_STATUS_INNER_ERROR);
80 : }
81 1 : return AE_STATUS_SUCCESS;
82 : }
83 :
84 7 : int32_t AIKernelsLibAiCpuKFC::GetApiWhenSonameNotEmpty(
85 : const aicpu::KernelType kernelType, const uint32_t soNameLen, const char_t* kernelSoName, const char_t* kernelName,
86 : void*& funcAddr)
87 : {
88 7 : if (static_cast<bool>(unlikely(soNameLen > AE_MAX_SO_NAME))) {
89 2 : AE_RUN_WARN_LOG(AE_MODULE_ID, "kernelSoName length is not supported, len=%d.", soNameLen);
90 2 : return static_cast<int32_t>(AE_STATUS_INNER_ERROR);
91 : }
92 :
93 5 : const auto ret = soMngr_.GetApi(kernelType, kernelSoName, kernelName, &funcAddr);
94 5 : if (static_cast<bool>(unlikely(ret != AE_STATUS_SUCCESS))) {
95 3 : AE_RUN_WARN_LOG(AE_MODULE_ID, "Get %s api from %s unsuccessfully.", kernelName, kernelSoName);
96 3 : return static_cast<int32_t>(AE_STATUS_INNER_ERROR);
97 : }
98 :
99 2 : if (static_cast<bool>(unlikely(funcAddr == nullptr))) {
100 1 : AE_RUN_WARN_LOG(AE_MODULE_ID, "Get %s api from %s success, but func is nullptr", kernelName, kernelSoName);
101 1 : return static_cast<int32_t>(AE_STATUS_INNER_ERROR);
102 : }
103 :
104 1 : return AE_STATUS_SUCCESS;
105 : }
106 :
107 9 : int32_t AIKernelsLibAiCpuKFC::GetApiBySoname(
108 : const aicpu::KernelType kernelType, const char_t* kernelSoName, AicpuKFCOpFuncPtr& opFuncPtr,
109 : const char_t* kernelName)
110 : {
111 9 : const uint32_t soNameLen = strnlen(kernelSoName, AE_MAX_SO_NAME + 1);
112 9 : if (soNameLen == 0) {
113 2 : if (GetApiGlobal(opFuncPtr, kernelName) != AE_STATUS_SUCCESS) {
114 1 : AE_ERR_LOG(
115 : AE_MODULE_ID, "Get KFC api by global failed, kernelSoName[%s], soNameLen[%u], kernelName[%s].",
116 : kernelSoName, soNameLen, kernelName);
117 1 : return static_cast<int32_t>(AE_STATUS_INNER_ERROR);
118 : }
119 : } else {
120 7 : void* funcAddr = nullptr;
121 7 : if (GetApiWhenSonameNotEmpty(kernelType, soNameLen, kernelSoName, kernelName, funcAddr) == AE_STATUS_SUCCESS) {
122 1 : opFuncPtr = PtrToFunctionPtr<void, AicpuKFCOpFuncPtr>(funcAddr);
123 : } else {
124 6 : if (GetApiGlobal(opFuncPtr, kernelName) != AE_STATUS_SUCCESS) {
125 6 : AE_ERR_LOG(
126 : AE_MODULE_ID,
127 : "Get KFC api by soname and global both failed, kernelSoName[%s], soNameLen[%u], kernelName[%s].",
128 : kernelSoName, soNameLen, kernelName);
129 6 : return static_cast<int32_t>(AE_STATUS_INNER_ERROR);
130 : }
131 : }
132 : }
133 :
134 2 : return AE_STATUS_SUCCESS;
135 : }
136 :
137 : // Implement call a aicpu op kernel interface
138 12 : int32_t AIKernelsLibAiCpuKFC::CallKernelApi(const aicpu::KernelType kernelType, const void* const kernelBase)
139 : {
140 : (void)kernelType;
141 12 : const aicpu::HwtsCceKernel* cceKernelBase = static_cast<const aicpu::HwtsCceKernel*>(kernelBase);
142 12 : if (static_cast<bool>(unlikely(cceKernelBase == nullptr))) {
143 1 : AE_ERR_LOG(AE_MODULE_ID, "Input param KFC kernelBase is nullptr.");
144 1 : return static_cast<int32_t>(AE_STATUS_BAD_PARAM);
145 : }
146 :
147 11 : char_t* kernelName = nullptr;
148 11 : aeStatus_t ret = GetKernelName(kernelName, cceKernelBase);
149 11 : if (static_cast<bool>(unlikely((ret != AE_STATUS_SUCCESS)))) {
150 1 : AE_ERR_LOG(AE_MODULE_ID, "get KFC kernelName failed, ret=%u.", ret);
151 1 : return static_cast<int32_t>(ret);
152 : }
153 10 : AicpuKFCOpFuncPtr opFuncPtr = nullptr;
154 10 : AE_RW_LOCK_RD_LOCK(&rwLock_);
155 20 : auto apiIter = apiCacher_.find(kernelName);
156 10 : if (apiIter != apiCacher_.end()) {
157 1 : opFuncPtr = apiIter->second;
158 : } else {
159 9 : AE_RW_LOCK_UN_LOCK(&rwLock_);
160 9 : AE_RW_LOCK_WR_LOCK(&rwLock_);
161 18 : apiIter = apiCacher_.find(kernelName);
162 9 : if (apiIter != apiCacher_.end()) {
163 0 : opFuncPtr = apiIter->second;
164 : } else {
165 9 : char_t* kernelSoName = PtrToPtr<void, char_t>(ValueToPtr(cceKernelBase->kernelSo));
166 9 : if (GetApiBySoname(kernelType, kernelSoName, opFuncPtr, kernelName) != AE_STATUS_SUCCESS) {
167 7 : AE_RW_LOCK_UN_LOCK(&rwLock_);
168 7 : AE_ERR_LOG(
169 : AE_MODULE_ID, "Get KFC kernel api failed, kernelSoName[%s], kernelName[%s].", kernelSoName,
170 : kernelName);
171 7 : return static_cast<int32_t>(AE_STATUS_INNER_ERROR);
172 : }
173 6 : apiCacher_[kernelName] = opFuncPtr;
174 : }
175 : }
176 :
177 3 : AE_RW_LOCK_UN_LOCK(&rwLock_);
178 3 : AE_INFO_LOG(AE_MODULE_ID, "Get KFC kernelname[%s] func success", kernelName);
179 3 : const uint32_t result = RunAicpuFunc(kernelBase, opFuncPtr);
180 3 : return static_cast<int32_t>(TransformKernelErrorCode(result, kernelName));
181 : }
182 :
183 4 : uint32_t AIKernelsLibAiCpuKFC::RunAicpuFunc(const void* const kernelBase, AicpuKFCOpFuncPtr& opFuncPtr) const
184 : {
185 4 : const auto cceKernelBase = static_cast<const aicpu::HwtsCceKernel*>(kernelBase);
186 4 : void* const param = ValueToPtr(static_cast<const uintptr_t>(cceKernelBase->paramBase));
187 4 : uint32_t result = 0U;
188 4 : if (&aicpu::SetBlockIdxAndBlockNum != nullptr) {
189 0 : (void)aicpu::SetBlockIdxAndBlockNum(cceKernelBase->blockId, cceKernelBase->blockNum);
190 : }
191 : #ifdef AICPU_PROFILING
192 : uint64_t runStartTick;
193 : uint64_t runStartTime;
194 : const std::shared_ptr<aicpu::ProfMessage> profHandle = aicpu::GetProfHandle();
195 : if (static_cast<bool>(unlikely(profHandle != nullptr))) {
196 : aicpu::GetMicrosAndSysTick(runStartTime, runStartTick);
197 : }
198 : #endif
199 4 : result = opFuncPtr(param);
200 : #ifdef AICPU_PROFILING
201 : if (static_cast<bool>(unlikely(profHandle != nullptr))) {
202 : uint64_t runEndTick;
203 : uint64_t runEndTime;
204 : aicpu::GetMicrosAndSysTick(runEndTime, runEndTick);
205 : (void)profHandle->SetRunStartTime(runStartTime)
206 : ->SetRunStartTick(runStartTick)
207 : ->SetRunEndTime(runEndTime)
208 : ->SetRunEndTick(runEndTick);
209 : }
210 : #endif
211 4 : return result;
212 : }
213 :
214 6 : int32_t AIKernelsLibAiCpuKFC::TransformKernelErrorCode(const uint32_t errCode, const char_t* const kernelName) const
215 : {
216 6 : if (likely(errCode == 0U)) {
217 2 : return AE_STATUS_SUCCESS;
218 : }
219 :
220 4 : if (errCode == static_cast<uint32_t>(AicpuOpErrorCode::AICPU_TASK_ABORT)) {
221 1 : AE_INFO_LOG(AE_MODULE_ID, "Get kfc task abort flag");
222 1 : return AE_STATUS_TASK_ABORT;
223 : }
224 :
225 3 : if ((errCode >= static_cast<uint32_t>(AicpuOpErrorCode::AICPU_KFC_PASSTHROUGH_START)) &&
226 : (errCode <= static_cast<uint32_t>(AicpuOpErrorCode::AICPU_KFC_PASSTHROUGH_END))) {
227 1 : AE_INFO_LOG(AE_MODULE_ID, "KFC %s run passthrough ret[%u]", kernelName, errCode);
228 1 : return static_cast<int32_t>(errCode);
229 : }
230 :
231 2 : AE_ERR_LOG(AE_MODULE_ID, "KFC %s run failed ret[%u]", kernelName, errCode);
232 2 : return AE_STATUS_TASK_FAIL;
233 : }
234 : } // namespace cce
|