已合并
将 BIRS 批量不变性扩展至 AllReduce(AllReduceBIAR) #2348
Davydov_Danil创建于 7月28日
将 BIRS 批量不变性扩展至 AllReduce(AllReduceBIAR) #2348
已合并
Davydov_Danil创建于 7月28日
共 37 个文件变更+2939-226
@@ -13,9 +13,9 @@ if(NOT ENABLE_EXPERIMENTAL)
13endif()13endif()
14 14 
15add_subdirectory(op_common)15add_subdirectory(op_common)
16+add_subdirectory(all_reduce)
16add_subdirectory(reduce_scatter)17add_subdirectory(reduce_scatter)
17add_subdirectory(reduce_scatter_v)18add_subdirectory(reduce_scatter_v)
18-add_subdirectory(all_reduce/example)
19 19 
20set(EXPERIMENTAL_INCLUDE_LIST20set(EXPERIMENTAL_INCLUDE_LIST
21 ${CMAKE_CURRENT_SOURCE_DIR}/../21 ${CMAKE_CURRENT_SOURCE_DIR}/../
@@ -23,18 +23,20 @@ set(EXPERIMENTAL_INCLUDE_LIST
23 ${CMAKE_CURRENT_SOURCE_DIR}/op_common/23 ${CMAKE_CURRENT_SOURCE_DIR}/op_common/
24 ${CMAKE_CURRENT_SOURCE_DIR}/op_common/template24 ${CMAKE_CURRENT_SOURCE_DIR}/op_common/template
25 ${CMAKE_CURRENT_SOURCE_DIR}/op_common/topo25 ${CMAKE_CURRENT_SOURCE_DIR}/op_common/topo
26+ ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/
27+ ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/biar/
28+ ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/biar/template/
29+ ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/example/
30+ ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/example/template/
31+ ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/example/template/ccu/
32+ ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/example/template/ccu/kernel/
33+ ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/example/executor/
26 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter/34 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter/
27 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter/birs/35 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter/birs/
28 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter/birs/template/36 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter/birs/template/
29 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter_v/37 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter_v/
30 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter_v/birs/38 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter_v/birs/
31 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter_v/birs/template/39 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter_v/birs/template/
32- ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/
33- ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/example/
34- ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/example/template/
35- ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/example/template/ccu/
36- ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/example/template/ccu/kernel/
37- ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/example/executor/
38)40)
39 41 
40if(TARGET scatter_aicpu_kernel)42if(TARGET scatter_aicpu_kernel)
@@ -43,6 +45,10 @@ if(TARGET scatter_aicpu_kernel)
43 target_sources(scatter_aicpu_kernel PRIVATE45 target_sources(scatter_aicpu_kernel PRIVATE
44 ${CMAKE_CURRENT_SOURCE_DIR}/op_common/template/alg_template_base_experimental.cc46 ${CMAKE_CURRENT_SOURCE_DIR}/op_common/template/alg_template_base_experimental.cc
45 ${CMAKE_CURRENT_SOURCE_DIR}/op_common/topo/topo_experimental.cc47 ${CMAKE_CURRENT_SOURCE_DIR}/op_common/topo/topo_experimental.cc
48+ ${CMAKE_CURRENT_SOURCE_DIR}/op_common/coll_executor_base_experimental.cc
49+ ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/biar/all_reduce_biar_executor.cc
50+ ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/biar/all_reduce_executor_base.cc
51+ ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce/biar/template/all_reduce_biar.cc
46 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter/birs/reduce_scatter_birs_executor.cc52 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter/birs/reduce_scatter_birs_executor.cc
47 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter/birs/reduce_scatter_executor_base.cc53 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter/birs/reduce_scatter_executor_base.cc
48 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter/birs/template/reduce_scatter_birs.cc54 ${CMAKE_CURRENT_SOURCE_DIR}/reduce_scatter/birs/template/reduce_scatter_birs.cc
@@ -0,0 +1,26 @@
1+# -----------------------------------------------------------------------------------------------------------
2+# Copyright (c) 2026 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+if(NOT ENABLE_EXPERIMENTAL)
12+ return()
13+endif()
14+ 
15+add_subdirectory(biar)
W
Wwenxuemin9月20日

⚠️ [中等] [构建] experimental/ops/all_reduce/CMakeLists.txt:15

本文件只 add_subdirectory(biar),遗漏了 add_subdirectory(example);而 experimental/ops/CMakeLists.txt 已将原 add_subdirectory(all_reduce/example) 改为 add_subdirectory(all_reduce)。结果 all_reduce/example(ins_v2_all_reduce_experimental_sole_executor)被移出构建,但其 include 路径仍残留在 EXPERIMENTAL_INCLUDE_LIST。

建议:确认 example 是否仍需编译;若需要,在此补 add_subdirectory(example);若为有意清理,同步移除 include 路径残留。

likedislike
Davydov_Danil
9月21日 评论:
Davydov_Danil
9月22日 评论:
16+add_subdirectory(example)
17+ 
18+set(src_list
19+ ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce_op_experimental.cc
20+)
21+ 
22+if(TARGET hccl)
23+ target_sources(hccl PRIVATE
24+ ${src_list}
25+ )
26+endif()
@@ -0,0 +1,157 @@
1+/**
2+ * Copyright (c) 2026 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_reduce_op_experimental.h"
12+#include "reduce_scatter_op_experimental.h"
13+#include "topo_host.h"
14+#include <algorithm>
15+#include <future>
16+#include <map>
17+#include <string>
18+#include "op_common_experimental.h"
19+#include "param_check.h"
20+#include "all_reduce.h"
21+#include "load_kernel.h"
22+#include "hcomm_dlsym.h"
23+#include "hcomm_host_profiling_dl.h"
24+ 
25+using namespace std;
26+ 
27+extern "C" HcclResult HcclAllReduceInner(
28+ void* sendBuf, void* recvBuf, uint64_t count, HcclDataType dataType, HcclReduceOp op, HcclComm comm,
29+ aclrtStream stream);
30+ 
31+namespace ops_hccl_experimental {
32+using ops_hccl::AllReduceEntryLog;
33+using ops_hccl::DATATYPE_SIZE_TABLE;
34+using ops_hccl::HcclNetLayer;
35+using ops_hccl::LoadAICPUKernel;
36+using ops_hccl::LogHcclExit;
37+using ops_hccl::OpMode;
38+ 
39+static bool MatchBIAR(HcclComm comm)
40+{
41+ if (!MatchBIRS()) {
严正行
严正行严正行23 天前

[LOW] HCCL_BIRS_ENABLE 语义扩展至 AllReduce 未同步文档

问题分析:

  • 第 44 行:if (!MatchBIRS()) {

MatchBIAR 复用 MatchBIRS(即 HCCL_BIRS_ENABLE 环境变量),使该环境变量的行为契约从 RFC 0001 文档所写的「ReduceScatter calls are routed to the BIRS implementation」静默扩展为同时路由 AllReduce;本 PR 描述的 Documentation Update 一节为空,docs/zh 与 docs/en 的 RFC 0001 环境变量表均未更新。实验特性阶段,用户按文档排障时会误以为该变量只影响 ReduceScatter。

建议修复:在 RFC 0001 环境变量表(中英文两份)补充 AllReduce BIAR 的路由说明与适用条件(910_93、偶数 rank、每 server 不少于 4 rank),或在 PR 描述 Documentation Update 中列出后续文档更新计划。

likedislike
严正行
严正行
21 天前 评论:
42+ return false;
43+ }
44+ u32 rankSize = INVALID_VALUE_RANKSIZE;
45+ if (HcclGetRankSize(comm, &rankSize) != HCCL_SUCCESS) {
46+ return false;
47+ }
48+ HcclDevType deviceType = HcclDevType::DEV_TYPE_COUNT;
49+ if (HcclGetDeviceType(deviceType) != HCCL_SUCCESS) {
50+ return false;
51+ }
52+ uint32_t* instSizeList = nullptr;
53+ uint32_t serverNum = 0;
54+ if (HcclRankGraphGetInstSizeListByLayer(
55+ comm, static_cast<uint32_t>(HcclNetLayer::HCCL_NetLayer_L0), &instSizeList, &serverNum)
56+ != HCCL_SUCCESS) {
57+ return false;
58+ }
59+ // 不适用条件统一回退老路径, 须与 DecideAllReduceBiarAlg 的拒绝条件保持一致(selector 仅作兜底),
60+ // 避免奇数规模静默回退而小规模偶数硬报错的分裂处置
61+ if (rankSize == 1 || deviceType != HcclDevType::DEV_TYPE_910_93 || rankSize % 2 != 0 || serverNum == 0
62+ || rankSize / serverNum < 4) {
63+ HCCL_INFO(
64+ "AllReduceBIAR not applicable: deviceType[%d] rankSize[%u] serverNum[%u], fallback to the default "
65+ "AllReduce",
66+ deviceType, rankSize, serverNum);
67+ return false;
68+ }
69+ return true;
70+}
71+ 
72+HcclResult AllReduceExperimental(
73+ void* sendBuf, void* recvBuf, uint64_t count, HcclDataType dataType, HcclReduceOp op, HcclComm comm,
74+ aclrtStream stream)
75+{
76+ if (!MatchBIAR(comm)) {
77+ return HcclAllReduceInner(sendBuf, recvBuf, count, dataType, op, comm, stream);
78+ }
79+ 
80+ CHK_PRT_RET(count == 0, HCCL_WARNING("input count is 0, return all reduce success"), HCCL_SUCCESS);
81+ 
82+ HcclUs startut = TIME_NOW(); // 走老流程的判断时间不统计在内
83+ OpParam param;
84+ CHK_RET(AllReduceInitAndCheck(comm, sendBuf, recvBuf, count, dataType, op, stream, param));
85+ 
86+ u32 rankSize = INVALID_VALUE_RANKSIZE;
87+ CHK_RET(HcclGetRankSize(comm, &rankSize));
严正行
严正行严正行23 天前

[MEDIUM] 第 78-89 行与 AllReduceInitAndCheck 的校验序列完全重复

问题分析:

  • 第 79 行:CHK_RET(HcclGetRankSize(comm, &rankSize));

第 76 行已调用 AllReduceInitAndCheck(src/ops/all_reduce/all_reduce.cc 第 111-138 行),其内部已完成 InitEnvConfig、CheckAllReduceInputPara、HcclGetRankSize、HcclGetRankId、HcclGetCommName、tag 填充与 HcclCheckTag、HcomCheckUserRank、CheckCount、CheckDataType、CheckReduceOp;本函数 78-89 行又把其中 8 项原样重做一遍。每次走 BIAR 路径的 AllReduce 都多执行一轮 dlsym 跨界查询与校验(集合通信热路径),且两处逻辑需双份同步维护——未来 tag/校验规则变化容易漏改其中一处。对照 ReduceScatterExperimental 只做一遍内联校验,无此重复。

建议修复:删除 78-89 行的重复块,仅保留 rankSize 的单次获取(供第 94 行 AllReduceOutPlaceCustom 使用),AllReduceEntryLog 直接复用 InitAndCheck 已填好的 param.tag 与 param.commName。

likedislike
Davydov_Danil
21 天前 评论:
严正行
严正行
21 天前 评论:
88+ 
89+ /* 接口交互信息日志 */
90+ CHK_RET(AllReduceEntryLog(sendBuf, recvBuf, count, dataType, op, stream, param.tag, "HcclAllReduce"));
91+ 
92+ CHK_RET(AllReduceOutPlaceCustom(param, sendBuf, recvBuf, count, dataType, op, comm, stream, rankSize));
93+ 
94+ CHK_RET(LogHcclExit("HcclAllReduce", param.tag, startut));
95+ 
96+ return HCCL_SUCCESS;
97+}
98+ 
99+static HcclResult PrepareAllReduceParam(
100+ OpParam& param, void* sendBuf, void* recvBuf, uint64_t count, HcclDataType dataType, HcclReduceOp op, HcclComm comm,
101+ aclrtStream stream, OpMode opMode)
102+{
103+ u32 perDataSize = DATATYPE_SIZE_TABLE[dataType];
104+ u64 outputSize = count * perDataSize;
105+ u64 inputSize = outputSize;
106+ 
107+ param.stream = stream;
108+ param.reduceType = op;
109+ param.opMode = opMode;
110+ 
111+ if (param.commName[0] == '\0') {
112+ CHK_RET(HcclGetCommName(comm, param.commName));
113+ }
114+ HcclDevType deviceType = HcclDevType::DEV_TYPE_COUNT;
115+ CHK_RET(HcclGetDeviceType(deviceType));
116+ 
117+ param.inputSize = inputSize;
118+ param.inputPtr = sendBuf;
119+ param.outputSize = outputSize;
120+ param.outputPtr = recvBuf;
121+ param.DataDes.dataType = dataType;
122+ param.DataDes.count = count;
123+ param.enableDetour = false;
124+ param.opType = HcclCMDType::HCCL_CMD_ALLREDUCE;
125+ param.deviceType = deviceType;
126+ 
127+ return HCCL_SUCCESS;
128+}
129+ 
130+HcclResult AllReduceOutPlaceCustom(
131+ OpParam& param, void* sendBuf, void* recvBuf, uint64_t count, HcclDataType dataType, HcclReduceOp op, HcclComm comm,
132+ aclrtStream stream, u32 userRankSize)
133+{
134+ HCCL_INFO("Start to execute AllReduceOutPlaceCustom");
135+ CHK_RET(PrepareAllReduceParam(param, sendBuf, recvBuf, count, dataType, op, comm, stream, OpMode::OPBASE));
136+ 
137+ if (IsAiCpuMode(param.deviceType, userRankSize)) {
138+ HCCL_DEBUG("is aicpu mode");
139+ CHK_RET(LoadAICPUKernel());
140+ param.engine = CommEngine::COMM_ENGINE_AICPU_TS;
141+ } else {
142+ HCCL_DEBUG("is host mode");
143+ param.engine = CommEngine::COMM_ENGINE_CPU_TS;
144+ }
145+ 
146+ uint64_t beginTime = 0;
147+ if (HcommIsProfilingSupported()) {
148+ beginTime = HcommGetProfilingSysCycleTime();
149+ }
150+ 
151+ CHK_RET(ProcessA3(comm, param, beginTime));
152+ 
153+ HCCL_INFO("Execute AllReduceOutPlaceCustom success.");
154+ return HCCL_SUCCESS;
155+}
156+ 
157+} // namespace ops_hccl_experimental
@@ -0,0 +1,42 @@
1+/**
2+ * Copyright (c) 2026 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+#ifndef OPS_HCCL_SRC_OPS_ALL_REDUCE_OP_CUSTOM
12+#define OPS_HCCL_SRC_OPS_ALL_REDUCE_OP_CUSTOM
13+ 
14+#include <string>
15+#include <memory>
16+#include "hccl.h"
17+ 
18+#include "alg_param.h"
19+#include "executor_v2_base.h"
20+#include "alg_type.h"
21+#include "execute_selector.h"
22+ 
23+#ifdef __cplusplus
24+extern "C" {
25+#endif
26+ 
27+#ifdef __cplusplus
28+}
29+#endif
30+ 
31+namespace ops_hccl_experimental {
32+using ops_hccl::OpParam;
33+ 
34+HcclResult AllReduceExperimental(
35+ void* sendBuf, void* recvBuf, uint64_t count, HcclDataType dataType, HcclReduceOp op, HcclComm comm,
36+ aclrtStream stream);
37+HcclResult AllReduceOutPlaceCustom(
38+ OpParam& param, void* sendBuf, void* recvBuf, uint64_t count, HcclDataType dataType, HcclReduceOp op, HcclComm comm,
39+ aclrtStream stream, u32 userRankSize);
40+} // namespace ops_hccl_experimental
41+ 
42+#endif
@@ -0,0 +1,27 @@
1+# -----------------------------------------------------------------------------------------------------------
2+# Copyright (c) 2026 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+if(NOT ENABLE_EXPERIMENTAL)
12+ return()
13+endif()
14+ 
15+add_subdirectory(template)
16+ 
17+set(src_list
18+ ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce_executor_base.cc
19+ ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce_biar_executor.cc
20+ ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce_biar_selector.cc
21+)
22+ 
23+if(TARGET hccl)
24+ target_sources(hccl PRIVATE
25+ ${src_list}
26+ )
27+endif()
@@ -0,0 +1,110 @@
1+/**
2+ * Copyright (c) 2026 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 <numeric>
12+#include "all_reduce_biar_executor.h"
13+#include "all_reduce_biar.h"
14+#include "topo_experimental.h"
15+ 
16+namespace ops_hccl_experimental {
17+ 
18+AllReduceBIARExecutor::AllReduceBIARExecutor() : AllReduceExecutorBase()
19+{
20+ desc_.level1SupportedAlgos
21+ = {AlgTypeLevel1::ALG_LEVEL1_NHR, AlgTypeLevel1::ALG_LEVEL1_NB, AlgTypeLevel1::ALG_LEVEL1_RING};
22+ desc_.level2SupportedAlgos
23+ = {AlgTypeLevel2::ALG_LEVEL2_NHR, AlgTypeLevel2::ALG_LEVEL2_NB, AlgTypeLevel2::ALG_LEVEL2_RING};
24+}
25+ 
26+HcclResult AllReduceBIARExecutor::CalcResRequest(
27+ HcclComm comm, const OpParam& param, TopoInfo* topoInfo, AlgHierarchyInfo& algHierarchyInfo,
28+ AlgResourceRequest& resourceRequest, AlgType& algType)
29+{
30+ if (topoInfo->serverNum == 1) {
31+ CHK_RET(CalcGeneralTopoInfoForA3(comm, topoInfo, algHierarchyInfo));
32+ } else {
33+ CHK_RET(CalcGeneralTopoInfoInterServer(comm, topoInfo, algHierarchyInfo));
34+ }
35+ CHK_RET(RefreshAlgType(algType));
36+ algType.algoLevel0 = AlgTypeLevel0::ALG_LEVEL0_NP_MESH;
37+ 
38+ resourceRequest.slaveThreadNum = BIAR_THREAD_NUM;
39+ for (u32 index = 0; index < BIAR_THREAD_NUM; index++) {
40+ resourceRequest.notifyNumPerThread.push_back(1);
41+ }
42+ resourceRequest.notifyNumOnMainThread = BIAR_THREAD_NUM;
43+ 
44+ // level0 channel
45+ std::vector<HcclChannelDesc> level0Channels;
46+ CHK_RET(CalcLevel0ChannelRequest(param, topoInfo, algHierarchyInfo, algType, level0Channels));
47+ resourceRequest.channels.push_back(level0Channels);
48+ 
49+ HCCL_INFO(
50+ "[AllReduceBIARExecutor][CalcResRequest]slaveThreadNum[%u] notifyNumPerThread[%zu]"
51+ " notifyNumOnMainThread[%u] level0Channels[%zu]",
52+ resourceRequest.slaveThreadNum, resourceRequest.notifyNumPerThread.size(),
53+ resourceRequest.notifyNumOnMainThread, level0Channels.size());
54+ return HCCL_SUCCESS;
55+}
56+ 
57+HcclResult AllReduceBIARExecutor::KernelRun(const OpParam& param, ExecMem& execMem)
58+{
59+ HCCL_CONFIG_INFO(HCCL_ALG, "[AllReduceBIARExecutor][KernelRun] starts.");
60+ 
61+ CHK_RET(KernelRunLevel0(param, execMem));
62+ 
63+ HCCL_INFO("AllReduce BIAR run success");
64+ return HCCL_SUCCESS;
65+}
66+ 
67+HcclResult AllReduceBIARExecutor::SelectAndPrepareBirsTemplate(
68+ u32 localRank, u32 localRankSize, std::unique_ptr<AlgTemplateBase>& templatePtr)
69+{
70+ TemplateType RStplType = TEMPLATE_ALL_REDUCE_BIAR;
71+ templatePtr = AlgTemplateRegistry::Instance().GetAlgTemplate(RStplType);
72+ CHK_SMART_PTR_NULL(templatePtr);
73+ CHK_RET(templatePtr->Prepare(localRank, localRankSize));
74+ HCCL_CONFIG_INFO(HCCL_ALG, "[%s] Run TEMPLATE_ALL_REDUCE_BIAR in COMM_LEVEL0", __func__);
75+ 
76+ return HCCL_SUCCESS;
77+}
78+ 
79+HcclResult AllReduceBIARExecutor::KernelRunLevel0(const OpParam& param, ExecMem& execMem)
80+{
81+ SubCommInfo level0CommInfo;
82+ CHK_RET(GetSubCommInfo(COMM_LEVEL0, level0CommInfo));
83+ u32 level0LocalRank = level0CommInfo.localRank;
84+ u32 level0LocalRankSize = level0CommInfo.localRankSize;
85+ u32 sliceNum = level0LocalRankSize;
86+ std::vector<Slice> dataSegsSlice;
87+ CHK_RET(PrepareDataSlice(execMem.count, unitSize_, sliceNum, dataSegsSlice));
88+ 
89+ std::unique_ptr<AlgTemplateBase> tempAlg = nullptr;
90+ CHK_RET(SelectAndPrepareBirsTemplate(level0LocalRank, level0LocalRankSize, tempAlg));
91+ 
92+ HcclMem UsrInputMem{HCCL_MEM_TYPE_DEVICE, execMem.inputPtr, execMem.count * unitSize_};
93+ HcclMem UsrOutputMem{HCCL_MEM_TYPE_DEVICE, execMem.outputPtr, execMem.count * unitSize_};
94+ 
95+ if (auto Exp = dynamic_cast<AlgTemplateBaseExperimental*>(tempAlg.get())) {
严正行
严正行严正行8月7日

[MEDIUM] dynamic_cast 结果未校验,转换失败时静默跳过全部逻辑返回 SUCCESS

问题分析:

  • 第 103 行:if (auto Exp = dynamic_cast<AlgTemplateBaseExperimental*>(tempAlg.get()))
  • 若 dynamic_cast 返回 nullptr(类型不匹配),if 块被跳过,KernelRunLevel0 直接返回 HCCL_SUCCESS
  • 结果:未执行任何 AllReduce 逻辑,output buffer 未初始化,但调用方收到 SUCCESS —— 静默数据损坏

建议修复: 在 if 块后添加 nullptr 校验:

if (auto Exp = dynamic_cast<AlgTemplateBaseExperimental*>(tempAlg.get())) {
    CHK_RET(Exp->Prepare(...));
    CHK_RET(Exp->RunAsync(...));
} else {
    HCCL_ERROR("[AllReduceBIARExecutor] template is not AlgTemplateBaseExperimental");
    return HCCL_E_INTERNAL;
}
likedislike
Lankin Ivan
Lankin Ivan
8月19日 评论:
96+ CHK_RET(Exp->Prepare(
97+ UsrInputMem, UsrOutputMem, execMem.inputMem, execMem.count, param.DataDes.dataType, thread_, slaveThreads_,
98+ param.reduceType, 0, dataSegsSlice, 0, false));
99+ 
100+ CHK_RET(Exp->RunAsync(level0LocalRank, level0LocalRankSize, channels_[COMM_LEVEL0]));
101+ } else {
102+ HCCL_ERROR("[AllReduceBIARExecutor] template is not AlgTemplateBaseExperimental");
103+ return HCCL_E_INTERNAL;
104+ }
105+ 
106+ return HCCL_SUCCESS;
107+}
108+ 
109+REGISTER_EXEC("AllReduceBIARExecutor", AllReduceBIAR, AllReduceBIARExecutor);
110+} // namespace ops_hccl_experimental
@@ -0,0 +1,59 @@
1+/**
2+ * Copyright (c) 2026 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+#ifndef ALL_REDUCE_BIAR_EXECUTOR_H
12+#define ALL_REDUCE_BIAR_EXECUTOR_H
13+#include "all_reduce_executor_base.h"
14+#include "alg_template_base_experimental.h"
15+#include "coll_alg_exec_registry.h"
16+ 
17+namespace ops_hccl_experimental {
18+using ops_hccl::AddAlgToAllAlgos;
19+using ops_hccl::AlgHierarchyInfo;
20+using ops_hccl::AlgResourceCtx;
21+using ops_hccl::AlgResourceRequest;
22+using ops_hccl::AlgTemplateBase;
23+using ops_hccl::AlgTemplateRegistry;
24+using ops_hccl::AlgType;
25+using ops_hccl::AlgTypeLevel0;
26+using ops_hccl::AlgTypeLevel1;
27+using ops_hccl::AlgTypeLevel2;
28+using ops_hccl::ChannelInfo;
29+using ops_hccl::CollAlgExecRegistry;
30+using ops_hccl::COMM_LEVEL0;
31+using ops_hccl::DefaultExecCreator;
32+using ops_hccl::ExecMem;
33+using ops_hccl::ExecutorBase;
34+using ops_hccl::HCCL_ALG;
35+using ops_hccl::OpParam;
36+using ops_hccl::Slice;
37+using ops_hccl::SubCommInfo;
38+using ops_hccl::TemplateType;
39+using ops_hccl::TopoInfo;
40+ 
41+class AllReduceBIARExecutor : public AllReduceExecutorBase {
42+public:
43+ explicit AllReduceBIARExecutor();
44+ ~AllReduceBIARExecutor() override = default;
45+ 
46+ HcclResult CalcResRequest(
47+ HcclComm comm, const OpParam& param, TopoInfo* topoInfo, AlgHierarchyInfo& algHierarchyInfo,
48+ AlgResourceRequest& resourceRequest, AlgType& algType) override;
49+ 
50+private:
51+ HcclResult
52+ SelectAndPrepareBirsTemplate(u32 localRank, u32 localRankSize, std::unique_ptr<AlgTemplateBase>& templatePtr);
53+ HcclResult KernelRunLevel0(const OpParam& param, ExecMem& execMem);
54+ HcclResult KernelRun(const OpParam& param, ExecMem& execMem) override;
55+};
56+ 
57+} // namespace ops_hccl_experimental
58+ 
59+#endif
@@ -0,0 +1,48 @@
1+/**
2+ * Copyright (c) 2026 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_reduce_biar_selector.h"
12+ 
13+namespace ops_hccl_experimental {
14+using ops_hccl::TopoInfo;
15+ 
16+BiarSelectResult DecideAllReduceBiarAlg(const TopoInfo& topoInfo, std::string& algName)
17+{
18+ if (topoInfo.userRankSize == 1) {
19+ return BiarSelectResult::bRejectRankSizeOne;
20+ }
21+ if (topoInfo.deviceType != HcclDevType::DEV_TYPE_910_93 || (topoInfo.userRankSize % 2 != 0)) {
22+ return BiarSelectResult::bNotSelected;
23+ }
24+ if (topoInfo.serverNum == 0) {
25+ return BiarSelectResult::bRejectServerNumZero;
26+ }
27+ if (topoInfo.userRankSize / topoInfo.serverNum < 4) {
W
Wwenxuemin9月20日

🔴 [严重] [代码正确性] experimental/ops/all_reduce/biar/all_reduce_biar_selector.cc:27

selector 仅校验 userRankSize/serverNum < 4,未拒绝 serverNum > 1;而 AllReduceBIAR 模板只有单机 level0 实现(RunReduceScatter + RunAllGather,无 inter-server 归约/广播阶段),且 AllReduceBIARExecutor::SelectAndPrepareBirsTemplate 的 isSingleServer 参数声明后未使用,恒选 TEMPLATE_ALL_REDUCE_BIAR。

后果:serverNum≥2 且每 server≥4 rank 时,AllReduce 退化为各 server 独立的 intra-server allreduce,跨 server 分量既不归约也不广播,结果错误。ST 用例 st_all_reduce_1416_test(1×4×16)恰会命中此路径,但该 ST 未纳入默认构建故未暴露。

建议:selector 增加 serverNum != 1 时返回 bNotSelected(回退老流程),或实现 AllReduceBIARInter 变体并让 isSingleServer 真实分流模板。

likedislike
Davydov_Danil
9月21日 评论:
28+ return BiarSelectResult::bRejectRanksPerServerLT4;
29+ }
30+ algName = "AllReduceBIARExecutor";
31+ return BiarSelectResult::bSelected;
32+}
33+ 
34+HcclResult BiarSelectResultToCode(BiarSelectResult result)
35+{
36+ switch (result) {
37+ case BiarSelectResult::bSelected:
38+ case BiarSelectResult::bNotSelected:
39+ return HCCL_SUCCESS;
40+ case BiarSelectResult::bRejectRankSizeOne:
41+ return HCCL_E_INTERNAL;
严正行
严正行严正行8月20日

[MEDIUM] 单 rank AllReduce 仍返回 HCCL_E_INTERNAL,核心问题未修复

复检核验:作者回复称已 fixed, add selector and unit tests。实读 current head 2b34a09 的 all_reduce_biar_selector.cc,新增了 DecideAllReduceBiarAlg selector 与 biar_selector_test.cc,结构上是改进,但核心语义问题仍在:

  • all_reduce_biar_selector.cc:18-20:if (topoInfo.userRankSize == 1) { return BiarSelectResult::bRejectRankSizeOne; }
  • all_reduce_biar_selector.cc:40-41:case BiarSelectResult::bRejectRankSizeOne: return HCCL_E_INTERNAL;
  • 单 rank AllReduce 经 AllReduceExperimental(all_reduce_op_experimental.cc:52 rankSize=INVALID_VALUE_RANKSIZE=0xFFFFFFFF,rankSize==1 判定恒 false)→ BIRS 路径 → ExecOpBirs → SelectAlgAllReduce → DecideAllReduceBiarAlg 返回 bRejectRankSizeOne → BiarSelectResultToCode 返回 HCCL_E_INTERNAL → 用户收到内部错误。
  • 原意见核心:单 rank 场景应直接拷贝 input 到 output(no-op 语义)并返回 SUCCESS,返回 HCCL_E_INTERNAL 让调用方收到内部错误而非正确结果。
  • 新增的 biar_selector_test.cc RankSizeOneIsRejected 测试反而锁定了这个错误行为(断言返回 bRejectRankSizeOne→HCCL_E_INTERNAL),使错误行为被测试固化。

建议修复:单 rank 不应返回错误码,应在 SelectAlgAllReduce 或 AllReduceExperimental 层对 userRankSize==1 做提前 LocalCopy 并返回 SUCCESS(algName 留空走默认 no-op 路径),或将 bRejectRankSizeOne 映射为 HCCL_SUCCESS 并在 executor 层做 LocalCopy。

likedislike
Lankin Ivan
Lankin Ivan
8月21日 评论:
42+ case BiarSelectResult::bRejectServerNumZero:
43+ case BiarSelectResult::bRejectRanksPerServerLT4:
44+ return HCCL_E_PARA;
45+ }
46+ return HCCL_E_INTERNAL;
47+}
48+} // namespace ops_hccl_experimental
@@ -0,0 +1,31 @@
1+/**
2+ * Copyright (c) 2026 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+#ifndef OPS_HCCL_EXPERIMENTAL_ALL_REDUCE_BIAR_SELECTOR
12+#define OPS_HCCL_EXPERIMENTAL_ALL_REDUCE_BIAR_SELECTOR
13+ 
14+#include <string>
15+#include "alg_param.h"
16+ 
17+namespace ops_hccl_experimental {
18+enum class BiarSelectResult {
19+ bNotSelected,
20+ bSelected,
21+ bRejectRankSizeOne,
22+ bRejectServerNumZero,
23+ bRejectRanksPerServerLT4,
24+};
25+ 
26+BiarSelectResult DecideAllReduceBiarAlg(const ops_hccl::TopoInfo& topoInfo, std::string& algName);
27+ 
28+HcclResult BiarSelectResultToCode(BiarSelectResult result);
29+} // namespace ops_hccl_experimental
30+ 
31+#endif
@@ -0,0 +1,49 @@
1+/**
2+ * Copyright (c) 2026 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_reduce_executor_base.h"
12+ 
13+namespace ops_hccl_experimental {
14+ 
15+AllReduceExecutorBase::AllReduceExecutorBase() : CollExecutorBaseExperimental() {}
16+ 
17+HcclResult AllReduceExecutorBase::CalcResRequest(
W
Wwenxuemin29 天前

⚠️ [中等] [接口设计] experimental/ops/all_reduce/biar/all_reduce_executor_base.cc:159

CalcResRequest 基类实现为 no-op,直接 return HCCL_SUCCESS。未来新增子类若忘记 override,会静默跳过资源申请,运行期才暴露且难以定位。

建议:声明为纯虚(= 0)强制子类实现;若基类确需默认实现,至少返回 HCCL_E_NOT_SUPPORT 而非 SUCCESS。

likedislike
Davydov_Danil
28 天前 评论:
18+ HcclComm comm, const OpParam& param, TopoInfo* topoInfo, AlgHierarchyInfo& algHierarchyInfo,
19+ AlgResourceRequest& resourceRequest, AlgType& algType)
20+{
21+ // 子类必须 override 完成资源申请;默认返回不支持错误,避免静默跳过。
22+ return HCCL_E_NOT_SUPPORT;
23+}
24+ 
25+HcclResult
26+AllReduceExecutorBase::PrepareDataSlice(u64 dataCount, u32 unitSize, u32 sliceNum, std::vector<Slice>& dataSlice)
27+{
28+ CHK_PRT_RET((sliceNum == 0), HCCL_ERROR("[AllReduceExecutorBase][PrepareDataSlice]sliceNum is zero."), HCCL_E_PARA);
29+ 
30+ dataSlice.resize(sliceNum);
31+ // V-style slicing: distribute remainder elements to the first 'remainder' ranks
32+ u64 baseCount = dataCount / sliceNum;
33+ u64 remainder = dataCount % sliceNum;
34+ u64 offsetCount = 0;
35+ for (u32 i = 0; i < sliceNum; i++) {
36+ u64 curCount = baseCount + (i < remainder ? 1 : 0);
37+ dataSlice[i].size = curCount * unitSize;
38+ dataSlice[i].offset = offsetCount * unitSize;
39+ offsetCount += curCount;
40+ HCCL_DEBUG(
41+ "[AllReduceExecutorBase][PrepareDataSlice] slice[%u]: offset[%llu] size[%llu] count[%llu]", i,
42+ dataSlice[i].offset, dataSlice[i].size, curCount);
43+ }
44+ return HCCL_SUCCESS;
45+}
46+ 
47+u64 AllReduceExecutorBase::CalcScratchDemand(u64 curRecvSize) const { return curRecvSize; }
48+ 
49+} // namespace ops_hccl_experimental
@@ -0,0 +1,48 @@
1+/**
2+ * Copyright (c) 2026 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+#ifndef ALL_REDUCE_EXECUTOR_H
12+#define ALL_REDUCE_EXECUTOR_H
13+ 
14+#include "alg_param.h"
15+#include "executor_base.h"
16+#include "config_log.h"
17+#include "alg_template_base_experimental.h"
18+#include "coll_executor_base_experimental.h"
19+ 
20+namespace ops_hccl_experimental {
21+using ops_hccl::AlgHierarchyInfo;
22+using ops_hccl::AlgResourceRequest;
23+using ops_hccl::AlgType;
24+using ops_hccl::OpParam;
25+using ops_hccl::Slice;
26+using ops_hccl::TopoInfo;
27+ 
28+class AllReduceExecutorBase : public CollExecutorBaseExperimental {
29+public:
30+ explicit AllReduceExecutorBase();
31+ ~AllReduceExecutorBase() override = default;
32+ 
33+ /* *************** 资源计算 *************** */
34+ HcclResult CalcResRequest(
35+ HcclComm comm, const OpParam& param, TopoInfo* topoInfo, AlgHierarchyInfo& algHierarchyInfo,
36+ AlgResourceRequest& resourceRequest, AlgType& algType) override;
37+ 
38+protected:
39+ /* *************** 通用工具 *************** */
40+ virtual HcclResult PrepareDataSlice(u64 dataCount, u32 unitSize, u32 sliceNum, std::vector<Slice>& dataSlice);
41+ 
42+ // AllReduce(BIAR) 为 RS+AG 分解: 切片总和为单 rank 数据量, scratch 需求按单 rank 量校验
43+ u64 CalcScratchDemand(u64 curRecvSize) const override;
44+};
45+ 
46+} // namespace ops_hccl_experimental
47+ 
48+#endif
@@ -0,0 +1,23 @@
1+# -----------------------------------------------------------------------------------------------------------
2+# Copyright (c) 2026 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+if(NOT ENABLE_EXPERIMENTAL)
12+ return()
13+endif()
14+ 
15+set(src_list
16+ ${CMAKE_CURRENT_SOURCE_DIR}/all_reduce_biar.cc
17+)
18+ 
19+if(TARGET hccl)
20+ target_sources(hccl PRIVATE
21+ ${src_list}
22+ )
23+endif()
@@ -0,0 +1,393 @@
1+/**
2+ * Copyright (c) 2026 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 "alg_template_register.h"
12+#include "all_reduce_biar.h"
13+ 
14+namespace ops_hccl_experimental {
15+ 
16+AllReduceBIAR::AllReduceBIAR() : AlgTemplateBaseExperimental() {}
17+ 
18+AllReduceBIAR::~AllReduceBIAR() {}
19+ 
20+HcclResult AllReduceBIAR::Prepare(u32 interRank, u32 interRankSize)
21+{
22+ interRank_ = interRank;
23+ interRankSize_ = interRankSize;
24+ return HCCL_SUCCESS;
25+}
26+ 
27+HcclResult AllReduceBIAR::Prepare(
28+ HcclMem& inputMem, HcclMem& outputMem, HcclMem& scratchMem, const u64 count, const HcclDataType dataType,
29+ ThreadHandle thread, const std::vector<ThreadHandle>& slaveThreads, const HcclReduceOp reductionOp, const u32 root,
30+ const std::vector<Slice>& slices, const u64 baseOffset, const bool disableDMAReduce)
31+{
32+ mainThread_ = thread;
33+ subThreads_ = slaveThreads;
34+ AlgTemplateBase::Prepare(
35+ inputMem, outputMem, scratchMem, count, dataType, thread, reductionOp, root, slices, baseOffset,
36+ disableDMAReduce);
37+ return HCCL_SUCCESS;
38+}
39+ 
40+void AllReduceBIAR::GetNotifyIdxMainToSub(std::vector<u32>& notifyIdxMainToSub)
41+{
42+ notifyIdxMainToSub.clear();
43+ u32 slaveThreadNum = BIAR_THREAD_NUM;
44+ for (u32 slaveThreadIdx = 0; slaveThreadIdx < slaveThreadNum; slaveThreadIdx++) {
45+ notifyIdxMainToSub.push_back(0);
46+ }
47+}
48+ 
49+void AllReduceBIAR::GetNotifyIdxSubToMain(std::vector<u32>& notifyIdxSubToMain)
50+{
51+ notifyIdxSubToMain.clear();
52+ u32 notifyNum = BIAR_THREAD_NUM;
53+ for (u32 notifyIdx = 0; notifyIdx < notifyNum; notifyIdx++) {
54+ notifyIdxSubToMain.push_back(notifyIdx);
55+ }
56+}
57+ 
58+HcclResult AllReduceBIAR::Preprocess(const u32 rank, const u32 rankSize, std::vector<ChannelInfo>& channels)
59+{
60+ if (rankSize == 1) {
61+ if (inputMem_.addr != outputMem_.addr) {
62+ CHK_RET(static_cast<HcclResult>(
63+ HcommLocalCopyOnThread(thread_, outputMem_.addr, inputMem_.addr, inputMem_.size)));
64+ }
65+ return HCCL_SUCCESS;
66+ }
67+ 
68+ if (channels.size() < rankSize) {
69+ HCCL_ERROR(
70+ "[AllReduceBIAR][RunAsync]rank[%u] linksize[%llu] is less than rankSize[%u]", rank, channels.size(),
71+ rankSize);
72+ return HCCL_E_INTERNAL;
73+ }
74+ 
75+ unitSize_ = DataUnitSize(dataType_);
76+ if (unitSize_ == 0) {
77+ HCCL_ERROR("[AllReduceBIAR][RunAsync]rank[%u] unit data size is zero", rank);
78+ return HCCL_E_INTERNAL;
79+ }
80+ 
81+ return HCCL_SUCCESS;
82+}
83+ 
84+HcclResult AllReduceBIAR::LocalReduceCCLToCCL(u64 srcOffset, u64 dstOffset, u64 size, ThreadHandle thread)
85+{
86+ void* srcSlice = static_cast<void*>(static_cast<u8*>(scratchMem_.addr) + srcOffset);
87+ void* dstSlice = static_cast<void*>(static_cast<u8*>(scratchMem_.addr) + dstOffset);
88+ CHK_RET(static_cast<HcclResult>(HcommLocalReduceOnThread(
89+ thread, dstSlice, srcSlice, size / unitSize_, static_cast<HcommDataType>(dataType_),
90+ static_cast<HcommReduceOp>(reductionOp_))));
91+ return HCCL_SUCCESS;
92+}
93+ 
94+HcclResult
95+AllReduceBIAR::HCCSProcessRsLoop(u32 round, const u32 rank, const u32 rankSize, u32 rankSizeX, u64 localStrideSize)
96+{
97+ if (round != 0 && round <= hccs_ranks.size()) {
98+ CHK_RET(static_cast<HcclResult>(
99+ HcommChannelNotifyRecordOnThread(subThreads_[0], hccs_links[round - 1].handle, NOTIFY_IDX_ACK)));
100+ CHK_RET(static_cast<HcclResult>(HcommChannelNotifyWaitOnThread(
101+ subThreads_[0], hccs_links_reversed[round - 1].handle, NOTIFY_IDX_ACK, CUSTOM_TIMEOUT)));
102+ u64 localOffsetByte = hccs_ranks[round - 1] / rankSizeX * localStrideSize;
103+ u64 remoteOffsetByte = ((rankSize / rankSizeX) + rank / rankSizeX) * localStrideSize;
104+ void* src = static_cast<void*>(static_cast<u8*>(scratchMem_.addr) + localOffsetByte);
105+ void* dst = static_cast<void*>(static_cast<u8*>(hccs_links[round - 1].remoteOutput.addr) + remoteOffsetByte);
106+ 
107+ if (slices_[hccs_ranks[round - 1]].size > 0) {
108+ CHK_RET(static_cast<HcclResult>(HcommWriteOnThread(
109+ subThreads_[0], hccs_links[round - 1].handle, dst, src, slices_[hccs_ranks[round - 1]].size)));
110+ }
111+ 
112+ CHK_RET(static_cast<HcclResult>(
113+ HcommChannelNotifyRecordOnThread(subThreads_[0], hccs_links[round - 1].handle, NOTIFY_IDX_DATA_SIGNAL)));
114+ CHK_RET(static_cast<HcclResult>(HcommChannelNotifyWaitOnThread(
115+ subThreads_[0], hccs_links_reversed[round - 1].handle, NOTIFY_IDX_DATA_SIGNAL, CUSTOM_TIMEOUT)));
116+ }
117+ return HCCL_SUCCESS;
118+}
119+ 
120+HcclResult
121+AllReduceBIAR::SIOProcessRsLoop(u32 round, const u32 rank, const u32 rankSize, u32 rankSizeX, u64 localStrideSize)
122+{
123+ CHK_RET(static_cast<HcclResult>(HcommChannelNotifyRecordOnThread(mainThread_, sio_link.handle, NOTIFY_IDX_ACK)));
124+ CHK_RET(static_cast<HcclResult>(
125+ HcommChannelNotifyWaitOnThread(mainThread_, sio_link.handle, NOTIFY_IDX_ACK, CUSTOM_TIMEOUT)));
126+ 
127+ u64 localOffsetByte
128+ = (round < hccs_ranks.size()) ? slices_[hccs_neighbour_rank[round]].offset : slices_[sio_rank_].offset;
129+ u64 remoteOffsetByte = (round < hccs_ranks.size()) ? hccs_ranks[round] / rankSizeX * localStrideSize :
130+ rank / rankSizeX * localStrideSize;
131+ u64 curSliceSize = (round < hccs_ranks.size()) ? slices_[hccs_neighbour_rank[round]].size : slices_[sio_rank_].size;
132+ void* src = static_cast<void*>(static_cast<u8*>(inputMem_.addr) + localOffsetByte);
133+ void* dst = static_cast<void*>(static_cast<u8*>(sio_link.remoteOutput.addr) + remoteOffsetByte);
134+ 
135+ if (curSliceSize > 0) {
136+ CHK_RET(static_cast<HcclResult>(HcommWriteReduceOnThread(
137+ mainThread_, sio_link.handle, dst, src, curSliceSize / unitSize_, static_cast<HcommDataType>(dataType_),
138+ static_cast<HcommReduceOp>(reductionOp_))));
139+ }
140+ 
141+ CHK_RET(static_cast<HcclResult>(
142+ HcommChannelNotifyRecordOnThread(mainThread_, sio_link.handle, NOTIFY_IDX_DATA_SIGNAL)));
143+ CHK_RET(static_cast<HcclResult>(
144+ HcommChannelNotifyWaitOnThread(mainThread_, sio_link.handle, NOTIFY_IDX_DATA_SIGNAL, CUSTOM_TIMEOUT)));
145+ 
146+ return HCCL_SUCCESS;
147+}
148+ 
149+HcclResult
150+AllReduceBIAR::LocalCopyRsLoop(u32 round, const u32 rank, const u32 rankSize, u32 rankSizeX, u64 localStrideSize)
151+{
152+ if (round < hccs_ranks.size()) {
153+ u32 rank_idx = (round + 1 < hccs_ranks.size()) ? hccs_ranks[round + 1] : rank;
154+ void* srcSlice = static_cast<void*>(static_cast<u8*>(inputMem_.addr) + slices_[rank_idx].offset);
155+ void* dstSlice
156+ = static_cast<void*>(static_cast<u8*>(scratchMem_.addr) + rank_idx / rankSizeX * localStrideSize);
157+ if (slices_[rank_idx].size > 0) {
158+ CHK_RET(static_cast<HcclResult>(
159+ HcommLocalCopyOnThread(subThreads_[1], dstSlice, srcSlice, slices_[rank_idx].size)));
160+ }
161+ }
162+ return HCCL_SUCCESS;
163+}
164+ 
165+HcclResult AllReduceBIAR::TreeReduceRs(const u32 rank, const u32 rankSize, u32 rankSizeX, u64 localStrideSize)
166+{
167+ std::vector<u64> vec;
168+ for (u32 i = 0; i < (rankSize / rankSizeX); i++) {
169+ if (i == (rank / rankSizeX)) {
170+ vec.push_back((rank / rankSizeX) * localStrideSize);
171+ } else {
172+ vec.push_back(((rankSize / rankSizeX) + i) * localStrideSize);
173+ }
174+ }
175+ // Tree local reduce
176+ auto ind = rankSize / rankSizeX;
177+ for (u32 stride = 1; stride < ind; stride *= 2) {
178+ for (u32 i = stride; i < ind; i += stride * 2) {
179+ if (slices_[rank].size > 0) {
180+ CHK_RET(LocalReduceCCLToCCL(vec[i], vec[i - stride], slices_[rank].size, mainThread_));
181+ }
182+ }
183+ }
184+ 
185+ u64 allGatherOffset = rank / rankSizeX * localStrideSize;
186+ 
187+ if (vec[0] != allGatherOffset) {
188+ void* srcSlice = static_cast<void*>(static_cast<u8*>(scratchMem_.addr) + vec[0]);
189+ void* dstSlice = static_cast<void*>(static_cast<u8*>(scratchMem_.addr) + allGatherOffset);
190+ if (slices_[rank].size > 0) {
191+ CHK_RET(
192+ static_cast<HcclResult>(HcommLocalCopyOnThread(mainThread_, dstSlice, srcSlice, slices_[rank].size)));
193+ }
194+ }
195+ 
196+ return HCCL_SUCCESS;
197+}
198+ 
199+HcclResult AllReduceBIAR::RunReduceScatter(
200+ const u32 rank, const u32 rankSize, std::vector<ChannelInfo>& channels, u64 localStrideSize)
201+{
202+ for (u32 round = 0; round < hccs_ranks.size() + 1; round++) {
203+ // MainRecordSub + SubWaitMain
204+ CHK_RET(PreSyncInterThreads(mainThread_, subThreads_, notifyIdxMainToSub_));
205+ 
206+ CHK_RET(HCCSProcessRsLoop(round, rank, rankSize, rankSizeX_, localStrideSize));
207+ CHK_RET(SIOProcessRsLoop(round, rank, rankSize, rankSizeX_, localStrideSize));
208+ CHK_RET(LocalCopyRsLoop(round, rank, rankSize, rankSizeX_, localStrideSize));
209+ 
210+ // SubRecordMain + MainWaitSub
211+ CHK_RET(PostSyncInterThreads(mainThread_, subThreads_, notifyIdxSubToMain_));
212+ }
213+ 
214+ CHK_RET(PreSyncInterThreads(mainThread_, subThreads_, notifyIdxMainToSub_));
215+ 
216+ CHK_RET(TreeReduceRs(rank, rankSize, rankSizeX_, localStrideSize));
217+ 
218+ CHK_RET(PostSyncInterThreads(mainThread_, subThreads_, notifyIdxSubToMain_));
219+ 
220+ return HCCL_SUCCESS;
221+}
222+ 
223+HcclResult
224+AllReduceBIAR::HCCSProcessAgLoop(u32 round, const u32 rank, const u32 rankSize, u32 rankSizeX, u64 localStrideSize)
225+{
226+ u64 allGatherOffset = rank / rankSizeX * localStrideSize;
227+ if (round < hccs_ranks.size()) {
228+ CHK_RET(static_cast<HcclResult>(
229+ HcommChannelNotifyRecordOnThread(subThreads_[0], hccs_links[round].handle, NOTIFY_IDX_ACK)));
230+ CHK_RET(static_cast<HcclResult>(HcommChannelNotifyWaitOnThread(
231+ subThreads_[0], hccs_links_reversed[round].handle, NOTIFY_IDX_ACK, CUSTOM_TIMEOUT)));
232+ u64 remoteOffsetByte = (rank / rankSizeX) * localStrideSize;
233+ void* src = static_cast<void*>(static_cast<u8*>(scratchMem_.addr) + allGatherOffset);
234+ void* dst = static_cast<void*>(static_cast<u8*>(hccs_links[round].remoteOutput.addr) + remoteOffsetByte);
235+ 
236+ if (slices_[rank].size > 0) {
237+ CHK_RET(static_cast<HcclResult>(
238+ HcommWriteOnThread(subThreads_[0], hccs_links[round].handle, dst, src, slices_[rank].size)));
239+ }
240+ 
241+ CHK_RET(static_cast<HcclResult>(
242+ HcommChannelNotifyRecordOnThread(subThreads_[0], hccs_links[round].handle, NOTIFY_IDX_DATA_SIGNAL)));
243+ CHK_RET(static_cast<HcclResult>(HcommChannelNotifyWaitOnThread(
244+ subThreads_[0], hccs_links_reversed[round].handle, NOTIFY_IDX_DATA_SIGNAL, CUSTOM_TIMEOUT)));
245+ }
246+ return HCCL_SUCCESS;
247+}
248+ 
249+HcclResult
250+AllReduceBIAR::SIOProcessAgLoop(u32 round, const u32 rank, const u32 rankSize, u32 rankSizeX, u64 localStrideSize)
251+{
252+ CHK_RET(static_cast<HcclResult>(HcommChannelNotifyRecordOnThread(mainThread_, sio_link.handle, NOTIFY_IDX_ACK)));
253+ CHK_RET(static_cast<HcclResult>(
254+ HcommChannelNotifyWaitOnThread(mainThread_, sio_link.handle, NOTIFY_IDX_ACK, CUSTOM_TIMEOUT)));
255+ 
256+ u32 agRank = (round != 0 && round <= hccs_ranks.size()) ? (hccs_ranks_reversed[round - 1] ^ 1) : sio_rank_;
257+ u64 localOffsetByte = slices_[agRank].offset;
258+ u64 remoteOffsetByte = (round != 0 && round <= hccs_ranks.size()) ?
259+ (hccs_ranks_reversed[round - 1] / rankSizeX) * localStrideSize :
260+ (sio_rank_ / rankSizeX) * localStrideSize;
261+ void* src = static_cast<void*>(static_cast<u8*>(sio_link.remoteOutput.addr) + remoteOffsetByte);
262+ void* dst = static_cast<void*>(static_cast<u8*>(outputMem_.addr) + localOffsetByte);
263+ 
264+ if (slices_[agRank].size > 0) {
265+ CHK_RET(
266+ static_cast<HcclResult>(HcommReadOnThread(mainThread_, sio_link.handle, dst, src, slices_[agRank].size)));
267+ }
268+ 
269+ CHK_RET(static_cast<HcclResult>(
270+ HcommChannelNotifyRecordOnThread(mainThread_, sio_link.handle, NOTIFY_IDX_DATA_SIGNAL)));
271+ CHK_RET(static_cast<HcclResult>(
272+ HcommChannelNotifyWaitOnThread(mainThread_, sio_link.handle, NOTIFY_IDX_DATA_SIGNAL, CUSTOM_TIMEOUT)));
273+ 
274+ return HCCL_SUCCESS;
275+}
276+ 
277+HcclResult
278+AllReduceBIAR::LocalCopyAgLoop(u32 round, const u32 rank, const u32 rankSize, u32 rankSizeX, u64 localStrideSize)
279+{
280+ if (round != 0 && round <= hccs_ranks.size()) {
281+ void* srcSlice = static_cast<void*>(
282+ static_cast<u8*>(scratchMem_.addr) + (hccs_ranks_reversed[round - 1] / rankSizeX) * localStrideSize);
283+ void* dstSlice
284+ = static_cast<void*>(static_cast<u8*>(outputMem_.addr) + slices_[hccs_ranks_reversed[round - 1]].offset);
285+ if (slices_[hccs_ranks_reversed[round - 1]].size > 0) {
286+ CHK_RET(static_cast<HcclResult>(HcommLocalCopyOnThread(
287+ subThreads_[1], dstSlice, srcSlice, slices_[hccs_ranks_reversed[round - 1]].size)));
288+ }
289+ }
290+ return HCCL_SUCCESS;
291+}
292+ 
293+HcclResult
294+AllReduceBIAR::RunAllGather(const u32 rank, const u32 rankSize, std::vector<ChannelInfo>& channels, u64 localStrideSize)
295+{
296+ for (u32 round = 0; round < hccs_ranks.size() + 1; round++) {
297+ // MainRecordSub + SubWaitMain
298+ CHK_RET(PreSyncInterThreads(mainThread_, subThreads_, notifyIdxMainToSub_));
299+ CHK_RET(HCCSProcessAgLoop(round, rank, rankSize, rankSizeX_, localStrideSize));
300+ CHK_RET(SIOProcessAgLoop(round, rank, rankSize, rankSizeX_, localStrideSize));
301+ CHK_RET(LocalCopyAgLoop(round, rank, rankSize, rankSizeX_, localStrideSize));
302+ 
303+ // SubRecordMain + MainWaitSub
304+ CHK_RET(PostSyncInterThreads(mainThread_, subThreads_, notifyIdxSubToMain_));
305+ }
306+ CHK_RET(PreSyncInterThreads(mainThread_, subThreads_, notifyIdxMainToSub_));
307+ u64 allGatherOffset = rank / rankSizeX_ * localStrideSize;
308+ void* srcSlice = static_cast<void*>(static_cast<u8*>(scratchMem_.addr) + allGatherOffset);
309+ void* dstSlice = static_cast<void*>(static_cast<u8*>(outputMem_.addr) + slices_[rank].offset);
310+ if (slices_[rank].size > 0) {
311+ CHK_RET(static_cast<HcclResult>(HcommLocalCopyOnThread(mainThread_, dstSlice, srcSlice, slices_[rank].size)));
312+ }
313+ 
314+ CHK_RET(PostSyncInterThreads(mainThread_, subThreads_, notifyIdxSubToMain_));
315+ return HCCL_SUCCESS;
316+}
317+ 
318+HcclResult AllReduceBIAR::CheckScratchCapacity(u32 rankSize, u64 localStrideSize)
319+{
320+ u64 scratchDemand = static_cast<u64>(rankSize) * localStrideSize;
321+ CHK_PRT_RET(
322+ scratchDemand > scratchMem_.size,
323+ HCCL_ERROR(
324+ "[AllReduceBIAR][CheckScratchCapacity]scratch demand[%llu] exceeds scratchMem size[%llu]", scratchDemand,
325+ scratchMem_.size),
326+ HCCL_E_PARA);
327+ return HCCL_SUCCESS;
328+}
329+ 
330+HcclResult AllReduceBIAR::RunAsync(const u32 rank, const u32 rankSize, std::vector<ChannelInfo>& channels)
331+{
332+ HCCL_INFO(
333+ "AllReduceBIAR run: rank[%u] rankSize[%u] inputMem[%p] to outputMem[%p] count[%llu]", rank, rankSize,
334+ inputMem_.addr, outputMem_.addr, count_);
335+ 
336+ CHK_RET(Preprocess(rank, rankSize, channels));
337+ 
338+ rankSizeX_ = 2;
339+ if (rankSize % rankSizeX_ != 0) {
340+ HCCL_ERROR(
341+ "[AllReduceBIAR][RunAsync]rankSize[%u] is not evenly divisible by rankSizeX_[%u]", rankSize, rankSizeX_);
342+ return HCCL_E_INTERNAL;
343+ }
344+ rankSizeY_ = rankSize / rankSizeX_;
345+ 
346+ sio_rank_ = rank ^ 1;
347+ sio_link = channels[sio_rank_];
348+ 
349+ for (u32 i = 1; i < rankSize / rankSizeX_; ++i) {
350+ u32 current_hccs_rank = (rank + rankSizeX_ * i) % (rankSizeX_ * rankSizeY_);
351+ hccs_ranks.push_back(current_hccs_rank);
352+ hccs_neighbour_rank.push_back(current_hccs_rank ^ 1);
353+ hccs_links.push_back(channels[hccs_ranks[i - 1]]);
354+ }
355+ hccs_ranks_reversed.assign(hccs_ranks.rbegin(), hccs_ranks.rend());
356+ hccs_links_reversed.assign(hccs_links.rbegin(), hccs_links.rend());
357+ 
358+ // slices_ prepared by Prepare() with V-style distribution (ReduceScatterV)
359+ u64 sliceSize = 0;
360+ for (u32 i = 0; i < rankSize; i++) {
361+ if (slices_[i].size > sliceSize) {
362+ sliceSize = slices_[i].size;
363+ }
364+ HCCL_DEBUG(" slice[%u]: offset: [%llu] size[%llu]", i, slices_[i].offset, slices_[i].size);
365+ }
366+ u64 localStrideSize = RoundUpWithDivisor(sliceSize, HCCL_MIN_SLICE_ALIGN_910B);
严正行
严正行严正行23 天前

[HIGH] RunAsync 计算 scratch 布局后无容量校验,大消息场景 CCL buffer 越界写

问题分析:

  • 第 357 行:u64 localStrideSize = RoundUpWithDivisor(sliceSize, HCCL_MIN_SLICE_ALIGN_910B);

模板在 RunAsync/TreeReduceRs/HCCSProcessAgLoop 中按 (rankSize/rankSizeX + i) * localStrideSize 计算偏移写入 scratchMem_(即 CCL buffer 前半区 cclInputMem),最大写入范围约为 rankSize * localStrideSize 量级。但整个 BIAR 路径没有任何 scratch 容量校验:本仓 ReduceScatterV 路径已有 CheckScratchCapacity 先例(reduce_scatter_v_birs.cc 第 60-69 行,scratchDemand = rankSize * localStrideSize 与 scratchMem_.size 比较,不足即报 HCCL_E_PARA),BIAR 完全没有对应检查。cclInputMem 实际容量为 HcclGetHcclBuffer 返回的固定 cclBufferSize/2(scatter.cc AllocAlgResource 第 802 行),大消息(数据总量接近或超过 cclBufferSize/2)时树归约与 HCCS 写远端的偏移将越过 buffer 末端,造成设备侧越界写、数据静默损坏。

建议修复: 参照 ReduceScatterVBIRS::CheckScratchCapacity 在 RunAsync 计算 localStrideSize 后增加校验:

u64 scratchDemand = static_cast<u64>(rankSize) * localStrideSize;
CHK_PRT_RET(scratchDemand > scratchMem_.size,
    HCCL_ERROR("[AllReduceBIAR]scratch demand[%llu] exceeds scratchMem size[%llu]",
        scratchDemand, scratchMem_.size), HCCL_E_PARA);

注意配套修正 scratchMem_.size 的声明来源(见对 coll_executor_base_experimental.cc RunLoop 的意见),否则该校验会被虚高的声明大小放行。

likedislike
Davydov_Danil
21 天前 评论:
严正行
严正行
21 天前 评论:
367+ 
368+ CHK_RET(CheckScratchCapacity(rankSize, localStrideSize));
369+ 
370+ GetNotifyIdxMainToSub(notifyIdxMainToSub_);
371+ CHK_RET(PreSyncInterThreads(mainThread_, subThreads_, notifyIdxMainToSub_));
372+ 
373+ if (!hccs_ranks.empty() && slices_[hccs_ranks[0]].size > 0) {
374+ void* srcSlice = static_cast<void*>(static_cast<u8*>(inputMem_.addr) + slices_[hccs_ranks[0]].offset);
375+ void* dstSlice
376+ = static_cast<void*>(static_cast<u8*>(scratchMem_.addr) + hccs_ranks[0] / rankSizeX_ * localStrideSize);
377+ CHK_RET(static_cast<HcclResult>(
378+ HcommLocalCopyOnThread(mainThread_, dstSlice, srcSlice, slices_[hccs_ranks[0]].size)));
379+ }
380+ 
381+ GetNotifyIdxSubToMain(notifyIdxSubToMain_);
382+ CHK_RET(PostSyncInterThreads(mainThread_, subThreads_, notifyIdxSubToMain_));
383+ 
384+ // MainRecordSub + SubWaitMain
385+ CHK_RET(RunReduceScatter(rank, rankSize, channels, localStrideSize));
386+ CHK_RET(RunAllGather(rank, rankSize, channels, localStrideSize));
387+ 
388+ HCCL_INFO("AllReduceBIAR finished: rank[%u]", rank);
389+ return HCCL_SUCCESS;
390+}
391+ 
392+REGISTER_TEMPLATE(TEMPLATE_ALL_REDUCE_BIAR, AllReduceBIAR);
393+} // namespace ops_hccl_experimental
@@ -0,0 +1,97 @@
1+/**
2+ * Copyright (c) 2026 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+#ifndef ALL_REDUCE_BIAR_H
12+#define ALL_REDUCE_BIAR_H
13+ 
14+#include "alg_template_base.h"
15+#include "alg_data_trans_wrapper.h"
16+#include "alg_template_base_experimental.h"
17+ 
18+namespace ops_hccl_experimental {
19+using ops_hccl::AlgTemplateBase;
20+using ops_hccl::AlgTemplateRegistry;
21+using ops_hccl::ChannelInfo;
22+using ops_hccl::CUSTOM_TIMEOUT;
23+using ops_hccl::DefaultTemplateCreator;
24+using ops_hccl::HCCL_MIN_SLICE_ALIGN_910B;
25+using ops_hccl::NOTIFY_IDX_ACK;
26+using ops_hccl::NOTIFY_IDX_DATA_SIGNAL;
27+using ops_hccl::PostSyncInterThreads;
28+using ops_hccl::PreSyncInterThreads;
29+using ops_hccl::RoundUpWithDivisor;
30+using ops_hccl::Slice;
31+using ops_hccl::TemplateType;
32+ 
33+// BIAR 从线程数单一事实源: executor 侧据此申请 slaveThreadNum/notify 资源, 模板侧据此生成 notifyIdx
34+// 并索引 subThreads_, 两侧必须一致
35+constexpr u32 BIAR_THREAD_NUM = 2;
36+ 
37+class AllReduceBIAR : public AlgTemplateBaseExperimental {
38+public:
39+ explicit AllReduceBIAR();
严正行
严正行严正行8月7日

[LOW] 无参构造函数标注 explicit 无意义

问题分析:

  • 第 35 行:explicit AllReduceBIAR();
  • explicit 防止隐式转换,但无参构造不存在隐式转换场景,标注无效果
  • 构造函数体为空(.cc 第 17-19 行),可用 = default

建议修复: 移除 explicit,或直接 AllReduceBIAR() = default;

likedislike
Lankin Ivan
Lankin Ivan
8月19日 评论:
40+ 
41+ ~AllReduceBIAR() override;
42+ 
43+ // should be called soon after template AllReduceBIAR instance created
44+ HcclResult Prepare(u32 interRank, u32 interRankSize) override;
45+ 
46+ HcclResult Prepare(
47+ HcclMem& inputMem, HcclMem& outputMem, HcclMem& scratchMem, const u64 count, const HcclDataType dataType,
48+ ThreadHandle thread, const std::vector<ThreadHandle>& slaveThreads, const HcclReduceOp reductionOp,
49+ const u32 root, const std::vector<Slice>& slices, const u64 baseOffset, const bool disableDMAReduce) override;
50+ 
51+ HcclResult RunAsync(const u32 rank, const u32 rankSize, std::vector<ChannelInfo>& channels) override;
52+ 
53+protected:
54+ void GetNotifyIdxMainToSub(std::vector<u32>& notifyIdxMainToSub);
55+ void GetNotifyIdxSubToMain(std::vector<u32>& notifyIdxSubToMain);
56+ 
57+ virtual HcclResult Preprocess(const u32 rank, const u32 rankSize, std::vector<ChannelInfo>& channels);
58+ HcclResult CheckScratchCapacity(u32 rankSize, u64 localStrideSize);
59+ HcclResult
60+ RunReduceScatter(const u32 rank, const u32 rankSize, std::vector<ChannelInfo>& channels, u64 localStrideSize);
61+ HcclResult
62+ RunAllGather(const u32 rank, const u32 rankSize, std::vector<ChannelInfo>& channels, u64 localStrideSize);
63+ 
64+ HcclResult HCCSProcessRsLoop(u32 round, const u32 rank, const u32 rankSize, u32 rankSizeX_, u64 localStrideSize);
65+ HcclResult SIOProcessRsLoop(u32 round, const u32 rank, const u32 rankSize, u32 rankSizeX_, u64 localStrideSize);
66+ HcclResult LocalCopyRsLoop(u32 round, const u32 rank, const u32 rankSize, u32 rankSizeX_, u64 localStrideSize);
67+ HcclResult TreeReduceRs(const u32 rank, const u32 rankSize, u32 rankSizeX_, u64 localStrideSize);
68+ HcclResult LocalReduceCCLToCCL(u64 srcOffset, u64 dstOffset, u64 size, ThreadHandle thread);
69+ 
70+ HcclResult HCCSProcessAgLoop(u32 round, const u32 rank, const u32 rankSize, u32 rankSizeX_, u64 localStrideSize);
71+ HcclResult SIOProcessAgLoop(u32 round, const u32 rank, const u32 rankSize, u32 rankSizeX_, u64 localStrideSize);
72+ HcclResult LocalCopyAgLoop(u32 round, const u32 rank, const u32 rankSize, u32 rankSizeX_, u64 localStrideSize);
73+ 
74+ u32 interRank_;
75+ u32 interRankSize_;
76+ u32 sio_rank_;
77+ std::vector<u32> hccs_ranks;
78+ std::vector<u32> hccs_ranks_reversed;
79+ std::vector<u32> hccs_neighbour_rank;
80+ 
81+ std::vector<ChannelInfo> hccs_links;
82+ std::vector<ChannelInfo> hccs_links_reversed;
83+ ChannelInfo sio_link;
84+ 
85+ u32 unitSize_;
86+ ThreadHandle mainThread_;
87+ std::vector<ThreadHandle> subThreads_;
88+ std::vector<u32> notifyIdxMainToSub_;
89+ std::vector<u32> notifyIdxSubToMain_;
90+ u32 rankSizeX_;
91+ u32 rankSizeY_;
92+ 
93+private:
94+};
95+} // namespace ops_hccl_experimental
96+ 
97+#endif /* ALL_REDUCE_BIAR_H */
@@ -13,6 +13,7 @@ add_subdirectory(recursive_executor)
13 13 
14set(src_list14set(src_list
15 ${CMAKE_CURRENT_SOURCE_DIR}/op_common_experimental.cc15 ${CMAKE_CURRENT_SOURCE_DIR}/op_common_experimental.cc
16+ ${CMAKE_CURRENT_SOURCE_DIR}/coll_executor_base_experimental.cc
16)17)
17 18 
18if(TARGET hccl)19if(TARGET hccl)
@@ -0,0 +1,184 @@
1+/**
2+ * Copyright (c) 2026 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 "coll_executor_base_experimental.h"
12+ 
13+namespace ops_hccl_experimental {
14+using ops_hccl::AlgHierarchyInfo;
15+using ops_hccl::ExecMem;
16+using ops_hccl::HCCL_INTERNODE_MAX_DATA_RATE;
17+using ops_hccl::RDMA_SEND_MAX_SIZE;
18+using ops_hccl::SDMA_SEND_MAX_SIZE;
19+ 
20+CollExecutorBaseExperimental::CollExecutorBaseExperimental() : ExecutorBase() {}
21+ 
22+u32 CollExecutorBaseExperimental::CalcUnitSize(const OpParam& param) const
23+{
24+ return HCCL_SIZE_TABLE[param.DataDes.dataType];
25+}
26+ 
27+u64 CollExecutorBaseExperimental::CalcScratchDemand(u64 curRecvSize) const
28+{
29+ return topoInfo_->userRankSize * curRecvSize;
30+}
31+ 
32+// 执行入口
33+HcclResult CollExecutorBaseExperimental::Orchestrate(const OpParam& param, AlgResourceCtx* resCtx)
34+{
35+ HcclUs startut = TIME_NOW();
36+ topoInfo_ = &(resCtx->topoInfo);
37+ algResource_ = resCtx;
38+ tag_ = std::string(param.tag);
39+ algType_ = resCtx->algType;
40+ unitSize_ = CalcUnitSize(param);
41+ 
42+ CHK_PTR_NULL(param.inputPtr);
43+ CHK_PTR_NULL(param.outputPtr);
44+ 
45+ // 做参数的还原
46+ ThreadHandle* threadHandlePtr
47+ = reinterpret_cast<ThreadHandle*>(reinterpret_cast<char*>(algResource_) + sizeof(AlgResourceCtx));
48+ ChannelInfo* channelInfoPtr = reinterpret_cast<ChannelInfo*>(
49+ reinterpret_cast<char*>(threadHandlePtr) + sizeof(ThreadHandle) * (algResource_->slaveThreadNum + 1));
50+ 
51+ HCCL_DEBUG("[CollExecutorBaseExperimental][Orchestrate] slaveThreadNum[%u]", algResource_->slaveThreadNum);
52+ for (u32 i = 0; i < algResource_->slaveThreadNum + 1; i++) {
53+ HCCL_DEBUG("[CollExecutorBaseExperimental][Orchestrate] threadHandle[%u]=[%llu]", i, threadHandlePtr[i]);
54+ if (i == 0) {
55+ thread_ = threadHandlePtr[i];
56+ } else {
57+ slaveThreads_.push_back(threadHandlePtr[i]);
58+ }
59+ }
60+ AlgHierarchyInfo& algHierarchyInfo = resCtx->algHierarchyInfo;
61+ channels_.resize(algHierarchyInfo.levels);
62+ for (u32 level = 0; level < algHierarchyInfo.levels; level++) {
63+ u32 curLevelRankSize = algHierarchyInfo.infos[level].localRankSize;
64+ channels_[level].resize(curLevelRankSize);
65+ for (u32 rank = 0; rank < curLevelRankSize; rank++) {
66+ channels_[level][rank] = channelInfoPtr[rank];
67+ }
68+ channelInfoPtr += curLevelRankSize;
69+ }
70+ 
71+ HcclResult ret = RunLoop(param);
72+ CHK_PRT_RET(
73+ ret != HCCL_SUCCESS,
74+ HCCL_ERROR(
75+ "[CollExecutorBaseExperimental][Orchestrate]errNo[0x%016llx]collective executor kernel run failed",
76+ HCCL_ERROR_CODE(ret)),
77+ ret);
78+ HCCL_INFO(
79+ "[CollExecutorBaseExperimental][Orchestrate]tag[%s] collective executor orchestrate success, take time "
80+ "[%lld]us.",
81+ param.tag, DURATION_US(TIME_NOW() - startut));
82+ return HCCL_SUCCESS;
83+}
84+ 
85+bool CollExecutorBaseExperimental::IsHugeData(u64 curSize) const
86+{
87+ bool hugeData = curSize * topoInfo_->userRankSize / HCCL_INTERNODE_MAX_DATA_RATE > RDMA_SEND_MAX_SIZE
88+ || curSize > SDMA_SEND_MAX_SIZE;
89+ return hugeData;
90+}
91+ 
92+HcclResult CollExecutorBaseExperimental::RunLoop(const OpParam& param)
93+{
94+ u64 totalRecvCount = param.DataDes.count;
95+ 
96+ u8* curUserInputPtr = static_cast<u8*>(param.inputPtr);
97+ u8* curUserOutputPtr = static_cast<u8*>(param.outputPtr);
98+ auto cclInputMem = algResource_->cclInputMem;
99+ auto cclOutputMem = algResource_->cclOutputMem;
100+ CHK_PRT_RET(
101+ (cclInputMem.size == 0), HCCL_ERROR("[CollExecutorBaseExperimental][RunLoop]cclBuffer size is zero"),
102+ HCCL_E_PARA);
103+ 
104+ u64 curRecvCount = totalRecvCount;
105+ u64 curRecvSize = curRecvCount * unitSize_;
106+ u64 curSendSize = topoInfo_->userRankSize * curRecvSize;
107+ 
108+ // 资源申请(HcommAcquireComm/HcommBatchModeStart)前先做容量校验, 校验失败直接返回不持有任何资源。
109+ // scratch 需求随算子语义不同: ReduceScatter 为全量(userRankSize*单rank量), AllReduce(RS+AG 分解,
110+ // 切片总和为单 rank 数据量)为单 rank 量, 由 CalcScratchDemand 统一提供
111+ u64 scratchDemand = CalcScratchDemand(curRecvSize);
112+ CHK_PRT_RET(
113+ scratchDemand > cclInputMem.size,
114+ HCCL_ERROR(
115+ "[CollExecutorBaseExperimental][RunLoop]scratch demand[%llu] exceeds cclInputMem size[%llu]", scratchDemand,
116+ cclInputMem.size),
117+ HCCL_E_PARA);
118+ 
119+ if (param.engine == CommEngine::COMM_ENGINE_CPU_TS || param.engine == CommEngine::COMM_ENGINE_CPU) {
120+ int32_t ret = HcommAcquireComm(param.commName);
121+ CHK_PRT_RET(
122+ ret != HCCL_SUCCESS, HCCL_ERROR("[%s] [%s] HcommAcquireComm failed ", __func__, param.commName),
123+ static_cast<HcclResult>(ret));
124+ }
125+ 
126+#ifndef AICPU_COMPILE
127+ if (!IsHugeData(curRecvSize)) {
128+ HcclResult startRet = static_cast<HcclResult>(HcommBatchModeStart(param.algTag));
129+ if (startRet != HCCL_SUCCESS) {
130+ HCCL_ERROR("[%s] [%s] HcommBatchModeStart failed", __func__, param.algTag);
131+ if (param.engine == CommEngine::COMM_ENGINE_CPU_TS || param.engine == CommEngine::COMM_ENGINE_CPU) {
132+ int32_t relRet = HcommReleaseComm(param.commName);
133+ if (relRet != HCCL_SUCCESS) {
134+ HCCL_ERROR("[%s] [%s] HcommReleaseComm failed ", __func__, param.commName);
135+ }
136+ }
137+ return startRet;
138+ }
139+ }
140+#endif
141+ // scratch 实际可用区域为整个 cclInputMem(CCL buffer 前半区), 声明大小必须传真实容量而非 curSendSize:
142+ // 模板容量校验(如 CheckScratchCapacity)以 scratchMem_.size 判断, 声明失真会误报或漏判
143+ HcclMem curInputMem{cclInputMem.type, cclInputMem.addr, cclInputMem.size};
144+ HcclMem curOutputMem{cclOutputMem.type, cclOutputMem.addr, curRecvSize};
145+ 
146+ ExecMem execMem;
147+ execMem.count = curRecvCount;
148+ execMem.inputMem = curInputMem;
149+ execMem.outputMem = curOutputMem;
150+ execMem.inputPtr = curUserInputPtr;
151+ execMem.outputPtr = curUserOutputPtr;
152+ 
153+ HCCL_DEBUG(
154+ "[CollExecutorBaseExperimental][RunLoop] curUserInputPtr[%p], curUserOutputPtr[%p], "
155+ "curRecvCount[%llu], curRecvSize[%llu], curSendSize[%llu], inputPtr[%p], outputPtr[%p]",
156+ curUserInputPtr, curUserOutputPtr, curRecvCount, curRecvSize, curSendSize, curInputMem.addr, curOutputMem.addr);
157+ 
158+ HcclResult runRet = KernelRun(param, execMem);
159+ 
160+ HcclResult releaseRet = HCCL_SUCCESS;
161+#ifndef AICPU_COMPILE
162+ if (!IsHugeData(curRecvSize)) {
163+ releaseRet = static_cast<HcclResult>(HcommBatchModeEnd(param.algTag));
164+ if (releaseRet != HCCL_SUCCESS) {
165+ HCCL_ERROR("[%s] [%s] HcommBatchModeEnd failed", __func__, param.algTag);
166+ }
167+ }
168+#endif
169+ if (param.engine == CommEngine::COMM_ENGINE_CPU_TS || param.engine == CommEngine::COMM_ENGINE_CPU) {
170+ int32_t ret = HcommReleaseComm(param.commName);
171+ if (ret != HCCL_SUCCESS) {
172+ HCCL_ERROR("[%s] [%s] HcommReleaseComm failed ", __func__, param.commName);
173+ if (releaseRet == HCCL_SUCCESS) {
174+ releaseRet = static_cast<HcclResult>(ret);
175+ }
176+ }
177+ }
178+ if (runRet != HCCL_SUCCESS) {
179+ return runRet;
180+ }
181+ return releaseRet;
182+}
183+ 
184+} // namespace ops_hccl_experimental
@@ -0,0 +1,56 @@
1+/**
2+ * Copyright (c) 2026 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+#ifndef COLL_EXECUTOR_BASE_EXPERIMENTAL_H
12+#define COLL_EXECUTOR_BASE_EXPERIMENTAL_H
13+ 
14+#include "alg_param.h"
15+#include "executor_base.h"
16+#include "config_log.h"
17+ 
18+namespace ops_hccl_experimental {
19+using ops_hccl::AlgResourceCtx;
20+using ops_hccl::ChannelInfo;
21+using ops_hccl::ExecutorBase;
22+using ops_hccl::OpParam;
23+ 
24+// 集合通信 executor 公共 orchestration 基类: 统一 Orchestrate/RunLoop/IsHugeData 与线程/通道成员,
25+// 消除各算子 executor 基类的逐行重复; RunLoop 失败路径保证 HcommBatchModeEnd/HcommReleaseComm 释放。
26+// 数据切片语义(均匀/V式)由派生类自行实现 PrepareDataSlice。
27+class CollExecutorBaseExperimental : public ExecutorBase {
28+public:
29+ explicit CollExecutorBaseExperimental();
30+ ~CollExecutorBaseExperimental() override = default;
31+ 
32+ HcclResult Orchestrate(const OpParam& param, AlgResourceCtx* resCtx) override;
33+ 
34+protected:
35+ // 用于需要Loop的Executor
36+ virtual HcclResult RunLoop(const OpParam& param);
37+ 
38+ bool IsHugeData(u64 curSize) const;
39+ 
40+ // 单位数据大小: 默认取 DataDes.dataType; 变长算子(如 ReduceScatterV) override 取 vDataDes.dataType
41+ virtual u32 CalcUnitSize(const OpParam& param) const;
42+ 
43+ // RunLoop 的 scratch 容量校验值: 默认按 ReduceScatter 语义取全量(userRankSize*单rank接收量,
44+ // 全量数据驻留 CCL buffer 前半区); AllReduce(RS+AG 分解, 切片总和为单 rank 数据量)等
45+ // 单 rank 量需求的算子由派生类 override
46+ virtual u64 CalcScratchDemand(u64 curRecvSize) const;
47+ 
48+ ThreadHandle thread_ = 0;
49+ std::vector<ThreadHandle> slaveThreads_;
50+ std::vector<std::vector<ChannelInfo>> channels_;
51+ u32 unitSize_;
52+};
53+ 
54+} // namespace ops_hccl_experimental
55+ 
56+#endif
@@ -20,6 +20,7 @@
20#include "hcomm_host_profiling_dl.h"20#include "hcomm_host_profiling_dl.h"
21#include "reduce_scatter_birs_selector.h"21#include "reduce_scatter_birs_selector.h"
22#include "reduce_scatter_v_birs_selector.h"22#include "reduce_scatter_v_birs_selector.h"
23+#include "all_reduce_biar_selector.h"
23#include <algorithm>24#include <algorithm>
24#include <future>25#include <future>
25#include <map>26#include <map>
@@ -178,6 +179,38 @@ SelectAlgReduceScatterV(HcclComm comm, OpParam& param, TopoInfo* topoInfo, AlgTy
178 return HCCL_SUCCESS;179 return HCCL_SUCCESS;
179}180}
180 181 
182+HcclResult SelectAlgAllReduce(HcclComm comm, OpParam& param, TopoInfo* topoInfo, AlgType& algType, std::string& algName)
183+{
184+ (void)comm;
185+ ValidateAndResetAlgLevel1(algType, "All_Reduce");
186+ 
187+ const BiarSelectResult biarResult = DecideAllReduceBiarAlg(*topoInfo, algName);
188+ const HcclResult biarRet = BiarSelectResultToCode(biarResult);
189+ if (biarRet != HCCL_SUCCESS) {
190+ if (biarResult == BiarSelectResult::bRejectServerNumZero) {
191+ HCCL_ERROR(
192+ "[%s] AllReduceBIAR not supported: serverNum is 0, cannot compute ranks per server "
193+ "(userRankSize[%u])",
194+ __func__, topoInfo->userRankSize);
195+ } else if (biarResult == BiarSelectResult::bRejectRanksPerServerLT4) {
196+ HCCL_ERROR(
197+ "[%s] AllReduceBIAR not supported: userRankSize[%u] / serverNum[%u] < 4", __func__,
198+ topoInfo->userRankSize, topoInfo->serverNum);
199+ }
200+ return biarRet;
201+ }
202+ if (biarResult != BiarSelectResult::bSelected || algName.empty()) {
203+ HCCL_ERROR(
204+ "[%s] AllReduceBIAR not selected: deviceType[%d] and even userRankSize[%u] are required, "
205+ "no fallback executor on the BIRS path",
206+ __func__, topoInfo->deviceType, topoInfo->userRankSize);
207+ return HCCL_E_PARA;
208+ }
209+ 
210+ CHK_RET(FillAlgTagAndDebugInfo(param, topoInfo, algType, algName, "All_Reduce"));
211+ return HCCL_SUCCESS;
212+}
atomgit-bot
atomgit-botatomgit-bot7月28日

🟡 Medium Priority

changed line → affected behavior/contract → failure mode → suggested fix

SelectAlgAllReduce(op_common_experimental.cc 第 138-151 行,本次新增)在处理约束条件时存在逻辑缺陷:

if (topoInfo->userRankSize == 1) { return HCCL_E_INTERNAL; } else if (topoInfo->deviceType == DevType::DEV_TYPE_910_93 && (topoInfo->userRankSize % 2 == 0)) { algName = "AllReduceBIARExecutor"; } // 当 deviceType != 910_93 或 rankSize 为奇数(且 >1)时,algName 保持空字符串 CHK_RET(FillAlgTagAndDebugInfo(param, topoInfo, algType, algName, "All_Reduce")); return HCCL_SUCCESS;

触发条件:当用户设置 HCCL_BIRS_ENABLE=TRUE 但运行在非 A3(910_93)设备上,或 rankSize 为奇数(如 3/5/7)时,MatchBIRS() 只检查环境变量、不检查设备/rank 约束,流程会进入 SelectAlgAllReduce,此后 algName 保持为空但函数返回 HCCL_SUCCESS。

失败模式:ExecOpBirs 随后调用 CollAlgExecRegistry::Instance().GetAlgExec(""),返回 nullptr,触发 "Fail to find executor for algName[]" 错误,用户看到的是一个无法定位的失败而非清晰的"算法不适用"提示。PR 设计文档声明"不满足约束时退出并打日志,回退既有算法",但此处并未回退,而是直接报错。

建议:在 if-else 链之后增加 algName.empty() 检查:若为空则打印日志说明设备类型或 rankSize 约束不满足,返回 HCCL_E_INTERNAL(或在 MatchBIRS() 中增加 deviceType==910_93 且 rankSize 为偶数的前置检查,不满足时直接走既有算法回退)。

likedislike
不准确?
Lankin Ivan
Lankin Ivan
9月1日 评论:
Davydov_Danil
9月15日 评论:
213+ 
181struct ThreadResources {214struct ThreadResources {
182 ThreadHandle cpuTsThread = 0;215 ThreadHandle cpuTsThread = 0;
183 ThreadHandle exportedAicpuTsThread = 0;216 ThreadHandle exportedAicpuTsThread = 0;
@@ -341,7 +374,12 @@ HcclResult DoAicpuKernelLaunch(OpParam& param, uint64_t& beginTime)
341 HCCL_E_OPEN_FILE_FAILURE);374 HCCL_E_OPEN_FILE_FAILURE);
342 375 
343 if (HcommIsProfilingSupported()) {376 if (HcommIsProfilingSupported()) {
344- std::string profName = "ReduceScatterAicpuKernel";377+ std::string profName = "";
378+ if (param.opType == HCCL_CMD_REDUCE_SCATTER) {
379+ profName = "ReduceScatterAicpuKernel";
380+ } else if (param.opType == HCCL_CMD_ALLREDUCE) {
381+ profName = "AllReduceAicpuKernel";
382+ }
345 HCCL_DEBUG("[%s] profName = [%s]", __func__, profName);383 HCCL_DEBUG("[%s] profName = [%s]", __func__, profName);
346 HcommProfilingReportKernel(beginTime, profName.c_str());384 HcommProfilingReportKernel(beginTime, profName.c_str());
347 }385 }
@@ -388,6 +426,8 @@ HcclResult ExecOpBirs(HcclComm comm, OpParam& param)
388 CHK_RET(SelectAlgReduceScatter(comm, param, topoInfo, algType, algName));426 CHK_RET(SelectAlgReduceScatter(comm, param, topoInfo, algType, algName));
389 } else if (param.opType == HCCL_CMD_REDUCE_SCATTER_V) {427 } else if (param.opType == HCCL_CMD_REDUCE_SCATTER_V) {
390 CHK_RET(SelectAlgReduceScatterV(comm, param, topoInfo, algType, algName));428 CHK_RET(SelectAlgReduceScatterV(comm, param, topoInfo, algType, algName));
429+ } else if (param.opType == HCCL_CMD_ALLREDUCE) {
430+ CHK_RET(SelectAlgAllReduce(comm, param, topoInfo, algType, algName));
391 }431 }
392 432 
393 std::unique_ptr<ExecutorBase> executor = CollAlgExecRegistry::Instance().GetAlgExec(algName);433 std::unique_ptr<ExecutorBase> executor = CollAlgExecRegistry::Instance().GetAlgExec(algName);
@@ -26,6 +26,7 @@ constexpr TemplateType TEMPLATE_REDUCE_SCATTER_BIRS = static_cast<TemplateType>(
26constexpr TemplateType TEMPLATE_REDUCE_SCATTER_BIRS_INTER = static_cast<TemplateType>(1002);26constexpr TemplateType TEMPLATE_REDUCE_SCATTER_BIRS_INTER = static_cast<TemplateType>(1002);
27constexpr TemplateType TEMPLATE_REDUCE_SCATTER_V_BIRS = static_cast<TemplateType>(1003);27constexpr TemplateType TEMPLATE_REDUCE_SCATTER_V_BIRS = static_cast<TemplateType>(1003);
28constexpr TemplateType TEMPLATE_REDUCE_SCATTER_V_BIRS_INTER = static_cast<TemplateType>(1004);28constexpr TemplateType TEMPLATE_REDUCE_SCATTER_V_BIRS_INTER = static_cast<TemplateType>(1004);
29+constexpr TemplateType TEMPLATE_ALL_REDUCE_BIAR = static_cast<TemplateType>(1005);
29 30 
30class AlgTemplateBaseExperimental : public ops_hccl::AlgTemplateBase {31class AlgTemplateBaseExperimental : public ops_hccl::AlgTemplateBase {
31public:32public:
@@ -11,131 +11,8 @@
11#include "reduce_scatter_executor_base.h"11#include "reduce_scatter_executor_base.h"
12 12 
13namespace ops_hccl_experimental {13namespace ops_hccl_experimental {
14-using ops_hccl::ExecMem;
15-using ops_hccl::HCCL_INTERNODE_MAX_DATA_RATE;
16-using ops_hccl::RDMA_SEND_MAX_SIZE;
17-using ops_hccl::SDMA_SEND_MAX_SIZE;
18 14 
19-ReduceScatterExecutorBase::ReduceScatterExecutorBase() : ExecutorBase() {}15+ReduceScatterExecutorBase::ReduceScatterExecutorBase() : CollExecutorBaseExperimental() {}
20- 
21-// 执行入口
22-HcclResult ReduceScatterExecutorBase::Orchestrate(const OpParam& param, AlgResourceCtx* resCtx)
23-{
24- HcclUs startut = TIME_NOW();
25- topoInfo_ = &(resCtx->topoInfo);
26- algResource_ = resCtx;
27- tag_ = std::string(param.tag);
28- algType_ = resCtx->algType;
29- unitSize_ = HCCL_SIZE_TABLE[param.DataDes.dataType];
30- 
31- CHK_PTR_NULL(param.inputPtr);
32- CHK_PTR_NULL(param.outputPtr);
33- 
34- // 做参数的还原
35- ThreadHandle* threadHandlePtr
36- = reinterpret_cast<ThreadHandle*>(reinterpret_cast<char*>(algResource_) + sizeof(AlgResourceCtx));
37- ChannelInfo* channelInfoPtr = reinterpret_cast<ChannelInfo*>(
38- reinterpret_cast<char*>(threadHandlePtr) + sizeof(ThreadHandle) * (algResource_->slaveThreadNum + 1));
39- 
40- HCCL_DEBUG("[ReduceScatterExecutorBase][Orchestrate] slaveThreadNum[%u]", algResource_->slaveThreadNum);
41- for (u32 i = 0; i < algResource_->slaveThreadNum + 1; i++) {
42- HCCL_DEBUG("[ReduceScatterExecutorBase][Orchestrate] threadHandle[%u]=[%llu]", i, threadHandlePtr[i]);
43- if (i == 0) {
44- thread_ = threadHandlePtr[i];
45- } else {
46- slaveThreads_.push_back(threadHandlePtr[i]);
47- }
48- }
49- AlgHierarchyInfo& algHierarchyInfo = resCtx->algHierarchyInfo;
50- channels_.resize(algHierarchyInfo.levels);
51- for (u32 level = 0; level < algHierarchyInfo.levels; level++) {
52- u32 curLevelRankSize = algHierarchyInfo.infos[level].localRankSize;
53- channels_[level].resize(curLevelRankSize);
54- for (u32 rank = 0; rank < curLevelRankSize; rank++) {
55- channels_[level][rank] = channelInfoPtr[rank];
56- }
57- channelInfoPtr += curLevelRankSize;
58- }
59- 
60- HcclResult ret = RunLoop(param);
61- CHK_PRT_RET(
62- ret != HCCL_SUCCESS,
63- HCCL_ERROR(
64- "[ReduceScatterExecutorBase][Orchestrate]errNo[0x%016llx] ReduceScatter executor kernel run failed",
65- HCCL_ERROR_CODE(ret)),
66- ret);
67- HCCL_INFO(
68- "[ReduceScatterExecutorBase][Orchestrate]tag[%s] ReduceScatter executor orchestrate success, take time "
69- "[%lld]us.",
70- param.tag, DURATION_US(TIME_NOW() - startut));
71- return HCCL_SUCCESS;
72-}
73- 
74-bool ReduceScatterExecutorBase::IsHugeData(u64 curSize) const
75-{
76- bool hugeData = curSize * topoInfo_->userRankSize / HCCL_INTERNODE_MAX_DATA_RATE > RDMA_SEND_MAX_SIZE
77- || curSize > SDMA_SEND_MAX_SIZE;
78- return hugeData;
79-}
80- 
81-HcclResult ReduceScatterExecutorBase::RunLoop(const OpParam& param)
82-{
83- u64 totalRecvCount = param.DataDes.count;
84- u64 totalRecvSize = totalRecvCount * unitSize_;
85- 
86- u8* curUserInputPtr = static_cast<u8*>(param.inputPtr);
87- u8* curUserOutputPtr = static_cast<u8*>(param.outputPtr);
88- auto cclInputMem = algResource_->cclInputMem;
89- auto cclOutputMem = algResource_->cclOutputMem;
90- CHK_PRT_RET(
91- (cclInputMem.size == 0), HCCL_ERROR("[ReduceScatterExecutorBase][RunLoop]cclBuffer size is zero"), HCCL_E_PARA);
92- 
93- if (param.engine == CommEngine::COMM_ENGINE_CPU_TS || param.engine == CommEngine::COMM_ENGINE_CPU) {
94- int32_t ret = HcommAcquireComm(param.commName);
95- CHK_PRT_RET(
96- ret != HCCL_SUCCESS, HCCL_ERROR("[%s] [%s] HcommAcquireComm failed ", __func__, param.commName),
97- static_cast<HcclResult>(ret));
98- }
99- 
100- u64 curRecvCount = totalRecvCount;
101- u64 curRecvSize = curRecvCount * unitSize_;
102- u64 curSendSize = topoInfo_->userRankSize * curRecvSize;
103- 
104-#ifndef AICPU_COMPILE
105- if (!IsHugeData(curRecvSize)) {
106- CHK_RET(static_cast<HcclResult>(HcommBatchModeStart(param.algTag)));
107- }
108-#endif
109- HcclMem curInputMem{cclInputMem.type, cclInputMem.addr, curSendSize};
110- HcclMem curOutputMem{cclOutputMem.type, cclOutputMem.addr, curRecvSize};
111- 
112- ExecMem execMem;
113- execMem.count = curRecvCount;
114- execMem.inputMem = curInputMem;
115- execMem.outputMem = curOutputMem;
116- execMem.inputPtr = curUserInputPtr;
117- execMem.outputPtr = curUserOutputPtr;
118- 
119- HCCL_DEBUG(
120- "[ReduceScatterExecutorBase][RunLoop] curUserInputPtr[%p], curUserOutputPtr[%p], "
121- "curRecvCount[%llu], curRecvSize[%llu], curSendSize[%llu], inputPtr[%p], outputPtr[%p]",
122- curUserInputPtr, curUserOutputPtr, curRecvCount, curRecvSize, curSendSize, curInputMem.addr, curOutputMem.addr);
123- 
124- CHK_RET(KernelRun(param, execMem));
125- 
126-#ifndef AICPU_COMPILE
127- if (!IsHugeData(curRecvSize)) {
128- CHK_RET(static_cast<HcclResult>(HcommBatchModeEnd(param.algTag)));
129- }
130-#endif
131- if (param.engine == CommEngine::COMM_ENGINE_CPU_TS || param.engine == CommEngine::COMM_ENGINE_CPU) {
132- int32_t ret = HcommReleaseComm(param.commName);
133- CHK_PRT_RET(
134- ret != HCCL_SUCCESS, HCCL_ERROR("[%s] [%s] HcommReleaseComm failed ", __func__, param.commName),
135- static_cast<HcclResult>(ret));
136- }
137- return HCCL_SUCCESS;
138-}
139 16 
140HcclResult ReduceScatterExecutorBase::CalcResRequest(17HcclResult ReduceScatterExecutorBase::CalcResRequest(
141 HcclComm comm, const OpParam& param, TopoInfo* topoInfo, AlgHierarchyInfo& algHierarchyInfo,18 HcclComm comm, const OpParam& param, TopoInfo* topoInfo, AlgHierarchyInfo& algHierarchyInfo,
@@ -15,44 +15,29 @@
15#include "executor_base.h"15#include "executor_base.h"
16#include "config_log.h"16#include "config_log.h"
17#include "alg_template_base_experimental.h"17#include "alg_template_base_experimental.h"
18+#include "coll_executor_base_experimental.h"
18 19 
19namespace ops_hccl_experimental {20namespace ops_hccl_experimental {
20using ops_hccl::AlgHierarchyInfo;21using ops_hccl::AlgHierarchyInfo;
21-using ops_hccl::AlgResourceCtx;
22using ops_hccl::AlgResourceRequest;22using ops_hccl::AlgResourceRequest;
23using ops_hccl::AlgType;23using ops_hccl::AlgType;
24-using ops_hccl::ChannelInfo;
25-using ops_hccl::ExecutorBase;
26using ops_hccl::OpParam;24using ops_hccl::OpParam;
27using ops_hccl::Slice;25using ops_hccl::Slice;
28using ops_hccl::TopoInfo;26using ops_hccl::TopoInfo;
29 27 
30-class ReduceScatterExecutorBase : public ExecutorBase {28+class ReduceScatterExecutorBase : public CollExecutorBaseExperimental {
31public:29public:
32 explicit ReduceScatterExecutorBase();30 explicit ReduceScatterExecutorBase();
33 ~ReduceScatterExecutorBase() override = default;31 ~ReduceScatterExecutorBase() override = default;
34 32 
35- HcclResult Orchestrate(const OpParam& param, AlgResourceCtx* resCtx) override;
36- 
37 /* *************** 资源计算 *************** */33 /* *************** 资源计算 *************** */
38 HcclResult CalcResRequest(34 HcclResult CalcResRequest(
39 HcclComm comm, const OpParam& param, TopoInfo* topoInfo, AlgHierarchyInfo& algHierarchyInfo,35 HcclComm comm, const OpParam& param, TopoInfo* topoInfo, AlgHierarchyInfo& algHierarchyInfo,
40 AlgResourceRequest& resourceRequest, AlgType& algType) override;36 AlgResourceRequest& resourceRequest, AlgType& algType) override;
41 37 
42protected:38protected:
43- // 用于需要Loop的Executor
44- virtual HcclResult RunLoop(const OpParam& param);
45- 
46 /* *************** 通用工具 *************** */39 /* *************** 通用工具 *************** */
47 virtual HcclResult PrepareDataSlice(u64 dataCount, u32 unitSize, u32 sliceNum, std::vector<Slice>& dataSlice);40 virtual HcclResult PrepareDataSlice(u64 dataCount, u32 unitSize, u32 sliceNum, std::vector<Slice>& dataSlice);
48- bool IsHugeData(u64 curSize) const;
49- 
50- ThreadHandle thread_ = 0;
51- std::vector<ThreadHandle> slaveThreads_;
52- std::vector<std::vector<ChannelInfo>> channels_;
53- OpParam param_;
54- u32 unitSize_;
55- u32 root_ = INVALID_VALUE_RANKID;
56};41};
57 42 
58} // namespace ops_hccl_experimental43} // namespace ops_hccl_experimental
@@ -12,71 +12,12 @@
12 12 
13namespace ops_hccl_experimental {13namespace ops_hccl_experimental {
14using ops_hccl::ExecMem;14using ops_hccl::ExecMem;
15-using ops_hccl::HCCL_INTERNODE_MAX_DATA_RATE;
16-using ops_hccl::RDMA_SEND_MAX_SIZE;
17-using ops_hccl::SDMA_SEND_MAX_SIZE;
18 15 
19-ReduceScatterVExecutorBase::ReduceScatterVExecutorBase() : ExecutorBase() {}16+ReduceScatterVExecutorBase::ReduceScatterVExecutorBase() : CollExecutorBaseExperimental() {}
20 17 
21-// 执行入口18+u32 ReduceScatterVExecutorBase::CalcUnitSize(const OpParam& param) const
22-HcclResult ReduceScatterVExecutorBase::Orchestrate(const OpParam& param, AlgResourceCtx* resCtx)
23{19{
24- HcclUs startut = TIME_NOW();20+ return HCCL_SIZE_TABLE[param.vDataDes.dataType];
25- topoInfo_ = &(resCtx->topoInfo);
26- algResource_ = resCtx;
27- tag_ = std::string(param.tag);
28- algType_ = resCtx->algType;
29- unitSize_ = HCCL_SIZE_TABLE[param.vDataDes.dataType];
30- 
31- CHK_PTR_NULL(param.inputPtr);
32- CHK_PTR_NULL(param.outputPtr);
33- 
34- // 做参数的还原
35- ThreadHandle* threadHandlePtr
36- = reinterpret_cast<ThreadHandle*>(reinterpret_cast<char*>(algResource_) + sizeof(AlgResourceCtx));
37- ChannelInfo* channelInfoPtr = reinterpret_cast<ChannelInfo*>(
38- reinterpret_cast<char*>(threadHandlePtr) + sizeof(ThreadHandle) * (algResource_->slaveThreadNum + 1));
39- 
40- HCCL_DEBUG("[ReduceScatterVExecutorBase][Orchestrate] slaveThreadNum[%u]", algResource_->slaveThreadNum);
41- for (u32 i = 0; i < algResource_->slaveThreadNum + 1; i++) {
42- HCCL_DEBUG("[ReduceScatterVExecutorBase][Orchestrate] threadHandle[%u]=[%llu]", i, threadHandlePtr[i]);
43- if (i == 0) {
44- thread_ = threadHandlePtr[i];
45- } else {
46- slaveThreads_.push_back(threadHandlePtr[i]);
47- }
48- }
49- AlgHierarchyInfo& algHierarchyInfo = resCtx->algHierarchyInfo;
50- channels_.resize(algHierarchyInfo.levels);
51- for (u32 level = 0; level < algHierarchyInfo.levels; level++) {
52- u32 curLevelRankSize = algHierarchyInfo.infos[level].localRankSize;
53- channels_[level].resize(curLevelRankSize);
54- for (u32 rank = 0; rank < curLevelRankSize; rank++) {
55- channels_[level][rank] = channelInfoPtr[rank];
56- }
57- channelInfoPtr += curLevelRankSize;
58- }
59- 
60- HcclResult ret = RunLoop(param);
61- CHK_PRT_RET(
62- ret != HCCL_SUCCESS,
63- HCCL_ERROR(
64- "[ReduceScatterVExecutorBase][Orchestrate]errNo[0x%016llx]"
65- " ReduceScatterV executor kernel run failed",
66- HCCL_ERROR_CODE(ret)),
67- ret);
68- HCCL_INFO(
69- "[ReduceScatterVExecutorBase][Orchestrate]tag[%s]"
70- " ReduceScatterV executor orchestrate success, take time [%lld]us.",
71- param.tag, DURATION_US(TIME_NOW() - startut));
72- return HCCL_SUCCESS;
73-}
74- 
75-bool ReduceScatterVExecutorBase::IsHugeData(u64 curSize) const
76-{
77- bool hugeData = curSize * topoInfo_->userRankSize / HCCL_INTERNODE_MAX_DATA_RATE > RDMA_SEND_MAX_SIZE
78- || curSize > SDMA_SEND_MAX_SIZE;
79- return hugeData;
80}21}
81 22 
82HcclResult ReduceScatterVExecutorBase::AcquireCommIfNeeded(const OpParam& param)23HcclResult ReduceScatterVExecutorBase::AcquireCommIfNeeded(const OpParam& param)
@@ -15,14 +15,12 @@
15#include "executor_base.h"15#include "executor_base.h"
16#include "config_log.h"16#include "config_log.h"
17#include "alg_template_base_experimental.h"17#include "alg_template_base_experimental.h"
18+#include "coll_executor_base_experimental.h"
18 19 
19namespace ops_hccl_experimental {20namespace ops_hccl_experimental {
20using ops_hccl::AlgHierarchyInfo;21using ops_hccl::AlgHierarchyInfo;
21-using ops_hccl::AlgResourceCtx;
22using ops_hccl::AlgResourceRequest;22using ops_hccl::AlgResourceRequest;
23using ops_hccl::AlgType;23using ops_hccl::AlgType;
24-using ops_hccl::ChannelInfo;
25-using ops_hccl::ExecutorBase;
26using ops_hccl::OpParam;24using ops_hccl::OpParam;
27using ops_hccl::Slice;25using ops_hccl::Slice;
28using ops_hccl::TopoInfo;26using ops_hccl::TopoInfo;
@@ -31,13 +29,11 @@ using ops_hccl::TopoInfo;
31// 两侧统一引用本常量, 禁止再各自定义29// 两侧统一引用本常量, 禁止再各自定义
32constexpr u32 BIRS_THREAD_NUM = 2;30constexpr u32 BIRS_THREAD_NUM = 2;
33 31 
34-class ReduceScatterVExecutorBase : public ExecutorBase {32+class ReduceScatterVExecutorBase : public CollExecutorBaseExperimental {
35public:33public:
36 explicit ReduceScatterVExecutorBase();34 explicit ReduceScatterVExecutorBase();
37 ~ReduceScatterVExecutorBase() override = default;35 ~ReduceScatterVExecutorBase() override = default;
38 36 
39- HcclResult Orchestrate(const OpParam& param, AlgResourceCtx* resCtx) override;
40- 
41 /* *************** 资源计算 *************** */37 /* *************** 资源计算 *************** */
42 HcclResult CalcResRequest(38 HcclResult CalcResRequest(
43 HcclComm comm, const OpParam& param, TopoInfo* topoInfo, AlgHierarchyInfo& algHierarchyInfo,39 HcclComm comm, const OpParam& param, TopoInfo* topoInfo, AlgHierarchyInfo& algHierarchyInfo,
@@ -45,20 +41,15 @@ public:
45 41 
46protected:42protected:
47 // 用于需要Loop的Executor43 // 用于需要Loop的Executor
48- virtual HcclResult RunLoop(const OpParam& param);44+ HcclResult RunLoop(const OpParam& param) override;
49 45 
50 /* *************** 通用工具 *************** */46 /* *************** 通用工具 *************** */
51 // 根据变长counts/displs准备每个rank的数据切片(变长)47 // 根据变长counts/displs准备每个rank的数据切片(变长)
52 HcclResult PrepareDataSliceV(48 HcclResult PrepareDataSliceV(
53 const u64* sendCounts, const u64* sendDispls, u32 unitSize, u32 sliceNum, std::vector<Slice>& dataSlice);49 const u64* sendCounts, const u64* sendDispls, u32 unitSize, u32 sliceNum, std::vector<Slice>& dataSlice);
54- bool IsHugeData(u64 curSize) const;
55 HcclResult AcquireCommIfNeeded(const OpParam& param);50 HcclResult AcquireCommIfNeeded(const OpParam& param);
56 HcclResult ReleaseCommIfNeeded(const OpParam& param);51 HcclResult ReleaseCommIfNeeded(const OpParam& param);
57- 52+ u32 CalcUnitSize(const OpParam& param) const override;
58- ThreadHandle thread_ = 0;
59- std::vector<ThreadHandle> slaveThreads_;
60- std::vector<std::vector<ChannelInfo>> channels_;
61- u32 unitSize_;
62};53};
63 54 
64} // namespace ops_hccl_experimental55} // namespace ops_hccl_experimental
@@ -32,7 +32,11 @@ HcclResult HcclAllReduce(
32 bool isOutPlace = false;32 bool isOutPlace = false;
33 CHK_RET(IsOutPlaceDevice(isOutPlace));33 CHK_RET(IsOutPlaceDevice(isOutPlace));
34 if (!isOutPlace) {34 if (!isOutPlace) {
35+#ifdef ENABLE_EXPERIMENTAL
36+ return ops_hccl_experimental::AllReduceExperimental(sendBuf, recvBuf, count, dataType, op, comm, stream);
37+#else
35 return HcclAllReduceInner(sendBuf, recvBuf, count, dataType, op, comm, stream);38 return HcclAllReduceInner(sendBuf, recvBuf, count, dataType, op, comm, stream);
39+#endif
36 }40 }
37 CHK_PRT_RET(count == 0, HCCL_WARNING("input count is 0, return all reduce success"), HCCL_SUCCESS);41 CHK_PRT_RET(count == 0, HCCL_WARNING("input count is 0, return all reduce success"), HCCL_SUCCESS);
38 42 
@@ -18,6 +18,9 @@
18#include "executor_v2_base.h"18#include "executor_v2_base.h"
19#include "alg_type.h"19#include "alg_type.h"
20#include "execute_selector.h"20#include "execute_selector.h"
21+#ifdef ENABLE_EXPERIMENTAL
22+#include "all_reduce_op_experimental.h"
23+#endif
21 24 
22#ifdef __cplusplus25#ifdef __cplusplus
23extern "C" {26extern "C" {
@@ -38,6 +38,7 @@ function(add_st_test OP_NAME OP_SRC)
38 ${HCCL_DEV_BASE}/src/ops/op_common38 ${HCCL_DEV_BASE}/src/ops/op_common
39 ${HCCL_DEV_BASE}/src/ops/op_common/inc39 ${HCCL_DEV_BASE}/src/ops/op_common/inc
40 ${HCCL_DEV_BASE}/src/common/hcomm_dlsym40 ${HCCL_DEV_BASE}/src/common/hcomm_dlsym
41+ ${HCCL_DEV_BASE}/src/common/hcomm_dlsym/ccu
41 42 
42 ${UTILS_DIR}/sim_world43 ${UTILS_DIR}/sim_world
43 ${UTILS_DIR}/common/utils44 ${UTILS_DIR}/common/utils
@@ -134,6 +135,8 @@ if("all" IN_LIST ST_TASKS OR "reduce_scatter" IN_LIST ST_TASKS)
134endif()135endif()
135# a3(BIRS/BIRS-V) 用例依赖 experimental 构建的 libhccl(HCCL_BIRS_ENABLE 选路);136# a3(BIRS/BIRS-V) 用例依赖 experimental 构建的 libhccl(HCCL_BIRS_ENABLE 选路);
136# 非 experimental 构建下 HcclReduceScatter(V)Inner 在 ST 打桩为 E_NOT_SUPPORT, 故仅在 ON 时注册137# 非 experimental 构建下 HcclReduceScatter(V)Inner 在 ST 打桩为 E_NOT_SUPPORT, 故仅在 ON 时注册
138+# a3(AllReduceBIAR) 用例依赖 experimental 构建的 libhccl(HCCL_BIRS_ENABLE 选路);
139+# 非 experimental 构建下老流程在 DEV_TYPE_910_93 仿真拓扑无可用算法(taskQueues 为空), 故仅在 ON 时注册
137if(ENABLE_EXPERIMENTAL)140if(ENABLE_EXPERIMENTAL)
138 if("all" IN_LIST ST_TASKS OR "reduce_scatter_v_a3" IN_LIST ST_TASKS)141 if("all" IN_LIST ST_TASKS OR "reduce_scatter_v_a3" IN_LIST ST_TASKS)
139 add_st_test(reduce_scatter_v_a3 reduce_scatter_v_testcase_a3.cc)142 add_st_test(reduce_scatter_v_a3 reduce_scatter_v_testcase_a3.cc)
@@ -141,6 +144,9 @@ if(ENABLE_EXPERIMENTAL)
141 if("all" IN_LIST ST_TASKS OR "reduce_scatter_a3" IN_LIST ST_TASKS)144 if("all" IN_LIST ST_TASKS OR "reduce_scatter_a3" IN_LIST ST_TASKS)
142 add_st_test(reduce_scatter_a3 reduce_scatter_testcase_a3.cc)145 add_st_test(reduce_scatter_a3 reduce_scatter_testcase_a3.cc)
143 endif()146 endif()
147+ if("all" IN_LIST ST_TASKS OR "all_reduce_a3" IN_LIST ST_TASKS)
148+ add_st_test(all_reduce_a3 all_reduce_testcase_a3.cc)
149+ endif()
144endif()150endif()
145if("all" IN_LIST ST_TASKS OR "reduce_scatter_3level" IN_LIST ST_TASKS)151if("all" IN_LIST ST_TASKS OR "reduce_scatter_3level" IN_LIST ST_TASKS)
146 add_st_test(reduce_scatter_3level reduce_scatter_3level_testcase.cc)152 add_st_test(reduce_scatter_3level reduce_scatter_3level_testcase.cc)
@@ -0,0 +1,257 @@
1+/**
2+ * Copyright (c) 2026 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 "alg_param.h"
12+#include "gtest/gtest.h"
13+#include "sim_world.h"
14+#include "hccl.h"
15+#include "hccl/hccl_types.h"
16+#include "acl/acl_rt.h"
17+#include "hccl_verifier.h"
18+#include "check_utils.h"
19+#include <thread>
20+#include "alg_env_config.h"
21+ 
22+using namespace HcclSim;
23+using namespace ops_hccl;
24+ 
25+class ST_ALL_REDUCE_TEST_A3 : public ::testing::Test {
26+protected:
27+ void SetUp() override { ResetAlgEnvConfigInitState(); }
28+ void TearDown() override
29+ {
30+ unsetenv("HCCL_OP_EXPANSION_MODE");
31+ unsetenv("HCCL_INDEPENDENT_OP");
32+ unsetenv("HCCL_ENABLE_OPEN_AICPU");
33+ unsetenv("HCCL_BIRS_ENABLE");
34+ }
35+ static void SetUpTestCase() {}
36+ static void TearDownTestCase() {}
37+ 
38+ void RunAllReduceBiarA3(
39+ const TopoMeta& topoMeta, const u64& count, const HcclDataType& dataType, const HcclReduceOp& reduceOp)
40+ {
41+ SimWorld::Global()->Init(topoMeta, HcclDevType::DEV_TYPE_910_93);
42+ 
43+ setenv("HCCL_OP_EXPANSION_MODE", "AI_CPU", 1);
44+ setenv("HCCL_INDEPENDENT_OP", "1", 1);
45+ setenv("HCCL_BIRS_ENABLE", "TRUE", 1);
46+ 
47+ // 算子执行参数设置
48+ auto rankSize = 0;
49+ for (u32 i = 0; i < topoMeta[0].size(); i++)
50+ rankSize += topoMeta[0][i].size(); // 参与集合通信的卡数(同topoMeta卡数一致)
51+ auto dataUnitSize = DATATYPE_SIZE_TABLE[dataType];
52+ // 多线程运行ReduceScatter算子
53+ std::vector<std::thread> threads;
54+ for (auto rankId = 0; rankId < rankSize; ++rankId) {
55+ threads.emplace_back([=]() {
56+ // 1.SetDevice
57+ aclrtSetDevice(rankId);
58+ 
59+ // 2.创建流
60+ aclrtStream stream = nullptr;
61+ aclrtCreateStream(&stream);
62+ 
63+ // 3.初始化通信域
64+ HcclComm comm = nullptr;
65+ CHK_RET(HcclCommInitClusterInfo("./ranktable.json", rankId, &comm));
66+ 
67+ void* sendBuf = nullptr;
68+ void* recvBuf = nullptr;
69+ u64 sendBufSize = count * dataUnitSize; // 数据量转化为字节数
70+ u64 recvBufSize = count * dataUnitSize;
71+ // 打桩实现,仿真运行需标记内存是INPUT和OUTPUT
72+ if (aclrtMalloc(&sendBuf, sendBufSize, static_cast<aclrtMemMallocPolicy>(BUFFER_INPUT_MARK))
73+ != ACL_SUCCESS) {
74+ return HcclResult::HCCL_E_MEMORY;
75+ }
76+ if (aclrtMalloc(&recvBuf, recvBufSize, static_cast<aclrtMemMallocPolicy>(BUFFER_OUTPUT_MARK))
77+ != ACL_SUCCESS) {
78+ return HcclResult::HCCL_E_MEMORY;
79+ }
80+ 
81+ // 4.算子下发
82+ CHK_RET(HcclAllReduce(sendBuf, recvBuf, count, dataType, reduceOp, comm, stream));
83+ 
84+ // 5.销毁通信域
85+ CHK_RET(HcclCommDestroy(comm));
86+ return HCCL_SUCCESS;
87+ });
88+ }
89+ 
90+ // 等待多线程执行完成
91+ for (auto& thread : threads) {
92+ thread.join();
93+ }
94+ 
95+ // 结果成图校验
96+ auto taskQueues = SimTaskQueue::Global()->GetAllRankTaskQueues();
97+ HcclResult res = CheckAllReduce(taskQueues, rankSize, dataType, count, reduceOp);
98+ EXPECT_TRUE(res == HCCL_SUCCESS);
99+ 
100+ // 资源清理
101+ SimWorld::Global()->Deinit();
102+ }
103+};
104+ 
105+TEST_F(ST_ALL_REDUCE_TEST_A3, st_all_reduce_114_test)
106+{
107+ // 仿真模型初始化
108+ TopoMeta topoMeta{{{0, 1, 2, 3}}}; // 三维数组指定超节点-Server-Device信息
109+ auto count = 400; // 单卡数据量
110+ auto dataType = HcclDataType::HCCL_DATA_TYPE_INT32; // 数据类型
111+ auto reduceOp = HcclReduceOp::HCCL_REDUCE_SUM;
112+ RunAllReduceBiarA3(topoMeta, count, dataType, reduceOp);
113+}
114+ 
115+TEST_F(ST_ALL_REDUCE_TEST_A3, st_all_reduce_114_rem_test)
116+{
117+ // 仿真模型初始化
118+ TopoMeta topoMeta{{{0, 1, 2, 3}}}; // 三维数组指定超节点-Server-Device信息
119+ auto count = 402; // 单卡数据量
120+ auto dataType = HcclDataType::HCCL_DATA_TYPE_INT32; // 数据类型
121+ auto reduceOp = HcclReduceOp::HCCL_REDUCE_SUM;
122+ RunAllReduceBiarA3(topoMeta, count, dataType, reduceOp);
123+}
124+ 
125+TEST_F(ST_ALL_REDUCE_TEST_A3, st_all_reduce_116_test)
126+{
127+ TopoMeta topoMeta{{{0, 1, 2, 3, 4, 5}}};
128+ auto count = 600;
129+ auto dataType = HcclDataType::HCCL_DATA_TYPE_INT32;
130+ auto reduceOp = HcclReduceOp::HCCL_REDUCE_SUM;
131+ RunAllReduceBiarA3(topoMeta, count, dataType, reduceOp);
132+}
133+ 
134+TEST_F(ST_ALL_REDUCE_TEST_A3, st_all_reduce_116_rem_test)
135+{
136+ TopoMeta topoMeta{{{0, 1, 2, 3, 4, 5}}};
137+ auto count = 602;
138+ auto dataType = HcclDataType::HCCL_DATA_TYPE_INT32;
139+ auto reduceOp = HcclReduceOp::HCCL_REDUCE_SUM;
140+ RunAllReduceBiarA3(topoMeta, count, dataType, reduceOp);
141+}
142+ 
143+TEST_F(ST_ALL_REDUCE_TEST_A3, st_all_reduce_118_test)
144+{
145+ TopoMeta topoMeta{{{0, 1, 2, 3, 4, 5, 6, 7}}};
146+ auto count = 800;
147+ auto dataType = HcclDataType::HCCL_DATA_TYPE_INT32;
148+ auto reduceOp = HcclReduceOp::HCCL_REDUCE_SUM;
149+ RunAllReduceBiarA3(topoMeta, count, dataType, reduceOp);
150+}
151+ 
152+TEST_F(ST_ALL_REDUCE_TEST_A3, st_all_reduce_118_rem_test)
153+{
154+ TopoMeta topoMeta{{{0, 1, 2, 3, 4, 5, 6, 7}}};
155+ auto count = 803;
156+ auto dataType = HcclDataType::HCCL_DATA_TYPE_INT32;
157+ auto reduceOp = HcclReduceOp::HCCL_REDUCE_SUM;
158+ RunAllReduceBiarA3(topoMeta, count, dataType, reduceOp);
159+}
160+ 
161+TEST_F(ST_ALL_REDUCE_TEST_A3, st_all_reduce_1110_test)
162+{
163+ // 仿真模型初始化
164+ TopoMeta topoMeta{{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}}; // 三维数组指定超节点-Server-Device信息
165+ auto count = 1000; // 单卡数据量
166+ auto dataType = HcclDataType::HCCL_DATA_TYPE_INT32; // 数据类型
167+ auto reduceOp = HcclReduceOp::HCCL_REDUCE_SUM;
168+ RunAllReduceBiarA3(topoMeta, count, dataType, reduceOp);
169+}
170+ 
171+TEST_F(ST_ALL_REDUCE_TEST_A3, st_all_reduce_1112_test)
172+{
173+ // 仿真模型初始化
174+ TopoMeta topoMeta{{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}}}; // 三维数组指定超节点-Server-Device信息
175+ auto count = 1200; // 单卡数据量
176+ auto dataType = HcclDataType::HCCL_DATA_TYPE_INT32; // 数据类型
177+ auto reduceOp = HcclReduceOp::HCCL_REDUCE_SUM;
178+ RunAllReduceBiarA3(topoMeta, count, dataType, reduceOp);
179+}
180+ 
181+TEST_F(ST_ALL_REDUCE_TEST_A3, st_all_reduce_1114_test)
182+{
183+ // 仿真模型初始化
184+ TopoMeta topoMeta{{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}}}; // 三维数组指定超节点-Server-Device信息
185+ auto count = 1400; // 单卡数据量
186+ auto dataType = HcclDataType::HCCL_DATA_TYPE_INT32; // 数据类型
187+ auto reduceOp = HcclReduceOp::HCCL_REDUCE_SUM;
188+ RunAllReduceBiarA3(topoMeta, count, dataType, reduceOp);
189+}
190+ 
191+TEST_F(ST_ALL_REDUCE_TEST_A3, st_all_reduce_1116_test)
192+{
193+ TopoMeta topoMeta{{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}};
194+ auto count = 1600;
195+ auto dataType = HcclDataType::HCCL_DATA_TYPE_INT32;
196+ auto reduceOp = HcclReduceOp::HCCL_REDUCE_SUM;
197+ RunAllReduceBiarA3(topoMeta, count, dataType, reduceOp);
198+}
199+ 
200+TEST_F(ST_ALL_REDUCE_TEST_A3, st_all_reduce_1116_rem_test)
201+{
202+ TopoMeta topoMeta{{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}};
203+ auto count = 1603;
204+ auto dataType = HcclDataType::HCCL_DATA_TYPE_INT32;
205+ auto reduceOp = HcclReduceOp::HCCL_REDUCE_SUM;
206+ RunAllReduceBiarA3(topoMeta, count, dataType, reduceOp);
207+}
208+ 
209+TEST_F(ST_ALL_REDUCE_TEST_A3, st_all_reduce_18_min_test)
210+{
211+ TopoMeta topoMeta{{{0, 1, 2, 3, 4, 5, 6, 7}}};
212+ auto count = 800;
213+ auto dataType = HcclDataType::HCCL_DATA_TYPE_INT32;
214+ auto reduceOp = HcclReduceOp::HCCL_REDUCE_MIN;
215+ RunAllReduceBiarA3(topoMeta, count, dataType, reduceOp);
216+}
217+ 
218+TEST_F(ST_ALL_REDUCE_TEST_A3, st_all_reduce_116_rem_max_test)
219+{
220+ TopoMeta topoMeta{{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}};
221+ auto count = 1603;
222+ auto dataType = HcclDataType::HCCL_DATA_TYPE_INT32;
223+ auto reduceOp = HcclReduceOp::HCCL_REDUCE_MAX;
224+ RunAllReduceBiarA3(topoMeta, count, dataType, reduceOp);
225+}
226+ 
227+TEST_F(ST_ALL_REDUCE_TEST_A3, st_all_reduce_1416_test)
228+{
229+ // 仿真模型初始化
230+ TopoMeta topoMeta;
231+ std::vector<u32> args{1, 4, 16};
232+ for (int i = 0; i < args[0]; i++) {
233+ SuperPodMeta superPodMeta;
234+ for (int j = 0; j < args[1]; j++) {
235+ ServerMeta serverMate;
236+ for (int k = 0; k < args[2]; k++) {
237+ serverMate.push_back((unsigned int)k);
238+ }
239+ superPodMeta.push_back(serverMate);
240+ }
241+ topoMeta.push_back(superPodMeta);
242+ }
243+ auto recvCount = 6400; // 单卡数据量
244+ auto dataType = HcclDataType::HCCL_DATA_TYPE_INT32; // 数据类型
245+ auto reduceOp = HcclReduceOp::HCCL_REDUCE_SUM;
246+ RunAllReduceBiarA3(topoMeta, recvCount, dataType, reduceOp);
247+}
248+ 
249+TEST_F(ST_ALL_REDUCE_TEST_A3, st_all_reduce_1416_max_test)
250+{
251+ TopoMeta topoMeta;
252+ GenTopoMeta(topoMeta, 1, 4, 16);
253+ auto count = 640;
254+ auto dataType = HcclDataType::HCCL_DATA_TYPE_INT32;
255+ auto reduceOp = HcclReduceOp::HCCL_REDUCE_MAX;
256+ RunAllReduceBiarA3(topoMeta, count, dataType, reduceOp);
257+}
@@ -8,6 +8,7 @@
8 * See LICENSE in the root of the software repository for the full text of the License.8 * See LICENSE in the root of the software repository for the full text of the License.
9 */9 */
10 10 
11+#include "alg_param.h"
11#include "gtest/gtest.h"12#include "gtest/gtest.h"
12#include "sim_world.h"13#include "sim_world.h"
13#include "hccl.h"14#include "hccl.h"
@@ -47,7 +48,7 @@ protected:
47 auto rankSize = 0;48 auto rankSize = 0;
48 for (u32 i = 0; i < topoMeta[0].size(); i++)49 for (u32 i = 0; i < topoMeta[0].size(); i++)
49 rankSize += topoMeta[0][i].size(); // 参与集合通信的卡数(同topoMeta卡数一致)50 rankSize += topoMeta[0][i].size(); // 参与集合通信的卡数(同topoMeta卡数一致)
50- auto dataUnitSize = sizeof(dataType);51+ auto dataUnitSize = DATATYPE_SIZE_TABLE[dataType];
51 // 多线程运行ReduceScatter算子52 // 多线程运行ReduceScatter算子
52 std::vector<std::thread> threads;53 std::vector<std::thread> threads;
53 for (auto rankId = 0; rankId < rankSize; ++rankId) {54 for (auto rankId = 0; rankId < rankSize; ++rankId) {
@@ -14,7 +14,8 @@ add_subdirectory(common/topo_match)
14add_subdirectory(alltoall_hier)14add_subdirectory(alltoall_hier)
15# recursive_executor 测试仅在 --experimental 构建(ENABLE_EXPERIMENTAL=ON)时编译15# recursive_executor 测试仅在 --experimental 构建(ENABLE_EXPERIMENTAL=ON)时编译
16if(ENABLE_EXPERIMENTAL)16if(ENABLE_EXPERIMENTAL)
17- add_subdirectory(recursive_executor)
18 add_subdirectory(reduce_scatter_birs)17 add_subdirectory(reduce_scatter_birs)
18+ add_subdirectory(recursive_executor)
19+ add_subdirectory(all_reduce_biar)
19 add_subdirectory(reduce_scatter_v_birs)20 add_subdirectory(reduce_scatter_v_birs)
20endif()21endif()
@@ -0,0 +1,140 @@
1+# -----------------------------------------------------------------------------------------------------------
2+# Copyright (c) 2026 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+set(_repo_root ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
12+ 
13+set(_biar_ut_include_dirs
14+ ${_repo_root}/experimental/ops/all_reduce/biar
15+ ${_repo_root}/experimental/ops/all_reduce/biar/template
16+ ${_repo_root}/experimental/ops/op_common
17+ ${_repo_root}/experimental/ops/op_common/template
18+ ${_repo_root}/src/ops/op_common/inc
19+ ${_repo_root}/src/ops/op_common
20+ ${_repo_root}/src/ops/op_common/algorithm/template
21+ ${_repo_root}/src/ops/op_common/algorithm/template/registry
22+ ${_repo_root}/src/ops/op_common/algorithm/template/wrapper
23+ ${_repo_root}/src/ops/op_common/algorithm/executor
24+ ${_repo_root}/src/ops/op_common/algorithm/executor/registry
25+ ${_repo_root}/src/ops/op_common/algorithm/executor/channel
26+ ${_repo_root}/src/ops/op_common/algorithm/topo_match
27+ ${_repo_root}/src/ops/op_common/selector
28+ ${_repo_root}/src/ops/op_common/topo_info
29+ ${_repo_root}/src/common
30+ ${_repo_root}/src/common/hcomm_dlsym
31+ ${_repo_root}/src/common/hcomm_dlsym/ccu
32+)
33+ 
34+# 前向兼容:探测 CANN 版本号,与主构建/ST 保持一致(宏逻辑与 test/ut/recursive_executor 一致)。
35+# 缺少该宏时 dlsym_common.h 中的桩类型块会启用,与 CANN 公共头重复定义导致 conflicting declaration。
36+macro(_detect_cann_version _target)
37+ file(GLOB _cann_arch_dirs LIST_DIRECTORIES true "${ASCEND_CANN_PACKAGE_PATH}/*-linux")
38+ if(_cann_arch_dirs)
39+ set(_cann_arch_dir "")
40+ foreach(_dir ${_cann_arch_dirs})
41+ if(_dir MATCHES "/${CMAKE_SYSTEM_PROCESSOR}-linux$")
42+ set(_cann_arch_dir ${_dir})
43+ break()
44+ endif()
45+ endforeach()
46+ if(NOT _cann_arch_dir)
47+ list(GET _cann_arch_dirs 0 _cann_arch_dir)
48+ endif()
49+ target_include_directories(${_target} PRIVATE
50+ ${_cann_arch_dir}/include
51+ ${_cann_arch_dir}/include/hccl
52+ ${_cann_arch_dir}/include/hcomm
53+ ${_cann_arch_dir}/include/hcomm/ccu
54+ ${_cann_arch_dir}/pkg_inc
55+ ${_cann_arch_dir}/pkg_inc/hccl
56+ ${_cann_arch_dir}/pkg_inc/base
57+ ${_cann_arch_dir}/pkg_inc/hcomm/ccu
58+ )
59+ foreach(_arch_dir ${_cann_arch_dirs})
60+ set(_ut_cann_ver_header "${_arch_dir}/include/version/cann_version.h")
61+ if(EXISTS "${_ut_cann_ver_header}")
62+ file(STRINGS "${_ut_cann_ver_header}" _ut_cann_ver_line
63+ REGEX "^#define[ \t]+CANN_VERSION_NUM[ \t]+")
64+ if(_ut_cann_ver_line)
65+ string(REGEX REPLACE "^#define[ \t]+CANN_VERSION_NUM[ \t]+(.+)$" "\\1"
66+ _UT_CANN_VERSION_EXPR "${_ut_cann_ver_line}")
67+ math(EXPR _UT_CANN_VERSION_NUM "${_UT_CANN_VERSION_EXPR}" OUTPUT_FORMAT DECIMAL)
68+ target_compile_definitions(${_target}
69+ PRIVATE CANN_VERSION_NUM=${_UT_CANN_VERSION_NUM})
70+ message(STATUS "[UT] Detected CANN_VERSION_NUM = ${_UT_CANN_VERSION_NUM}")
71+ else()
72+ message(FATAL_ERROR "[UT] Failed to parse CANN_VERSION_NUM from ${_ut_cann_ver_header}: "
73+ "no '#define CANN_VERSION_NUM' line found. "
74+ "dlsym_common.h stub blocks would collide with CANN public headers.")
75+ endif()
76+ break()
77+ endif()
78+ endforeach()
79+ endif()
80+endmacro()
81+ 
82+# ---------- all_reduce_biar_selector_test: 选路判定纯逻辑 ----------
83+set(ut_src_list
84+ ${CMAKE_CURRENT_SOURCE_DIR}/biar_selector_test.cc
85+ ${_repo_root}/experimental/ops/all_reduce/biar/all_reduce_biar_selector.cc
86+)
87+ 
88+add_executable(all_reduce_biar_selector_test ${ut_src_list})
89+ 
90+target_compile_options(all_reduce_biar_selector_test PRIVATE
91+ -U_FORTIFY_SOURCE
92+)
93+ 
94+target_include_directories(all_reduce_biar_selector_test PRIVATE ${_biar_ut_include_dirs})
95+ 
96+_detect_cann_version(all_reduce_biar_selector_test)
97+ 
98+target_link_libraries(all_reduce_biar_selector_test PRIVATE
99+ $<BUILD_INTERFACE:intf_llt_pub>
100+ GTest::gtest_main
101+ -lpthread
102+)
103+ 
104+run_llt_test(TARGET all_reduce_biar_selector_test TASK_NUM 1)
105+ 
106+# ---------- all_reduce_biar_core_test: 切片换算/TreeReduce/RS·AG 环路核心逻辑 ----------
107+# executor_base/template 源文件整体编译; HCOMM 原语与 AlgTemplateBase 运行时依赖由本目录桩提供, 不依赖硬件
108+set(core_src_list
109+ ${CMAKE_CURRENT_SOURCE_DIR}/biar_core_test.cc
110+ ${CMAKE_CURRENT_SOURCE_DIR}/log_stub.cc
111+ ${CMAKE_CURRENT_SOURCE_DIR}/hcomm_stub.cc
112+ ${CMAKE_CURRENT_SOURCE_DIR}/base_class_stub.cc
113+ ${_repo_root}/experimental/ops/all_reduce/biar/all_reduce_executor_base.cc
114+ ${_repo_root}/experimental/ops/all_reduce/biar/template/all_reduce_biar.cc
115+ ${_repo_root}/experimental/ops/op_common/coll_executor_base_experimental.cc
116+ ${_repo_root}/experimental/ops/op_common/template/alg_template_base_experimental.cc
117+ ${_repo_root}/src/ops/op_common/algorithm/executor/executor_base.cc
118+ ${_repo_root}/src/ops/op_common/algorithm/template/registry/alg_template_register.cc
119+)
120+ 
121+add_executable(all_reduce_biar_core_test ${core_src_list})
122+ 
123+target_compile_options(all_reduce_biar_core_test PRIVATE
124+ -U_FORTIFY_SOURCE
125+)
126+ 
127+target_include_directories(all_reduce_biar_core_test PRIVATE
128+ ${CMAKE_CURRENT_SOURCE_DIR}
129+ ${_biar_ut_include_dirs}
130+)
131+ 
132+_detect_cann_version(all_reduce_biar_core_test)
133+ 
134+target_link_libraries(all_reduce_biar_core_test PRIVATE
135+ $<BUILD_INTERFACE:intf_llt_pub>
136+ GTest::gtest_main
137+ -lpthread
138+)
139+ 
140+run_llt_test(TARGET all_reduce_biar_core_test TASK_NUM 1)
@@ -0,0 +1,113 @@
1+/**
2+ * Copyright (c) 2026 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+// UT 桩: AlgTemplateBase 的构造/析构/虚函数与线程同步原语。
12+// 真实实现(src/ops/op_common/algorithm/template/alg_template_base.cc)依赖 ExecTimeoutManager 与
13+// hcomm_primitives_dl 的 dlsym 运行时符号, 不适合 UT 独立编译; 本桩按真实实现的成员初始化语义等价提供,
14+// 保证被测的 BIAR 模板成员(slices_/scratchMem_ 等)行为与生产一致。
15+// PreSync/PostSync 除返回成功外还记录调用序列, 供 RunAsync 编排确定性断言使用。
16+ 
17+#include "alg_template_base.h"
18+#include "alg_data_trans_wrapper.h"
19+#include "hcomm_stub.h"
20+ 
21+namespace ops_hccl {
22+ 
23+AlgTemplateBase::AlgTemplateBase()
24+ : slices_(slicesDummy_),
25+ count_(0),
26+ dataBytes_(0),
27+ dataType_(HCCL_DATA_TYPE_RESERVED),
28+ reductionOp_(HCCL_REDUCE_RESERVED),
29+ root_(INVALID_VALUE_RANKID),
30+ baseOffset_(0),
31+ barrierSwitchOn_(true)
32+{}
33+ 
34+AlgTemplateBase::~AlgTemplateBase() { slices_.clear(); }
35+ 
36+HcclResult AlgTemplateBase::Prepare(PrepareData& param)
37+{
38+ (void)param;
39+ return HCCL_E_PARA;
40+}
41+ 
42+HcclResult AlgTemplateBase::Prepare(
43+ HcclMem& inputMem, HcclMem& outputMem, HcclMem& scratchMem, const u64 count, const HcclDataType dataType,
44+ ThreadHandle thread, const HcclReduceOp reductionOp, const u32 root, const std::vector<Slice>& slices,
45+ const u64 baseOffset, const bool disableDMAReduce)
46+{
47+ inputMem_ = inputMem;
48+ outputMem_ = outputMem;
49+ scratchMem_ = scratchMem;
50+ thread_ = thread;
51+ count_ = count;
52+ dataType_ = dataType;
53+ dataBytes_ = count * DataUnitSize(dataType);
54+ reductionOp_ = reductionOp;
55+ root_ = root;
56+ disableDMAReduce_ = disableDMAReduce;
57+ baseOffset_ = baseOffset;
58+ if (slices.size() > 0) {
59+ slices_.resize(slices.size());
60+ slices_ = slices;
61+ }
62+ return HCCL_SUCCESS;
63+}
64+ 
65+HcclResult AlgTemplateBase::Prepare(u32 interRank, u32 interRankSize)
66+{
67+ (void)interRank;
68+ (void)interRankSize;
69+ return HCCL_E_PARA;
70+}
71+ 
72+HcclResult AlgTemplateBase::Prepare(
73+ HcclCollOpInfo* opInfo, const u32 userRank, const std::vector<u32>& ringsOrders,
74+ const std::vector<Slice>& userMemInputSlices)
75+{
76+ (void)opInfo;
77+ (void)userRank;
78+ (void)ringsOrders;
79+ (void)userMemInputSlices;
80+ return HCCL_E_PARA;
81+}
82+ 
83+HcclResult AlgTemplateBase::RunAsync(const u32 rank, const u32 rankSize, std::vector<ChannelInfo>& channels)
84+{
85+ (void)rank;
86+ (void)rankSize;
87+ (void)channels;
88+ return HCCL_SUCCESS;
89+}
90+ 
91+HcclResult PreSyncInterThreads(
92+ const ThreadHandle& mainThread, const std::vector<ThreadHandle>& subThreads,
93+ const std::vector<u32>& notifyIdxMainToSub)
94+{
95+ (void)subThreads;
96+ (void)notifyIdxMainToSub;
97+ int32_t stubRet
98+ = biar_ut::RecordCall({biar_ut::StubApi::kPreSync, mainThread, 0, nullptr, nullptr, 0, -1, -1, 0, ""});
99+ return stubRet == 0 ? HCCL_SUCCESS : static_cast<HcclResult>(stubRet);
100+}
101+ 
102+HcclResult PostSyncInterThreads(
103+ const ThreadHandle& mainThread, const std::vector<ThreadHandle>& subThreads,
104+ const std::vector<u32>& notifyIdxSubToMain)
105+{
106+ (void)subThreads;
107+ (void)notifyIdxSubToMain;
108+ int32_t stubRet
109+ = biar_ut::RecordCall({biar_ut::StubApi::kPostSync, mainThread, 0, nullptr, nullptr, 0, -1, -1, 0, ""});
110+ return stubRet == 0 ? HCCL_SUCCESS : static_cast<HcclResult>(stubRet);
111+}
112+ 
113+} // namespace ops_hccl
@@ -0,0 +1,678 @@
1+/**
2+ * Copyright (c) 2026 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 <gtest/gtest.h>
12+#include <vector>
13+#include "hcomm_stub.h"
14+#include "hcomm_primitives.h"
15+#include "all_reduce_biar.h"
16+#include "all_reduce_executor_base.h"
17+ 
18+namespace {
19+using namespace ops_hccl;
20+using namespace ops_hccl_experimental;
21+using biar_ut::StubApi;
22+using biar_ut::StubCall;
23+ 
24+void* const kInputBase = reinterpret_cast<void*>(0x10000000000ULL);
25+void* const kOutputBase = reinterpret_cast<void*>(0x20000000000ULL);
26+void* const kScratchBase = reinterpret_cast<void*>(0x30000000000ULL);
27+void* const kRemoteBase = reinterpret_cast<void*>(0x40000000000ULL);
28+constexpr u64 kMemSize = 1ULL << 20;
29+constexpr u64 kRemoteStep = 1ULL << 24;
30+constexpr u64 kStride = 256;
31+constexpr u32 kUnit = 4;
32+constexpr ThreadHandle kMainThread = 100;
33+constexpr ThreadHandle kSub0 = 101;
34+constexpr ThreadHandle kSub1 = 102;
35+constexpr ChannelHandle kHandleBase = 0x1000;
36+ 
37+void* PtrAt(void* base, u64 offset) { return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(base) + offset); }
38+ 
39+u64 OffsetFrom(const void* ptr, const void* base)
40+{
41+ return static_cast<u64>(reinterpret_cast<uintptr_t>(ptr) - reinterpret_cast<uintptr_t>(base));
42+}
43+ 
44+std::vector<Slice> MakeSlices(const std::vector<u64>& sizes)
45+{
46+ std::vector<Slice> slices;
47+ u64 offset = 0;
48+ for (u64 size : sizes) {
49+ slices.push_back(Slice{offset, size});
50+ offset += size;
51+ }
52+ return slices;
53+}
54+ 
55+ChannelInfo MakeChannel(u32 remoteRank)
56+{
57+ ChannelInfo channel;
58+ channel.isValid = true;
59+ channel.remoteRank = remoteRank;
60+ channel.handle = kHandleBase + remoteRank;
61+ channel.remoteOutput = HcclMem{HCCL_MEM_TYPE_DEVICE, PtrAt(kRemoteBase, remoteRank * kRemoteStep), kMemSize};
62+ return channel;
63+}
64+ 
65+std::vector<ChannelInfo> MakeChannels(u32 rankSize)
66+{
67+ std::vector<ChannelInfo> channels;
68+ for (u32 i = 0; i < rankSize; i++) {
69+ channels.push_back(MakeChannel(i));
70+ }
71+ return channels;
72+}
73+ 
74+class BiarExecutorUnderTest : public AllReduceExecutorBase {
75+public:
76+ using AllReduceExecutorBase::PrepareDataSlice;
77+};
78+ 
79+class BiarTemplateUnderTest : public AllReduceBIAR {
80+public:
81+ using AllReduceBIAR::HCCSProcessAgLoop;
82+ using AllReduceBIAR::HCCSProcessRsLoop;
83+ using AllReduceBIAR::LocalCopyAgLoop;
84+ using AllReduceBIAR::LocalCopyRsLoop;
85+ using AllReduceBIAR::Preprocess;
86+ using AllReduceBIAR::SIOProcessAgLoop;
87+ using AllReduceBIAR::SIOProcessRsLoop;
88+ using AllReduceBIAR::TreeReduceRs;
89+ 
90+ void SetupMem(const std::vector<Slice>& slices, u64 count, HcclReduceOp op = HCCL_REDUCE_SUM, u32 unitSize = kUnit)
91+ {
92+ HcclMem inputMem{HCCL_MEM_TYPE_DEVICE, kInputBase, kMemSize};
93+ HcclMem outputMem{HCCL_MEM_TYPE_DEVICE, kOutputBase, kMemSize};
94+ HcclMem scratchMem{HCCL_MEM_TYPE_DEVICE, kScratchBase, kMemSize};
95+ std::vector<ThreadHandle> slaveThreads{kSub0, kSub1};
96+ AllReduceBIAR::Prepare(
97+ inputMem, outputMem, scratchMem, count, HCCL_DATA_TYPE_INT32, kMainThread, slaveThreads, op, 0, slices, 0,
98+ false);
99+ unitSize_ = unitSize;
100+ }
@@ -0,0 +1,120 @@
1+/**
W
Wwenxuemin9月20日

⚠️ [中等] [测试覆盖率] test/ut/all_reduce_biar/biar_selector_test.cc:1

当前 UT 仅覆盖 selector 返回码(120 行),all_reduce_biar.cc 382 行模板核心逻辑(PrepareDataSlice 切片换算/余数分布、TreeReduceRs 拓扑、HCCS/SIO ProcessRsLoop、RunAllGather)零 UT。切片换算与 tree-reduce 均为纯逻辑,可低成本单测(参考 PR #2338 补充 birs_v_core_test.cc 的模式)。

建议:补充 core 逻辑 UT,至少覆盖切片换算与 TreeReduce 的非均匀/边界场景。

likedislike
Davydov_Danil
9月21日 评论:
2+ * Copyright (c) 2026 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 <string>
12+#include <gtest/gtest.h>
13+#include "all_reduce_biar_selector.h"
14+ 
15+using ops_hccl::TopoInfo;
16+using ops_hccl_experimental::BiarSelectResult;
17+using ops_hccl_experimental::BiarSelectResultToCode;
18+using ops_hccl_experimental::DecideAllReduceBiarAlg;
19+ 
20+namespace {
21+TopoInfo MakeTopo(u32 userRankSize, u32 serverNum, HcclDevType deviceType)
22+{
23+ TopoInfo topo{};
24+ topo.userRankSize = userRankSize;
25+ topo.serverNum = serverNum;
26+ topo.deviceType = deviceType;
27+ return topo;
28+}
29+ 
30+const std::string BIAR_ALG_NAME = "AllReduceBIARExecutor";
31+} // namespace
32+ 
33+TEST(AllReduceBiarSelector, ServerNumZeroIsRejectedInsteadOfDivByZero)
34+{
35+ std::string algName;
36+ TopoInfo topo = MakeTopo(8, 0, HcclDevType::DEV_TYPE_910_93);
37+ EXPECT_EQ(DecideAllReduceBiarAlg(topo, algName), BiarSelectResult::bRejectServerNumZero);
38+ EXPECT_TRUE(algName.empty());
39+}
40+ 
41+TEST(AllReduceBiarSelector, DualCardSingleServerIsRejected)
42+{
43+ std::string algName;
44+ TopoInfo topo = MakeTopo(2, 1, HcclDevType::DEV_TYPE_910_93);
45+ EXPECT_EQ(DecideAllReduceBiarAlg(topo, algName), BiarSelectResult::bRejectRanksPerServerLT4);
46+ EXPECT_TRUE(algName.empty());
47+}
48+ 
49+TEST(AllReduceBiarSelector, ThreeRanksPerServerIsRejected)
50+{
51+ std::string algName;
52+ TopoInfo topo = MakeTopo(6, 2, HcclDevType::DEV_TYPE_910_93);
53+ EXPECT_EQ(DecideAllReduceBiarAlg(topo, algName), BiarSelectResult::bRejectRanksPerServerLT4);
54+ EXPECT_TRUE(algName.empty());
55+}
56+ 
57+TEST(AllReduceBiarSelector, RankSizeOneIsRejected)
58+{
59+ std::string algName;
60+ TopoInfo topo = MakeTopo(1, 1, HcclDevType::DEV_TYPE_910_93);
61+ EXPECT_EQ(DecideAllReduceBiarAlg(topo, algName), BiarSelectResult::bRejectRankSizeOne);
62+ EXPECT_TRUE(algName.empty());
63+}
64+ 
65+TEST(AllReduceBiarSelector, FourRanksPerServerIsSelected)
66+{
67+ std::string algName;
68+ TopoInfo topo = MakeTopo(8, 2, HcclDevType::DEV_TYPE_910_93);
69+ EXPECT_EQ(DecideAllReduceBiarAlg(topo, algName), BiarSelectResult::bSelected);
70+ EXPECT_EQ(algName, BIAR_ALG_NAME);
71+}
72+ 
73+TEST(AllReduceBiarSelector, ExactlyFourRanksPerServerBoundarySelected)
74+{
75+ std::string algName;
76+ TopoInfo topo = MakeTopo(4, 1, HcclDevType::DEV_TYPE_910_93);
77+ EXPECT_EQ(DecideAllReduceBiarAlg(topo, algName), BiarSelectResult::bSelected);
78+ EXPECT_EQ(algName, BIAR_ALG_NAME);
79+}
80+ 
81+TEST(AllReduceBiarSelector, MoreThanFourRanksSingleServerIsSelected)
82+{
83+ std::string algName;
84+ TopoInfo topo = MakeTopo(16, 1, HcclDevType::DEV_TYPE_910_93);
85+ EXPECT_EQ(DecideAllReduceBiarAlg(topo, algName), BiarSelectResult::bSelected);
86+ EXPECT_EQ(algName, BIAR_ALG_NAME);
87+}
88+ 
89+TEST(AllReduceBiarSelector, MoreThanFourRanksPerServerIsSelected)
90+{
91+ std::string algName;
92+ TopoInfo topo = MakeTopo(16, 4, HcclDevType::DEV_TYPE_910_93);
93+ EXPECT_EQ(DecideAllReduceBiarAlg(topo, algName), BiarSelectResult::bSelected);
94+ EXPECT_EQ(algName, BIAR_ALG_NAME);
95+}
96+ 
97+TEST(AllReduceBiarSelector, NonA3DeviceIsNotSelected)
98+{
99+ std::string algName;
100+ TopoInfo topo = MakeTopo(8, 2, HcclDevType::DEV_TYPE_910B);
101+ EXPECT_EQ(DecideAllReduceBiarAlg(topo, algName), BiarSelectResult::bNotSelected);
102+ EXPECT_TRUE(algName.empty());
103+}
104+ 
105+TEST(AllReduceBiarSelector, OddRankSizeIsNotSelected)
106+{
107+ std::string algName;
108+ TopoInfo topo = MakeTopo(9, 1, HcclDevType::DEV_TYPE_910_93);
109+ EXPECT_EQ(DecideAllReduceBiarAlg(topo, algName), BiarSelectResult::bNotSelected);
110+ EXPECT_TRUE(algName.empty());
111+}
112+ 
113+TEST(AllReduceBiarSelector, SelectResultToCodeMapsRejectsToErrorCodes)
114+{
115+ EXPECT_EQ(BiarSelectResultToCode(BiarSelectResult::bSelected), HCCL_SUCCESS);
116+ EXPECT_EQ(BiarSelectResultToCode(BiarSelectResult::bNotSelected), HCCL_SUCCESS);
117+ EXPECT_EQ(BiarSelectResultToCode(BiarSelectResult::bRejectRankSizeOne), HCCL_E_INTERNAL);
118+ EXPECT_EQ(BiarSelectResultToCode(BiarSelectResult::bRejectServerNumZero), HCCL_E_PARA);
119+ EXPECT_EQ(BiarSelectResultToCode(BiarSelectResult::bRejectRanksPerServerLT4), HCCL_E_PARA);
120+}