| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 22 天前 | ||
| 22 天前 | ||
| 1 个月前 | ||
| 22 天前 | ||
| 22 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 22 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 22 天前 |
HCCL Tuner Plugin 示例
概述
本目录提供 HCCL Tuner Plugin 的参考实现,演示如何通过外部 .so 插件读取 JSON 配置并修改cost table,影响 Selector 的算法选择。
编译
source /usr/local/Ascend/cann/set_env.sh
make
产物:hccl_tuner_example.so
首次构建会自动下载 nlohmann/json(header-only)到 third_party/。离线场景可手动预放 third_party/nlohmann/json.hpp,make 检测到即跳过下载。
使用
export HCCL_TUNER_PLUGIN=/path/to/hccl_tuner_example.so
export HCCL_TUNER_CONFIG_FILE=/path/to/hccl_tuner_config.json
插件按以下顺序查找配置文件,找到第一个可读的即加载:
$HCCL_TUNER_CONFIG_FILE(未设置时跳过)./hccl_tuner_config.json/etc/hccl/hccl_tuner_config.json
数据采集与配置生成
手工编写 JSON 配置难以猜中各拓扑下的最优算法。本目录提供两个脚本,把这件事变成三步:
flowchart LR
A["prof_test.py<br/>逐算法拉起 mpirun + hccl_test"] -->|"性能 CSV"| B["optimize_config.py<br/>逐 size 挑带宽最优算法"]
B -->|"tuner JSON"| C["插件加载<br/>改写 cost table 生效"]
第一步:采集性能数据(prof_test.py)
prof_test.py 在环境里逐个算法拉起 mpirun + hccl_test,解析输出表格,把各算法在每个数据量下的带宽和时延写入 CSV。
运行前请确认:
- Python >= 3.8
mpirun在 PATH 中(MPICH 或 Open MPI 均可,脚本自动适配两种命令格式)- 已 source CANN 环境变量(
$ASCEND_HOME_PATH已设置),hccl_test 可执行文件位于$ASCEND_HOME_PATH/tools/hccl_test/bin/(也可通过--bin-dir指定其他位置) - 脚本要在 mpirun 会话外运行(登录节点普通 shell)。如果检测到自己在 MPI 会话里, 脚本会直接报错退出,避免嵌套拉起导致采集进程数被放大
典型命令:
python3 prof_test.py --op-types allreduce,allgather --engines aicpu --np-total 16 --npus 8 \
--hostfile hostfile --minbytes 1K --maxbytes 2G --stepfactor 2 \
--data-types fp32 --output hccl_prof.csv
参数说明
| 参数 | 默认值 | 说明 |
|---|---|---|
--op-types |
(必填) | 采集的算子,逗号分隔,支持 all(8 种白名单) |
--np-total |
(必填) | 总 rank 数,即 mpirun -n 的值 |
--npus |
未指定 | 每台服务器的 NPU 数,透传给 hccl_test -p |
--hostfile |
未指定 | 多机 hostfile 文件,单机不用传。每行写一条 IP:NPU数(如 10.10.130.22:8),# 开头的注释行和空行忽略;服务器数按有效行数统计 |
--minbytes / --maxbytes |
未指定 | 数据量区间,对应 -b / -e;两者必须同时给。单位:纯数字按字节,K/M/G 后缀按 1024 进制(1K=1024B,1M=1024K),支持小数(如 1.5K) |
--stepbytes |
未指定 | 线性步进(字节),正整数,对应 -i,与 --stepfactor 互斥;两者都不传时由 hccl_test 按默认序列扫点 |
--stepfactor |
未指定 | 等比步进因子,对应 -f,浮点(典型值 2,即 1K→2K→4K…);与 --stepbytes 互斥 |
--data-types |
fp32 |
数据类型,逗号分隔(16 种),对应 -d |
--reduce-op |
sum |
reduce 操作类型,仅对 reduce 类算子下发 -o |
--engines |
all |
采集引擎,支持 aicpu / aiv / dpu,all 展开全部(见下方说明) |
--algos |
全量 | 显式指定算法串(HCCL_ALGO 语义,如 sole{mesh};parallel{mesh,nhr}) |
--executors / --templates |
全量 | 按执行器 × 模板展开组合(--algos 存在时忽略) |
--warmup-iters |
10 | 预热次数,对应 -w |
--iters |
20 | 迭代次数,对应 -n |
--run-timeout |
600 | 单轮超时秒数,超时杀掉整轮进程,按失败继续 |
--pods |
0 | Pod 数;0 表示未指定,生成的配置不约束该维度 |
--super-pods |
0 | 超节点数;同上 |
--output |
hccl_prof.csv |
CSV 输出路径 |
--bin-dir |
tools/hccl_test/bin |
hccl_test 目录,相对 $ASCEND_HOME_PATH 或绝对路径 |
采集行为说明
引擎范围:当前支持 aicpu / aiv / dpu(all 展开全部三种)。dpu 不下发
-a 参数,由拓扑绑定决定。暂不支持 ccums / ccusched,传入会直接报错:当前
hccl 不支持 ccu_sched_only / ccu_ms_only 模式,配了 ccu 算法也可能回退到 aicpu
算法执行,测出的耗时不准,会污染选优结果。后续放开 ccums / ccusched。
算法黑名单:执行器带 concur 的算法、模板带 multilink / meshconcurrent 的算法 不采集(meshconcurrent 为 meshclos 方阵组网专属,executor 仍是 sole,故单独拉 黑)。这类算法在老选择逻辑下的选中条件很苛刻(特定机型、特定拓扑、特定数据量), 普通环境下就算配了,实际可能会选中其他算法,导致测出来的耗时不准,会污染选优 结果。
拓扑层数剪枝:脚本按 --hostfile 行数、--pods、--super-pods 估算拓扑
层数(单机=1 层,跨机/跨 Pod=2 层,跨超节点=3 层),只采集层数匹配的算法,
比如单机环境不会采 2 层专属算法——采了运行时也选不上。注意这只是估算下限:
跨超节点环境务必显式传 --super-pods,多 Pod 环境要传 --pods,否则对应层
的专属算法会被误剪掉。指定 --algos 时,层数不匹配的算法会被跳过并在结果里
标注。
超时容错:每轮默认 600 秒超时,到点杀掉整个进程树,该轮记为失败并继续后续
采集,单轮挂死不会卡住全程。失败或没解析出数据的轮次会在 CSV 里落一行
check_result=failed / noresult 的审计记录,原始输出追加到 <output>.raw
文件里供排查(缺 so、dlopen 失败等原因都能在里面找到)。
增量采集:CSV 是追加写的。文件已存在且表头一致就接着写,表头不一致会拒绝 追加,防止不同格式的数据混进一个文件。因此可以分多次跑,往同一个文件里补数据; 生成配置时按时间戳去重,同一个点只取最新一轮的结果。
第二步:生成最优配置(optimize_config.py)
python3 optimize_config.py --input hccl_prof.csv --output hccl_tuner_config.json
脚本读取 CSV,按算子、数据类型、reduce 类型、拓扑维度分组,在每个数据量点上 挑带宽最高的算法(带宽相同比时延),相邻点同算法的合并成区间,区间之间的缝隙 划给右边的区间,最后输出插件格式的 JSON。
两处口径换算需要注意:
- allgather 系按每 rank 口径换算:hccl_test 采集的 size 是每个 rank 收到的 总量,而插件运行时匹配的是每个 rank 发出的量。生成规则前会自动除以 rank 数, CSV 里的原始数值不受影响
- scatter 按总发出量换算:hccl_test 采集的 size 是每个 rank 收到的量,而插件 运行时匹配的是 root 总发出量。生成规则前会自动乘以 rank 数,CSV 里的原始数值 不受影响
- dpu 规则强制
min_servers>=2:原因见下文「engine 可选值」一节
校验不通过的行(比如插件不支持的 executor)直接丢弃并在日志里给出计数和原因, 不会让一条坏数据导致整份配置失效。
第三步:加载生效
export HCCL_TUNER_PLUGIN=/path/to/hccl_tuner_example.so
export HCCL_TUNER_CONFIG_FILE=/path/to/hccl_tuner_config.json
之后正常运行业务即可,插件会按配置改写 cost table。配置格式见下一节。
目录下其他文件
tuner_common.py 是两个脚本共用的常量表(CSV 字段、算法注册表、黑名单等),
被两边直接引用,不需要单独运行。有两点维护上的事需要知道:
- 算法注册表是人工维护的:合法算法组合表、拓扑层数约束表从 HCCL 源码的 算法注册宏归纳而来,不会随 HCCL 版本自动更新。升级 HCCL 后如果新增了算法, 需要手动同步这两张表,否则新算法采不了(按未注册组合被跳过)
- 黑名单可以放开:排除逻辑集中在
tuner_common.py的is_blacklisted(concur 拦截在函数里写死,multilink 走关键词表),想采集这些算法时改这里
JSON 配置格式
{
"version": 1,
"op_types": {
"allreduce": {
"rules": [
{
"match": {
"min_ranks": 8, "max_ranks": 8,
"min_bytes": 0, "max_bytes": 65536,
"data_type": "fp16"
},
"engine": "aicpu",
"executor": "sole",
"template": "nhr",
"cost": 0.0
}
]
}
}
}
顶层字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
version |
int | 是 | 配置格式版本,目前必须为 1 |
op_types |
object | 是 | 按算子类型组织的规则集 |
match 条件(全部 AND;首条真正改到条目的规则生效)
规则命中但目标不在 cost table 或被禁用时穿透,继续评估后续规则;全部落空则 matched=0。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
min_ranks / max_ranks |
uint32 | 是 | 通信域 rank 数范围 |
min_bytes / max_bytes |
size_t | 是 | 数据量范围(字节) |
data_type |
string | 否 | 数据类型(int8/int16/int32/int64/uint8/uint16/uint32/uint64/fp16/float16/fp32/float32/fp64/float64/bfp16/bfloat16) |
comm_name |
string | 否 | 通信域名(子串匹配) |
min_npus_per_server / max_npus_per_server |
uint32 | 否 | 每服务器 NPU 数范围 |
min_servers / max_servers |
uint32 | 否 | 服务器数范围 |
min_pods / max_pods |
uint32 | 否 | Pod 数范围 |
min_super_pods / max_super_pods |
uint32 | 否 | 超节点数范围 |
buffer_size |
uint64 | 否 | 通信域 buffer 大小(精确匹配) |
命中行为
engine/executor/template(必填)指定 cost table 中的目标位置template对单级算法是单 template 名(如mesh),对多级算法是 executor 后剩余串小写化的拼接(如meshconcurnhrnhr)cost(必填)设置该位置的 cost 值,0.0表示最优- Selector 从 cost table 中选最小值确定算法
engine 可选值
aicpu / ccums / ccusched / aiv / dpu
注意:dpu 与前 4 个 device 引擎拓扑互斥、非同台竞争。dpu 算法注册
isHostDpuOnly=true,仅 hostdpu 拓扑(多 server 且末层 CLOS 全连通,见
CheckHostDPUOnly)可选;普通环境 dpu 算法全部被 topo 过滤,hostdpu 环境
device 算法全部被过滤。因此 optimize_config 为 dpu rule 强制 min_servers>=2:
单机采集的 dpu 数据测得的是静默回退的其他算法耗时,属无效数据。
executor 可选值
executor 不做枚举校验:合法集合随 HCCL 版本演进(如 strictordered 为后增),固定枚举会拒绝新增值;拼写错误由运行时 "no entry modified" warning 兜底。以下为当前常见值,以所用 HCCL 版本的维度定义为准:
sole / sequence / parallel / pipeline / concur / strictordered
template 可选值
template 不做枚举校验:单级是单 template 名,多级是 executor 后剩余串小写化的拼接串;rule 是否生效由 cost 表 templateName 匹配决定(Enrich 按 algName 派生),拼写错误匹配不到条目、靠运行时 warning 兜底。
单级:
mesh / mesh2die / meshoneshot / meshtwoshot / meshconcur / meshmultilink / meshchunk / meshchunktwoshot / nhr / nhrmultilink / nhraicpureduce / meshsinglechannel / meshconcurrent
多级(拼接串):
取 algName 中 executor 后的剩余串小写化,如 AicpuAllReduceSequenceMeshConcurNHRNHR → meshconcurnhrnhr。
{ "engine": "aicpu", "executor": "sequence", "template": "meshconcurnhrnhr", "cost": 0.0 }
支持的 op_type
allreduce / allgather / broadcast / reduce / reduce_scatter / scatter / alltoall / alltoallv
以上 engine / executor / template / op_type 的可选值与 HCCL 算法选择器的维度定义一致。
CSV 列格式
hccl_prof.csv 每行一个采集点,列固定为(供自行后处理参考):
| 列 | 含义 |
|---|---|
op_type / data_type / reduce_type |
采集维度(reduce 类之外的算子 reduce_type 为 NA) |
size_bytes |
数据量(字节) |
engine |
采集引擎(当前固定 aicpu) |
algorithm.executor_type / algorithm.template_type |
算法(多级模板为逗号分隔串,如 meshconcur,nhr,nhr) |
HCCL_BUFFSIZE |
采集时的 HCCL_BUFFSIZE 环境变量值 |
ranks.ranks / ranks.npus_per_server / ranks.servers / ranks.pods / ranks.super_pods |
拓扑 5 字段(未指定的 pods/super_pods 记 0) |
check_result |
结果校验状态:success 表示算法结果比对通过;failed / noresult 表示该轮执行失败或未产出数据,仅供参考,不参与选优 |
alg_bandwidth(GB/s) / alg_latency(us) |
性能数据(optimize_config 以带宽选优) |
timestamp(ms) |
毫秒时间戳(增量采集去重依据) |
测试
Python 单测(覆盖两个脚本的全部纯函数):
python3 test_l0.py
C++ 插件测试:
cd test
make
./test_plugin
插件接口
插件需导出符号 hcclTunerPlugin_v1(类型 hcclTunerFuncs_v1_t),包含 init 和 getCollInfo 两个函数指针。HCCL 核心通过 dlsym 获取该符号加载插件。
详见 include/hccl_tuner_plugin.h。
运行示例
以下为 ./test_plugin 的典型输出,展示插件的各种行为。
命中规则并覆盖 cost
AllReduce 8 ranks、4096B、fp32 匹配规则,将目标算法 cost 从 100.0 改为 0.0(最优偏好),Selector 会选这个算法:
[TunerDFX] rule hit: opType=2 nBytes=4096 dataType=3 ruleIdx=0/2
engine=aicpu executor=sole template=meshoneshot cost=0.000000
[TunerDFX] modify: algName=AicpuAllReduceSoleMeshOneShot
cost 100.000000 -> 0.000000
多级算法同样支持,template 为 executor 后剩余串小写化拼接:
[TunerDFX] rule hit: opType=2 nBytes=4096 dataType=3 ruleIdx=0/1
engine=aicpu executor=sequence template=meshconcurnhrnhr cost=0.000000
[TunerDFX] modify: algName=AicpuAllReduceSequenceMeshConcurNHRNHR
cost 5.000000 -> 0.000000
不匹配时不干预
4 ranks 不在规则要求的 8~16 范围内,无规则命中,cost table 保持 CostModel 原值:
[TunerDFX] no rule matched: opType=2 nBytes=4096 dataType=3
目标算法已禁用(cost<0)时跳过
目标条目 cost=-1(已被禁用),插件不改它(SelectMinCost 中 cost<0 视为 filtered 不参与选择);该规则穿透,后续规则继续评估(穿透细节为 DEBUG 级日志):
[TunerDFX] skip disabled: algName=AicpuAllReduceSoleMeshOneShot cost=-1.000000
Schema 校验:逐规则剔除,格式级错误整体不干预
规则级错误(缺失必填字段、枚举非法、范围颠倒、data_type 非法等)只剔除该条规则,其余规则照常生效;仅格式级错误(根不是对象、version 缺失或非 1、op_types 缺失)才整体不干预(安全降级)。校验只覆盖部分内容(如 template 拼写不做枚举校验):
Schema: unknown field 'mtach' in rule, skipping
Schema: rule missing required field 'match'
Schema: invalid engine 'invalid_engine'
Schema: min_ranks(16) > max_ranks(8)
tuner config loaded from hccl_tuner_config.json, opSetCount=1, totalRules=4, validRules=1, schemaErrors=3, schemaWarnings=1
Schema: 3 rules rejected, 1 rules active
格式级错误示例(整份拒绝):
Schema: version must be 1, got 2
Schema fatal error (1), plugin will not intervene