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