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 "ccu_kernel_mgr.h"
12 :
13 : #include "hccl_common.h"
14 : #include "exception_handler.h"
15 : #include "adapter_rts.h"
16 : #include "ccu_assist_v1.h"
17 : #include "dev_buffer.h"
18 : #include "ccu_ins_generater_v1.h"
19 : #include "ccu_dev_mgr_imp.h"
20 :
21 : #include "ccu_rep_base_v1.h"
22 : #include "ccu_rep_block_v1.h"
23 : #include "ccu_rep_type_v1.h"
24 :
25 : #include "hcomm_adapter_hccp.h"
26 :
27 : #include "ccu_log.h"
28 : #include "ccu_kernel_func.h"
29 :
30 : namespace hcomm {
31 :
32 198 : CcuKernelMgr::~CcuKernelMgr()
33 : {
34 198 : if (!initializedFlag_) {
35 198 : return;
36 : }
37 :
38 0 : if (instructionLoadDevMem_) {
39 0 : HCCL_RUN_INFO("[CcuKernelMgr][~CcuKernelMgr]: deviceLogicId[%d], free addr[%p]",
40 : devLogicId_, instructionLoadDevMem_);
41 0 : (void)hrtFree(instructionLoadDevMem_);
42 0 : instructionLoadDevMem_ = nullptr;
43 : }
44 :
45 0 : (void)Deinit();
46 1188 : }
47 :
48 1128 : CcuKernelMgr &CcuKernelMgr::GetInstance(const int32_t deviceLogicId)
49 : {
50 1326 : static CcuKernelMgr kernelManager[MAX_MODULE_DEVICE_NUM + 1];
51 :
52 1128 : int32_t devLogicId = deviceLogicId;
53 1128 : if (devLogicId < 0 || static_cast<uint32_t>(devLogicId) >= MAX_MODULE_DEVICE_NUM) {
54 0 : HCCL_WARNING("[CcuKernelMgr][%s] use the backup device, devLogicId[%d] should be "
55 : "less than %u.", __func__, devLogicId, MAX_MODULE_DEVICE_NUM);
56 0 : devLogicId = MAX_MODULE_DEVICE_NUM; // 使用备份设备
57 : }
58 :
59 1128 : kernelManager[devLogicId].devLogicId_ = devLogicId;
60 1128 : return kernelManager[devLogicId];
61 : }
62 :
63 27 : HcclResult CcuKernelMgr::Init()
64 : {
65 27 : std::unique_lock<std::mutex> lock(kernelMapMutex_);
66 27 : if (initializedFlag_) {
67 0 : return HcclResult::HCCL_SUCCESS;
68 : }
69 :
70 81 : for (uint8_t dieId = 0; dieId < CCU_MAX_IODIE_NUM; dieId++) {
71 54 : bool enableFlag = false;
72 54 : CHK_RET(static_cast<HcclResult>(CcuGetDieEnableInfo(devLogicId_, dieId, enableFlag)));
73 54 : if (!enableFlag) {
74 0 : continue;
75 : }
76 :
77 54 : CHK_RET(InstantiationTranslator(dieId));
78 : }
79 :
80 27 : initializedFlag_ = true;
81 27 : kernelMap_.clear();
82 :
83 27 : CHK_RET(CcuDevMgrImp::GetCcuVersion(devLogicId_, ccuVersion_));
84 27 : if (ccuVersion_ == CcuVersion::INVALID) {
85 0 : HCCL_RUN_WARNING("[CcuKernelMgr][%s] Invalid chip type.", __func__);
86 : }
87 :
88 27 : HCCL_INFO("[CcuKernelMgr] Init CcuInsGeneraterV1");
89 27 : insGenePtr = std::make_shared<CcuRep::CcuInsGeneraterV1>();
90 27 : return HcclResult::HCCL_SUCCESS;
91 27 : }
92 :
93 27 : HcclResult CcuKernelMgr::Deinit()
94 : {
95 : // 不需要主动释放CCU指令空间等资源,因为设备管理与kernelMgr都为静态,生命周期一致
96 27 : std::unique_lock<std::mutex> lock(kernelMapMutex_);
97 27 : translatorResPack.handles.clear();
98 27 : initializedFlag_ = false;
99 27 : kernelMap_.clear();
100 27 : translators.clear();
101 27 : referenceMgrs.clear();
102 27 : return HcclResult::HCCL_SUCCESS;
103 27 : }
104 :
105 26 : CcuResult CcuKernelMgr::Register(
106 : CcuResPack &resPack, const char *kernelFuncName,
107 : const void *kernelFunc, const void **kernelArgs, const uint32_t argNum,
108 : CcuKernelHandle &kernelHandle)
109 : {
110 : // 允许kernelFuncName未空,此时传递默认名称
111 : (void)kernelFuncName;
112 26 : CCU_CHK_PTR_NULL(kernelFunc);
113 :
114 : // 当前argNum仅允许 0 或 1
115 26 : if (argNum > 1) {
116 0 : HCCL_ERROR("[%s] failed, argNum[%u] now only support 0 or 1.",
117 : __func__, argNum);
118 0 : return CcuResult::CCU_E_PARA;
119 : }
120 :
121 : // 注意处理时序,需要先重置后处理rep
122 26 : std::unique_lock<std::mutex> lock(kernelMapMutex_);
123 26 : currKernel_ = std::make_unique<CcuKernel>(); // 重置待注册kernel
124 26 : currKernel_->SetDieId(0); // 默认填0值,后续SelectDie选择真实id
125 26 : CCU_CHK_RET(currKernel_->SetupProfilingInfo(kernelFuncName));
126 :
127 : // 初始化翻译器(需在执行kernel func前设置,因为func执行时会创建rep对象)
128 26 : currKernel_->SetInsGenerater(insGenePtr.get());
129 26 : currKernel_->SetCcuVersion(ccuVersion_);
130 :
131 26 : if (argNum == 0) {
132 0 : auto ccuKernelFunc = reinterpret_cast<CcuKernelFuncNoArg>(kernelFunc);
133 0 : CCU_CHK_RET(ccuKernelFunc()); // 执行算法流程,生成rep和计算资源占用
134 : } else {
135 26 : CCU_CHK_PTR_NULL(kernelArgs);
136 26 : const void *kernelArg = kernelArgs[0];
137 26 : CCU_CHK_PTR_NULL(kernelArg);
138 26 : const auto ccuKernelArg = const_cast<CcuKernelArg>(kernelArg);
139 26 : auto ccuKernelFunc = reinterpret_cast<CcuKernelFuncOneArg>(kernelFunc);
140 26 : CCU_CHK_RET(ccuKernelFunc(ccuKernelArg)); // 执行算法流程,生成rep和计算资源占用
141 : }
142 :
143 19 : currKernel_->FlushClosablePendingIfs(); // 处理未闭合的if
144 19 : CCU_CHK_RET(currKernel_->SelectDie()); // 先处理rep,后选择die
145 19 : CCU_CHK_RET(PrepareConstValueResources()); // 记录翻译过程所需常量并申请对应资源
146 :
147 19 : CcuResult ret = AllocRes(resPack);
148 19 : if (ret != CcuResult::CCU_SUCCESS) {
149 0 : HCCL_WARNING("[%s] AllocRes failed, maybe resource not enough, please check ret[%d]",
150 : __func__, ret);
151 0 : return ret;
152 : }
153 :
154 19 : kernelId_++;
155 19 : kernelMap_[kernelId_] = std::move(currKernel_);
156 :
157 19 : kernelHandle = kernelId_;
158 19 : return CcuResult::CCU_SUCCESS;
159 26 : }
160 :
161 92 : static void DumpResReqInfo(const CcuResReq &totalRes)
162 : {
163 276 : for (uint32_t i = 0; i < CCU_MAX_IODIE_NUM; i++) {
164 368 : if (totalRes.msReq[i] != 0 || totalRes.blockMsReq[i] != 0 || totalRes.ckeReq[i] != 0 || totalRes.blockCkeReq[i] != 0
165 87 : || totalRes.loopEngineReq[i] != 0 || totalRes.blockLoopEngineReq[i] != 0 || totalRes.gsaReq[i] != 0
166 82 : || totalRes.xnReq[i] != 0 || totalRes.continuousXnReq[i] != 0
167 368 : ||totalRes.missionReq.req[i] != 0) {
168 111 : HCCL_INFO("DumpResReqInfo: dieId[%u], msReq[%u], blockMsReq[%u], ckeReq[%u], blockCkeReq[%u], "
169 : "loopEngineReq[%u], blockLoopEngineReq[%u], gsaReq[%u], xnReq[%u], continuousXnReq[%u], "
170 : "missionReq[%u]",
171 : i, totalRes.msReq[i], totalRes.blockMsReq[i], totalRes.ckeReq[i], totalRes.blockCkeReq[i],
172 : totalRes.loopEngineReq[i], totalRes.blockLoopEngineReq[i], totalRes.gsaReq[i],
173 : totalRes.xnReq[i], totalRes.continuousXnReq[i], totalRes.missionReq.req[i]);
174 : }
175 : }
176 92 : }
177 :
178 380 : inline int32_t GetResTotalNum(const std::vector<ResInfo> &resInfos)
179 : {
180 380 : int32_t resNum = 0;
181 642 : for (ResInfo resInfo : resInfos) {
182 262 : resNum += static_cast<int32_t>(resInfo.num);
183 : }
184 380 : return resNum;
185 : }
186 :
187 19 : static void GetResNumFromResPack(CcuResPack &resPack, CcuResReq &totalRes)
188 : {
189 : // 获取通信域当前所持有的资源
190 19 : const auto &tmpResRepository = resPack.GetCcuResRepo();
191 :
192 : // 合并获取的所持有的资源信息, 按照类型合并资源总和到totalRes的第0个vector中
193 57 : for (u32 i = 0; i < CCU_MAX_IODIE_NUM; i++) {
194 38 : totalRes.msReq[i] += GetResTotalNum(tmpResRepository.ms[i]);
195 38 : totalRes.blockMsReq[i] += GetResTotalNum(tmpResRepository.blockMs[i]);
196 38 : totalRes.ckeReq[i] += GetResTotalNum(tmpResRepository.cke[i]);
197 38 : totalRes.blockCkeReq[i] += GetResTotalNum(tmpResRepository.blockCke[i]);
198 38 : totalRes.loopEngineReq[i] += GetResTotalNum(tmpResRepository.loopEngine[i]);
199 38 : totalRes.blockLoopEngineReq[i] += GetResTotalNum(tmpResRepository.blockLoopEngine[i]);
200 38 : totalRes.gsaReq[i] += GetResTotalNum(tmpResRepository.gsa[i]);
201 38 : totalRes.xnReq[i] += GetResTotalNum(tmpResRepository.xn[i]);
202 38 : totalRes.continuousXnReq[i] += GetResTotalNum(tmpResRepository.continuousXn[i]);
203 38 : totalRes.missionReq.req[i] += GetResTotalNum(tmpResRepository.mission.mission[i]);
204 : }
205 :
206 19 : DumpResReqInfo(totalRes);
207 19 : HCCL_INFO("GetResPackTotalResNum:dumpInfos success.");
208 19 : }
209 :
210 380 : inline uint32_t GetReqResNum(const uint32_t reqRes, const uint32_t totalRes)
211 : {
212 380 : return ((reqRes > totalRes) ? (reqRes - totalRes) : 0);
213 : }
214 :
215 19 : static bool CheckResIfAvailable(const CcuResReq &totalRes, const CcuResReq &resReq)
216 : {
217 19 : DumpResReqInfo(resReq);
218 :
219 19 : CcuResReq needResReq{};
220 : // todo: 优化为遍历数组
221 57 : for (u32 i = 0; i < CCU_MAX_IODIE_NUM; i++) {
222 38 : needResReq.msReq[i] = GetReqResNum(resReq.msReq[i], totalRes.msReq[i]);
223 38 : needResReq.blockMsReq[i] = GetReqResNum(resReq.blockMsReq[i], totalRes.blockMsReq[i]);
224 38 : needResReq.ckeReq[i] = GetReqResNum(resReq.ckeReq[i], totalRes.ckeReq[i]);
225 38 : needResReq.blockCkeReq[i] = GetReqResNum(resReq.blockCkeReq[i], totalRes.blockCkeReq[i]);
226 38 : needResReq.loopEngineReq[i] = GetReqResNum(resReq.loopEngineReq[i], totalRes.loopEngineReq[i]);
227 38 : needResReq.blockLoopEngineReq[i] = GetReqResNum(resReq.blockLoopEngineReq[i], totalRes.blockLoopEngineReq[i]);
228 38 : needResReq.gsaReq[i] = GetReqResNum(resReq.gsaReq[i], totalRes.gsaReq[i]);
229 38 : needResReq.xnReq[i] = GetReqResNum(resReq.xnReq[i], totalRes.xnReq[i]);
230 38 : needResReq.continuousXnReq[i] = GetReqResNum(resReq.continuousXnReq[i], totalRes.continuousXnReq[i]);
231 38 : needResReq.missionReq.req[i]
232 38 : = GetReqResNum(resReq.missionReq.req[i], totalRes.missionReq.req[i]);
233 :
234 38 : if (needResReq.missionReq.req[i] > 0) {
235 0 : needResReq.missionReq.reqType = resReq.missionReq.reqType;
236 : }
237 :
238 76 : if (needResReq.msReq[i] != 0 || needResReq.blockMsReq[i] != 0 || needResReq.ckeReq[i] != 0 || needResReq.blockCkeReq[i] != 0
239 38 : || needResReq.loopEngineReq[i] != 0 || needResReq.blockLoopEngineReq[i] != 0 || needResReq.gsaReq[i] != 0
240 38 : || needResReq.xnReq[i] != 0 || needResReq.continuousXnReq[i] != 0
241 76 : || needResReq.missionReq.req[i] != 0) {
242 0 : HCCL_WARNING("[CcuKernelMgr][%s] dieId[%u] not enough, msReq[%u] blockMsReq[%u] ckeReq[%u]"
243 : "blockCkeReq[%u] loopEngineReq[%u] blockLoopEngineReq[%u] gsaReq[%u] xnReq[%u]"
244 : "continuousXnReq[%u] missionReq[%u].", __func__, i, needResReq.msReq[i],
245 : needResReq.blockMsReq[i], needResReq.ckeReq[i], needResReq.blockCkeReq[i],
246 : needResReq.loopEngineReq[i], needResReq.blockLoopEngineReq[i], needResReq.gsaReq[i],
247 : needResReq.xnReq[i], needResReq.continuousXnReq[i], needResReq.missionReq.req[i]);
248 0 : return false;
249 : }
250 : }
251 :
252 19 : return true;
253 : }
254 :
255 380 : static void MoveResInfo(std::vector<ResInfo> &dest, std::vector<ResInfo> &source,
256 : const uint32_t resNum)
257 : {
258 : // Register 前序流程已检查资源不足场景
259 380 : if (resNum == 0) {
260 318 : return;
261 : }
262 :
263 62 : dest.clear();
264 62 : auto iter = source.begin();
265 62 : uint32_t remain = resNum;
266 124 : while (remain > 0 && iter != source.end()) {
267 62 : auto &srcBlock = *iter;
268 62 : const uint32_t take = std::min(remain, srcBlock.num);
269 62 : dest.emplace_back(srcBlock.startId, take);
270 :
271 62 : if (take == srcBlock.num) {
272 : // 完全用掉这个资源,source中移除
273 0 : iter = source.erase(iter);
274 : } else {
275 : // 只用了部分,更新source中的资源
276 62 : srcBlock.startId += take;
277 62 : srcBlock.num -= take;
278 : }
279 :
280 62 : remain -= take; // 更新剩余需要的资源数量
281 : }
282 : }
283 :
284 19 : static void LoadRes(std::unique_ptr<CcuKernel> &kernel, CcuResPack &resPack)
285 : {
286 19 : const CcuResReq &resReq = kernel->GetResourceRequest();
287 19 : CcuResRepository &totalResRepo = resPack.GetCcuResRepo();
288 399 : CcuResRepository kernelResRepo{};
289 :
290 57 : for (uint8_t i = 0; i < CCU_MAX_IODIE_NUM; i++) { // todo: 建议改成dieId
291 38 : MoveResInfo(kernelResRepo.loopEngine[i], totalResRepo.loopEngine[i], resReq.loopEngineReq[i]);
292 38 : MoveResInfo(kernelResRepo.blockLoopEngine[i], totalResRepo.blockLoopEngine[i], resReq.blockLoopEngineReq[i]);
293 38 : MoveResInfo(kernelResRepo.ms[i], totalResRepo.ms[i], resReq.msReq[i]);
294 38 : MoveResInfo(kernelResRepo.blockMs[i], totalResRepo.blockMs[i], resReq.blockMsReq[i]);
295 38 : MoveResInfo(kernelResRepo.cke[i], totalResRepo.cke[i], resReq.ckeReq[i]);
296 38 : MoveResInfo(kernelResRepo.blockCke[i], totalResRepo.blockCke[i], resReq.blockCkeReq[i]);
297 38 : MoveResInfo(kernelResRepo.continuousXn[i], totalResRepo.continuousXn[i], resReq.continuousXnReq[i]);
298 38 : MoveResInfo(kernelResRepo.xn[i], totalResRepo.xn[i], resReq.xnReq[i]);
299 38 : MoveResInfo(kernelResRepo.gsa[i], totalResRepo.gsa[i], resReq.gsaReq[i]);
300 38 : MoveResInfo(kernelResRepo.mission.mission[i], totalResRepo.mission.mission[i], resReq.missionReq.req[i]);
301 : }
302 :
303 19 : kernel->SetResRepository(kernelResRepo);
304 19 : }
305 :
306 19 : static CcuResult AllocInstrRes(std::unique_ptr<CcuKernel> &kernel, const int32_t devLogicId)
307 : {
308 19 : const uint32_t instrCount = kernel->GetInstrCount() + CcuRep::CcuRepTranslator::GetInstrNum() + kernel->GetConstValue2VarMap().size();
309 19 : const uint32_t dieId = kernel->GetDieId();
310 19 : ResInfo insInfo(0, 0);
311 19 : CCU_CHK_RET(CcuDevMgrImp::AllocIns(devLogicId, dieId, instrCount, insInfo));
312 19 : HCCL_INFO("[CcuKernelMgr][%s]: devLogicId[%d], dieId[%u], startId[%u], count[%u]",
313 : __func__, devLogicId, dieId, insInfo.startId, insInfo.num);
314 19 : kernel->SetInstrId(insInfo.startId);
315 :
316 19 : return CcuResult::CCU_SUCCESS;
317 : }
318 :
319 19 : CcuResult CcuKernelMgr::PrepareConstValueResources()
320 : {
321 : // insGenerator统计rep中常量,并填写当前kernel的常量表,当前只有A6有对应处理,A5没有常量处理需求
322 19 : CCU_CHK_PTR_NULL(currKernel_);
323 19 : const auto &repVec = currKernel_->GetRepSequence();
324 :
325 19 : const auto &translator = translators[currKernel_->GetDieId()][0];
326 19 : CCU_CHK_PTR_NULL(translator);
327 19 : const auto &transDep = translator->GetTransDep(); // 此时未分配missionid,取0对应的transDep读取常量
328 19 : CCU_CHK_PTR_NULL(insGenePtr);
329 428 : for (uint32_t index = 0; index < repVec.size(); index++) {
330 409 : const auto &curRepType = repVec[index]->Type();
331 409 : CcuRep::CcuRepBase* curRepPtr = repVec[index].get();
332 409 : CCU_CHK_PTR_NULL(curRepPtr);
333 :
334 : // 遍历每个rep,包括repBlock中的每个rep,将常量资源需求记录在currkernel中
335 409 : insGenePtr->PrepareConstValue(curRepPtr, transDep, currKernel_.get());
336 409 : if (curRepType == CcuRep::CcuRepType::BLOCK || curRepType == CcuRep::CcuRepType::FUNC_BLOCK ||
337 405 : curRepType == CcuRep::CcuRepType::LOOP_BLOCK)
338 : {
339 28 : CcuRep::CcuRepBlock* curRepBlockPtr = static_cast<CcuRep::CcuRepBlock*>(curRepPtr);
340 28 : CCU_CHK_PTR_NULL(curRepBlockPtr);
341 75 : for (const auto &repInBlock : curRepBlockPtr->GetReps())
342 : {
343 47 : insGenePtr->PrepareConstValue(repInBlock.get(), transDep, currKernel_.get());
344 : }
345 : }
346 : }
347 19 : return CcuResult::CCU_SUCCESS;
348 : }
349 :
350 19 : CcuResult CcuKernelMgr::AllocRes(CcuResPack &resPack)
351 : {
352 19 : CcuResReq leftRes{};
353 19 : GetResNumFromResPack(resPack, leftRes);
354 :
355 19 : const CcuResReq &resReq = currKernel_->GetResourceRequest();
356 : // todo: 需要整改,传递资源不足的信息
357 19 : if (!CheckResIfAvailable(leftRes, resReq)) {
358 0 : HCCL_WARNING("[CcuKernelMgr][%s] resource is not enough.", __func__);
359 0 : return CcuResult::CCU_E_UNAVAIL;
360 : }
361 :
362 : // 申请指令空间资源
363 19 : CCU_CHK_RET(AllocInstrRes(currKernel_, devLogicId_));
364 :
365 : // 资源从respack转移至kernel
366 19 : LoadRes(currKernel_, resPack);
367 :
368 19 : return CcuResult::CCU_SUCCESS;
369 : }
370 :
371 : template <typename T1, typename T2>
372 1460 : HcclResult ResetRepResourceTemplate(std::vector<T1> &resource, const std::vector<T2> &repository,
373 : const uint32_t startIndex = 0)
374 : {
375 1460 : if (resource.size() > repository.size() - startIndex) {
376 0 : HCCL_ERROR("[CcuKernelMgr][ResetRepResourceTemplate]resource size[%u] bigger "
377 : "repository size[%u] typeid[%s]",
378 : resource.size(), repository.size(), typeid(T1).name());
379 0 : return HcclResult::HCCL_E_INTERNAL;
380 : }
381 :
382 14147 : for (uint32_t j = 0; j < resource.size(); j++) {
383 12687 : resource[j].Reset(repository[j + startIndex].startId);
384 : }
385 :
386 1460 : return HcclResult::HCCL_SUCCESS;
387 : }
388 :
389 73 : static HcclResult ResetRepResourceToResRepository(CcuRepResource &totalRepRes,
390 : const CcuResRepository &totalResRepository)
391 : {
392 : // 遍历translatorRepRes, 将每个rep的虚拟资源翻译到实际物理资源上
393 219 : for (u32 i = 0; i < CCU_MAX_IODIE_NUM; i++) {
394 146 : CHK_RET(ResetRepResourceTemplate(totalRepRes.ccubufs[i], totalResRepository.ms[i]));
395 146 : CHK_RET(ResetRepResourceTemplate(totalRepRes.blockCcubufs[i], totalResRepository.blockMs[i]));
396 146 : CHK_RET(ResetRepResourceTemplate(totalRepRes.executor[i], totalResRepository.loopEngine[i]));
397 146 : CHK_RET(ResetRepResourceTemplate(totalRepRes.blockExecutor[i], totalResRepository.blockLoopEngine[i]));
398 146 : CHK_RET(ResetRepResourceTemplate(totalRepRes.completedEvent[i], totalResRepository.cke[i]));
399 146 : CHK_RET(ResetRepResourceTemplate(totalRepRes.blockCompletedEvent[i], totalResRepository.blockCke[i]));
400 146 : CHK_RET(ResetRepResourceTemplate(totalRepRes.localNotify[i], totalResRepository.cke[i],
401 : totalRepRes.completedEvent[i].size())); // 两类资源都使用cke,需要调整起始分配位置
402 146 : CHK_RET(ResetRepResourceTemplate(totalRepRes.address[i], totalResRepository.gsa[i]));
403 146 : CHK_RET(ResetRepResourceTemplate(totalRepRes.variable[i], totalResRepository.xn[i]));
404 146 : CHK_RET(ResetRepResourceTemplate(totalRepRes.continuousVariable[i], totalResRepository.continuousXn[i]));
405 : }
406 73 : return HcclResult::HCCL_SUCCESS;
407 : }
408 :
409 : using DieResInfos = std::array<std::vector<ResInfo>, CCU_MAX_IODIE_NUM>;
410 19 : static HcclResult SaveKernelMissionInfo(CcuKernel *kernel,
411 : const DieResInfos &missionId, const int32_t devLogicId)
412 : {
413 19 : const uint32_t dieId = kernel->GetDieId();
414 19 : uint32_t missionKey{0};
415 19 : CHK_RET(CcuDevMgrImp::GetMissionKey(devLogicId, dieId, missionKey));
416 :
417 19 : HCCL_INFO("[CcuKernelMgr][%s] deviceLogicId[%d] dieId[%u]",
418 : __func__, devLogicId, dieId);
419 :
420 19 : kernel->SetMissionKey(missionKey);
421 : // 从missionId中获取一个元素并从missionId中删除,当前应只有一个元素,且无需删除
422 19 : if (missionId[dieId].empty()) {
423 0 : HCCL_ERROR("[%s] failed, devLogicId[%d] dieId[%u] do not have missions.",
424 : __func__, devLogicId, dieId);
425 0 : return HcclResult::HCCL_E_INTERNAL;
426 : }
427 :
428 19 : kernel->SetMissionId(missionId[dieId].back().startId);
429 19 : return HcclResult::HCCL_SUCCESS;
430 : }
431 :
432 100 : static void DumpResRepositoryInfo(const CcuResRepository &resRepo)
433 : {
434 300 : for (uint32_t i = 0; i < CCU_MAX_IODIE_NUM; i++) {
435 400 : if (resRepo.ms[i].size() != 0 || resRepo.blockMs[i].size() != 0 || resRepo.cke[i].size() != 0 || resRepo.blockCke[i].size() != 0
436 87 : || resRepo.loopEngine[i].size() != 0 || resRepo.blockLoopEngine[i].size() != 0 || resRepo.gsa[i].size() != 0
437 82 : || resRepo.xn[i].size() != 0 || resRepo.continuousXn[i].size() != 0
438 400 : || resRepo.mission.mission[i].size() != 0) {
439 127 : HCCL_INFO("DumpResRepository: dieId[%u], ms size[%u], blockMs size[%u], cke size[%u], blockCke size[%u], "
440 : "loopEngine size[%u], blockLoopEngine size[%u], gsa size[%u], xn size[%u], "
441 : "continuous xn size[%u], mission size[%u]",
442 : i, resRepo.ms[i].size(), resRepo.blockMs[i].size(), resRepo.cke[i].size(),
443 : resRepo.blockCke[i].size(), resRepo.loopEngine[i].size(), resRepo.blockLoopEngine[i].size(),
444 : resRepo.gsa[i].size(), resRepo.xn[i].size(), resRepo.continuousXn[i].size(),
445 : resRepo.mission.mission[i].size());
446 : }
447 : }
448 100 : }
449 :
450 2000 : inline void ExpandResInfo(std::vector<ResInfo> &expendResInfos, const std::vector<ResInfo> &resInfos)
451 : {
452 : // 将resInfo中的资源信息还原为单个资源粒度
453 2299 : for (auto &resInfo : resInfos) {
454 18957 : for (uint32_t id = 0; id < resInfo.num; id++) {
455 18658 : expendResInfos.push_back({(resInfo.startId + id), {1}});
456 : }
457 : }
458 2000 : }
459 :
460 100 : static CcuResult ExpandResRepo(CcuResRepository &totalRes, const CcuResRepository &tmpResRepository)
461 : {
462 : // 合并获取的所持有的资源信息, 按照类型合并资源总和到totalRes中
463 300 : for (u32 i = 0; i < CCU_MAX_IODIE_NUM; i++) {
464 200 : ExpandResInfo(totalRes.ms[i], tmpResRepository.ms[i]);
465 200 : ExpandResInfo(totalRes.blockMs[i], tmpResRepository.blockMs[i]);
466 200 : ExpandResInfo(totalRes.loopEngine[i], tmpResRepository.loopEngine[i]);
467 200 : ExpandResInfo(totalRes.blockLoopEngine[i], tmpResRepository.blockLoopEngine[i]);
468 200 : ExpandResInfo(totalRes.cke[i], tmpResRepository.cke[i]);
469 200 : ExpandResInfo(totalRes.blockCke[i], tmpResRepository.blockCke[i]);
470 200 : ExpandResInfo(totalRes.gsa[i], tmpResRepository.gsa[i]);
471 200 : ExpandResInfo(totalRes.xn[i], tmpResRepository.xn[i]);
472 200 : ExpandResInfo(totalRes.continuousXn[i], tmpResRepository.continuousXn[i]);
473 200 : ExpandResInfo(totalRes.mission.mission[i], tmpResRepository.mission.mission[i]);
474 : }
475 100 : DumpResRepositoryInfo(totalRes);
476 100 : return CcuResult::CCU_SUCCESS;
477 : }
478 :
479 : template <typename T>
480 19 : static HcclResult MergeExportedResources(
481 : const std::unordered_map<std::string, T> &inputRes,
482 : std::unordered_map<std::string, T> &outputRes)
483 : {
484 19 : for (const auto &item : inputRes) {
485 0 : const auto &resTag = item.first;
486 0 : if (outputRes.find(resTag) != outputRes.end()) {
487 0 : HCCL_ERROR("[CcuKernelMgr][%s] failed, exported resource tag[%s] is already existed, "
488 : "please check.", __func__, resTag);
489 0 : return HcclResult::HCCL_E_PARA;
490 : }
491 :
492 0 : outputRes.insert(item);
493 : }
494 :
495 19 : return HcclResult::HCCL_SUCCESS;
496 : }
497 :
498 : template <typename T>
499 19 : static HcclResult ResetImportedResources(
500 : std::unordered_map<std::string, T> &importedRes,
501 : const std::unordered_map<std::string, T> &exportedRes)
502 : {
503 19 : for (auto &item : importedRes) {
504 0 : const auto &resTag = item.first;
505 0 : const auto &iter = exportedRes.find(resTag);
506 0 : if (iter == exportedRes.end()) {
507 0 : HCCL_ERROR("[CcuKernelMgr][%s] failed to find exported resources by tag[%s].",
508 : __func__, resTag.c_str());
509 0 : return HcclResult::HCCL_E_NOT_FOUND;
510 : }
511 :
512 0 : item.second.Reset(iter->second.Id(), iter->second.DieId());
513 : }
514 :
515 19 : return HcclResult::HCCL_SUCCESS;
516 : }
517 :
518 19 : static HcclResult ProcessInterCtxRes(const std::vector<CcuKernel *> &kernels)
519 : {
520 19 : std::unordered_map<std::string, CcuRep::LocalNotify> totalExportedNotifies;
521 :
522 38 : for (const auto kernel : kernels) {
523 19 : const auto &exportedRes = kernel->GetExportedRes();
524 19 : CHK_RET(MergeExportedResources(exportedRes.sharedNotifies, totalExportedNotifies));
525 : }
526 :
527 38 : for (auto kernel : kernels) {
528 19 : auto &importedRes = kernel->GetImportedRes();
529 19 : CHK_RET(ResetImportedResources(importedRes.sharedNotifies, totalExportedNotifies));
530 : }
531 :
532 19 : return HcclResult::HCCL_SUCCESS;
533 19 : }
534 :
535 19 : static HcclResult TransRepResToPhyRes(
536 : const std::vector<CcuKernel *> &kernels, const int32_t devLogicId)
537 : {
538 38 : for (auto kernel : kernels) {
539 19 : const auto &totalResRepository = kernel->GetResRepository();
540 19 : auto &totalRepRes = kernel->GetResource();
541 :
542 : // 将ccu kernel持有的物理资源赋给资源对象
543 399 : CcuResRepository expandedResRepo{};
544 19 : ExpandResRepo(expandedResRepo, totalResRepository);
545 19 : CHK_RET(ResetRepResourceToResRepository(totalRepRes, expandedResRepo));
546 :
547 19 : CHK_RET(SaveKernelMissionInfo(kernel,
548 : totalResRepository.mission.mission, devLogicId));
549 19 : }
550 :
551 19 : CHK_RET(ProcessInterCtxRes(kernels));
552 :
553 19 : return HcclResult::HCCL_SUCCESS;
554 : }
555 :
556 19 : CcuResult CcuKernelMgr::Translate(const std::vector<CcuKernelHandle> &kernelHandles)
557 : {
558 19 : if (kernelHandles.empty()) {
559 0 : HCCL_INFO("[CcuKernelMgr][%s] passed, kernelHandles are empty.", __func__);
560 0 : return CcuResult::CCU_SUCCESS;
561 : }
562 :
563 19 : std::vector<CcuKernel *> kernels{};
564 19 : std::unique_lock<std::mutex> mapLock(kernelMapMutex_);
565 38 : for (const auto kernelHandle : kernelHandles) {
566 19 : const auto &iter = kernelMap_.find(kernelHandle);
567 19 : if (iter == kernelMap_.end()) {
568 0 : HCCL_ERROR("[CcuKernelMgr][%s] failed to find kernel by ccu kernel handle[0x%llx].",
569 : __func__, kernelHandle);
570 0 : return CcuResult::CCU_E_NOT_FOUND;
571 : }
572 :
573 19 : kernels.push_back(iter->second.get());
574 : }
575 19 : mapLock.unlock();
576 :
577 19 : constexpr bool isFuncBlock = false; // 当前不支持MC2
578 :
579 19 : std::unique_lock<std::mutex> translateLock(translateMutex_);
580 19 : CCU_CHK_RET(TransRepResToPhyRes(kernels, devLogicId_));
581 19 : CCU_CHK_RET(TransRepSequenceToMicrocode(kernels, isFuncBlock));
582 :
583 57 : for (auto &referenceMgrMap : referenceMgrs) {
584 646 : for (auto &referenceMgr : referenceMgrMap.second) {
585 608 : referenceMgr.second->ClearRepReference();
586 : }
587 : }
588 19 : return CcuResult::CCU_SUCCESS;
589 19 : }
590 :
591 19 : static HcclResult ReleaseInstrRes(CcuKernel *kernel, const int32_t devLogicId)
592 : {
593 19 : const uint32_t instrCount = kernel->GetInstrCount() + CcuRep::CcuRepTranslator::GetInstrNum() + kernel->GetConstValue2VarMap().size();
594 19 : const ResInfo insInfo{kernel->GetInstrId(), instrCount};
595 19 : const uint8_t dieId = static_cast<uint8_t>(kernel->GetDieId());
596 19 : HCCL_INFO("[CcuKernelMgr][%s] devLogicId[%d], dieId[%u], startId[%u], count[%u]",
597 : __func__, devLogicId, dieId, insInfo.startId, insInfo.num);
598 19 : CHK_RET(CcuDevMgrImp::ReleaseIns(devLogicId, dieId, insInfo));
599 :
600 19 : return HcclResult::HCCL_SUCCESS;
601 : }
602 :
603 19 : CcuResult CcuKernelMgr::UnRegister(const CcuKernelHandle kernelHandle)
604 : {
605 19 : std::unique_lock<std::mutex> lock(kernelMapMutex_);
606 :
607 : // 校验kernelMap_中是否存在executorId对应的kernel
608 19 : auto it = kernelMap_.find(kernelHandle);
609 19 : CHK_PRT_RET(it == kernelMap_.end(),
610 : HCCL_ERROR("[CcuKernelMgr][%s] kernelHandle [%llu] does not exist",
611 : __func__, kernelHandle),
612 : CcuResult::CCU_E_NOT_FOUND);
613 :
614 19 : auto kernel = it->second.get();
615 19 : CCU_CHK_RET(ReleaseInstrRes(kernel, devLogicId_));
616 19 : kernelMap_.erase(kernelHandle);
617 19 : return CcuResult::CCU_SUCCESS;
618 19 : }
619 :
620 54 : HcclResult CcuKernelMgr::GetResPackTotalResRepository(
621 : const CcuKernelMgr::CcuTranslatResPack &resPack,
622 : CcuResRepository &totalRes) const
623 : {
624 1134 : CcuResRepository tmpResRepository{};
625 : // 获取通信域当前所持有的资源
626 135 : for (CcuResHandle resHandle : resPack.handles) {
627 81 : CHK_RET(CcuDevMgrImp::GetResource(devLogicId_, resHandle, tmpResRepository));
628 81 : ExpandResRepo(totalRes, tmpResRepository);
629 81 : HCCL_INFO("[%s] succeed, deviceLogicId[%d] resHandle[%p].",
630 : __func__, devLogicId_, resHandle);
631 : }
632 54 : return HcclResult::HCCL_SUCCESS;
633 54 : }
634 :
635 1728 : static void MergeCcuResReq(CcuResReq &resReqA, const CcuResReq &resReqB)
636 : {
637 : // 合并获取的所持有的资源信息, 按照类型合并资源总和到totalRes的第0个vector中
638 5184 : for (uint32_t i = 0; i < CCU_MAX_IODIE_NUM; i++) {
639 3456 : resReqA.msReq[i] += resReqB.msReq[i];
640 3456 : resReqA.blockMsReq[i] += resReqB.blockMsReq[i];
641 3456 : resReqA.ckeReq[i] += resReqB.ckeReq[i];
642 3456 : resReqA.blockCkeReq[i] += resReqB.blockCkeReq[i];
643 3456 : resReqA.loopEngineReq[i] += resReqB.loopEngineReq[i];
644 3456 : resReqA.blockLoopEngineReq[i] += resReqB.blockLoopEngineReq[i];
645 3456 : resReqA.gsaReq[i] += resReqB.gsaReq[i];
646 3456 : resReqA.xnReq[i] += resReqB.xnReq[i];
647 3456 : resReqA.continuousXnReq[i] += resReqB.continuousXnReq[i];
648 3456 : resReqA.missionReq.req[i] += resReqB.missionReq.req[i];
649 :
650 3456 : if (resReqB.missionReq.req[i] > 0) {
651 0 : resReqA.missionReq.reqType = resReqB.missionReq.reqType;
652 : }
653 : }
654 1728 : }
655 :
656 54 : HcclResult CcuKernelMgr::InstantiationTranslator(const uint16_t dieId)
657 : {
658 54 : if (translators.find(dieId) != translators.end()) {
659 0 : return HcclResult::HCCL_SUCCESS;
660 : }
661 :
662 54 : std::array<uint16_t, CCU_MAX_IODIE_NUM> tmpChannelId{};
663 54 : uint32_t channelId = 0;
664 : // 获取innerDieChannelId
665 54 : auto ret = CcuDevMgrImp::GetLoopChannelId(devLogicId_, dieId, dieId, channelId);
666 54 : CHK_RET(ret);
667 :
668 54 : tmpChannelId[0] = channelId;
669 : // 获取interDieChannelId
670 54 : uint8_t dstDieId = ((dieId == 0) ? 1 : 0);
671 54 : ret = CcuDevMgrImp::GetLoopChannelId(devLogicId_, dieId, dstDieId, channelId);
672 54 : CHK_RET(ret);
673 54 : tmpChannelId[1] = channelId;
674 :
675 54 : uint64_t tokenId = 0;
676 54 : uint64_t tokenValue = 0;
677 54 : ret = CcuDevMgrImp::GetCcuResourceSpaceTokenInfo(devLogicId_, dieId, tokenId, tokenValue);
678 54 : CHK_RET(ret);
679 :
680 54 : std::pair<uint64_t, uint64_t> ccuTokenInfo(tokenId, tokenValue);
681 54 : Hccl::DevBuffer tmpDevMem{1}; // 临时申请device hbm内存用于查询token信息
682 54 : auto hbmTokenInfo = hcomm::CcuRep::GetTokenInfo(tmpDevMem.GetAddr(), 1);
683 :
684 54 : CcuResReq totalResReq{};
685 : // 实例化CcuRepReferenceManager和CcuRepTranslator,并为CcuRepReferenceManager绑定物理资源
686 918 : for (uint32_t i = 0; i < 16; i++) { // mgr有16个
687 864 : referenceMgrs[dieId][i] = std::make_shared<hcomm::CcuRep::CcuRepReferenceManager>(dieId);
688 1728 : translators[dieId][i] = std::make_shared<hcomm::CcuRep::CcuRepTranslator>(devLogicId_,
689 1728 : dieId, referenceMgrs[dieId][i], tmpChannelId, ccuTokenInfo, hbmTokenInfo);
690 :
691 : // 统计&合并refManager和translaotr所有资源REQ
692 864 : auto refMangerResReq = CcuRep::CcuRepReferenceManager::GetResReq(dieId);
693 864 : auto transLatorResReq = CcuRep::CcuRepTranslator::GetResReq(dieId);
694 864 : MergeCcuResReq(totalResReq, refMangerResReq);
695 864 : MergeCcuResReq(totalResReq, transLatorResReq);
696 : }
697 54 : DumpResReqInfo(totalResReq);
698 :
699 : // 为refManager和translaotr申请物理资源
700 : CcuResHandle handle;
701 54 : CHK_RET(CcuDevMgrImp::AllocResHandle(devLogicId_, totalResReq, handle));
702 54 : translatorResPack.handles.push_back(handle);
703 :
704 54 : CcuRepResource translatorRepRes;
705 918 : for (uint32_t i = 0; i < 16; i++) { // mgr有16个
706 864 : referenceMgrs[dieId][i]->GetRes(translatorRepRes);
707 864 : translators[dieId][i]->GetRes(translatorRepRes);
708 : }
709 :
710 54 : CcuResRepository totalResRepository;
711 54 : CHK_RET(GetResPackTotalResRepository(translatorResPack, totalResRepository));
712 : // 将kernel中的rep虚拟资源按类型进行和CCU物理资源映射
713 54 : CHK_RET(ResetRepResourceToResRepository(translatorRepRes, totalResRepository));
714 54 : return HcclResult::HCCL_SUCCESS;
715 54 : }
716 :
717 19 : HcclResult CcuKernelMgr::LoadInstruction(const CcuRep::CcuInstrInfo &instrInfo, const uint32_t dieId)
718 : {
719 19 : const uint64_t instrInfoSize = instrInfo.instrVec.size() * sizeof(hcomm::CcuRep::CcuInstr);
720 :
721 19 : if (!instructionLoadDevMem_) {
722 11 : uint32_t instrNum = 0;
723 11 : CHK_RET(CcuDevMgrImp::GetInstructionNum(devLogicId_, 0, instrNum));
724 11 : HCCL_INFO("[CcuKernelMgr]LoadInstruction: deviceLogicId[%d], instrNum[%u]",
725 : devLogicId_, instrNum);
726 11 : CHK_RET(hrtMalloc(&instructionLoadDevMem_, instrNum * sizeof(hcomm::CcuRep::CcuInstr)));
727 : }
728 :
729 19 : CHK_RET(hrtMemcpy(instructionLoadDevMem_, instrInfoSize,
730 : instrInfo.instrVec.data(), instrInfoSize,
731 : HcclRtMemcpyKind::HCCL_RT_MEMCPY_KIND_HOST_TO_DEVICE));
732 :
733 19 : uint32_t devPhyId = 0;
734 19 : CHK_RET(hrtGetDevicePhyIdByIndex(static_cast<uint32_t>(devLogicId_), devPhyId));
735 :
736 19 : CustomChannelInfoIn inBuff{};
737 19 : CustomChannelInfoOut outBuff{};
738 :
739 : // 设置操作码和通道数据
740 19 : inBuff.op = CcuOpcodeType::CCU_U_OP_SET_INSTRUCTION;
741 19 : inBuff.offsetStartIdx = instrInfo.startInstrId;
742 19 : inBuff.data.dataInfo.udieIdx = dieId;
743 19 : inBuff.data.dataInfo.dataArraySize = 1;
744 19 : inBuff.data.dataInfo.dataLen = instrInfoSize;
745 :
746 19 : CcuDataTypeUnion tmp{};
747 19 : tmp.insinfo.resourceAddr = reinterpret_cast<uint64_t>(instructionLoadDevMem_);
748 19 : (void)memcpy_s(inBuff.data.dataInfo.dataArray, sizeof(CcuDataTypeUnion), &tmp, sizeof(CcuDataTypeUnion));
749 :
750 19 : auto ret = HccpRaTlvCcuCustomChannel(devLogicId_,
751 : static_cast<void *>(&inBuff), static_cast<void *>(&outBuff));
752 19 : if (ret != HCCL_SUCCESS) {
753 0 : HCCL_ERROR("[CcuResSpecifications][%s] failed to call ccu driver, "
754 : "devLogicId[%d] devPhyId[%u] dieId[%d] op[%s] ret[%d].", __func__, devLogicId_, devPhyId, dieId,
755 : "SET_INSTRUCTION", ret);
756 0 : return ret;
757 : }
758 :
759 19 : return HcclResult::HCCL_SUCCESS;
760 : }
761 :
762 19 : HcclResult CcuKernelMgr::TransRepSequenceToMicrocode(
763 : const std::vector<CcuKernel *> &kernels, bool isFuncBlock)
764 : {
765 38 : for (auto kernel : kernels) {
766 19 : const uint32_t dieId = kernel->GetDieId();
767 19 : const uint32_t missionId = kernel->GetMissionId();
768 :
769 : EXCEPTION_HANDLE_BEGIN
770 19 : const auto &instrInfo = translators[dieId][missionId]->Translate(
771 19 : kernel, kernel->GetRepSequence(), kernel->GetInstrId(), isFuncBlock);
772 :
773 19 : CHK_RET(LoadInstruction(instrInfo, dieId));
774 :
775 19 : kernel->SetCcuInstrInfo(instrInfo); // 指令下发成功后可以对kernel进行launch
776 19 : EXCEPTION_HANDLE_END
777 : }
778 :
779 19 : return HcclResult::HCCL_SUCCESS;
780 : }
781 :
782 7 : CcuKernel *CcuKernelMgr::GetKernel(const CcuKernelHandle kernelHandle)
783 : {
784 7 : std::unique_lock<std::mutex> lock(kernelMapMutex_);
785 7 : auto it = kernelMap_.find(kernelHandle);
786 7 : if (it == kernelMap_.end()) {
787 4 : HCCL_ERROR("[CcuKernelMgr][%s] handle[%llx] is not existed.",
788 : __func__, kernelHandle);
789 4 : return nullptr;
790 : }
791 :
792 3 : return it->second.get();
793 7 : }
794 :
795 996 : CcuKernel *CcuKernelMgr::GetCurrentKernel() {
796 996 : return currKernel_.get();
797 : }
798 :
799 : } // namespace hcomm
|