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 "lib_path.h"
16 : #include "file_utils.h"
17 : #include "log/adx_log.h"
18 : #include "adump_platform_api.h"
19 : #include "adump_platform_manager.h"
20 : #include "runtime/kernel.h"
21 : #include "runtime/mem.h"
22 : #include "runtime/dev.h"
23 :
24 : namespace Adx {
25 : constexpr uint32_t SINGLE_STATS_BYTE = 8; // 单个统计项的占用大小
26 : constexpr uint32_t BLOCK_MIN_SIZE = 32; // 最小搬运单元
27 : constexpr uint32_t DCCI_SYNC_SIZE = 64; // DCCI强制同步数据64B
28 : constexpr uint32_t MAX_STATS_NUM = 64; // 最大统计项个数
29 : constexpr uint32_t INTEGER_KILOBYTE = 1024; // 表示1KB
30 :
31 : constexpr const char *const KFC_OPERATOR_STUB_NAME = "kfc_dump_stat_stub";
32 : constexpr const char *const KFC_OPERATOR_NAME = "kfc_dump_stat";
33 :
34 : static const std::vector<PlatformType> AICORE_RELATED = {PlatformType::CHIP_DC_TYPE};
35 :
36 21 : OperatorPreliminary::OperatorPreliminary(const DumpSetting &setting, const uint32_t deviceId)
37 21 : : deviceId_(deviceId), setting_(setting), opData_({})
38 : {
39 21 : }
40 :
41 21 : OperatorPreliminary::~OperatorPreliminary()
42 : {
43 21 : }
44 :
45 3 : uint64_t OperatorPreliminary::CalcWorkspaceSize(uint64_t statsCnt)
46 : {
47 3 : PlatformType platform = setting_.GetPlatformType();
48 3 : uint32_t coreSize = opData_.vectCoreCnt;
49 3 : auto coreIter = std::find(AICORE_RELATED.begin(), AICORE_RELATED.end(), platform);
50 3 : if (coreIter != AICORE_RELATED.cend()) {
51 0 : return DCCI_SYNC_SIZE * opData_.aiCoreCnt * statsCnt;
52 : }
53 3 : return BLOCK_MIN_SIZE * (coreSize + 1) * statsCnt; // + 1 用于当做同步空间
54 : }
55 :
56 3 : std::string OperatorPreliminary::GetBinName() const
57 : {
58 3 : auto plat = PlatformReflection<DataDumpInterface>::CreatePlatform(setting_.GetPlatformType());
59 3 : if (plat == nullptr) {
60 0 : return "UNKNOW_FILENAME";
61 : }
62 3 : std::string name = plat->GetKfcBinName();
63 3 : return name.empty() ? "UNKNOW_FILENAME" : name;
64 3 : }
65 :
66 6 : int32_t OperatorPreliminary::GetStreamInfo()
67 : {
68 6 : IDE_LOGI("Start GetStreamInfo on device %u.", deviceId_);
69 6 : rtError_t ret = rtSetDevice(deviceId_);
70 6 : IDE_CTRL_VALUE_FAILED(ret == RT_ERROR_NONE, return ADUMP_FAILED,
71 : "Execute rtSetDevice on device %u failed with result %d", deviceId_, ret);
72 6 : opData_.setDevice = true;
73 :
74 6 : ret = rtStreamCreateWithFlags(&opData_.deviceStm, 0, RT_STREAM_CP_PROCESS_USE);
75 6 : IDE_CTRL_VALUE_FAILED(ret == RT_ERROR_NONE, return ADUMP_FAILED,
76 : "Execute rtStreamCreateWithFlags on device %u failed with result %d", deviceId_, ret);
77 :
78 6 : ret = rtGetStreamId(opData_.deviceStm, &opData_.streamId);
79 6 : IDE_CTRL_VALUE_FAILED(ret == RT_ERROR_NONE, return ADUMP_FAILED,
80 : "Execute rtGetStreamId on device %u failed with result %d", deviceId_, ret);
81 :
82 6 : ret = rtStreamGetSqid(opData_.deviceStm, &opData_.sqId);
83 6 : IDE_CTRL_VALUE_FAILED(ret == RT_ERROR_NONE, return ADUMP_FAILED,
84 : "Execute rtStreamGetSqid on device %u failed with result %d", deviceId_, ret);
85 :
86 6 : ret = rtStreamGetCqid(opData_.deviceStm, &opData_.cqIds, &opData_.logicCqIds);
87 6 : IDE_CTRL_VALUE_FAILED(ret == RT_ERROR_NONE, return ADUMP_FAILED,
88 : "Execute rtStreamGetCqid on device %u failed with result %d", deviceId_, ret);
89 :
90 6 : IDE_LOGI("Success to get stream id=%d, sqId=%u, cqId=%u, logic cqId=%u on device %u.", opData_.streamId,
91 : opData_.sqId, opData_.cqIds, opData_.logicCqIds, deviceId_);
92 6 : return ADUMP_SUCCESS;
93 : }
94 :
95 6 : int32_t OperatorPreliminary::GetUBSizeAndCoreNum()
96 : {
97 6 : char version[SOC_VERSION_LEN] = {};
98 6 : IDE_CTRL_VALUE_FAILED(rtGetSocVersion(version, SOC_VERSION_LEN) == RT_ERROR_NONE, return ADUMP_FAILED,
99 : "Failed to get soc version");
100 6 : const std::string socVersion(version);
101 :
102 : PlatformData platformData;
103 6 : IDE_CTRL_VALUE_FAILED(AdumpPlatformApi::GetUBSizeAndCoreNum(socVersion, setting_.GetPlatformType(), platformData),
104 : return ADUMP_FAILED, "Failed to read platform info from fe api.");
105 :
106 3 : opData_.ubSize = platformData.ubSize;
107 3 : opData_.aiCoreCnt = platformData.aiCoreCnt;
108 3 : opData_.vectCoreCnt = platformData.vectCoreCnt;
109 3 : IDE_LOGI("Get ub size:%" PRIu64 ", ai core count:%" PRIu64 ", vector core count:%" PRIu64 " on device %u.",
110 : opData_.ubSize, opData_.aiCoreCnt, opData_.vectCoreCnt, deviceId_);
111 3 : return ADUMP_SUCCESS;
112 6 : }
113 :
114 3 : std::unique_ptr<char[]> OperatorPreliminary::LoadBinFile(const std::string &filename, size_t &fileSize) const
115 : {
116 3 : std::string realPath;
117 3 : IDE_CTRL_VALUE_FAILED(FileUtils::FileNameIsReal(filename, realPath) == IDE_DAEMON_OK, return nullptr,
118 : "LoadBinFile failed. The real path is %s.", filename.c_str());
119 :
120 3 : std::ifstream iFile(realPath, std::ios::binary | std::ios::ate);
121 3 : IDE_CTRL_VALUE_FAILED(iFile.is_open(), return nullptr, "Failed to open file: %s", realPath.c_str());
122 :
123 3 : auto pos = iFile.tellg();
124 3 : if (pos <= 0) {
125 0 : IDE_LOGE("Failed to get file size. file: %s, size: %ld", realPath.c_str(), pos);
126 0 : return nullptr;
127 : }
128 3 : fileSize = static_cast<size_t>(pos);
129 3 : iFile.seekg(0, std::ios::beg);
130 3 : char* buffer = new(std::nothrow) char[fileSize];
131 3 : IDE_CTRL_VALUE_FAILED(buffer != nullptr, return nullptr, "Failed to new file buffer");
132 3 : IDE_CTRL_VALUE_FAILED(iFile.read(buffer, fileSize), {delete[] buffer; return nullptr;},
133 : "Failed to read file data. file: %s, size: %ld", filename.c_str(), fileSize);
134 3 : return std::unique_ptr<char []>(buffer);
135 3 : }
136 :
137 3 : int32_t OperatorPreliminary::GetOperatorPCAddr()
138 : {
139 3 : static std::unique_ptr<char[]> binData = nullptr;
140 3 : rtError_t ret = RT_ERROR_NONE;
141 :
142 3 : if (binData == nullptr) {
143 3 : std::string opName = GetBinName();
144 3 : IDE_CTRL_VALUE_FAILED(!opName.empty(), return ADUMP_FAILED, "Failed to find kfc operator file.");
145 :
146 3 : const std::string opPath = LibPath::Instance().GetTargetPath(opName);
147 3 : IDE_CTRL_VALUE_FAILED(!opPath.empty(), return ADUMP_FAILED, "Received an empty path for file %s.", opName.c_str());
148 3 : IDE_CTRL_VALUE_FAILED(FileUtils::IsFileExist(opPath), return ADUMP_FAILED,
149 : "Failed to binary file from %s.", opPath.c_str());
150 :
151 3 : size_t fileSize = 0;
152 3 : binData = LoadBinFile(opPath, fileSize);
153 3 : IDE_CTRL_VALUE_FAILED(binData != nullptr, return ADUMP_FAILED, "Get binary handle failed");
154 :
155 3 : rtDevBinary_t bin{.magic = RT_DEV_BINARY_MAGIC_ELF_AIVEC, .version = 0,
156 3 : .data = static_cast<void*>(binData.get()), .length = fileSize};
157 :
158 3 : ret = rtDevBinaryRegister(&bin, &opData_.binHandle);
159 3 : IDE_CTRL_VALUE_FAILED(ret == RT_ERROR_NONE, return ADUMP_FAILED,
160 : "Failed to parse bin data into handle, ret is %d", ret);
161 :
162 3 : ret = rtFunctionRegister(opData_.binHandle, KFC_OPERATOR_STUB_NAME, KFC_OPERATOR_NAME, KFC_OPERATOR_NAME, 0U);
163 3 : IDE_CTRL_VALUE_FAILED(ret == RT_ERROR_NONE, return ADUMP_FAILED,
164 : "Failed to register handle into stub kernel name %s, ret is %d", KFC_OPERATOR_STUB_NAME, ret);
165 3 : }
166 :
167 3 : ret = rtGetAddrByFun(KFC_OPERATOR_STUB_NAME, &opData_.pcAddr);
168 3 : IDE_CTRL_VALUE_FAILED(ret == RT_ERROR_NONE, return ADUMP_FAILED,
169 : "Failed to get pc addr from stub kernel name %s, ret is %d", KFC_OPERATOR_STUB_NAME, ret);
170 :
171 3 : IDE_LOGI("Success to get pc address %p on device %u.", opData_.pcAddr, deviceId_);
172 3 : return ADUMP_SUCCESS;
173 : }
174 :
175 3 : int32_t OperatorPreliminary::CreateMemory()
176 : {
177 3 : opData_.msgQSize = INTEGER_KILOBYTE * INTEGER_KILOBYTE; // 1M 消息轮询、参数保存、多核同步空间
178 3 : opData_.outputSize = MAX_STATS_NUM * SINGLE_STATS_BYTE;
179 3 : uint64_t statsCnt = 0;
180 195 : for (uint64_t idx = 0; idx < MAX_STATS_NUM; idx++) {
181 192 : if ((setting_.GetDumpStatsItem() & (1LLU << idx)) != 0) {
182 18 : statsCnt++; // 统计项个数
183 : }
184 : }
185 3 : opData_.workspaceSize = CalcWorkspaceSize(statsCnt);
186 3 : opData_.stackBaseSize = CalcStackSize();
187 :
188 3 : IDE_CTRL_VALUE_FAILED(opData_.workspaceSize != 0 && opData_.stackBaseSize != 0, return ADUMP_FAILED,
189 : "The size of the workspaceSize is 0");
190 3 : IDE_LOGI("Calculate MsgQ Size:%" PRIu64 "Byte, output size:%" PRIu64 "Byte, workspace size:%" PRIu64 "Byte,"
191 : "stack base size:%" PRIu64 "Byte on device %u.", opData_.msgQSize, opData_.outputSize,
192 : opData_.workspaceSize, opData_.stackBaseSize, deviceId_);
193 :
194 6 : rtError_t ret = rtMalloc(&opData_.memoryAddr, opData_.msgQSize + opData_.outputSize +
195 3 : opData_.workspaceSize + opData_.stackBaseSize, RT_MEMORY_DEFAULT, AICPU);
196 3 : IDE_CTRL_VALUE_FAILED(ret == RT_ERROR_NONE, return ADUMP_FAILED,
197 : "Execute rtMalloc failed with result %d", ret);
198 3 : IDE_LOGI("Rt malloc success on device %u.", deviceId_);
199 3 : return ADUMP_SUCCESS;
200 : }
201 :
202 3 : int32_t OperatorPreliminary::KFCKernelLaunch()
203 : {
204 3 : IDE_LOGD("Start to init kfc kernel information for device %u.", deviceId_);
205 3 : KfcDumpOpInitParam kfcParam;
206 3 : kfcParam.kfcWorkSpace.msgQ = reinterpret_cast<uint64_t>(opData_.memoryAddr);
207 3 : kfcParam.kfcWorkSpace.msgQSize = opData_.msgQSize;
208 3 : kfcParam.kfcWorkSpace.output = kfcParam.kfcWorkSpace.msgQ + opData_.msgQSize;
209 3 : kfcParam.kfcWorkSpace.outputSize = opData_.outputSize;
210 3 : kfcParam.kfcWorkSpace.workspace = kfcParam.kfcWorkSpace.output + opData_.outputSize;
211 3 : kfcParam.kfcWorkSpace.workspaceSize = opData_.workspaceSize;
212 3 : kfcParam.kfcWorkSpace.stackBase = kfcParam.kfcWorkSpace.workspace + opData_.workspaceSize;
213 3 : kfcParam.kfcWorkSpace.stackBaseSize = opData_.stackBaseSize;
214 :
215 3 : kfcParam.config.aiCoreNum = opData_.aiCoreCnt;
216 3 : kfcParam.config.vectorCoreNum = opData_.vectCoreCnt;
217 3 : kfcParam.config.ubSize = opData_.ubSize;
218 3 : kfcParam.config.dumpStatPcAddr = reinterpret_cast<uint64_t>(opData_.pcAddr);
219 3 : kfcParam.config.statsType = setting_.GetDumpStatsItem();
220 3 : kfcParam.config.chipType = static_cast<uint64_t>(setting_.GetPlatformType());
221 :
222 3 : kfcParam.streamInfo.streamId = opData_.streamId;
223 3 : kfcParam.streamInfo.sqIds = opData_.sqId;
224 3 : kfcParam.streamInfo.cqIds = opData_.cqIds;
225 3 : kfcParam.streamInfo.logicCqIds = opData_.logicCqIds;
226 3 : kfcParam.streamInfo.deviceId = deviceId_;
227 :
228 : rtAicpuArgsEx_t argsInfo;
229 3 : argsInfo.args = static_cast<void*>(&kfcParam);
230 3 : argsInfo.argsSize = sizeof(kfcParam);
231 3 : argsInfo.soNameAddrOffset = static_cast<uint16_t>(offsetof(KfcDumpOpInitParam, soName));
232 3 : argsInfo.kernelNameAddrOffset = static_cast<uint16_t>(offsetof(KfcDumpOpInitParam, kernelName));
233 3 : argsInfo.hostInputInfoPtr = nullptr;
234 3 : argsInfo.kernelOffsetInfoPtr = nullptr;
235 3 : argsInfo.hostInputInfoNum = 0;
236 3 : argsInfo.kernelOffsetInfoNum = 0;
237 3 : argsInfo.isNoNeedH2DCopy = false;
238 :
239 3 : rtError_t ret = rtAicpuKernelLaunchExWithArgs(KERNEL_TYPE_AICPU_KFC, "VectorStats", 1, &argsInfo, nullptr,
240 : nullptr, 0);
241 3 : IDE_CTRL_VALUE_FAILED(ret == RT_ERROR_NONE, return ADUMP_FAILED,
242 : "Failed to launch kernel for KFC, ret is %d", ret);
243 :
244 3 : ret = rtStreamSynchronize(nullptr); // Use the default flow to ensure successful execution.
245 3 : IDE_CTRL_VALUE_FAILED(ret == RT_ERROR_NONE, return ADUMP_FAILED,
246 : "Execute rtStreamSynchronize for kernel launch failed with result %d", ret);
247 :
248 3 : IDE_LOGI("Success to init kfc kernel information on device %u.", deviceId_);
249 3 : return ADUMP_SUCCESS;
250 : }
251 :
252 6 : int32_t OperatorPreliminary::OperatorInit()
253 : {
254 6 : int32_t version = AdumpDsmi::DrvGetAPIVersion();
255 6 : if (version != 0 && version < SUPPORTED_DRV_VERSION) {
256 0 : IDE_LOGW("Current driver version %d does not support this feature.", version);
257 0 : return ADUMP_SUCCESS;
258 : }
259 : // If version is 0, it indicates that the interface is obsolete and the current operator continues to execute.
260 :
261 6 : IDE_LOGI("Prepare to initialize the resources of kfc kernel on device %u.", deviceId_);
262 : do {
263 6 : int32_t ret = GetStreamInfo();
264 6 : IDE_CTRL_VALUE_FAILED_NODO(ret == ADUMP_SUCCESS, break, "OperatorInit fails at GetStreamInfo when executed.");
265 :
266 6 : ret = GetUBSizeAndCoreNum();
267 6 : IDE_CTRL_VALUE_FAILED_NODO(ret == ADUMP_SUCCESS, break,
268 : "OperatorInit fails at GetUBSizeAndCoreNum when executed.");
269 :
270 3 : ret = GetOperatorPCAddr();
271 3 : IDE_CTRL_VALUE_FAILED_NODO(ret == ADUMP_SUCCESS, break,
272 : "OperatorInit fails at GetOperatorPCAddr when executed.");
273 :
274 3 : ret = CreateMemory();
275 3 : IDE_CTRL_VALUE_FAILED_NODO(ret == ADUMP_SUCCESS, break, "OperatorInit fails at CreateMemory when executed.");
276 :
277 3 : ret = KFCKernelLaunch();
278 3 : IDE_CTRL_VALUE_FAILED_NODO(ret == ADUMP_SUCCESS, break, "OperatorInit fails at kernel launch when executed.");
279 3 : return ADUMP_SUCCESS;
280 : } while (0);
281 3 : IDE_LOGW("Start to destroy rt api resources on device %u.", deviceId_);
282 3 : return ADUMP_FAILED;
283 : }
284 :
285 : } // namespace Adx
|