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 "sal_pub.h"
12 : #include "alg_template_base.h"
13 :
14 : namespace hccl {
15 232 : ExecutorBase::ExecutorBase(const HcclDispatcher dispatcher)
16 232 : : dispatcher_(dispatcher),
17 232 : slices_(slicesDummy_),
18 232 : count_(0),
19 232 : dataBytes_(0),
20 232 : dataType_(HCCL_DATA_TYPE_RESERVED),
21 232 : reductionOp_(HCCL_REDUCE_RESERVED),
22 232 : root_(INVALID_VALUE_RANKID),
23 232 : baseOffset_(0),
24 232 : barrierSwitchOn_(true)
25 232 : {}
26 :
27 232 : ExecutorBase::~ExecutorBase() { slices_.clear(); }
28 :
29 1 : HcclResult ExecutorBase::Prepare([[maybe_unused]] PrepareData& param) { return HCCL_E_PARA; }
30 :
31 : // prepare函数给需要进行集合通信操作进行参数赋值
32 113 : HcclResult ExecutorBase::Prepare(
33 : DeviceMem& inputMem, DeviceMem& outputMem, DeviceMem& scratchMem, const u64 count, const HcclDataType dataType,
34 : const Stream& stream, const HcclReduceOp reductionOp, const u32 root, const std::vector<Slice>& slices,
35 : const u64 baseOffset, std::vector<u32> nicRankList, const bool disableDMAReduce)
36 : {
37 : // 部分集合通信操作允许input_mem/output_mem为空
38 :
39 : /* * 参数保存 */
40 113 : inputMem_ = inputMem;
41 113 : outputMem_ = outputMem;
42 113 : scratchMem_ = scratchMem;
43 113 : stream_ = stream;
44 113 : count_ = count;
45 113 : dataType_ = dataType;
46 113 : dataBytes_ = count * DataUnitSize(dataType);
47 113 : reductionOp_ = reductionOp;
48 113 : HCCL_DEBUG("[ExecutorBase][Prepare]count is %lu, reductionOp is %d", count_, reductionOp_);
49 113 : root_ = root;
50 113 : disableDMAReduce_ = disableDMAReduce;
51 113 : HCCL_DEBUG("ExecutorBase prepare start");
52 :
53 : /* 相对用户基地址偏移 */
54 113 : baseOffset_ = baseOffset;
55 :
56 113 : if (slices.size() > 0) {
57 37 : slices_.resize(slices.size());
58 37 : slices_ = slices;
59 : }
60 :
61 113 : nicRankList_.assign(nicRankList.begin(), nicRankList.end());
62 : // 不带入该参数,代表数据均分,直接用count赋值
63 113 : HCCL_DEBUG("ExecutorBase prepare end");
64 113 : return HCCL_SUCCESS;
65 : }
66 :
67 0 : HcclResult ExecutorBase::Prepare(
68 : DeviceMem& inputMem, DeviceMem& scratchMem, const u64 count, const HcclDataType dataType, const Stream& stream,
69 : const HcclReduceOp reductionOp, const u32 root, const std::vector<Slice>& slices, const u64 baseOffset,
70 : std::vector<u32> nicRankList, const bool disableDMAReduce)
71 : {
72 : // 部分集合通信操作允许input_mem/output_mem为空
73 0 : CHK_PTR_NULL(stream.ptr());
74 :
75 0 : HCCL_DEBUG("ExecutorBase prepare start");
76 :
77 : /* * 参数保存 */
78 0 : inputMem_ = inputMem;
79 0 : outputMem_ = inputMem;
80 0 : scratchMem_ = scratchMem;
81 0 : stream_ = stream;
82 0 : count_ = count;
83 0 : dataType_ = dataType;
84 0 : dataBytes_ = count * DataUnitSize(dataType);
85 0 : reductionOp_ = reductionOp;
86 0 : root_ = root;
87 0 : disableDMAReduce_ = disableDMAReduce;
88 :
89 : /* 相对用户基地址偏移 */
90 0 : baseOffset_ = baseOffset;
91 :
92 0 : if (slices.size() > 0) {
93 0 : slices_.resize(slices.size());
94 0 : slices_ = slices;
95 : }
96 :
97 0 : nicRankList_.assign(nicRankList.begin(), nicRankList.end());
98 : // 不带入该参数,代表数据均分,直接用count赋值
99 0 : HCCL_DEBUG("ExecutorBase prepare end");
100 0 : return HCCL_SUCCESS;
101 : }
102 :
103 66 : HcclResult ExecutorBase::Prepare(
104 : DeviceMem& inputMem, DeviceMem& outputMem, DeviceMem& scratchMem, const u64 count, const HcclDataType dataType,
105 : const Stream& stream, const std::vector<std::vector<Slice>>& multRingsSlices, const HcclReduceOp reductionOp,
106 : const u32 root, const u64 baseOffset, const bool disableDMAReduce)
107 : {
108 : // 部分集合通信操作允许input_mem/output_mem为空
109 :
110 66 : HCCL_DEBUG("AlignedDoubleRing prepare start");
111 :
112 : /* * 参数保存 */
113 66 : inputMem_ = inputMem;
114 66 : outputMem_ = outputMem;
115 66 : scratchMem_ = scratchMem;
116 66 : stream_ = stream;
117 66 : count_ = count;
118 66 : dataType_ = dataType;
119 66 : dataBytes_ = count * DataUnitSize(dataType);
120 66 : reductionOp_ = reductionOp;
121 66 : root_ = root;
122 66 : disableDMAReduce_ = disableDMAReduce;
123 :
124 : /* 相对用户基地址偏移 */
125 66 : baseOffset_ = baseOffset;
126 66 : multRingsSlices_.resize(multRingsSlices.size());
127 198 : for (u32 ringIndex = 0; ringIndex < multRingsSlices.size(); ringIndex++) {
128 132 : if (multRingsSlices[ringIndex].size() > 0) {
129 132 : multRingsSlices_[ringIndex].resize(multRingsSlices[ringIndex].size());
130 132 : multRingsSlices_[ringIndex] = multRingsSlices[ringIndex];
131 : }
132 : }
133 :
134 66 : HCCL_DEBUG("AlignedDoubleRing prepare end");
135 66 : return HCCL_SUCCESS;
136 : }
137 :
138 : /* 1个参数 */
139 : // AllGatherNHR, ScatterNHR
140 0 : HcclResult ExecutorBase::Prepare([[maybe_unused]] bool needSaveRankMap) { return HCCL_E_PARA; }
141 :
142 : // GatherStar
143 0 : HcclResult ExecutorBase::Prepare([[maybe_unused]] u32 userRank) { return HCCL_E_PARA; }
144 :
145 : // AHC 扩展参数
146 0 : HcclResult ExecutorBase::Prepare([[maybe_unused]] AHCExtendPreparePara& extendParam) { return HCCL_E_PARA; }
147 :
148 : /* 2个参数 */
149 : // ReduceScatterNB, ReduceScatterNHRV1, ReduceScatterRing, ReduceScatterRecursiveHalvingDoubling
150 1 : HcclResult ExecutorBase::Prepare([[maybe_unused]] u64 reduceAttrBitMap, [[maybe_unused]] HcomCollOpInfo* opInfo)
151 : {
152 1 : return HCCL_E_PARA;
153 : }
154 :
155 : // ReduceScatterNHR
156 1 : HcclResult ExecutorBase::Prepare([[maybe_unused]] u64 reduceAttrBitMap, [[maybe_unused]] bool needMerge)
157 : {
158 1 : return HCCL_E_PARA;
159 : }
160 :
161 : // ReduceScatterMeshMixSingleStream, ReduceScatterMesh
162 1 : HcclResult ExecutorBase::Prepare([[maybe_unused]] u64 reduceAttrBitMap, [[maybe_unused]] u32 streamIndex)
163 : {
164 1 : return HCCL_E_PARA;
165 : }
166 :
167 : // ScatterMesh
168 0 : HcclResult ExecutorBase::Prepare([[maybe_unused]] u32 interRank, [[maybe_unused]] u32 interRankSize)
169 : {
170 0 : return HCCL_E_PARA;
171 : }
172 :
173 : /* 3个参数 */
174 : // for AllGatherHalvingDoubling based on intput_scratch_Mem_nicRankList Prepare
175 : // and should be called soon template AllGatherHalvingDoubling created
176 0 : HcclResult ExecutorBase::Prepare(
177 : [[maybe_unused]] u32 blockSize, [[maybe_unused]] UserMemType hdInputMemType,
178 : [[maybe_unused]] UserMemType hdOutputMemType)
179 : {
180 0 : return HCCL_E_PARA;
181 : }
182 :
183 : /* 4个参数 */
184 : // ScatterRingDirect
185 0 : HcclResult ExecutorBase::Prepare(
186 : [[maybe_unused]] HcomCollOpInfo* opInfo, [[maybe_unused]] const u32 userRank,
187 : [[maybe_unused]] const std::vector<u32>& ringsOrders, [[maybe_unused]] const std::vector<Slice>& userMemInputSlices)
188 : {
189 0 : return HCCL_E_PARA;
190 : }
191 :
192 0 : HcclResult ExecutorBase::Prepare(
193 : [[maybe_unused]] HcomCollOpInfo* opInfo, [[maybe_unused]] u32 userRank,
194 : [[maybe_unused]] const std::vector<Slice>& userMemOutputSlices, [[maybe_unused]] bool isSdma)
195 : {
196 0 : return HCCL_E_PARA;
197 : }
198 :
199 : /* 5个参数 */
200 : // AHC 5个参数,带扩展参数
201 0 : HcclResult ExecutorBase::Prepare(
202 : [[maybe_unused]] u64 totalCount, [[maybe_unused]] const std::vector<std::vector<std::vector<u32>>>& subGroups,
203 : [[maybe_unused]] std::map<AHCConcOpType, TemplateType>& ahcAlgOption, [[maybe_unused]] bool extendFlag,
204 : [[maybe_unused]] AHCExtendPreparePara extendPara)
205 : {
206 0 : return HCCL_E_PARA;
207 : }
208 :
209 : /* 6个参数 */
210 : // AlltoAllVStagedPairwise
211 1 : HcclResult ExecutorBase::Prepare(
212 : [[maybe_unused]] DeviceMem& sendMem, [[maybe_unused]] DeviceMem& recvMem,
213 : [[maybe_unused]] StageAlltoAllVAddrInfo& sendAddrInfo, [[maybe_unused]] StageAlltoAllVAddrInfo& recvAddrInfo,
214 : [[maybe_unused]] bool isAlltoAllZCopyMode, [[maybe_unused]] Stream& mainStream)
215 : {
216 1 : return HCCL_E_PARA;
217 : }
218 :
219 : /* 7个参数 */
220 0 : HcclResult ExecutorBase::Prepare(
221 : [[maybe_unused]] u64 reduceAttrBitMap, [[maybe_unused]] std::vector<Stream>& meshStreams,
222 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignal,
223 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignalAux, [[maybe_unused]] u32 userRank,
224 : [[maybe_unused]] HcomCollOpInfo* opInfo, [[maybe_unused]] bool aicpu)
225 : {
226 0 : return HCCL_E_PARA;
227 : }
228 :
229 : // AlltoAllVPairWise
230 1 : HcclResult ExecutorBase::Prepare(
231 : [[maybe_unused]] AlltoAllVBufferInfo& sendBuffer, [[maybe_unused]] AlltoAllVBufferInfo& recvBuffer,
232 : [[maybe_unused]] bool isAlltoAllZCopyMode, [[maybe_unused]] const Stream& stream,
233 : [[maybe_unused]] HcclWorkflowMode workMode, [[maybe_unused]] std::map<u32, std::vector<u64>>& rankSendDisplsMap,
234 : [[maybe_unused]] std::map<u32, std::vector<u64>>& rankRecvDisplsMap)
235 : {
236 1 : return HCCL_E_PARA;
237 : }
238 :
239 : // AlignedAllGatherDoubleRing
240 0 : HcclResult ExecutorBase::Prepare(
241 : [[maybe_unused]] HcomCollOpInfo* opInfo, [[maybe_unused]] const u32 userRank,
242 : [[maybe_unused]] std::vector<Stream>& subStreams,
243 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& mainSignals,
244 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& subSignals,
245 : [[maybe_unused]] const std::vector<std::vector<u32>>& ringsOrders,
246 : [[maybe_unused]] const std::vector<std::vector<Slice>>& userMemOutputSlicesOfDoubleRing)
247 : {
248 0 : return HCCL_E_PARA;
249 : }
250 :
251 : // AllGatherMeshAtomic, AllgatherMeshDirect, AllGatherMesh, AllgatherMeshMix GatherMesh
252 0 : HcclResult ExecutorBase::Prepare(
253 : [[maybe_unused]] std::vector<Stream>& meshStreams,
254 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignal,
255 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignalAux, [[maybe_unused]] u32 userRank,
256 : [[maybe_unused]] HcomCollOpInfo* opInfo, [[maybe_unused]] u32 interRank, [[maybe_unused]] u32 interRankSize)
257 : {
258 0 : return HCCL_E_PARA;
259 : }
260 :
261 : /* 8个参数 */
262 0 : HcclResult ExecutorBase::Prepare(
263 : [[maybe_unused]] u64 reduceAttrBitMap, [[maybe_unused]] std::vector<Stream>& meshStreams,
264 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignal,
265 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignalAux, [[maybe_unused]] u32 interRank,
266 : [[maybe_unused]] u32 interRankSize, [[maybe_unused]] u32 userRank, [[maybe_unused]] HcomCollOpInfo* opInfo)
267 : {
268 0 : return HCCL_E_PARA;
269 : }
270 :
271 : // AlltoAllVStagedPairwise
272 1 : HcclResult ExecutorBase::Prepare(
273 : [[maybe_unused]] DeviceMem& sendMem, [[maybe_unused]] DeviceMem& recvMem,
274 : [[maybe_unused]] DeviceMem& scratchInputMem, [[maybe_unused]] DeviceMem& scratchOutputMem,
275 : [[maybe_unused]] StageAlltoAllVAddrInfo& sendAddrInfo, [[maybe_unused]] StageAlltoAllVAddrInfo& recvAddrInfo,
276 : [[maybe_unused]] bool isAlltoAllZCopyMode, [[maybe_unused]] Stream& mainStream)
277 : {
278 1 : return HCCL_E_PARA;
279 : }
280 :
281 : // AllGatherRingConcurrentDirect ScatterRingConcurrentDirect
282 0 : HcclResult ExecutorBase::Prepare(
283 : [[maybe_unused]] HcomCollOpInfo* opInfo, [[maybe_unused]] const u32 userRank,
284 : [[maybe_unused]] std::vector<Stream>& subStreams,
285 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& mainSignals,
286 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& subSignals,
287 : [[maybe_unused]] const std::vector<u32>& ringsOrder, [[maybe_unused]] const std::vector<Slice>& userMemSlices,
288 : [[maybe_unused]] bool isSdma)
289 : {
290 0 : return HCCL_E_PARA;
291 : }
292 :
293 : /* 9个参数 */
294 : // catterDoubleRingDirect
295 0 : HcclResult ExecutorBase::Prepare(
296 : [[maybe_unused]] HcomCollOpInfo* opInfo, [[maybe_unused]] const u32 userRank,
297 : [[maybe_unused]] const u32 subRingRank, [[maybe_unused]] std::vector<Stream>& subStreams,
298 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& mainSignals,
299 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& subSignals,
300 : [[maybe_unused]] const std::vector<std::vector<u32>>& ringsOrders,
301 : [[maybe_unused]] const std::vector<std::vector<Slice>>& multiRingSlices,
302 : [[maybe_unused]] const std::vector<std::vector<Slice>>& userMemInputSlices)
303 : {
304 0 : return HCCL_E_PARA;
305 : }
306 :
307 : // ReduceScatterRingConcurrentDirect
308 1 : HcclResult ExecutorBase::Prepare(
309 : [[maybe_unused]] const u64 reduceAttrBitMap, [[maybe_unused]] const HcomCollOpInfo* opInfo,
310 : [[maybe_unused]] const u32 userRank, [[maybe_unused]] std::vector<Stream>& subStreams,
311 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& mainSignals,
312 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& subSignals,
313 : [[maybe_unused]] const std::vector<u32>& ringsOrder, [[maybe_unused]] const std::vector<Slice>& userMemInputSlices,
314 : [[maybe_unused]] bool isSdma)
315 : {
316 1 : return HCCL_E_PARA;
317 : }
318 :
319 : // AlltoAllVPairWise
320 1 : HcclResult ExecutorBase::Prepare(
321 : [[maybe_unused]] AlltoAllVBufferInfo& sendBuffer, [[maybe_unused]] AlltoAllVBufferInfo& recvBuffer,
322 : [[maybe_unused]] DeviceMem& scratchInputMem, [[maybe_unused]] DeviceMem& scratchOutputMem,
323 : [[maybe_unused]] bool isAlltoAllZCopyMode, [[maybe_unused]] const Stream& stream,
324 : [[maybe_unused]] HcclWorkflowMode workMode, [[maybe_unused]] std::map<u32, std::vector<u64>>& rankSendDisplsMap,
325 : [[maybe_unused]] std::map<u32, std::vector<u64>>& rankRecvDisplsMap)
326 : {
327 1 : return HCCL_E_PARA;
328 : }
329 :
330 : /* 10个参数 */
331 0 : HcclResult ExecutorBase::Prepare(
332 : [[maybe_unused]] const HcomCollOpInfo* opInfo, [[maybe_unused]] DeviceMem& cclBufferA,
333 : [[maybe_unused]] DeviceMem& cclBufferB, [[maybe_unused]] const u64 count,
334 : [[maybe_unused]] const SubCommInfo& level1CommInfo, [[maybe_unused]] const SubCommInfo& level0CommInfo,
335 : [[maybe_unused]] Stream& mainStream, [[maybe_unused]] std::vector<Stream>& subStream,
336 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifyMain,
337 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifySub)
338 : {
339 0 : return HCCL_E_PARA;
340 : }
341 :
342 : // AlltoallPipelineMeshPairwiseCCLEnough, AlltoallPipelineMeshPairwisePingPong
343 0 : HcclResult ExecutorBase::Prepare(
344 : [[maybe_unused]] u32 userRank, [[maybe_unused]] A2aPipelineMemory A2aPipelineMemory,
345 : [[maybe_unused]] const SubCommInfo& level0CommInfo, [[maybe_unused]] const SubCommInfo& level1CommInfo,
346 : [[maybe_unused]] Stream& mainStream, [[maybe_unused]] std::vector<Stream>& subStream,
347 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifyMain,
348 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifySub,
349 : [[maybe_unused]] std::vector<SendRecvInfo>& allMeshAggregationSendRecvInfo,
350 : [[maybe_unused]] HcclWorkflowMode workMode)
351 : {
352 0 : return HCCL_E_PARA;
353 : }
354 :
355 : // AlltoAllVStagedMesh
356 1 : HcclResult ExecutorBase::Prepare(
357 : [[maybe_unused]] DeviceMem& sendMem, [[maybe_unused]] DeviceMem& recvMem,
358 : [[maybe_unused]] StageAlltoAllVAddrInfo& sendAddrInfo, [[maybe_unused]] StageAlltoAllVAddrInfo& recvAddrInfo,
359 : [[maybe_unused]] bool isAlltoAllZCopyMode, [[maybe_unused]] u32 userRank, [[maybe_unused]] Stream& mainStream,
360 : [[maybe_unused]] std::vector<Stream>& subStreams,
361 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignalMainToSub,
362 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignalSubToMain)
363 : {
364 1 : return HCCL_E_PARA;
365 : }
366 :
367 : // ReduceScatterPlantLocalReduceCombine
368 0 : HcclResult ExecutorBase::Prepare(
369 : [[maybe_unused]] DeviceMem& cclInMem, [[maybe_unused]] DeviceMem& outputMem, [[maybe_unused]] const Stream& stream,
370 : [[maybe_unused]] std::vector<Stream>& subStreams,
371 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignal,
372 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignalAux, MemBlockInfo& memBlockInfo,
373 : [[maybe_unused]] const HcclReduceOp reductionOp, [[maybe_unused]] const HcclDataType dataType, bool isUseCclIn,
374 : bool isLevel0LastRank, bool isNeedSpaceBorrow)
375 : {
376 : (void)isUseCclIn;
377 : (void)memBlockInfo;
378 : (void)isLevel0LastRank;
379 : (void)isNeedSpaceBorrow;
380 0 : return HCCL_E_PARA;
381 : }
382 :
383 : /* 11个参数 */
384 : // Prepare for AllGatherPipeline
385 0 : HcclResult ExecutorBase::Prepare(
386 : [[maybe_unused]] HcomCollOpInfo* opInfo, [[maybe_unused]] u32 userRank, [[maybe_unused]] u64& count,
387 : [[maybe_unused]] DeviceMem& cclBufferPartOne, [[maybe_unused]] DeviceMem& cclBufferPartTwo,
388 : [[maybe_unused]] SubCommInfo& level0CommInfo, [[maybe_unused]] SubCommInfo& level1CommInfo,
389 : [[maybe_unused]] Stream& mainStream, [[maybe_unused]] std::vector<Stream>& subStream,
390 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifyMain,
391 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifySub)
392 : {
393 0 : return HCCL_E_PARA;
394 : }
395 :
396 : // Prepare for AllGatherUnifiedMarch
397 0 : HcclResult ExecutorBase::Prepare(
398 : [[maybe_unused]] const Stream& mainStream, [[maybe_unused]] SubCommInfo& level0CommInfo,
399 : [[maybe_unused]] DeviceMem& userInput, [[maybe_unused]] DeviceMem& userOutput, [[maybe_unused]] DeviceMem& usrInMem,
400 : [[maybe_unused]] DeviceMem& usrOutMem, [[maybe_unused]] u64 blockDataByte,
401 : [[maybe_unused]] std::vector<Stream>& subStreams,
402 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& meshSignalMainToSub,
403 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& meshSignalSubToMain,
404 : [[maybe_unused]] const std::vector<std::vector<Slice>>& multRingsUserMemSlice,
405 : [[maybe_unused]] const u64 baseOffset)
406 : {
407 0 : return HCCL_E_PARA;
408 : }
409 :
410 : // Prepare for ReduceScatterPlantLocalReduce
411 0 : HcclResult ExecutorBase::Prepare(
412 : void* inputMemPtr, [[maybe_unused]] DeviceMem& cclInMem, [[maybe_unused]] DeviceMem& outputMem,
413 : [[maybe_unused]] const Stream& stream, [[maybe_unused]] std::vector<Stream>& subStreams,
414 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignal,
415 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignalAux, GroupSlicesInfo& grouSlicesInfo,
416 : [[maybe_unused]] const HcclReduceOp reductionOp, u32 all2allOffset, [[maybe_unused]] const HcclDataType dataType,
417 : bool isNeedSpaceBorrow, [[maybe_unused]] bool reverseMemUsage, [[maybe_unused]] bool isA3CrossNode)
418 : {
419 : (void)inputMemPtr;
420 : (void)all2allOffset;
421 : (void)grouSlicesInfo;
422 : (void)isNeedSpaceBorrow;
423 0 : return HCCL_E_PARA;
424 : }
425 :
426 : // Prepare for ReduceScatterVPipeline
427 0 : HcclResult ExecutorBase::Prepare(
428 : [[maybe_unused]] HcomCollOpInfo* opInfo, [[maybe_unused]] DeviceMem& cclBuffer,
429 : [[maybe_unused]] const u64 bufferSize, [[maybe_unused]] const std::vector<Slice>& slices,
430 : [[maybe_unused]] const SubCommInfo& level0CommInfo, [[maybe_unused]] const SubCommInfo& level1CommInfo,
431 : [[maybe_unused]] Stream& mainStream, [[maybe_unused]] std::vector<Stream>& subStream,
432 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifyMain,
433 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifySub, [[maybe_unused]] u64 reduceAttrBitMap)
434 : {
435 0 : return HCCL_E_PARA;
436 : }
437 :
438 0 : HcclResult ExecutorBase::Prepare(
439 : [[maybe_unused]] const u32 userRank, const A2aPipelineMemory& a2aPipelineMemory,
440 : [[maybe_unused]] const SubCommInfo& level0CommInfo, [[maybe_unused]] const SubCommInfo& level1CommInfo,
441 : [[maybe_unused]] const Stream& mainStream, [[maybe_unused]] std::vector<Stream>& subStream,
442 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifyMain,
443 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifySub, std::vector<SendRecvInfo>& sendRecvInfoList,
444 : [[maybe_unused]] const HcclDataType dataType, [[maybe_unused]] const HcclWorkflowMode workMode)
445 : {
446 : (void)a2aPipelineMemory;
447 : (void)sendRecvInfoList;
448 0 : return HCCL_E_PARA;
449 : }
450 :
451 : /* 12个参数 */
452 : // AlltoAllVFor310P
453 1 : HcclResult ExecutorBase::Prepare(
454 : [[maybe_unused]] DeviceMem& userInput, [[maybe_unused]] DeviceMem& userOutput, [[maybe_unused]] DeviceMem& cclInMem,
455 : [[maybe_unused]] DeviceMem& cclOutMem,
456 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& signalMainToSub,
457 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& signalSubToMain,
458 : [[maybe_unused]] Stream& mainStream, [[maybe_unused]] std::vector<Stream>& subStreams,
459 : [[maybe_unused]] const std::vector<LINK>& links, [[maybe_unused]] u32 userRank, [[maybe_unused]] u32 userRankSize,
460 : [[maybe_unused]] std::vector<SendRecvInfo>& allMeshAggregationSendRecvInfo)
461 : {
462 1 : return HCCL_E_PARA;
463 : }
464 :
465 : // AlltoAllVStagedMesh
466 1 : HcclResult ExecutorBase::Prepare(
467 : [[maybe_unused]] DeviceMem& sendMem, [[maybe_unused]] DeviceMem& recvMem,
468 : [[maybe_unused]] DeviceMem& scratchInputMem, [[maybe_unused]] DeviceMem& scratchOutputMem,
469 : [[maybe_unused]] StageAlltoAllVAddrInfo& sendAddrInfo, [[maybe_unused]] StageAlltoAllVAddrInfo& recvAddrInfo,
470 : [[maybe_unused]] bool isAlltoAllZCopyMode, [[maybe_unused]] u32 userRank, [[maybe_unused]] Stream& mainStream,
471 : [[maybe_unused]] std::vector<Stream>& subStreams,
472 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignalMainToSub,
473 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignalSubToMain)
474 : {
475 1 : return HCCL_E_PARA;
476 : }
477 :
478 : // ReduceScatterPipeline
479 1 : HcclResult ExecutorBase::Prepare(
480 : [[maybe_unused]] HcomCollOpInfo* opInfo, [[maybe_unused]] DeviceMem& cclBuffer, [[maybe_unused]] const u64 count,
481 : [[maybe_unused]] const u64 bufferSize, [[maybe_unused]] const u64 offset,
482 : [[maybe_unused]] const SubCommInfo& level0CommInfo, [[maybe_unused]] const SubCommInfo& level1CommInfo,
483 : [[maybe_unused]] Stream& mainStream, [[maybe_unused]] std::vector<Stream>& subStream,
484 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifyMain,
485 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifySub, [[maybe_unused]] u64 reduceAttrBitMap)
486 : {
487 1 : return HCCL_E_PARA;
488 : }
489 :
490 : // BroadcastStar
491 1 : HcclResult ExecutorBase::Prepare(
492 : [[maybe_unused]] DeviceMem& inputMem, [[maybe_unused]] DeviceMem& outputMem, [[maybe_unused]] DeviceMem& scratchMem,
493 : [[maybe_unused]] const u64 count, [[maybe_unused]] const HcclDataType dataType,
494 : [[maybe_unused]] const Stream& stream, [[maybe_unused]] const HcclReduceOp reductionOp,
495 : [[maybe_unused]] const u32 root, [[maybe_unused]] const std::vector<Slice>& slices,
496 : [[maybe_unused]] const u64 baseOffset, [[maybe_unused]] std::vector<u32> nicRankList, [[maybe_unused]] u32 userRank)
497 : {
498 1 : return HCCL_E_PARA;
499 : }
500 :
501 : // Prepare for AllGatherVPipeline
502 0 : HcclResult ExecutorBase::Prepare(
503 : [[maybe_unused]] HcomCollOpInfo* opInfo, [[maybe_unused]] u32 userRank, [[maybe_unused]] u64& count,
504 : [[maybe_unused]] DeviceMem& cclBufferPartOne, [[maybe_unused]] DeviceMem& cclBufferPartTwo,
505 : [[maybe_unused]] SubCommInfo& level0CommInfo, [[maybe_unused]] SubCommInfo& level1CommInfo,
506 : [[maybe_unused]] Stream& mainStream, [[maybe_unused]] std::vector<Stream>& subStream,
507 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifyMain,
508 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifySub, std::vector<Slice>& userOutSlice)
509 : {
510 : (void)userOutSlice;
511 0 : return HCCL_E_PARA;
512 : }
513 :
514 : /* 13个参数 */
515 : // BroadcastHD
516 1 : HcclResult ExecutorBase::Prepare(
517 : [[maybe_unused]] DeviceMem& inputMem, [[maybe_unused]] DeviceMem& outputMem, [[maybe_unused]] DeviceMem& scratchMem,
518 : [[maybe_unused]] const u64 count, [[maybe_unused]] const HcclDataType dataType,
519 : [[maybe_unused]] const Stream& stream, [[maybe_unused]] const HcclReduceOp reductionOp,
520 : [[maybe_unused]] const u32 root, [[maybe_unused]] std::vector<Stream>& meshStreams,
521 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& meshSignal,
522 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& meshSignalAux, [[maybe_unused]] u32 interRank,
523 : [[maybe_unused]] const HcomCollOpInfo* opInfo)
524 : {
525 1 : return HCCL_E_PARA;
526 : }
527 :
528 : /* 14个参数 */
529 : // ReduceScatterUnifiedMarch
530 1 : HcclResult ExecutorBase::Prepare(
531 : [[maybe_unused]] Stream& mainStream, [[maybe_unused]] SubCommInfo& level0CommInfo,
532 : [[maybe_unused]] DeviceMem& userInput, [[maybe_unused]] DeviceMem& userOutput, [[maybe_unused]] DeviceMem& usrInMem,
533 : [[maybe_unused]] DeviceMem& scratchMem, [[maybe_unused]] u64 totalCount,
534 : [[maybe_unused]] std::vector<Stream>& subStreams,
535 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& meshSignalMainToSub,
536 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& meshSignalSubToMain,
537 : [[maybe_unused]] const HcclDataType dataType, [[maybe_unused]] const HcclReduceOp reductionOp,
538 : [[maybe_unused]] const std::vector<std::vector<Slice>>& multRingsUserMemSlice,
539 : [[maybe_unused]] u64 reduceAttrBitMap)
540 : {
541 1 : return HCCL_E_PARA;
542 : }
543 :
544 : // ReduceScatterHalvingDoubling
545 1 : HcclResult ExecutorBase::Prepare(
546 : [[maybe_unused]] DeviceMem& inputMem, [[maybe_unused]] DeviceMem& outputMem, [[maybe_unused]] DeviceMem& scratchMem,
547 : [[maybe_unused]] const u64 count, [[maybe_unused]] const HcclDataType dataType,
548 : [[maybe_unused]] const Stream& stream, [[maybe_unused]] const HcclReduceOp reductionOp,
549 : [[maybe_unused]] const u32 root, [[maybe_unused]] const std::vector<Slice>& slices,
550 : [[maybe_unused]] const u64 baseOffset, [[maybe_unused]] const u32 blockSize,
551 : [[maybe_unused]] const u64 reduceAttrBitMap, [[maybe_unused]] const UserMemType hdInputMemType,
552 : [[maybe_unused]] const UserMemType hdOutputMemType)
553 : {
554 1 : return HCCL_E_PARA;
555 : }
556 :
557 : /* 15个参数 */
558 : // AlltoAllVMeshReadOnly
559 0 : HcclResult ExecutorBase::Prepare(
560 : [[maybe_unused]] DeviceMem& userInput, [[maybe_unused]] DeviceMem& userOutput,
561 : [[maybe_unused]] DeviceMem& scratchPingMem, [[maybe_unused]] DeviceMem& scratchPongMem,
562 : [[maybe_unused]] StageAlltoAllVAddrInfo& sendAddrInfo, [[maybe_unused]] StageAlltoAllVAddrInfo& recvAddrInfo,
563 : [[maybe_unused]] HcclWorkflowMode workMode, [[maybe_unused]] Stream& mainStream,
564 : [[maybe_unused]] std::vector<Stream>& subStreams,
565 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& meshSignalMainToSub,
566 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& meshSignalSubToMain,
567 : [[maybe_unused]] u32 userRank, [[maybe_unused]] u32 intraRankSize, [[maybe_unused]] const std::vector<LINK>& links,
568 : [[maybe_unused]] std::vector<SendRecvInfo>& allMeshAggregationSendRecvInfo)
569 : {
570 0 : return HCCL_E_PARA;
571 : }
572 :
573 : /* 16个参数 */
574 : // ReduceScatterHDStage, ReduceScatterLocalReduce, ReduceScatterMeshAtomic, ReduceScatterMeshDirect
575 1 : HcclResult ExecutorBase::Prepare(
576 : [[maybe_unused]] DeviceMem& inputMem, [[maybe_unused]] DeviceMem& outputMem, [[maybe_unused]] DeviceMem& scratchMem,
577 : [[maybe_unused]] const u64 count, [[maybe_unused]] const HcclDataType dataType,
578 : [[maybe_unused]] const Stream& stream, [[maybe_unused]] const HcclReduceOp reductionOp,
579 : [[maybe_unused]] const u32 root, [[maybe_unused]] const std::vector<Slice>& slices,
580 : [[maybe_unused]] const u64 baseOffset, [[maybe_unused]] const u64 reduceAttrBitMap,
581 : [[maybe_unused]] std::vector<Stream>& meshStreams,
582 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignal,
583 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignalAux, [[maybe_unused]] u32 userRank,
584 : [[maybe_unused]] const HcomCollOpInfo* opInfo)
585 : {
586 1 : return HCCL_E_PARA;
587 : }
588 :
589 : /* 17个参数 */
590 : // ReduceScatterMeshMix
591 1 : HcclResult ExecutorBase::Prepare(
592 : [[maybe_unused]] DeviceMem& inputMem, [[maybe_unused]] DeviceMem& outputMem, [[maybe_unused]] DeviceMem& scratchMem,
593 : [[maybe_unused]] const u64 count, [[maybe_unused]] const HcclDataType dataType,
594 : [[maybe_unused]] const Stream& stream, [[maybe_unused]] const HcclReduceOp reductionOp,
595 : [[maybe_unused]] const u32 root, [[maybe_unused]] const std::vector<Slice>& slices,
596 : [[maybe_unused]] const u64 baseOffset, [[maybe_unused]] const u64 reduceAttrBitMap,
597 : [[maybe_unused]] std::vector<Stream>& meshStreams,
598 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& meshSignal,
599 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& meshSignalAux, [[maybe_unused]] u32 interRank,
600 : [[maybe_unused]] u32 interRankSize, [[maybe_unused]] HcomCollOpInfo* opInfo)
601 : {
602 1 : return HCCL_E_PARA;
603 : }
604 :
605 : /* 19个参数 */
606 : // AlignedReduceScatterDoubleRing, AlignedReduceScatter, DoubleRingWithSerialLocalCopy
607 1 : HcclResult ExecutorBase::Prepare(
608 : [[maybe_unused]] DeviceMem& inputMem, [[maybe_unused]] DeviceMem& outputMem, [[maybe_unused]] DeviceMem& scratchMem,
609 : [[maybe_unused]] const u64 count, [[maybe_unused]] const HcclDataType dataType,
610 : [[maybe_unused]] const Stream& stream, [[maybe_unused]] const std::vector<std::vector<Slice>>& multRingsSlices,
611 : [[maybe_unused]] const HcclReduceOp reductionOp, [[maybe_unused]] const u32 root,
612 : [[maybe_unused]] const u64 baseOffset, [[maybe_unused]] const bool disableDMAReduce,
613 : [[maybe_unused]] const u64 reduceAttrBitMap, [[maybe_unused]] const HcomCollOpInfo* opInfo,
614 : [[maybe_unused]] const u32 userRank, [[maybe_unused]] std::vector<Stream>& subStreams,
615 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& mainSignals,
616 : [[maybe_unused]] const std::vector<std::shared_ptr<LocalNotify>>& subSignals,
617 : [[maybe_unused]] const std::vector<std::vector<u32>>& ringsOrders,
618 : [[maybe_unused]] const std::vector<std::vector<Slice>>& userMemInputSlicesOfDoubleRing)
619 : {
620 1 : return HCCL_E_PARA;
621 : }
622 :
623 : // ReduceScatterHccsSio
624 0 : HcclResult ExecutorBase::Prepare(
625 : [[maybe_unused]] DeviceMem& inputMem, [[maybe_unused]] DeviceMem& outputMem, [[maybe_unused]] DeviceMem& scratchMem,
626 : [[maybe_unused]] const u64 count, [[maybe_unused]] const HcclDataType dataType,
627 : [[maybe_unused]] const Stream& stream, [[maybe_unused]] const HcclReduceOp reductionOp,
628 : [[maybe_unused]] const u32 root, [[maybe_unused]] const u64 baseOffset, [[maybe_unused]] const u64 reduceAttrBitMap,
629 : [[maybe_unused]] std::vector<Stream>& meshStreams,
630 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignal,
631 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignalAux, [[maybe_unused]] u32 userRank,
632 : [[maybe_unused]] SubCommInfo subCommInfoHccs, [[maybe_unused]] SubCommInfo subCommInfoSio,
633 : [[maybe_unused]] HcomCollOpInfo* opInfo)
634 : {
635 0 : return HCCL_E_PARA;
636 : }
637 :
638 : // AllGatherHccsSio
639 0 : HcclResult ExecutorBase::Prepare(
640 : [[maybe_unused]] SubCommInfo& outerCommInfoHccs, [[maybe_unused]] SubCommInfo& outerCommInfoSio,
641 : [[maybe_unused]] DeviceMem& usrInMem, [[maybe_unused]] DeviceMem& usrOutMem, [[maybe_unused]] u64 totalCount,
642 : [[maybe_unused]] const HcclDataType dataType, [[maybe_unused]] const Stream& mainStream,
643 : [[maybe_unused]] std::vector<Stream>& meshStreams,
644 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignal,
645 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& meshSignalAux, [[maybe_unused]] u32 userRank,
646 : [[maybe_unused]] HcomCollOpInfo* opInfo)
647 : {
648 0 : return HCCL_E_PARA;
649 : }
650 :
651 : // ReduceScatterDeterPipeline
652 0 : HcclResult ExecutorBase::Prepare(
653 : [[maybe_unused]] HcomCollOpInfo* opInfo, [[maybe_unused]] DeviceMem& buffer, [[maybe_unused]] const u64 count,
654 : [[maybe_unused]] const u64 offset, [[maybe_unused]] const std::vector<Slice>& slices,
655 : [[maybe_unused]] const SubCommInfo& level0CommInfo, [[maybe_unused]] const SubCommInfo& level1CommInfo,
656 : [[maybe_unused]] Stream& mainStream, [[maybe_unused]] std::vector<Stream>& subStream,
657 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifyMain,
658 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifySub)
659 : {
660 0 : return HCCL_E_PARA;
661 : }
662 :
663 : // AllReduceDeterPipeline
664 0 : HcclResult ExecutorBase::Prepare(
665 : [[maybe_unused]] HcomCollOpInfo* opInfo, [[maybe_unused]] DeviceMem& inBuffer,
666 : [[maybe_unused]] DeviceMem& outBuffer, [[maybe_unused]] const u64 count,
667 : [[maybe_unused]] const std::vector<Slice>& slices, [[maybe_unused]] const SubCommInfo& level0CommInfo,
668 : [[maybe_unused]] const SubCommInfo& level1CommInfo, [[maybe_unused]] Stream& mainStream,
669 : [[maybe_unused]] std::vector<Stream>& subStream,
670 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifyMain,
671 : [[maybe_unused]] std::vector<std::shared_ptr<LocalNotify>>& notifySub)
672 : {
673 0 : return HCCL_E_PARA;
674 : }
675 :
676 146 : HcclResult ExecutorBase::RegisterProfiler(s32 planeId, s32 stage, s32 step, const Stream& stream)
677 : {
678 146 : profilerInput_.streamID = stream.id();
679 146 : profilerInput_.planeID = planeId;
680 146 : profilerInput_.stage = stage;
681 146 : profilerInput_.step = step;
682 146 : return HCCL_SUCCESS;
683 : }
684 :
685 0 : HcclResult ExecutorBase::RunAsync() { return HCCL_SUCCESS; }
686 :
687 : HcclResult
688 0 : ExecutorBase::RunAsync(const u32 rank, const u32 rankSize, const std::vector<std::shared_ptr<Transport>>& links)
689 : {
690 : (void)rank;
691 : (void)rankSize;
692 : (void)links;
693 0 : return HCCL_SUCCESS;
694 : }
695 :
696 0 : HcclResult ExecutorBase::RunAsyncStaged(
697 : const u32 rank, const u32 rankSize, const std::vector<std::shared_ptr<Transport>>& links, RunStage stage)
698 : {
699 : (void)rank;
700 : (void)rankSize;
701 : (void)links;
702 : (void)stage;
703 0 : return HCCL_SUCCESS;
704 : }
705 :
706 0 : void ExecutorBase::CalcBinaryBlockParams(
707 : u32 rank, u32 rankSize, u32& stepsInBlock, u32& lowerBlockSize, u32& myBlockSize, u32& rankInMyBlock,
708 : u32& myBlockOffset, u32& higherBlockSize)
709 : {
710 0 : u32 offset = rankSize;
711 0 : u32 blockSize = 1;
712 :
713 0 : u32 currentBlockSize = 0;
714 0 : u32 preBlockSize = 0;
715 0 : while (offset != 0) {
716 0 : if ((rankSize & blockSize) != 0) {
717 0 : preBlockSize = currentBlockSize;
718 0 : currentBlockSize = blockSize;
719 0 : if (blockSize == 0) {
720 0 : HCCL_ERROR("[Calc][BinaryBlockParams]calculate_binary_block_paras: blockSize[%u] is zero", blockSize);
721 0 : break;
722 : }
723 0 : offset -= blockSize;
724 0 : if (myBlockSize != 0) {
725 0 : higherBlockSize = currentBlockSize;
726 0 : break;
727 : }
728 0 : if (offset <= rank) {
729 0 : myBlockOffset = offset;
730 0 : myBlockSize = currentBlockSize;
731 0 : lowerBlockSize = preBlockSize;
732 : }
733 : }
734 0 : blockSize <<= 1;
735 : }
736 0 : stepsInBlock = SalLog2(myBlockSize);
737 0 : if (myBlockSize != 0) {
738 0 : rankInMyBlock = rank % myBlockSize;
739 : }
740 0 : }
741 6 : std::vector<bool> ExecutorBase::CalcLinksRelation(
742 : const u32 rank, const u32 rankSize, const u32 rootRank, HalvingDoublingType algorithmType)
743 : {
744 6 : HCCL_INFO(
745 : "Calculate links relation: Rank[%u], RankSize[%u], RootRank[%u], HDType[%d]", rank, rankSize, rootRank,
746 : algorithmType);
747 6 : std::vector<bool> linkRelation(rankSize, false);
748 :
749 : HcclResult ret;
750 6 : switch (algorithmType) {
751 6 : case HalvingDoublingType::RECURSIVE_HALVING_DOUBLING:
752 6 : CalcRecursiveHalvingDobuleLinkReleation(rank, rankSize, rootRank, linkRelation);
753 6 : break;
754 0 : case HalvingDoublingType::BINARY_BLOCK_HALVING_DOUBLING:
755 : default:
756 0 : ret = CalcBinaryBlockHalvingDoubleLinkReleation(rank, rankSize, linkRelation);
757 0 : if (ret == HCCL_E_PARA) {
758 0 : HCCL_ERROR(
759 : "[Calc][LinksRelation]errNo[0x%016llx] Calculation binary block parameter error",
760 : HCCL_ERROR_CODE(HCCL_E_PARA));
761 0 : for (u32 i = 0; i < rankSize; i++) {
762 0 : linkRelation[i] = false;
763 : }
764 0 : return linkRelation;
765 : }
766 0 : break;
767 : }
768 :
769 : // 打印建链关系
770 6 : std::string strLinkRelation;
771 6 : u32 index = 0;
772 18 : for (auto link : linkRelation) {
773 12 : if (link) {
774 6 : strLinkRelation.append(std::to_string(index));
775 : }
776 12 : if (index < linkRelation.size() - 1) {
777 6 : strLinkRelation.append(", ");
778 : }
779 12 : index++;
780 : }
781 6 : HCCL_DEBUG("Rank[%u] has link to these Ranks: %s", rank, strLinkRelation.c_str());
782 :
783 6 : return linkRelation;
784 0 : }
785 :
786 : // 将数据均分,最小单位是128
787 16 : HcclResult ExecutorBase::PrepareSliceData(
788 : u64 dataCount, u32 unitSize, u32 sliceNum, u64 piplineOffset, std::vector<Slice>& dataSlice)
789 : {
790 16 : Slice temp;
791 16 : u64 totalSize = dataCount * unitSize;
792 16 : dataSlice.clear();
793 16 : dataSlice.reserve(sliceNum);
794 16 : CHK_PRT_RET((sliceNum == 0), HCCL_ERROR("[Prepare][SliceData]data slice prepare, sliceNum is 0"), HCCL_E_PARA);
795 16 : u64 tempPerSlice = (totalSize + sliceNum - 1) / sliceNum; /* 1是为了向上取整 */
796 16 : u64 sizePerSlice = RoundUpWithDivisor(tempPerSlice, HCCL_MIN_SLICE_ALIGN);
797 16 : HCCL_DEBUG(
798 : "total_size:%llu sliceNum:%u temp_per_ring:%llu size_per_ring:%llu", totalSize, sliceNum, tempPerSlice,
799 : sizePerSlice);
800 16 : u64 residueSize = totalSize;
801 16 : u32 i = 0;
802 56 : while (residueSize > 0) {
803 40 : u64 sliceSize = sizePerSlice < residueSize ? sizePerSlice : residueSize;
804 40 : temp.size = sliceSize;
805 40 : temp.offset = totalSize - residueSize + piplineOffset;
806 40 : i++;
807 40 : CHK_PRT_RET(
808 : (sliceSize <= 0), HCCL_ERROR("[Prepare][SliceData]data_slice_prepare sliceSize[%llu]", sliceSize),
809 : HCCL_E_PARA);
810 40 : residueSize -= sliceSize;
811 40 : dataSlice.push_back(temp);
812 : }
813 16 : while (i < sliceNum) {
814 0 : temp.size = 0;
815 0 : temp.offset = totalSize + piplineOffset;
816 0 : i++;
817 0 : dataSlice.push_back(temp);
818 : }
819 16 : return HCCL_SUCCESS;
820 : }
821 :
822 : // 数据切分到每个stream上,最小单位是128
823 0 : HcclResult ExecutorBase::PrepareSliceMeshStreams(
824 : const std::vector<Slice>& rankSegsSlice, u32 streamCount, std::vector<std::vector<Slice>>& mutliStreamsSlices)
825 : {
826 0 : std::vector<u64> rankStreamSize;
827 0 : std::vector<u64> rankResidueSize;
828 0 : rankStreamSize.reserve(rankSegsSlice.size());
829 0 : rankResidueSize.reserve(rankSegsSlice.size());
830 0 : mutliStreamsSlices.clear();
831 0 : mutliStreamsSlices.reserve(streamCount);
832 0 : if (streamCount == 0) {
833 0 : HCCL_ERROR("[Prepare][SliceMeshStreams]data slice mesh prepare, streamCount is 0");
834 0 : return HCCL_E_PARA;
835 : }
836 0 : for (u32 rankId = 0; rankId < rankSegsSlice.size(); rankId++) {
837 0 : u64 rankDataSize = rankSegsSlice[rankId].size;
838 0 : u64 sizePerStream = (rankDataSize + streamCount - 1) / streamCount;
839 0 : u64 sizeAlgin = ExecutorBase::RoundUpWithDivisor(sizePerStream, HCCL_MIN_SLICE_ALIGN);
840 0 : rankStreamSize.push_back(sizeAlgin);
841 0 : rankResidueSize.push_back(rankDataSize);
842 : }
843 :
844 0 : for (u32 streamIndex = 0; streamIndex < streamCount; streamIndex++) {
845 0 : std::vector<Slice> singleStreamSlices;
846 0 : singleStreamSlices.reserve(rankSegsSlice.size());
847 0 : for (u32 rankId = 0; rankId < rankSegsSlice.size(); rankId++) {
848 0 : Slice rankSliceTemp;
849 0 : u64 rankDataResidue = rankResidueSize[rankId];
850 0 : u64 singleStreamSize = 0;
851 0 : if (rankDataResidue > 0) {
852 0 : singleStreamSize = rankStreamSize[rankId] < rankDataResidue ? rankStreamSize[rankId] : rankDataResidue;
853 0 : rankSliceTemp.offset = rankSegsSlice[rankId].offset + rankSegsSlice[rankId].size - rankDataResidue;
854 0 : rankSliceTemp.size = singleStreamSize;
855 0 : rankResidueSize[rankId] -= singleStreamSize;
856 : } else {
857 0 : rankSliceTemp.offset = rankSegsSlice[rankId].offset;
858 0 : rankSliceTemp.size = 0;
859 : }
860 0 : singleStreamSlices.push_back(rankSliceTemp);
861 : }
862 0 : mutliStreamsSlices.push_back(singleStreamSlices);
863 0 : }
864 0 : return HCCL_SUCCESS;
865 0 : }
866 :
867 : HcclResult
868 0 : ExecutorBase::CalcBinaryBlockHalvingDoubleLinkReleation(u32 rank, u32 rankSize, std::vector<bool>& linkRelation)
869 : {
870 0 : u32 stepsInBlock = 0;
871 0 : u32 myBlockSize = 0;
872 0 : u32 rankInMyBlock = INVALID_VALUE_RANKID;
873 0 : u32 myBlockOffset = 0;
874 0 : u32 higherBlockSize = 0;
875 0 : u32 lowerBlockSize = 0;
876 0 : CalcBinaryBlockParams(
877 : rank, rankSize, stepsInBlock, lowerBlockSize, myBlockSize, rankInMyBlock, myBlockOffset, higherBlockSize);
878 0 : if (lowerBlockSize == 0) {
879 0 : HCCL_ERROR("[Calc][BinaryBlockHalvingDoubleLinkReleation]lowerBlockSize size is zero.");
880 0 : return HCCL_E_PARA;
881 : }
882 0 : for (u32 i = 0; i < rankSize; i++) {
883 0 : linkRelation[i] = false;
884 : }
885 0 : u32 dstRankBitmask = 1;
886 0 : for (u32 i = 0; i < stepsInBlock; i++) {
887 0 : u32 dstRankBitmaskTemp = dstRankBitmask;
888 0 : u32 dstRank = rank ^ dstRankBitmaskTemp;
889 0 : linkRelation[dstRank] = true;
890 0 : dstRankBitmask <<= 1;
891 : }
892 0 : if (lowerBlockSize != 0) {
893 0 : u32 divBlockSize = myBlockSize / lowerBlockSize;
894 0 : u32 dstRank = myBlockOffset + myBlockSize + rankInMyBlock / divBlockSize;
895 0 : linkRelation[dstRank] = true;
896 : }
897 0 : if (higherBlockSize != 0) {
898 0 : u32 segments = higherBlockSize / myBlockSize; // 和高阶block的rank数差n倍,那么本rank就要向高阶的n个rank发送
899 0 : u32 dstRank = (myBlockOffset - higherBlockSize) + rankInMyBlock * segments;
900 0 : for (u32 i = 0; i < segments; i++) {
901 0 : linkRelation[dstRank] = true;
902 0 : dstRank++;
903 : }
904 : }
905 0 : return HCCL_SUCCESS;
906 : }
907 :
908 : // 用于recursive halving doubling
909 6 : void ExecutorBase::CalcLinkInBlock(u32 blockSize, u32 rankInBlock, std::list<u32>& linkRankIndexInBlock)
910 : {
911 6 : u32 blockSizeHalving = blockSize / 2; // 每个循环除2计算当前block的折半rank数
912 6 : u32 rankInTempBlock = rankInBlock;
913 12 : while (blockSizeHalving >= 1) {
914 6 : if (rankInTempBlock < blockSizeHalving) {
915 6 : linkRankIndexInBlock.push_back(rankInBlock + blockSizeHalving);
916 : } else {
917 0 : linkRankIndexInBlock.push_back(rankInBlock - blockSizeHalving);
918 0 : rankInTempBlock -= blockSizeHalving;
919 : }
920 6 : blockSizeHalving = blockSizeHalving / 2; // 每个循环除2计算当前block的折半rank数
921 : }
922 6 : }
923 :
924 : // 用于recursive halving doubling
925 6 : void ExecutorBase::CalcLinkBetweenParts(
926 : u32 part1Size, std::list<u32>& linkRankIndexInBlock, std::list<u32>& linkRankIndex, bool oddRank)
927 : {
928 12 : for (auto it : linkRankIndexInBlock) {
929 6 : if (it < (part1Size / 2)) { // 属于part1,除2计算part1中的rank范围
930 0 : if (oddRank) {
931 0 : linkRankIndex.push_back(it * 2 + 1); // 乘2加1得到part1中奇数rank
932 : } else {
933 0 : linkRankIndex.push_back(it * 2); // 乘2得到part1中偶数rank
934 : }
935 : } else {
936 6 : linkRankIndex.push_back(part1Size / 2 + it); // 不属于part1,除2得到part1中rank范围
937 : }
938 : }
939 6 : }
940 :
941 : // 用于recursive halving doubling
942 6 : void ExecutorBase::CalcRecursiveHalvingDobuleLinkReleation(
943 : u32 rank, u32 rankSize, u32 rootRank, std::vector<bool>& linkRelation)
944 : {
945 6 : u32 exponent = 0;
946 :
947 6 : if (rootRank == INVALID_VALUE_RANKID) { // all reduce 走这个分支
948 6 : rootRank = 0;
949 : }
950 :
951 6 : u32 base = 1;
952 18 : while ((base << exponent) <= rankSize) {
953 12 : exponent++;
954 : }
955 6 : if (exponent > 0) {
956 6 : exponent--;
957 : }
958 6 : u32 blockSize = base << exponent;
959 6 : u32 part1Size = (rankSize - blockSize) * 2; // part1的大小为总rankSize减去blockSize再乘2
960 :
961 : // 情况1、情况3的建链方式
962 6 : if (rootRank >= part1Size || rootRank % 2 == 0) { // 除2判断是否为偶数
963 6 : CalcRecursiveHdLinkRelationForFirstScene(rank, part1Size, blockSize, linkRelation);
964 : } else { // 情况2的建链方式,rootRank<part1Size && 1==rootRank%2
965 0 : CalcRecursiveHdLinkRelationForSecondScene(rank, part1Size, blockSize, linkRelation);
966 : }
967 6 : }
968 :
969 6 : void ExecutorBase::CalcRecursiveHdLinkRelationForFirstScene(
970 : u32 rank, u32 part1Size, u32 blockSize, std::vector<bool>& linkRelation)
971 : {
972 6 : if (rank < part1Size && rank % 2 == 0) { // 除2判断是否为偶数
973 0 : std::list<u32> linkRankIndex;
974 0 : std::list<u32> linkRankIndexInBlock;
975 0 : u32 rankInBlock = rank / 2; // 除2计算block内的rank号
976 0 : CalcLinkInBlock(blockSize, rankInBlock, linkRankIndexInBlock);
977 0 : CalcLinkBetweenParts(part1Size, linkRankIndexInBlock, linkRankIndex, false);
978 0 : linkRankIndex.push_back(rank + 1); // 加1得到旁边的那个rank
979 0 : for (auto it : linkRankIndex) {
980 0 : linkRelation[it] = true;
981 : }
982 6 : } else if (rank < part1Size && rank % 2 == 1) { // 除2判断是否为奇数
983 0 : if ((rank > 0) && (rank - 1 < linkRelation.size())) {
984 0 : linkRelation[rank - 1] = true; // 只有旁边的那个rank
985 : }
986 : } else { // rank大于等于part1Size
987 6 : std::list<u32> linkRankIndexInBlock;
988 6 : u32 rankInBlock = rank - part1Size / 2; // 除2计算part1在block内的rank范围
989 6 : std::list<u32> linkRankIndex;
990 6 : CalcLinkInBlock(blockSize, rankInBlock, linkRankIndexInBlock);
991 6 : CalcLinkBetweenParts(part1Size, linkRankIndexInBlock, linkRankIndex, false);
992 12 : for (auto it : linkRankIndex) {
993 6 : linkRelation[it] = true;
994 : }
995 6 : }
996 6 : }
997 :
998 0 : void ExecutorBase::CalcRecursiveHdLinkRelationForSecondScene(
999 : u32 rank, u32 part1Size, u32 blockSize, std::vector<bool>& linkRelation)
1000 : {
1001 0 : if (rank < part1Size && rank % 2 == 1) { // 除2判断是否为奇数
1002 0 : std::list<u32> linkRankIndex;
1003 0 : std::list<u32> linkRankIndexInBlock;
1004 0 : u32 rankInBlock = (rank - 1) / 2; // 减1再除2计算在block内的rank
1005 0 : CalcLinkInBlock(blockSize, rankInBlock, linkRankIndexInBlock);
1006 0 : CalcLinkBetweenParts(part1Size, linkRankIndexInBlock, linkRankIndex, true);
1007 0 : linkRankIndex.push_back(rank - 1); // 减1得到旁边的那个rank
1008 0 : for (auto it : linkRankIndex) {
1009 0 : linkRelation[it] = true;
1010 : }
1011 0 : } else if (rank < part1Size && rank % 2 == 0) { // 除2判断是否为偶数
1012 0 : if (rank + 1 < linkRelation.size()) {
1013 0 : linkRelation[rank + 1] = true; // 只有旁边的那个rank
1014 : }
1015 : } else { // rank大于等于part1Size
1016 0 : std::list<u32> linkRankIndexInBlock;
1017 0 : u32 rankInBlock = rank - part1Size / 2; // 除2计算part1在block内的rank范围
1018 0 : std::list<u32> linkRankIndex;
1019 0 : CalcLinkInBlock(blockSize, rankInBlock, linkRankIndexInBlock);
1020 0 : CalcLinkBetweenParts(part1Size, linkRankIndexInBlock, linkRankIndex, true);
1021 0 : for (auto it : linkRankIndex) {
1022 0 : linkRelation[it] = true;
1023 : }
1024 0 : }
1025 0 : }
1026 :
1027 : HcclResult
1028 0 : ExecutorBase::ExecuteBarrier(const std::shared_ptr<Transport>& preLink, const std::shared_ptr<Transport>& aftLink)
1029 : {
1030 0 : return ExecuteBarrier(preLink, aftLink, stream_);
1031 : }
1032 :
1033 0 : HcclResult ExecutorBase::ExecuteBarrier(
1034 : const std::shared_ptr<Transport>& preLink, const std::shared_ptr<Transport>& aftLink, Stream& stream)
1035 : {
1036 : // 同步与preLink保证数据收发已结束
1037 0 : CHK_RET(preLink->TxAck(stream));
1038 :
1039 0 : CHK_RET(aftLink->RxAck(stream));
1040 :
1041 : // 同步与aftLink保证数据收发已结束
1042 0 : CHK_RET(aftLink->TxDataSignal(stream));
1043 :
1044 0 : CHK_RET(preLink->RxDataSignal(stream));
1045 :
1046 0 : return HCCL_SUCCESS;
1047 : }
1048 :
1049 0 : HcclResult ExecutorBase::ExecuteBarrier(std::shared_ptr<Transport> link, Stream& stream)
1050 : {
1051 0 : CHK_RET(link->TxAck(stream));
1052 :
1053 0 : CHK_RET(link->RxAck(stream));
1054 :
1055 0 : CHK_RET(link->TxDataSignal(stream));
1056 :
1057 0 : CHK_RET(link->RxDataSignal(stream));
1058 :
1059 0 : return HCCL_SUCCESS;
1060 : }
1061 :
1062 0 : HcclResult ExecutorBase::ExecuteBarrier(
1063 : const std::shared_ptr<Transport>& preLink, const std::shared_ptr<Transport>& aftLink, u32 notifyIdx)
1064 : {
1065 0 : return ExecuteBarrier(preLink, aftLink, notifyIdx, stream_);
1066 : }
1067 :
1068 0 : HcclResult ExecutorBase::ExecuteBarrier(
1069 : const std::shared_ptr<Transport>& preLink, const std::shared_ptr<Transport>& aftLink, u32 notifyIdx, Stream& stream)
1070 : {
1071 : // 同步与aftLink保证数据收发已结束
1072 0 : CHK_RET(aftLink->Post(notifyIdx, stream));
1073 :
1074 0 : CHK_RET(preLink->Wait(notifyIdx, stream));
1075 :
1076 0 : return HCCL_SUCCESS;
1077 : }
1078 :
1079 0 : HcclResult ExecutorBase::Sum(const std::vector<Slice>& inputSlices, u32 start, u32 num, u64& sizeOut)
1080 : {
1081 0 : u64 totalSize = 0;
1082 : // 判断不是<=因为访问vector前会先进行num--
1083 0 : CHK_PRT_RET(
1084 : inputSlices.size() < start + num,
1085 : HCCL_ERROR(
1086 : "[ExecutorBase][Sum]recursive Halving Doubling sum "
1087 : "error.para: size[%llu], start[%u], num[%u]",
1088 : inputSlices.size(), start, num),
1089 : HCCL_E_PARA);
1090 0 : while (num > 0) {
1091 0 : num--;
1092 0 : totalSize += inputSlices[start + num].size;
1093 : }
1094 0 : sizeOut = totalSize;
1095 0 : return HCCL_SUCCESS;
1096 : }
1097 0 : HcclResult ExecutorBase::ExecuteRxSync(
1098 : std::shared_ptr<Transport> link, UserMemType srcMemType, u64 srcOffset, void* dst, u64 len, Stream& stream) const
1099 : {
1100 0 : HcclResult ret = link->TxAsync(srcMemType, srcOffset, dst, 0, stream);
1101 0 : CHK_PRT_RET(
1102 : ret != HCCL_SUCCESS,
1103 : HCCL_ERROR(
1104 : "[ExecutorBase][ExecuteRxSync]ExecuteRxSync: tx async size[%llu] "
1105 : "failed",
1106 : len),
1107 : ret);
1108 0 : ret = link->RxAsync(srcMemType, srcOffset, dst, len, stream);
1109 0 : CHK_PRT_RET(
1110 : ret != HCCL_SUCCESS,
1111 : HCCL_ERROR(
1112 : "[ExecutorBase][ExecuteRxSync]ExecuteRxSync: rx async with rcvMem[%p] "
1113 : "offset[%llu] size[%llu] failed",
1114 : dst, srcOffset, len),
1115 : ret);
1116 0 : ret = link->DataReceivedAck(stream);
1117 0 : CHK_PRT_RET(
1118 : ret != HCCL_SUCCESS, HCCL_ERROR("[ExecutorBase][ExecuteRxSync]ExecuteRxSync: data received ack failed"), ret);
1119 0 : return HCCL_SUCCESS;
1120 : }
1121 0 : HcclResult ExecutorBase::ExecuteTxSync(
1122 : std::shared_ptr<Transport> link, UserMemType dstMemType, u64 dstOffset, void* src, u64 len, Stream& stream) const
1123 : {
1124 0 : HcclResult ret = link->TxAsync(dstMemType, dstOffset, src, len, stream);
1125 0 : CHK_PRT_RET(
1126 : ret != HCCL_SUCCESS,
1127 : HCCL_ERROR(
1128 : "[ExecutorBase][ExecuteTxSync]ExecuteTxSync: tx async sendMem[%p] "
1129 : "offset[%llu] size[%llu] failed",
1130 : src, dstOffset, len),
1131 : ret);
1132 : // 接收应答
1133 0 : ret = link->RxAsync(dstMemType, dstOffset, src, 0, stream);
1134 0 : CHK_PRT_RET(
1135 : ret != HCCL_SUCCESS,
1136 : HCCL_ERROR(
1137 : "[ExecutorBase][ExecuteTxSync]ExecuteTxSync: rx async size[%llu] "
1138 : "failed",
1139 : len),
1140 : ret);
1141 0 : ret = link->DataReceivedAck(stream);
1142 0 : CHK_PRT_RET(
1143 : ret != HCCL_SUCCESS, HCCL_ERROR("[ExecutorBase][ExecuteTxSync]ExecuteTxSync: data received ack failed"), ret);
1144 0 : return HCCL_SUCCESS;
1145 : }
1146 :
1147 : HcclResult
1148 0 : ExecutorBase::PrepareRunAsync(const u32 rank, const u32 rankSize, const std::vector<std::shared_ptr<Transport>>& links)
1149 : {
1150 : (void)rank;
1151 : (void)rankSize;
1152 : (void)links;
1153 0 : return HCCL_SUCCESS;
1154 : }
1155 :
1156 : HcclResult
1157 42 : ExecutorBase::ExecEmptyTask(DeviceMem& inputMem, DeviceMem& outputMem, Stream& stream, const HcclDispatcher dispatcher)
1158 : {
1159 42 : DeviceMem emptySrcMem = DeviceMem::create(inputMem.ptr(), 0);
1160 42 : DeviceMem emptyDstMem = DeviceMem::create(outputMem.ptr(), 0);
1161 42 : CHK_RET(HcclD2DMemcpyAsync(dispatcher, emptyDstMem, emptySrcMem, stream));
1162 42 : return HCCL_SUCCESS;
1163 42 : }
1164 :
1165 : HcclResult
1166 0 : ExecutorBase::CheckConcurrentDirectParameters(const u32 rank, const u32 rankSize, const std::vector<LINK>& links)
1167 : {
1168 : // 判断stream, dispatcher是否为空
1169 0 : CHK_SMART_PTR_NULL(dispatcher_);
1170 0 : CHK_PTR_NULL(stream_.ptr());
1171 :
1172 : // inputMem_ == outputMem_ 是允许的, 因为ring的时候收的slice和发的slice不是同一片
1173 : // reduce scatter用inputMem_,allgather用outputMem_
1174 0 : if (!outputMem_ || !inputMem_) {
1175 0 : HCCL_ERROR("[ExecutorBase] rank[%u] run_async inputmem or outputmem is null", rank);
1176 0 : return HCCL_E_PTR;
1177 : }
1178 0 : HCCL_INFO(
1179 : "ExecutorBase run: rank[%u] ranksize[%u] inputMem[%p] outputMem[%p] count[%llu]", rank, rankSize,
1180 : inputMem_.ptr(), outputMem_.ptr(), count_);
1181 :
1182 : // 判断links数量是否正确
1183 0 : CHK_PRT_RET(
1184 : links.size() < rankSize,
1185 : HCCL_ERROR(
1186 : "[ExecutorBase] rank[%u] link size[%u] is less than "
1187 : "rank size[%u]",
1188 : rank, links.size(), rankSize),
1189 : HCCL_E_PARA);
1190 :
1191 : // 校验DataUnitSize
1192 0 : if (DataUnitSize(dataType_) == 0) {
1193 0 : HCCL_ERROR("[ExecutorBase] rank[%u] unit data size is zero", rank);
1194 0 : return HCCL_E_INTERNAL;
1195 : }
1196 :
1197 0 : HCCL_INFO("ExecutorBase finished to CheckParameters");
1198 0 : return HCCL_SUCCESS;
1199 : }
1200 :
1201 0 : HcclResult ExecutorBase::GetNslbAdjInfo(
1202 : const u32 rank, const u32 rankSize, [[maybe_unused]] const std::vector<LINK>& links, AdjInfo& nslbAdjInfo)
1203 : {
1204 : (void)rank;
1205 : (void)rankSize;
1206 : (void)nslbAdjInfo;
1207 0 : return HCCL_SUCCESS;
1208 : }
1209 :
1210 : HcclResult
1211 0 : ExecutorBase::GetHcclOffsetDstRanksMap(std::unordered_map<uint64_t, std::vector<uint32_t>>& hcclOffsetDstRanksMap) const
1212 : {
1213 : UNUSED_PARAM(hcclOffsetDstRanksMap);
1214 0 : HCCL_ERROR("[ExecutorBase][GetHcclOffsetDstRanksMap] not supported for current template!");
1215 0 : return HCCL_E_NOT_SUPPORT;
1216 : }
1217 :
1218 : } // namespace hccl
|