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