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 "all_gather_ring.h"
12 : #include "alg_template_register.h"
13 :
14 : namespace hccl {
15 32 : AllGatherRing::AllGatherRing(const HcclDispatcher dispatcher) : AlgTemplateBase(dispatcher) {}
16 :
17 55 : AllGatherRing::~AllGatherRing() {}
18 :
19 0 : HcclResult AllGatherRing::TxVector(const LINK& link, const std::vector<Slice>& txSlices)
20 : {
21 0 : std::vector<TxMemoryInfo> txMems;
22 0 : for (const Slice& txSlice : txSlices) {
23 0 : DeviceMem srcMem = outputMem_.range(txSlice.offset, txSlice.size);
24 0 : HCCL_DEBUG("tx srcMem[%p] range[%llu] size[%llu] ", srcMem.ptr(), txSlice.offset, txSlice.size);
25 0 : txMems.emplace_back(
26 0 : TxMemoryInfo{UserMemType::OUTPUT_MEM, txSlice.offset + baseOffset_, srcMem.ptr(), txSlice.size});
27 0 : }
28 0 : CHK_RET(link->TxAsync(txMems, stream_));
29 0 : HCCL_DEBUG("[AllGatherRing]TxVector for txMems success");
30 0 : return HCCL_SUCCESS;
31 0 : }
32 :
33 0 : HcclResult AllGatherRing::RxVector(const LINK& link, const std::vector<Slice>& rxSlices)
34 : {
35 0 : std::vector<RxMemoryInfo> rxMems;
36 0 : for (const Slice& rxSlice : rxSlices) {
37 0 : DeviceMem dstMem = outputMem_.range(rxSlice.offset, rxSlice.size);
38 0 : HCCL_DEBUG("rx dstMem[%p] range[%llu], size[%llu] ", dstMem.ptr(), rxSlice.offset, rxSlice.size);
39 0 : rxMems.emplace_back(
40 0 : RxMemoryInfo{UserMemType::OUTPUT_MEM, rxSlice.offset + baseOffset_, dstMem.ptr(), rxSlice.size});
41 0 : }
42 0 : CHK_RET(link->RxAsync(rxMems, stream_));
43 0 : return HCCL_SUCCESS;
44 0 : }
45 :
46 0 : HcclResult AllGatherRing::Tx(const LINK& link, const Slice& txSlice)
47 : {
48 0 : DeviceMem srcMem = outputMem_.range(txSlice.offset, txSlice.size);
49 0 : HCCL_DEBUG("tx srcMem[%p] range[%llu] size[%llu] ", srcMem.ptr(), txSlice.offset, txSlice.size);
50 0 : CHK_RET(link->TxAsync(UserMemType::OUTPUT_MEM, txSlice.offset + baseOffset_, srcMem.ptr(), txSlice.size, stream_));
51 0 : return HCCL_SUCCESS;
52 0 : }
53 :
54 0 : HcclResult AllGatherRing::Rx(const LINK& link, const Slice& rxSlice)
55 : {
56 0 : DeviceMem dstMem = outputMem_.range(rxSlice.offset, rxSlice.size);
57 0 : HCCL_DEBUG("rx dstMem[%p] range[%llu], size[%llu] ", dstMem.ptr(), rxSlice.offset, rxSlice.size);
58 0 : CHK_RET(link->RxAsync(UserMemType::OUTPUT_MEM, rxSlice.offset + baseOffset_, dstMem.ptr(), rxSlice.size, stream_));
59 0 : return HCCL_SUCCESS;
60 0 : }
61 :
62 : // 服务器间allgather的入口函数
63 0 : HcclResult AllGatherRing::RunAsync(const u32 rank, const u32 rankSize, const std::vector<LINK>& links)
64 : {
65 0 : CHK_SMART_PTR_NULL(dispatcher_);
66 0 : CHK_PTR_NULL(stream_.ptr());
67 0 : HCCL_INFO(
68 : "AllGatherRing run_async rank[%u] ranksize[%u] inputMem[%p] outputMem[%p] count[%llu]", rank, rankSize,
69 : inputMem_.ptr(), outputMem_.ptr(), count_);
70 :
71 0 : if (rankSize == 1) {
72 0 : if (inputMem_ != outputMem_) {
73 0 : CHK_RET(HcclD2DMemcpyAsync(dispatcher_, outputMem_, inputMem_, stream_));
74 : }
75 0 : return HCCL_SUCCESS;
76 : }
77 0 : HCCL_DEBUG("[AllGatherRing][RunAsync] AllGather Ring begins");
78 : // 获取ring algorithm所需的通信连接
79 0 : u32 ringPrevRank = (rank + rankSize - 1) % rankSize;
80 0 : u32 ringNextRank = (rank + 1) % rankSize;
81 :
82 0 : if (links.size() < rankSize) {
83 0 : HCCL_ERROR("[AllGatherRing][RunAsync]rank[%u] linkSize is less than rankSize", rank);
84 0 : return HCCL_E_INTERNAL;
85 : }
86 :
87 0 : linkLeft_ = links[ringPrevRank];
88 0 : CHK_SMART_PTR_NULL(linkLeft_);
89 :
90 0 : linkRight_ = links[ringNextRank];
91 0 : CHK_SMART_PTR_NULL(linkRight_);
92 :
93 0 : u32 unitSize = DataUnitSize(dataType_);
94 0 : if (unitSize == 0) {
95 0 : HCCL_ERROR("[AllGatherRing][RunAsync]unitSize is zero");
96 0 : return HCCL_E_INTERNAL;
97 : }
98 :
99 0 : std::vector<Slice> inputSlices(slices_);
100 0 : if (slices_.size() == 0) {
101 0 : slices_.resize(rankSize);
102 0 : inputSlices.resize(rankSize);
103 :
104 0 : u64 sliceSize = count_ * unitSize;
105 0 : for (u32 i = 0; i < rankSize; i++) {
106 0 : slices_[i].size = sliceSize;
107 0 : slices_[i].offset = sliceSize * i;
108 0 : inputSlices[i].size = sliceSize;
109 0 : inputSlices[i].offset = (inputMem_.size() < outputMem_.size()) ? 0 : (sliceSize * i);
110 0 : HCCL_DEBUG(
111 : "rank[%u], slices[%u].offset=%llu, slices[%u].size=%llu", rank, i, slices_[i].offset, i,
112 : slices_[i].size);
113 : }
114 : }
115 :
116 : // 双buffer下, 先将input拷贝到output的合适位置
117 0 : if (inputMem_ != outputMem_) {
118 0 : DeviceMem dst = outputMem_.range(slices_[rank].offset, slices_[rank].size);
119 0 : DeviceMem src = inputMem_.range(inputSlices[rank].offset, inputSlices[rank].size);
120 0 : CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dst, src, stream_));
121 0 : }
122 :
123 : // 运行all-gather, ring算法
124 : // 单环场景下 nicRankList_ 长度默认为 8。
125 : // 多环场景下 nicRankList_ 长度为网口数量。此时若 rankSize != nicRankList_ 则为网口裁剪场景
126 0 : if (rankSize != HCCL_NIC_MAX_NUM || nicRankList_.size() == HCCL_NIC_MAX_NUM) {
127 : // 非网口裁剪场景:
128 0 : CHK_RET(RunAllGather(rank, rankSize, slices_));
129 : } else {
130 : // 网口裁剪场景:当前仅在 910A 8P_RING (4环),且网口不满配情况下使用
131 0 : CHK_RET(AllGatherSlicesPrep(rankSize, nicRankList_.size()));
132 0 : CHK_RET(RunAllGatherChunk(rank, rankSize, slices_));
133 : }
134 :
135 0 : if (barrierSwitchOn_) {
136 : // 执行barrier,保证数据收发完成
137 0 : CHK_RET(ExecuteBarrier(linkLeft_, linkRight_));
138 : }
139 0 : HCCL_INFO("AllGatherRing finished: rank[%u] end", rank);
140 0 : return HCCL_SUCCESS;
141 0 : }
142 :
143 0 : HcclResult AllGatherRing::RunAllGather(u32 rank, u32 rankSize, const std::vector<Slice>& outputSlices)
144 : {
145 0 : if (outputSlices.size() < rankSize) {
146 0 : HCCL_ERROR("[Run][AllGather]rank[%u] OutputSlice Size is less than rank size", rank);
147 0 : return HCCL_E_INTERNAL;
148 : }
149 0 : HcclResult ret = HCCL_SUCCESS;
150 :
151 : // 首次传输,将本rank的数据发送到下游
152 0 : u32 sliceSize = outputSlices.size() / rankSize;
153 0 : u32 rxSliceIndex = ForwordRank(rank, rankSize, 1);
154 0 : u32 txSliceIndex = rank;
155 0 : HCCL_DEBUG("[AllGatherRing][RunAllGather]sliceSize is %u, rxSliceIndex is %u", sliceSize, rxSliceIndex);
156 0 : for (u32 i = 0; i < rankSize - 1; i++) {
157 0 : HCCL_DEBUG(
158 : "rank[%u] round[%u] will tx_ack outputslice[%u].offset is[%llu] size[%llu]", rank, i, rxSliceIndex,
159 : outputSlices[rxSliceIndex].offset, outputSlices[rxSliceIndex].size);
160 0 : CHK_RET(linkLeft_->TxAck(stream_));
161 :
162 : // reduce目的操作
163 0 : HCCL_DEBUG(
164 : "rank[%u] round[%u] will rx ack because outputSlices[%u] size[%llu] ", rank, i, txSliceIndex,
165 : outputSlices[txSliceIndex].size);
166 0 : CHK_RET(linkRight_->RxAck(stream_));
167 :
168 0 : std::vector<Slice> txSegsSlice;
169 0 : std::vector<Slice> rxSegsSlice;
170 0 : for (u32 j = 0; j < sliceSize; j++) {
171 0 : txSegsSlice.push_back(outputSlices[txSliceIndex * sliceSize + j]);
172 0 : rxSegsSlice.push_back(outputSlices[rxSliceIndex * sliceSize + j]);
173 : }
174 0 : ret = TxVector(linkRight_, txSegsSlice);
175 0 : CHK_PRT_RET(
176 : ret != HCCL_SUCCESS,
177 : HCCL_ERROR(
178 : "[Run][AllGather]rank[%u] round[%u] Right Link tx outputSlices[%u] "
179 : "Failed",
180 : rank, i, txSliceIndex),
181 : ret);
182 :
183 : // reduce源操作
184 0 : HCCL_DEBUG(
185 : "rank[%u] round[%u] rx data outputSlices[%u] offset[%llu] size[%llu]", rank, i, rxSliceIndex,
186 : outputSlices[rxSliceIndex].offset, outputSlices[rxSliceIndex].size);
187 0 : ret = RxVector(linkLeft_, rxSegsSlice);
188 0 : CHK_PRT_RET(
189 : ret != HCCL_SUCCESS,
190 : HCCL_ERROR(
191 : "[Run][AllGather]rank[%u] round[%u] Left Link rx outputSlices[%u] "
192 : "Failed",
193 : rank, i, rxSliceIndex),
194 : ret);
195 :
196 : // 末尾传输, 只接收一次, 不用再次发送
197 0 : txSliceIndex = ForwordRank(txSliceIndex, rankSize, 1);
198 0 : rxSliceIndex = ForwordRank(rxSliceIndex, rankSize, 1);
199 :
200 0 : ret = linkLeft_->RxWaitDone(stream_);
201 0 : CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("[Run][ReduceScatter]RxWaitDone failed"), ret);
202 0 : ret = linkRight_->TxWaitDone(stream_);
203 0 : CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("[Run][ReduceScatter]TxWaitDone failed"), ret);
204 0 : }
205 0 : return HCCL_SUCCESS;
206 : }
207 :
208 0 : HcclResult AllGatherRing::RunAllGatherChunk(const u32 rank, const u32 rankSize, const std::vector<Slice>& outputSlices)
209 : {
210 0 : if (outputSlices.size() < rankSize) {
211 0 : HCCL_ERROR("[Run][AllGatherChunk]rank[%u] OutputSlice Size is less than rank size", rank);
212 0 : return HCCL_E_INTERNAL;
213 : }
214 : HcclResult ret;
215 0 : u32 sendSliceLen = rankSliceLists_[rank].size();
216 0 : u32 chunkSize = HCCL_NIC_MAX_NUM / nicRankList_.size();
217 0 : if (sendSliceLen >= chunkSize) {
218 0 : CHK_RET(HeadAllGatherChunk(rank, rankSize, outputSlices));
219 0 : for (u32 midRankIdx = 1; midRankIdx < sendSliceLen - 1; midRankIdx++) {
220 0 : ret = MidAllGatherChunk(rank, rankSize, midRankIdx, outputSlices);
221 0 : CHK_PRT_RET(
222 : ret != HCCL_SUCCESS,
223 : HCCL_ERROR("[Run][AllGatherChunk]rank[%u] run mid[%u] ReduceScatter chunk failed", rank, midRankIdx),
224 : HCCL_E_INTERNAL);
225 : }
226 0 : CHK_RET(TailAllGatherChunk(rank, rankSize, sendSliceLen - 1, outputSlices));
227 : } else {
228 0 : for (u32 rxSliceIndex = 0; rxSliceIndex < HCCL_NIC_MAX_NUM; rxSliceIndex++) {
229 0 : CHK_RET(linkLeft_->TxAck(stream_));
230 :
231 0 : ret = Rx(linkLeft_, outputSlices[rxSliceIndex]);
232 0 : CHK_PRT_RET(
233 : ret != HCCL_SUCCESS,
234 : HCCL_ERROR(
235 : "[Run][AllGatherChunk]rank[%u] Left Link rx outputSlices[%u] "
236 : "Failed",
237 : rank, rxSliceIndex),
238 : ret);
239 : }
240 : }
241 0 : return HCCL_SUCCESS;
242 : }
243 :
244 0 : HcclResult AllGatherRing::HeadAllGatherChunk(u32 rank, u32 rankSize, const std::vector<Slice>& outputSlices)
245 : {
246 0 : if (outputSlices.size() < rankSize) {
247 0 : HCCL_ERROR("[AllGatherRing][HeadAllGatherChunk]rank[%u] OutputSlice Size is less than rank size", rank);
248 0 : return HCCL_E_INTERNAL;
249 : }
250 : HcclResult ret;
251 0 : u32 rxSliceIndex = rankSliceLists_[rank][0];
252 0 : u32 txSliceIndex = rxSliceIndex;
253 0 : std::vector<u32> preRankSlices(rankSliceLists_[(rank - 1 + rankSize) % rankSize]);
254 0 : std::vector<u32>::iterator iterSlice = std::find(preRankSlices.begin(), preRankSlices.end(), rxSliceIndex);
255 0 : if (iterSlice != preRankSlices.end()) {
256 0 : CHK_RET(linkLeft_->TxAck(stream_));
257 :
258 0 : ret = Rx(linkLeft_, outputSlices[rxSliceIndex]);
259 0 : CHK_PRT_RET(
260 : ret != HCCL_SUCCESS,
261 : HCCL_ERROR(
262 : "[AllGatherRing][HeadAllGatherChunk]rank[%u] Left Link rx "
263 : "outputSlices[%u] Failed",
264 : rank, rxSliceIndex),
265 : ret);
266 : }
267 :
268 0 : iterSlice = std::find(preRankSlices.begin(), preRankSlices.end(), rankSliceLists_[rank][1]);
269 0 : if (iterSlice != preRankSlices.end()) {
270 0 : CHK_RET(MidAllGatherChunk(rank, rankSize, 0, outputSlices));
271 : } else {
272 0 : CHK_RET(linkRight_->RxAck(stream_));
273 :
274 0 : ret = Tx(linkRight_, outputSlices[txSliceIndex]);
275 0 : CHK_PRT_RET(
276 : ret != HCCL_SUCCESS,
277 : HCCL_ERROR(
278 : "[AllGatherRing][HeadAllGatherChunk]rank[%u] Right Link tx "
279 : "outputSlices[%u] Failed",
280 : rank, txSliceIndex),
281 : ret);
282 : }
283 0 : return HCCL_SUCCESS;
284 0 : }
285 :
286 : HcclResult
287 0 : AllGatherRing::MidAllGatherChunk(u32 rank, u32 rankSize, u32 sliceIdx, const std::vector<Slice>& outputSlices)
288 : {
289 0 : if (outputSlices.size() < rankSize) {
290 0 : HCCL_ERROR("[AllGatherRing][MidAllGatherChunk]rank[%u] OutputSlice Size is less than rank size", rank);
291 0 : return HCCL_E_INTERNAL;
292 : }
293 : HcclResult ret;
294 0 : u32 rxSliceIndex = rankSliceLists_[rank][sliceIdx + 1];
295 0 : u32 txSliceIndex = rankSliceLists_[rank][sliceIdx];
296 0 : std::vector<u32> preRankSlices(rankSliceLists_[(rank - 1 + rankSize) % rankSize]);
297 0 : std::vector<u32>::iterator iterSlice = std::find(preRankSlices.begin(), preRankSlices.end(), rxSliceIndex);
298 0 : if (iterSlice != preRankSlices.end()) {
299 0 : CHK_RET(linkLeft_->TxAck(stream_));
300 :
301 0 : CHK_RET(linkRight_->RxAck(stream_));
302 :
303 0 : ret = Tx(linkRight_, outputSlices[txSliceIndex]);
304 0 : CHK_PRT_RET(
305 : ret != HCCL_SUCCESS,
306 : HCCL_ERROR(
307 : "[AllGatherRing][MidAllGatherChunk]rank[%u] Right Link tx "
308 : "outputSlices[%u] Failed",
309 : rank, txSliceIndex),
310 : ret);
311 0 : ret = Rx(linkLeft_, outputSlices[rxSliceIndex]);
312 0 : CHK_PRT_RET(
313 : ret != HCCL_SUCCESS,
314 : HCCL_ERROR(
315 : "[AllGatherRing][MidAllGatherChunk]rank[%u] Left Link rx "
316 : "outputSlices[%u] Failed",
317 : rank, rxSliceIndex),
318 : ret);
319 : } else {
320 0 : CHK_RET(linkRight_->RxAck(stream_));
321 :
322 0 : ret = Tx(linkRight_, outputSlices[txSliceIndex]);
323 0 : CHK_PRT_RET(
324 : ret != HCCL_SUCCESS,
325 : HCCL_ERROR(
326 : "[AllGatherRing][MidAllGatherChunk]rank[%u] Right Link tx "
327 : "outputSlices[%u] Failed",
328 : rank, txSliceIndex),
329 : ret);
330 : }
331 0 : return HCCL_SUCCESS;
332 0 : }
333 :
334 : HcclResult
335 0 : AllGatherRing::TailAllGatherChunk(u32 rank, u32 rankSize, u32 sliceIdx, const std::vector<Slice>& outputSlices)
336 : {
337 0 : if (outputSlices.size() < rankSize) {
338 0 : HCCL_ERROR("[AllGatherRing][TailAllGatherChunk]rank[%u] OutputSlice Size is less than rank size", rank);
339 0 : return HCCL_E_INTERNAL;
340 : }
341 : HcclResult ret;
342 0 : u32 chunkSize = HCCL_NIC_MAX_NUM / nicRankList_.size();
343 0 : u32 txSliceIndex = rankSliceLists_[rank][sliceIdx];
344 0 : u32 nextRank = (rank + 1 + rankSize) % rankSize;
345 0 : std::vector<u32>::iterator iterNic = std::find(nicRankList_.begin(), nicRankList_.end(), nextRank);
346 0 : if (iterNic != nicRankList_.end()) {
347 0 : u32 nicIdx = distance(nicRankList_.begin(), iterNic);
348 0 : u32 chunkStart = nicIdx * chunkSize;
349 0 : u32 rxSliceIndex = chunkStart;
350 0 : CHK_RET(linkLeft_->TxAck(stream_));
351 :
352 0 : CHK_RET(linkRight_->RxAck(stream_));
353 :
354 0 : ret = Tx(linkRight_, outputSlices[txSliceIndex]);
355 0 : CHK_PRT_RET(
356 : ret != HCCL_SUCCESS,
357 : HCCL_ERROR(
358 : "[AllGatherRing][TailAllGatherChunk]rank[%u] Right Link tx "
359 : "outputSlices[%u] Failed",
360 : rank, txSliceIndex),
361 : ret);
362 0 : ret = Rx(linkLeft_, outputSlices[rxSliceIndex]);
363 0 : CHK_PRT_RET(
364 : ret != HCCL_SUCCESS,
365 : HCCL_ERROR(
366 : "[AllGatherRing][TailAllGatherChunk]rank[%u] Left Link rx "
367 : "outputSlices[%u] Failed",
368 : rank, rxSliceIndex),
369 : ret);
370 :
371 0 : for (u32 sliceIdx = 1; sliceIdx < chunkSize; sliceIdx++) {
372 0 : rxSliceIndex = chunkStart + sliceIdx;
373 0 : CHK_RET(linkLeft_->TxAck(stream_));
374 :
375 0 : ret = Rx(linkLeft_, outputSlices[rxSliceIndex]);
376 0 : CHK_PRT_RET(
377 : ret != HCCL_SUCCESS,
378 : HCCL_ERROR(
379 : "[AllGatherRing][TailAllGatherChunk]rank[%u] Left Link rx "
380 : "outputSlices[%u] Failed",
381 : rank, rxSliceIndex),
382 : ret);
383 : }
384 : } else {
385 0 : CHK_RET(linkRight_->RxAck(stream_));
386 :
387 0 : ret = Tx(linkRight_, outputSlices[txSliceIndex]);
388 0 : CHK_PRT_RET(
389 : ret != HCCL_SUCCESS,
390 : HCCL_ERROR(
391 : "[AllGatherRing][TailAllGatherChunk]rank[%u] Right Link tx "
392 : "outputSlices[%u] Failed",
393 : rank, txSliceIndex),
394 : ret);
395 : }
396 0 : return HCCL_SUCCESS;
397 : }
398 :
399 : // 多网口allgather各rank发送slice准备
400 0 : HcclResult AllGatherRing::AllGatherSlicesPrep(u32 rankSize, u32 nicSize)
401 : {
402 0 : u32 chunkSize = HCCL_NIC_MAX_NUM / nicSize;
403 0 : for (u32 rankIdx = 0; rankIdx < rankSize; rankIdx++) {
404 0 : std::vector<u32> sliceList; // 单个rank上的发送slice编号
405 0 : for (u32 nicDis = 0; nicDis <= rankSize - 2; nicDis++) { // 递减从当前rank遍历至(rank+2+ranksize)%ranksize的位置
406 0 : u32 nicIdx = (rankIdx + rankSize - nicDis) % rankSize;
407 0 : std::vector<u32>::iterator iterNic = std::find(nicRankList_.begin(), nicRankList_.end(), nicIdx);
408 0 : if (iterNic != nicRankList_.end()) { // 当前rank为网口所在位置,将网口对应的chunksize份silce放入sliceList
409 0 : u32 nicListIdx = distance(nicRankList_.begin(), iterNic);
410 0 : for (u32 chunkIdx = 0; chunkIdx < chunkSize; chunkIdx++) {
411 0 : sliceList.push_back(chunkSize * nicListIdx + chunkIdx);
412 : }
413 : }
414 : }
415 0 : HCCL_DEBUG("[AllGatherRing][AllGatherSlicesPrep]rankIdx now is [%u]", rankIdx);
416 0 : rankSliceLists_.push_back(sliceList);
417 0 : }
418 0 : return HCCL_SUCCESS;
419 : }
420 :
421 : HcclResult
422 0 : AllGatherRing::GetNslbAdjInfo(const u32 rank, const u32 rankSize, const std::vector<LINK>& links, AdjInfo& nslbAdjInfo)
423 : {
424 0 : NslbDpAdjInfo adjInfoStep = {};
425 0 : u32 ringNextRank = (rank + 1) % rankSize;
426 0 : LINK nslbNext = links[ringNextRank];
427 :
428 0 : nslbAdjInfo.dstRankNum = 1;
429 0 : adjInfoStep.dstLocalRankId = nslbNext->GetRemoteRank();
430 0 : adjInfoStep.phaseId = 1;
431 0 : adjInfoStep.rev = 0;
432 0 : nslbAdjInfo.nsAdjInfo.push_back(adjInfoStep);
433 :
434 0 : return HCCL_SUCCESS;
435 0 : }
436 : REGISTER_TEMPLATE(TemplateType::TEMPLATE_ALL_GATHER_RING, AllGatherRing);
437 : } // namespace hccl
|