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