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_channel_ctx_pool.h"
12 :
13 : #include <unordered_set>
14 :
15 : #include "ccu_device_pub.h"
16 : #include "orion_adpt_utils.h"
17 :
18 : namespace hcomm {
19 :
20 : constexpr uint32_t CCU_DEFAULT_REQUEST_SQ_SIZE = 128;
21 : constexpr uint32_t CCU_DEFAULT_REQUEST_CHANNEL_NUM = 1;
22 : constexpr uint32_t CCU_DEFAULT_REQUEST_JETTY_NUM = 0; // 申请数量为0时,由平台层决定提供数量
23 :
24 29 : CcuChannelCtxPool::CcuChannelCtxPool(int32_t devLogicId) : devLogicId_(devLogicId) {}
25 :
26 29 : CcuChannelCtxPool::~CcuChannelCtxPool()
27 : {
28 : // 对象析构时清空多个map,batchMap_中元素的jettys清空触发ccuJetty析构释放
29 29 : (void)ReleaseConfirmedChannelRes();
30 29 : }
31 :
32 15 : HcclResult CcuChannelCtxPool::ResourceBatch::Init(const std::vector<CcuChannelInfo>& channelInfos)
33 : {
34 15 : const uint32_t channelNum = channelInfos.size();
35 15 : channelIdKeys.reserve(channelNum);
36 15 : availableChannelIdKeys.reserve(channelNum);
37 44 : for (const auto& channelInfo : channelInfos) {
38 29 : const auto dieId = channelInfo.dieId;
39 29 : const auto channelId = channelInfo.channelId;
40 29 : channelIdKeys.emplace_back(dieId, channelId);
41 29 : availableChannelIdKeys.emplace_back(dieId, channelId);
42 :
43 58 : for (const auto& jettyInfo : channelInfo.jettyInfos) {
44 29 : const auto taJettyId = jettyInfo.taJettyId;
45 29 : const auto jettyIdKey = std::make_pair(dieId, taJettyId);
46 29 : if (jettys.find(jettyIdKey) != jettys.end()) {
47 14 : continue;
48 : }
49 :
50 15 : std::unique_ptr<CcuJetty> ccuJetty;
51 15 : CHK_RET(CcuCreateJetty(key, jettyInfo, ccuJetty));
52 :
53 15 : jettys[jettyIdKey] = std::move(ccuJetty);
54 15 : }
55 : }
56 :
57 15 : return HcclResult::HCCL_SUCCESS;
58 : }
59 :
60 15 : HcclResult CcuChannelCtxPool::PrepareCreate(const std::vector<Hccl::LinkData>& links, uint32_t sqSize)
61 : {
62 15 : CHK_PRT_RET(
63 : links.empty(),
64 : HCCL_INFO("[CcuChannelCtxPool][%s] passed, links is empty, devLogicId[%d].", __func__, devLogicId_),
65 : HcclResult::HCCL_SUCCESS);
66 :
67 30 : for (const auto& link : links) {
68 15 : auto it = allocatedChannelIdMap_.find(link);
69 15 : if (it != allocatedChannelIdMap_.end()) {
70 0 : HCCL_INFO(
71 : "[CcuChannelCtxPool][%s] passed, link[%s] is already allocated, "
72 : "devLogicId[%d].",
73 : __func__, link.Describe().c_str(), devLogicId_);
74 0 : continue;
75 : }
76 :
77 15 : const auto& locAddr = link.GetLocalAddr();
78 15 : ResourceBatch* batchPtr = nullptr;
79 15 : auto ret = GetAvailableBatch(locAddr, batchPtr, sqSize);
80 15 : CHK_PRT_RET(
81 : ret == HcclResult::HCCL_E_UNAVAIL,
82 : HCCL_WARNING(
83 : "[CcuChannelCtxPool][%s] failed to alloc ccu channels, ccu resources "
84 : "are unavailable, locAddr[%s], devLogicId[%d], sqSize[%u].",
85 : __func__, locAddr.Describe().c_str(), devLogicId_, sqSize),
86 : ret);
87 15 : CHK_RET(ret);
88 :
89 15 : ChannelIdKey channelIdKey = batchPtr->availableChannelIdKeys.back();
90 15 : batchPtr->availableChannelIdKeys.pop_back();
91 15 : unconfirmedRecord_.allocations.emplace_back(Allocation{link, channelIdKey, batchPtr});
92 15 : allocatedChannelIdMap_[link] = channelIdKey;
93 15 : channelRemoteRankIdMap_[channelIdKey] = link.GetRemoteRankId();
94 :
95 15 : HCCL_INFO(
96 : "[CcuChannelCtxPool][%s] allocated new channelId[%u] of die[%u] to link[%s], "
97 : "devLogicId[%d], sqSize[%u].",
98 : __func__, channelIdKey.second, channelIdKey.first, link.Describe().c_str(), devLogicId_, sqSize);
99 : }
100 :
101 15 : isReleased_ = false;
102 15 : return HcclResult::HCCL_SUCCESS;
103 : }
104 :
105 : // 当前以locAddr为粒度调用,根据locAddr可以找到已申请的批次,如果资源充足则复用,不足则按新批次申请资源
106 15 : HcclResult CcuChannelCtxPool::GetAvailableBatch(const BatchKey& batchKey, ResourceBatch*& batchPtr, uint32_t sqSize)
107 : {
108 : // 当前以locAddr作为batchKey,不同本端不能复用资源
109 15 : if (FindAvailableBatch(batchKey, batchPtr)) {
110 0 : return HcclResult::HCCL_SUCCESS;
111 : }
112 : // 已有的资源不足,需要新增资源,获取的channel数量可能超过申请数量
113 15 : CommAddr commAddr{};
114 15 : CHK_RET(IpAddressToCommAddr(batchKey, commAddr));
115 : // 使用传入的sqSize,如果为0xFFFFFFFF则使用默认值
116 15 : uint32_t actualSqSize = (sqSize != 0xFFFFFFFF) ? sqSize : CCU_DEFAULT_REQUEST_SQ_SIZE;
117 : const CcuChannelPara channelPara{
118 15 : commAddr, CCU_DEFAULT_REQUEST_CHANNEL_NUM, CCU_DEFAULT_REQUEST_JETTY_NUM, actualSqSize};
119 15 : std::vector<CcuChannelInfo> channelInfos;
120 15 : auto ret = CcuAllocChannels(devLogicId_, channelPara, channelInfos);
121 15 : CHK_PRT_RET(
122 : ret == HcclResult::HCCL_E_UNAVAIL,
123 : HCCL_WARNING(
124 : "[CcuChannelCtxPool][%s] failed to alloc ccu channels, ccu resources "
125 : "are unavailable, locAddr[%s] devLogicId[%d].",
126 : __func__, batchKey.Describe().c_str(), devLogicId_),
127 : ret);
128 15 : CHK_RET(ret);
129 : // 如果新增资源保存失败,手动释放避免泄露
130 15 : ret = CreateAndSaveNewBatch(batchKey, channelInfos, batchPtr);
131 15 : if (ret != HcclResult::HCCL_SUCCESS) {
132 0 : HCCL_ERROR(
133 : "[CcuChannelCtxPool][%s] failed, try to release temp ccu resources, locAddr[%s], "
134 : "devLogicId[%d], .",
135 : __func__, batchKey.Describe().c_str(), devLogicId_);
136 0 : for (const auto& channelInfo : channelInfos) {
137 0 : const auto dieId = channelInfo.dieId;
138 0 : const auto channelId = channelInfo.channelId;
139 0 : CHK_RET(CcuReleaseChannel(devLogicId_, dieId, channelId));
140 : }
141 0 : return ret;
142 : }
143 15 : return HcclResult::HCCL_SUCCESS;
144 15 : }
145 :
146 15 : HcclResult CcuChannelCtxPool::CreateAndSaveNewBatch(
147 : const BatchKey& batchKey, const std::vector<CcuChannelInfo> channelInfos, ResourceBatch*& batchPtr)
148 : {
149 : // todo: 需要检查资源管理是否存在泄露可能
150 15 : auto& batches = batchMap_[batchKey];
151 15 : std::unique_ptr<ResourceBatch> newBatch{nullptr};
152 15 : newBatch.reset(new (std::nothrow) ResourceBatch(batchKey));
153 15 : CHK_PTR_NULL(newBatch);
154 15 : CHK_RET(newBatch->Init(channelInfos));
155 44 : for (const auto& channelInfo : channelInfos) {
156 29 : const auto dieId = channelInfo.dieId;
157 29 : const auto channelIdKey = std::make_pair(dieId, channelInfo.channelId);
158 :
159 29 : std::vector<CcuJetty*> jettys;
160 58 : for (const auto& jettyInfo : channelInfo.jettyInfos) {
161 29 : const auto jettyIdKey = std::make_pair(dieId, jettyInfo.taJettyId);
162 29 : jettys.emplace_back(newBatch->jettys[jettyIdKey].get());
163 : }
164 :
165 29 : channelJettyInfoMap_.emplace(channelIdKey, std::make_pair(channelInfo, jettys));
166 29 : usedChannelCntMap_[dieId] += 1;
167 29 : }
168 :
169 15 : batches.push_back(std::move(newBatch));
170 15 : ResourceBatch* rawBatch = batches.back().get();
171 :
172 15 : unconfirmedRecord_.newBatchSet.insert(rawBatch);
173 15 : batchPtr = rawBatch;
174 15 : return HcclResult::HCCL_SUCCESS;
175 15 : }
176 :
177 15 : bool CcuChannelCtxPool::FindAvailableBatch(const BatchKey& batchKey, ResourceBatch*& batchPtr) const
178 : {
179 15 : auto it = batchMap_.find(batchKey);
180 15 : if (it == batchMap_.end()) {
181 15 : return false;
182 : }
183 :
184 0 : auto& batches = it->second;
185 0 : if (batches.empty()) {
186 0 : return false;
187 : }
188 : // 当前分配逻辑只有最后一个batch可能还有空闲资源
189 0 : auto& lastBatch = batches.back();
190 0 : if (lastBatch->availableChannelIdKeys.empty()) {
191 0 : return false;
192 : }
193 :
194 0 : batchPtr = lastBatch.get();
195 0 : return true;
196 : }
197 :
198 : HcclResult
199 15 : CcuChannelCtxPool::GetChannelCtx(const Hccl::LinkData& link, CcuChannelCtxPool::CcuChannelCtx& channelCtx) const
200 : {
201 15 : const auto& it = allocatedChannelIdMap_.find(link);
202 15 : CHK_PRT_RET(
203 : it == allocatedChannelIdMap_.end(),
204 : HCCL_ERROR(
205 : "[CcuChannelCtxPool][%s] failed to find allocated channelId of link[%s], ", "devLogicId[%d].", __func__,
206 : link.Describe().c_str(), devLogicId_),
207 : HcclResult::HCCL_E_NOT_FOUND);
208 : // 内部维护数据保证channelJettyInfoMap_记录的资源存在
209 15 : channelCtx = channelJettyInfoMap_.at(it->second);
210 15 : return HcclResult::HCCL_SUCCESS;
211 : }
212 :
213 29 : HcclResult CcuChannelCtxPool::ReleaseConfirmedChannelRes()
214 : {
215 58 : for (const auto& infoEntry : channelJettyInfoMap_) {
216 29 : const auto& channelIdKey = infoEntry.first;
217 29 : const auto dieId = channelIdKey.first;
218 29 : const auto channelId = channelIdKey.second;
219 29 : CHK_RET(CcuReleaseChannel(devLogicId_, dieId, channelId));
220 : }
221 29 : isReleased_ = true;
222 29 : return HcclResult::HCCL_SUCCESS;
223 : }
224 :
225 0 : HcclResult CcuChannelCtxPool::GetCcuChannelCtxById(const std::pair<uint8_t, uint32_t>& key, CcuChannelCtx& ctx)
226 : {
227 0 : auto it = channelJettyInfoMap_.find(key);
228 0 : if (it == channelJettyInfoMap_.end()) {
229 0 : HCCL_ERROR("[%s]fail, key[%u, %u] not found", __func__, key.first, key.second);
230 0 : return HCCL_E_NOT_FOUND;
231 : }
232 0 : ctx = it->second;
233 0 : return HCCL_SUCCESS;
234 : }
235 : } // namespace hcomm
|