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 "log.h"
12 :
13 : #include "alg_data_trans_wrapper.h"
14 : #include "ins_temp_scatter_mesh_1d.h"
15 :
16 : namespace Hccl {
17 0 : InsTempScatterMesh1D::InsTempScatterMesh1D(
18 : const RankId virtualRank, const u32 tempRankSize, const std::vector<std::vector<RankId>>& tempVTopo,
19 0 : const std::map<RankId, u32>& tempVirtRankMap)
20 0 : : InsAlgTemplateBase(virtualRank, tempRankSize, tempVTopo, tempVirtRankMap)
21 0 : {}
22 :
23 0 : InsTempScatterMesh1D::~InsTempScatterMesh1D() {}
24 :
25 0 : HcclResult InsTempScatterMesh1D::CalcRes(AlgTempResReq& tempResReq)
26 : {
27 0 : HCCL_DEBUG("Enter InsTempScatterMesh1D::CalcRes");
28 0 : CHK_RET(CalcResLinksMesh(myRank_, tempRankSize_, tempVTopo_, linkNumBtwPeers_, tempResReq));
29 0 : auto& linkReq = tempResReq.links;
30 0 : u32 pathNum = 0;
31 0 : for (auto resReqIter = linkReq.begin(); resReqIter != linkReq.end(); resReqIter++) {
32 0 : auto remoteRank = resReqIter->first;
33 0 : if (rank2PathNumMap_.find(remoteRank) == rank2PathNumMap_.end() || rank2PathNumMap_[remoteRank] == 0) {
34 0 : HCCL_ERROR("[InsTempScatterMesh1D] No path to remoteRank[%d]", remoteRank);
35 0 : return HcclResult::HCCL_E_INTERNAL;
36 : }
37 0 : if (pathNum == 0) {
38 0 : pathNum = rank2PathNumMap_[remoteRank];
39 0 : } else if (rank2PathNumMap_[remoteRank] != pathNum) {
40 0 : HCCL_ERROR(
41 : "[InsTempScatterMesh1D] Inconsistency pathNum to remoteRanks, Previous consistent pathNum=[%u], "
42 : "mismatched "
43 : "remoteRank=[%d], pathNum=[%u]",
44 : pathNum, remoteRank, rank2PathNumMap_[remoteRank]);
45 0 : return HcclResult::HCCL_E_INTERNAL;
46 : }
47 0 : resReqIter->second = pathNum;
48 : }
49 :
50 0 : tempResReq.queNum = tempVTopo_[0].size() * pathNum;
51 0 : HCCL_INFO("[InsTempScatterMesh1D] tempResReq.queNum = %u", tempResReq.queNum);
52 0 : tempResReq.streamNum = tempResReq.queNum;
53 0 : tempResReq.queNotifys = CreateMasterSlaveQueNotifiesRequest(tempResReq.queNum);
54 :
55 0 : QId centerQ = 0;
56 0 : tempResReq.localWaitGroupCntNotify.emplace_back(centerQ, 0);
57 0 : tempResReq.localBcastPostCntNotify.emplace_back(centerQ, 0);
58 :
59 0 : return HcclResult::HCCL_SUCCESS;
60 : }
61 :
62 0 : u32 InsTempScatterMesh1D::CalcScratchMultiple(BufferType inBuffType, BufferType outBuffType)
63 : {
64 : (void)inBuffType;
65 : (void)outBuffType;
66 0 : if (op_.opMode == OpMode::OPBASE) {
67 0 : return 1;
68 : } else {
69 0 : return 0;
70 : }
71 : }
72 :
73 : // 需要支持 input->output, input->scratch, scratch->output
74 0 : HcclResult InsTempScatterMesh1D::GenExtIns(
75 : TempFuncs& tempFuncs, TemplateDataParams& tempAlgParams, ResLinks& tempResLinks,
76 : std::vector<InsQuePtr>& tempInsQues)
77 : {
78 0 : HCCL_INFO("[InsTempScatterMesh1D][Run] start: Rank [%d]", myRank_);
79 :
80 0 : opMode_ = tempFuncs.opMode;
81 0 : buffInfo_ = tempAlgParams.buffInfo;
82 0 : majorQueNum_ = tempVTopo_[0].size();
83 0 : isZeroCopy_ = opMode_ == OpMode::OFFLOAD && buffInfo_.inBuffType == BufferType::INPUT
84 0 : && buffInfo_.outBuffType == BufferType::OUTPUT;
85 :
86 0 : uint32_t linkNum = tempResLinks.begin()->second.size();
87 : // 流的数量不能少于linkNum
88 0 : CHK_PRT_RET(
89 : linkNum > tempInsQues.size(),
90 : HCCL_ERROR("[CollAlgFactory] [InsTempScatterMesh1D] Rank [%d], requiredQue Error.", myRank_),
91 : HcclResult::HCCL_E_INTERNAL);
92 0 : std::vector<float> dataSplitRate(linkNum);
93 0 : CHK_RET(CalcDataSplitRateForLinks(tempResLinks.begin()->second, dataSplitRate));
94 0 : queNumPerNeighbor_ = linkNum;
95 0 : std::vector<InsQuePtr> localInsQues;
96 0 : localInsQues.push_back(tempInsQues[0]);
97 0 : localInsQues.push_back(tempInsQues[tempInsQues.size() - 1]);
98 : // queNumPerNeighbor_初始化是1
99 0 : CHK_PRT_RET(
100 : majorQueNum_ * queNumPerNeighbor_ > tempInsQues.size(),
101 : HCCL_ERROR(
102 : "[InsCollAlgFactory] [InsTempScatterMesh1D] Rank [%d], requiredQueNum [%u] not equals to "
103 : "templateQueNum [%u].",
104 : myRank_, majorQueNum_ * queNumPerNeighbor_, tempInsQues.size()),
105 : HcclResult::HCCL_E_INTERNAL);
106 :
107 0 : PreCopy(tempAlgParams, tempInsQues);
108 : // semaphore sync
109 0 : if (majorQueNum_ > 1) { // more than one rank
110 0 : CHK_RET(PreSyncInterQueues(tempInsQues));
111 : }
112 :
113 : // run Mesh
114 0 : CHK_RET(RunMesh(tempAlgParams, tempResLinks, tempInsQues));
115 :
116 : // semaphore sync
117 0 : if (majorQueNum_ > 1) { // more than one rank
118 0 : CHK_RET(PostSyncInterQueues(tempInsQues));
119 : }
120 0 : PostCopy(tempAlgParams, tempInsQues);
121 0 : return HcclResult::HCCL_SUCCESS;
122 0 : }
123 :
124 0 : uint64_t InsTempScatterMesh1D::GetExpandedMode() const { return 1; }
125 :
126 0 : HcclResult InsTempScatterMesh1D::RunMeshTx(
127 : u32 myAlgRank, u32 repeatTimes, const TemplateDataParams& tempAlgParams, ResLinks& tempResLinks,
128 : std::vector<InsQuePtr>& tempInsQues)
129 : {
130 : // root卡需要将发送的数据刷新为尾部数据长度,保护一下tailSize=0认为没有
131 0 : u64 sliceSize = tempAlgParams.tailSize == 0 ? tempAlgParams.sliceSize : tempAlgParams.tailSize;
132 0 : u32 count = 0;
133 0 : for (u32 algRank = 0; algRank < tempVTopo_[0].size(); algRank++) {
134 0 : if (myAlgRank == algRank) {
135 0 : continue;
136 : }
137 0 : if (tempInsQues.size() < tempVTopo_[0].size()) {
138 0 : HCCL_ERROR(
139 : "tempInsQues size [%zu] is smaller than tempVTopo_[0].size() [%zu]", tempInsQues.size(),
140 : tempVTopo_[0].size());
141 0 : return HcclResult::HCCL_E_INTERNAL;
142 : }
143 :
144 0 : u32 peerRank = tempVTopo_[0][algRank];
145 0 : std::vector<LinkData>& neighborLinkDatas = tempResLinks.at(peerRank);
146 0 : u32 linkNum = rank2PathNumMap_.at(peerRank);
147 0 : if (linkNum != neighborLinkDatas.size()) {
148 0 : HCCL_ERROR("InsTempScatterMesh1D::RunMeshTx linkNum != neighborLinkDatas.size()");
149 0 : return HcclResult::HCCL_E_INTERNAL;
150 : }
151 0 : std::vector<float> dataSplitRate(linkNum);
152 0 : CHK_RET(CalcDataSplitRateForLinks(neighborLinkDatas, dataSplitRate));
153 :
154 0 : u64 srcOffset = buffInfo_.inBuffType == BufferType::SCRATCH ?
155 0 : buffInfo_.scratchBuffBaseOff + repeatTimes * tempAlgParams.inputRepeatStride
156 0 : + algRank * tempAlgParams.inputSliceStride :
157 0 : repeatTimes * tempAlgParams.inputRepeatStride + algRank * tempAlgParams.inputSliceStride
158 0 : + buffInfo_.inBuffBaseOff;
159 0 : u64 dstOffset = isZeroCopy_ ? buffInfo_.outBuffBaseOff + repeatTimes * tempAlgParams.outputRepeatStride :
160 0 : buffInfo_.scratchBuffBaseOff + repeatTimes * tempAlgParams.outputRepeatStride;
161 0 : BufferType dstBuffType = isZeroCopy_ ? BufferType::OUTPUT : BufferType::SCRATCH;
162 0 : DataSlice srcSlice(buffInfo_.inBuffType, srcOffset, sliceSize);
163 0 : DataSlice dstSlice(dstBuffType, dstOffset, sliceSize);
164 0 : for (u32 j = 0; j < linkNum; j++) {
165 0 : CHK_PRT_RET(
166 : count >= tempInsQues.size(),
167 : HCCL_ERROR("[InsTempScatterMesh1D] count=%u, tempInsQues.size=%zu", count, tempInsQues.size()),
168 : HcclResult::HCCL_E_INTERNAL);
169 0 : LinkData& neighborLinkData = neighborLinkDatas[j];
170 :
171 0 : vector<DataSlice> txSrcSlices{CalcDataSliceForLinks(srcSlice, dataSplitRate, j, dataType_)};
172 0 : vector<DataSlice> txDstSlices{CalcDataSliceForLinks(dstSlice, dataSplitRate, j, dataType_)};
173 :
174 0 : SlicesList txSlicesList({txSrcSlices}, {txDstSlices});
175 0 : DataInfo sendData(neighborLinkData, txSlicesList);
176 0 : CHK_PRT_RET(
177 : Send(sendData, tempInsQues[++count], 0, true, DmaMode::PUT),
178 : HCCL_ERROR("[InsTempScatterMesh1D] BatchSend failed"), HcclResult::HCCL_E_INTERNAL);
179 0 : }
180 0 : }
181 0 : return HcclResult::HCCL_SUCCESS;
182 : }
183 :
184 0 : HcclResult InsTempScatterMesh1D::RunMeshRx(
185 : u32 myAlgRank, u32 repeatTimes, const TemplateDataParams& tempAlgParams, ResLinks& tempResLinks,
186 : std::vector<InsQuePtr>& tempInsQues)
187 : {
188 0 : u64 srcOffset = buffInfo_.inBuffType == BufferType::SCRATCH ?
189 0 : buffInfo_.scratchBuffBaseOff + repeatTimes * tempAlgParams.inputRepeatStride
190 0 : + myAlgRank * tempAlgParams.inputSliceStride :
191 0 : repeatTimes * tempAlgParams.inputRepeatStride + myAlgRank * tempAlgParams.inputSliceStride
192 0 : + buffInfo_.inBuffBaseOff;
193 0 : u64 dstOffset = isZeroCopy_ ? buffInfo_.outBuffBaseOff + repeatTimes * tempAlgParams.outputRepeatStride :
194 0 : buffInfo_.scratchBuffBaseOff + repeatTimes * tempAlgParams.outputRepeatStride;
195 0 : BufferType dstBuffType = isZeroCopy_ ? BufferType::OUTPUT : BufferType::SCRATCH;
196 :
197 : // root卡需要将发送的数据刷新为尾部数据长度,保护一下tailSize=0认为没有
198 0 : u64 tailSize = tempAlgParams.tailSize == 0 ? tempAlgParams.sliceSize : tempAlgParams.tailSize;
199 : // 支持不均匀切分的情况下需要把尾部数据放到最后一张卡上
200 0 : u64 sliceSize = myAlgRank == tempVTopo_[0].size() - 1 ? tailSize : tempAlgParams.sliceSize;
201 :
202 0 : DataSlice srcSlice(buffInfo_.inBuffType, srcOffset, sliceSize);
203 0 : DataSlice dstSlice(dstBuffType, dstOffset, sliceSize);
204 :
205 0 : u32 currQueIdx = 0;
206 0 : for (currQueIdx = 1; currQueIdx < tempVTopo_[0].size(); currQueIdx++) {
207 0 : if ((myAlgRank + currQueIdx) % tempVTopo_[0].size() == root_ % tempVTopo_[0].size()) {
208 0 : break;
209 : }
210 : }
211 0 : std::vector<LinkData>& neighborLinkDatas = tempResLinks.at(root_);
212 0 : u32 linkNum = rank2PathNumMap_.at(root_);
213 0 : if (linkNum != neighborLinkDatas.size()) {
214 0 : HCCL_ERROR("InsTempScatterMesh1D::RunMeshTx linkNum != neighborLinkDatas.size()");
215 0 : return HcclResult::HCCL_E_INTERNAL;
216 : }
217 0 : std::vector<float> dataSplitRate(linkNum);
218 0 : CHK_RET(CalcDataSplitRateForLinks(neighborLinkDatas, dataSplitRate));
219 0 : for (u32 j = 0; j < linkNum; j++) {
220 0 : const LinkData& linkRecv = tempResLinks.at(root_)[j];
221 0 : vector<DataSlice> rxSrcSlices{CalcDataSliceForLinks(srcSlice, dataSplitRate, j, dataType_)};
222 0 : vector<DataSlice> rxDstSlices{CalcDataSliceForLinks(dstSlice, dataSplitRate, j, dataType_)};
223 0 : SlicesList rxSlicesList({rxSrcSlices}, {rxDstSlices});
224 0 : DataInfo recvData(linkRecv, rxSlicesList);
225 0 : CHK_PRT_RET(
226 : Recv(recvData, tempInsQues[currQueIdx++], 0, true, DmaMode::PUT),
227 : HCCL_ERROR("[InsTempScatterMesh1D] RunMeshRx failed"), HcclResult::HCCL_E_INTERNAL);
228 0 : }
229 0 : return HcclResult::HCCL_SUCCESS;
230 0 : }
231 :
232 0 : HcclResult InsTempScatterMesh1D::RunMesh(
233 : TemplateDataParams& tempAlgParams, ResLinks& tempResLinks, std::vector<InsQuePtr>& tempInsQues)
234 : {
235 : u32 myAlgRank;
236 0 : GetAlgRank(myRank_, tempVTopo_[0], myAlgRank);
237 0 : for (u32 r = 0; r < tempAlgParams.repeatNum; r++) {
238 0 : if (root_ == u32(myRank_)) {
239 0 : CHK_PRT_RET(
240 : RunMeshTx(myAlgRank, r, tempAlgParams, tempResLinks, tempInsQues),
241 : HCCL_ERROR("[InsTempScatterMesh1D] RunMeshTx failed"), HcclResult::HCCL_E_INTERNAL);
242 : } else {
243 0 : CHK_PRT_RET(
244 : RunMeshRx(myAlgRank, r, tempAlgParams, tempResLinks, tempInsQues),
245 : HCCL_ERROR("[InsTempScatterMesh1D] BatchRecv failed"), HcclResult::HCCL_E_INTERNAL);
246 : }
247 : }
248 0 : return HcclResult::HCCL_SUCCESS;
249 : }
250 :
251 0 : HcclResult InsTempScatterMesh1D::PreCopy(TemplateDataParams& tempAlgParams, std::vector<InsQuePtr>& tempInsQues)
252 : {
253 0 : if (u32(myRank_) != root_) {
254 0 : return HCCL_SUCCESS;
255 : }
256 : // root卡需要将发送的数据刷新为尾部数据长度,保护一下tailSize=0认为没有
257 0 : u64 sliceSize = tempAlgParams.tailSize == 0 ? tempAlgParams.sliceSize : tempAlgParams.tailSize;
258 : u32 myAlgRank;
259 0 : GetAlgRank(myRank_, tempVTopo_[0], myAlgRank);
260 : // 零拷贝而且不是最后一张卡的情况需要拷贝sliceSize
261 0 : if (isZeroCopy_ && myAlgRank != tempVTopo_[0].size() - 1) {
262 0 : sliceSize = tempAlgParams.sliceSize;
263 : }
264 0 : for (u32 r = 0; r < tempAlgParams.repeatNum; r++) {
265 : u64 srcOffset
266 0 : = buffInfo_.inBuffType == BufferType::SCRATCH ? buffInfo_.scratchBuffBaseOff : buffInfo_.inBuffBaseOff;
267 0 : srcOffset += r * tempAlgParams.inputRepeatStride + tempAlgParams.inputSliceStride * myAlgRank;
268 : BufferType dstBufferType
269 0 : = buffInfo_.outBuffType == BufferType::INPUT ? buffInfo_.scratBuffType : buffInfo_.outBuffType;
270 0 : u64 dstOffset = buffInfo_.outBuffType == BufferType::SCRATCH || buffInfo_.outBuffType == BufferType::INPUT ?
271 0 : r * tempAlgParams.outputRepeatStride + buffInfo_.scratchBuffBaseOff :
272 0 : r * tempAlgParams.outputRepeatStride + buffInfo_.outBuffBaseOff;
273 0 : DataSlice srcSlice(buffInfo_.inBuffType, srcOffset, sliceSize);
274 0 : DataSlice dstSlice(dstBufferType, dstOffset, sliceSize);
275 0 : LocalCopy(tempInsQues[0], srcSlice, dstSlice);
276 : }
277 :
278 0 : return HcclResult::HCCL_SUCCESS;
279 : }
280 :
281 0 : HcclResult InsTempScatterMesh1D::PostCopy(const TemplateDataParams& tempAlgParams, std::vector<InsQuePtr>& tempInsQues)
282 : {
283 : // 零拷贝或者输出地址是SCRATCH场景在PreCopy阶段就已经拷贝完了
284 0 : if (isZeroCopy_ || buffInfo_.outBuffType == BufferType::SCRATCH) {
285 0 : return HCCL_SUCCESS;
286 : }
287 0 : if (buffInfo_.outBuffType == BufferType::OUTPUT && (static_cast<u32>(myRank_) == root_)) {
288 0 : return HCCL_SUCCESS;
289 : }
290 : u32 myAlgRank;
291 0 : GetAlgRank(myRank_, tempVTopo_[0], myAlgRank);
292 : // root卡需要将发送的数据刷新为尾部数据长度,保护一下tailSize=0认为没有
293 0 : u64 tailSize = tempAlgParams.tailSize == 0 ? tempAlgParams.sliceSize : tempAlgParams.tailSize;
294 : // 支持不均匀切分的情况下需要把尾部数据放到最后一张卡上
295 0 : u64 sliceSize = myAlgRank == tempVTopo_[0].size() - 1 ? tailSize : tempAlgParams.sliceSize;
296 :
297 0 : DataSlice dstSlice(buffInfo_.outBuffType, buffInfo_.outBuffBaseOff, sliceSize * tempAlgParams.repeatNum);
298 0 : DataSlice srcSlice(buffInfo_.scratBuffType, buffInfo_.scratchBuffBaseOff, sliceSize * tempAlgParams.repeatNum);
299 0 : if (buffInfo_.outBuffType == buffInfo_.scratBuffType && buffInfo_.outBuffBaseOff == buffInfo_.scratchBuffBaseOff) {
300 0 : return HCCL_SUCCESS;
301 : }
302 0 : LocalCopy(tempInsQues[0], srcSlice, dstSlice);
303 :
304 0 : return HcclResult::HCCL_SUCCESS;
305 : }
306 : } // namespace Hccl
|