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 :
11 : #include "ccu_launch.h"
12 :
13 : #include <algorithm>
14 : #include <iterator>
15 : #include <limits>
16 : #include <memory>
17 : #include <utility>
18 : #include <vector>
19 :
20 : #include "adapter_rts_common.h"
21 : #include "ccu_res.h"
22 :
23 : #include "ccu_log.h"
24 :
25 : #include "hcom_common.h"
26 :
27 : #include "ccu_kernel_mgr.h"
28 : #include "ccu_instance_mgr.h"
29 : #include "ccu_var_event_res_mgr.h"
30 :
31 : #include "thread.h"
32 :
33 : #include "env_config/env_config_v2.h" // 暂时引用orion的环境变量处理模块
34 :
35 : #include "hcomm_adapter_rts.h"
36 :
37 : #include "task_param.h"
38 :
39 : #include "ccu_assist_v1.h"
40 :
41 : #include "unified_platform/pub_inc/config_plf_log.h"
42 : using Hccl::PLF_TASK;
43 :
44 55 : CcuResult HcommCcuKernelRegisterStart(CcuInsHandle insHandle)
45 : {
46 55 : const uint32_t devLogicId = HcclGetThreadDeviceId();
47 55 : auto* ccuIns = hcomm::CcuInstanceMgr::GetInstance(devLogicId).Get(insHandle);
48 55 : CCU_CHK_PTR_NULL(ccuIns);
49 :
50 55 : CCU_CHK_RET(ccuIns->BeginRegister());
51 :
52 55 : CcuResult ret = ccuIns->Reset();
53 55 : if (ret != CcuResult::CCU_SUCCESS) {
54 0 : (void)ccuIns->EndRegister();
55 0 : HCCL_ERROR("[%s] failed, Reset failed[%d], rollback register state.", __func__, ret);
56 0 : return ret;
57 : }
58 55 : return CcuResult::CCU_SUCCESS;
59 : }
60 :
61 55 : static CcuResult CcuKernelTryRegister(
62 : hcomm::CcuInstance* ccuIns, hcomm::CcuResPack* resPack, uint32_t devLogicId, uint32_t dieId,
63 : const char* kernelFuncName, const void* kernelFunc, const void** kernelArgs, uint32_t argNum,
64 : CcuKernelHandle& newHandle)
65 : {
66 : CCU_EXCEPTION_HANDLE_BEGIN
67 55 : auto& kernelMgr = hcomm::CcuKernelMgr::GetInstance(devLogicId);
68 55 : CCU_CHK_RET(kernelMgr.Register(*resPack, dieId, kernelFuncName, kernelFunc, kernelArgs, argNum, newHandle));
69 44 : CCU_CHK_RET(ccuIns->SaveKernel(newHandle));
70 8 : CCU_EXCEPTION_HANDLE_END
71 44 : return CcuResult::CCU_SUCCESS;
72 : }
73 :
74 55 : CcuResult HcommCcuKernelRegister(
75 : CcuInsHandle insHandle, uint32_t dieId, const char* kernelFuncName, const void* kernelFunc, const void** kernelArgs,
76 : uint32_t argNum, CcuKernelHandle* kernelHandle)
77 : {
78 55 : HCCL_RUN_INFO("Entry-%s", __func__);
79 55 : HcclUs startut = TIME_NOW();
80 :
81 55 : CCU_CHK_PTR_NULL(kernelFunc);
82 55 : CCU_CHK_PTR_NULL(kernelHandle);
83 :
84 55 : if (argNum != 0) {
85 55 : CCU_CHK_PTR_NULL(kernelArgs);
86 : }
87 :
88 55 : const uint32_t devLogicId = HcclGetThreadDeviceId();
89 55 : auto* ccuIns = hcomm::CcuInstanceMgr::GetInstance(devLogicId).Get(insHandle);
90 55 : CCU_CHK_PTR_NULL(ccuIns);
91 :
92 55 : CCU_CHK_RET(ccuIns->CheckRegistering());
93 :
94 55 : auto* resPack = ccuIns->GetResPack();
95 55 : CCU_CHK_PTR_NULL(resPack);
96 :
97 55 : CcuKernelHandle newHandle{0};
98 55 : CcuResult ret = CcuKernelTryRegister(
99 : ccuIns, resPack, devLogicId, dieId, kernelFuncName, kernelFunc, kernelArgs, argNum, newHandle);
100 55 : if (ret != CcuResult::CCU_SUCCESS) {
101 11 : ccuIns->AbortRegister();
102 11 : if (CCU_CHK_RES_UNAVAIL(ret)) {
103 0 : HCCL_WARNING(
104 : "[%s] register kernel resource unavailable[%d], current register round aborted.", __func__, ret);
105 0 : return CcuResult::CCU_E_UNAVAIL;
106 : } else {
107 11 : HCCL_ERROR("[%s] failed, register kernel failed[%d], current register round aborted.", __func__, ret);
108 11 : return ret;
109 : }
110 : }
111 :
112 44 : *kernelHandle = newHandle;
113 44 : HCCL_INFO("[%s] success, take time [%lld]us.", __func__, DURATION_US(TIME_NOW() - startut).count());
114 44 : return CcuResult::CCU_SUCCESS;
115 : }
116 :
117 45 : CcuResult HcommCcuKernelRegisterEnd(CcuInsHandle insHandle)
118 : {
119 45 : const uint32_t devLogicId = HcclGetThreadDeviceId();
120 45 : auto* ccuIns = hcomm::CcuInstanceMgr::GetInstance(devLogicId).Get(insHandle);
121 45 : CCU_CHK_PTR_NULL(ccuIns);
122 :
123 45 : CCU_CHK_RET(ccuIns->EndRegister());
124 45 : const auto& newKernels = ccuIns->GetUntranslatedKernels();
125 :
126 45 : auto& kernelMgr = hcomm::CcuKernelMgr::GetInstance(devLogicId);
127 : // 当前翻译内部流程可能抛异常
128 : CCU_EXCEPTION_HANDLE_BEGIN
129 45 : CCU_CHK_RET(kernelMgr.Translate(newKernels));
130 0 : CCU_EXCEPTION_HANDLE_END
131 :
132 44 : return CcuResult::CCU_SUCCESS;
133 : }
134 :
135 5 : CcuResult HcommCcuGetTaskArgsNum(CcuKernelHandle kernelHandle, uint32_t* taskArgsNum)
136 : {
137 5 : HCCL_INFO("Entry-%s", __func__);
138 5 : CCU_CHK_PTR_NULL(taskArgsNum);
139 :
140 4 : const uint32_t devLogicId = HcclGetThreadDeviceId();
141 4 : auto& kernelMgr = hcomm::CcuKernelMgr::GetInstance(devLogicId);
142 :
143 4 : hcomm::CcuKernelInfo info{};
144 4 : CCU_CHK_RET(kernelMgr.GetCcuKernelInfo(kernelHandle, info));
145 :
146 3 : *taskArgsNum = info.maxTaskArgsNum;
147 3 : HCCL_INFO("[%s] success, kernelHandle[%llx], taskArgsNum[%u].", __func__, kernelHandle, *taskArgsNum);
148 3 : return CcuResult::CCU_SUCCESS;
149 : }
150 :
151 : static std::shared_ptr<std::vector<Hccl::CcuProfilingInfo>>
152 5 : ConstructCcuDetailInfo(const std::vector<hcomm::CcuProfilingInfo>& allCcuProfilingInfo, bool isSaveProfilingData)
153 : {
154 5 : if (allCcuProfilingInfo.empty() || !isSaveProfilingData) {
155 5 : return nullptr;
156 : }
157 :
158 0 : std::vector<Hccl::CcuProfilingInfo> converted(allCcuProfilingInfo.size());
159 0 : for (u32 idx = 0; idx < allCcuProfilingInfo.size(); ++idx) {
160 0 : auto& src = allCcuProfilingInfo[idx];
161 0 : auto& dst = converted[idx];
162 0 : dst.name = src.name;
163 0 : dst.type = src.type;
164 0 : dst.dieId = src.dieId;
165 0 : dst.missionId = src.missionId;
166 0 : dst.instrId = src.instrId;
167 0 : dst.reduceOpType = src.reduceOpType;
168 0 : dst.inputDataType = src.inputDataType;
169 0 : dst.outputDataType = src.outputDataType;
170 0 : dst.dataSize = src.dataSize;
171 0 : dst.ckeId = src.ckeId;
172 0 : dst.mask = src.mask;
173 0 : (void)memcpy_s(dst.channelId, sizeof(dst.channelId), src.channelId, sizeof(src.channelId));
174 0 : (void)memcpy_s(dst.channelHandle, sizeof(dst.channelHandle), src.channelHandle, sizeof(src.channelHandle));
175 : }
176 0 : return std::make_shared<std::vector<Hccl::CcuProfilingInfo>>(std::move(converted));
177 0 : }
178 :
179 8 : static Hccl::TaskParam ConstructCcuTaskParam(
180 : const hcomm::CcuTaskParam& ccuParam, const CcuKernelHandle kernelHandle,
181 : const std::shared_ptr<std::vector<Hccl::CcuProfilingInfo>>& ccuDetailInfo, u64 beginTime, u64 endTime,
182 : bool isMaster)
183 : {
184 8 : Hccl::TaskParam taskParam{};
185 8 : taskParam.beginTime = beginTime;
186 8 : taskParam.endTime = endTime;
187 8 : taskParam.taskType = Hccl::TaskParamType::TASK_CCU;
188 8 : taskParam.taskPara.Ccu.dieId = ccuParam.dieId;
189 8 : taskParam.taskPara.Ccu.missionId = ccuParam.missionId;
190 8 : taskParam.taskPara.Ccu.execMissionId = ccuParam.missionId;
191 8 : taskParam.taskPara.Ccu.instrId = ccuParam.instStartId;
192 8 : taskParam.taskPara.Ccu.executeId = kernelHandle;
193 8 : taskParam.taskPara.Ccu.ccuKernelHandle = kernelHandle;
194 8 : taskParam.isMaster = isMaster;
195 8 : taskParam.ccuDetailInfo = ccuDetailInfo;
196 8 : return taskParam;
197 : }
198 :
199 5 : static void LogCcuTaskInfo(const std::vector<hcomm::CcuTaskParam>& ccuParams, const CcuKernelHandle kernelHandle)
200 : {
201 5 : if (!HcclCheckLogLevel(HCCL_LOG_INFO)) {
202 0 : return;
203 : }
204 5 : const uint32_t execTimeOutSec = Hccl::EnvConfig::GetInstance().GetRtsConfig().GetExecTimeOut();
205 13 : for (u32 idx = 0; idx < ccuParams.size(); idx++) {
206 8 : const auto& param = ccuParams[idx];
207 8 : PLF_CONFIG_INFO(
208 : PLF_TASK,
209 : "[%s] start ccu task, dieId[%u], missionId[%u], execMissionId[%u], instStartId[%u], instCnt[%u], "
210 : "argSize[%u], timeout[%u]s, executeId[0x%llx], ccuKernelHandle[0x%llx]",
211 : __func__, param.dieId, param.missionId, param.missionId, param.instStartId, param.instCnt, param.argSize,
212 : execTimeOutSec, kernelHandle, kernelHandle);
213 : }
214 : }
215 :
216 0 : static void ConstructProfilingInfoLog(const std::vector<hcomm::CcuProfilingInfo>& allCcuProfilingInfo)
217 : {
218 0 : if (!HcclCheckLogLevel(HCCL_LOG_INFO)) {
219 0 : return;
220 : }
221 0 : for (const hcomm::CcuProfilingInfo& profInfo : allCcuProfilingInfo) {
222 0 : for (int idx = 0; idx < hcomm::CCU_MAX_CHANNEL_NUM; idx++) {
223 0 : if (profInfo.channelId[idx] == hcomm::INVALID_VALUE_CHANNELID) {
224 0 : break;
225 : }
226 0 : HCCL_INFO(
227 : "[%s]idx[%d]: channelId[%u], channelHandle[0x%llx]", __func__, idx, profInfo.channelId[idx],
228 : profInfo.channelHandle[idx]);
229 : }
230 : }
231 : }
232 :
233 5 : static CcuResult ConstructProfilingInfo(
234 : hcomm::CcuKernel* kernel, const uint64_t* taskArgs, uint32_t argNum,
235 : std::vector<hcomm::CcuProfilingInfo>& allCcuProfilingInfo, bool isSaveProfilingData)
236 : {
237 5 : if (!isSaveProfilingData) {
238 5 : return CcuResult::CCU_SUCCESS;
239 : }
240 :
241 0 : CCU_CHK_RET(kernel->GetCcuProfilingInfo(taskArgs, argNum, allCcuProfilingInfo));
242 0 : if (allCcuProfilingInfo.empty()) {
243 0 : return CcuResult::CCU_SUCCESS;
244 : }
245 0 : ConstructProfilingInfoLog(allCcuProfilingInfo);
246 0 : return CcuResult::CCU_SUCCESS;
247 : }
248 :
249 8 : static CcuResult ReportCcuTaskDfx(const ThreadHandle threadHandle, const Hccl::TaskParam& taskParam)
250 : {
251 8 : auto* rtsThread = reinterpret_cast<hccl::Thread*>(threadHandle);
252 8 : CCU_CHK_PTR_NULL(rtsThread);
253 :
254 8 : auto callback = rtsThread->GetCallback();
255 8 : if (!callback) {
256 8 : HCCL_WARNING("[%s] task info callback is not registered on thread, skip ccu profiling report.", __func__);
257 8 : return CcuResult::CCU_SUCCESS;
258 : }
259 0 : u32 streamId = INVALID_UINT;
260 0 : u32 taskId = INVALID_UINT;
261 0 : CCU_CHK_RET(hrtGetTaskIdAndStreamID(taskId, streamId));
262 0 : CCU_CHK_RET(callback(streamId, taskId, taskParam, DFX_INVALID_U64));
263 0 : return CcuResult::CCU_SUCCESS;
264 8 : }
265 :
266 8 : static HcclResult LaunchCcuTasks(const hcomm::CcuTaskParam& param, const aclrtStream stream)
267 : {
268 8 : const uint32_t execTimeOutSec = Hccl::EnvConfig::GetInstance().GetRtsConfig().GetExecTimeOut();
269 8 : rtCcuTaskInfo_t taskInfo{};
270 8 : taskInfo.dieId = param.dieId;
271 8 : taskInfo.missionId = param.missionId;
272 8 : taskInfo.instStartId = param.instStartId;
273 8 : taskInfo.instCnt = param.instCnt;
274 8 : taskInfo.key = param.key;
275 8 : taskInfo.argSize = param.argSize;
276 8 : taskInfo.timeout = execTimeOutSec >= std::numeric_limits<u16>::max() ? std::numeric_limits<u16>::max() :
277 : static_cast<u16>(execTimeOutSec);
278 24 : std::copy(std::begin(param.args), std::end(param.args), std::begin(taskInfo.args));
279 :
280 8 : auto ret = rtCCULaunch(&taskInfo, stream);
281 8 : if (ret != RT_ERROR_NONE) {
282 0 : HCCL_ERROR("[%s] failed to launch ccu, ret[%d]", __func__, ret);
283 0 : return HcclResult::HCCL_E_RUNTIME;
284 : }
285 :
286 8 : return HcclResult::HCCL_SUCCESS;
287 : }
288 :
289 : CcuResult
290 5 : HcommCcuKernelLaunch(ThreadHandle threadHandle, CcuKernelHandle kernelHandle, const void* taskArgs, uint32_t argNum)
291 : {
292 5 : const auto& startus = TIME_NOW();
293 :
294 5 : CHK_PRT_RET(threadHandle == 0, HCCL_ERROR("[%s] failed, thread handle is empty.", __func__), CcuResult::CCU_E_PARA);
295 5 : CHK_PRT_RET(kernelHandle == 0, HCCL_ERROR("[%s] failed, kernel handle is empty.", __func__), CcuResult::CCU_E_PARA);
296 5 : CHK_PRT_RET(
297 : argNum > 0 && taskArgs == nullptr,
298 : HCCL_ERROR("[%s] failed, taskArgs is nullptr while argNum[%u] > 0.", __func__, argNum), CcuResult::CCU_E_PTR);
299 :
300 5 : PLF_CONFIG_INFO(
301 : PLF_TASK, "[HcommCcuKernelLaunch] threadHandle[0x%llx] kernelHandle[0x%llx].", threadHandle, kernelHandle);
302 :
303 5 : const auto* rtsThread = reinterpret_cast<hccl::Thread*>(threadHandle);
304 5 : const auto* threadStream = rtsThread->GetStream();
305 5 : CCU_CHK_PTR_NULL(threadStream);
306 5 : auto* streamPtr = threadStream->ptr();
307 5 : CCU_CHK_PTR_NULL(streamPtr);
308 :
309 5 : const uint32_t devLogicId = HcclGetThreadDeviceId();
310 5 : auto& kernelMgr = hcomm::CcuKernelMgr::GetInstance(devLogicId);
311 5 : auto* kernel = kernelMgr.GetKernel(kernelHandle);
312 5 : CCU_CHK_PTR_NULL(kernel);
313 :
314 : CCU_EXCEPTION_HANDLE_BEGIN
315 5 : std::vector<hcomm::CcuTaskParam> taskParams{};
316 5 : auto ret = kernel->GeneTaskParams(static_cast<const uint64_t*>(taskArgs), argNum, taskParams);
317 5 : CHK_PRT_RET(
318 : ret != CcuResult::CCU_SUCCESS,
319 : HCCL_ERROR("[%s] failed, threadHandle[0x%llx] kernelHandle[0x%llx].", __func__, threadHandle, kernelHandle),
320 : ret);
321 :
322 5 : if (taskParams.empty()) {
323 0 : HCCL_INFO("[%s] passed, ccu params are empty.", __func__);
324 0 : return CcuResult::CCU_SUCCESS;
325 : }
326 5 : bool isProfilingEnabledL1 = Hccl::ProfilingHandler::GetInstance().GetHcclL1State();
327 5 : bool isProfilingEnabledL0 = Hccl::ProfilingHandler::GetInstance().GetHcclL0State();
328 5 : bool isCached = Hccl::ProfilingHandler::GetInstance().GetCachedFlag();
329 5 : bool isSaveProfilingData = isProfilingEnabledL1 || isProfilingEnabledL0 || isCached;
330 :
331 5 : std::vector<hcomm::CcuProfilingInfo> allCcuProfilingInfo;
332 5 : CCU_CHK_RET(ConstructProfilingInfo(
333 : kernel, static_cast<const uint64_t*>(taskArgs), argNum, allCcuProfilingInfo, isSaveProfilingData));
334 5 : LogCcuTaskInfo(taskParams, kernelHandle);
335 5 : auto ccuDetailInfo = ConstructCcuDetailInfo(allCcuProfilingInfo, isSaveProfilingData);
336 13 : for (u32 idx = 0; idx < taskParams.size(); idx++) {
337 8 : u64 beginTime = Hccl::DlProfFunction::GetInstance().dlMsprofSysCycleTime();
338 8 : CCU_CHK_RET(LaunchCcuTasks(taskParams[idx], streamPtr));
339 8 : u64 endTime = Hccl::DlProfFunction::GetInstance().dlMsprofSysCycleTime();
340 : Hccl::TaskParam taskParam = ConstructCcuTaskParam(
341 8 : taskParams[idx], kernelHandle, ccuDetailInfo, beginTime, endTime, rtsThread->GetMaster());
342 8 : CCU_CHK_RET(ReportCcuTaskDfx(threadHandle, taskParam));
343 8 : }
344 5 : CCU_EXCEPTION_HANDLE_END
345 5 : HCCL_INFO("[%s] success, take time [%lld]us.", __func__, DURATION_US(TIME_NOW() - startus).count());
346 5 : return CcuResult::CCU_SUCCESS;
347 : }
348 :
349 : // 定位实例资源仓后转发给 CcuVarEventResMgr;预约、地址映射与失败回滚均由该类内部完成
350 14 : static CcuResult CcuAllocVarEventRes(
351 : CcuInsHandle insHandle, hcomm::CcuVarEventType type, uint8_t dieId, uint32_t num, uint64_t& outHandle)
352 : {
353 14 : const uint32_t devLogicId = HcclGetThreadDeviceId();
354 14 : auto* ccuIns = hcomm::CcuInstanceMgr::GetInstance(devLogicId).Get(insHandle);
355 14 : CCU_CHK_PTR_NULL(ccuIns);
356 :
357 14 : auto* resPack = ccuIns->GetResPack();
358 14 : CCU_CHK_PTR_NULL(resPack);
359 :
360 14 : CCU_CHK_RET(hcomm::CcuVarEventResMgr::GetInstance(devLogicId)
361 : .Acquire(insHandle, resPack->GetCcuResRepo(), type, dieId, num, outHandle));
362 7 : return CcuResult::CCU_SUCCESS;
363 : }
364 :
365 9 : CcuResult HcommCcuVariableAlloc(CcuInsHandle insHandle, uint8_t dieId, uint32_t num, CcuVariableHandle* varHandle)
366 : {
367 9 : CCU_CHK_PTR_NULL(varHandle);
368 8 : *varHandle = 0;
369 8 : CCU_CHK_RET(CcuAllocVarEventRes(insHandle, hcomm::CcuVarEventType::VARIABLE, dieId, num, *varHandle));
370 4 : return CcuResult::CCU_SUCCESS;
371 : }
372 :
373 7 : CcuResult HcommCcuEventAlloc(CcuInsHandle insHandle, uint8_t dieId, uint32_t num, CcuEventHandle* eventHandle)
374 : {
375 7 : CCU_CHK_PTR_NULL(eventHandle);
376 6 : *eventHandle = 0;
377 6 : CCU_CHK_RET(CcuAllocVarEventRes(insHandle, hcomm::CcuVarEventType::EVENT, dieId, num, *eventHandle));
378 3 : return CcuResult::CCU_SUCCESS;
379 : }
380 :
381 21 : CcuResult HcommCcuVariableGetAddr(CcuVariableHandle varHandle, uint32_t index, uint64_t* va)
382 : {
383 21 : CCU_CHK_PTR_NULL(va);
384 :
385 20 : const uint32_t devLogicId = HcclGetThreadDeviceId();
386 20 : CCU_CHK_RET(hcomm::CcuVarEventResMgr::GetInstance(devLogicId)
387 : .GetSavedAddr(hcomm::CcuVarEventType::VARIABLE, varHandle, index, *va));
388 :
389 18 : return CcuResult::CCU_SUCCESS;
390 : }
391 :
392 11 : CcuResult HcommCcuEventGetAddr(CcuEventHandle eventHandle, uint32_t index, uint64_t* va)
393 : {
394 11 : CCU_CHK_PTR_NULL(va);
395 :
396 11 : const uint32_t devLogicId = HcclGetThreadDeviceId();
397 11 : CCU_CHK_RET(hcomm::CcuVarEventResMgr::GetInstance(devLogicId)
398 : .GetSavedAddr(hcomm::CcuVarEventType::EVENT, eventHandle, index, *va));
399 :
400 8 : return CcuResult::CCU_SUCCESS;
401 : }
402 :
403 0 : CcuResult HcommCcuGetMemToken(uint64_t srcVa, uint64_t size, uint64_t* tokenInfo)
404 : {
405 0 : CCU_CHK_PTR_NULL(tokenInfo);
406 :
407 0 : if (srcVa == 0 || size == 0) {
408 0 : HCCL_ERROR(
409 : "[%s] failed, srcVa[0x%llx] size[%llu] should not be 0.", __func__, static_cast<unsigned long long>(srcVa),
410 : static_cast<unsigned long long>(size));
411 0 : return CcuResult::CCU_E_PARA;
412 : }
413 : // 注意token信息属于安全信息,均不允许打印
414 0 : hcomm::rtMemUbTokenInfo info{};
415 0 : info.va = srcVa;
416 0 : info.size = size;
417 0 : CCU_CHK_RET(hcomm::RtsUbDevQueryInfo(QUERY_PROCESS_TOKEN, info));
418 0 : *tokenInfo = hcomm::CcuRep::CcuCombineTokenInfo(info.tokenId, info.tokenValue, 1);
419 :
420 0 : return CcuResult::CCU_SUCCESS;
421 : }
|