Open
[Documentation|文档反馈]: MoeDistributeDispatch 的预留参数 groupTp 未说明会被当作 TP 通信域名解析,设置后第一段回 361001 而非参数非法码 #7221
liuhanwen8Add on  1 day ago
liuhanwen8
liuhanwen8
1 day ago Create

[Documentation|文档反馈]: MoeDistributeDispatch 的预留参数 groupTp 未说明会被当作 TP 通信域名解析,未注册域名时第一段只回 361001

现象

关联:#6951(同接口族的另一个现象:那条是 EP8/EP16 多机同步 507035,本条是 groupTp 域名解析失配回 361001,根因不同;本条不重复其证据)
资料把 groupTp 写作「TP通信域名称(预留参数,当前版本不支持),默认值为空串」(mc2/moe_distribute_dispatch/docs/aclnnMoeDistributeDispatch.md:213),
约束说明另写「仅支持EP域,无TP域,不支持 groupTp、tpWorldSize、tpRankId 属性」(同文件 :396)。按这两处表述该属性应被忽略或被拒,实测它没有被忽略:非空值会被当作 HCCL 通信域名去查句柄。

组 groupTp 取值 第一段 GetWorkspaceSize 返回码 workspaceSize
对照 空串(资料默认值) 0 16777216
对照 真实通信域名(HcclGetCommName 原值) 0 16777216
缺陷 未注册的域名(如 hccl_world_group) 361001 0
对同文件 :396 一起判为「不支持」的另两个属性补对照(groupTp 空串):
组 tpWorldSize / tpRankId 第一段返回码 ws
--- --- --- ---
对照 0 / 0(默认) 0 16777216
对照 1 / 0 0 16777216
对照 0 / 1 0 16777216
缺陷 99 / 7 561002 0
即「不支持」的三个属性里:小值被忽略、越界值回 561002、groupTp 非空回 361001 —— 三种都不是参数非法码 161002。
判定量是第一段接口返回码,不是两段式整体成败:本用例第一段返回 0 时,执行段仍会因 EP 通信域问题失败(aclrtSynchronizeStream 507035),那是另一个问题,与本条无关。
plog 中与 361001 对应的原文(缺陷组,2 rank 各一条,已去重;第三行说明被解析的正是 groupTpOptional,即调用方以为「预留、不生效」的那个参数):
[ERROR] HCCL: [hcom_common.cc:258] [HcomGetCommHandleByGroup]HcomGetCommByGroup failed, group[hccl_world_group], errNo[0x0000000005010002]
[ERROR] OP: [indv_lib_wrapper.cpp:247][NNOP] errno[561000] OpName:[MoeDistributeDispatch_0] Failed to invoke the HcomGetCommHandleByGroup function of the hccl module, ret = 2
[ERROR] OP: [individual_op_api.cpp:34][NNOP] errno[361001] OpName:[MoeDistributeDispatch_0] Check NnopbaseSetHcomGroup(*executor, groupTpOptional) failed

期望

以下任一可收敛。支撑点不是「预留参数不许解析」,而是错误码归类:调用方按资料把该属性当保留字段,误设后拿到的却是 361001(ACLNN_ERR_RUNTIME_ERROR,指向 runtime/hccl 内部)或 561002(内部错误),而不是参数非法码 161002 —— 调用方无法从错误码判断是自己传错参数:

  1. 按资料「不支持该属性」:groupTp 非空时返回 161002(ACLNN_ERR_PARAM_INVALID),日志写明 groupTp is reserved and must be empty;
  2. 若实现确要按名解析:在参数表 groupTp 一行补写「非空时按 TP 通信域名解析,域名未注册时第一段返回 361001」。

环境

  • 硬件:单机 8x Ascend950PR(Ascend950PR_9579),2 rank(ASCEND_RT_VISIBLE_DEVICES=0,1)
  • 软件:CANN 9.2.0-beta.2(aclnn / libhccl / libopapi)
  • 仓库基线:本地镜像 cann/ops-transformer 537d738a9;gitcode master 最新 2c1938672da16df6c50475ad5c176e18814b8731(已 fetch 核对:op_api/aclnn_moe_distribute_dispatch.cpp 的 CheckParams 仍按 groupTp 解析、NnopbaseSetHcomGroup(*executor, groupTpOptional) 仍在,文档 :213/:396 原文仍在;实测二进制为 CANN 9.2.0-beta.2)

复现步骤

  1. 准备 2 张空闲 NPU,ASCEND_RT_VISIBLE_DEVICES 只暴露这两张
  2. source CANN 的 set_env.sh(ASCEND_HOME_PATH 指向 9.2.0-beta.2)
  3. 按下方代码块首行注释编译
  4. 对照组:./repro "" 期望两 rank ret=0 / ws=16777216
  5. 对照组:./repro SAME 期望两 rank ret=0 / ws=16777216(把真实通信域名填进 groupTp)
  6. 缺陷组:./repro hccl_world_group 期望两 rank ret=361001 / ws=0;要看日志时加 ASCEND_GLOBAL_LOG_LEVEL=1 ASCEND_PROCESS_LOG_PATH= 再 grep HcomGetCommByGroup

复现脚本

单文件,只依赖 CANN 头文件与库(acl / hccl / opapi / nnopbase),无任何内部脚手架。groupTp 之外的全部参数在三次运行中完全一致。

// build: g++ -std=c++17 repro.cpp -o repro -I$ASCEND_HOME_PATH/include \
//   -I$ASCEND_HOME_PATH/x86_64-linux/include -L$ASCEND_HOME_PATH/x86_64-linux/lib64 \
//   -lascendcl -lhccl -lopapi -lnnopbase
#include <cstdio>
#include <cstring>
#include <unistd.h>
#include <thread>
#include <vector>
#include "acl/acl.h"
#include "hccl/hccl.h"
#include "aclnnop/aclnn_moe_distribute_dispatch.h"
static const int R = 2, BS = 8, H = 7168, K = 2, NE = 2, A = 16;
static HcclRootInfo gRoot; static char gName[128];
static aclTensor* mk(void* p, std::vector<int64_t> d, aclDataType t) {
  std::vector<int64_t> s(d.size(), 1);
  for (int i = (int)d.size() - 2; i >= 0; --i) s[i] = s[i + 1] * d[i + 1];
  return aclCreateTensor(d.data(), d.size(), t, s.data(), 0, ACL_FORMAT_ND, d.data(), d.size(), p);
}
static void* al(size_t n) { void* p = nullptr; aclrtMalloc(&p, n, ACL_MEM_MALLOC_HUGE_FIRST); return p; }
static void run(int r, const char* tp) {
  aclrtSetDevice(r);
  HcclComm c;
  if (HcclCommInitRootInfo(R, &gRoot, r, &c)) { printf("comm init fail\n"); return; }
  HcclGetCommName(c, gName);
  if (r == 0) printf("[setup] commName=%s\n", gName);
  if (!strcmp(tp, "SAME")) tp = gName;
  aclTensor* x = mk(al(BS * H * 2), {BS, H}, ACL_FLOAT16);
  aclTensor* eid = mk(al(BS * K * 4), {BS, K}, ACL_INT32);
  aclTensor* es = mk(al(BS * K * 4), {BS, K}, ACL_FLOAT);
  aclTensor* ex = mk(al(A * H * 2), {A, H}, ACL_FLOAT16);
  aclTensor* ds = mk(al(A * 4), {A}, ACL_FLOAT);
  aclTensor* ei = mk(al(BS * K * 4), {BS * K}, ACL_INT32);
  aclTensor* etn = mk(al(8), {1}, ACL_INT64);
  aclTensor* erc = mk(al(R * 4), {R}, ACL_INT32);
  aclTensor* tpc = mk(al(4), {0}, ACL_INT32);
  aclTensor* es2 = mk(al(A * 4), {A}, ACL_FLOAT);
  uint64_t ws = 0; aclOpExecutor* op = nullptr;
  int ret = aclnnMoeDistributeDispatchGetWorkspaceSize(x, eid, nullptr, nullptr, es, gName, R, r, NE, tp,
      0, 0, 0, 1, 0, 0, BS * R, 1, ex, ds, ei, etn, erc, tpc, es2, &ws, &op);
  printf("rank%d groupTp=\"%s\" ret=%d ws=%llu\n", r, tp, ret, (unsigned long long)ws);
}
int main(int argc, char** argv) {
  const char* tp = argc > 1 ? argv[1] : "";
  aclInit(nullptr); aclrtSetDevice(0);
  if (HcclGetRootInfo(&gRoot)) { printf("rootinfo fail\n"); return -1; }
  std::thread t0(run, 0, tp), t1(run, 1, tp);
  t0.join(); t1.join();
  fflush(stdout); _exit(0);
}

实测输出(已脱敏;tpRecvCounts 为预留出参,传 nullptr 得 161001,故给零元素张量):

# 对照 groupTp=""
rank0 groupTp="" ret=0 ws=16777216   (rank1 同)
# 对照 groupTp=SAME(真实通信域名)
rank0 groupTp="<node>_60000_<dev>_<ts>" ret=0 ws=16777216   (rank1 同)
# 缺陷 groupTp=hccl_world_group(未注册域名)
rank0 groupTp="hccl_world_group" ret=361001 ws=0   (rank1 同)

影响

把 group/groupTp 一起透传的调用方碰到 361001 时拿不到定位线索:错误码归类是 ACLNN_ERR_RUNTIME_ERROR,必须把 plog 拉到 ERROR 级才能看到 groupTpOptional。实际排查中我们先后怀疑过 EP 通信域未建、epWorldSize 不匹配、通信引擎配置缺失。

建议

预留参数既然声明不支持,就在 host 侧显式拒绝并回 161002(标量字符串,host 侧已有值,校验成本为零);若要保留按名解析,请在参数表补齐语义、取值范围与错误码。

闸门自检

闸 结论 依据
G1 真机可复现 通过 上面三次运行的真实输出,对照 ret=0 / 缺陷 361001 双向齐全;正文代码块已编译并实跑
G2 与资料不一致 通过 资料 :213「预留参数,当前版本不支持」+ :396「不支持 groupTp 属性」vs 实测该字段被解析
G3 查重 通过 check_duplicate.py(cann/ops-transformer,300 条)判 SIBLING #6951(EP8/EP16 同步 507035,根因不同),正文已补关联行
G4 最新提交仍在 通过 gitcode master 已 fetch:2c1938672;该提交上 op_api 仍按 groupTp 解析(NnopbaseSetHcomGroup(*executor, groupTpOptional))、文档 :213/:396 原文仍在
G5 脱敏 通过 已去内网 IP、家目录、批次目录名;节点名与时间戳占位符
G6 可读 通过 七小节齐全、步骤 6 步、代码块 49 行、正文 ≤120 行(lint_issue.py PASS)
G7 口径 通过 应得值有出处(文档两行原文 + 161002/361001 语义);未主张实现算错
G7b/G7c 通过 校验可行(groupTp 为标量字符串,host 有值,Q1/Q2/Q3 均无风险)+ 无自证矛盾(已把「非空即失败」修正为「非空被解析」)
likedislike
liuhanwen8liuhanwen8
1 day ago Added label: documentation
周云飞
周云飞Collaborators
1 day ago Comments:

问题说明

从您提供的 CANN 9.2.0-beta.2 对照结果和日志看,groupTp 非空时会参与通信域解析,并非被忽略;未注册域名在第一段返回 361001。这里需要澄清的是预留参数的实际行为及错误码归类,与执行段的 507035 分开处理。tpWorldSize/tpRankId=99/7 返回 561002 的现象也需单独核对,不能直接归为同一原因。

处理建议

若该平台确实不支持 TP,可考虑在 host 参数检查中拒绝非空 groupTp,返回 161002 并明确提示必须为空;需评估对现有传入有效域名调用的兼容影响。若保留解析行为,则应补齐文档中的非空语义、域名注册要求及第一段错误码说明。当前使用可先保持 groupTp 为空、其余 TP 参数为默认值;这仅避开本条触发条件,不代表执行段问题已解决。

likedislike