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_res_batch_allocator.h"
12 :
13 : #include <array>
14 : #include <memory>
15 : #include <utility>
16 : #include <iterator>
17 : #include <algorithm>
18 :
19 : #include "hccl_common.h"
20 :
21 : #include "ccu_comp.h"
22 : #include "ccu_res_specs.h"
23 :
24 : namespace hcomm {
25 :
26 : constexpr uint32_t REQ_RES_TYPE_NUM = 10;
27 : constexpr uint32_t BLOCK_RES_TYPE_NUM = 3;
28 : constexpr uint32_t CONS_RES_TYPE_NUM = 1;
29 : constexpr uint32_t DISCRETE_RES_TYPE_NUM = 5;
30 : constexpr uint32_t NON_BLOCK_TYPE_NUM = CONS_RES_TYPE_NUM + DISCRETE_RES_TYPE_NUM;
31 : constexpr uint32_t BLOCK_SIZE_MS_AX_DIE0 = 128;
32 : constexpr uint32_t CCUA_NUM = 4;
33 :
34 328 : CcuResBatchAllocator &CcuResBatchAllocator::GetInstance(const int32_t deviceLogicId)
35 : {
36 460 : static CcuResBatchAllocator ccuResBatchAllocator[MAX_MODULE_DEVICE_NUM + 1];
37 328 : int32_t devLogicId = deviceLogicId;
38 328 : if (devLogicId < 0 || static_cast<uint32_t>(devLogicId) >= MAX_MODULE_DEVICE_NUM) {
39 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] use the backup device, devLogicId[%d] "
40 : "should be less than %u.", __func__, devLogicId, MAX_MODULE_DEVICE_NUM);
41 0 : devLogicId = MAX_MODULE_DEVICE_NUM; // 使用备份设备
42 : }
43 328 : ccuResBatchAllocator[devLogicId].devLogicId_ = devLogicId;
44 328 : return ccuResBatchAllocator[devLogicId];
45 : }
46 :
47 58 : HcclResult CcuResBatchAllocator::Init()
48 : {
49 58 : if (initFlag_) {
50 30 : return HcclResult::HCCL_SUCCESS;
51 : }
52 :
53 28 : dieEnableFlags_ = CcuComponent::GetInstance(devLogicId_).GetDieEnableFlags();
54 28 : if (!dieEnableFlags_[0] && !dieEnableFlags_[1]) {
55 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] failed but passed, "
56 : "devLogicId[%d] no usable die.", __func__, devLogicId_);
57 0 : return HcclResult::HCCL_E_UNAVAIL;
58 : }
59 :
60 28 : auto ret = PreAllocBlockRes();
61 28 : if (ret == HcclResult::HCCL_E_UNAVAIL) {
62 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] pre alloc block res failed but passed, "
63 : "some sources are not enough, devLogicId[%d].", __func__, devLogicId_);
64 0 : return ret;
65 : }
66 28 : CHK_RET(ret);
67 :
68 28 : ret = missionMgr_.PreAlloc(devLogicId_, resStrategys_[0].missionNum, dieEnableFlags_);
69 28 : if (ret == HcclResult::HCCL_E_UNAVAIL) {
70 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] pre alloc mission res failed but passed, "
71 : "some sources are not enough, devLogicId[%d].", __func__, devLogicId_);
72 0 : return ret;
73 : }
74 28 : CHK_RET(ret);
75 :
76 28 : initFlag_ = true;
77 28 : return HcclResult::HCCL_SUCCESS;
78 : }
79 :
80 27 : HcclResult CcuResBatchAllocator::Deinit()
81 : {
82 27 : missionMgr_.Reset();
83 81 : for (uint8_t dieId = 0; dieId < CCU_MAX_IODIE_NUM; dieId++) {
84 54 : resBlocks_[dieId].clear();
85 : }
86 :
87 27 : handleMap_.clear();
88 27 : initFlag_ = false;
89 27 : return HcclResult::HCCL_SUCCESS;
90 : }
91 :
92 : struct CcuResBlockNum {
93 : uint32_t loopNum{0};
94 : uint32_t msNum{0};
95 : uint32_t ckeNum{0};
96 : };
97 :
98 56 : static CcuResBlockNum GetPreAllocatedMaxBlockNum(const uint32_t devLogicId, const uint8_t dieId,
99 : const std::array<CcuBlockResStrategy, CCU_MAX_IODIE_NUM> &resStrategys)
100 : {
101 56 : CcuResBlockNum blockNum{};
102 :
103 56 : CcuResSpecifications &ccuResSepcs = CcuResSpecifications::GetInstance(devLogicId);
104 :
105 56 : uint32_t loopNum = 0;
106 56 : (void)ccuResSepcs.GetLoopEngineNum(dieId, loopNum);
107 56 : blockNum.loopNum = loopNum / resStrategys[dieId].loopNum;
108 :
109 56 : uint32_t msNum = 0;
110 56 : (void)ccuResSepcs.GetMsNum(dieId, msNum);
111 56 : blockNum.msNum = msNum / resStrategys[dieId].msNum;
112 :
113 56 : uint32_t ckeNum = 0;
114 56 : (void)ccuResSepcs.GetCkeNum(dieId, ckeNum);
115 56 : const uint32_t maxCkeBlockNum = ckeNum / resStrategys[dieId].ckeNum;
116 56 : blockNum.ckeNum = std::min({std::max({blockNum.loopNum, blockNum.msNum}), maxCkeBlockNum});
117 :
118 56 : HCCL_INFO("[CcuResBatchAllocator][%s] batch allocator will alloc blocks resources: loop blocks[%u] "
119 : "ms blocks[%u] cke blocks[%u], devLogicId[%d] dieId[%u].", __func__, blockNum.loopNum,
120 : blockNum.msNum, blockNum.ckeNum, devLogicId, dieId);
121 56 : return blockNum;
122 : }
123 :
124 28 : HcclResult CcuResBatchAllocator::PreAllocBlockRes()
125 : {
126 28 : CcuComponent &ccuComponent = CcuComponent::GetInstance(devLogicId_);
127 28 : const auto serveMode = CcuResSpecifications::GetInstance(devLogicId_).GetServeMode();
128 84 : for (uint8_t dieId = 0; dieId < CCU_MAX_IODIE_NUM; dieId++) {
129 56 : if (!dieEnableFlags_[dieId]) {
130 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] devLogicId[%d] dieId[%u] is not enable, "
131 : "will not pre-allocate block resource.", __func__, devLogicId_, dieId);
132 0 : continue;
133 : }
134 :
135 56 : CcuResBlockNum blockNums = GetPreAllocatedMaxBlockNum(devLogicId_, dieId, resStrategys_);
136 : const std::array<std::tuple<ResType, uint32_t, uint32_t>, BLOCK_RES_TYPE_NUM> blockResReqs = {
137 56 : std::make_tuple(ResType::LOOP, blockNums.loopNum, resStrategys_[dieId].loopNum),
138 56 : std::make_tuple(ResType::MS, blockNums.msNum, resStrategys_[dieId].msNum),
139 56 : std::make_tuple(ResType::CKE, blockNums.ckeNum, resStrategys_[dieId].ckeNum),
140 168 : };
141 :
142 224 : for (auto &resReq : blockResReqs) {
143 168 : const ResType resType = std::get<0>(resReq);
144 168 : const uint32_t blockNum = std::get<1>(resReq);
145 168 : const uint32_t blockSize = std::get<2>(resReq);
146 168 : const uint32_t reqNum = blockNum * blockSize; // 生成时已保证不会溢出
147 168 : if (reqNum == 0) {
148 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] devLogicId[%d] dieId[%u], "
149 : "resType[%s], request num is 0, passed.", __func__,
150 : devLogicId_, dieId, resType.Describe().c_str());
151 0 : continue;
152 : }
153 :
154 168 : std::vector<ResInfo> tempResInfos;
155 168 : auto ret = ccuComponent.AllocRes(dieId, resType, reqNum, true, tempResInfos);
156 168 : if (ret == HcclResult::HCCL_E_UNAVAIL) {
157 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] failed, devLogicId[%d] dieId[%u], "
158 : "failed to pre allocate block type resource, resType[%s], num[%u].",
159 : __func__, devLogicId_, dieId, resType.Describe().c_str(), reqNum);
160 0 : return ret;
161 : }
162 168 : CHK_RET(ret);
163 :
164 168 : const bool avoidCcu0Flag = (serveMode == ServeMode::ARMX86 && dieId == 0 && resType == ResType::MS);
165 168 : std::vector<BlockInfo> tempBlocks;
166 168 : const uint32_t startId = tempResInfos[0].startId;
167 2184 : for (uint32_t k = 0; k < blockNum; k++) {
168 2016 : BlockInfo blockInfo;
169 2016 : blockInfo.id = k;
170 2016 : blockInfo.startId = startId + k * blockSize;
171 2016 : blockInfo.num = blockSize;
172 : // A+X形态,PCIE连接到IOdie0,导致IOdie0上连接PCIE的CCUA0无法使用,分配MS资源时需要跳过CCUA0
173 : // 给要分给CCUA0的块,设置成已分配过,防止后续分给算法使用
174 2016 : blockInfo.allocated = avoidCcu0Flag ? k % CCUA_NUM == 0 : false;
175 2016 : blockInfo.handle = 0;
176 2016 : tempBlocks.emplace_back(blockInfo);
177 : }
178 168 : resBlocks_[dieId].emplace_back(tempBlocks);
179 168 : }
180 : }
181 :
182 28 : return HcclResult::HCCL_SUCCESS;
183 : }
184 :
185 81 : static bool CheckReqValid(const CcuResReq &req, int32_t devLogicId,
186 : std::array<bool, CCU_MAX_IODIE_NUM> &dieEnableFlags)
187 : {
188 81 : bool ifValid = false;
189 243 : for (uint8_t i = 0; i < CCU_MAX_IODIE_NUM; i++) {
190 : const std::array<uint32_t, REQ_RES_TYPE_NUM> reqs = {
191 162 : req.loopEngineReq[i],
192 162 : req.blockLoopEngineReq[i],
193 162 : req.msReq[i],
194 162 : req.blockMsReq[i],
195 162 : req.ckeReq[i],
196 162 : req.blockCkeReq[i],
197 162 : req.continuousXnReq[i],
198 162 : req.xnReq[i],
199 162 : req.gsaReq[i],
200 162 : req.missionReq.req[i]
201 162 : };
202 :
203 324 : const bool ifReqEmpty = std::all_of(std::begin(reqs), std::end(reqs),
204 918 : [](uint32_t x) { return x == 0; });
205 162 : if (!dieEnableFlags[i] && !ifReqEmpty) { // 当前die未使能,但请求资源
206 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] failed, dieId[%u] is not enable, "
207 : "but resource request is not empty, devLogicId[%d].",
208 : __func__, i, devLogicId);
209 0 : return false;
210 : }
211 :
212 : // 当前die使能,并且请求资源即合法
213 162 : if (dieEnableFlags[i] && !ifReqEmpty) {
214 108 : ifValid = true;
215 : }
216 : }
217 :
218 81 : if (!ifValid) {
219 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] all dies resource request is empty, "
220 : "devLogicId[%d].", __func__, devLogicId);
221 : }
222 :
223 81 : return ifValid;
224 : }
225 :
226 81 : HcclResult CcuResBatchAllocator::AllocResHandle(const CcuResReq &resReq,
227 : CcuResHandle &resHandle)
228 : {
229 81 : if (!CheckReqValid(resReq, devLogicId_, dieEnableFlags_)) {
230 0 : resHandle = nullptr;
231 0 : HCCL_ERROR("[CcuResBatchAllocator][%s] failed, devLogicId[%d], invalid resource "
232 : "request, all resource request is empty.", __func__, devLogicId_);
233 0 : return HcclResult::HCCL_E_PARA;
234 : }
235 :
236 81 : std::unique_ptr<CcuResRepository> resRepoPtr = nullptr;
237 81 : resRepoPtr.reset(new (std::nothrow) CcuResRepository());
238 81 : CHK_PTR_NULL(resRepoPtr);
239 81 : const uintptr_t handleKey = reinterpret_cast<uintptr_t>(resRepoPtr.get());
240 : // 申请分配临时资源
241 81 : HcclResult ret = TryAllocResHandle(handleKey, resReq, resRepoPtr);
242 81 : if (ret != HcclResult::HCCL_SUCCESS) {
243 0 : resHandle = nullptr;
244 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] failed, devLogicId[%d], failed to "
245 : "allocate resource handle, release temporary resources of this request.",
246 : __func__, devLogicId_);
247 :
248 : // 释放申请的临时资源,由CcuResRepo对象对应的智能指针管理
249 0 : HcclResult releaseRet = ReleaseResource(resRepoPtr);
250 0 : if (releaseRet != HcclResult::HCCL_SUCCESS) {
251 0 : HCCL_ERROR("[CcuResBatchAllocator][%s] failed, devLogicId[%d], "
252 : "failed to release temporary resources of this request.",
253 : __func__, devLogicId_);
254 0 : return releaseRet;
255 : }
256 :
257 0 : HCCL_INFO("[CcuResBatchAllocator][%s] devLogicId[%d], "
258 : "temporary resources released.", __func__, devLogicId_);
259 0 : return ret;
260 : }
261 : // 保存资源信息
262 81 : resHandle = reinterpret_cast<CcuResHandle>(resRepoPtr.get());
263 81 : handleMap_[handleKey] = std::move(resRepoPtr);
264 :
265 81 : return HcclResult::HCCL_SUCCESS;
266 81 : }
267 :
268 189 : static HcclResult HandleBlockRes(const uintptr_t handleKey, const uint32_t num,
269 : const uint32_t blockSize, std::vector<BlockInfo> &blocks,
270 : std::vector<ResInfo> &resInfos)
271 : {
272 189 : uint32_t blockNum = 1 + (num - 1) / blockSize;
273 189 : uint32_t blockMaxSize = blocks.size();
274 189 : uint32_t blockStartId = blockMaxSize;
275 189 : uint32_t freeNum = 0;
276 189 : bool allocatable = false;
277 1323 : for (size_t k = 0; k < blockMaxSize; k++) {
278 : // 如果当前块已分配,说明当前分配不够,重置分配数量与起始id
279 1323 : if (blocks[k].allocated) {
280 0 : blockStartId = blockMaxSize;
281 0 : freeNum = 0;
282 0 : continue;
283 : }
284 : // 如果是首个可分配块,记录起始id
285 1323 : if (blockStartId == blockMaxSize) {
286 189 : blockStartId = k;
287 : }
288 : // 当前块未分配,更新可分配数量
289 1323 : freeNum++;
290 : // 可分配数量足够则分配成功
291 1323 : if (freeNum >= blockNum) {
292 189 : allocatable = true;
293 189 : break;
294 : }
295 : }
296 189 : if (!allocatable) {
297 0 : return HcclResult::HCCL_E_UNAVAIL;
298 : }
299 : // 更新所有新分配的块的信息
300 1512 : for (size_t k = blockStartId; k < blockStartId + blockNum; k++) {
301 1323 : blocks[k].handle = handleKey;
302 1323 : blocks[k].allocated = true;
303 : }
304 189 : resInfos.emplace_back(ResInfo{blocks[blockStartId].startId, blockNum * blockSize});
305 189 : return HcclResult::HCCL_SUCCESS;
306 : }
307 :
308 0 : static void DumpBlockResInfo(ResType resType, const std::vector<BlockInfo> &blocks)
309 : {
310 0 : HCCL_INFO("Dump ResType[%s] block resources info: ", resType.Describe().c_str());
311 0 : uint32_t blockNum = blocks.size();
312 0 : for (size_t k = 0; k < blockNum; k++) {
313 0 : HCCL_INFO("Block[id[%u], startId[%u], num[%u], handle(uintptr_t)[%llu], allocated[%d]]",
314 : blocks[k].id, blocks[k].startId, blocks[k].num, blocks[k].handle,
315 : static_cast<int>(blocks[k].allocated));
316 : }
317 0 : }
318 :
319 81 : HcclResult CcuResBatchAllocator::AllocBlockRes(const uintptr_t handleKey,
320 : const CcuResReq &resReq, std::unique_ptr<CcuResRepository> &resRepoPtr)
321 : {
322 : using ResTypeReqNumBlockNumFunc =
323 : std::tuple<ResType::Value, uint32_t, uint32_t, std::vector<ResInfo> &>;
324 :
325 243 : for (uint8_t dieId = 0; dieId < CCU_MAX_IODIE_NUM; dieId++) {
326 162 : if (!dieEnableFlags_[dieId]) {
327 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] devLogicId[%d] dieId[%u] is not enable, "
328 : "will not allocate block resource.", __func__, devLogicId_, dieId);
329 0 : continue;
330 : }
331 :
332 : std::array<ResTypeReqNumBlockNumFunc, BLOCK_RES_TYPE_NUM> blockReqParas = {
333 0 : std::make_tuple(ResType::LOOP, resReq.blockLoopEngineReq[dieId],
334 162 : resStrategys_[dieId].loopNum, std::ref(resRepoPtr->blockLoopEngine[dieId])),
335 0 : std::make_tuple(ResType::MS, resReq.blockMsReq[dieId],
336 162 : resStrategys_[dieId].msNum, std::ref(resRepoPtr->blockMs[dieId])),
337 0 : std::make_tuple(ResType::CKE, resReq.blockCkeReq[dieId],
338 162 : resStrategys_[dieId].ckeNum, std::ref(resRepoPtr->blockCke[dieId]))
339 486 : };
340 :
341 648 : for (uint32_t blockType = 0; blockType < BLOCK_RES_TYPE_NUM; blockType++) {
342 486 : const auto &req = blockReqParas[blockType];
343 486 : const uint32_t num = std::get<1>(req);
344 486 : if (num == 0) {
345 324 : continue;
346 : }
347 :
348 162 : const ResType resType = std::get<0>(req);
349 162 : const uint32_t blockSize = std::get<2>(req);
350 162 : auto &blocks = resBlocks_[dieId][blockType];
351 162 : auto &resInfos = std::get<3>(req);
352 162 : auto ret = HandleBlockRes(handleKey, num, blockSize, blocks, resInfos);
353 162 : if (ret != HcclResult::HCCL_SUCCESS) {
354 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] failed, devLogicId[%d] dieId[%u], "
355 : "failed to allocate [%s] block resource, remaining block resources are "
356 : "not enough, request num[%u].", __func__, devLogicId_, dieId,
357 : resType.Describe().c_str(), num);
358 0 : DumpBlockResInfo(std::get<0>(req), resBlocks_[dieId][blockType]);
359 0 : return ret;
360 : }
361 : }
362 : }
363 81 : return HcclResult::HCCL_SUCCESS;
364 : }
365 :
366 81 : HcclResult CcuResBatchAllocator::AllocConsecutiveRes(const CcuResReq &resReq,
367 : std::unique_ptr<CcuResRepository> &resRepoPtr) const
368 : {
369 : using ResTypeReqNumResInfoTuple = std::tuple<ResType, uint32_t, std::vector<ResInfo>&>;
370 :
371 81 : CcuComponent &ccuComponent = CcuComponent::GetInstance(devLogicId_);
372 243 : for (uint8_t dieId = 0; dieId < CCU_MAX_IODIE_NUM; dieId++) {
373 162 : if (!dieEnableFlags_[dieId]) {
374 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] devLogicId[%d] dieId[%u] is not enable, "
375 : "will not allocate consecutive resource.", __func__, devLogicId_, dieId);
376 0 : continue;
377 : }
378 :
379 : std::array<ResTypeReqNumResInfoTuple, CONS_RES_TYPE_NUM> reqParas = {
380 162 : std::make_tuple(ResType::XN, resReq.continuousXnReq[dieId],
381 162 : std::ref(resRepoPtr->continuousXn[dieId]))
382 162 : };
383 :
384 324 : for (const auto &req : reqParas) {
385 162 : if (std::get<1>(req) == 0) {
386 54 : continue;
387 : }
388 :
389 108 : std::vector<ResInfo> resInfos;
390 108 : auto ret = ccuComponent.AllocRes(dieId, std::get<0>(req), std::get<1>(req),
391 : true, resInfos);
392 108 : if (ret == HcclResult::HCCL_E_UNAVAIL) {
393 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] failed, devLogicId[%d] dieId[%u], "
394 : "failed to allocate %s resource, num[%u].", __func__, devLogicId_, dieId,
395 : std::get<0>(req).Describe().c_str(), std::get<1>(req));
396 0 : return ret;
397 : }
398 108 : CHK_RET(ret);
399 :
400 108 : std::get<2>(req) = resInfos;
401 108 : }
402 : }
403 :
404 81 : return HcclResult::HCCL_SUCCESS;
405 : }
406 :
407 81 : HcclResult CcuResBatchAllocator::AllocDiscreteRes(const CcuResReq &resReq,
408 : std::unique_ptr<CcuResRepository> &resRepoPtr) const
409 : {
410 : using ResTypeReqNumResInfoTuple = std::tuple<ResType, uint32_t, std::vector<ResInfo>&>;
411 :
412 81 : CcuComponent &ccuComponent = CcuComponent::GetInstance(devLogicId_);
413 243 : for (uint8_t dieId = 0; dieId < CCU_MAX_IODIE_NUM; dieId++) {
414 162 : if (!dieEnableFlags_[dieId]) {
415 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] devLogicId[%d] dieId[%u] is not enable, "
416 : "will not allocate discrete resource.", __func__, devLogicId_, dieId);
417 0 : continue;
418 : }
419 :
420 : std::array<ResTypeReqNumResInfoTuple, DISCRETE_RES_TYPE_NUM> reqParas = {
421 162 : std::make_tuple(ResType::LOOP, resReq.loopEngineReq[dieId],
422 162 : std::ref(resRepoPtr->loopEngine[dieId])),
423 162 : std::make_tuple(ResType::MS, resReq.msReq[dieId], std::ref(resRepoPtr->ms[dieId])),
424 162 : std::make_tuple(ResType::CKE, resReq.ckeReq[dieId], std::ref(resRepoPtr->cke[dieId])),
425 162 : std::make_tuple(ResType::XN, resReq.xnReq[dieId], std::ref(resRepoPtr->xn[dieId])),
426 162 : std::make_tuple(ResType::GSA, resReq.gsaReq[dieId], std::ref(resRepoPtr->gsa[dieId]))
427 810 : };
428 :
429 972 : for (const auto &req : reqParas) {
430 810 : if (std::get<1>(req) == 0) {
431 602 : continue;
432 : }
433 :
434 208 : std::vector<ResInfo> resInfos;
435 208 : auto ret = ccuComponent.AllocRes(dieId, std::get<0>(req), std::get<1>(req),
436 : false, resInfos);
437 208 : if (ret == HcclResult::HCCL_E_UNAVAIL) {
438 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] failed, devLogicId[%d] dieId[%u], "
439 : "failed to allocate %s resource, num[%u].", __func__, devLogicId_, dieId,
440 : std::get<0>(req).Describe().c_str(), std::get<1>(req));
441 0 : return ret;
442 : }
443 208 : CHK_RET(ret);
444 :
445 208 : std::get<2>(req) = resInfos; // 2: resRepotPtr to resource
446 208 : }
447 : }
448 :
449 81 : return HcclResult::HCCL_SUCCESS;
450 : }
451 :
452 81 : HcclResult CcuResBatchAllocator::TryAllocResHandle(const uintptr_t handleKey,
453 : const CcuResReq &resReq, std::unique_ptr<CcuResRepository> &resRepoPtr)
454 : {
455 81 : std::unique_lock<std::mutex> lock(innerMutex_);
456 :
457 81 : HcclResult ret = AllocBlockRes(handleKey, resReq, resRepoPtr);
458 81 : if (ret == HcclResult::HCCL_E_UNAVAIL) {
459 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] failed, devLogicId[%d], "
460 : "failed to allocate block type resource.", __func__, devLogicId_);
461 0 : return ret;
462 : }
463 81 : CHK_RET(ret);
464 :
465 81 : ret = missionMgr_.Alloc(handleKey, resReq.missionReq, resRepoPtr->mission);
466 81 : if (ret == HcclResult::HCCL_E_UNAVAIL) {
467 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] devLogicId[%d], failed to allocate "
468 : "mission resource, remaining block resources are not enough.",
469 : __func__, devLogicId_);
470 0 : return ret;
471 : }
472 81 : CHK_RET(ret);
473 :
474 81 : ret = AllocConsecutiveRes(resReq, resRepoPtr);
475 81 : if (ret == HcclResult::HCCL_E_UNAVAIL) {
476 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] devLogicId[%d], failed to allocate "
477 : "consecutive resource.", __func__, devLogicId_);
478 0 : return ret;
479 : }
480 81 : CHK_RET(ret);
481 :
482 81 : ret = AllocDiscreteRes(resReq, resRepoPtr);
483 81 : if (ret == HcclResult::HCCL_E_UNAVAIL) {
484 0 : HCCL_WARNING("[CcuResBatchAllocator][%s] devLogicId[%d], failed to allocate "
485 : "discrete resource.", __func__, devLogicId_);
486 0 : return ret;
487 : }
488 81 : CHK_RET(ret);
489 :
490 81 : return HcclResult::HCCL_SUCCESS;
491 81 : }
492 :
493 189 : static void ReleaseBlockRes(const uint32_t blockSize, std::vector<BlockInfo> &blocks,
494 : std::vector<ResInfo> &resInfos)
495 : {
496 189 : uint32_t startId = resInfos[0].startId;
497 189 : uint32_t num = resInfos[0].num;
498 189 : uint32_t startBlockId = (startId - blocks[0].startId) / blockSize;
499 189 : uint32_t blockNum = num / blockSize;
500 :
501 1512 : for (uint32_t k = startBlockId; k < startBlockId + blockNum; k++) {
502 1323 : blocks[k].handle = 0;
503 1323 : blocks[k].allocated = false;
504 : }
505 189 : resInfos.clear();
506 189 : }
507 :
508 27 : HcclResult CcuResBatchAllocator::ReleaseResHandle(const CcuResHandle &handle)
509 : {
510 27 : std::unique_lock<std::mutex> lock(innerMutex_);
511 :
512 27 : uintptr_t handleKey = reinterpret_cast<uintptr_t>(handle);
513 27 : if (handleMap_.find(handleKey) == handleMap_.end()) {
514 0 : HCCL_ERROR("[CcuResBatchAllocator][%s] failed, devLogicId[%d], "
515 : "failed to find resource repository, invalid resource handle(uintptr_t)[%llu]",
516 : __func__, devLogicId_, handleKey);
517 0 : return HcclResult::HCCL_E_PARA;
518 : }
519 :
520 27 : std::unique_ptr<CcuResRepository> &resRepoPtr = handleMap_[handleKey];
521 :
522 27 : auto ret = ReleaseResource(resRepoPtr);
523 27 : if (ret != HcclResult::HCCL_SUCCESS) {
524 0 : HCCL_ERROR("[CcuResBatchAllocator][%s] failed, devLogicId[%d], "
525 : "failed[%u] to release resource.", __func__, devLogicId_, ret);
526 0 : return ret;
527 : }
528 :
529 27 : handleMap_.erase(handleKey);
530 27 : return HcclResult::HCCL_SUCCESS;
531 27 : }
532 :
533 27 : HcclResult CcuResBatchAllocator::ReleaseResource(std::unique_ptr<CcuResRepository> &resRepoPtr)
534 : {
535 27 : ReleaseBlockResource(resRepoPtr);
536 27 : missionMgr_.Release(resRepoPtr->mission);
537 27 : HcclResult ret = ReleaseNonBlockTypeRes(resRepoPtr);
538 27 : if (ret != HcclResult::HCCL_SUCCESS) {
539 0 : HCCL_ERROR("[CcuResBatchAllocator][%s] failed, devLogicId[%d], "
540 : "failed[%u] to release discrete resource.", __func__, devLogicId_, ret);
541 0 : return ret;
542 : }
543 :
544 27 : return HcclResult::HCCL_SUCCESS;
545 : }
546 :
547 27 : void CcuResBatchAllocator::ReleaseBlockResource(std::unique_ptr<CcuResRepository> &resRepoPtr)
548 : {
549 : using BlockSizeResNum = std::pair<uint32_t, std::vector<ResInfo>&>;
550 :
551 81 : for (uint8_t i = 0; i < CCU_MAX_IODIE_NUM; i++) {
552 54 : if (!dieEnableFlags_[i]) {
553 0 : continue;
554 : }
555 :
556 : const std::array<BlockSizeResNum, BLOCK_RES_TYPE_NUM> blockReqParas = {
557 54 : std::make_pair(resStrategys_[i].loopNum, std::ref(resRepoPtr->blockLoopEngine[i])),
558 54 : std::make_pair(resStrategys_[i].msNum, std::ref(resRepoPtr->blockMs[i])),
559 54 : std::make_pair(resStrategys_[i].ckeNum, std::ref(resRepoPtr->blockCke[i]))
560 : };
561 :
562 216 : for (uint32_t j = 0; j < BLOCK_RES_TYPE_NUM; j++) {
563 162 : auto req = blockReqParas[j];
564 162 : std::vector<ResInfo> &resInfos = req.second;
565 162 : if (resInfos.size() == 0) {
566 0 : continue;
567 : }
568 :
569 162 : ReleaseBlockRes(req.first, resBlocks_[i][j], resInfos);
570 : }
571 : }
572 27 : }
573 :
574 : using ResTypeResInfo = std::pair<ResType, std::vector<ResInfo>*>;
575 158 : static auto EraseReverse(std::vector<ResInfo>& vec,
576 : std::vector<ResInfo>::reverse_iterator it)
577 : -> std::vector<ResInfo>::reverse_iterator
578 : {
579 : return std::vector<ResInfo>::reverse_iterator(
580 316 : vec.erase(std::next(it).base())
581 158 : );
582 : }
583 :
584 54 : static HcclResult DoReleaseNonBlockTypeRes(
585 : int32_t devLogicId, uint8_t dieId,
586 : std::array<ResTypeResInfo, NON_BLOCK_TYPE_NUM>& infoParas)
587 : {
588 54 : CcuComponent& ccuComponent = CcuComponent::GetInstance(devLogicId);
589 :
590 378 : for (auto& infos : infoParas) {
591 324 : const ResType resType = infos.first;
592 324 : std::vector<ResInfo>* resInfosPtr = infos.second;
593 324 : if (resInfosPtr == nullptr || resInfosPtr->empty()) {
594 166 : continue;
595 : }
596 158 : std::vector<ResInfo>& resInfos = *resInfosPtr;
597 : // 倒序删除,减少vector元素移动
598 316 : for (auto it = resInfos.rbegin(); it != resInfos.rend(); ) {
599 158 : const uint32_t num = it->num;
600 158 : if (num == 0) {
601 0 : it = EraseReverse(resInfos, it);
602 0 : continue;
603 : }
604 :
605 158 : const uint32_t startId = it->startId;
606 158 : auto ret = ccuComponent.ReleaseRes(dieId, resType, startId, num);
607 158 : if (ret != HcclResult::HCCL_SUCCESS) {
608 0 : HCCL_ERROR("[CcuResBatchAllocator][%s] failed, devLogicId[%d] dieId[%u], "
609 : "failed to release %s resource, startId[%u], num[%u].", __func__,
610 : devLogicId, dieId, resType.Describe().c_str(), startId, num);
611 0 : return ret;
612 : }
613 :
614 158 : it = EraseReverse(resInfos, it);
615 : }
616 : }
617 54 : return HcclResult::HCCL_SUCCESS;
618 : }
619 :
620 27 : HcclResult CcuResBatchAllocator::ReleaseNonBlockTypeRes(
621 : std::unique_ptr<CcuResRepository>& resRepoPtr) const
622 : {
623 81 : for (uint8_t dieId = 0; dieId < CCU_MAX_IODIE_NUM; dieId++) {
624 54 : if (!dieEnableFlags_[dieId]) {
625 0 : continue;
626 : }
627 :
628 : std::array<ResTypeResInfo, NON_BLOCK_TYPE_NUM> infoParas = {{
629 54 : {ResType::LOOP, &resRepoPtr->loopEngine[dieId]},
630 54 : {ResType::MS, &resRepoPtr->ms[dieId]},
631 54 : {ResType::CKE, &resRepoPtr->cke[dieId]},
632 54 : {ResType::XN, &resRepoPtr->continuousXn[dieId]},
633 54 : {ResType::XN, &resRepoPtr->xn[dieId]},
634 54 : {ResType::GSA, &resRepoPtr->gsa[dieId]}
635 324 : }};
636 :
637 54 : CHK_RET(DoReleaseNonBlockTypeRes(devLogicId_, dieId, infoParas));
638 : }
639 :
640 27 : return HcclResult::HCCL_SUCCESS;
641 : }
642 :
643 134 : HcclResult CcuResBatchAllocator::GetResource(const CcuResHandle &handle,
644 : CcuResRepository &ccuResRepo)
645 : {
646 134 : std::unique_lock<std::mutex> lock(innerMutex_);
647 :
648 134 : uintptr_t handleKey = reinterpret_cast<uintptr_t>(handle);
649 134 : if (handleMap_.find(handleKey) == handleMap_.end()) {
650 0 : HCCL_ERROR("[CcuResBatchAllocator][%s] devLogicId[%d], failed to find "
651 : "resource repository, invalid resource handle(uintptr_t)[%lu]",
652 : __func__, devLogicId_, handleKey);
653 0 : return HcclResult::HCCL_E_PARA;
654 : }
655 :
656 134 : ccuResRepo = *(handleMap_[handleKey].get());
657 134 : return HcclResult::HCCL_SUCCESS;
658 134 : }
659 :
660 28 : static HcclResult PreAllocMissionRes(int32_t devLogicId,
661 : std::array<bool, CCU_MAX_IODIE_NUM> &dieEnableFlags,
662 : std::array<uint32_t, CCU_MAX_IODIE_NUM> &missionNums,
663 : std::array<uint32_t, CCU_MAX_IODIE_NUM> &missionStartIds)
664 : {
665 28 : auto &ccuResSepcs = CcuResSpecifications::GetInstance(devLogicId);
666 28 : auto &ccuComponent = CcuComponent::GetInstance(devLogicId);
667 84 : for (uint8_t i = 0; i < CCU_MAX_IODIE_NUM; i++) {
668 56 : if (!dieEnableFlags[i]) {
669 0 : missionNums[i] = 0;
670 0 : missionStartIds[i] = 0;
671 0 : continue;
672 : }
673 :
674 56 : (void)ccuResSepcs.GetMissionNum(i, missionNums[i]);
675 56 : std::vector<ResInfo> tempResInfos;
676 56 : auto ret = ccuComponent.AllocRes(i, ResType::MISSION, missionNums[i],
677 : true, tempResInfos);
678 56 : if (ret == HcclResult::HCCL_E_UNAVAIL) {
679 0 : HCCL_WARNING("[CcuMissionMgr][%s] devLogicId[%d] dieId[%u], failed[%u] "
680 : "to pre allocate mission resource, num[%u]", __func__, devLogicId,
681 : i, ret, missionNums[i]);
682 0 : return ret;
683 : }
684 56 : CHK_RET(ret);
685 :
686 56 : missionStartIds[i] = tempResInfos[0].startId;
687 56 : }
688 :
689 28 : return HcclResult::HCCL_SUCCESS;
690 : }
691 :
692 28 : HcclResult CcuResBatchAllocator::CcuMissionMgr::PreAlloc(const int32_t devLogicId,
693 : const uint32_t blockSize, const std::array<bool, CCU_MAX_IODIE_NUM> &dieFlags)
694 : {
695 28 : dieEnableFlags_ = dieFlags;
696 : std::array<uint32_t, CCU_MAX_IODIE_NUM> missionNums;
697 : std::array<uint32_t, CCU_MAX_IODIE_NUM> missionStartIds;
698 :
699 28 : auto ret = PreAllocMissionRes(devLogicId, dieEnableFlags_,
700 : missionNums, missionStartIds);
701 28 : if (ret != HcclResult::HCCL_SUCCESS) {
702 0 : return ret;
703 : }
704 :
705 28 : uint32_t missionNum = 0;
706 28 : if (dieEnableFlags_[0]) {
707 28 : missionNum = missionNums[0];
708 0 : } else if (dieEnableFlags_[1]) {
709 0 : missionNum = missionNums[1];
710 : }
711 :
712 56 : if (dieEnableFlags_[0] && dieEnableFlags_[1] &&
713 28 : missionStartIds[0] != missionStartIds[1]) {
714 : // 当前 FUSION_MULTIPLE_DIE 要求多Die ID一致
715 0 : HCCL_ERROR("[CcuMissionMgr][%s] devLogicId[%d] die 0 allocated missions "
716 : "start with id %u, die 1 allocated missions start with id %u, the start "
717 : "id should be same.", __func__, devLogicId, missionStartIds[0],
718 : missionStartIds[1]);
719 0 : return HcclResult::HCCL_E_INTERNAL;
720 : }
721 :
722 28 : stragtegy_ = blockSize;
723 28 : uint32_t blockNum = missionNum / stragtegy_;
724 252 : for (uint32_t i = 0; i < blockNum; i++) {
725 224 : BlockInfo blockInfo;
726 224 : blockInfo.id = i;
727 224 : blockInfo.startId = missionStartIds[0] + i * stragtegy_;
728 224 : blockInfo.num = stragtegy_;
729 224 : blockInfo.allocated = false;
730 224 : blockInfo.handle = 0;
731 224 : blocks_.emplace_back(blockInfo);
732 : }
733 :
734 28 : return HcclResult::HCCL_SUCCESS;
735 : }
736 :
737 83 : static uint32_t Check2DieMissionReqNum(const MissionReq &missionReq,
738 : const std::array<bool, CCU_MAX_IODIE_NUM> &dieEnableFlags)
739 : {
740 83 : uint32_t die0ReqNum = missionReq.req[0];
741 83 : uint32_t die1ReqNum = missionReq.req[1];
742 :
743 83 : if (dieEnableFlags[0] && dieEnableFlags[1]) {
744 81 : if (die0ReqNum != die1ReqNum) {
745 0 : HCCL_WARNING("[CcuMissionMgr][Alloc] die 0 request %u, die 1 request %u, "
746 : "will choose the larger one.", die0ReqNum, die1ReqNum);
747 0 : return std::max(die0ReqNum, die1ReqNum);
748 : }
749 :
750 81 : return die0ReqNum;
751 : }
752 :
753 2 : if (dieEnableFlags[0]) {
754 0 : return die0ReqNum;
755 : }
756 :
757 2 : if (dieEnableFlags[1]) {
758 0 : return die1ReqNum;
759 : }
760 :
761 2 : return 0;
762 : }
763 :
764 83 : HcclResult CcuResBatchAllocator::CcuMissionMgr::Alloc(const uintptr_t handleKey,
765 : const MissionReq &missionReq, MissionResInfo &missionInfos)
766 : {
767 83 : MissionReqType reqType = missionReq.reqType;
768 83 : constexpr MissionReqType defaultReqType = MissionReqType::FUSION_MULTIPLE_DIE;
769 83 : if (missionReq.reqType != MissionReqType::FUSION_MULTIPLE_DIE) {
770 1 : HCCL_WARNING("[CcuMissionMgr][%s] mission reqType[%d], mission resources "
771 : "now only support %d.", __func__, reqType,
772 : defaultReqType);
773 1 : reqType = MissionReqType::FUSION_MULTIPLE_DIE;
774 : }
775 :
776 83 : uint32_t reqNum = Check2DieMissionReqNum(missionReq, dieEnableFlags_);
777 83 : if (reqNum == 0) {
778 56 : HCCL_INFO("[CcuMissionMgr][%s] passed, request mission num is 0, "
779 : "will not allocate mission resource.", __func__);
780 56 : return HcclResult::HCCL_SUCCESS;
781 : }
782 :
783 27 : std::vector<ResInfo> resInfos;
784 27 : auto ret = HandleBlockRes(handleKey, reqNum, stragtegy_, blocks_, resInfos);
785 27 : if (ret == HcclResult::HCCL_E_UNAVAIL) {
786 0 : HCCL_WARNING("[CcuMissionMgr][%s] failed, mission block resources are unavailable, "
787 : "reqNum[%u], stragtegy[%u], reqType[%d].", __func__, reqNum, stragtegy_,
788 : reqType);
789 0 : DumpBlockResInfo(ResType::MISSION, blocks_);
790 0 : return ret;
791 : }
792 27 : CHK_RET(ret);
793 :
794 27 : missionInfos.reqType = reqType;
795 :
796 81 : for (uint8_t i = 0; i < CCU_MAX_IODIE_NUM; i++) {
797 54 : if (dieEnableFlags_[i]) {
798 54 : missionInfos.mission[i] = resInfos;
799 : }
800 : }
801 :
802 27 : return HcclResult::HCCL_SUCCESS;
803 27 : }
804 :
805 27 : void CcuResBatchAllocator::CcuMissionMgr::Release(MissionResInfo &missionInfos)
806 : {
807 : // 目前支持 FUSION_MULTIPLE_DIE 类型,故多die同步释放
808 27 : for (uint8_t i = 0; i < CCU_MAX_IODIE_NUM; i++) {
809 27 : if (dieEnableFlags_[i] && missionInfos.mission[i].size() != 0) {
810 27 : ReleaseBlockRes(stragtegy_, blocks_, missionInfos.mission[i]);
811 27 : break;
812 : }
813 : }
814 :
815 81 : for (uint8_t i = 0; i < CCU_MAX_IODIE_NUM; i++) {
816 54 : missionInfos.mission[i].clear();
817 : }
818 27 : }
819 :
820 27 : void CcuResBatchAllocator::CcuMissionMgr::Reset()
821 : {
822 27 : blocks_.clear();
823 27 : }
824 :
825 : }; // namespace hcomm
|