Line data Source code
1 : /**
2 : * Copyright (c) 2026 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 <atomic>
11 :
12 : #include "dump_stats_process.h"
13 : #include "adx_log.h"
14 :
15 : namespace kfc_dump_stats {
16 : static std::atomic<bool> g_isInitialized(false);
17 : static PrintSqeInfo g_printSqeInfo = nullptr;
18 : static AddOneStatDumpTask g_addOneStatDumpTask = nullptr;
19 : uint32_t g_tensorCount = 0;
20 : KfcDumpOpInitParam g_dumpParam;
21 : KfcDumpContext g_dumpContext;
22 : KfcDumpStreamCtx g_kfcDumpStreamInfo;
23 :
24 24 : bool KfcDumpProcess::GetStatsOpInitStatus() { return g_isInitialized; }
25 :
26 54 : void KfcDumpProcess::ResetForTest()
27 : {
28 54 : g_isInitialized = false;
29 54 : g_printSqeInfo = nullptr;
30 54 : g_addOneStatDumpTask = nullptr;
31 54 : g_tensorCount = 0;
32 54 : g_dumpParam = {};
33 54 : g_dumpContext = {};
34 54 : g_kfcDumpStreamInfo = {};
35 54 : }
36 :
37 36 : KfcDumpResult InitSqCqFunction()
38 : {
39 36 : if (g_kfcDumpStreamInfo.chipType == CHIP_DC) {
40 2 : g_addOneStatDumpTask = AddOneStatDumpTaskV2;
41 2 : g_printSqeInfo = KfcDumpPrintf::PrintSqeV2;
42 34 : } else if (g_kfcDumpStreamInfo.chipType == CHIP_CLOUD_V2) {
43 27 : g_addOneStatDumpTask = AddOneStatDumpTaskV1;
44 27 : g_printSqeInfo = KfcDumpPrintf::PrintSqeV1;
45 7 : } else if (g_kfcDumpStreamInfo.chipType == CHIP_CLOUD_V4) {
46 2 : g_addOneStatDumpTask = AddStatDumpTaskCloudV4;
47 2 : g_printSqeInfo = KfcDumpPrintf::PrintSqeCloudV4;
48 5 : } else if (g_kfcDumpStreamInfo.chipType == CHIP_CLOUD_V5) {
49 2 : g_addOneStatDumpTask = AddStatDumpTaskCloudV5;
50 2 : g_printSqeInfo = KfcDumpPrintf::PrintSqeCloudV5;
51 : } else {
52 3 : IDE_LOGE(
53 : "Kfc dump does not support chip type[%u], only chip type[%d,%d,%d,%d] are supported",
54 : g_kfcDumpStreamInfo.chipType, CHIP_DC, CHIP_CLOUD_V2, CHIP_CLOUD_V4, CHIP_CLOUD_V5);
55 3 : return KFC_DUMP_E_NOT_SUPPORT;
56 : }
57 33 : return KFC_DUMP_SUCCESS;
58 : }
59 :
60 47 : KfcDumpResult KfcDumpProcess::InitKfcDumpInfo(KfcDumpOpInitParam* dumpParam)
61 : {
62 47 : KfcDumpPrintf::PrintKfcDumpInitParam(dumpParam);
63 47 : g_isInitialized = false;
64 47 : IDE_CTRL_VALUE_FAILED(
65 : dumpParam->kfcWorkSpace.outputSize >= STAT_LEN, return KFC_DUMP_E_PARA,
66 : "Output buffer size[%lu] is less than the required statistics length[%zu]", dumpParam->kfcWorkSpace.outputSize,
67 : STAT_LEN);
68 : // 不能用 constexpr:vectorCoreNum 是运行期入参。msgQ 布局为
69 : // msgBody + syncSpace(每核 SYNC_SPACE_BYTES_PER_CORE) + 尾部 KfcDumpContext,故下限随核数变化。
70 46 : const uint64_t minMsgQSize =
71 46 : MSG_BODY_SIZE + dumpParam->config.vectorCoreNum * SYNC_SPACE_BYTES_PER_CORE + sizeof(KfcDumpContext);
72 46 : IDE_CTRL_VALUE_FAILED(
73 : dumpParam->kfcWorkSpace.msgQSize >= minMsgQSize, return KFC_DUMP_E_PARA,
74 : "Msg queue size[%lu] is less than the required minimum[%lu]", dumpParam->kfcWorkSpace.msgQSize, minMsgQSize);
75 44 : IDE_CTRL_VALUE_FAILED(
76 : dumpParam->config.vectorCoreNum != 0U && dumpParam->config.ubSize != 0U, return KFC_DUMP_E_PARA,
77 : "Invalid platform config, vectorCoreNum[%lu] and ubSize[%lu] must be positive", dumpParam->config.vectorCoreNum,
78 : dumpParam->config.ubSize);
79 :
80 42 : g_dumpParam = *dumpParam;
81 42 : g_kfcDumpStreamInfo.chipType = g_dumpParam.config.chipType;
82 42 : g_kfcDumpStreamInfo.streamId = g_dumpParam.streamInfo.streamIds;
83 42 : g_kfcDumpStreamInfo.sqId = g_dumpParam.streamInfo.sqIds;
84 42 : g_kfcDumpStreamInfo.cqId = g_dumpParam.streamInfo.cqIds;
85 42 : g_kfcDumpStreamInfo.logicCqId = g_dumpParam.streamInfo.logicCqIds;
86 42 : IDE_CTRL_VALUE_FAILED(
87 : drvGetLocalDevIDByHostDevID != nullptr, return KFC_DUMP_E_NOT_SUPPORT,
88 : "drvGetLocalDevIDByHostDevID is unresolved, driver does not support device id conversion");
89 :
90 42 : drvError_t drvRet = drvGetLocalDevIDByHostDevID(g_dumpParam.streamInfo.deviceId, &(g_kfcDumpStreamInfo.devId));
91 42 : IDE_CTRL_VALUE_FAILED(
92 : drvRet == DRV_ERROR_NONE, return KFC_DUMP_E_DRIVE,
93 : "Failed to convert host device id[%u] to local device id, ret[%d]", g_dumpParam.streamInfo.deviceId,
94 : static_cast<int32_t>(drvRet));
95 : uint64_t sqAddr;
96 41 : DUMP_STATS_CHK_RET(
97 : KfcDumpTaskDispatcher::QuerySqBaseAddr(g_kfcDumpStreamInfo.devId, g_kfcDumpStreamInfo.sqId, sqAddr));
98 40 : g_kfcDumpStreamInfo.sqBaseAddr = reinterpret_cast<void*>(sqAddr);
99 40 : DUMP_STATS_CHK_RET(KfcDumpTaskDispatcher::QuerySqStatusByType(
100 : g_kfcDumpStreamInfo.devId, g_kfcDumpStreamInfo.sqId, DRV_SQCQ_PROP_SQ_DEPTH, g_kfcDumpStreamInfo.sqDepth));
101 39 : IDE_CTRL_VALUE_FAILED(
102 : g_kfcDumpStreamInfo.sqDepth != 0U, return KFC_DUMP_E_DRIVE,
103 : "Invalid sq depth[0] queried from driver, devId[%u] sqId[%u]", g_kfcDumpStreamInfo.devId,
104 : g_kfcDumpStreamInfo.sqId);
105 :
106 38 : DUMP_STATS_CHK_RET(KfcDumpTaskDispatcher::QuerySqStatusByType(
107 : g_kfcDumpStreamInfo.devId, g_kfcDumpStreamInfo.sqId, DRV_SQCQ_PROP_SQ_HEAD, g_kfcDumpStreamInfo.sqHead));
108 37 : DUMP_STATS_CHK_RET(KfcDumpTaskDispatcher::QuerySqStatusByType(
109 : g_kfcDumpStreamInfo.devId, g_kfcDumpStreamInfo.sqId, DRV_SQCQ_PROP_SQ_TAIL, g_kfcDumpStreamInfo.sqTail));
110 36 : KfcDumpPrintf::PrintKfcDumpStreamCtx(&g_kfcDumpStreamInfo);
111 36 : DUMP_STATS_CHK_RET(InitSqCqFunction());
112 33 : g_isInitialized = true;
113 33 : IDE_LOGI("Success to initialize the kfc dump server");
114 33 : return KFC_DUMP_SUCCESS;
115 : }
116 :
117 32 : KfcDumpResult KfcDumpProcess::GetAivDumpContext()
118 : {
119 32 : g_dumpContext.msgQ = g_dumpParam.kfcWorkSpace.msgQ;
120 32 : g_dumpContext.workspace = g_dumpParam.kfcWorkSpace.workspace;
121 32 : g_dumpContext.workspaceSize = g_dumpParam.kfcWorkSpace.workspaceSize;
122 32 : g_dumpContext.aiCoreNum = g_dumpParam.config.vectorCoreNum;
123 32 : g_dumpContext.ubSize = g_dumpParam.config.ubSize;
124 32 : g_dumpContext.syncSpace = g_dumpParam.kfcWorkSpace.msgQ + MSG_BODY_SIZE;
125 64 : errno_t ret = memset_s(
126 32 : reinterpret_cast<uint8_t*>(g_dumpParam.kfcWorkSpace.msgQ),
127 32 : static_cast<size_t>(g_dumpParam.kfcWorkSpace.msgQSize), 0,
128 32 : static_cast<size_t>(g_dumpParam.kfcWorkSpace.msgQSize));
129 32 : if (ret != EOK) {
130 0 : IDE_LOGE("Failed to reset kfc dump message queue, ret[%d]", ret);
131 0 : return KFC_DUMP_E_MEMORY;
132 : }
133 32 : return KFC_DUMP_SUCCESS;
134 : }
135 :
136 43 : KfcDumpResult KfcDumpProcess::PostDumpResults(OpStatsResult& opStatsResult, KfcDumpTask* dumpTask, uint32_t resultNum)
137 : {
138 43 : if (AicpuDumpOpTaskData == nullptr) {
139 0 : IDE_LOGE("AicpuDumpOpTaskData is unresolved, statistics result cannot be reported");
140 0 : return KFC_DUMP_E_NOT_SUPPORT;
141 : }
142 43 : auto dumpOpTaskDataStartTime = GetCurCpuTimestamp();
143 43 : opStatsResult.tensorNum = resultNum;
144 43 : uint32_t ret = AicpuDumpOpTaskData(*dumpTask, &opStatsResult, sizeof(OpStatsResult));
145 43 : if (ret != 0) {
146 1 : IDE_LOGE("Failed to report statistics result to aicpu scheduler, ret[%u]", ret);
147 1 : return KFC_DUMP_E_INTERNAL;
148 : }
149 42 : IDE_LOGI(
150 : "Report[%u] statistics results, time cost[%lu us]", resultNum,
151 : (GetCurCpuTimestamp() - dumpOpTaskDataStartTime) / NSEC_PER_USEC);
152 42 : return KFC_DUMP_SUCCESS;
153 : }
154 :
155 32 : KfcDumpResult KfcDumpProcess::FillAivArgs(KfcDumpContext* kfcAivArgs)
156 : {
157 32 : g_dumpContext.workspaceSizeAddr = reinterpret_cast<uint64_t>(&kfcAivArgs->workspaceSize);
158 32 : g_dumpContext.aiCoreNumAddr = reinterpret_cast<uint64_t>(&kfcAivArgs->aiCoreNum);
159 32 : g_dumpContext.ubSizeAddr = reinterpret_cast<uint64_t>(&kfcAivArgs->ubSize);
160 32 : errno_t ret = memcpy_s(kfcAivArgs, sizeof(KfcDumpContext), &g_dumpContext, sizeof(KfcDumpContext));
161 32 : if (ret != EOK) {
162 0 : IDE_LOGE("Failed to fill statistics operator arguments, ret[%d]", ret);
163 0 : return KFC_DUMP_E_MEMORY;
164 : }
165 32 : KfcDumpPrintf::PrintDumpContext(kfcAivArgs);
166 32 : return KFC_DUMP_SUCCESS;
167 : }
168 :
169 30 : KfcDumpResult KfcDumpProcess::WaitTaskFinish()
170 : {
171 30 : uint32_t curSqHead = g_kfcDumpStreamInfo.sqHead;
172 30 : auto waitTaskTimeStart = GetCurCpuTimestamp();
173 60 : while (g_kfcDumpStreamInfo.sqHead <= curSqHead) {
174 30 : DUMP_STATS_CHK_RET(KfcDumpTaskDispatcher::QuerySqStatusByType(
175 : g_kfcDumpStreamInfo.devId, g_kfcDumpStreamInfo.sqId, DRV_SQCQ_PROP_SQ_HEAD, g_kfcDumpStreamInfo.sqHead));
176 30 : if ((curSqHead == (g_kfcDumpStreamInfo.sqDepth - 1)) && g_kfcDumpStreamInfo.sqHead == 0) {
177 0 : IDE_LOGD("Sq head wrapped around to[%u]", g_kfcDumpStreamInfo.sqHead);
178 0 : break;
179 : }
180 30 : if (CheckTimeOut(waitTaskTimeStart) != KFC_DUMP_SUCCESS) {
181 0 : IDE_LOGE(
182 : "Wait for statistics task finish timeout, devId[%u] sqId[%u] sqHead[%u]", g_kfcDumpStreamInfo.devId,
183 : g_kfcDumpStreamInfo.sqId, g_kfcDumpStreamInfo.sqHead);
184 0 : return KFC_DUMP_E_TIMEOUT;
185 : }
186 : }
187 30 : IDE_LOGI("Statistics dump task finished, sqHead[%u]", g_kfcDumpStreamInfo.sqHead);
188 30 : return KFC_DUMP_SUCCESS;
189 : }
190 :
191 34 : KfcDumpResult KfcDumpProcess::KfcDumpRunStatServer(KfcDumpTask* dumpTask, KfcDumpInfo* dumpInfo)
192 : {
193 34 : if (!g_isInitialized) {
194 1 : IDE_LOGE("Kfc dump server is not initialized, cannot launch dump statistics task");
195 1 : return KFC_DUMP_E_INTERNAL;
196 : }
197 :
198 33 : OpStatsResult dumpResult = {};
199 33 : dumpResult.statItem = g_dumpParam.config.statsType;
200 33 : uint32_t tensorNum = dumpInfo->inputDumpInfo.size() + dumpInfo->outputDumpInfo.size();
201 33 : if (tensorNum == 0) {
202 1 : return KFC_DUMP_SUCCESS;
203 : }
204 32 : IDE_LOGI("Kfc dump server received %u tensors to dump", tensorNum);
205 32 : DUMP_STATS_CHK_RET(GetAivDumpContext());
206 : static KfcDumpStatsServer dump;
207 32 : dump.Init(g_dumpParam.kfcWorkSpace.msgQ);
208 :
209 32 : if (g_addOneStatDumpTask == nullptr || g_printSqeInfo == nullptr) {
210 0 : IDE_LOGE("Sqe construct function is null, chip type may be unsupported");
211 0 : return KFC_DUMP_E_INTERNAL;
212 : }
213 32 : uint8_t sqeBuffer[AC_SQE_SIZE] = {0};
214 : // msgQ长度1M,后半部分(+0x800)分配给syncSpace,尾部72B(KfcDumpContext)分配给kfc算子作为输入参数
215 32 : KfcDumpContext* kfcStatOpArgs = reinterpret_cast<KfcDumpContext*>(
216 32 : g_dumpParam.kfcWorkSpace.msgQ + g_dumpParam.kfcWorkSpace.msgQSize - sizeof(KfcDumpContext));
217 32 : DUMP_STATS_CHK_RET(FillAivArgs(kfcStatOpArgs));
218 : // 根据不同的芯片类型构造Sqe参数
219 32 : g_addOneStatDumpTask(sqeBuffer, &g_dumpParam, kfcStatOpArgs);
220 32 : g_printSqeInfo(sqeBuffer);
221 : // 下发Sqe拉起kfc算子
222 32 : DUMP_STATS_CHK_RET(KfcDumpTaskDispatcher::LaunchTask(sqeBuffer, &g_kfcDumpStreamInfo));
223 :
224 : // 算子已拉起:此后无论统计阶段成败,都必须发 FINISHED 让 AIV 退出循环,
225 : // 否则该实例永久占核,且下一次 Launch 拉起的新实例会与它争抢同一消息队列。
226 30 : KfcDumpResult statsRet = RunStatsExchange(dumpTask, dumpInfo, dump, dumpResult, tensorNum);
227 30 : KfcDumpResult finishRet = FinishStatsTask(dump);
228 : // 保留首个业务错误码,避免被收尾结果掩盖
229 30 : return (statsRet != KFC_DUMP_SUCCESS) ? statsRet : finishRet;
230 : }
231 :
232 30 : KfcDumpResult KfcDumpProcess::RunStatsExchange(
233 : KfcDumpTask* dumpTask, KfcDumpInfo* dumpInfo, KfcDumpStatsServer& dump, OpStatsResult& dumpResult,
234 : uint32_t tensorNum)
235 : {
236 : // 通知kfc算子做tensor统计任务。
237 30 : g_tensorCount = 0;
238 30 : DUMP_STATS_CHK_RET(
239 : KfcDumpStatClientProcess(dumpTask, dumpInfo->inputDumpInfo, dump, dumpResult, TENSOR_TYPE_INPUT));
240 23 : DUMP_STATS_CHK_RET(
241 : KfcDumpStatClientProcess(dumpTask, dumpInfo->outputDumpInfo, dump, dumpResult, TENSOR_TYPE_OUTPUT));
242 :
243 : // 未满STEP上报给aicpu
244 23 : if (tensorNum % STEP_COUNT != 0) {
245 0 : DUMP_STATS_CHK_RET(PostDumpResults(dumpResult, dumpTask, tensorNum % STEP_COUNT));
246 : }
247 23 : return KFC_DUMP_SUCCESS;
248 : }
249 :
250 30 : KfcDumpResult KfcDumpProcess::FinishStatsTask(KfcDumpStatsServer& dump)
251 : {
252 : // 通知kfc算子结束退出
253 30 : IDE_LOGD("All tensor dump finished, unlaunch dump statistics task");
254 30 : KfcDumpStatsMsg gMsg = {};
255 30 : gMsg.msgType = DumpStatMsgType::KFC_DUMP_MSG_FINISHED;
256 : // PostMsg 失败也要继续 WaitTaskFinish:AIV 可能已消费到 FINISHED 而仅是本次投递超时,
257 : // 直接返回会漏掉等待,使下一次 Launch 与未退出的实例重叠。
258 30 : KfcDumpResult postRet = dump.PostMsg(&gMsg);
259 30 : if (postRet != KFC_DUMP_SUCCESS) {
260 0 : IDE_LOGE("Failed to post KFC_DUMP_MSG_FINISHED, result=%d", postRet);
261 : }
262 30 : KfcDumpResult waitRet = KfcDumpProcess::WaitTaskFinish();
263 60 : return (postRet != KFC_DUMP_SUCCESS) ? postRet : waitRet;
264 : }
265 :
266 53 : KfcDumpResult KfcDumpProcess::KfcDumpStatClientProcess(
267 : KfcDumpTask* dumpTask, const std::vector<InputOutputKfcDumpInfo>& dumpTensorList, KfcDumpStatsServer& dump,
268 : OpStatsResult& dumpResult, TensorType tensorType)
269 : {
270 53 : if (dumpTensorList.size() == 0) {
271 4 : IDE_LOGW(
272 : "No tensor in this task, streamId=%u, taskId=%u, index=%u, tensorType=%u", dumpTask->streamId_,
273 : dumpTask->taskId_, dumpTask->index_, static_cast<uint32_t>(tensorType));
274 4 : return KFC_DUMP_SUCCESS;
275 : }
276 :
277 49 : KfcDumpStatsMsg gMsg = {};
278 478 : for (size_t tensorIndex = 0; tensorIndex < dumpTensorList.size(); tensorIndex++) {
279 436 : const auto& dumpTensor = dumpTensorList[tensorIndex];
280 436 : gMsg.msgType = DumpStatMsgType::KFC_DUMP_MSG_REQUEST;
281 436 : gMsg.dataType = dumpTensor.data_type;
282 436 : gMsg.dataCount = dumpTensor.size;
283 436 : gMsg.dataAddr = dumpTensor.address;
284 436 : gMsg.dumpStatClass = g_dumpParam.config.statsType;
285 436 : gMsg.outputAddr = g_dumpParam.kfcWorkSpace.output;
286 436 : gMsg.outputAddrSize = g_dumpParam.kfcWorkSpace.outputSize;
287 436 : KfcDumpPrintf::PrintMsg(gMsg);
288 436 : uint64_t computeStartTime = GetCurCpuTimestamp();
289 436 : DUMP_STATS_CHK_RET(dump.PostMsg(&gMsg));
290 436 : DUMP_STATS_CHK_RET(dump.RcvMsg(&gMsg));
291 435 : IDE_LOGI(
292 : "Aiv statistics computation finished, time cost[%lu us]",
293 : (GetCurCpuTimestamp() - computeStartTime) / NSEC_PER_USEC);
294 435 : KfcDumpPrintf::PrintMsg(gMsg);
295 435 : if (gMsg.msgType != KFC_DUMP_MSG_RESPONSE) {
296 3 : IDE_LOGW("Received unexpected msgType[%u], expect KFC_DUMP_MSG_RESPONSE[2]", gMsg.msgType);
297 3 : return KFC_DUMP_E_PARA;
298 : }
299 432 : dump.CheckDumpResult(&gMsg);
300 432 : DUMP_STATS_CHK_RET(
301 : UpdateDumpResult(dumpTensor, dumpResult.stat[g_tensorCount % STEP_COUNT], &gMsg, tensorType));
302 430 : g_tensorCount++;
303 : // 满STEP上报给aicpu
304 430 : if (g_tensorCount % STEP_COUNT == 0) {
305 43 : DUMP_STATS_CHK_RET(PostDumpResults(dumpResult, dumpTask, STEP_COUNT));
306 : }
307 : }
308 42 : return KFC_DUMP_SUCCESS;
309 : }
310 :
311 432 : KfcDumpResult KfcDumpProcess::UpdateDumpResult(
312 : const InputOutputKfcDumpInfo& dumpTensor, TensorStatsResult& statsResult, KfcDumpStatsMsg* gMsg,
313 : TensorType tensorType)
314 : {
315 432 : IDE_LOGI("Update statistics result of one tensor");
316 432 : if (dumpTensor.shape.size() > SHAPE_SIZE) {
317 2 : IDE_LOGE(
318 : "Tensor shape size[%zu] exceeds the upper limit[%u], index[%d]", dumpTensor.shape.size(), SHAPE_SIZE,
319 : dumpTensor.index);
320 2 : return KFC_DUMP_E_PARA;
321 : }
322 430 : if (gMsg->outputAddr != g_dumpParam.kfcWorkSpace.output) {
323 0 : IDE_LOGE(
324 : "Aiv returned unexpected output address, expect[0x%lx] actual[0x%lx]", g_dumpParam.kfcWorkSpace.output,
325 : gMsg->outputAddr);
326 0 : return KFC_DUMP_E_PARA;
327 : }
328 430 : statsResult.size = gMsg->dataCount;
329 430 : statsResult.dType = gMsg->dataType;
330 430 : statsResult.format = dumpTensor.format;
331 430 : statsResult.shapeSize = static_cast<int32_t>(dumpTensor.shape.size());
332 2160 : for (size_t index = 0; index < dumpTensor.shape.size(); ++index) {
333 1730 : statsResult.shape[index] = static_cast<uint32_t>(dumpTensor.shape[index]);
334 : }
335 430 : statsResult.result = gMsg->result;
336 430 : statsResult.statsLen = STAT_LEN;
337 430 : statsResult.io = static_cast<int32_t>(tensorType);
338 430 : statsResult.index = dumpTensor.index;
339 430 : IDE_LOGD(
340 : "dataSize[%ld] dataType[%u] shapeSize[%d] tensorType[%u] index[%d]", statsResult.size, statsResult.dType,
341 : statsResult.shapeSize, static_cast<uint32_t>(tensorType), statsResult.index);
342 860 : errno_t ret = memcpy_s(
343 430 : reinterpret_cast<uint8_t*>(statsResult.stats), STAT_LEN,
344 430 : reinterpret_cast<uint8_t*>(g_dumpParam.kfcWorkSpace.output), STAT_LEN);
345 430 : if (ret != EOK) {
346 0 : IDE_LOGE("Failed to copy statistics data to result buffer, ret[%d]", ret);
347 0 : return KFC_DUMP_E_MEMORY;
348 : }
349 430 : return KFC_DUMP_SUCCESS;
350 : }
351 : } // namespace kfc_dump_stats
|