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_halving_doubling.h"
12 : #include "alg_template_register.h"
13 :
14 : namespace hccl {
15 0 : AllGatherHalvingDoubling::AllGatherHalvingDoubling(const HcclDispatcher dispatcher)
16 : : AlgTemplateBase(dispatcher),
17 0 : interRank_(0),
18 0 : interRankSize_(0)
19 0 : {}
20 :
21 0 : AllGatherHalvingDoubling::~AllGatherHalvingDoubling() {}
22 :
23 0 : HcclResult AllGatherHalvingDoubling::Prepare(u32 blockSize, UserMemType hdInputMemType, UserMemType hdOutputMemType)
24 : {
25 0 : blockSize_ = blockSize;
26 0 : hdInputMemType_ = hdInputMemType;
27 0 : hdOutputMemType_ = hdOutputMemType;
28 0 : return HCCL_SUCCESS;
29 : }
30 :
31 0 : u32 AllGatherHalvingDoubling::Log2(u32 antilogarithm) const
32 : {
33 : // 求以2为底数的对数计算
34 0 : u32 logarithm = 0;
35 0 : while ((antilogarithm >> (logarithm + 1)) != 0) {
36 0 : logarithm++;
37 : }
38 :
39 0 : return logarithm;
40 : }
41 :
42 0 : HcclResult AllGatherHalvingDoubling::CalculateSlices(
43 : const std::vector<Slice>& inputSlices, u32 stepNum, u32 rank, SliceType type, std::vector<Slice>& sliceOut)
44 : {
45 0 : std::vector<Slice> slice(stepNum);
46 :
47 0 : for (u32 step = 0; step < stepNum; step++) {
48 : // all-gather操作, halving_bitmask从低往高循环, size倍增
49 0 : u32 halvingBitmask = (1 << step);
50 0 : u32 peerRank = rank ^ halvingBitmask;
51 :
52 : // 计算tx_slice/rx_slice
53 0 : u32 sliceId = (type == SliceType::SLICE_TYPE_RX) ? (peerRank & (~(halvingBitmask - 1))) :
54 0 : (rank & (~(halvingBitmask - 1)));
55 :
56 0 : slice[step].offset = inputSlices[sliceId].offset;
57 0 : CHK_RET(Sum(inputSlices, sliceId, halvingBitmask, slice[step].size));
58 :
59 0 : HCCL_DEBUG(
60 : "Slice Info: rank[%u], slices[%u].offset=%llu, slices[%u].size=%llu", rank, step, slice[step].offset, step,
61 : slice[step].size);
62 : }
63 :
64 0 : sliceOut = std::move(slice);
65 0 : return HCCL_SUCCESS;
66 0 : }
67 :
68 0 : HcclResult AllGatherHalvingDoubling::CalculateSlices(u64 size, u32 sliceNum, std::vector<Slice>& sliceOut) const
69 : {
70 : // 不对size, count和slice_num做检查, 默认满足all-gather的要求
71 0 : std::vector<Slice> slices(sliceNum);
72 :
73 0 : for (u32 i = 0; i < sliceNum; i++) {
74 0 : slices[i].size = size;
75 0 : slices[i].offset = i * size;
76 0 : HCCL_DEBUG("Slice Info: slices[%u].offset=%llu, slices[%u].size=%llu", i, slices[i].offset, i, slices[i].size);
77 : }
78 :
79 0 : sliceOut = std::move(slices);
80 0 : return HCCL_SUCCESS;
81 0 : }
82 :
83 0 : HcclResult AllGatherHalvingDoubling::Rx(const LINK& link, const Slice& rxSlice)
84 : {
85 : // 目前不考虑Halving-Doubling算法引入inlne-reduce
86 0 : DeviceMem rxMem = outputMem_.range(rxSlice.offset, rxSlice.size);
87 : // 接收数据到output
88 0 : HcclResult ret = link->RxAsync(hdOutputMemType_, rxSlice.offset + baseOffset_, rxMem.ptr(), rxSlice.size, stream_);
89 0 : CHK_PRT_RET(
90 : ret != HCCL_SUCCESS,
91 : HCCL_ERROR("[AllGatherHalvingDoubling][Rx]rank[%u] rx_async with rxMem[%p] Failed", interRank_, rxMem.ptr()),
92 : ret);
93 0 : ret = link->DataReceivedAck(stream_);
94 0 : CHK_PRT_RET(
95 : ret != HCCL_SUCCESS, HCCL_ERROR("[AllGatherHalvingDoubling][Rx]rank[%u] data_received_ack Failed", interRank_),
96 : ret);
97 0 : return HCCL_SUCCESS;
98 0 : }
99 :
100 0 : HcclResult AllGatherHalvingDoubling::Tx(const LINK& link, const Slice& txSlice)
101 : {
102 : // 目前不考虑Halving-Doubling算法引入inlne-reduce
103 0 : HcclResult ret = link->RxAck(stream_);
104 0 : CHK_PRT_RET(
105 : ret != HCCL_SUCCESS,
106 : HCCL_ERROR(
107 : "[AllGatherHalvingDoubling][Tx]rank[%u] txSlice.size[%llu]Link rx_ack "
108 : "Failed",
109 : interRank_, txSlice.size),
110 : ret);
111 0 : DeviceMem txMem = inputMem_.range(txSlice.offset, txSlice.size);
112 : // input的数据发送
113 0 : ret = link->TxAsync(hdOutputMemType_, txSlice.offset + baseOffset_, txMem.ptr(), txSlice.size, stream_);
114 0 : CHK_PRT_RET(
115 : ret != HCCL_SUCCESS,
116 : HCCL_ERROR("[AllGatherHalvingDoubling][Tx]rank[%u] tx_async txMem[%p] Failed", interRank_, txMem.ptr()), ret);
117 0 : return HCCL_SUCCESS;
118 0 : }
119 :
120 0 : HcclResult AllGatherHalvingDoubling::RunAsync(const u32 rank, const u32 rankSize, const std::vector<LINK>& links)
121 : {
122 0 : CHK_SMART_PTR_NULL(dispatcher_);
123 0 : CHK_PTR_NULL(stream_.ptr());
124 :
125 0 : HCCL_INFO(
126 : "AllGatherHD Run: rank[%u] totalrank[%u] inputMem[%p] outputMem[%p] count[%llu]", rank, rankSize,
127 : inputMem_.ptr(), outputMem_.ptr(), count_);
128 :
129 0 : HcclResult ret = HCCL_SUCCESS;
130 0 : interRank_ = rank;
131 0 : interRankSize_ = rankSize;
132 :
133 : // 检查rank, rank_size合法性
134 : // 仅一个rank, 则直接input拷贝到output
135 0 : if (rankSize == 1) {
136 0 : if (inputMem_ != outputMem_) {
137 0 : ret = HcclD2DMemcpyAsync(dispatcher_, outputMem_, inputMem_, stream_);
138 : }
139 :
140 0 : return ret;
141 : }
142 :
143 0 : if (links.size() < rankSize) {
144 0 : HCCL_ERROR("[AllGatherHalvingDoubling][RunAsync]rank[%u] link size error", rank);
145 0 : return HCCL_E_INTERNAL;
146 : }
147 : // 检查是否已对数据分片
148 0 : if (slices_.size() != rankSize) {
149 0 : CHK_RET(CalculateSlices(inputMem_.size(), rankSize, slices_));
150 : }
151 :
152 : // 计算每个step的数据size
153 0 : u32 stepNum = Log2(blockSize_);
154 0 : CHK_RET(CalculateSlices(slices_, stepNum, rank, SliceType::SLICE_TYPE_TX, txSlices_));
155 :
156 0 : CHK_RET(CalculateSlices(slices_, stepNum, rank, SliceType::SLICE_TYPE_RX, rxSlices_));
157 :
158 0 : CHK_RET(RunAllGather(rank, stepNum, links));
159 :
160 0 : HCCL_INFO("AllGatherHD finished: rank[%u]", rank);
161 0 : return HCCL_SUCCESS;
162 : }
163 :
164 0 : HcclResult AllGatherHalvingDoubling::RunAllGather(u32 rank, u32 stepNum, const std::vector<LINK>& links)
165 : {
166 0 : HcclResult ret = HCCL_SUCCESS;
167 :
168 0 : if (rxSlices_.size() < stepNum || txSlices_.size() < stepNum) {
169 0 : HCCL_ERROR("[Run][AllGather]rank[%u] rxslice size or tx slice size error", rank);
170 0 : return HCCL_E_INTERNAL;
171 : }
172 :
173 0 : for (u32 step = 0; step < stepNum; step++) {
174 : // all-gather操作, peer_rank_bitmask从低往高循环
175 0 : u32 peerRankBitmask = (1 << step);
176 0 : u32 peerRank = rank ^ peerRankBitmask;
177 0 : CHK_SMART_PTR_NULL(links[peerRank]);
178 :
179 0 : ret = links[peerRank]->TxAck(stream_);
180 0 : CHK_PRT_RET(
181 : ret != HCCL_SUCCESS,
182 : HCCL_ERROR("[Run][AllGather]rank[%u] step[%u] tx ack to dstrank[%u] Failed", rank, step, peerRank), ret);
183 :
184 : // 本rank的发送侧的动作
185 0 : HCCL_DEBUG(
186 : "Rank[%u] send to PeerRank[%u] in Round[%u], silce.offset[%llu], slice.size[%llu]", rank, peerRank, step,
187 : txSlices_[step].offset, txSlices_[step].size);
188 0 : ret = Tx(links[peerRank], txSlices_[step]);
189 0 : CHK_PRT_RET(
190 : ret != HCCL_SUCCESS,
191 : HCCL_ERROR("[Run][AllGather]Rank[%u] end to PeerRank[%u] run tx failed ", rank, peerRank), ret);
192 0 : HCCL_DEBUG(
193 : "Rank[%u]receive from PeerRank[%u] in Round[%u], silce.offset[%llu], slice.size[%llu]", rank, peerRank,
194 : step, rxSlices_[step].offset, rxSlices_[step].size);
195 : // 本rank的接收侧的动作
196 0 : ret = Rx(links[peerRank], rxSlices_[step]);
197 0 : CHK_PRT_RET(
198 : ret != HCCL_SUCCESS, HCCL_ERROR("[Run][AllGather]Rank[%u] rx from PeerRank[%u] failed", rank, peerRank),
199 : ret);
200 0 : ret = links[peerRank]->RxWaitDone(stream_);
201 0 : CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("[Run][AllGather]RxWaitDone failed"), ret);
202 0 : ret = links[peerRank]->TxWaitDone(stream_);
203 0 : CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("[Run][AllGather]TxWaitDone failed"), ret);
204 : }
205 0 : return ret;
206 : }
207 :
208 0 : HcclResult AllGatherHalvingDoubling::GetNslbAdjInfo(
209 : [[maybe_unused]] const u32 rank, [[maybe_unused]] const u32 rankSize,
210 : [[maybe_unused]] const std::vector<LINK>& links, [[maybe_unused]] AdjInfo& nslbAdjInfo)
211 : {
212 0 : return HCCL_SUCCESS;
213 : }
214 :
215 : REGISTER_TEMPLATE(TemplateType::TEMPLATE_ALL_GATHER_HALVING_DOUBLING, AllGatherHalvingDoubling);
216 : } // namespace hccl
|