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