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 : #include "operator_preliminary.h"
11 :
12 : #include <cinttypes>
13 : #include <fstream>
14 : #include <algorithm>
15 : #include "securec.h"
16 : #include "lib_path.h"
17 : #include "file_utils.h"
18 : #include "log/adx_log.h"
19 : #include "adump_platform_api.h"
20 : #include "adump_platform_manager.h"
21 : #include "runtime/kernel.h"
22 : #include "runtime/mem.h"
23 : #include "runtime/dev.h"
24 :
25 : namespace Adx {
26 : constexpr uint32_t SINGLE_STATS_BYTE = 8; // 单个统计项的占用大小
27 : constexpr uint32_t BLOCK_MIN_SIZE = 32; // 最小搬运单元
28 : constexpr uint32_t DCCI_SYNC_SIZE = 64; // DCCI强制同步数据64B
29 : constexpr uint32_t MAX_STATS_NUM = 64; // 最大统计项个数
30 : constexpr uint32_t INTEGER_KILOBYTE = 1024; // 表示1KB
31 :
32 : constexpr const char* const KFC_OPERATOR_STUB_NAME = "kfc_dump_stat_stub";
33 : constexpr const char* const KFC_OPERATOR_NAME = "kfc_dump_stat";
34 :
35 : static const std::vector<PlatformType> AICORE_RELATED = {PlatformType::CHIP_DC_TYPE};
36 :
37 42 : OperatorPreliminary::OperatorPreliminary(const DumpSetting& setting, const uint32_t deviceId)
38 42 : : deviceId_(deviceId), setting_(setting), opData_({})
39 42 : {}
40 :
41 42 : OperatorPreliminary::~OperatorPreliminary() {}
42 :
43 15 : uint64_t OperatorPreliminary::CalcWorkspaceSize(uint64_t statsCnt)
44 : {
45 15 : PlatformType platform = setting_.GetPlatformType();
46 15 : uint32_t coreSize = opData_.vectCoreCnt;
47 15 : auto coreIter = std::find(AICORE_RELATED.begin(), AICORE_RELATED.end(), platform);
48 30 : if (coreIter != AICORE_RELATED.cend()) {
49 0 : return DCCI_SYNC_SIZE * opData_.aiCoreCnt * statsCnt;
50 : }
51 15 : return BLOCK_MIN_SIZE * (coreSize + 1) * statsCnt; // + 1 用于当做同步空间
52 : }
53 :
54 3 : std::vector<std::string> OperatorPreliminary::GetBinNames() const
55 : {
56 3 : auto plat = PlatformReflection<DataDumpInterface>::CreatePlatform(setting_.GetPlatformType());
57 3 : if (plat == nullptr) {
58 0 : return {};
59 : }
60 3 : return plat->GetKfcBinNames();
61 3 : }
62 :
63 18 : int32_t OperatorPreliminary::GetStreamInfo()
64 : {
65 18 : IDE_LOGI("Start GetStreamInfo on device %u.", deviceId_);
66 18 : rtError_t ret = rtSetDevice(deviceId_);
67 18 : IDE_CTRL_VALUE_FAILED(
68 : ret == RT_ERROR_NONE, return ADUMP_FAILED, "Execute rtSetDevice on device %u failed with result %d", deviceId_,
69 : ret);
70 18 : opData_.setDevice = true;
71 :
72 18 : ret = rtStreamCreateWithFlags(&opData_.deviceStm, 0, RT_STREAM_CP_PROCESS_USE);
73 18 : IDE_CTRL_VALUE_FAILED(
74 : ret == RT_ERROR_NONE, return ADUMP_FAILED, "Execute rtStreamCreateWithFlags on device %u failed with result %d",
75 : deviceId_, ret);
76 :
77 18 : ret = rtGetStreamId(opData_.deviceStm, &opData_.streamId);
78 18 : IDE_CTRL_VALUE_FAILED(
79 : ret == RT_ERROR_NONE, return ADUMP_FAILED, "Execute rtGetStreamId on device %u failed with result %d",
80 : deviceId_, ret);
81 :
82 18 : ret = rtStreamGetSqid(opData_.deviceStm, &opData_.sqId);
83 18 : IDE_CTRL_VALUE_FAILED(
84 : ret == RT_ERROR_NONE, return ADUMP_FAILED, "Execute rtStreamGetSqid on device %u failed with result %d",
85 : deviceId_, ret);
86 :
87 18 : ret = rtStreamGetCqid(opData_.deviceStm, &opData_.cqIds, &opData_.logicCqIds);
88 18 : IDE_CTRL_VALUE_FAILED(
89 : ret == RT_ERROR_NONE, return ADUMP_FAILED, "Execute rtStreamGetCqid on device %u failed with result %d",
90 : deviceId_, ret);
91 :
92 18 : IDE_LOGI(
93 : "Success to get stream id=%d, sqId=%u, cqId=%u, logic cqId=%u on device %u.", opData_.streamId, opData_.sqId,
94 : opData_.cqIds, opData_.logicCqIds, deviceId_);
95 18 : return ADUMP_SUCCESS;
96 : }
97 :
98 18 : int32_t OperatorPreliminary::GetUBSizeAndCoreNum()
99 : {
100 18 : char version[SOC_VERSION_LEN] = {};
101 18 : IDE_CTRL_VALUE_FAILED(
102 : rtGetSocVersion(version, SOC_VERSION_LEN) == RT_ERROR_NONE, return ADUMP_FAILED, "Failed to get soc version");
103 18 : const std::string socVersion(version);
104 :
105 : PlatformData platformData;
106 18 : IDE_CTRL_VALUE_FAILED(
107 : AdumpPlatformApi::GetUBSizeAndCoreNum(socVersion, setting_.GetPlatformType(), platformData),
108 : return ADUMP_FAILED, "Failed to read platform information from fe api.");
109 :
110 15 : opData_.ubSize = platformData.ubSize;
111 15 : opData_.aiCoreCnt = platformData.aiCoreCnt;
112 15 : opData_.vectCoreCnt = platformData.vectCoreCnt;
113 15 : IDE_LOGI(
114 : "Get ub size:%" PRIu64 ", ai core count:%" PRIu64 ", vector core count:%" PRIu64 " on device %u.",
115 : opData_.ubSize, opData_.aiCoreCnt, opData_.vectCoreCnt, deviceId_);
116 15 : return ADUMP_SUCCESS;
117 18 : }
118 :
119 3 : std::unique_ptr<char[]> OperatorPreliminary::LoadBinFile(const std::string& filename, size_t& fileSize) const
120 : {
121 3 : std::string realPath;
122 3 : IDE_CTRL_VALUE_FAILED(
123 : FileUtils::FileNameIsReal(filename, realPath) == IDE_DAEMON_OK, return nullptr,
124 : "LoadBinFile failed. The real path is %s.", filename.c_str());
125 :
126 3 : std::ifstream iFile(realPath, std::ios::binary | std::ios::ate);
127 3 : IDE_CTRL_VALUE_FAILED(iFile.is_open(), return nullptr, "Failed to open file: %s", realPath.c_str());
128 :
129 3 : auto pos = iFile.tellg();
130 3 : if (pos <= 0) {
131 0 : IDE_LOGE("Failed to get file size. file: %s, size: %ld", realPath.c_str(), pos);
132 0 : return nullptr;
133 : }
134 3 : fileSize = static_cast<size_t>(pos);
135 3 : iFile.seekg(0, std::ios::beg);
136 3 : char* buffer = new (std::nothrow) char[fileSize];
137 3 : IDE_CTRL_VALUE_FAILED(buffer != nullptr, return nullptr, "Failed to new file buffer");
138 3 : IDE_CTRL_VALUE_FAILED(
139 : iFile.read(buffer, fileSize),
140 : {
141 : delete[] buffer;
142 : return nullptr;
143 : },
144 : "Failed to read file data. file: %s, size: %ld", filename.c_str(), fileSize);
145 3 : return std::unique_ptr<char[]>(buffer);
146 3 : }
147 :
148 15 : int32_t OperatorPreliminary::GetOperatorPCAddr()
149 : {
150 15 : static std::unique_ptr<char[]> binData = nullptr;
151 15 : rtError_t ret = RT_ERROR_NONE;
152 :
153 15 : if (binData == nullptr) {
154 3 : const std::vector<std::string> opNames = GetBinNames();
155 3 : std::string hitPath;
156 6 : for (const auto& opName : opNames) {
157 3 : const std::string opPath = LibPath::Instance().GetTargetPath(opName);
158 3 : IDE_CTRL_VALUE_FAILED(
159 : !opPath.empty(), continue, "Failed to get the path of the kfc operator. opName=%s", opName.c_str());
160 3 : if (FileUtils::IsFileExist(opPath)) {
161 3 : hitPath = opPath;
162 3 : break;
163 : }
164 3 : }
165 3 : IDE_CTRL_VALUE_FAILED(
166 : !hitPath.empty(), return ADUMP_FAILED, "Failed to find an existing kfc operator file. candidates=%zu",
167 : opNames.size());
168 :
169 3 : size_t fileSize = 0;
170 3 : binData = LoadBinFile(hitPath, fileSize);
171 3 : IDE_CTRL_VALUE_FAILED(
172 : binData != nullptr, return ADUMP_FAILED, "Failed to load the kfc operator data. opPath=%s",
173 : hitPath.c_str());
174 3 : IDE_LOGI("Success to load the kfc operator data. opPath=%s, fileSize=%zu", hitPath.c_str(), fileSize);
175 :
176 3 : rtDevBinary_t bin{
177 : .magic = RT_DEV_BINARY_MAGIC_ELF_AIVEC,
178 : .version = 0,
179 3 : .data = static_cast<void*>(binData.get()),
180 3 : .length = fileSize};
181 :
182 3 : ret = rtDevBinaryRegister(&bin, &opData_.binHandle);
183 3 : IDE_CTRL_VALUE_FAILED(
184 : ret == RT_ERROR_NONE, return ADUMP_FAILED, "Failed to register the kfc operator binary. ret=%d", ret);
185 :
186 3 : ret = rtFunctionRegister(opData_.binHandle, KFC_OPERATOR_STUB_NAME, KFC_OPERATOR_NAME, KFC_OPERATOR_NAME, 0U);
187 3 : IDE_CTRL_VALUE_FAILED(
188 : ret == RT_ERROR_NONE, return ADUMP_FAILED,
189 : "Failed to register the kfc operator function. stubFunc=%s, stubName=%s, ret=%d", KFC_OPERATOR_STUB_NAME,
190 : KFC_OPERATOR_NAME, ret);
191 3 : }
192 :
193 15 : ret = rtGetAddrByFun(KFC_OPERATOR_STUB_NAME, &opData_.pcAddr);
194 15 : IDE_CTRL_VALUE_FAILED(
195 : ret == RT_ERROR_NONE, return ADUMP_FAILED,
196 : "Failed to get the kfc pc address with stubFunc. stubFunc=%s, ret=%d", KFC_OPERATOR_STUB_NAME, ret);
197 :
198 15 : IDE_LOGI("Success to get the kfc pc address on device %u. pcAddr=%p", deviceId_, opData_.pcAddr);
199 15 : return ADUMP_SUCCESS;
200 : }
201 :
202 15 : int32_t OperatorPreliminary::CreateMemory()
203 : {
204 15 : opData_.msgQSize = INTEGER_KILOBYTE * INTEGER_KILOBYTE; // 1M 消息轮询、参数保存、多核同步空间
205 15 : opData_.outputSize = MAX_STATS_NUM * SINGLE_STATS_BYTE;
206 15 : uint64_t statsCnt = 0;
207 975 : for (uint64_t idx = 0; idx < MAX_STATS_NUM; idx++) {
208 960 : if ((setting_.GetDumpStatsItem() & (1LLU << idx)) != 0) {
209 90 : statsCnt++; // 统计项个数
210 : }
211 : }
212 15 : opData_.workspaceSize = CalcWorkspaceSize(statsCnt);
213 15 : opData_.stackBaseSize = CalcStackSize();
214 :
215 15 : IDE_CTRL_VALUE_FAILED(
216 : opData_.workspaceSize != 0 && opData_.stackBaseSize != 0, return ADUMP_FAILED,
217 : "The workspaceSize is 0 or the stackBaseSize is 0");
218 15 : IDE_LOGI(
219 : "Calculate MsgQ Size:%" PRIu64 "Byte, output size:%" PRIu64 "Byte, workspace size:%" PRIu64 "Byte,"
220 : "stack base size:%" PRIu64 "Byte on device %u.",
221 : opData_.msgQSize, opData_.outputSize, opData_.workspaceSize, opData_.stackBaseSize, deviceId_);
222 :
223 15 : uint64_t memSize = opData_.msgQSize + opData_.outputSize + opData_.workspaceSize + opData_.stackBaseSize;
224 15 : rtError_t ret = rtMalloc(&opData_.memoryAddr, memSize, RT_MEMORY_DEFAULT, AICPU);
225 15 : IDE_CTRL_VALUE_FAILED(ret == RT_ERROR_NONE, return ADUMP_FAILED, "rtMalloc failed. ret=%d", ret);
226 15 : IDE_LOGI("rtMalloc success for the kfc operator. memAddr=%p, memSize=%llu", opData_.memoryAddr, memSize);
227 15 : return ADUMP_SUCCESS;
228 : }
229 :
230 15 : int32_t OperatorPreliminary::KFCKernelLaunch()
231 : {
232 15 : IDE_LOGD("Start to initialize the kfc kernel information on device %u.", deviceId_);
233 15 : KfcDumpOpInitParam kfcParam;
234 15 : kfcParam.kfcWorkSpace.msgQ = reinterpret_cast<uint64_t>(opData_.memoryAddr);
235 15 : kfcParam.kfcWorkSpace.msgQSize = opData_.msgQSize;
236 15 : kfcParam.kfcWorkSpace.output = kfcParam.kfcWorkSpace.msgQ + opData_.msgQSize;
237 15 : kfcParam.kfcWorkSpace.outputSize = opData_.outputSize;
238 15 : kfcParam.kfcWorkSpace.workspace = kfcParam.kfcWorkSpace.output + opData_.outputSize;
239 15 : kfcParam.kfcWorkSpace.workspaceSize = opData_.workspaceSize;
240 15 : kfcParam.kfcWorkSpace.stackBase = kfcParam.kfcWorkSpace.workspace + opData_.workspaceSize;
241 15 : kfcParam.kfcWorkSpace.stackBaseSize = opData_.stackBaseSize;
242 :
243 15 : kfcParam.config.aiCoreNum = opData_.aiCoreCnt;
244 15 : kfcParam.config.vectorCoreNum = opData_.vectCoreCnt;
245 15 : kfcParam.config.ubSize = opData_.ubSize;
246 15 : kfcParam.config.dumpStatPcAddr = reinterpret_cast<uint64_t>(opData_.pcAddr);
247 15 : kfcParam.config.statsType = setting_.GetDumpStatsItem();
248 15 : kfcParam.config.chipType = static_cast<uint64_t>(setting_.GetPlatformType());
249 :
250 15 : kfcParam.streamInfo.streamId = opData_.streamId;
251 15 : kfcParam.streamInfo.sqIds = opData_.sqId;
252 15 : kfcParam.streamInfo.cqIds = opData_.cqIds;
253 15 : kfcParam.streamInfo.logicCqIds = opData_.logicCqIds;
254 15 : kfcParam.streamInfo.deviceId = deviceId_;
255 :
256 15 : if (UpdateKFCLaunchInfo(kfcParam) != ADUMP_SUCCESS) {
257 0 : return ADUMP_FAILED;
258 : }
259 :
260 : rtAicpuArgsEx_t argsInfo;
261 15 : argsInfo.args = static_cast<void*>(&kfcParam);
262 15 : argsInfo.argsSize = sizeof(kfcParam);
263 15 : argsInfo.soNameAddrOffset = static_cast<uint16_t>(offsetof(KfcDumpOpInitParam, soName));
264 15 : argsInfo.kernelNameAddrOffset = static_cast<uint16_t>(offsetof(KfcDumpOpInitParam, kernelName));
265 15 : argsInfo.hostInputInfoPtr = nullptr;
266 15 : argsInfo.kernelOffsetInfoPtr = nullptr;
267 15 : argsInfo.hostInputInfoNum = 0;
268 15 : argsInfo.kernelOffsetInfoNum = 0;
269 15 : argsInfo.isNoNeedH2DCopy = false;
270 :
271 : rtError_t ret =
272 15 : rtAicpuKernelLaunchExWithArgs(KERNEL_TYPE_AICPU_KFC, "VectorStats", 1, &argsInfo, nullptr, nullptr, 0);
273 15 : IDE_CTRL_VALUE_FAILED(ret == RT_ERROR_NONE, return ADUMP_FAILED, "Failed to launch kfc kernel, ret=%d", ret);
274 :
275 15 : ret = rtStreamSynchronize(nullptr); // Use the default flow to ensure successful execution.
276 15 : IDE_CTRL_VALUE_FAILED(
277 : ret == RT_ERROR_NONE, return ADUMP_FAILED, "Execute rtStreamSynchronize failed for kfc kernel. ret=%d", ret);
278 :
279 15 : IDE_LOGI("Success to initialize the kfc kernel information on device %u.", deviceId_);
280 15 : return ADUMP_SUCCESS;
281 : }
282 :
283 27 : KfcLaunchMode OperatorPreliminary::DecideKFCLaunchMode(int32_t driverApiVersion)
284 : {
285 : // 低于LAUNCH_MODE_AICPU,驱动版本过低(含:0(无驱动接口符号)和-1(获取驱动失败))),统一不支持KFC算子。
286 27 : if (driverApiVersion < KFC_AICPU_DRV_VERSION) {
287 9 : return KfcLaunchMode::UNSUPPORTED;
288 : }
289 18 : if (driverApiVersion < KFC_ADUMP_DRV_VERSION) {
290 12 : return KfcLaunchMode::LAUNCH_MODE_AICPU;
291 : }
292 6 : return KfcLaunchMode::LAUNCH_MODE_ADUMP;
293 : }
294 :
295 15 : int32_t OperatorPreliminary::UpdateKFCLaunchInfo(KfcDumpOpInitParam& kfcParam) const
296 : {
297 15 : KfcLaunchInfo launchInfo = {};
298 15 : switch (kfcLaunchMode_) {
299 9 : case KfcLaunchMode::LAUNCH_MODE_AICPU:
300 9 : launchInfo = AICPU_LAUNCH_INFO;
301 9 : break;
302 6 : case KfcLaunchMode::LAUNCH_MODE_ADUMP:
303 6 : launchInfo = ADUMP_LAUNCH_INFO;
304 6 : break;
305 0 : default:
306 0 : IDE_LOGE("Kfc launch mode is unsupported");
307 0 : return ADUMP_FAILED;
308 : }
309 :
310 15 : errno_t ret = strcpy_s(kfcParam.soName, FILE_NAME_MAX, launchInfo.soName);
311 15 : if (ret != EOK) {
312 0 : IDE_LOGE("Failed to set kfc soName, ret=%d", ret);
313 0 : return ADUMP_FAILED;
314 : }
315 15 : ret = strcpy_s(kfcParam.kernelName, FILE_NAME_MAX, launchInfo.kernelName);
316 15 : if (ret != EOK) {
317 0 : IDE_LOGE("Failed to set kfc kernelName, ret=%d", ret);
318 0 : return ADUMP_FAILED;
319 : }
320 :
321 15 : IDE_LOGI("Kfc operator uses soName[%s], kernelName[%s]", launchInfo.soName, launchInfo.kernelName);
322 15 : return ADUMP_SUCCESS;
323 : }
324 :
325 27 : int32_t OperatorPreliminary::OperatorInit()
326 : {
327 27 : int32_t version = AdumpDsmi::DrvGetAPIVersion();
328 27 : kfcLaunchMode_ = DecideKFCLaunchMode(version);
329 27 : if (kfcLaunchMode_ == KfcLaunchMode::UNSUPPORTED) {
330 9 : IDE_LOGW("Current driver version %d does not support kfc feature for dump statistics.", version);
331 9 : return ADUMP_SUCCESS;
332 : }
333 :
334 18 : IDE_LOGI("Prepare to initialize the resources of kfc operator on device %u.", deviceId_);
335 : do {
336 18 : int32_t ret = GetStreamInfo();
337 18 : IDE_CTRL_VALUE_FAILED_NODO(
338 : ret == ADUMP_SUCCESS, break, "OperatorInit is failed at GetStreamInfo when executed.");
339 :
340 18 : ret = GetUBSizeAndCoreNum();
341 18 : IDE_CTRL_VALUE_FAILED_NODO(
342 : ret == ADUMP_SUCCESS, break, "OperatorInit is failed at GetUBSizeAndCoreNum when executed.");
343 :
344 15 : ret = GetOperatorPCAddr();
345 15 : IDE_CTRL_VALUE_FAILED_NODO(
346 : ret == ADUMP_SUCCESS, break, "OperatorInit is failed at GetOperatorPCAddr when executed.");
347 :
348 15 : ret = CreateMemory();
349 15 : IDE_CTRL_VALUE_FAILED_NODO(
350 : ret == ADUMP_SUCCESS, break, "OperatorInit is failed at CreateMemory when executed.");
351 :
352 15 : ret = KFCKernelLaunch();
353 15 : IDE_CTRL_VALUE_FAILED_NODO(
354 : ret == ADUMP_SUCCESS, break, "OperatorInit is failed at kernel launch when executed.");
355 15 : return ADUMP_SUCCESS;
356 : } while (0);
357 3 : IDE_LOGW("Start to destroy rt api resources on device %u.", deviceId_);
358 3 : return ADUMP_FAILED;
359 : }
360 :
361 : } // namespace Adx
|