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 "scatter_double_ring_direct.h"
12 : #include "alg_template_register.h"
13 :
14 : namespace hccl {
15 :
16 : constexpr u32 RANK_SIZE_THREE = 3;
17 :
18 0 : ScatterDoubleRingDirect::ScatterDoubleRingDirect(const HcclDispatcher dispatcher) : AlgTemplateBase(dispatcher) {}
19 :
20 0 : ScatterDoubleRingDirect::~ScatterDoubleRingDirect() {}
21 :
22 0 : HcclResult ScatterDoubleRingDirect::Prepare(
23 : HcomCollOpInfo* opInfo, const u32 userRank, const u32 subRingRank, std::vector<Stream>& subStreams,
24 : const std::vector<std::shared_ptr<LocalNotify>>& mainSignals,
25 : const std::vector<std::shared_ptr<LocalNotify>>& subSignals, const std::vector<std::vector<u32>>& ringsOrders,
26 : const std::vector<std::vector<Slice>>& multiRingSlices, const std::vector<std::vector<Slice>>& userMemInputSlices)
27 : {
28 0 : opInfo_ = opInfo;
29 0 : userRank_ = userRank;
30 0 : subRingRank_ = subRingRank;
31 0 : subStreams_ = subStreams;
32 0 : mainSignals_ = mainSignals;
33 0 : subSignals_ = subSignals;
34 0 : ringsOrders_ = ringsOrders;
35 0 : multiRingSlices_ = multiRingSlices;
36 0 : userMemInputSlices_ = userMemInputSlices;
37 0 : return HCCL_SUCCESS;
38 : }
39 :
40 : // reduce scatter ring direct算法的函数入口
41 0 : HcclResult ScatterDoubleRingDirect::RunAsync(const u32 rank, const u32 rankSize, const std::vector<LINK>& links)
42 : {
43 : // 基本的检查
44 0 : CHK_RET(CheckParameters(rank, rankSize, links));
45 :
46 : // 判断rank_size == 1
47 0 : if (rankSize == 1) {
48 0 : CHK_RET(MemcpyByOneRank());
49 0 : return HCCL_SUCCESS;
50 : }
51 : // 收集邻居信息
52 0 : CHK_RET(GetInitializedNeighborLinks(rank, rankSize, links));
53 :
54 : // 运行scatter, ring算法
55 0 : CHK_RET(RunScatter(rank, rankSize));
56 0 : CHK_RET(LaunchTaskExtend(dispatcher_, stream_, subStreams_));
57 :
58 0 : HCCL_INFO("ScatterDoubleRingDirect finished: rank[%u]", rank);
59 0 : return HCCL_SUCCESS;
60 : }
61 :
62 0 : HcclResult ScatterDoubleRingDirect::CheckParameters(const u32 rank, const u32 rankSize, const std::vector<LINK>& links)
63 : {
64 0 : CHK_PTR_NULL(opInfo_);
65 0 : CHK_RET(CheckConcurrentDirectParameters(rank, rankSize, links));
66 : // 判断ranksize大小
67 0 : CHK_PRT_RET(
68 : rankSize < 1, HCCL_ERROR("[ScatterDoubleRingDirect] rankSize size[%u] is less than 1", rankSize), HCCL_E_PARA);
69 : // 判断subStreams数量是否正确
70 0 : if (GetWorkflowMode() == HcclWorkflowMode::HCCL_WORKFLOW_MODE_OPS_KERNEL_INFO_LIB) {
71 0 : CHK_PRT_RET(
72 : subStreams_.size() != 1,
73 : HCCL_ERROR("[ScatterDoubleRingDirect] subStreams size[%u] must equal to 1", subStreams_.size()),
74 : HCCL_E_PARA);
75 : } else {
76 0 : CHK_PRT_RET(
77 : subStreams_.size() != DOUBLE_RING_STREAM_NUM,
78 : HCCL_ERROR("[ScatterDoubleRingDirect] subStreams size[%u] must equal to 3", subStreams_.size()),
79 : HCCL_E_PARA);
80 : }
81 0 : for (auto& s : subStreams_) {
82 0 : CHK_PTR_NULL(s.ptr());
83 : }
84 : // 判断mainSignals数量是否正确
85 0 : CHK_PRT_RET(
86 : mainSignals_.size() < 1,
87 : HCCL_ERROR("[ScatterDoubleRingDirect] mainSignals size[%u] is less than 1", mainSignals_.size()), HCCL_E_PARA);
88 : // 判断subSignals数量是否正确
89 0 : CHK_PRT_RET(
90 : subSignals_.size() < 1,
91 : HCCL_ERROR("[ScatterDoubleRingDirect] subSignals size[%u] is less than 1", subSignals_.size()), HCCL_E_PARA);
92 : // 判断ringsOrder size, multiRingSlices size, userMemInputSlices size是否正确
93 0 : if (ringsOrders_.size() != DOUBLE_RING_NUM || multiRingSlices_.size() != DOUBLE_RING_NUM
94 0 : || userMemInputSlices_.size() != DOUBLE_RING_NUM) {
95 0 : HCCL_ERROR(
96 : "[ScatterDoubleRingDirect] ringsOrder size[%u], multiRingSlices size[%u], userMemInputSlices"
97 : "size[%u] must equal to 2",
98 : ringsOrders_.size(), multiRingSlices_.size(), userMemInputSlices_.size());
99 0 : return HCCL_E_PARA;
100 : }
101 : // 判断ringsOrder数量是否正确
102 0 : for (u32 ringIndex = 0; ringIndex < ringsOrders_.size(); ringIndex++) {
103 0 : CHK_PRT_RET(
104 : ringsOrders_[ringIndex].size() != rankSize,
105 : HCCL_ERROR(
106 : "[ScatterDoubleRingDirect] ringsOrders[%u] size[%u] must equal to rank size[%u]", ringIndex,
107 : ringsOrders_[ringIndex].size(), rankSize),
108 : HCCL_E_PARA);
109 : }
110 : // 判断multiRingSlices数量是否正确
111 0 : for (u32 ringIndex = 0; ringIndex < multiRingSlices_.size(); ringIndex++) {
112 0 : CHK_PRT_RET(
113 : multiRingSlices_[ringIndex].size() != rankSize,
114 : HCCL_ERROR(
115 : "[ScatterDoubleRingDirect] multiRingSlices[%u] size[%u] must equal to rank size[%u]", ringIndex,
116 : multiRingSlices_[ringIndex].size(), rankSize),
117 : HCCL_E_PARA);
118 : }
119 : // 判断userMemInputSlices数量是否正确
120 0 : for (u32 ringIndex = 0; ringIndex < userMemInputSlices_.size(); ringIndex++) {
121 0 : CHK_PRT_RET(
122 : userMemInputSlices_[ringIndex].size() != rankSize,
123 : HCCL_ERROR(
124 : "[ScatterDoubleRingDirect] userMemInputSlices_[%u] size[%u] must equal to rank size[%u]", ringIndex,
125 : userMemInputSlices_[ringIndex].size(), rankSize),
126 : HCCL_E_PARA);
127 : }
128 0 : HCCL_INFO("ScatterDoubleRingDirect CheckParameters success");
129 0 : return HCCL_SUCCESS;
130 : }
131 :
132 0 : HcclResult ScatterDoubleRingDirect::MemcpyByOneRank()
133 : {
134 0 : for (u32 ringIndex = 0; ringIndex < multiRingSlices_.size(); ringIndex++) {
135 0 : const Slice& srcSlice = userMemInputSlices_[ringIndex][0];
136 0 : const Slice& dstSlice = multiRingSlices_[ringIndex][0];
137 0 : DeviceMem src = DeviceMem::create(static_cast<u8*>(opInfo_->inputAddr) + srcSlice.offset, srcSlice.size);
138 0 : DeviceMem dst;
139 0 : if (opInfo_->outputAddr != nullptr) {
140 : // opInfo_->outputAddr != nullptr指示要将输出发送至user output
141 0 : u64 stepOffset = multiRingSlices_[ringIndex][ringsOrders_[ringIndex][0]].offset;
142 0 : HCCL_DEBUG(
143 : "Memcpy operation: stream[main], rank[%u] starts to rcv offset[%llu], size[%llu] at userMemOut_",
144 : userRank_, stepOffset, dstSlice.size);
145 0 : dst = DeviceMem::create(static_cast<u8*>(opInfo_->outputAddr) + stepOffset, dstSlice.size);
146 : } else {
147 : // opInfo_->outputAddr == nullptr指示要将输出发送至CCL buffer
148 0 : HCCL_DEBUG(
149 : "Memcpy operation: stream[main], rank[%u] starts to rcv offset[%llu], size[%llu] at outputMem_",
150 : userRank_, dstSlice.offset, dstSlice.size);
151 0 : dst = outputMem_.range(dstSlice.offset, dstSlice.size);
152 : }
153 0 : CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dst, src, stream_));
154 0 : }
155 0 : return HCCL_SUCCESS;
156 : }
157 :
158 : HcclResult
159 0 : ScatterDoubleRingDirect::GetInitializedNeighborLinks(const u32 rank, const u32 rankSize, const std::vector<LINK>& links)
160 : {
161 : // 收集左邻居信息
162 0 : leftLink_ = links[(rank + rankSize - 1) % rankSize];
163 0 : CHK_SMART_PTR_NULL(leftLink_);
164 :
165 : // 收集右邻居信息
166 0 : rightLink_ = links[(rank + 1) % rankSize];
167 0 : CHK_SMART_PTR_NULL(rightLink_);
168 0 : HCCL_INFO("ScatterDoubleRingDirect finished to GetInitializedNeighborLinks");
169 0 : return HCCL_SUCCESS;
170 : }
171 :
172 0 : HcclResult ScatterDoubleRingDirect::RunInitStep(const u32 rank, const u32 rankSize)
173 : {
174 0 : if (rank != root_) {
175 0 : return HCCL_SUCCESS;
176 : }
177 0 : for (u32 ringIndex = 0; ringIndex < multiRingSlices_.size(); ringIndex++) {
178 0 : u32 initSlice0Idx = 0;
179 0 : if (ringIndex == 0) {
180 0 : initSlice0Idx = (rank + rankSize - 1) % rankSize;
181 : } else {
182 0 : initSlice0Idx = (subRingRank_ + rankSize - 1) % rankSize;
183 : }
184 0 : const Slice& srcInitSlice0 = userMemInputSlices_[ringIndex][initSlice0Idx];
185 : DeviceMem srcInit
186 0 : = DeviceMem::create(static_cast<u8*>(opInfo_->inputAddr) + srcInitSlice0.offset, srcInitSlice0.size);
187 0 : const Slice& dstInitSlice0 = multiRingSlices_[ringIndex][initSlice0Idx];
188 0 : DeviceMem dstInit = inputMem_.range(dstInitSlice0.offset, dstInitSlice0.size);
189 0 : HCCL_DEBUG(
190 : "Memcpy operation: step[-1] stream[sub] src rank[%u] starts to copy(rcv) offset[%llu], size[%llu] "
191 : "on userMemInput to offset[%llu], size[%llu] on CCL",
192 : userRank_, srcInitSlice0.offset, srcInitSlice0.size, dstInitSlice0.offset, dstInitSlice0.size);
193 0 : if (GetWorkflowMode() != HcclWorkflowMode::HCCL_WORKFLOW_MODE_OPS_KERNEL_INFO_LIB) {
194 0 : CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dstInit, srcInit, stream_));
195 : }
196 0 : }
197 : // 第-1步,片内将部分数据从userIn搬到cclIn
198 0 : return HCCL_SUCCESS;
199 : }
200 :
201 0 : HcclResult ScatterDoubleRingDirect::RunAllStreams(
202 : const u32 rank, const u32 step, const u32 rankSize, RxMemoryInfo& mainRxMem, RxMemoryInfo& subRxMem,
203 : DeviceMem& mainLocalSrcMem, DeviceMem& mainLocalDstMem, DeviceMem& subLocalSrcMem, DeviceMem& subLocalDstMem)
204 : {
205 : (void)step;
206 : (void)rankSize;
207 0 : Stream mainStream = stream_;
208 0 : LINK mainPreLink = rightLink_;
209 0 : LINK mainNextLink = leftLink_;
210 0 : Stream subStream = subStreams_[0];
211 0 : LINK subPreLink = leftLink_;
212 0 : LINK subNextLink = rightLink_;
213 :
214 : // 唤醒所有环的主流做跨片同步
215 0 : CHK_RET(LocalNotify::Post(stream_, dispatcher_, subSignals_[0], profilerInput_.stage));
216 0 : CHK_RET(LocalNotify::Wait(subStreams_[0], dispatcher_, subSignals_[0], profilerInput_.stage));
217 :
218 0 : CHK_RET(mainNextLink->TxAck(mainStream));
219 0 : CHK_RET(subNextLink->TxAck(subStream));
220 :
221 0 : CHK_RET(mainPreLink->RxAck(mainStream));
222 0 : CHK_RET(subPreLink->RxAck(subStream));
223 :
224 : // 回到主流
225 0 : CHK_RET(LocalNotify::Post(subStreams_[0], dispatcher_, mainSignals_[0], profilerInput_.stage));
226 0 : CHK_RET(LocalNotify::Wait(stream_, dispatcher_, mainSignals_[0], profilerInput_.stage));
227 :
228 : // 主流唤醒所有流做跨片拷贝和片内拷贝
229 0 : CHK_RET(MainRecordSub());
230 :
231 : // 小数据量减少冗余通信,
232 0 : const u64 SMALL_DATASIZE = 4 * 1024 * 1024;
233 0 : bool isLargeCount = opInfo_->count * SIZE_TABLE[opInfo_->dataType] > SMALL_DATASIZE;
234 0 : if (isLargeCount || (step + 1 >= (root_ + rankSize - rank) % rankSize)) {
235 0 : CHK_RET(RxAsyncMemcpy(mainRxMem, mainStream, mainPreLink));
236 : }
237 0 : if (isLargeCount || (step + 1 >= (rank + rankSize - root_) % rankSize)) {
238 0 : CHK_RET(RxAsyncMemcpy(subRxMem, subStream, subPreLink));
239 : }
240 :
241 : // 本地拷贝
242 0 : if (rank == root_ && GetWorkflowMode() != HcclWorkflowMode::HCCL_WORKFLOW_MODE_OPS_KERNEL_INFO_LIB) {
243 0 : if (mainLocalDstMem != mainLocalSrcMem) {
244 0 : CHK_RET(HcclD2DMemcpyAsync(dispatcher_, mainLocalDstMem, mainLocalSrcMem, subStreams_[1]));
245 : }
246 0 : if (subLocalDstMem != subLocalSrcMem) {
247 0 : CHK_RET(HcclD2DMemcpyAsync(dispatcher_, subLocalDstMem, subLocalSrcMem, subStreams_[2]));
248 : }
249 : }
250 :
251 0 : CHK_RET(mainPreLink->TxDataSignal(mainStream));
252 0 : CHK_RET(subPreLink->TxDataSignal(subStream));
253 :
254 0 : CHK_RET(mainNextLink->RxDataSignal(mainStream));
255 0 : CHK_RET(subNextLink->RxDataSignal(subStream));
256 :
257 0 : CHK_RET(MainWaitSub());
258 0 : return HCCL_SUCCESS;
259 0 : }
260 :
261 0 : HcclResult ScatterDoubleRingDirect::RxAsyncMemcpy(RxMemoryInfo& mem, Stream& stream, LINK& link)
262 : {
263 0 : CHK_PTR_NULL(mem.dst);
264 0 : void* srcMemPtr = nullptr;
265 0 : CHK_RET(link->GetRemoteMem(mem.srcMemType, &srcMemPtr));
266 :
267 0 : DeviceMem srcDevMem(static_cast<s8*>(srcMemPtr) + mem.srcOffset, mem.len);
268 0 : DeviceMem dstDevMem(static_cast<s8*>(mem.dst), mem.len);
269 0 : CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dstDevMem, srcDevMem, stream, link->GetRemoteRank(), link->GetLinkType()));
270 0 : return HCCL_SUCCESS;
271 0 : }
272 :
273 0 : HcclResult ScatterDoubleRingDirect::PrepareDeviceMems(
274 : const u32 rank, const u32 step, const u32 ringIndex, const u32 rankSize, const u32 subSliceIdx,
275 : const u32 rxSliceIdx, RxMemoryInfo& rxMem, DeviceMem& localSrcMem, DeviceMem& localDstMem)
276 : {
277 0 : const Slice& subSlice = userMemInputSlices_[ringIndex][subSliceIdx];
278 0 : const Slice& cclSlice = multiRingSlices_[ringIndex][subSliceIdx];
279 0 : const Slice& rxSlice = multiRingSlices_[ringIndex][rxSliceIdx];
280 :
281 0 : u64 lastStepOffset = multiRingSlices_[ringIndex][ringsOrders_[ringIndex][0]].offset;
282 :
283 0 : DeviceMem dst;
284 0 : if (step == rankSize - DMA_REDUCE_TWO_OFFSET && opInfo_->outputAddr != nullptr) {
285 0 : HCCL_DEBUG(
286 : "MemcpyAsync operation: step[%u] stream[main], dst rank[%u] starts to rcv offset[%llu], "
287 : "size[%llu] at userMemOut_",
288 : step, userRank_, lastStepOffset, rxSlice.size);
289 0 : dst = DeviceMem::create(static_cast<u8*>(opInfo_->outputAddr) + lastStepOffset, rxSlice.size);
290 : } else {
291 0 : HCCL_DEBUG(
292 : "MemcpyAsync operation: step[%u] stream[main], dst rank[%u] starts to rcv offset[%llu], "
293 : "size[%llu] at inputMem_",
294 : step, userRank_, rxSlice.offset, rxSlice.size);
295 0 : dst = inputMem_.range(rxSlice.offset, rxSlice.size);
296 : }
297 0 : rxMem = RxMemoryInfo{UserMemType::INPUT_MEM, rxSlice.offset + baseOffset_, dst.ptr(), rxSlice.size};
298 :
299 0 : if (rank == root_) {
300 : // root节点参与通信,避免片内拷贝带宽过高过分抢占HBM带宽导致其他节点读取数据时性能下降
301 0 : u32 rxSliceIdxForRoot = (rxSliceIdx + DMA_REDUCE_TWO_OFFSET) % rankSize;
302 0 : Slice rxSliceForRoot = multiRingSlices_[ringIndex][rxSliceIdxForRoot];
303 0 : if ((rankSize < RANK_SIZE_THREE && step == 0) || (inputMem_.ptr() == opInfo_->inputAddr))
304 0 : rxSliceForRoot.size = 0;
305 0 : dst = inputMem_.range(rxSliceForRoot.offset, rxSliceForRoot.size);
306 : rxMem
307 0 : = RxMemoryInfo{UserMemType::INPUT_MEM, rxSliceForRoot.offset + baseOffset_, dst.ptr(), rxSliceForRoot.size};
308 0 : HCCL_DEBUG(
309 : "Memcpy operation: step[%u] stream[sub], src rank[%u] starts to send offset[%llu], size[%llu] "
310 : "from userMemIn_",
311 : step, userRank_, subSlice.offset, subSlice.size);
312 0 : localSrcMem = DeviceMem::create(static_cast<u8*>(opInfo_->inputAddr) + subSlice.offset, subSlice.size);
313 0 : if (step == rankSize - DMA_REDUCE_TWO_OFFSET && opInfo_->outputAddr != nullptr) {
314 0 : HCCL_DEBUG(
315 : "Memcpy operation: step[%u] stream[sub], dst rank[%u] starts to rcv offset[%llu], size[%llu] "
316 : "to userMemOut_",
317 : step, userRank_, lastStepOffset, subSlice.size);
318 0 : localDstMem = DeviceMem::create(static_cast<u8*>(opInfo_->outputAddr) + lastStepOffset, subSlice.size);
319 : } else {
320 0 : HCCL_DEBUG(
321 : "Memcpy operation: step[%u] stream[sub], dst rank[%u] starts to rcv offset[%llu], size[%llu] "
322 : "to inputMem_",
323 : step, userRank_, cclSlice.offset, cclSlice.size);
324 0 : localDstMem = inputMem_.range(cclSlice.offset, cclSlice.size);
325 : }
326 : }
327 0 : return HCCL_SUCCESS;
328 0 : }
329 :
330 0 : HcclResult ScatterDoubleRingDirect::RunScatter(const u32 rank, const u32 rankSize)
331 : {
332 0 : HCCL_INFO("ScatterDoubleRingDirect starts, the input param rank[%u]", rank);
333 :
334 0 : CHK_RET(RunInitStep(rank, rankSize));
335 :
336 : // 例如rank[0,1,2,3]中,rank0的rxSliceIdx = 2,txSliceIdx = 3, subSliceIdx = 1
337 0 : u32 subSliceIdx = (rank + rankSize - DMA_REDUCE_TWO_OFFSET) % rankSize;
338 0 : u32 mainSliceIdx = (subRingRank_ + rankSize - DMA_REDUCE_TWO_OFFSET) % rankSize;
339 :
340 0 : for (u32 step = 0; step < rankSize - 1; step++) {
341 : RxMemoryInfo rxMemSub;
342 0 : DeviceMem localSrcMemSub;
343 0 : DeviceMem localDstMemSub;
344 0 : CHK_RET(PrepareDeviceMems(
345 : rank, step, ALIGNED_SUB_RING_INDEX, rankSize, subSliceIdx, subSliceIdx, rxMemSub, localSrcMemSub,
346 : localDstMemSub));
347 : RxMemoryInfo rxMemMain;
348 0 : DeviceMem localSrcMemMain;
349 0 : DeviceMem localDstMemMain;
350 0 : CHK_RET(PrepareDeviceMems(
351 : rank, step, ALIGNED_MAIN_RING_INDEX, rankSize, mainSliceIdx, mainSliceIdx, rxMemMain, localSrcMemMain,
352 : localDstMemMain));
353 :
354 0 : CHK_RET(RunAllStreams(
355 : rank, step, rankSize, rxMemMain, rxMemSub, localSrcMemMain, localDstMemMain, localSrcMemSub,
356 : localDstMemSub));
357 :
358 : // 更新索引
359 0 : mainSliceIdx = (mainSliceIdx + rankSize - 1) % rankSize;
360 0 : subSliceIdx = (subSliceIdx + rankSize - 1) % rankSize;
361 0 : }
362 0 : HCCL_INFO("ScatterDoubleRingDirect finished to RunScatter");
363 0 : return HCCL_SUCCESS;
364 : }
365 :
366 : // 主流通知从流干活, 从流等待主流
367 0 : HcclResult ScatterDoubleRingDirect::MainRecordSub()
368 : {
369 0 : for (u32 signalIndex = 0; signalIndex < subSignals_.size(); signalIndex++) {
370 0 : CHK_RET(LocalNotify::Post(stream_, dispatcher_, subSignals_[signalIndex], profilerInput_.stage));
371 : }
372 0 : for (u32 signalIndex = 0; signalIndex < subSignals_.size(); signalIndex++) {
373 0 : CHK_RET(
374 : LocalNotify::Wait(subStreams_[signalIndex], dispatcher_, subSignals_[signalIndex], profilerInput_.stage));
375 : }
376 0 : for (u32 signalIndex = 0; signalIndex < subSignals_.size(); signalIndex++) {
377 0 : CHK_RET(ExecEmptyTask(inputMem_, outputMem_, subStreams_[signalIndex], dispatcher_));
378 : }
379 0 : CHK_RET(ExecEmptyTask(inputMem_, outputMem_, stream_, dispatcher_));
380 0 : return HCCL_SUCCESS;
381 : }
382 :
383 : // 主流等待从流, 从流告诉主流活干完了
384 0 : HcclResult ScatterDoubleRingDirect::MainWaitSub()
385 : {
386 0 : for (u32 signalIndex = 0; signalIndex < mainSignals_.size(); signalIndex++) {
387 0 : CHK_RET(LocalNotify::Wait(stream_, dispatcher_, mainSignals_[signalIndex], profilerInput_.stage));
388 : }
389 0 : for (u32 signalIndex = 0; signalIndex < mainSignals_.size(); signalIndex++) {
390 0 : CHK_RET(
391 : LocalNotify::Post(subStreams_[signalIndex], dispatcher_, mainSignals_[signalIndex], profilerInput_.stage));
392 : }
393 0 : for (u32 signalIndex = 0; signalIndex < mainSignals_.size(); signalIndex++) {
394 0 : CHK_RET(ExecEmptyTask(inputMem_, outputMem_, subStreams_[signalIndex], dispatcher_));
395 : }
396 0 : CHK_RET(ExecEmptyTask(inputMem_, outputMem_, stream_, dispatcher_));
397 0 : return HCCL_SUCCESS;
398 : }
399 : REGISTER_TEMPLATE(TemplateType::TEMPLATE_SCATTER_DOUBLE_RING_DIRECT, ScatterDoubleRingDirect);
400 : } // namespace hccl
|