Merged
同步 CheckerL2 最新代码到 hccl_vm #6047
git_qkAdd on 24 days ago
同步 CheckerL2 最新代码到 hccl_vm #6047
Merged
Merged fromgit_qk/hcommmasterintocann/hcommmaster
Total: 154 files changed+20883-1365
| @@ -31,3 +31,4 @@ oat_reports/ | |||
| 31 | __pycache__/ | 31 | __pycache__/ |
| 32 | **/__pycache__/ | 32 | **/__pycache__/ |
| 33 | *.pyc | 33 | *.pyc |
| 34 | +/graph_dump/ | ||
| @@ -24,6 +24,8 @@ set(HCCLVM_OPT_LEVEL "-O2" CACHE STRING "Optimization level for host targets (us | |||
| 24 | function(hcclvm_apply_common_flags target) | 24 | function(hcclvm_apply_common_flags target) |
| 25 | target_compile_options(${target} PRIVATE | 25 | target_compile_options(${target} PRIVATE |
| 26 | -Werror | 26 | -Werror |
| 27 | + # GCC13 -O2 false positive: empty-vector copy -> memmove(null,null,0). Keep after -Werror. | ||
| 28 | + -Wno-error=nonnull | ||
| 27 | -fno-common | 29 | -fno-common |
| 28 | -fno-strict-aliasing | 30 | -fno-strict-aliasing |
| 29 | -pipe | 31 | -pipe |
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | HCCL-VM是面向华为昇腾NPU卡的高性能集合通信的虚拟执行环境,该工具旨在无真实昇腾硬件的条件下,实现HCCL集合通信算子的开发和功能验证。 | 5 | HCCL-VM是面向华为昇腾NPU卡的高性能集合通信的虚拟执行环境,该工具旨在无真实昇腾硬件的条件下,实现HCCL集合通信算子的开发和功能验证。 |
| 6 | 6 | ||
| 7 | +工具提供三种运行模式:`normal`(真实多卡通信,结果正确性无损)、`check-only`(仅校验,大块内存复用共享池,大幅压低内存占用)、`estimate`(估算,跳过真实通信阻塞,快速产出任务清单),支持启动时指定与运行期通过 `hccl-vm mode` 命令即时切换,详见[运行模式](#49-运行模式normal--check-only--estimate)。 | ||
| 8 | + | ||
| 7 |  | 9 |  |
| 8 | 10 | ||
| 9 | ## 2. 前置依赖 | 11 | ## 2. 前置依赖 |
| @@ -36,13 +38,13 @@ hccl_test是昇腾官方提供的HCCL性能测试工具,详见[HCCL性能测 | |||
| 36 | 38 | ||
| 37 | ### 2.3 QEMU 部署(仅 AICPU 模式、x86_64 宿主需要) | 39 | ### 2.3 QEMU 部署(仅 AICPU 模式、x86_64 宿主需要) |
| 38 | 40 | ||
| 39 | -AICPU 展开模式在 x86_64 宿主上需要 QEMU 用户态模拟(linux-user 模拟 aarch64)。系统自带的 qemu-user-static 可直接使用;版本低于 **10.2.4** 时不支持 `-tb-size` 限制翻译代码缓存,QEMU 常驻内存较大,可能严重影响性能,建议安装 **10.2.4 及以上**版本。 | 41 | +AICPU 展开模式在 x86_64 宿主上需要 QEMU 用户态模拟(linux-user 模拟 aarch64)。系统自带的 qemu-user-static 可直接使用;版本低于 **10.2.4** 时不支持 `-tb-size` 限制翻译代码缓存,QEMU 常驻内存较大,可能严重影响性能,按照如下操作安装 **10.2.4 及以上**版本。 |
| 40 | 42 | ||
| 41 | ```bash | 43 | ```bash |
| 42 | # 1) 构建依赖(gcc/make/ninja 一般已随系统或本工具安装存在) | 44 | # 1) 构建依赖(gcc/make/ninja 一般已随系统或本工具安装存在) |
| 43 | sudo apt-get install -y meson flex bison libglib2.0-dev libpcre2-dev libffi-dev | 45 | sudo apt-get install -y meson flex bison libglib2.0-dev libpcre2-dev libffi-dev |
| 44 | 46 | ||
| 45 | -# 2) 官方源码归档(示例为 10.2.4,建议 10.2.4 及以上版本) | 47 | +# 2) 官方源码归档(示例为 10.2.4,10.2.4 及以上版本均可) |
| 46 | curl -fsSL -O https://download.qemu.org/qemu-10.2.4.tar.xz | 48 | curl -fsSL -O https://download.qemu.org/qemu-10.2.4.tar.xz |
| 47 | tar -xf qemu-10.2.4.tar.xz && cd qemu-10.2.4 | 49 | tar -xf qemu-10.2.4.tar.xz && cd qemu-10.2.4 |
| 48 | 50 | ||
| @@ -69,6 +71,14 @@ export HCCL_VM_QEMU_TB_SIZE=16 | |||
| 69 | 71 | ||
| 70 | ## 3. 快速上手 | 72 | ## 3. 快速上手 |
| 71 | 73 | ||
| 74 | +### 一键安装 | ||
| 75 | + | ||
| 76 | +拉取完整 CheckerL2 源码后,在仓库根目录执行: | ||
| 77 | + | ||
| 78 | +```bash | ||
| 79 | +bash ./hccl_vm_installer | ||
| 80 | +``` | ||
| 81 | + | ||
| 72 | ### 3.1 手动构建&安装 | 82 | ### 3.1 手动构建&安装 |
| 73 | 83 | ||
| 74 | ```bash | 84 | ```bash |
| @@ -101,9 +111,6 @@ bash build_pkg.sh | |||
| 101 | 111 | ||
| 102 | 若/etc路径下已存在hccl_rootinfo.json文件,请手动删除该文件。 | 112 | 若/etc路径下已存在hccl_rootinfo.json文件,请手动删除该文件。 |
| 103 | 113 | ||
| 104 | -存储初始化与连接配置请先阅读[存储后端导航](src/storage_backends/README.md),确认是否需要额外配置; | ||
| 105 | -然后回到本节按对应执行模式运行算子。 | ||
| 106 | - | ||
| 107 | #### 3.2.2 CCU模式 | 114 | #### 3.2.2 CCU模式 |
| 108 | 115 | ||
| 109 | 1. 环境变量配置。 | 116 | 1. 环境变量配置。 |
| @@ -704,7 +711,7 @@ HCCL-VM Runner插件支持数据类如下: | |||
| 704 | 711 | ||
| 705 | **硬件规格**: | 712 | **硬件规格**: |
| 706 | 713 | ||
| 707 | -目前本工具仅适配支持Ascend950芯片。单server内最大支持8张卡;超过8张卡,需要跨server运行。 | 714 | +目前本工具仅适配支持Ascend950芯片。单server内最大支持8张卡;超过8张卡,需要跨server运行。默认内置存储适用 1~128 卡的通信域,无需配置数据库。 |
| 708 | 715 | ||
| 709 | ### 4.6 HCCL-VM插件功能 | 716 | ### 4.6 HCCL-VM插件功能 |
| 710 | 717 | ||
| @@ -817,18 +824,80 @@ data_size(Bytes): | aveg_time(us): | alg_bandwidth(GB/s): | check_result: | |||
| 817 | ``` | 824 | ``` |
| 818 | 825 | ||
| 819 | --- | 826 | --- |
| 820 | -### 4.9 大块内存复用(仅校验模式) | 827 | +### 4.9 运行模式(normal / check-only / estimate) |
| 821 | 828 | ||
| 822 | -仅校验模式用于大规模集群仅运行 Checker 校验的场景。开启后,单块 200MB 到 4GB 的大内存申请复用同一块 4GB 共享区 `HcclCommPool`,各 rank 共享、允许互相覆盖,以此大幅降低 `/dev/shm` 占用。此时大块内容不保证正确,仅适用于不读取缓冲区数据的 Checker V3 校验链路,需要数值正确的结果时请勿开启。 | 829 | +HCCL-VM 有三种运行模式,任意时刻有且仅有一个生效,默认为 `normal`: |
| 823 | 830 | ||
| 824 | -仅校验模式是会话级开关,在 `start` 子命令后追加 `--check-only` 显式开启;不加时为默认的普通模式,大块走真实独立分配,正确性无损。小于 200MB 的申请始终走真实分配,单块大于 4GB 在仅校验模式下直接报错拒绝。仅校验模式与 Runner 不互斥,但在仅校验模式开启时安装 Runner,大块复用仍会生效、可能覆盖 Runner 数据,工具会打印告警。 | 831 | +| 模式 | 定位 | 说明 | |
| 832 | +| ---- | ---- | ---- | | ||
| 833 | +| `normal` | 普通模式(默认) | 真实独立分配与完整多 rank 通信,结果正确性无损 | | ||
| 834 | +| `check-only` | 仅校验模式 | 大块内存复用 4GB 共享池,大幅压低内存占用;只保证 Checker 校验链路,缓冲区数据内容不保证正确 | | ||
| 835 | +| `estimate` | 估算模式 | 单卡(rank0)构造幻影对端跳过真实通信阻塞点,快速产出任务清单,不真跑数据传输(需先关闭链路心跳与一致性校验,见 [4.9.4](#494-估算模式限制说明)) | | ||
| 836 | + | ||
| 837 | +#### 4.9.1 启动时指定模式 | ||
| 838 | + | ||
| 839 | +`start` 与 `run`(one-shot)子命令均支持 `--check-only` / `--estimate` 标志(二者互斥),不加任何标志即为 `normal`: | ||
| 825 | 840 | ||
| 826 | ```bash | 841 | ```bash |
| 827 | - | 842 | +# 以仅校验模式启动 |
| 828 | -# 启动工具时开启仅校验模式 | ||
| 829 | ./hccl-vm start ascend950_cluster_32_server_normal.yaml --check-only | 843 | ./hccl-vm start ascend950_cluster_32_server_normal.yaml --check-only |
| 844 | + | ||
| 845 | +# 以估算模式启动 | ||
| 846 | +./hccl-vm start ascend950_cluster_32_server_normal.yaml --estimate | ||
| 830 | ``` | 847 | ``` |
| 831 | 848 | ||
| 849 | +#### 4.9.2 运行时查询与切换模式 | ||
| 850 | + | ||
| 851 | +在已启动的 VM 命令行内,可通过 `hccl-vm mode` 即时查询与切换模式,无需重启 VM: | ||
| 852 | + | ||
| 853 | +```bash | ||
| 854 | +# 查询:列出全部支持模式与当前模式(不带参数等价于 show,无副作用) | ||
| 855 | +(hvm)$> hccl-vm mode show | ||
| 856 | +Supported modes: | ||
| 857 | + check-only : 仅校验模式,大块内存复用 4GB 共享池 HcclCommPool,大幅降低 /dev/shm 占用;只保证校验链路,缓冲区数据内容不保证正确 | ||
| 858 | + estimate : 估算模式,单卡(rank0)构造幻影对端跳过真实通信阻塞点,快速产出任务清单,不真跑数据传输 | ||
| 859 | + normal : 普通模式(默认),真实独立分配与完整多 rank 通信,结果正确性无损 | ||
| 860 | +Current mode: normal | ||
| 861 | + | ||
| 862 | +# 切换模式 | ||
| 863 | +(hvm)$> hccl-vm mode check-only | ||
| 864 | +(chk-only)$> hccl-vm mode estimate | ||
| 865 | +(estimate)$> hccl-vm mode normal | ||
| 866 | +``` | ||
| 867 | + | ||
| 868 | +切换成功后,终端提示符随模式变化:normal → `(hvm)$>`、check-only → `(chk-only)$>`、estimate → `(estimate)$>`。 | ||
| 869 | + | ||
| 870 | +**切换行为与约束**: | ||
| 871 | + | ||
| 872 | +- **拼写严格**:模式名须严格使用小写连字符拼写,`CHECK-ONLY`、`check_only` 等变体及非法串均被拒绝,当前模式不受影响。 | ||
| 873 | +- **幂等**:切换到当前已处的模式为空操作,提示已处于该模式。 | ||
| 874 | +- **复用池随模式建/拆**:切入 check-only 时自动创建 4GB 共享复用池(创建前先清理残留),切走时自动释放;normal / estimate 模式下不存在该池。 | ||
| 875 | +- **切换前卸载 runner**:切向非 normal 模式前,若 runner 插件驻留则先卸载;卸载失败则中止切换。切向 normal 不触发卸载。 | ||
| 876 | +- **切换原子性**:切换过程中任一步骤失败(建池失败、拆池失败等)即报错中止,模式与资源保持切换前原状。已知局限:切换失败时提示符仍可能变更,此时以 `hccl-vm mode show` 的查询结果为准。 | ||
| 877 | +- **对新算例生效**:新模式对切换成功后新启动的业务算例生效;切换前已在运行的算例不受影响,仍按其启动时的模式运行。 | ||
| 878 | +- **不跨重启保留**:模式不跨 VM 重启保留,重启后回到由启动参数决定的初始模式(未指定即 normal)。 | ||
| 879 | + | ||
| 880 | +#### 4.9.3 仅校验模式大块内存复用说明 | ||
| 881 | + | ||
| 882 | +check-only 模式用于大规模集群仅运行 Checker 校验的场景。开启后,单块 200MB 到 4GB 的大内存申请复用同一块 4GB 共享区 `HcclCommPool`,各 rank 共享、允许互相覆盖,以此大幅降低 `/dev/shm` 占用。此时大块内容不保证正确,仅适用于不读取缓冲区数据的 Checker V3 校验链路,需要数值正确的结果时请勿开启。 | ||
| 883 | + | ||
| 884 | +小于 200MB 的申请始终走真实分配;单块大于 4GB 在 check-only 模式下直接报错拒绝。check-only 模式与 Runner 不互斥,但在 check-only 模式开启时安装 Runner,大块复用仍会生效、可能覆盖 Runner 数据,工具会打印告警。 | ||
| 885 | + | ||
| 886 | +#### 4.9.4 估算模式限制说明 | ||
| 887 | + | ||
| 888 | +estimate 模式单卡执行、对端为构造出的幻影对端,链路上没有真实对端参与,链路心跳与一致性校验无法正常完成,会带来误报或异常退出。因此**使用 estimate 模式前必须先关闭链路心跳与一致性校验**: | ||
| 889 | + | ||
| 890 | +```bash | ||
| 891 | +export HCCL_DFS_CONFIG=cluster_heartbeat:off,inconsistent_check:off | ||
| 892 | +``` | ||
| 893 | + | ||
| 894 | +该环境变量需在业务算例启动前生效,`start` 与 `run`(one-shot)两种方式均适用;基于 README 中的 `start.sh` 示例修改时,注意其默认只关闭了心跳(`cluster_heartbeat:off`),用于 estimate 模式时需按上式补上 `inconsistent_check:off`。 | ||
| 895 | + | ||
| 896 | +其余限制: | ||
| 897 | + | ||
| 898 | +- 仅构造单卡(rank0)执行路径,跳过真实通信阻塞点,用于快速产出任务清单,不真跑数据传输。 | ||
| 899 | +- 需要功能正确性校验或真实通信行为时,请改用 `normal` 模式。 | ||
| 900 | + | ||
| 832 | *** | 901 | *** |
| 833 | 902 | ||
| 834 | ## 5 附录 | 903 | ## 5 附录 |
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | HCCL-VM是面向华为昇腾NPU卡的高性能集合通信的虚拟执行环境,该工具旨在无真实昇腾硬件的条件下,实现HCCL集合通信算子的开发和功能验证。 | 5 | HCCL-VM是面向华为昇腾NPU卡的高性能集合通信的虚拟执行环境,该工具旨在无真实昇腾硬件的条件下,实现HCCL集合通信算子的开发和功能验证。 |
| 6 | 6 | ||
| 7 | +工具提供三种运行模式:`normal`(真实多卡通信,结果正确性无损)、`check-only`(仅校验,大块内存复用共享池,大幅压低内存占用)、`estimate`(估算,跳过真实通信阻塞,快速产出任务清单),支持启动时指定与运行期通过 `hccl-vm mode` 命令即时切换,详见[运行模式](#49-运行模式normal--check-only--estimate)。 | ||
| 8 | + | ||
| 7 |  | 9 |  |
| 8 | 10 | ||
| 9 | ## 2. 前置依赖 | 11 | ## 2. 前置依赖 |
| @@ -36,13 +38,13 @@ hccl_test是昇腾官方提供的HCCL性能测试工具,详见[HCCL性能测 | |||
| 36 | 38 | ||
| 37 | ### 2.3 QEMU 部署(仅 AICPU 模式、x86_64 宿主需要) | 39 | ### 2.3 QEMU 部署(仅 AICPU 模式、x86_64 宿主需要) |
| 38 | 40 | ||
| 39 | -AICPU 展开模式在 x86_64 宿主上需要 QEMU 用户态模拟(linux-user 模拟 aarch64)。系统自带的 qemu-user-static 可直接使用;版本低于 **10.2.4** 时不支持 `-tb-size` 限制翻译代码缓存,QEMU 常驻内存较大,可能严重影响性能,建议安装 **10.2.4 及以上**版本。 | 41 | +AICPU 展开模式在 x86_64 宿主上需要 QEMU 用户态模拟(linux-user 模拟 aarch64)。系统自带的 qemu-user-static 可直接使用;版本低于 **10.2.4** 时不支持 `-tb-size` 限制翻译代码缓存,QEMU 常驻内存较大,可能严重影响性能,按照如下操作安装 **10.2.4 及以上**版本。 |
| 40 | 42 | ||
| 41 | ```bash | 43 | ```bash |
| 42 | # 1) 构建依赖(gcc/make/ninja 一般已随系统或本工具安装存在) | 44 | # 1) 构建依赖(gcc/make/ninja 一般已随系统或本工具安装存在) |
| 43 | sudo apt-get install -y meson flex bison libglib2.0-dev libpcre2-dev libffi-dev | 45 | sudo apt-get install -y meson flex bison libglib2.0-dev libpcre2-dev libffi-dev |
| 44 | 46 | ||
| 45 | -# 2) 官方源码归档(示例为 10.2.4,建议 10.2.4 及以上版本) | 47 | +# 2) 官方源码归档(示例为 10.2.4,10.2.4 及以上版本均可) |
| 46 | curl -fsSL -O https://download.qemu.org/qemu-10.2.4.tar.xz | 48 | curl -fsSL -O https://download.qemu.org/qemu-10.2.4.tar.xz |
| 47 | tar -xf qemu-10.2.4.tar.xz && cd qemu-10.2.4 | 49 | tar -xf qemu-10.2.4.tar.xz && cd qemu-10.2.4 |
| 48 | 50 | ||
| @@ -69,6 +71,14 @@ export HCCL_VM_QEMU_TB_SIZE=16 | |||
| 69 | 71 | ||
| 70 | ## 3. 快速上手 | 72 | ## 3. 快速上手 |
| 71 | 73 | ||
| 74 | +### 一键安装 | ||
| 75 | + | ||
| 76 | +拉取完整 CheckerL2 源码后,在仓库根目录执行: | ||
| 77 | + | ||
| 78 | +```bash | ||
| 79 | +bash ./hccl_vm_installer | ||
| 80 | +``` | ||
| 81 | + | ||
| 72 | ### 3.1 手动构建&安装 | 82 | ### 3.1 手动构建&安装 |
| 73 | 83 | ||
| 74 | ```bash | 84 | ```bash |
| @@ -101,9 +111,6 @@ bash build_pkg.sh | |||
| 101 | 111 | ||
| 102 | 若/etc路径下已存在hccl_rootinfo.json文件,请手动删除该文件。 | 112 | 若/etc路径下已存在hccl_rootinfo.json文件,请手动删除该文件。 |
| 103 | 113 | ||
| 104 | -存储初始化与连接配置请先阅读[存储后端导航](src/storage_backends/README.md),确认是否需要额外配置; | ||
| 105 | -然后回到本节按对应执行模式运行算子。 | ||
| 106 | - | ||
| 107 | #### 3.2.2 CCU模式 | 114 | #### 3.2.2 CCU模式 |
| 108 | 115 | ||
| 109 | 1. 环境变量配置。 | 116 | 1. 环境变量配置。 |
| @@ -704,7 +711,7 @@ HCCL-VM Runner插件支持数据类如下: | |||
| 704 | 711 | ||
| 705 | **硬件规格**: | 712 | **硬件规格**: |
| 706 | 713 | ||
| 707 | -目前本工具仅适配支持Ascend950芯片。单server内最大支持8张卡;超过8张卡,需要跨server运行。 | 714 | +目前本工具仅适配支持Ascend950芯片。单server内最大支持8张卡;超过8张卡,需要跨server运行。默认内置存储适用 1~128 卡的通信域,无需配置数据库。 |
| 708 | 715 | ||
| 709 | ### 4.6 HCCL-VM插件功能 | 716 | ### 4.6 HCCL-VM插件功能 |
| 710 | 717 | ||
| @@ -817,18 +824,80 @@ data_size(Bytes): | aveg_time(us): | alg_bandwidth(GB/s): | check_result: | |||
| 817 | ``` | 824 | ``` |
| 818 | 825 | ||
| 819 | --- | 826 | --- |
| 820 | -### 4.9 大块内存复用(仅校验模式) | 827 | +### 4.9 运行模式(normal / check-only / estimate) |
| 821 | 828 | ||
| 822 | -仅校验模式用于大规模集群仅运行 Checker 校验的场景。开启后,单块 200MB 到 4GB 的大内存申请复用同一块 4GB 共享区 `HcclCommPool`,各 rank 共享、允许互相覆盖,以此大幅降低 `/dev/shm` 占用。此时大块内容不保证正确,仅适用于不读取缓冲区数据的 Checker V3 校验链路,需要数值正确的结果时请勿开启。 | 829 | +HCCL-VM 有三种运行模式,任意时刻有且仅有一个生效,默认为 `normal`: |
| 823 | 830 | ||
| 824 | -仅校验模式是会话级开关,在 `start` 子命令后追加 `--check-only` 显式开启;不加时为默认的普通模式,大块走真实独立分配,正确性无损。小于 200MB 的申请始终走真实分配,单块大于 4GB 在仅校验模式下直接报错拒绝。仅校验模式与 Runner 不互斥,但在仅校验模式开启时安装 Runner,大块复用仍会生效、可能覆盖 Runner 数据,工具会打印告警。 | 831 | +| 模式 | 定位 | 说明 | |
| 832 | +| ---- | ---- | ---- | | ||
| 833 | +| `normal` | 普通模式(默认) | 真实独立分配与完整多 rank 通信,结果正确性无损 | | ||
| 834 | +| `check-only` | 仅校验模式 | 大块内存复用 4GB 共享池,大幅压低内存占用;只保证 Checker 校验链路,缓冲区数据内容不保证正确 | | ||
| 835 | +| `estimate` | 估算模式 | 单卡(rank0)构造幻影对端跳过真实通信阻塞点,快速产出任务清单,不真跑数据传输(需先关闭链路心跳与一致性校验,见 [4.9.4](#494-估算模式限制说明)) | | ||
| 836 | + | ||
| 837 | +#### 4.9.1 启动时指定模式 | ||
| 838 | + | ||
| 839 | +`start` 与 `run`(one-shot)子命令均支持 `--check-only` / `--estimate` 标志(二者互斥),不加任何标志即为 `normal`: | ||
| 825 | 840 | ||
| 826 | ```bash | 841 | ```bash |
| 827 | - | 842 | +# 以仅校验模式启动 |
| 828 | -# 启动工具时开启仅校验模式 | ||
| 829 | ./hccl-vm start ascend950_cluster_32_server_normal.yaml --check-only | 843 | ./hccl-vm start ascend950_cluster_32_server_normal.yaml --check-only |
| 844 | + | ||
| 845 | +# 以估算模式启动 | ||
| 846 | +./hccl-vm start ascend950_cluster_32_server_normal.yaml --estimate | ||
| 830 | ``` | 847 | ``` |
| 831 | 848 | ||
| 849 | +#### 4.9.2 运行时查询与切换模式 | ||
| 850 | + | ||
| 851 | +在已启动的 VM 命令行内,可通过 `hccl-vm mode` 即时查询与切换模式,无需重启 VM: | ||
| 852 | + | ||
| 853 | +```bash | ||
| 854 | +# 查询:列出全部支持模式与当前模式(不带参数等价于 show,无副作用) | ||
| 855 | +(hvm)$> hccl-vm mode show | ||
| 856 | +Supported modes: | ||
| 857 | + check-only : 仅校验模式,大块内存复用 4GB 共享池 HcclCommPool,大幅降低 /dev/shm 占用;只保证校验链路,缓冲区数据内容不保证正确 | ||
| 858 | + estimate : 估算模式,单卡(rank0)构造幻影对端跳过真实通信阻塞点,快速产出任务清单,不真跑数据传输 | ||
| 859 | + normal : 普通模式(默认),真实独立分配与完整多 rank 通信,结果正确性无损 | ||
| 860 | +Current mode: normal | ||
| 861 | + | ||
| 862 | +# 切换模式 | ||
| 863 | +(hvm)$> hccl-vm mode check-only | ||
| 864 | +(chk-only)$> hccl-vm mode estimate | ||
| 865 | +(estimate)$> hccl-vm mode normal | ||
| 866 | +``` | ||
| 867 | + | ||
| 868 | +切换成功后,终端提示符随模式变化:normal → `(hvm)$>`、check-only → `(chk-only)$>`、estimate → `(estimate)$>`。 | ||
| 869 | + | ||
| 870 | +**切换行为与约束**: | ||
| 871 | + | ||
| 872 | +- **拼写严格**:模式名须严格使用小写连字符拼写,`CHECK-ONLY`、`check_only` 等变体及非法串均被拒绝,当前模式不受影响。 | ||
| 873 | +- **幂等**:切换到当前已处的模式为空操作,提示已处于该模式。 | ||
| 874 | +- **复用池随模式建/拆**:切入 check-only 时自动创建 4GB 共享复用池(创建前先清理残留),切走时自动释放;normal / estimate 模式下不存在该池。 | ||
| 875 | +- **切换前卸载 runner**:切向非 normal 模式前,若 runner 插件驻留则先卸载;卸载失败则中止切换。切向 normal 不触发卸载。 | ||
| 876 | +- **切换原子性**:切换过程中任一步骤失败(建池失败、拆池失败等)即报错中止,模式与资源保持切换前原状。已知局限:切换失败时提示符仍可能变更,此时以 `hccl-vm mode show` 的查询结果为准。 | ||
| 877 | +- **对新算例生效**:新模式对切换成功后新启动的业务算例生效;切换前已在运行的算例不受影响,仍按其启动时的模式运行。 | ||
| 878 | +- **不跨重启保留**:模式不跨 VM 重启保留,重启后回到由启动参数决定的初始模式(未指定即 normal)。 | ||
| 879 | + | ||
| 880 | +#### 4.9.3 仅校验模式大块内存复用说明 | ||
| 881 | + | ||
| 882 | +check-only 模式用于大规模集群仅运行 Checker 校验的场景。开启后,单块 200MB 到 4GB 的大内存申请复用同一块 4GB 共享区 `HcclCommPool`,各 rank 共享、允许互相覆盖,以此大幅降低 `/dev/shm` 占用。此时大块内容不保证正确,仅适用于不读取缓冲区数据的 Checker V3 校验链路,需要数值正确的结果时请勿开启。 | ||
| 883 | + | ||
| 884 | +小于 200MB 的申请始终走真实分配;单块大于 4GB 在 check-only 模式下直接报错拒绝。check-only 模式与 Runner 不互斥,但在 check-only 模式开启时安装 Runner,大块复用仍会生效、可能覆盖 Runner 数据,工具会打印告警。 | ||
| 885 | + | ||
| 886 | +#### 4.9.4 估算模式限制说明 | ||
| 887 | + | ||
| 888 | +estimate 模式单卡执行、对端为构造出的幻影对端,链路上没有真实对端参与,链路心跳与一致性校验无法正常完成,会带来误报或异常退出。因此**使用 estimate 模式前必须先关闭链路心跳与一致性校验**: | ||
| 889 | + | ||
| 890 | +```bash | ||
| 891 | +export HCCL_DFS_CONFIG=cluster_heartbeat:off,inconsistent_check:off | ||
| 892 | +``` | ||
| 893 | + | ||
| 894 | +该环境变量需在业务算例启动前生效,`start` 与 `run`(one-shot)两种方式均适用;基于 README 中的 `start.sh` 示例修改时,注意其默认只关闭了心跳(`cluster_heartbeat:off`),用于 estimate 模式时需按上式补上 `inconsistent_check:off`。 | ||
| 895 | + | ||
| 896 | +其余限制: | ||
| 897 | + | ||
| 898 | +- 仅构造单卡(rank0)执行路径,跳过真实通信阻塞点,用于快速产出任务清单,不真跑数据传输。 | ||
| 899 | +- 需要功能正确性校验或真实通信行为时,请改用 `normal` 模式。 | ||
| 900 | + | ||
| 832 | *** | 901 | *** |
| 833 | 902 | ||
| 834 | ## 5 附录 | 903 | ## 5 附录 |
| @@ -0,0 +1,168 @@ | |||
| 1 | +# HCOMM CCU 数据面 SO 拆分架构图 | ||
| 2 | + | ||
| 3 | +HCOMM 将 CCU(Collective Communication Unit)能力拆分为**控制面**(本仓 hcomm,产出 `libhcomm.so`)与**数据面**(asc-comm 仓,产出 `libasccomm_ccu_dataplane.so`)两个独立 SO,通过 POD ABI 契约层交互,可独立编译、独立版本演进。 | ||
| 4 | + | ||
| 5 | +## 架构图(Mermaid 渲染版) | ||
| 6 | + | ||
| 7 | +```mermaid | ||
| 8 | +flowchart TD | ||
| 9 | + subgraph CALLER["调用方"] | ||
| 10 | + FW["AI 框架"] --> HCCL["libhccl.so(cann/hccl 仓)"] | ||
| 11 | + OP["CCU 自定义通信算子"] | ||
| 12 | + end | ||
| 13 | + | ||
| 14 | + subgraph CTRL["libhcomm.so · 控制面(hcomm 仓)"] | ||
| 15 | + C1["通信域 / CCU 实例 / 资源池"] | ||
| 16 | + C2["建链握手 Channel / Jetty"] | ||
| 17 | + C3["指令下发(TLV → 驱动)"] | ||
| 18 | + end | ||
| 19 | + | ||
| 20 | + subgraph DP["libasccomm_ccu_dataplane.so · 数据面(asc-comm 仓)"] | ||
| 21 | + D1["Kernel 注册 · 录制 REP"] | ||
| 22 | + D2["REP 翻译微码 + 调度优化"] | ||
| 23 | + D3["Launch(rtCCULaunch)"] | ||
| 24 | + end | ||
| 25 | + | ||
| 26 | + DRV["驱动 / 运行时<br/>TLV 指令槽 · urma(Jetty) · stream"] | ||
| 27 | + HW["CCU 硬件单元(IO Die)<br/>Mission × 微码 · URMA 搬数 · XN/GSA/CKE 同步"] | ||
| 28 | + | ||
| 29 | + HCCL -->|"(1) 控制面 C API"| CTRL | ||
| 30 | + OP -->|"(2) 数据面 DSL(弱符号)"| DP | ||
| 31 | + CTRL -.->|"(3) RegisterContext 只读快照"| DP | ||
| 32 | + DP -.->|"(4) controlOps 回调 / 4 个 C API"| CTRL | ||
| 33 | + DP -->|"(5) rtCCULaunch 提交任务"| DRV | ||
| 34 | + CTRL -->|"(6) TLV 驱动交互"| DRV | ||
| 35 | + DRV --> HW | ||
| 36 | + | ||
| 37 | + classDef caller fill:#F3E5F5,stroke:#7B1FA2 | ||
| 38 | + classDef ctrl fill:#E3F2FD,stroke:#1565C0 | ||
| 39 | + classDef dp fill:#E8F5E9,stroke:#2E7D32 | ||
| 40 | + classDef infra fill:#FFF3E0,stroke:#E65100 | ||
| 41 | + class FW,HCCL,OP caller | ||
| 42 | + class C1,C2,C3 ctrl | ||
| 43 | + class D1,D2,D3 dp | ||
| 44 | + class DRV,HW infra | ||
| 45 | +``` | ||
| 46 | + | ||
| 47 | +## 简版架构图(文本版,适配终端/纯文本场景) | ||
| 48 | + | ||
| 49 | +```text | ||
| 50 | + AI 框架 ──► libhccl.so〔dlsym 加载 hcomm〕 CCU 自定义通信算子 | ||
| 51 | + | ||
| 52 | + 控制面 C API 数据面 DSL(弱符号) | ||
| 53 | + │ │ | ||
| 54 | + ▼ ▼ | ||
| 55 | + | ||
| 56 | +╭─────────────────────────────────╮ ╭───────────────────────────────────╮ | ||
| 57 | +│ │ │ │ | ||
| 58 | +│ libhcomm.so · 控制面 │ │ libasccomm_ccu_dataplane.so │ | ||
| 59 | +│ 〔 hcomm 仓〕 │ │ 〔 asc-comm 仓 〕· 数据面 │ | ||
| 60 | +│ │ ◄═══ POD ABI ═══► │ │ | ||
| 61 | +│· 通信域 / CCU 实例 / 资源池 │ RegisterContext 快照 │· Kernel 注册 · 录制 REP │ | ||
| 62 | +│· 建链握手 Channel / Jetty │ + controlOps 回调 │· REP 翻译微码 + 调度优化 │ | ||
| 63 | +│· 指令下发 TLV → 驱动 │ │· Launch(rtCCULaunch) │ | ||
| 64 | +│ │ │ │ | ||
| 65 | +╰─────────────────────────────────╯ ╰───────────────────────────────────╯ | ||
| 66 | + | ||
| 67 | + │ │ | ||
| 68 | + (6) TLV (5) rtCCULaunch | ||
| 69 | + ▼ ▼ | ||
| 70 | + | ||
| 71 | +╭─────────────────────────────────────────────────────────────────────────────────────────────╮ | ||
| 72 | +│ 驱 动 / 运 行 时 层:TLV 指令槽 · urma(Jetty) · stream │ | ||
| 73 | +╰─────────────────────────────────────────────────────────────────────────────────────────────╯ | ||
| 74 | + ▼ | ||
| 75 | + | ||
| 76 | +╭─────────────────────────────────────────────────────────────────────────────────────────────╮ | ||
| 77 | +│ CCU 硬件单元(IO Die):Mission × 微码 · URMA 搬数 · XN/GSA/CKE 同步 │ | ||
| 78 | +╰─────────────────────────────────────────────────────────────────────────────────────────────╯ | ||
| 79 | +``` | ||
| 80 | + | ||
| 81 | +一句话流程:算子经数据面 DSL 注册 Kernel(录制 REP → 翻译微码)→ 控制面经 POD ABI 交付资源快照并提供回调(建链、指令下发)→ 数据面 `rtCCULaunch` 提交任务 → CCU 硬件执行微码搬数。 | ||
| 82 | + | ||
| 83 | +## 完整架构图 | ||
| 84 | + | ||
| 85 | +```text | ||
| 86 | +┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ | ||
| 87 | +│ 调用方: AI框架 ──► libhccl.so〔cann/hccl仓, dlsym加载hcomm〕 // CCU自定义通信算子开发者 │ | ||
| 88 | +│ (custom_ccu_allreduce/allgather/broadcast... 样例链接数据面SO) │ | ||
| 89 | +└────────────────────┬────────────────────────────────────────────────────────────────────┬──────────────────────────┘ | ||
| 90 | + (1) 建通信域·绑CCU实例·资源预约 (2) Kernel注册·下发(数据面DSL) | ||
| 91 | + │ │ | ||
| 92 | + ▼ ▼ | ||
| 93 | +┌──────────────────────────────────────┐ ╔══════════════════════════╗ ┌────────────────────────────────────────┐ | ||
| 94 | +│libhcomm.so 〔hcomm 仓〕 │ ║跨 SO ABI 契约层 ║ │libasccomm_ccu_dataplane.so │ | ||
| 95 | +│━━━━━ CCU 控制面 ━━━━━ │ ║(pkg_inc/hcomm/*.h) ║ │〔asc-comm 仓〕━ CCU 数据面 ━ │ | ||
| 96 | +│coll_communicator_mgr 通信域/拓扑 │ ║ ║ │primitives/ CcuXxx 原语实现 │ | ||
| 97 | +│ HcclCommAssignCcuIns │──► ║──► 控制面交付数据面: ║──► │ HcommCcuKernelRegisterStart/ │ | ||
| 98 | +│ HcclCommQueryCcuRegisterContext │ ║ RegisterContextPod ║ │ Register/End (弱符号入口) │ | ||
| 99 | +│ccu_instance/ 实例与资源预约 │ ║ (CCU2只读快照+代际句柄) ║ │resource/kernel/ Kernel录制 │ | ||
| 100 | +│ CcuInstanceMgr / CcuInstance │ ║ LaunchContext/Channel/ ║ │ CcuKernel·Mgr·Registry │ | ||
| 101 | +│ CcuResDescMgr 资源描述符 │ ║ InstructionLoad POD ║ │resource/representation/ REP IR │ | ||
| 102 | +│ CcuVarEventResMgr XN/CKE预约 │ ║ ║ │ ~45种节点(算术/搬运/同步/ │ | ||
| 103 | +│ccu_transport/ 建链握手 │◄── ║◄── 数据面回调控制面: ║◄── │ 控制流/循环) │ | ||
| 104 | +│ CcuTransport/Conn/Jetty │ ║ controlOps 函数表7项 ║ │ + InsGenerator V1(A5)/V2(A6) │ | ||
| 105 | +│ccu_device/ 设备资源·驱动交互 │ ║ channelQuery/loadInstr ║ │resource/microcode(+microcode_opt) │ | ||
| 106 | +│ CcuComponent·CcuResBatchAlloc │ ║ missionCtx/loopCtx/cke/ ║ │ 32B定长微码·指令调度优化 │ | ||
| 107 | +│ CcuChannelCtxMgr V1/V2·PFE │ ║ xn/gsa Query ║ │resource/common/ 资源快照 │ | ||
| 108 | +│ RegisterContextRegistry │ ║ + hcomm侧4个C API ║ │launch: GeneTaskParams │ | ||
| 109 | +│ (代际句柄防悬挂) │ ║ ║ │ (dieId/missionId/args[13]) │ | ||
| 110 | +│对上层: include/hccl·hcomm │ ║契约: 只传POD不传C++对象 ║ │ ──► rtCCULaunch(stream) │ | ||
| 111 | +│ HcclComm*/HcommCcuIns* C API │ ║ 16B ABI头(magic/ver/ ║ │(链接 acl_rt / runtime) │ | ||
| 112 | +│ │ ║ size) + static_assert ║ │ │ | ||
| 113 | +└──────────────────────────────────────┘ ╚══════════════════════════╝ └────────────────────────────────────────┘ | ||
| 114 | + │ │ | ||
| 115 | + ▼ ▼ | ||
| 116 | + (6) TLV驱动交互(指令/通道) (5) rtCCULaunch提交Mission任务 | ||
| 117 | +┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ | ||
| 118 | +│ 驱动/运行时层: runtime(rtCCULaunch) · ascend_hal(HccpRaTlvCcuCustomChannel TLV: │ | ||
| 119 | +│ SET/GET_INSTRUCTION·CHANNEL·JETTY_CTX·MISSION_CTX·LOOP_CTX·GSA/XN/CKE) · urma(Jetty) · Socket(握手) │ | ||
| 120 | +└──────────────────────────────────────────────────────────┬─────────────────────────────────────────────────────────┘ | ||
| 121 | + ▼ | ||
| 122 | +┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ | ||
| 123 | +│ 硬件: Ascend IO Die 内 CCU 集合通信单元 —— Mission(硬件线程)×微码指令槽 · XN/GSA/CKE/MS 资源 │ | ||
| 124 | +│ URMA 统一远端内存访问引擎搬运数据 (950PR/950DT, 高带宽低时延) │ | ||
| 125 | +└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ | ||
| 126 | +``` | ||
| 127 | + | ||
| 128 | +## 运行时主流程 | ||
| 129 | + | ||
| 130 | +1. **建域与资源预约**:框架/HCCL → 控制面,建通信域,`HcclCommAssignCcuIns` / `HcommCcuInsCreate` 创建 CCU 实例,Variable(XN)/Event(CKE) 资源预约与 VA 映射。 | ||
| 131 | +2. **Kernel 注册录制**:算子 → 数据面,`HcommCcuKernelRegisterStart/Register/End`(弱符号,落在数据面 SO),执行用户 kernelFunc,`CcuXxx` 原语录制 REP 中间表示。 | ||
| 132 | +3. **交付快照**:控制面 → 数据面,`HcclCommQueryCcuRegisterContext` 交付 RegisterContext 只读快照(资源 range 视图 + die 元数据 + controlOps 函数表)。 | ||
| 133 | +4. **回调控制面**:数据面 → 控制面,经 controlOps 表 / 4 个 C API(`include/hcomm/hcomm_ccu_{res,channel,instruction,launch}_api.h`)查询 Channel POD、下发微码;翻译产物由控制面走 TLV 驱动接口写入硬件指令槽。 | ||
| 134 | +5. **任务提交**:数据面组 `CcuTaskParam(dieId/missionId/instStartId/args[13])` → `rtCCULaunch` 提交流。 | ||
| 135 | +6. **硬件执行**:CCU Mission 执行微码,URMA 引擎搬运数据,XN/GSA/CKE 完成同步。 | ||
| 136 | + | ||
| 137 | +## 构建期边界保障 | ||
| 138 | + | ||
| 139 | +| 机制 | 说明 | | ||
| 140 | +|------|------| | ||
| 141 | +| 双 SO 联合编译 | 本仓按候选路径查找 / FetchContent 拉取 asc-comm(`cmake/third_party/asccomm-ccu.cmake`),数据面 SO 随 hcomm 包交付;找不到则只构建控制面 | | ||
| 142 | +| 源归属校验(双向) | `hcomm_check_source_ownership(hcomm/hccl_v2)` + asc-comm 侧对称校验,禁止跨仓引用源文件 | | ||
| 143 | +| 链接期校验(双向) | 双方均 `-Wl,--no-undefined`,不允许无意识依赖对方符号 | | ||
| 144 | +| 单源双头 | 资源仓库类型 `pub_inc/ccu_res_repo.h` ⇔ `internal/hcomm/resource/common/ccu_res_repository_local.h` 宏互斥定义 | | ||
| 145 | +| POD 契约 | 跨 SO 只传 POD(16B ABI 头 magic/version/size + `static_assert` 锁布局),不传 C++ 对象 | | ||
| 146 | + | ||
| 147 | +> 注:当前 dev_rename 分支为过渡态,libhcomm 内仍保留一套进程内旧实现(`src/base_comm/resources/ccu/{ccu_kernel,ccu_representation,ccu_microcode}` + `primitives/api_c_adpt/ccu`)作兼容,图中为目标拆分形态。 | ||
| 148 | + | ||
| 149 | +## 关键路径速查 | ||
| 150 | + | ||
| 151 | +``` | ||
| 152 | +hcomm 仓(控制面) | ||
| 153 | +├── include/ccu/ # DSL 头(Variable/Event/Buffer/Loop + ccu_res.h/ccu_launch.h 弱符号) | ||
| 154 | +├── include/hcomm/hcomm_ccu_*_api.h # 数据面调用的 4 个 C API | ||
| 155 | +├── pkg_inc/hcomm/hcomm_ccu_*.h # 跨 SO POD ABI(abi/common/res/control/channel/instruction/launch/dfx) | ||
| 156 | +├── src/base_comm/resources/ccu/ | ||
| 157 | +│ ├── ccu_instance/ # CcuInstanceMgr/CcuInstance/CcuResDescMgr/CcuVarEventResMgr | ||
| 158 | +│ ├── ccu_transport/ # CcuTransport/CcuConnection/CcuJetty 建链握手 | ||
| 159 | +│ └── ccu_device/ # CcuComponent/资源分配器/ChannelCtxMgr V1,V2/RegisterContextRegistry | ||
| 160 | +└── cmake/third_party/asccomm-ccu.cmake # 数据面 SO 联合编译与交付 | ||
| 161 | + | ||
| 162 | +asc-comm 仓(数据面) | ||
| 163 | +├── src/ccu/hcomm/primitives/ # CcuXxx 原语实现 + Kernel 注册/Launch | ||
| 164 | +├── src/ccu/hcomm/resource/kernel/ # CcuKernel/CcuKernelMgr/CcuKernelRegistry | ||
| 165 | +├── src/ccu/hcomm/resource/representation/ # REP IR + InsGenerator V1(A5)/V2(A6) 翻译器 | ||
| 166 | +├── src/ccu/hcomm/resource/microcode(+_opt)/ # 32B 定长微码 + 指令调度优化 | ||
| 167 | +└── include/ccu/hcomm/ # 数据面公共 DSL 头(安装供 CCU 算子开发者使用) | ||
| 168 | +``` | ||
| @@ -0,0 +1,168 @@ | |||
| 1 | +# HCOMM CCU 数据面 SO 拆分架构图 | ||
| 2 | + | ||
| 3 | +HCOMM 将 CCU(Collective Communication Unit)能力拆分为**控制面**(本仓 hcomm,产出 `libhcomm.so`)与**数据面**(asc-comm 仓,产出 `libasccomm_ccu_dataplane.so`)两个独立 SO,通过 POD ABI 契约层交互,可独立编译、独立版本演进。 | ||
| 4 | + | ||
| 5 | +## 架构图(Mermaid 渲染版) | ||
| 6 | + | ||
| 7 | +```mermaid | ||
| 8 | +flowchart TD | ||
| 9 | + subgraph CALLER["调用方"] | ||
| 10 | + FW["AI 框架"] --> HCCL["libhccl.so(cann/hccl 仓)"] | ||
| 11 | + OP["CCU 自定义通信算子"] | ||
| 12 | + end | ||
| 13 | + | ||
| 14 | + subgraph CTRL["libhcomm.so · 控制面(hcomm 仓)"] | ||
| 15 | + C1["通信域 / CCU 实例 / 资源池"] | ||
| 16 | + C2["建链握手 Channel / Jetty"] | ||
| 17 | + C3["指令下发(TLV → 驱动)"] | ||
| 18 | + end | ||
| 19 | + | ||
| 20 | + subgraph DP["libasccomm_ccu_dataplane.so · 数据面(asc-comm 仓)"] | ||
| 21 | + D1["Kernel 注册 · 录制 REP"] | ||
| 22 | + D2["REP 翻译微码 + 调度优化"] | ||
| 23 | + D3["Launch(rtCCULaunch)"] | ||
| 24 | + end | ||
| 25 | + | ||
| 26 | + DRV["驱动 / 运行时<br/>TLV 指令槽 · urma(Jetty) · stream"] | ||
| 27 | + HW["CCU 硬件单元(IO Die)<br/>Mission × 微码 · URMA 搬数 · XN/GSA/CKE 同步"] | ||
| 28 | + | ||
| 29 | + HCCL -->|"(1) 控制面 C API"| CTRL | ||
| 30 | + OP -->|"(2) 数据面 DSL(弱符号)"| DP | ||
| 31 | + CTRL -.->|"(3) RegisterContext 只读快照"| DP | ||
| 32 | + DP -.->|"(4) controlOps 回调 / 4 个 C API"| CTRL | ||
| 33 | + DP -->|"(5) rtCCULaunch 提交任务"| DRV | ||
| 34 | + CTRL -->|"(6) TLV 驱动交互"| DRV | ||
| 35 | + DRV --> HW | ||
| 36 | + | ||
| 37 | + classDef caller fill:#F3E5F5,stroke:#7B1FA2 | ||
| 38 | + classDef ctrl fill:#E3F2FD,stroke:#1565C0 | ||
| 39 | + classDef dp fill:#E8F5E9,stroke:#2E7D32 | ||
| 40 | + classDef infra fill:#FFF3E0,stroke:#E65100 | ||
| 41 | + class FW,HCCL,OP caller | ||
| 42 | + class C1,C2,C3 ctrl | ||
| 43 | + class D1,D2,D3 dp | ||
| 44 | + class DRV,HW infra | ||
| 45 | +``` | ||
| 46 | + | ||
| 47 | +## 简版架构图(文本版,适配终端/纯文本场景) | ||
| 48 | + | ||
| 49 | +```text | ||
| 50 | + AI 框架 ──► libhccl.so〔dlsym 加载 hcomm〕 CCU 自定义通信算子 | ||
| 51 | + | ||
| 52 | + 控制面 C API 数据面 DSL(弱符号) | ||
| 53 | + │ │ | ||
| 54 | + ▼ ▼ | ||
| 55 | + | ||
| 56 | +╭─────────────────────────────────╮ ╭───────────────────────────────────╮ | ||
| 57 | +│ │ │ │ | ||
| 58 | +│ libhcomm.so · 控制面 │ │ libasccomm_ccu_dataplane.so │ | ||
| 59 | +│ 〔 hcomm 仓〕 │ │ 〔 asc-comm 仓 〕· 数据面 │ | ||
| 60 | +│ │ ◄═══ POD ABI ═══► │ │ | ||
| 61 | +│· 通信域 / CCU 实例 / 资源池 │ RegisterContext 快照 │· Kernel 注册 · 录制 REP │ | ||
| 62 | +│· 建链握手 Channel / Jetty │ + controlOps 回调 │· REP 翻译微码 + 调度优化 │ | ||
| 63 | +│· 指令下发 TLV → 驱动 │ │· Launch(rtCCULaunch) │ | ||
| 64 | +│ │ │ │ | ||
| 65 | +╰─────────────────────────────────╯ ╰───────────────────────────────────╯ | ||
| 66 | + | ||
| 67 | + │ │ | ||
| 68 | + (6) TLV (5) rtCCULaunch | ||
| 69 | + ▼ ▼ | ||
| 70 | + | ||
| 71 | +╭─────────────────────────────────────────────────────────────────────────────────────────────╮ | ||
| 72 | +│ 驱 动 / 运 行 时 层:TLV 指令槽 · urma(Jetty) · stream │ | ||
| 73 | +╰─────────────────────────────────────────────────────────────────────────────────────────────╯ | ||
| 74 | + ▼ | ||
| 75 | + | ||
| 76 | +╭─────────────────────────────────────────────────────────────────────────────────────────────╮ | ||
| 77 | +│ CCU 硬件单元(IO Die):Mission × 微码 · URMA 搬数 · XN/GSA/CKE 同步 │ | ||
| 78 | +╰─────────────────────────────────────────────────────────────────────────────────────────────╯ | ||
| 79 | +``` | ||
| 80 | + | ||
| 81 | +一句话流程:算子经数据面 DSL 注册 Kernel(录制 REP → 翻译微码)→ 控制面经 POD ABI 交付资源快照并提供回调(建链、指令下发)→ 数据面 `rtCCULaunch` 提交任务 → CCU 硬件执行微码搬数。 | ||
| 82 | + | ||
| 83 | +## 完整架构图 | ||
| 84 | + | ||
| 85 | +```text | ||
| 86 | +┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ | ||
| 87 | +│ 调用方: AI框架 ──► libhccl.so〔cann/hccl仓, dlsym加载hcomm〕 // CCU自定义通信算子开发者 │ | ||
| 88 | +│ (custom_ccu_allreduce/allgather/broadcast... 样例链接数据面SO) │ | ||
| 89 | +└────────────────────┬────────────────────────────────────────────────────────────────────┬──────────────────────────┘ | ||
| 90 | + (1) 建通信域·绑CCU实例·资源预约 (2) Kernel注册·下发(数据面DSL) | ||
| 91 | + │ │ | ||
| 92 | + ▼ ▼ | ||
| 93 | +┌──────────────────────────────────────┐ ╔══════════════════════════╗ ┌────────────────────────────────────────┐ | ||
| 94 | +│libhcomm.so 〔hcomm 仓〕 │ ║跨 SO ABI 契约层 ║ │libasccomm_ccu_dataplane.so │ | ||
| 95 | +│━━━━━ CCU 控制面 ━━━━━ │ ║(pkg_inc/hcomm/*.h) ║ │〔asc-comm 仓〕━ CCU 数据面 ━ │ | ||
| 96 | +│coll_communicator_mgr 通信域/拓扑 │ ║ ║ │primitives/ CcuXxx 原语实现 │ | ||
| 97 | +│ HcclCommAssignCcuIns │──► ║──► 控制面交付数据面: ║──► │ HcommCcuKernelRegisterStart/ │ | ||
| 98 | +│ HcclCommQueryCcuRegisterContext │ ║ RegisterContextPod ║ │ Register/End (弱符号入口) │ | ||
| 99 | +│ccu_instance/ 实例与资源预约 │ ║ (CCU2只读快照+代际句柄) ║ │resource/kernel/ Kernel录制 │ | ||
| 100 | +│ CcuInstanceMgr / CcuInstance │ ║ LaunchContext/Channel/ ║ │ CcuKernel·Mgr·Registry │ | ||
| 101 | +│ CcuResDescMgr 资源描述符 │ ║ InstructionLoad POD ║ │resource/representation/ REP IR │ | ||
| 102 | +│ CcuVarEventResMgr XN/CKE预约 │ ║ ║ │ ~45种节点(算术/搬运/同步/ │ | ||
| 103 | +│ccu_transport/ 建链握手 │◄── ║◄── 数据面回调控制面: ║◄── │ 控制流/循环) │ | ||
| 104 | +│ CcuTransport/Conn/Jetty │ ║ controlOps 函数表7项 ║ │ + InsGenerator V1(A5)/V2(A6) │ | ||
| 105 | +│ccu_device/ 设备资源·驱动交互 │ ║ channelQuery/loadInstr ║ │resource/microcode(+microcode_opt) │ | ||
| 106 | +│ CcuComponent·CcuResBatchAlloc │ ║ missionCtx/loopCtx/cke/ ║ │ 32B定长微码·指令调度优化 │ | ||
| 107 | +│ CcuChannelCtxMgr V1/V2·PFE │ ║ xn/gsa Query ║ │resource/common/ 资源快照 │ | ||
| 108 | +│ RegisterContextRegistry │ ║ + hcomm侧4个C API ║ │launch: GeneTaskParams │ | ||
| 109 | +│ (代际句柄防悬挂) │ ║ ║ │ (dieId/missionId/args[13]) │ | ||
| 110 | +│对上层: include/hccl·hcomm │ ║契约: 只传POD不传C++对象 ║ │ ──► rtCCULaunch(stream) │ | ||
| 111 | +│ HcclComm*/HcommCcuIns* C API │ ║ 16B ABI头(magic/ver/ ║ │(链接 acl_rt / runtime) │ | ||
| 112 | +│ │ ║ size) + static_assert ║ │ │ | ||
| 113 | +└──────────────────────────────────────┘ ╚══════════════════════════╝ └────────────────────────────────────────┘ | ||
| 114 | + │ │ | ||
| 115 | + ▼ ▼ | ||
| 116 | + (6) TLV驱动交互(指令/通道) (5) rtCCULaunch提交Mission任务 | ||
| 117 | +┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ | ||
| 118 | +│ 驱动/运行时层: runtime(rtCCULaunch) · ascend_hal(HccpRaTlvCcuCustomChannel TLV: │ | ||
| 119 | +│ SET/GET_INSTRUCTION·CHANNEL·JETTY_CTX·MISSION_CTX·LOOP_CTX·GSA/XN/CKE) · urma(Jetty) · Socket(握手) │ | ||
| 120 | +└──────────────────────────────────────────────────────────┬─────────────────────────────────────────────────────────┘ | ||
| 121 | + ▼ | ||
| 122 | +┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ | ||
| 123 | +│ 硬件: Ascend IO Die 内 CCU 集合通信单元 —— Mission(硬件线程)×微码指令槽 · XN/GSA/CKE/MS 资源 │ | ||
| 124 | +│ URMA 统一远端内存访问引擎搬运数据 (950PR/950DT, 高带宽低时延) │ | ||
| 125 | +└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ | ||
| 126 | +``` | ||
| 127 | + | ||
| 128 | +## 运行时主流程 | ||
| 129 | + | ||
| 130 | +1. **建域与资源预约**:框架/HCCL → 控制面,建通信域,`HcclCommAssignCcuIns` / `HcommCcuInsCreate` 创建 CCU 实例,Variable(XN)/Event(CKE) 资源预约与 VA 映射。 | ||
| 131 | +2. **Kernel 注册录制**:算子 → 数据面,`HcommCcuKernelRegisterStart/Register/End`(弱符号,落在数据面 SO),执行用户 kernelFunc,`CcuXxx` 原语录制 REP 中间表示。 | ||
| 132 | +3. **交付快照**:控制面 → 数据面,`HcclCommQueryCcuRegisterContext` 交付 RegisterContext 只读快照(资源 range 视图 + die 元数据 + controlOps 函数表)。 | ||
| 133 | +4. **回调控制面**:数据面 → 控制面,经 controlOps 表 / 4 个 C API(`include/hcomm/hcomm_ccu_{res,channel,instruction,launch}_api.h`)查询 Channel POD、下发微码;翻译产物由控制面走 TLV 驱动接口写入硬件指令槽。 | ||
| 134 | +5. **任务提交**:数据面组 `CcuTaskParam(dieId/missionId/instStartId/args[13])` → `rtCCULaunch` 提交流。 | ||
| 135 | +6. **硬件执行**:CCU Mission 执行微码,URMA 引擎搬运数据,XN/GSA/CKE 完成同步。 | ||
| 136 | + | ||
| 137 | +## 构建期边界保障 | ||
| 138 | + | ||
| 139 | +| 机制 | 说明 | | ||
| 140 | +|------|------| | ||
| 141 | +| 双 SO 联合编译 | 本仓按候选路径查找 / FetchContent 拉取 asc-comm(`cmake/third_party/asccomm-ccu.cmake`),数据面 SO 随 hcomm 包交付;找不到则只构建控制面 | | ||
| 142 | +| 源归属校验(双向) | `hcomm_check_source_ownership(hcomm/hccl_v2)` + asc-comm 侧对称校验,禁止跨仓引用源文件 | | ||
| 143 | +| 链接期校验(双向) | 双方均 `-Wl,--no-undefined`,不允许无意识依赖对方符号 | | ||
| 144 | +| 单源双头 | 资源仓库类型 `pub_inc/ccu_res_repo.h` ⇔ `internal/hcomm/resource/common/ccu_res_repository_local.h` 宏互斥定义 | | ||
| 145 | +| POD 契约 | 跨 SO 只传 POD(16B ABI 头 magic/version/size + `static_assert` 锁布局),不传 C++ 对象 | | ||
| 146 | + | ||
| 147 | +> 注:当前 dev_rename 分支为过渡态,libhcomm 内仍保留一套进程内旧实现(`src/base_comm/resources/ccu/{ccu_kernel,ccu_representation,ccu_microcode}` + `primitives/api_c_adpt/ccu`)作兼容,图中为目标拆分形态。 | ||
| 148 | + | ||
| 149 | +## 关键路径速查 | ||
| 150 | + | ||
| 151 | +``` | ||
| 152 | +hcomm 仓(控制面) | ||
| 153 | +├── include/ccu/ # DSL 头(Variable/Event/Buffer/Loop + ccu_res.h/ccu_launch.h 弱符号) | ||
| 154 | +├── include/hcomm/hcomm_ccu_*_api.h # 数据面调用的 4 个 C API | ||
| 155 | +├── pkg_inc/hcomm/hcomm_ccu_*.h # 跨 SO POD ABI(abi/common/res/control/channel/instruction/launch/dfx) | ||
| 156 | +├── src/base_comm/resources/ccu/ | ||
| 157 | +│ ├── ccu_instance/ # CcuInstanceMgr/CcuInstance/CcuResDescMgr/CcuVarEventResMgr | ||
| 158 | +│ ├── ccu_transport/ # CcuTransport/CcuConnection/CcuJetty 建链握手 | ||
| 159 | +│ └── ccu_device/ # CcuComponent/资源分配器/ChannelCtxMgr V1,V2/RegisterContextRegistry | ||
| 160 | +└── cmake/third_party/asccomm-ccu.cmake # 数据面 SO 联合编译与交付 | ||
| 161 | + | ||
| 162 | +asc-comm 仓(数据面) | ||
| 163 | +├── src/ccu/hcomm/primitives/ # CcuXxx 原语实现 + Kernel 注册/Launch | ||
| 164 | +├── src/ccu/hcomm/resource/kernel/ # CcuKernel/CcuKernelMgr/CcuKernelRegistry | ||
| 165 | +├── src/ccu/hcomm/resource/representation/ # REP IR + InsGenerator V1(A5)/V2(A6) 翻译器 | ||
| 166 | +├── src/ccu/hcomm/resource/microcode(+_opt)/ # 32B 定长微码 + 指令调度优化 | ||
| 167 | +└── include/ccu/hcomm/ # 数据面公共 DSL 头(安装供 CCU 算子开发者使用) | ||
| 168 | +``` | ||
| @@ -0,0 +1,432 @@ | |||
| 1 | +# CCU 模式北向接口调用时序(首次下发 / 快速下发 / 回退 AICPU) | ||
| 2 | + | ||
| 3 | +> 范围:以 HCCL 仓(`cann/hccl`)AllReduce 为样本算子,梳理 CCU 模式的三种主要流程下 **HCCL → HCOMM 的 CCU 北向接口**(dlsym C ABI)调用时序。 | ||
| 4 | +> | ||
| 5 | +> 术语: | ||
| 6 | +> - **北向接口** = HCCL 调 HCOMM 的 C ABI 边界(`hccl/src/common/hcomm_dlsym/` 中的弱符号 + `dlsym`,HCOMM 侧 `HCOMM_WEAK_SYMBOL` 导出)。南向 = HCOMM 之下的 Runtime/Driver 边界(`rtCCULaunch` / TLV / `hrtMemcpy`),本文只作终点标注。 | ||
| 7 | +> - **CCU 三段式**:注册期「就地执行 kernelFunc 录制 rep」→ 翻译期「rep 翻成微码并装载指令空间」→ 发射期「只换 taskArgs 下发」。 | ||
| 8 | +> | ||
| 9 | +> 代码基线:`hccl/` 与 `hcomm/` 与 `CheckerL2/` 同层目录。 | ||
| 10 | + | ||
| 11 | +--- | ||
| 12 | + | ||
| 13 | +## 0. 三条流程的判定入口(一张图) | ||
| 14 | + | ||
| 15 | +```mermaid | ||
| 16 | +flowchart TD | ||
| 17 | + A["HcclAllReduce<br/>(all_reduce.cc:AllReduceOutPlaceCommon)"] --> B["HcclGetOpExpansionMode<br/>param.engine = COMM_ENGINE_CCU"] | ||
| 18 | + B --> C{"ShouldGoCcuFastLaunch?<br/>(op_common.cc:386)"} | ||
| 19 | + C -->|"① engine==CCU 且非 OFFLOAD<br/>② engineCtx 命中 fastLaunchTag"| FAST["★ 流程二:快速下发<br/>HcclExecOpCcuFastLaunch<br/>(op_common.cc:559)"] | ||
| 20 | + C -->|"未命中"| SEL["Selector<br/>(op_common.cc:159)"] | ||
| 21 | + SEL --> SEL2["CheckCcuParamAndFallback<br/>(ccu_fallback.cc:482)<br/>跨 rank 协商 opExecuteConfig"] | ||
| 22 | + SEL2 --> EXEC["HcclExecOp<br/>(op_common.cc:787)<br/>★ 流程一:首次下发(慢路径)"] | ||
| 23 | + EXEC --> RES{"HcclGetAlgRes<br/>资源是否 UNAVAIL?"} | ||
| 24 | + RES -->|"可用"| REG["资源申请 + Kernel 注册 + Orchestrate<br/>→ HcommCcuKernelLaunch"] | ||
| 25 | + RES -->|"UNAVAIL"| FB["★ 流程三:回退<br/>FallbackOp (op_common.cc:652)<br/>CCU_MS→CCU_SCHED→AICPU_TS"] | ||
| 26 | + FB --> EXEC | ||
| 27 | + REG --> SAVE["FastLaunchSaveCtx<br/>写 engineCtx(供流程二命中)"] | ||
| 28 | +``` | ||
| 29 | + | ||
| 30 | +三条流程的本质区别只有「走到哪一段、跳过哪一段」: | ||
| 31 | + | ||
| 32 | +| 流程 | 入口 | 是否选算法 | 是否申请资源/注册 kernel | 运行期北向调用 | | ||
| 33 | +|---|---|---|---|---| | ||
| 34 | +| ① 首次下发 | `HcclExecOp` 慢路径 | 是(Selector) | 是(三件套 + 84 原语录制 + 翻译) | `HcommCcuKernelLaunch` | | ||
| 35 | +| ② 快速下发 | `ShouldGoCcuFastLaunch` 命中 | 否(复用 ctx.algName) | 否(复用 ctx 的 thread/kernelHandle/cachedArgs) | `HcommCcuKernelLaunch` | | ||
| 36 | +| ③ 回退 AICPU | 资源/协商失败 → `FallbackOp` | 是(ReSelector 降级重选) | **不再走 CCU**(改 AICPU 资源) | 无(转 AICPU 北向族) | | ||
| 37 | + | ||
| 38 | +--- | ||
| 39 | + | ||
| 40 | +## 1. CCU 北向接口全景(调用时序图的「参与者」) | ||
| 41 | + | ||
| 42 | +### 1.1 接口分类与符号/实现映射 | ||
| 43 | + | ||
| 44 | +| 类 | 北向符号(HCCL 侧声明文件) | HCOMM 侧实现 | 暴露时机 | | ||
| 45 | +|---|---|---|---| | ||
| 46 | +| **A. 通信域↔实例绑定** | `HcclCommQueryCcuIns` / `HcclCommQueryAssignedCcuIns` / `HcclCommAssignCcuIns`<br/>(`hccl_ccu_res_dl.h`) | `coll_comm_ccu_c_adpt.cc:67 / :109 / :148` | 资源申请期 | | ||
| 47 | +| **B. 实例/资源族** | `HcommCcuInsResDescCreate` / `Destroy` / `SetNum` / `QueryNum`、`HcommCcuInsCreate` / `CreateDefault` / `Destroy` / `QueryResDesc`、`HcommCcuQueryRemainResDesc`、`HcommCcuKernelQueryResReq`<br/>(`ccu_res_dl.h`) | `ccu_res_c_adpt.cc` | 首算子资源申请期 | | ||
| 48 | +| **B'. 实例/资源族(兼容旧包)** | `HcommCcuInsCreateLegacy`、`HcommCcuGetMemToken` | `ccu_res_c_adpt.cc:195`、`ccu_launch.cc:406` | 旧路径 / 每次下发 | | ||
| 49 | +| **C. Kernel 生命周期(弱定义 W)** | `HcommCcuKernelRegisterStart` / `HcommCcuKernelRegister` / `HcommCcuKernelRegisterEnd` / `HcommCcuKernelLaunch`<br/>(`ccu_launch_dl.h`) | `ccu_launch.cc:47 / :77 / :120 / :293` | 注册期 / 每次下发 | | ||
| 50 | +| **D. DSL 原语族(84~88 个)** | `CcuVariableAlloc` / `CcuLoadArg` / `CcuNotifyRecord` / `CcuNotifyWait` / `CcuWriteVariableWithNotify` / `CcuReadMemToMem` / `CcuLocalMemReduce` / `CcuLoopGroupCreate` / `CcuIf*` / `CcuWhile*` …<br/>(`ccu_primitives_impl_dl.h` ↔ `hcomm/include/ccu/ccu_primitives.hpp`) | `ccu_primitives_impl.cc` | **仅注册期**(kernelFunc 内) | | ||
| 51 | +| **E. 线程/通道(既有桩 + CCU 分支)** | `HcclThreadAcquireWithStream` / `HcclChannelAcquire` / `HcclChannelQuery` / `HcclRankGraphGetEndpointInfo` | HCOMM base_comm thread/channel | 资源申请期(每次慢路径)/ 快速下发期(仅 thread) | | ||
| 52 | +| **F. 辅助查询** | `HcommCcuGetTaskArgsNum`、`HcclGetCcuTaskInfo` | `ccu_launch.cc:138` | 可选 | | ||
| 53 | + | ||
| 54 | +### 1.2 关键不变量 | ||
| 55 | + | ||
| 56 | +1. **注册期录 rep、发射期只换 args**:`HcommCcuKernelRegister` 内**同步回调** `kernelFunc`,函数体里逐条 `Ccu*` 原语不搬数、只把动作录成 rep 存进 `CcuKernel::res_`;`HcommCcuKernelRegisterEnd` 的 `Translate` 才把 rep 翻成微码并 `LoadInstruction`。 | ||
| 57 | +2. **原语作用于「当前注册 kernel」**:所有 `Ccu*` 实现 = `CcuKernelMgr::GetInstance(devId).GetCurrentKernel()->XXX()`,依赖 TLS 注册事务上下文。 | ||
| 58 | +3. **`HcommCcuKernelLaunch` 的 threadHandle 是 RTS Thread**:HCOMM 侧 `reinterpret_cast<hccl::Thread*>` 后 `GetStream()->ptr()` 取挂载的 `aclrtStream`。 | ||
| 59 | + | ||
| 60 | +--- | ||
| 61 | + | ||
| 62 | +## 2. 流程一:首次算子下发(慢路径) | ||
| 63 | + | ||
| 64 | +### 2.1 时序图 | ||
| 65 | + | ||
| 66 | +```mermaid | ||
| 67 | +sequenceDiagram | ||
| 68 | + autonumber | ||
| 69 | + participant APP as AI 框架 / 用户 | ||
| 70 | + participant OPS as HCCL 编排层<br/>(op_common.cc) | ||
| 71 | + participant EXE as HCCL 执行器/模板<br/>(ins_v2_all_reduce_sole_executor.cc<br/>ccu_temp_all_reduce_mesh_1D_one_shot.cc) | ||
| 72 | + participant NA as HCCL 算法体<br/>(ccu_kernel_all_reduce_mesh1d_one_shot.cc) | ||
| 73 | + participant DL as dlsym 弱符号桥<br/>(hcomm_dlsym/*_dl.*) | ||
| 74 | + participant HC as HCOMM CCU<br/>(ccu_launch.cc / ccu_res_c_adpt.cc<br/>coll_comm_ccu_c_adpt.cc) | ||
| 75 | + participant HW as 南向 Runtime/Driver<br/>(rtCCULaunch / TLV / hrtMemcpy) | ||
| 76 | + | ||
| 77 | + APP->>OPS: HcclAllReduce(...) | ||
| 78 | + OPS->>OPS: HcclGetOpExpansionMode → param.engine=CCU | ||
| 79 | + Note over OPS: ShouldGoCcuFastLaunch 未命中(首跑无 ctx) | ||
| 80 | + OPS->>OPS: Selector:选算法 CcuMSAllReduceSoleMeshOneShot 等 | ||
| 81 | + OPS->>DL: CheckCcuParamAndFallbackC(跨 rank 协商 opExecuteConfig) | ||
| 82 | + DL->>HC: (子通信域 AllGather,AICPU 模式) / 命中缓存则跳过 | ||
| 83 | + | ||
| 84 | + rect rgb(225,240,255) | ||
| 85 | + Note over OPS,HW: P1 资源申请 HcclGetAlgRes → GetAlgResCcu → HcclAllocAlgResourceCcu | ||
| 86 | + OPS->>DL: HcclGetHcclBuffer(取 cclMem/scratch,通用) | ||
| 87 | + OPS->>DL: HcclThreadAcquireWithStream(comm, CCU, stream, notifyNum) | ||
| 88 | + DL->>HC: 申请 CCU 主流 Thread(Mission 载体) | ||
| 89 | + OPS->>DL: HcclChannelQuery / HcclChannelAcquire(comm, CCU, descs[], n) | ||
| 90 | + DL->>HC: 以 kernel 为粒度申请 channel | ||
| 91 | + OPS->>DL: HcclRankGraphGetEndpointInfo(ENDPOINT_ATTR_DIE_ID) → dieId | ||
| 92 | + end | ||
| 93 | + | ||
| 94 | + rect rgb(235,250,235) | ||
| 95 | + Note over OPS,HW: P2 Kernel 注册 HcclGetCcuKernelDynamic(三件套) | ||
| 96 | + OPS->>DL: HcommCcuInsResDescCreate / SetNum(按 dieId 聚合资源需求) | ||
| 97 | + OPS->>DL: HcommCcuQueryRemainResDesc(IsDieEnabledForPadding 探测 die 使能) | ||
| 98 | + OPS->>DL: HcclCommQueryAssignedCcuIns → HCCL_E_UNAVAIL(首调未绑定) | ||
| 99 | + OPS->>DL: HcommCcuInsResDescCreate / QueryNum / SetNum(finalReqDesc) | ||
| 100 | + OPS->>DL: HcommCcuInsCreate → newInsHandle | ||
| 101 | + DL->>HC: CcuInstanceMgr::Create → CcuInstance::Init(建资源池) | ||
| 102 | + OPS->>DL: HcclCommAssignCcuIns(comm, insHandle) | ||
| 103 | + loop 每个 resGroup | ||
| 104 | + OPS->>DL: HcommCcuKernelRegisterStart(insHandle) | ||
| 105 | + DL->>HC: CcuInstance::BeginRegister + Reset | ||
| 106 | + loop 每个 kernel | ||
| 107 | + OPS->>DL: HcommCcuKernelRegister(ins, dieId, funcName, kernelFunc, args, 1) | ||
| 108 | + DL->>HC: CcuKernelMgr::Register → 同步回调 kernelFunc | ||
| 109 | + HC->>NA: ccuKernelFunc(kernelArg)(就地执行一次) | ||
| 110 | + loop kernelFunc 内每条原语 | ||
| 111 | + NA->>DL: CcuVariableAlloc / CcuLoadArg / CcuNotifyRecord / CcuReadMemToMem / CcuLocalMemReduce / CcuLoopGroupCreate ... | ||
| 112 | + DL->>HC: CcuKernelMgr::GetCurrentKernel()->XXX() → Append(rep) | ||
| 113 | + end | ||
| 114 | + HC-->>OPS: kernelHandle | ||
| 115 | + end | ||
| 116 | + OPS->>DL: HcommCcuKernelRegisterEnd(insHandle) | ||
| 117 | + DL->>HC: EndRegister + CcuKernelMgr::Translate(rep→微码) | ||
| 118 | + HC->>HW: LoadInstruction → hrtMemcpy(指令空间) | ||
| 119 | + end | ||
| 120 | + end | ||
| 121 | + | ||
| 122 | + rect rgb(255,245,230) | ||
| 123 | + Note over OPS,HW: P3 编排发射 exec->Orchestrate → template->KernelRun | ||
| 124 | + OPS->>EXE: executor->Orchestrate(param, resCtxHost) | ||
| 125 | + EXE->>EXE: OrchestrateLoop(按 maxDataCountPerLoop 切 loop) | ||
| 126 | + EXE->>EXE: template->KernelRun(param, tempAlgParams, templateAlgRes) | ||
| 127 | + EXE->>DL: HcommCcuGetMemToken(va, size) → token | ||
| 128 | + EXE->>DL: HcommCcuKernelLaunch(thread, kernelHandle, taskArgs[7], 7) | ||
| 129 | + DL->>HC: GeneTaskParams + LaunchCcuTasks | ||
| 130 | + HC->>HW: rtCCULaunch(&taskInfo, stream)(每个切片一次) | ||
| 131 | + end | ||
| 132 | + | ||
| 133 | + rect rgb(250,235,250) | ||
| 134 | + Note over OPS: P4 首跑缓存(供流程二命中) | ||
| 135 | + EXE->>OPS: loopTimes==1 时 FastLaunchSaveCtx | ||
| 136 | + OPS->>OPS: HcclEngineCtxCreate(fastLaunchTag, COMM_ENGINE_CCU, size)<br/>存 algName / threadNum / notifyNum / kernelHandle / cachedArgs | ||
| 137 | + end | ||
| 138 | + OPS-->>APP: 返回 | ||
| 139 | +``` | ||
| 140 | + | ||
| 141 | +### 2.2 关键步骤与北向接口清单 | ||
| 142 | + | ||
| 143 | +| 阶段 | HCCL 调用点 | 北向接口(dlsym) | HCOMM 实现 | 产物 | | ||
| 144 | +|---|---|---|---|---| | ||
| 145 | +| 算法选择 | `Selector`→`CheckCcuParamAndFallback` | (子通信域协商,非 CCU 主链路) | `ccu_fallback.cc:482` | `algName` + 最终 `opExecuteConfig` | | ||
| 146 | +| 线程 | `HcclAllocAlgResourceCcu`→`HcclGetThread` | `HcclThreadAcquireWithStream(CCU)` | base_comm thread | `resCtxHost->threads[0]`(主流) | | ||
| 147 | +| 通道 | `HcclGetChannelForCcu`→`CcuAcquireKernelChannels` | `HcclChannelQuery`、`HcclChannelAcquire`、`HcclRankGraphGetEndpointInfo` | base_comm channel | `kernelArg->channels[i]` + `kernelInfo.dieId` | | ||
| 148 | +| 需求聚合 | `BuildAggregatedResReq` | `HcommCcuInsResDescCreate` / `SetNum` / `Destroy`,`HcommCcuQueryRemainResDesc` | `ccu_res_c_adpt.cc` | `reqDescs`(按 dieId) | | ||
| 149 | +| 查实例 | `HcclGetCcuKernelDynamic` | `HcclCommQueryAssignedCcuIns`(首调 UNAVAIL) | `coll_comm_ccu_c_adpt.cc:109` | 走新建路径 | | ||
| 150 | +| 建实例 | `CreateAndAssignNewCcuIns` | `HcommCcuInsResDescCreate/QueryNum/SetNum`、`HcommCcuInsCreate`、`HcclCommAssignCcuIns` | `ccu_res_c_adpt.cc:208`、`coll_comm_ccu_c_adpt.cc:148` | `insHandle` 绑定到 comm | | ||
| 151 | +| 注册 | `RegisterCcuKernels` | `HcommCcuKernelRegisterStart` / `HcommCcuKernelRegister` / `HcommCcuKernelRegisterEnd` | `ccu_launch.cc:47/:77/:120` | `kernelHandle` + 微码已装载 | | ||
| 152 | +| 录制 | (HCOMM 回调 kernelFunc) | `CcuVariableAlloc` / `CcuLoadArg` / `CcuNotify*` / `CcuReadMemToMem` / `CcuLocalMemReduce` / `CcuLoopGroupCreate` … | `ccu_primitives_impl.cc` | `CcuKernel::res_`(rep 序列) | | ||
| 153 | +| 发射 | `template->KernelRun` | `HcommCcuGetMemToken`、`HcommCcuKernelLaunch` | `ccu_launch.cc:406/:293` | `rtCCULaunch`(南向) | | ||
| 154 | +| 缓存 | `FastLaunchSaveCtx` | (非跨仓,`HcclEngineCtxCreate`) | — | `fastLaunchCtx` | | ||
| 155 | + | ||
| 156 | +> **慢路径里的 CCU 资源回退点**:`HcclGetChannelForCcu` 的 `HcclChannelAcquire` 返回 `HCCL_E_UNAVAIL`,或 `HcclGetCcuKernelDynamic` 的容量判定/`HcommCcuInsCreate`/`HcommCcuKernelRegister` 返回 `CCU_E_UNAVAIL`,都会让 `HcclGetAlgRes` 返回 `HCCL_E_UNAVAIL` → 触发流程三。 | ||
| 157 | + | ||
| 158 | +--- | ||
| 159 | + | ||
| 160 | +## 3. 流程二:快速下发(快路径) | ||
| 161 | + | ||
| 162 | +### 3.1 时序图 | ||
| 163 | + | ||
| 164 | +```mermaid | ||
| 165 | +sequenceDiagram | ||
| 166 | + autonumber | ||
| 167 | + participant APP as AI 框架 / 用户 | ||
| 168 | + participant OPS as HCCL 编排层<br/>(op_common.cc) | ||
| 169 | + participant EXE as HCCL 执行器/模板 | ||
| 170 | + participant DL as dlsym 弱符号桥 | ||
| 171 | + participant HC as HCOMM CCU<br/>(ccu_launch.cc) | ||
| 172 | + participant HW as 南向 Runtime<br/>(rtCCULaunch) | ||
| 173 | + | ||
| 174 | + APP->>OPS: HcclAllReduce(...)(同 shape 第二次起) | ||
| 175 | + OPS->>OPS: HcclGetOpExpansionMode → engine=CCU | ||
| 176 | + | ||
| 177 | + rect rgb(225,240,255) | ||
| 178 | + Note over OPS: ShouldGoCcuFastLaunch(op_common.cc:386) | ||
| 179 | + OPS->>OPS: 校验 opMode!=OFFLOAD 且 engine==CCU | ||
| 180 | + OPS->>OPS: SetOpParamFastLaunchTag(dataType/reduceOp/count/root 拼 tag) | ||
| 181 | + OPS->>OPS: HcclEngineCtxGet(comm, fastLaunchTag, COMM_ENGINE_CCU) → 命中 ✓ | ||
| 182 | + end | ||
| 183 | + | ||
| 184 | + OPS->>OPS: HcclExecOpCcuFastLaunch(op_common.cc:559) | ||
| 185 | + OPS->>OPS: CollAlgExecRegistryV2::GetAlgExec(opType, ctx->algName) | ||
| 186 | + OPS->>OPS: HcclGetHcclBuffer → param.hcclBuff(scratch) | ||
| 187 | + OPS->>DL: HcclThreadAcquireWithStream(comm, CCU, stream, ctx->notifyNumOnMainThread) | ||
| 188 | + DL->>HC: 覆盖主流(取一个 CCU Thread,写回 ctx->threads[0]) | ||
| 189 | + OPS->>OPS: ConstructHcclDfxOpInfo + HcclDfxRegOpInfoByCommId | ||
| 190 | + opt 图捕获且多线程 | ||
| 191 | + OPS->>OPS: CaptureSlaveStreams | ||
| 192 | + end | ||
| 193 | + | ||
| 194 | + rect rgb(235,250,235) | ||
| 195 | + Note over OPS,HW: executor->FastLaunch → template->FastLaunch(无 Selector / 无 CalcRes / 无 Register) | ||
| 196 | + OPS->>EXE: executor->FastLaunch(param, ccuFastLaunchCtx) | ||
| 197 | + EXE->>EXE: 从 ctx 取 threads / submitInfos + 新 inputPtr/outputPtr | ||
| 198 | + EXE->>EXE: args[0]=inputPtr+args[7];args[1]=outputPtr+args[8](只改地址) | ||
| 199 | + EXE->>DL: HcommCcuKernelLaunch(threads[0], kernelHandle, args, argSize) | ||
| 200 | + DL->>HC: GeneTaskParams(校验 argsNum==LoadArg 集合)→ LaunchCcuTasks | ||
| 201 | + HC->>HW: rtCCULaunch(&taskInfo, stream) | ||
| 202 | + end | ||
| 203 | + OPS->>OPS: HcclProfilingReportOp | ||
| 204 | + OPS-->>APP: 返回 | ||
| 205 | +``` | ||
| 206 | + | ||
| 207 | +### 3.2 与流程一的关键差异 | ||
| 208 | + | ||
| 209 | +| 维度 | 首次下发 | 快速下发 | | ||
| 210 | +|---|---|---| | ||
| 211 | +| 判定 | 无 fastLaunchTag 命中 | `ShouldGoCcuFastLaunch` 命中 | | ||
| 212 | +| 算法选择 | `Selector` + 跨 rank 协商 | 无(直接用 `CcuFastLaunchCtx::algName`) | | ||
| 213 | +| 资源/注册 | `HcclGetAlgRes` 全量 + `HcommCcuKernelRegister*` | 无(复用 thread / kernelHandle / cachedArgs) | | ||
| 214 | +| 北向接口 | 线程 + 通道 + 资源族 + 生命周期 + 原语 | **仅 `HcclThreadAcquireWithStream` + `HcommCcuKernelLaunch`** | | ||
| 215 | +| 缓存写入 | `FastLaunchSaveCtx`(loopTimes==1 且非 OFFLOAD) | — | | ||
| 216 | +| 缓存结构 | — | `CcuFastLaunchCtx{algName, threadNum, notifyNumOnMainThread, ccuKernelNum[], ThreadHandle[], CcuKernelSubmitInfo{handle, cachedArgs[48]}}`(`alg_param.h:407`) | | ||
| 217 | + | ||
| 218 | +> `cachedArgs` 布局约定(以 one-shot 为例):`[0]=inputAddr, [1]=outputAddr, [2]=token, [3..6]=goSize[0..3], [7]=inBuffBaseOff, [8]=outBuffBaseOff`。快路径只改 `[0]/[1]`,其余(token/goSize/offset)从缓存复用,这正是「同 shape 直发」的前提。 | ||
| 219 | + | ||
| 220 | +--- | ||
| 221 | + | ||
| 222 | +## 4. 流程三:CCU 回退 AICPU | ||
| 223 | + | ||
| 224 | +回退有 **4 个触发点**,最终都收敛到 `FallbackOp`(逐级 `CCU_MS → CCU_SCHED → AICPU_TS`)。 | ||
| 225 | + | ||
| 226 | +### 4.1 触发点总览 | ||
| 227 | + | ||
| 228 | +| # | 触发位置 | 条件 | 处理 | | ||
| 229 | +|---|---|---|---| | ||
| 230 | +| T1 | `HcclGetAlgRes`(`op_common.cc:863`)返回 `HCCL_E_UNAVAIL` | 通道申请/kernel 注册/实例创建资源不足 | `HcclExecOp` 调 `FallbackOp` | | ||
| 231 | +| T2 | `Selector` 内 `CheckCcuParamAndFallback`(`ccu_fallback.cc:482`) | 跨 rank 交换 `opExecuteConfig`,取最低公共值 < 本地 | `ReSelector(lowestConfig)` 直接降级重选 | | ||
| 232 | +| T3 | `GetAlgResWithEngine` CCU 分支 `CheckCcuResNegotiation`(`ccu_fallback.cc:337`) | 本端资源 OK 但对端有 rank 不足(AllReduce MIN 协商失败) | `ReleaseCcuAcquiredChannels` → 返回 `HCCL_E_UNAVAIL` | | ||
| 233 | +| T4 | HCOMM `CreateCcuInsByFixedResNum`(`coll_comm_ccu_c_adpt.cc:21`) | 旧路径 CCU_MS 实例资源不足 | 内部降级 CCU_MS→CCU_SCHED 重试一次 | | ||
| 234 | + | ||
| 235 | +### 4.2 时序图(资源回退主链 T1 + 协商 T2/T3) | ||
| 236 | + | ||
| 237 | +```mermaid | ||
| 238 | +sequenceDiagram | ||
| 239 | + autonumber | ||
| 240 | + participant OPS as HCCL 编排层<br/>(op_common.cc) | ||
| 241 | + participant NEG as 跨 rank 协商<br/>(ccu_fallback.cc) | ||
| 242 | + participant DL as dlsym 弱符号桥 | ||
| 243 | + participant HC as HCOMM CCU | ||
| 244 | + participant AICPU as AICPU 执行路径<br/>(GetAlgResAICPU /<br/>HcclAicpuKernelEntranceLaunch) | ||
| 245 | + | ||
| 246 | + rect rgb(255,235,235) | ||
| 247 | + Note over OPS,HC: 触发:资源不足(DIE 未使能 / 容量不足 / 通道不足) | ||
| 248 | + OPS->>DL: HcclGetCcuKernel → HcommCcuInsCreate / HcommCcuKernelRegister | ||
| 249 | + DL->>HC: 容量/资源校验 | ||
| 250 | + HC-->>OPS: CCU_E_UNAVAIL | ||
| 251 | + Note over OPS: HcclAllocAlgResourceCcu 返回 HCCL_E_UNAVAIL | ||
| 252 | + end | ||
| 253 | + | ||
| 254 | + rect rgb(255,245,225) | ||
| 255 | + Note over OPS,NEG: T3 多卡资源协商(本地成功也要确认对端) | ||
| 256 | + OPS->>NEG: CheckCcuResNegotiationC(comm, param, localResAvailable) | ||
| 257 | + NEG->>NEG: 取 commName+"_negotiation" 子通信域(AICPU 模式) | ||
| 258 | + NEG->>AICPU: HcclAllReduce(MIN, localVal=成功/失败标记) on subComm | ||
| 259 | + AICPU-->>NEG: result | ||
| 260 | + NEG-->>OPS: result==FAIL → HCCL_E_UNAVAIL(任一对端不足) | ||
| 261 | + OPS->>OPS: ReleaseCcuAcquiredChannels(释放已申请的 CCU 通道) | ||
| 262 | + end | ||
| 263 | + | ||
| 264 | + rect rgb(225,240,255) | ||
| 265 | + Note over OPS,AICPU: T2 跨 rank 参数协商(Selector 内,CANN≥9.2.0) | ||
| 266 | + OPS->>NEG: CheckCcuParamAndFallbackC | ||
| 267 | + NEG->>NEG: 查 cacheTag=algName+config+"_ccuParamCache"(命中直接复用) | ||
| 268 | + NEG->>AICPU: HcclAllGather(CheckParamInfo) on subComm → 取 lowestConfig | ||
| 269 | + alt lowestConfig != 本地 config | ||
| 270 | + NEG->>OPS: ReSelector(comm, param, topoInfo, algName, lowestConfig) | ||
| 271 | + end | ||
| 272 | + end | ||
| 273 | + | ||
| 274 | + rect rgb(240,240,240) | ||
| 275 | + Note over OPS,AICPU: FallbackOp 逐级降级(op_common.cc:652) | ||
| 276 | + OPS->>OPS: nextConfig: CCU_MS→CCU_SCHED;CCU_SCHED→AICPU_TS | ||
| 277 | + OPS->>OPS: HcclEngineCtxCreate(fallbackTag, COMM_ENGINE_CCU, FallbackCtxData)<br/>缓存 algName + opExecuteConfig | ||
| 278 | + OPS->>OPS: ReSelector(param.opExecuteConfig=nextConfig → 重选 algName) | ||
| 279 | + alt nextConfig == AICPU_TS | ||
| 280 | + OPS->>AICPU: LoadAICPUKernel() | ||
| 281 | + end | ||
| 282 | + OPS->>OPS: SetCommEngine() → param.engine=AICPU_TS;SetOpParamAlgTag() | ||
| 283 | + OPS->>OPS: HcclExecOp 递归(此时走 AICPU 分支) | ||
| 284 | + OPS->>AICPU: GetAlgResAICPU(HcclGetThread/HcclGetChannel,AICPU 族) | ||
| 285 | + OPS->>AICPU: executor->Orchestrate → HcclAicpuKernelEntranceLaunch | ||
| 286 | + end | ||
| 287 | + | ||
| 288 | + Note over OPS: 下次同算法调用:HcclExecOp 入口查 fallbackTag 命中<br/>→ 直接应用缓存 config/algName → 递归执行(不再尝试 CCU) | ||
| 289 | +``` | ||
| 290 | + | ||
| 291 | +### 4.3 关键点 | ||
| 292 | + | ||
| 293 | +1. **降级是「配置级」的,不是「本算子实例内」的**:`FallbackOp` 先 `ReSelector` 用更低 `opExecuteConfig` **重新选算法**,再从头 `HcclExecOp`。CCU_MS 与 CCU_SCHED 是两套不同资源阈值/算法(MS 模式 LOOP/CCU_BUF/EVENT 阈值更大)。 | ||
| 294 | +2. **回退结果被缓存两处**: | ||
| 295 | + - `fallbackTag = algName + "_fallback"`,`FallbackCtxData{algName, opExecuteConfig}`(`FallbackOp` 写,`HcclExecOp` 入口读)→ 下次直接复用降级结论; | ||
| 296 | + - `cacheTag = algName + config + "_ccuParamCache"`(`CheckCcuParamAndFallback` 写/读)→ 跳过跨 rank 协商。 | ||
| 297 | +3. **协商用「子通信域」**:`CheckCcuParamAndFallback` / `CheckCcuResNegotiation` 都会懒建一个 `commName+"_negotiation"` 子通信域(`hcclOpExpansionMode=AICPU`),在其上跑 `HcclAllGather`/`HcclAllReduce`。因此回退过程中的「通信」本身**不再经过 CCU 北向接口**,避免回退逻辑与 CCU 资源耦合。 | ||
| 298 | +4. **回退后无 CCU 北向调用**:`param.engine` 变为 `AICPU_TS` 后,`HcclGetAlgRes`→`GetAlgResWithEngine` 走 `GetAlgResAICPU`,执行走 `HcclAicpuKernelEntranceLaunch`;CCU 三件套/原语/发射接口在该次调用中全部不再出现。 | ||
| 299 | +5. **单 die 未使能不是回退,而是跳过补齐**:`IsDieEnabledForPadding` 用 `HcommCcuQueryRemainResDesc` 探测,未使能(`CCU_E_UNAVAIL`)只跳过该 die 的 padding,避免冗余申请;只有真正容量不足才回退。 | ||
| 300 | + | ||
| 301 | +### 4.4 回退 AICPU 时逐项操作清单(按调用顺序) | ||
| 302 | + | ||
| 303 | +> 目标:回答「一次 CCU 回退 AICPU 到底做了哪些事」。按**触发 → 回滚 → 降级重选 → 递归执行 → 记忆**五段拆解,每项标注调用点与接口。 | ||
| 304 | + | ||
| 305 | +#### 阶段 0:触发判定(回退的「因」) | ||
| 306 | + | ||
| 307 | +| # | 触发点 | 代码位置 | 触发条件 | 与本端/对端关系 | 后续去向 | | ||
| 308 | +|---|---|---|---|---|---| | ||
| 309 | +| T1 | `HcclExecOp` 捕获 `HcclGetAlgRes` 返回 `HCCL_E_UNAVAIL` | `op_common.cc:863` | 通道申请 / kernel 注册 / 实例创建资源不足 | 本端 | `FallbackOp` | | ||
| 310 | +| T2 | `Selector` 内 `CheckCcuParamAndFallback` | `ccu_fallback.cc:482`(`op_common.cc:225`) | 跨 rank 交换 `opExecuteConfig`,取到比本地更低的值 | 跨 rank 取最低 | 直接 `ReSelector`(**不经 `FallbackOp`**) | | ||
| 311 | +| T3 | `GetAlgResWithEngine` CCU 分支 `CheckCcuResNegotiation` | `op_common.cc:1578` / `ccu_fallback.cc:337` | 本端资源 OK,但 `HcclAllReduce(MIN)` 协商发现**任一 rank** 不足 | 对端 | 释放本端通道 → 返回 UNAVAIL → 再由 T1 进 `FallbackOp` | | ||
| 312 | +| T4 | hcomm 旧路径 `CreateCcuInsByFixedResNum` | `coll_comm_ccu_c_adpt.cc:21` | 固定资源方式建 CCU_MS 实例时资源不足 | 本端 | 内部 `CCU_MS→CCU_SCHED` 重试一次(**仍在 CCU 内**) | | ||
| 313 | + | ||
| 314 | +> 注意 T2 与 T1/T3 的区别:**T2 是「选阶段降级」**(仅换 `opExecuteConfig` 与 `algName`,后面仍可能停留在 CCU),**T1/T3/T4 是「执行阶段回退」**。只有 `FallbackOp` 才可能一路降到 AICPU_TS。 | ||
| 315 | + | ||
| 316 | +#### 阶段 1:本端资源回滚(回退前先还账) | ||
| 317 | + | ||
| 318 | +| 操作 | 接口/代码 | 说明 | | ||
| 319 | +|---|---|---| | ||
| 320 | +| 释放本次为 CCU kernel 新建的通道 | `ReleaseCcuAcquiredChannels`(`op_common.cc:1531`)→ `HcclChannelDestroy(comm, acquiredChannels[], n)` | 只释放 `resRequest.acquiredChannels`(`CcuAcquireKernelChannels` 记录的、本次 `HcclChannelAcquire` 新建的通道;已存在的复用通道不释放),释放后 `clear()` | | ||
| 321 | +| 通道申请阶段即失败时的自动回滚 | `CcuAcquireKernelChannels` UNAVAIL 分支(`op_common.cc:2269-2273`) | 申请中失败当场 `ReleaseCcuAcquiredChannels`,不把脏状态带出去 | | ||
| 322 | +| 协商失败时的回滚 | `GetAlgResWithEngine`(`op_common.cc:1581`) | `CheckCcuResNegotiation` 返回 UNAVAIL 后释放通道再返回 UNAVAIL | | ||
| 323 | +| **不做的事** | — | 已创建的 `CcuInstance`、已注册的 `CcuKernel`/微码、主流 `Thread` 均**不主动销毁**(归 comm 持有,下次若再试 CCU 可复用;AICPU 路径不复用它们但也无需拆除) | | ||
| 324 | + | ||
| 325 | +#### 阶段 2:`FallbackOp` 主体(`op_common.cc:652`) | ||
| 326 | + | ||
| 327 | +| 步骤 | 操作 | 代码/接口 | 说明 | | ||
| 328 | +|---|---|---|---| | ||
| 329 | +| 1 | 计算 `nextConfig` | `FallbackOp:656-670` | `CCU_MS→CCU_SCHED`;`CCU_SCHED→AICPU_TS`;已在 AICPU_TS 或未知 → `HCCL_E_NOT_SUPPORT`(CANN<9.2.0 直接 `AICPU_TS`) | | ||
| 330 | +| 2 | 申请回退结果缓存 | `HcclEngineCtxCreate(comm, fallbackTag, COMM_ENGINE_CCU, sizeof(FallbackCtxData))`(`:674`) | `fallbackTag = algName+"_fallback"`(`SetOpParamFallbackTag`,`:812`);**注意 ctx 挂在 CCU 引擎下**,但内容是回退结论 | | ||
| 331 | +| 3 | 降级重选 | `ReSelector(comm, param, topoInfo, algName, nextConfig)`(`:676`) | 见阶段 3 | | ||
| 332 | +| 4 | 写回退后算法名 | `sprintf_s(ctxData->algName, algName)`(`:677`) | `FallbackCtxData{algName, opExecuteConfig}`(`op_common.h:36`) | | ||
| 333 | +| 5 | 写回退后配置 | `ctxData->opExecuteConfig = param.opExecuteConfig`(`:682`) | 供下次顶层调用命中 | | ||
| 334 | +| 6 | 用新配置继续执行 | `HcclExecOp(comm, param, topoInfo, algName, resPack)`(`:683`) | 递归,见阶段 4 | | ||
| 335 | + | ||
| 336 | +#### 阶段 3:`ReSelector` 重选(`op_common.cc:687`) | ||
| 337 | + | ||
| 338 | +| 步骤 | 操作 | 说明 | | ||
| 339 | +|---|---|---| | ||
| 340 | +| 1 | `param.opExecuteConfig = executeConfig` | 覆写为 `nextConfig` | | ||
| 341 | +| 2 | **不重算拓扑** | 复用已算好的 `topoInfo`(与首次 `Selector` 的差别) | | ||
| 342 | +| 3 | 重新选算法 | `SelectorEngine::Global()->Run(...)` 或 `ExecuteSelector::Run(...)`;候选引擎优先级由 `SelectorEngine::GetEnginePriority` 给出:`CCU_MS→{CCU_MS,CCU_SCHED,AICPU_TS,HOSTCPU}`、`CCU_SCHED→{CCU_SCHED,AICPU_TS,HOSTCPU}` | | ||
| 343 | +| 4 | 更新引擎 | `SetCommEngine(param)`(`op_common.cc:3288`):`AICPU_TS→COMM_ENGINE_AICPU_TS`、`CCU_MS/CCU_SCHED→COMM_ENGINE_CCU` | | ||
| 344 | +| 5 | 按新引擎补加载物 | 落到 `AICPU_TS` → `LoadAICPUKernel()`(`load_kernel.cc:40`,内部防重复加载);落到 `AIV` → `RegisterKernel()` | | ||
| 345 | +| 6 | 更新 algTag | `SetOpParamAlgTag(param, algName)` | | ||
| 346 | +| 7 | 返回 | `checkValidAlgName` 校验非空 | | ||
| 347 | + | ||
| 348 | +#### 阶段 4:递归 `HcclExecOp` 走 AICPU 路径 | ||
| 349 | + | ||
| 350 | +| 步骤 | 操作 | 代码/接口 | 说明 | | ||
| 351 | +|---|---|---|---| | ||
| 352 | +| 1 | 入口查回退缓存 | `HcclEngineCtxGet(comm, fallbackTag, param.engine, ...)`(`:813`) | 本次递归 algName 已变,通常不命中;下次顶层调用命中 | | ||
| 353 | +| 2 | 资源申请(AICPU 族) | `GetAlgResWithEngine` → `GetAlgResAICPU` → `HcclAllocAlgResourceAICPU`(`:1751`) | `HcclGetHcclBuffer`(scratch)、`HcclGetThread`→`HcclGetAicpuThread`(`HcclThreadAcquireWithConfig(COMM_ENGINE_AICPU)` + 展开流 Thread)、`HcclGetChannel` | | ||
| 354 | +| 3 | ctx 序列化下发 | `Serialize()` + `HcclMemcpyCtxHostToDevice`(`:1735`) | `HcclEngineCtxCreate(AICPU_TS)` + `HcclEngineCtxCopy` | | ||
| 355 | +| 4 | 执行 | `executor->Orchestrate` → `HcclAicpuKernelEntranceLaunch`(`:902`) | **此处不再出现任何 CCU 北向接口** | | ||
| 356 | +| 5 | 缓存检查(AICPU 侧) | `HcclAivCacheCheckAndReplay` / `aicpuCacheEnable` | 与回退无关,走各自缓存 | | ||
| 357 | + | ||
| 358 | +#### 阶段 5:记忆(避免下次再回退) | ||
| 359 | + | ||
| 360 | +| 缓存 | 键 | 写入点 | 命中效果 | | ||
| 361 | +|---|---|---|---| | ||
| 362 | +| 回退结论 | `fallbackTag = algName+"_fallback"`(COMM_ENGINE_CCU) | `FallbackOp:674` | 下次顶层 `HcclExecOp` 入口(`:813`)命中 → 直接 `param.opExecuteConfig=缓存 config` + `SetCommEngine`(→AICPU_TS)+ `SetOpParamAlgTag(缓存 algName)` → 递归执行(**不再尝试 CCU 的三件套/资源申请**) | | ||
| 363 | +| 跨 rank 参数协商结论 | `cacheTag = algName+"_"+config+"_ccuParamCache"`(COMM_ENGINE_CCU) | `ccu_fallback.cc:553` | 下次 `CheckCcuParamAndFallback` 命中 → config 相同则跳过协商;config 不同则直接应用缓存结论(`SetCommEngine`+`SetOpParamAlgTag`) | | ||
| 364 | + | ||
| 365 | +#### 附:回退过程中「协商通信」本身走什么 | ||
| 366 | + | ||
| 367 | +`CheckCcuParamAndFallback` / `CheckCcuResNegotiation` 都会懒建 `commName+"_negotiation"` **子通信域**(`hcclOpExpansionMode=AICPU`,`ccu_fallback.cc:199`),并准备: | ||
| 368 | + | ||
| 369 | +| 资源 | 操作 | 代码 | | ||
| 370 | +|---|---|---| | ||
| 371 | +| Stream | `aclrtCreateStream` | `ccu_fallback.cc:158` | | ||
| 372 | +| Host/Device Buffer | `aclrtMallocHost` / `aclrtMalloc`(send/recv 各一) | `ccu_fallback.cc:162-181` | | ||
| 373 | +| 子通信域 | `HcclCreateSubCommConfig`(rankIds 恒等映射) | `ccu_fallback.cc:213` | | ||
| 374 | +| 常驻 worker | `CommWorkerMgr::GetInstance().Submit(comm, task)` 串行执行协商算子 | `ccu_fallback.cc:273` | | ||
| 375 | +| 参数协商 | `HcclAllGather(CheckParamInfo)` → `CompareCcuParam` 取最低 config | `ccu_fallback.cc:408 / :433` | | ||
| 376 | +| 资源协商 | `HcclAllReduce(MIN, 0x5a5a5a5a/0x0)` → `CompareNegotiationResult` | `ccu_fallback.cc:297 / :326` | | ||
| 377 | +| 每次复用前清账 | `ClearNegotiationBuf`(memset host/device 收发 buffer) | `ccu_fallback.cc:136` | | ||
| 378 | +| 生命周期 | `NegotiationCleanupCb`:`DESTROY_PRE` 释放(`Remove` worker → `CleanupNegotiationRes` → `HcclEngineCtxDestroy`),`RESUME_POST` 级联 `HcclCommResume` | `ccu_fallback.cc:96` | | ||
| 379 | + | ||
| 380 | +> 因此回退链上的「通信」全部在 AICPU 子通信域内完成,**不经过 CCU 北向接口**,保证回退判定与 CCU 资源解耦。 | ||
| 381 | + | ||
| 382 | +#### 一句话总结 | ||
| 383 | + | ||
| 384 | +一次「CCU 回退 AICPU」= **释放本端脏通道** → **`FallbackOp` 建回退缓存 + `ReSelector` 降级重选(CCU_MS→CCU_SCHED→AICPU_TS)** → **递归 `HcclExecOp` 用 AICPU 引擎重新申请 thread/channel 并执行** → **把结论写进 `fallbackTag`/`cacheTag`**,使后续同算法调用**直接从 AICPU 起步**,不再重走 CCU。 | ||
| 385 | + | ||
| 386 | +--- | ||
| 387 | + | ||
| 388 | +## 5. 三流程北向接口调用对比 | ||
| 389 | + | ||
| 390 | +| 北向接口 | ① 首次下发 | ② 快速下发 | ③ 回退 AICPU | | ||
| 391 | +|---|:---:|:---:|:---:| | ||
| 392 | +| `HcclCommQueryAssignedCcuIns` | ✓ | — | ✓(失败即回退) | | ||
| 393 | +| `HcclCommAssignCcuIns` | ✓ | — | —(回退后不走) | | ||
| 394 | +| `HcommCcuInsResDescCreate/SetNum/QueryNum/Destroy` | ✓ | — | ✓(失败即回退) | | ||
| 395 | +| `HcommCcuQueryRemainResDesc` | ✓(die 探测) | — | ✓(失败即回退) | | ||
| 396 | +| `HcommCcuKernelQueryResReq` | (可选) | — | (可选) | | ||
| 397 | +| `HcommCcuInsCreate` | ✓ | — | ✓(失败即回退) | | ||
| 398 | +| `HcclThreadAcquireWithStream(CCU)` | ✓ | ✓ | — | | ||
| 399 | +| `HcclChannelAcquire/HcclChannelQuery` | ✓ | — | — | | ||
| 400 | +| `HcclRankGraphGetEndpointInfo` | ✓ | — | — | | ||
| 401 | +| `HcommCcuKernelRegisterStart/Register/RegisterEnd` | ✓ | — | — | | ||
| 402 | +| `Ccu*` DSL 原语(84~88) | ✓(回调录制) | — | — | | ||
| 403 | +| `HcommCcuGetMemToken` | ✓ | —(复用 cachedArgs 的 token) | — | | ||
| 404 | +| `HcommCcuKernelLaunch` | ✓ | ✓ | — | | ||
| 405 | +| AICPU 北向族(`HcclThreadAcquire*`/`HcclGetChannel`/…) | — | — | ✓ | | ||
| 406 | + | ||
| 407 | +--- | ||
| 408 | + | ||
| 409 | +## 6. 参考文件清单 | ||
| 410 | + | ||
| 411 | +**HCCL 仓** | ||
| 412 | +- `src/ops/all_reduce/all_reduce.cc`(算子入口 / 快路径分叉) | ||
| 413 | +- `src/ops/op_common/op_common.cc`(`Selector` / `HcclExecOp` / `HcclGetAlgRes` / `HcclAllocAlgResourceCcu` / `HcclGetChannelForCcu` / `HcclGetCcuKernel` / `ShouldGoCcuFastLaunch` / `HcclExecOpCcuFastLaunch` / `FallbackOp` / `ReSelector` / `SetCommEngine`) | ||
| 414 | +- `src/ops/op_common/ccu_fallback.{h,cc}`(`CheckCcuResNegotiation` / `CheckCcuParamAndFallback`) | ||
| 415 | +- `src/ops/op_common/inc/alg_param.h`(`CcuKernelSubmitInfo` / `CcuFastLaunchCtx`) | ||
| 416 | +- `src/ops/all_reduce/algorithm/executor/ins_v2_all_reduce_sole_executor.cc`(`Orchestrate` / `OrchestrateLoop` / `FastLaunchSaveCtx` / `FastLaunch`) | ||
| 417 | +- `src/ops/all_reduce/algorithm/template/ccu/ccu_temp_all_reduce_mesh_1D_one_shot.cc`(`CalcRes` / `KernelRun` / `FastLaunch`) | ||
| 418 | +- `src/ops/all_reduce/algorithm/template/ccu/kernel/ccu_kernel_all_reduce_mesh1d_one_shot.{h,cc}`(算法体,注册期录制) | ||
| 419 | +- `src/common/hcomm_dlsym/`(`ccu_launch_dl.*`、`ccu_res_dl.*`、`hccl_ccu_res_dl.*`、`ccu_primitives_impl_dl.*`) | ||
| 420 | + | ||
| 421 | +**HCOMM 仓** | ||
| 422 | +- `include/ccu/ccu_launch.h` / `ccu_primitives.hpp` / `ccu_res.h`(北向 CCU API) | ||
| 423 | +- `src/base_comm/primitives/api_c_adpt/ccu/ccu_launch.cc`(`HcommCcuKernelRegister*` / `HcommCcuKernelLaunch` / `HcommCcuGetMemToken`) | ||
| 424 | +- `src/base_comm/primitives/api_c_adpt/ccu/ccu_res_c_adpt.cc`(`HcommCcuInsCreate*`) | ||
| 425 | +- `src/base_comm/primitives/api_c_adpt/ccu/ccu_primitives_impl.cc`(`Ccu*` 原语 C 适配) | ||
| 426 | +- `src/coll_communicator_mgr/api_c_adpt/coll_comm_ccu_c_adpt.cc`(`HcclCommQuery/AssignCcuIns`) | ||
| 427 | +- `src/base_comm/resources/ccu/ccu_instance/`、`ccu_kernel/`、`ccu_representation/`(实例 / Kernel / rep→微码翻译) | ||
| 428 | + | ||
| 429 | +**相关既有文档(CheckerL2)** | ||
| 430 | +- `ccu_allreduce_call_flow.md`(AllReduce CCU 端到端流程) | ||
| 431 | +- `ccu_dataplane_architecture.md`(控制面/数据面 SO 拆分) | ||
| 432 | +- `docs/CCU北向劫持四方案对比与选型.md`(hccl→hcomm CCU 调用时序与打桩对象) | ||
| @@ -0,0 +1,432 @@ | |||
| 1 | +# CCU 模式北向接口调用时序(首次下发 / 快速下发 / 回退 AICPU) | ||
| 2 | + | ||
| 3 | +> 范围:以 HCCL 仓(`cann/hccl`)AllReduce 为样本算子,梳理 CCU 模式的三种主要流程下 **HCCL → HCOMM 的 CCU 北向接口**(dlsym C ABI)调用时序。 | ||
| 4 | +> | ||
| 5 | +> 术语: | ||
| 6 | +> - **北向接口** = HCCL 调 HCOMM 的 C ABI 边界(`hccl/src/common/hcomm_dlsym/` 中的弱符号 + `dlsym`,HCOMM 侧 `HCOMM_WEAK_SYMBOL` 导出)。南向 = HCOMM 之下的 Runtime/Driver 边界(`rtCCULaunch` / TLV / `hrtMemcpy`),本文只作终点标注。 | ||
| 7 | +> - **CCU 三段式**:注册期「就地执行 kernelFunc 录制 rep」→ 翻译期「rep 翻成微码并装载指令空间」→ 发射期「只换 taskArgs 下发」。 | ||
| 8 | +> | ||
| 9 | +> 代码基线:`hccl/` 与 `hcomm/` 与 `CheckerL2/` 同层目录。 | ||
| 10 | + | ||
| 11 | +--- | ||
| 12 | + | ||
| 13 | +## 0. 三条流程的判定入口(一张图) | ||
| 14 | + | ||
| 15 | +```mermaid | ||
| 16 | +flowchart TD | ||
| 17 | + A["HcclAllReduce<br/>(all_reduce.cc:AllReduceOutPlaceCommon)"] --> B["HcclGetOpExpansionMode<br/>param.engine = COMM_ENGINE_CCU"] | ||
| 18 | + B --> C{"ShouldGoCcuFastLaunch?<br/>(op_common.cc:386)"} | ||
| 19 | + C -->|"① engine==CCU 且非 OFFLOAD<br/>② engineCtx 命中 fastLaunchTag"| FAST["★ 流程二:快速下发<br/>HcclExecOpCcuFastLaunch<br/>(op_common.cc:559)"] | ||
| 20 | + C -->|"未命中"| SEL["Selector<br/>(op_common.cc:159)"] | ||
| 21 | + SEL --> SEL2["CheckCcuParamAndFallback<br/>(ccu_fallback.cc:482)<br/>跨 rank 协商 opExecuteConfig"] | ||
| 22 | + SEL2 --> EXEC["HcclExecOp<br/>(op_common.cc:787)<br/>★ 流程一:首次下发(慢路径)"] | ||
| 23 | + EXEC --> RES{"HcclGetAlgRes<br/>资源是否 UNAVAIL?"} | ||
| 24 | + RES -->|"可用"| REG["资源申请 + Kernel 注册 + Orchestrate<br/>→ HcommCcuKernelLaunch"] | ||
| 25 | + RES -->|"UNAVAIL"| FB["★ 流程三:回退<br/>FallbackOp (op_common.cc:652)<br/>CCU_MS→CCU_SCHED→AICPU_TS"] | ||
| 26 | + FB --> EXEC | ||
| 27 | + REG --> SAVE["FastLaunchSaveCtx<br/>写 engineCtx(供流程二命中)"] | ||
| 28 | +``` | ||
| 29 | + | ||
| 30 | +三条流程的本质区别只有「走到哪一段、跳过哪一段」: | ||
| 31 | + | ||
| 32 | +| 流程 | 入口 | 是否选算法 | 是否申请资源/注册 kernel | 运行期北向调用 | | ||
| 33 | +|---|---|---|---|---| | ||
| 34 | +| ① 首次下发 | `HcclExecOp` 慢路径 | 是(Selector) | 是(三件套 + 84 原语录制 + 翻译) | `HcommCcuKernelLaunch` | | ||
| 35 | +| ② 快速下发 | `ShouldGoCcuFastLaunch` 命中 | 否(复用 ctx.algName) | 否(复用 ctx 的 thread/kernelHandle/cachedArgs) | `HcommCcuKernelLaunch` | | ||
| 36 | +| ③ 回退 AICPU | 资源/协商失败 → `FallbackOp` | 是(ReSelector 降级重选) | **不再走 CCU**(改 AICPU 资源) | 无(转 AICPU 北向族) | | ||
| 37 | + | ||
| 38 | +--- | ||
| 39 | + | ||
| 40 | +## 1. CCU 北向接口全景(调用时序图的「参与者」) | ||
| 41 | + | ||
| 42 | +### 1.1 接口分类与符号/实现映射 | ||
| 43 | + | ||
| 44 | +| 类 | 北向符号(HCCL 侧声明文件) | HCOMM 侧实现 | 暴露时机 | | ||
| 45 | +|---|---|---|---| | ||
| 46 | +| **A. 通信域↔实例绑定** | `HcclCommQueryCcuIns` / `HcclCommQueryAssignedCcuIns` / `HcclCommAssignCcuIns`<br/>(`hccl_ccu_res_dl.h`) | `coll_comm_ccu_c_adpt.cc:67 / :109 / :148` | 资源申请期 | | ||
| 47 | +| **B. 实例/资源族** | `HcommCcuInsResDescCreate` / `Destroy` / `SetNum` / `QueryNum`、`HcommCcuInsCreate` / `CreateDefault` / `Destroy` / `QueryResDesc`、`HcommCcuQueryRemainResDesc`、`HcommCcuKernelQueryResReq`<br/>(`ccu_res_dl.h`) | `ccu_res_c_adpt.cc` | 首算子资源申请期 | | ||
| 48 | +| **B'. 实例/资源族(兼容旧包)** | `HcommCcuInsCreateLegacy`、`HcommCcuGetMemToken` | `ccu_res_c_adpt.cc:195`、`ccu_launch.cc:406` | 旧路径 / 每次下发 | | ||
| 49 | +| **C. Kernel 生命周期(弱定义 W)** | `HcommCcuKernelRegisterStart` / `HcommCcuKernelRegister` / `HcommCcuKernelRegisterEnd` / `HcommCcuKernelLaunch`<br/>(`ccu_launch_dl.h`) | `ccu_launch.cc:47 / :77 / :120 / :293` | 注册期 / 每次下发 | | ||
| 50 | +| **D. DSL 原语族(84~88 个)** | `CcuVariableAlloc` / `CcuLoadArg` / `CcuNotifyRecord` / `CcuNotifyWait` / `CcuWriteVariableWithNotify` / `CcuReadMemToMem` / `CcuLocalMemReduce` / `CcuLoopGroupCreate` / `CcuIf*` / `CcuWhile*` …<br/>(`ccu_primitives_impl_dl.h` ↔ `hcomm/include/ccu/ccu_primitives.hpp`) | `ccu_primitives_impl.cc` | **仅注册期**(kernelFunc 内) | | ||
| 51 | +| **E. 线程/通道(既有桩 + CCU 分支)** | `HcclThreadAcquireWithStream` / `HcclChannelAcquire` / `HcclChannelQuery` / `HcclRankGraphGetEndpointInfo` | HCOMM base_comm thread/channel | 资源申请期(每次慢路径)/ 快速下发期(仅 thread) | | ||
| 52 | +| **F. 辅助查询** | `HcommCcuGetTaskArgsNum`、`HcclGetCcuTaskInfo` | `ccu_launch.cc:138` | 可选 | | ||
| 53 | + | ||
| 54 | +### 1.2 关键不变量 | ||
| 55 | + | ||
| 56 | +1. **注册期录 rep、发射期只换 args**:`HcommCcuKernelRegister` 内**同步回调** `kernelFunc`,函数体里逐条 `Ccu*` 原语不搬数、只把动作录成 rep 存进 `CcuKernel::res_`;`HcommCcuKernelRegisterEnd` 的 `Translate` 才把 rep 翻成微码并 `LoadInstruction`。 | ||
| 57 | +2. **原语作用于「当前注册 kernel」**:所有 `Ccu*` 实现 = `CcuKernelMgr::GetInstance(devId).GetCurrentKernel()->XXX()`,依赖 TLS 注册事务上下文。 | ||
| 58 | +3. **`HcommCcuKernelLaunch` 的 threadHandle 是 RTS Thread**:HCOMM 侧 `reinterpret_cast<hccl::Thread*>` 后 `GetStream()->ptr()` 取挂载的 `aclrtStream`。 | ||
| 59 | + | ||
| 60 | +--- | ||
| 61 | + | ||
| 62 | +## 2. 流程一:首次算子下发(慢路径) | ||
| 63 | + | ||
| 64 | +### 2.1 时序图 | ||
| 65 | + | ||
| 66 | +```mermaid | ||
| 67 | +sequenceDiagram | ||
| 68 | + autonumber | ||
| 69 | + participant APP as AI 框架 / 用户 | ||
| 70 | + participant OPS as HCCL 编排层<br/>(op_common.cc) | ||
| 71 | + participant EXE as HCCL 执行器/模板<br/>(ins_v2_all_reduce_sole_executor.cc<br/>ccu_temp_all_reduce_mesh_1D_one_shot.cc) | ||
| 72 | + participant NA as HCCL 算法体<br/>(ccu_kernel_all_reduce_mesh1d_one_shot.cc) | ||
| 73 | + participant DL as dlsym 弱符号桥<br/>(hcomm_dlsym/*_dl.*) | ||
| 74 | + participant HC as HCOMM CCU<br/>(ccu_launch.cc / ccu_res_c_adpt.cc<br/>coll_comm_ccu_c_adpt.cc) | ||
| 75 | + participant HW as 南向 Runtime/Driver<br/>(rtCCULaunch / TLV / hrtMemcpy) | ||
| 76 | + | ||
| 77 | + APP->>OPS: HcclAllReduce(...) | ||
| 78 | + OPS->>OPS: HcclGetOpExpansionMode → param.engine=CCU | ||
| 79 | + Note over OPS: ShouldGoCcuFastLaunch 未命中(首跑无 ctx) | ||
| 80 | + OPS->>OPS: Selector:选算法 CcuMSAllReduceSoleMeshOneShot 等 | ||
| 81 | + OPS->>DL: CheckCcuParamAndFallbackC(跨 rank 协商 opExecuteConfig) | ||
| 82 | + DL->>HC: (子通信域 AllGather,AICPU 模式) / 命中缓存则跳过 | ||
| 83 | + | ||
| 84 | + rect rgb(225,240,255) | ||
| 85 | + Note over OPS,HW: P1 资源申请 HcclGetAlgRes → GetAlgResCcu → HcclAllocAlgResourceCcu | ||
| 86 | + OPS->>DL: HcclGetHcclBuffer(取 cclMem/scratch,通用) | ||
| 87 | + OPS->>DL: HcclThreadAcquireWithStream(comm, CCU, stream, notifyNum) | ||
| 88 | + DL->>HC: 申请 CCU 主流 Thread(Mission 载体) | ||
| 89 | + OPS->>DL: HcclChannelQuery / HcclChannelAcquire(comm, CCU, descs[], n) | ||
| 90 | + DL->>HC: 以 kernel 为粒度申请 channel | ||
| 91 | + OPS->>DL: HcclRankGraphGetEndpointInfo(ENDPOINT_ATTR_DIE_ID) → dieId | ||
| 92 | + end | ||
| 93 | + | ||
| 94 | + rect rgb(235,250,235) | ||
| 95 | + Note over OPS,HW: P2 Kernel 注册 HcclGetCcuKernelDynamic(三件套) | ||
| 96 | + OPS->>DL: HcommCcuInsResDescCreate / SetNum(按 dieId 聚合资源需求) | ||
| 97 | + OPS->>DL: HcommCcuQueryRemainResDesc(IsDieEnabledForPadding 探测 die 使能) | ||
| 98 | + OPS->>DL: HcclCommQueryAssignedCcuIns → HCCL_E_UNAVAIL(首调未绑定) | ||
| 99 | + OPS->>DL: HcommCcuInsResDescCreate / QueryNum / SetNum(finalReqDesc) | ||
| 100 | + OPS->>DL: HcommCcuInsCreate → newInsHandle | ||
| 101 | + DL->>HC: CcuInstanceMgr::Create → CcuInstance::Init(建资源池) | ||
| 102 | + OPS->>DL: HcclCommAssignCcuIns(comm, insHandle) | ||
| 103 | + loop 每个 resGroup | ||
| 104 | + OPS->>DL: HcommCcuKernelRegisterStart(insHandle) | ||
| 105 | + DL->>HC: CcuInstance::BeginRegister + Reset | ||
| 106 | + loop 每个 kernel | ||
| 107 | + OPS->>DL: HcommCcuKernelRegister(ins, dieId, funcName, kernelFunc, args, 1) | ||
| 108 | + DL->>HC: CcuKernelMgr::Register → 同步回调 kernelFunc | ||
| 109 | + HC->>NA: ccuKernelFunc(kernelArg)(就地执行一次) | ||
| 110 | + loop kernelFunc 内每条原语 | ||
| 111 | + NA->>DL: CcuVariableAlloc / CcuLoadArg / CcuNotifyRecord / CcuReadMemToMem / CcuLocalMemReduce / CcuLoopGroupCreate ... | ||
| 112 | + DL->>HC: CcuKernelMgr::GetCurrentKernel()->XXX() → Append(rep) | ||
| 113 | + end | ||
| 114 | + HC-->>OPS: kernelHandle | ||
| 115 | + end | ||
| 116 | + OPS->>DL: HcommCcuKernelRegisterEnd(insHandle) | ||
| 117 | + DL->>HC: EndRegister + CcuKernelMgr::Translate(rep→微码) | ||
| 118 | + HC->>HW: LoadInstruction → hrtMemcpy(指令空间) | ||
| 119 | + end | ||
| 120 | + end | ||
| 121 | + | ||
| 122 | + rect rgb(255,245,230) | ||
| 123 | + Note over OPS,HW: P3 编排发射 exec->Orchestrate → template->KernelRun | ||
| 124 | + OPS->>EXE: executor->Orchestrate(param, resCtxHost) | ||
| 125 | + EXE->>EXE: OrchestrateLoop(按 maxDataCountPerLoop 切 loop) | ||
| 126 | + EXE->>EXE: template->KernelRun(param, tempAlgParams, templateAlgRes) | ||
| 127 | + EXE->>DL: HcommCcuGetMemToken(va, size) → token | ||
| 128 | + EXE->>DL: HcommCcuKernelLaunch(thread, kernelHandle, taskArgs[7], 7) | ||
| 129 | + DL->>HC: GeneTaskParams + LaunchCcuTasks | ||
| 130 | + HC->>HW: rtCCULaunch(&taskInfo, stream)(每个切片一次) | ||
| 131 | + end | ||
| 132 | + | ||
| 133 | + rect rgb(250,235,250) | ||
| 134 | + Note over OPS: P4 首跑缓存(供流程二命中) | ||
| 135 | + EXE->>OPS: loopTimes==1 时 FastLaunchSaveCtx | ||
| 136 | + OPS->>OPS: HcclEngineCtxCreate(fastLaunchTag, COMM_ENGINE_CCU, size)<br/>存 algName / threadNum / notifyNum / kernelHandle / cachedArgs | ||
| 137 | + end | ||
| 138 | + OPS-->>APP: 返回 | ||
| 139 | +``` | ||
| 140 | + | ||
| 141 | +### 2.2 关键步骤与北向接口清单 | ||
| 142 | + | ||
| 143 | +| 阶段 | HCCL 调用点 | 北向接口(dlsym) | HCOMM 实现 | 产物 | | ||
| 144 | +|---|---|---|---|---| | ||
| 145 | +| 算法选择 | `Selector`→`CheckCcuParamAndFallback` | (子通信域协商,非 CCU 主链路) | `ccu_fallback.cc:482` | `algName` + 最终 `opExecuteConfig` | | ||
| 146 | +| 线程 | `HcclAllocAlgResourceCcu`→`HcclGetThread` | `HcclThreadAcquireWithStream(CCU)` | base_comm thread | `resCtxHost->threads[0]`(主流) | | ||
| 147 | +| 通道 | `HcclGetChannelForCcu`→`CcuAcquireKernelChannels` | `HcclChannelQuery`、`HcclChannelAcquire`、`HcclRankGraphGetEndpointInfo` | base_comm channel | `kernelArg->channels[i]` + `kernelInfo.dieId` | | ||
| 148 | +| 需求聚合 | `BuildAggregatedResReq` | `HcommCcuInsResDescCreate` / `SetNum` / `Destroy`,`HcommCcuQueryRemainResDesc` | `ccu_res_c_adpt.cc` | `reqDescs`(按 dieId) | | ||
| 149 | +| 查实例 | `HcclGetCcuKernelDynamic` | `HcclCommQueryAssignedCcuIns`(首调 UNAVAIL) | `coll_comm_ccu_c_adpt.cc:109` | 走新建路径 | | ||
| 150 | +| 建实例 | `CreateAndAssignNewCcuIns` | `HcommCcuInsResDescCreate/QueryNum/SetNum`、`HcommCcuInsCreate`、`HcclCommAssignCcuIns` | `ccu_res_c_adpt.cc:208`、`coll_comm_ccu_c_adpt.cc:148` | `insHandle` 绑定到 comm | | ||
| 151 | +| 注册 | `RegisterCcuKernels` | `HcommCcuKernelRegisterStart` / `HcommCcuKernelRegister` / `HcommCcuKernelRegisterEnd` | `ccu_launch.cc:47/:77/:120` | `kernelHandle` + 微码已装载 | | ||
| 152 | +| 录制 | (HCOMM 回调 kernelFunc) | `CcuVariableAlloc` / `CcuLoadArg` / `CcuNotify*` / `CcuReadMemToMem` / `CcuLocalMemReduce` / `CcuLoopGroupCreate` … | `ccu_primitives_impl.cc` | `CcuKernel::res_`(rep 序列) | | ||
| 153 | +| 发射 | `template->KernelRun` | `HcommCcuGetMemToken`、`HcommCcuKernelLaunch` | `ccu_launch.cc:406/:293` | `rtCCULaunch`(南向) | | ||
| 154 | +| 缓存 | `FastLaunchSaveCtx` | (非跨仓,`HcclEngineCtxCreate`) | — | `fastLaunchCtx` | | ||
| 155 | + | ||
| 156 | +> **慢路径里的 CCU 资源回退点**:`HcclGetChannelForCcu` 的 `HcclChannelAcquire` 返回 `HCCL_E_UNAVAIL`,或 `HcclGetCcuKernelDynamic` 的容量判定/`HcommCcuInsCreate`/`HcommCcuKernelRegister` 返回 `CCU_E_UNAVAIL`,都会让 `HcclGetAlgRes` 返回 `HCCL_E_UNAVAIL` → 触发流程三。 | ||
| 157 | + | ||
| 158 | +--- | ||
| 159 | + | ||
| 160 | +## 3. 流程二:快速下发(快路径) | ||
| 161 | + | ||
| 162 | +### 3.1 时序图 | ||
| 163 | + | ||
| 164 | +```mermaid | ||
| 165 | +sequenceDiagram | ||
| 166 | + autonumber | ||
| 167 | + participant APP as AI 框架 / 用户 | ||
| 168 | + participant OPS as HCCL 编排层<br/>(op_common.cc) | ||
| 169 | + participant EXE as HCCL 执行器/模板 | ||
| 170 | + participant DL as dlsym 弱符号桥 | ||
| 171 | + participant HC as HCOMM CCU<br/>(ccu_launch.cc) | ||
| 172 | + participant HW as 南向 Runtime<br/>(rtCCULaunch) | ||
| 173 | + | ||
| 174 | + APP->>OPS: HcclAllReduce(...)(同 shape 第二次起) | ||
| 175 | + OPS->>OPS: HcclGetOpExpansionMode → engine=CCU | ||
| 176 | + | ||
| 177 | + rect rgb(225,240,255) | ||
| 178 | + Note over OPS: ShouldGoCcuFastLaunch(op_common.cc:386) | ||
| 179 | + OPS->>OPS: 校验 opMode!=OFFLOAD 且 engine==CCU | ||
| 180 | + OPS->>OPS: SetOpParamFastLaunchTag(dataType/reduceOp/count/root 拼 tag) | ||
| 181 | + OPS->>OPS: HcclEngineCtxGet(comm, fastLaunchTag, COMM_ENGINE_CCU) → 命中 ✓ | ||
| 182 | + end | ||
| 183 | + | ||
| 184 | + OPS->>OPS: HcclExecOpCcuFastLaunch(op_common.cc:559) | ||
| 185 | + OPS->>OPS: CollAlgExecRegistryV2::GetAlgExec(opType, ctx->algName) | ||
| 186 | + OPS->>OPS: HcclGetHcclBuffer → param.hcclBuff(scratch) | ||
| 187 | + OPS->>DL: HcclThreadAcquireWithStream(comm, CCU, stream, ctx->notifyNumOnMainThread) | ||
| 188 | + DL->>HC: 覆盖主流(取一个 CCU Thread,写回 ctx->threads[0]) | ||
| 189 | + OPS->>OPS: ConstructHcclDfxOpInfo + HcclDfxRegOpInfoByCommId | ||
| 190 | + opt 图捕获且多线程 | ||
| 191 | + OPS->>OPS: CaptureSlaveStreams | ||
| 192 | + end | ||
| 193 | + | ||
| 194 | + rect rgb(235,250,235) | ||
| 195 | + Note over OPS,HW: executor->FastLaunch → template->FastLaunch(无 Selector / 无 CalcRes / 无 Register) | ||
| 196 | + OPS->>EXE: executor->FastLaunch(param, ccuFastLaunchCtx) | ||
| 197 | + EXE->>EXE: 从 ctx 取 threads / submitInfos + 新 inputPtr/outputPtr | ||
| 198 | + EXE->>EXE: args[0]=inputPtr+args[7];args[1]=outputPtr+args[8](只改地址) | ||
| 199 | + EXE->>DL: HcommCcuKernelLaunch(threads[0], kernelHandle, args, argSize) | ||
| 200 | + DL->>HC: GeneTaskParams(校验 argsNum==LoadArg 集合)→ LaunchCcuTasks | ||
| 201 | + HC->>HW: rtCCULaunch(&taskInfo, stream) | ||
| 202 | + end | ||
| 203 | + OPS->>OPS: HcclProfilingReportOp | ||
| 204 | + OPS-->>APP: 返回 | ||
| 205 | +``` | ||
| 206 | + | ||
| 207 | +### 3.2 与流程一的关键差异 | ||
| 208 | + | ||
| 209 | +| 维度 | 首次下发 | 快速下发 | | ||
| 210 | +|---|---|---| | ||
| 211 | +| 判定 | 无 fastLaunchTag 命中 | `ShouldGoCcuFastLaunch` 命中 | | ||
| 212 | +| 算法选择 | `Selector` + 跨 rank 协商 | 无(直接用 `CcuFastLaunchCtx::algName`) | | ||
| 213 | +| 资源/注册 | `HcclGetAlgRes` 全量 + `HcommCcuKernelRegister*` | 无(复用 thread / kernelHandle / cachedArgs) | | ||
| 214 | +| 北向接口 | 线程 + 通道 + 资源族 + 生命周期 + 原语 | **仅 `HcclThreadAcquireWithStream` + `HcommCcuKernelLaunch`** | | ||
| 215 | +| 缓存写入 | `FastLaunchSaveCtx`(loopTimes==1 且非 OFFLOAD) | — | | ||
| 216 | +| 缓存结构 | — | `CcuFastLaunchCtx{algName, threadNum, notifyNumOnMainThread, ccuKernelNum[], ThreadHandle[], CcuKernelSubmitInfo{handle, cachedArgs[48]}}`(`alg_param.h:407`) | | ||
| 217 | + | ||
| 218 | +> `cachedArgs` 布局约定(以 one-shot 为例):`[0]=inputAddr, [1]=outputAddr, [2]=token, [3..6]=goSize[0..3], [7]=inBuffBaseOff, [8]=outBuffBaseOff`。快路径只改 `[0]/[1]`,其余(token/goSize/offset)从缓存复用,这正是「同 shape 直发」的前提。 | ||
| 219 | + | ||
| 220 | +--- | ||
| 221 | + | ||
| 222 | +## 4. 流程三:CCU 回退 AICPU | ||
| 223 | + | ||
| 224 | +回退有 **4 个触发点**,最终都收敛到 `FallbackOp`(逐级 `CCU_MS → CCU_SCHED → AICPU_TS`)。 | ||
| 225 | + | ||
| 226 | +### 4.1 触发点总览 | ||
| 227 | + | ||
| 228 | +| # | 触发位置 | 条件 | 处理 | | ||
| 229 | +|---|---|---|---| | ||
| 230 | +| T1 | `HcclGetAlgRes`(`op_common.cc:863`)返回 `HCCL_E_UNAVAIL` | 通道申请/kernel 注册/实例创建资源不足 | `HcclExecOp` 调 `FallbackOp` | | ||
| 231 | +| T2 | `Selector` 内 `CheckCcuParamAndFallback`(`ccu_fallback.cc:482`) | 跨 rank 交换 `opExecuteConfig`,取最低公共值 < 本地 | `ReSelector(lowestConfig)` 直接降级重选 | | ||
| 232 | +| T3 | `GetAlgResWithEngine` CCU 分支 `CheckCcuResNegotiation`(`ccu_fallback.cc:337`) | 本端资源 OK 但对端有 rank 不足(AllReduce MIN 协商失败) | `ReleaseCcuAcquiredChannels` → 返回 `HCCL_E_UNAVAIL` | | ||
| 233 | +| T4 | HCOMM `CreateCcuInsByFixedResNum`(`coll_comm_ccu_c_adpt.cc:21`) | 旧路径 CCU_MS 实例资源不足 | 内部降级 CCU_MS→CCU_SCHED 重试一次 | | ||
| 234 | + | ||
| 235 | +### 4.2 时序图(资源回退主链 T1 + 协商 T2/T3) | ||
| 236 | + | ||
| 237 | +```mermaid | ||
| 238 | +sequenceDiagram | ||
| 239 | + autonumber | ||
| 240 | + participant OPS as HCCL 编排层<br/>(op_common.cc) | ||
| 241 | + participant NEG as 跨 rank 协商<br/>(ccu_fallback.cc) | ||
| 242 | + participant DL as dlsym 弱符号桥 | ||
| 243 | + participant HC as HCOMM CCU | ||
| 244 | + participant AICPU as AICPU 执行路径<br/>(GetAlgResAICPU /<br/>HcclAicpuKernelEntranceLaunch) | ||
| 245 | + | ||
| 246 | + rect rgb(255,235,235) | ||
| 247 | + Note over OPS,HC: 触发:资源不足(DIE 未使能 / 容量不足 / 通道不足) | ||
| 248 | + OPS->>DL: HcclGetCcuKernel → HcommCcuInsCreate / HcommCcuKernelRegister | ||
| 249 | + DL->>HC: 容量/资源校验 | ||
| 250 | + HC-->>OPS: CCU_E_UNAVAIL | ||
| 251 | + Note over OPS: HcclAllocAlgResourceCcu 返回 HCCL_E_UNAVAIL | ||
| 252 | + end | ||
| 253 | + | ||
| 254 | + rect rgb(255,245,225) | ||
| 255 | + Note over OPS,NEG: T3 多卡资源协商(本地成功也要确认对端) | ||
| 256 | + OPS->>NEG: CheckCcuResNegotiationC(comm, param, localResAvailable) | ||
| 257 | + NEG->>NEG: 取 commName+"_negotiation" 子通信域(AICPU 模式) | ||
| 258 | + NEG->>AICPU: HcclAllReduce(MIN, localVal=成功/失败标记) on subComm | ||
| 259 | + AICPU-->>NEG: result | ||
| 260 | + NEG-->>OPS: result==FAIL → HCCL_E_UNAVAIL(任一对端不足) | ||
| 261 | + OPS->>OPS: ReleaseCcuAcquiredChannels(释放已申请的 CCU 通道) | ||
| 262 | + end | ||
| 263 | + | ||
| 264 | + rect rgb(225,240,255) | ||
| 265 | + Note over OPS,AICPU: T2 跨 rank 参数协商(Selector 内,CANN≥9.2.0) | ||
| 266 | + OPS->>NEG: CheckCcuParamAndFallbackC | ||
| 267 | + NEG->>NEG: 查 cacheTag=algName+config+"_ccuParamCache"(命中直接复用) | ||
| 268 | + NEG->>AICPU: HcclAllGather(CheckParamInfo) on subComm → 取 lowestConfig | ||
| 269 | + alt lowestConfig != 本地 config | ||
| 270 | + NEG->>OPS: ReSelector(comm, param, topoInfo, algName, lowestConfig) | ||
| 271 | + end | ||
| 272 | + end | ||
| 273 | + | ||
| 274 | + rect rgb(240,240,240) | ||
| 275 | + Note over OPS,AICPU: FallbackOp 逐级降级(op_common.cc:652) | ||
| 276 | + OPS->>OPS: nextConfig: CCU_MS→CCU_SCHED;CCU_SCHED→AICPU_TS | ||
| 277 | + OPS->>OPS: HcclEngineCtxCreate(fallbackTag, COMM_ENGINE_CCU, FallbackCtxData)<br/>缓存 algName + opExecuteConfig | ||
| 278 | + OPS->>OPS: ReSelector(param.opExecuteConfig=nextConfig → 重选 algName) | ||
| 279 | + alt nextConfig == AICPU_TS | ||
| 280 | + OPS->>AICPU: LoadAICPUKernel() | ||
| 281 | + end | ||
| 282 | + OPS->>OPS: SetCommEngine() → param.engine=AICPU_TS;SetOpParamAlgTag() | ||
| 283 | + OPS->>OPS: HcclExecOp 递归(此时走 AICPU 分支) | ||
| 284 | + OPS->>AICPU: GetAlgResAICPU(HcclGetThread/HcclGetChannel,AICPU 族) | ||
| 285 | + OPS->>AICPU: executor->Orchestrate → HcclAicpuKernelEntranceLaunch | ||
| 286 | + end | ||
| 287 | + | ||
| 288 | + Note over OPS: 下次同算法调用:HcclExecOp 入口查 fallbackTag 命中<br/>→ 直接应用缓存 config/algName → 递归执行(不再尝试 CCU) | ||
| 289 | +``` | ||
| 290 | + | ||
| 291 | +### 4.3 关键点 | ||
| 292 | + | ||
| 293 | +1. **降级是「配置级」的,不是「本算子实例内」的**:`FallbackOp` 先 `ReSelector` 用更低 `opExecuteConfig` **重新选算法**,再从头 `HcclExecOp`。CCU_MS 与 CCU_SCHED 是两套不同资源阈值/算法(MS 模式 LOOP/CCU_BUF/EVENT 阈值更大)。 | ||
| 294 | +2. **回退结果被缓存两处**: | ||
| 295 | + - `fallbackTag = algName + "_fallback"`,`FallbackCtxData{algName, opExecuteConfig}`(`FallbackOp` 写,`HcclExecOp` 入口读)→ 下次直接复用降级结论; | ||
| 296 | + - `cacheTag = algName + config + "_ccuParamCache"`(`CheckCcuParamAndFallback` 写/读)→ 跳过跨 rank 协商。 | ||
| 297 | +3. **协商用「子通信域」**:`CheckCcuParamAndFallback` / `CheckCcuResNegotiation` 都会懒建一个 `commName+"_negotiation"` 子通信域(`hcclOpExpansionMode=AICPU`),在其上跑 `HcclAllGather`/`HcclAllReduce`。因此回退过程中的「通信」本身**不再经过 CCU 北向接口**,避免回退逻辑与 CCU 资源耦合。 | ||
| 298 | +4. **回退后无 CCU 北向调用**:`param.engine` 变为 `AICPU_TS` 后,`HcclGetAlgRes`→`GetAlgResWithEngine` 走 `GetAlgResAICPU`,执行走 `HcclAicpuKernelEntranceLaunch`;CCU 三件套/原语/发射接口在该次调用中全部不再出现。 | ||
| 299 | +5. **单 die 未使能不是回退,而是跳过补齐**:`IsDieEnabledForPadding` 用 `HcommCcuQueryRemainResDesc` 探测,未使能(`CCU_E_UNAVAIL`)只跳过该 die 的 padding,避免冗余申请;只有真正容量不足才回退。 | ||
| 300 | + | ||
| 301 | +### 4.4 回退 AICPU 时逐项操作清单(按调用顺序) | ||
| 302 | + | ||
| 303 | +> 目标:回答「一次 CCU 回退 AICPU 到底做了哪些事」。按**触发 → 回滚 → 降级重选 → 递归执行 → 记忆**五段拆解,每项标注调用点与接口。 | ||
| 304 | + | ||
| 305 | +#### 阶段 0:触发判定(回退的「因」) | ||
| 306 | + | ||
| 307 | +| # | 触发点 | 代码位置 | 触发条件 | 与本端/对端关系 | 后续去向 | | ||
| 308 | +|---|---|---|---|---|---| | ||
| 309 | +| T1 | `HcclExecOp` 捕获 `HcclGetAlgRes` 返回 `HCCL_E_UNAVAIL` | `op_common.cc:863` | 通道申请 / kernel 注册 / 实例创建资源不足 | 本端 | `FallbackOp` | | ||
| 310 | +| T2 | `Selector` 内 `CheckCcuParamAndFallback` | `ccu_fallback.cc:482`(`op_common.cc:225`) | 跨 rank 交换 `opExecuteConfig`,取到比本地更低的值 | 跨 rank 取最低 | 直接 `ReSelector`(**不经 `FallbackOp`**) | | ||
| 311 | +| T3 | `GetAlgResWithEngine` CCU 分支 `CheckCcuResNegotiation` | `op_common.cc:1578` / `ccu_fallback.cc:337` | 本端资源 OK,但 `HcclAllReduce(MIN)` 协商发现**任一 rank** 不足 | 对端 | 释放本端通道 → 返回 UNAVAIL → 再由 T1 进 `FallbackOp` | | ||
| 312 | +| T4 | hcomm 旧路径 `CreateCcuInsByFixedResNum` | `coll_comm_ccu_c_adpt.cc:21` | 固定资源方式建 CCU_MS 实例时资源不足 | 本端 | 内部 `CCU_MS→CCU_SCHED` 重试一次(**仍在 CCU 内**) | | ||
| 313 | + | ||
| 314 | +> 注意 T2 与 T1/T3 的区别:**T2 是「选阶段降级」**(仅换 `opExecuteConfig` 与 `algName`,后面仍可能停留在 CCU),**T1/T3/T4 是「执行阶段回退」**。只有 `FallbackOp` 才可能一路降到 AICPU_TS。 | ||
| 315 | + | ||
| 316 | +#### 阶段 1:本端资源回滚(回退前先还账) | ||
| 317 | + | ||
| 318 | +| 操作 | 接口/代码 | 说明 | | ||
| 319 | +|---|---|---| | ||
| 320 | +| 释放本次为 CCU kernel 新建的通道 | `ReleaseCcuAcquiredChannels`(`op_common.cc:1531`)→ `HcclChannelDestroy(comm, acquiredChannels[], n)` | 只释放 `resRequest.acquiredChannels`(`CcuAcquireKernelChannels` 记录的、本次 `HcclChannelAcquire` 新建的通道;已存在的复用通道不释放),释放后 `clear()` | | ||
| 321 | +| 通道申请阶段即失败时的自动回滚 | `CcuAcquireKernelChannels` UNAVAIL 分支(`op_common.cc:2269-2273`) | 申请中失败当场 `ReleaseCcuAcquiredChannels`,不把脏状态带出去 | | ||
| 322 | +| 协商失败时的回滚 | `GetAlgResWithEngine`(`op_common.cc:1581`) | `CheckCcuResNegotiation` 返回 UNAVAIL 后释放通道再返回 UNAVAIL | | ||
| 323 | +| **不做的事** | — | 已创建的 `CcuInstance`、已注册的 `CcuKernel`/微码、主流 `Thread` 均**不主动销毁**(归 comm 持有,下次若再试 CCU 可复用;AICPU 路径不复用它们但也无需拆除) | | ||
| 324 | + | ||
| 325 | +#### 阶段 2:`FallbackOp` 主体(`op_common.cc:652`) | ||
| 326 | + | ||
| 327 | +| 步骤 | 操作 | 代码/接口 | 说明 | | ||
| 328 | +|---|---|---|---| | ||
| 329 | +| 1 | 计算 `nextConfig` | `FallbackOp:656-670` | `CCU_MS→CCU_SCHED`;`CCU_SCHED→AICPU_TS`;已在 AICPU_TS 或未知 → `HCCL_E_NOT_SUPPORT`(CANN<9.2.0 直接 `AICPU_TS`) | | ||
| 330 | +| 2 | 申请回退结果缓存 | `HcclEngineCtxCreate(comm, fallbackTag, COMM_ENGINE_CCU, sizeof(FallbackCtxData))`(`:674`) | `fallbackTag = algName+"_fallback"`(`SetOpParamFallbackTag`,`:812`);**注意 ctx 挂在 CCU 引擎下**,但内容是回退结论 | | ||
| 331 | +| 3 | 降级重选 | `ReSelector(comm, param, topoInfo, algName, nextConfig)`(`:676`) | 见阶段 3 | | ||
| 332 | +| 4 | 写回退后算法名 | `sprintf_s(ctxData->algName, algName)`(`:677`) | `FallbackCtxData{algName, opExecuteConfig}`(`op_common.h:36`) | | ||
| 333 | +| 5 | 写回退后配置 | `ctxData->opExecuteConfig = param.opExecuteConfig`(`:682`) | 供下次顶层调用命中 | | ||
| 334 | +| 6 | 用新配置继续执行 | `HcclExecOp(comm, param, topoInfo, algName, resPack)`(`:683`) | 递归,见阶段 4 | | ||
| 335 | + | ||
| 336 | +#### 阶段 3:`ReSelector` 重选(`op_common.cc:687`) | ||
| 337 | + | ||
| 338 | +| 步骤 | 操作 | 说明 | | ||
| 339 | +|---|---|---| | ||
| 340 | +| 1 | `param.opExecuteConfig = executeConfig` | 覆写为 `nextConfig` | | ||
| 341 | +| 2 | **不重算拓扑** | 复用已算好的 `topoInfo`(与首次 `Selector` 的差别) | | ||
| 342 | +| 3 | 重新选算法 | `SelectorEngine::Global()->Run(...)` 或 `ExecuteSelector::Run(...)`;候选引擎优先级由 `SelectorEngine::GetEnginePriority` 给出:`CCU_MS→{CCU_MS,CCU_SCHED,AICPU_TS,HOSTCPU}`、`CCU_SCHED→{CCU_SCHED,AICPU_TS,HOSTCPU}` | | ||
| 343 | +| 4 | 更新引擎 | `SetCommEngine(param)`(`op_common.cc:3288`):`AICPU_TS→COMM_ENGINE_AICPU_TS`、`CCU_MS/CCU_SCHED→COMM_ENGINE_CCU` | | ||
| 344 | +| 5 | 按新引擎补加载物 | 落到 `AICPU_TS` → `LoadAICPUKernel()`(`load_kernel.cc:40`,内部防重复加载);落到 `AIV` → `RegisterKernel()` | | ||
| 345 | +| 6 | 更新 algTag | `SetOpParamAlgTag(param, algName)` | | ||
| 346 | +| 7 | 返回 | `checkValidAlgName` 校验非空 | | ||
| 347 | + | ||
| 348 | +#### 阶段 4:递归 `HcclExecOp` 走 AICPU 路径 | ||
| 349 | + | ||
| 350 | +| 步骤 | 操作 | 代码/接口 | 说明 | | ||
| 351 | +|---|---|---|---| | ||
| 352 | +| 1 | 入口查回退缓存 | `HcclEngineCtxGet(comm, fallbackTag, param.engine, ...)`(`:813`) | 本次递归 algName 已变,通常不命中;下次顶层调用命中 | | ||
| 353 | +| 2 | 资源申请(AICPU 族) | `GetAlgResWithEngine` → `GetAlgResAICPU` → `HcclAllocAlgResourceAICPU`(`:1751`) | `HcclGetHcclBuffer`(scratch)、`HcclGetThread`→`HcclGetAicpuThread`(`HcclThreadAcquireWithConfig(COMM_ENGINE_AICPU)` + 展开流 Thread)、`HcclGetChannel` | | ||
| 354 | +| 3 | ctx 序列化下发 | `Serialize()` + `HcclMemcpyCtxHostToDevice`(`:1735`) | `HcclEngineCtxCreate(AICPU_TS)` + `HcclEngineCtxCopy` | | ||
| 355 | +| 4 | 执行 | `executor->Orchestrate` → `HcclAicpuKernelEntranceLaunch`(`:902`) | **此处不再出现任何 CCU 北向接口** | | ||
| 356 | +| 5 | 缓存检查(AICPU 侧) | `HcclAivCacheCheckAndReplay` / `aicpuCacheEnable` | 与回退无关,走各自缓存 | | ||
| 357 | + | ||
| 358 | +#### 阶段 5:记忆(避免下次再回退) | ||
| 359 | + | ||
| 360 | +| 缓存 | 键 | 写入点 | 命中效果 | | ||
| 361 | +|---|---|---|---| | ||
| 362 | +| 回退结论 | `fallbackTag = algName+"_fallback"`(COMM_ENGINE_CCU) | `FallbackOp:674` | 下次顶层 `HcclExecOp` 入口(`:813`)命中 → 直接 `param.opExecuteConfig=缓存 config` + `SetCommEngine`(→AICPU_TS)+ `SetOpParamAlgTag(缓存 algName)` → 递归执行(**不再尝试 CCU 的三件套/资源申请**) | | ||
| 363 | +| 跨 rank 参数协商结论 | `cacheTag = algName+"_"+config+"_ccuParamCache"`(COMM_ENGINE_CCU) | `ccu_fallback.cc:553` | 下次 `CheckCcuParamAndFallback` 命中 → config 相同则跳过协商;config 不同则直接应用缓存结论(`SetCommEngine`+`SetOpParamAlgTag`) | | ||
| 364 | + | ||
| 365 | +#### 附:回退过程中「协商通信」本身走什么 | ||
| 366 | + | ||
| 367 | +`CheckCcuParamAndFallback` / `CheckCcuResNegotiation` 都会懒建 `commName+"_negotiation"` **子通信域**(`hcclOpExpansionMode=AICPU`,`ccu_fallback.cc:199`),并准备: | ||
| 368 | + | ||
| 369 | +| 资源 | 操作 | 代码 | | ||
| 370 | +|---|---|---| | ||
| 371 | +| Stream | `aclrtCreateStream` | `ccu_fallback.cc:158` | | ||
| 372 | +| Host/Device Buffer | `aclrtMallocHost` / `aclrtMalloc`(send/recv 各一) | `ccu_fallback.cc:162-181` | | ||
| 373 | +| 子通信域 | `HcclCreateSubCommConfig`(rankIds 恒等映射) | `ccu_fallback.cc:213` | | ||
| 374 | +| 常驻 worker | `CommWorkerMgr::GetInstance().Submit(comm, task)` 串行执行协商算子 | `ccu_fallback.cc:273` | | ||
| 375 | +| 参数协商 | `HcclAllGather(CheckParamInfo)` → `CompareCcuParam` 取最低 config | `ccu_fallback.cc:408 / :433` | | ||
| 376 | +| 资源协商 | `HcclAllReduce(MIN, 0x5a5a5a5a/0x0)` → `CompareNegotiationResult` | `ccu_fallback.cc:297 / :326` | | ||
| 377 | +| 每次复用前清账 | `ClearNegotiationBuf`(memset host/device 收发 buffer) | `ccu_fallback.cc:136` | | ||
| 378 | +| 生命周期 | `NegotiationCleanupCb`:`DESTROY_PRE` 释放(`Remove` worker → `CleanupNegotiationRes` → `HcclEngineCtxDestroy`),`RESUME_POST` 级联 `HcclCommResume` | `ccu_fallback.cc:96` | | ||
| 379 | + | ||
| 380 | +> 因此回退链上的「通信」全部在 AICPU 子通信域内完成,**不经过 CCU 北向接口**,保证回退判定与 CCU 资源解耦。 | ||
| 381 | + | ||
| 382 | +#### 一句话总结 | ||
| 383 | + | ||
| 384 | +一次「CCU 回退 AICPU」= **释放本端脏通道** → **`FallbackOp` 建回退缓存 + `ReSelector` 降级重选(CCU_MS→CCU_SCHED→AICPU_TS)** → **递归 `HcclExecOp` 用 AICPU 引擎重新申请 thread/channel 并执行** → **把结论写进 `fallbackTag`/`cacheTag`**,使后续同算法调用**直接从 AICPU 起步**,不再重走 CCU。 | ||
| 385 | + | ||
| 386 | +--- | ||
| 387 | + | ||
| 388 | +## 5. 三流程北向接口调用对比 | ||
| 389 | + | ||
| 390 | +| 北向接口 | ① 首次下发 | ② 快速下发 | ③ 回退 AICPU | | ||
| 391 | +|---|:---:|:---:|:---:| | ||
| 392 | +| `HcclCommQueryAssignedCcuIns` | ✓ | — | ✓(失败即回退) | | ||
| 393 | +| `HcclCommAssignCcuIns` | ✓ | — | —(回退后不走) | | ||
| 394 | +| `HcommCcuInsResDescCreate/SetNum/QueryNum/Destroy` | ✓ | — | ✓(失败即回退) | | ||
| 395 | +| `HcommCcuQueryRemainResDesc` | ✓(die 探测) | — | ✓(失败即回退) | | ||
| 396 | +| `HcommCcuKernelQueryResReq` | (可选) | — | (可选) | | ||
| 397 | +| `HcommCcuInsCreate` | ✓ | — | ✓(失败即回退) | | ||
| 398 | +| `HcclThreadAcquireWithStream(CCU)` | ✓ | ✓ | — | | ||
| 399 | +| `HcclChannelAcquire/HcclChannelQuery` | ✓ | — | — | | ||
| 400 | +| `HcclRankGraphGetEndpointInfo` | ✓ | — | — | | ||
| 401 | +| `HcommCcuKernelRegisterStart/Register/RegisterEnd` | ✓ | — | — | | ||
| 402 | +| `Ccu*` DSL 原语(84~88) | ✓(回调录制) | — | — | | ||
| 403 | +| `HcommCcuGetMemToken` | ✓ | —(复用 cachedArgs 的 token) | — | | ||
| 404 | +| `HcommCcuKernelLaunch` | ✓ | ✓ | — | | ||
| 405 | +| AICPU 北向族(`HcclThreadAcquire*`/`HcclGetChannel`/…) | — | — | ✓ | | ||
| 406 | + | ||
| 407 | +--- | ||
| 408 | + | ||
| 409 | +## 6. 参考文件清单 | ||
| 410 | + | ||
| 411 | +**HCCL 仓** | ||
| 412 | +- `src/ops/all_reduce/all_reduce.cc`(算子入口 / 快路径分叉) | ||
| 413 | +- `src/ops/op_common/op_common.cc`(`Selector` / `HcclExecOp` / `HcclGetAlgRes` / `HcclAllocAlgResourceCcu` / `HcclGetChannelForCcu` / `HcclGetCcuKernel` / `ShouldGoCcuFastLaunch` / `HcclExecOpCcuFastLaunch` / `FallbackOp` / `ReSelector` / `SetCommEngine`) | ||
| 414 | +- `src/ops/op_common/ccu_fallback.{h,cc}`(`CheckCcuResNegotiation` / `CheckCcuParamAndFallback`) | ||
| 415 | +- `src/ops/op_common/inc/alg_param.h`(`CcuKernelSubmitInfo` / `CcuFastLaunchCtx`) | ||
| 416 | +- `src/ops/all_reduce/algorithm/executor/ins_v2_all_reduce_sole_executor.cc`(`Orchestrate` / `OrchestrateLoop` / `FastLaunchSaveCtx` / `FastLaunch`) | ||
| 417 | +- `src/ops/all_reduce/algorithm/template/ccu/ccu_temp_all_reduce_mesh_1D_one_shot.cc`(`CalcRes` / `KernelRun` / `FastLaunch`) | ||
| 418 | +- `src/ops/all_reduce/algorithm/template/ccu/kernel/ccu_kernel_all_reduce_mesh1d_one_shot.{h,cc}`(算法体,注册期录制) | ||
| 419 | +- `src/common/hcomm_dlsym/`(`ccu_launch_dl.*`、`ccu_res_dl.*`、`hccl_ccu_res_dl.*`、`ccu_primitives_impl_dl.*`) | ||
| 420 | + | ||
| 421 | +**HCOMM 仓** | ||
| 422 | +- `include/ccu/ccu_launch.h` / `ccu_primitives.hpp` / `ccu_res.h`(北向 CCU API) | ||
| 423 | +- `src/base_comm/primitives/api_c_adpt/ccu/ccu_launch.cc`(`HcommCcuKernelRegister*` / `HcommCcuKernelLaunch` / `HcommCcuGetMemToken`) | ||
| 424 | +- `src/base_comm/primitives/api_c_adpt/ccu/ccu_res_c_adpt.cc`(`HcommCcuInsCreate*`) | ||
| 425 | +- `src/base_comm/primitives/api_c_adpt/ccu/ccu_primitives_impl.cc`(`Ccu*` 原语 C 适配) | ||
| 426 | +- `src/coll_communicator_mgr/api_c_adpt/coll_comm_ccu_c_adpt.cc`(`HcclCommQuery/AssignCcuIns`) | ||
| 427 | +- `src/base_comm/resources/ccu/ccu_instance/`、`ccu_kernel/`、`ccu_representation/`(实例 / Kernel / rep→微码翻译) | ||
| 428 | + | ||
| 429 | +**相关既有文档(CheckerL2)** | ||
| 430 | +- `ccu_allreduce_call_flow.md`(AllReduce CCU 端到端流程) | ||
| 431 | +- `ccu_dataplane_architecture.md`(控制面/数据面 SO 拆分) | ||
| 432 | +- `docs/CCU北向劫持四方案对比与选型.md`(hccl→hcomm CCU 调用时序与打桩对象) | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | +version https://git-lfs.github.com/spec/v1 | ||
| 2 | +oid sha256:72187772bdebc6709fd1724431ed82eaa23b9ac4918fd5f419d3c5589820786a | ||
| 3 | +size 281402 | ||
| @@ -0,0 +1,179 @@ | |||
| 1 | +#!/usr/bin/env python3 | ||
| 2 | +# -*- coding: UTF-8 -*- | ||
| 3 | +# ----------------------------------------------------------------------------------------------------------- | ||
| 4 | +# Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 5 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 6 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 7 | +# Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 8 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 9 | +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 10 | +# See LICENSE in the root of the software repository for the full text of the License. | ||
| 11 | +# ----------------------------------------------------------------------------------------------------------- | ||
| 12 | + | ||
| 13 | +""" | ||
| 14 | +Level1 CCU 函数度量扫描(超长/超大/过深)。 | ||
| 15 | + | ||
| 16 | +口径(去注释/字符串 -> 花括号匹配取函数体): | ||
| 17 | + sloc = 函数体内非空、非注释代码行数; | ||
| 18 | + cc = 1 + if + for + while + case + catch + && + || + ?(含 case); | ||
| 19 | + depth = 函数体内相对函数起始的最大花括号嵌套深度; | ||
| 20 | + phys = 物理行数。 | ||
| 21 | + | ||
| 22 | +用法: | ||
| 23 | + python3 docs/ccu_func_metrics.py [目标目录或文件...] | ||
| 24 | +默认扫描 src/proxy/level1/ccu(相对本脚本所在仓库根)。 | ||
| 25 | +仅打印“违反指标(SLOC>50 或 CC>=20 或 depth>=5)”的函数;全部达标则无输出。 | ||
| 26 | +""" | ||
| 27 | +import os | ||
| 28 | +import re | ||
| 29 | +import sys | ||
| 30 | +import glob | ||
| 31 | + | ||
| 32 | +SLOC_LIMIT = 50 | ||
| 33 | +CC_LIMIT = 20 | ||
| 34 | +DEPTH_LIMIT = 5 | ||
| 35 | + | ||
| 36 | +REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) | ||
| 37 | +DEFAULT_DIR = os.path.join(REPO_ROOT, "src", "proxy", "level1", "ccu") | ||
| 38 | + | ||
| 39 | +CTRL = {"if", "for", "while", "switch", "catch", "do", "else", "return", | ||
| 40 | + "sizeof", "throw", "typedef", "using"} | ||
| 41 | + | ||
| 42 | + | ||
| 43 | +def strip_comments_strings(src): | ||
| 44 | + out = list(src) | ||
| 45 | + i, n = 0, len(src) | ||
| 46 | + while i < n: | ||
| 47 | + c = src[i] | ||
| 48 | + if c == '/' and i + 1 < n and src[i + 1] == '/': | ||
| 49 | + j = i | ||
| 50 | + while j < n and src[j] != '\n': | ||
| 51 | + out[j] = ' ' | ||
| 52 | + j += 1 | ||
| 53 | + i = j | ||
| 54 | + elif c == '/' and i + 1 < n and src[i + 1] == '*': | ||
| 55 | + j = i | ||
| 56 | + while j < n and not (src[j] == '*' and j + 1 < n and src[j + 1] == '/'): | ||
| 57 | + if src[j] != '\n': | ||
| 58 | + out[j] = ' ' | ||
| 59 | + j += 1 | ||
| 60 | + if j < n: | ||
| 61 | + out[j] = ' ' | ||
| 62 | + if j + 1 < n: | ||
| 63 | + out[j + 1] = ' ' | ||
| 64 | + i = j + 2 | ||
| 65 | + elif c == '"' or c == "'": | ||
| 66 | + q = c | ||
| 67 | + j = i + 1 | ||
| 68 | + while j < n and src[j] != q: | ||
| 69 | + if src[j] == '\\': | ||
| 70 | + j += 1 | ||
| 71 | + if j < n and src[j] != '\n': | ||
| 72 | + out[j] = ' ' | ||
| 73 | + j += 1 | ||
| 74 | + if j < n: | ||
| 75 | + out[j] = ' ' | ||
| 76 | + i = j + 1 | ||
| 77 | + else: | ||
| 78 | + i += 1 | ||
| 79 | + return "".join(out) | ||
| 80 | + | ||
| 81 | + | ||
| 82 | +def first_ident(s): | ||
| 83 | + m = re.match(r"\s*([A-Za-z_]\w*)", s) | ||
| 84 | + return m.group(1) if m else "" | ||
| 85 | + | ||
| 86 | + | ||
| 87 | +def sig_tail_ok(s): | ||
| 88 | + t = s.strip() | ||
| 89 | + if t == "" or t.startswith("#"): | ||
| 90 | + return False | ||
| 91 | + if first_ident(t) in CTRL: | ||
| 92 | + return False | ||
| 93 | + if t.endswith(";") or t.endswith("{"): | ||
| 94 | + return False | ||
| 95 | + return t.endswith(")") or t.endswith("const") | ||
| 96 | + | ||
| 97 | + | ||
| 98 | +def analyze(path): | ||
| 99 | + with open(path, "r", encoding="utf-8", errors="replace") as f: | ||
| 100 | + src = f.read() | ||
| 101 | + cl = strip_comments_strings(src) | ||
| 102 | + cl_lines = cl.split("\n") | ||
| 103 | + rows = [] | ||
| 104 | + i = 0 | ||
| 105 | + while i < len(cl_lines): | ||
| 106 | + if cl_lines[i].strip() == "{": | ||
| 107 | + j = i - 1 | ||
| 108 | + while j >= 0 and cl_lines[j].strip() == "": | ||
| 109 | + j -= 1 | ||
| 110 | + if j >= 0 and sig_tail_ok(cl_lines[j]): | ||
| 111 | + s = j | ||
| 112 | + k = j - 1 | ||
| 113 | + while k >= 0: | ||
| 114 | + t = cl_lines[k].strip() | ||
| 115 | + if (t == "" or t.endswith(";") or t.endswith("{") or t.endswith("}") | ||
| 116 | + or t.startswith("#") or t.endswith(":") | ||
| 117 | + or t.startswith(("public", "private", "protected"))): | ||
| 118 | + break | ||
| 119 | + s = k | ||
| 120 | + k -= 1 | ||
| 121 | + depth = 0 | ||
| 122 | + e = i | ||
| 123 | + while e < len(cl_lines): | ||
| 124 | + depth += cl_lines[e].count("{") - cl_lines[e].count("}") | ||
| 125 | + if depth <= 0: | ||
| 126 | + break | ||
| 127 | + e += 1 | ||
| 128 | + body = cl_lines[s:e + 1] | ||
| 129 | + sloc = sum(1 for ln in body if ln.strip() != "") | ||
| 130 | + d = 0 | ||
| 131 | + dep = 0 | ||
| 132 | + for ln in body: | ||
| 133 | + d += ln.count("{") - ln.count("}") | ||
| 134 | + dep = max(dep, d) | ||
| 135 | + txt = "\n".join(body) | ||
| 136 | + cc = 1 | ||
| 137 | + cc += len(re.findall(r"\bif\b", txt)) | ||
| 138 | + cc += len(re.findall(r"\bfor\b", txt)) | ||
| 139 | + cc += len(re.findall(r"\bwhile\b", txt)) | ||
| 140 | + cc += len(re.findall(r"\bcase\b", txt)) | ||
| 141 | + cc += len(re.findall(r"\bcatch\b", txt)) | ||
| 142 | + cc += txt.count("&&") + txt.count("||") + txt.count("?") | ||
| 143 | + nm = first_ident(cl_lines[s]) | ||
| 144 | + for ln in cl_lines[s:j + 1]: | ||
| 145 | + m = re.search(r"([A-Za-z_]\w*)\s*\(", ln) | ||
| 146 | + if m and m.group(1) not in CTRL: | ||
| 147 | + nm = m.group(1) | ||
| 148 | + break | ||
| 149 | + rows.append((os.path.basename(path), nm, s + 1, sloc, e - s + 1, cc, dep)) | ||
| 150 | + i = e + 1 | ||
| 151 | + continue | ||
| 152 | + i += 1 | ||
| 153 | + return rows | ||
| 154 | + | ||
| 155 | + | ||
| 156 | +def main(): | ||
| 157 | + targets = sys.argv[1:] or [DEFAULT_DIR] | ||
| 158 | + files = [] | ||
| 159 | + for t in targets: | ||
| 160 | + if os.path.isdir(t): | ||
| 161 | + files += sorted(glob.glob(os.path.join(t, "*.cc")) + glob.glob(os.path.join(t, "*.h"))) | ||
| 162 | + else: | ||
| 163 | + files.append(t) | ||
| 164 | + total = 0 | ||
| 165 | + bad = 0 | ||
| 166 | + for f in files: | ||
| 167 | + rows = analyze(f) | ||
| 168 | + total += len(rows) | ||
| 169 | + for r in rows: | ||
| 170 | + if r[3] > SLOC_LIMIT or r[5] >= CC_LIMIT or r[6] >= DEPTH_LIMIT: | ||
| 171 | + bad += 1 | ||
| 172 | + print(" %-22s %-40s L%-5d sloc=%-4d phys=%-4d cc=%-4d depth=%d" | ||
| 173 | + % (r[0], r[1], r[2], r[3], r[4], r[5], r[6])) | ||
| 174 | + print("总函数数:%d;违反(sloc>%d 或 cc>=%d 或 depth>=%d):%d" | ||
| 175 | + % (total, SLOC_LIMIT, CC_LIMIT, DEPTH_LIMIT, bad)) | ||
| 176 | + | ||
| 177 | + | ||
| 178 | +if __name__ == "__main__": | ||
| 179 | + main() | ||
| @@ -57,11 +57,11 @@ flowchart TD | |||
| 57 | 57 | ||
| 58 | | 任务类型 | 说明 | 核心字段 | | 58 | | 任务类型 | 说明 | 核心字段 | |
| 59 | |---|---|---| | 59 | |---|---|---| |
| 60 | -| `TRANS_MEM` | 内存数据搬运 | `srcRankId`, `srcOffset`<br>`dstRankId`, `dstOffset`<br>`len`, `type` | | 60 | +| `TRANS_MEM` | 内存数据搬运 | `srcDeviceId`, `srcOffset`<br>`dstDeviceId`, `dstOffset`<br>`len`, `type` | |
| 61 | | `BATCH_TRANS_MEM` | 批量内存数据搬运,一个节点内包含多组 `(src -> dst)` 搬运关系 | `srcs[]`<br>`dsts[]` | | 61 | | `BATCH_TRANS_MEM` | 批量内存数据搬运,一个节点内包含多组 `(src -> dst)` 搬运关系 | `srcs[]`<br>`dsts[]` | |
| 62 | -| `REDUCE` | 数据规约 | `srcRankId`, `srcOffset`<br>`dstRankId`, `dstOffset`<br>`type`, `dataCount`, `dataType`, `reduceOp` | | 62 | +| `REDUCE` | 数据规约 | `srcDeviceId`, `srcOffset`<br>`dstDeviceId`, `dstOffset`<br>`type`, `dataCount`, `dataType`, `reduceOp` | |
| 63 | | `BATCH_REDUCE` | 批量数据规约,一个节点内包含多组 `(src -> dst)` 规约关系 | `srcs[][]`<br>`dsts[]`<br>`dataType`, `reduceOp` | | 63 | | `BATCH_REDUCE` | 批量数据规约,一个节点内包含多组 `(src -> dst)` 规约关系 | `srcs[][]`<br>`dsts[]`<br>`dataType`, `reduceOp` | |
| 64 | -| `RECORD` / `WAIT` | 同步任务,分别表示发出同步信号和等待同步信号 | `srcRankId`(发出方)<br>`dstRankId`(等待方)<br>`notifyId` | | 64 | +| `RECORD` / `WAIT` | 同步任务,分别表示发出同步信号和等待同步信号 | `srcDeviceId`(发出方)<br>`dstDeviceId`(等待方)<br>`notifyId` | |
| 65 | 65 | ||
| 66 | 除上述真实执行任务外,任务图中还会补充 `START` / `END` 两类虚拟边界节点。它们不对应实际的数据搬运或计算动作,主要用于表达主图、子图和 Loop 结构的边界。 | 66 | 除上述真实执行任务外,任务图中还会补充 `START` / `END` 两类虚拟边界节点。它们不对应实际的数据搬运或计算动作,主要用于表达主图、子图和 Loop 结构的边界。 |
| 67 | 67 | ||
| @@ -57,11 +57,11 @@ flowchart TD | |||
| 57 | 57 | ||
| 58 | | 任务类型 | 说明 | 核心字段 | | 58 | | 任务类型 | 说明 | 核心字段 | |
| 59 | |---|---|---| | 59 | |---|---|---| |
| 60 | -| `TRANS_MEM` | 内存数据搬运 | `srcRankId`, `srcOffset`<br>`dstRankId`, `dstOffset`<br>`len`, `type` | | 60 | +| `TRANS_MEM` | 内存数据搬运 | `srcDeviceId`, `srcOffset`<br>`dstDeviceId`, `dstOffset`<br>`len`, `type` | |
| 61 | | `BATCH_TRANS_MEM` | 批量内存数据搬运,一个节点内包含多组 `(src -> dst)` 搬运关系 | `srcs[]`<br>`dsts[]` | | 61 | | `BATCH_TRANS_MEM` | 批量内存数据搬运,一个节点内包含多组 `(src -> dst)` 搬运关系 | `srcs[]`<br>`dsts[]` | |
| 62 | -| `REDUCE` | 数据规约 | `srcRankId`, `srcOffset`<br>`dstRankId`, `dstOffset`<br>`type`, `dataCount`, `dataType`, `reduceOp` | | 62 | +| `REDUCE` | 数据规约 | `srcDeviceId`, `srcOffset`<br>`dstDeviceId`, `dstOffset`<br>`type`, `dataCount`, `dataType`, `reduceOp` | |
| 63 | | `BATCH_REDUCE` | 批量数据规约,一个节点内包含多组 `(src -> dst)` 规约关系 | `srcs[][]`<br>`dsts[]`<br>`dataType`, `reduceOp` | | 63 | | `BATCH_REDUCE` | 批量数据规约,一个节点内包含多组 `(src -> dst)` 规约关系 | `srcs[][]`<br>`dsts[]`<br>`dataType`, `reduceOp` | |
| 64 | -| `RECORD` / `WAIT` | 同步任务,分别表示发出同步信号和等待同步信号 | `srcRankId`(发出方)<br>`dstRankId`(等待方)<br>`notifyId` | | 64 | +| `RECORD` / `WAIT` | 同步任务,分别表示发出同步信号和等待同步信号 | `srcDeviceId`(发出方)<br>`dstDeviceId`(等待方)<br>`notifyId` | |
| 65 | 65 | ||
| 66 | 除上述真实执行任务外,任务图中还会补充 `START` / `END` 两类虚拟边界节点。它们不对应实际的数据搬运或计算动作,主要用于表达主图、子图和 Loop 结构的边界。 | 66 | 除上述真实执行任务外,任务图中还会补充 `START` / `END` 两类虚拟边界节点。它们不对应实际的数据搬运或计算动作,主要用于表达主图、子图和 Loop 结构的边界。 |
| 67 | 67 | ||
| @@ -39,7 +39,7 @@ def parse_faq_markdown(md_content: str) -> List[Dict]: | |||
| 39 | current_submodule = '' | 39 | current_submodule = '' |
| 40 | current_error_code_group = '' | 40 | current_error_code_group = '' |
| 41 | 41 | ||
| 42 | - faq_blocks = re.split(r'\n#### FAQ-', md_content) | 42 | + faq_blocks = re.split(r'(?m)^#### FAQ-', md_content) |
| 43 | 43 | ||
| 44 | for i, block in enumerate(faq_blocks[1:]): | 44 | for i, block in enumerate(faq_blocks[1:]): |
| 45 | faq_id_match = re.match(r'([A-Z]+\d+)', block) | 45 | faq_id_match = re.match(r'([A-Z]+\d+)', block) |
| @@ -48,7 +48,7 @@ def parse_faq_markdown(md_content: str) -> List[Dict]: | |||
| 48 | 48 | ||
| 49 | faq_id = faq_id_match.group(1) | 49 | faq_id = faq_id_match.group(1) |
| 50 | 50 | ||
| 51 | - original_block = '\n#### FAQ-' + block | 51 | + original_block = '#### FAQ-' + block |
| 52 | current_module, current_submodule, current_error_code_group = find_context(md_content, original_block) | 52 | current_module, current_submodule, current_error_code_group = find_context(md_content, original_block) |
| 53 | 53 | ||
| 54 | faq_item = parse_faq_block(faq_id, block) | 54 | faq_item = parse_faq_block(faq_id, block) |
| @@ -215,19 +215,34 @@ def extract_diagram(block: str) -> Dict: | |||
| 215 | return {'content': '', 'type': ''} | 215 | return {'content': '', 'type': ''} |
| 216 | 216 | ||
| 217 | 217 | ||
| 218 | +def safe_json_dumps(obj, **kwargs): | ||
| 219 | + """JSON 序列化并转义 HTML/script 危险字符,防止模板注入和 script 提前结束""" | ||
| 220 | + result = json.dumps(obj, **kwargs) | ||
| 221 | + # 转义可能导致 HTML 解析器提前结束 script 的字符 | ||
| 222 | + result = result.replace('<', '\\u003c') | ||
| 223 | + result = result.replace('>', '\\u003e') | ||
| 224 | + result = result.replace('&', '\\u0026') | ||
| 225 | + # 转义 JavaScript 的行/段落分隔符(在 JSON 字符串中合法,但在 JS 中不合法) | ||
| 226 | + result = result.replace('\u2028', '\\u2028') | ||
| 227 | + result = result.replace('\u2029', '\\u2029') | ||
| 228 | + return result | ||
| 229 | + | ||
| 230 | + | ||
| 218 | def generate_html(faq_data: List[Dict], modules: List[str], submodules: Dict[str, List[str]], error_codes: List[str]) -> str: | 231 | def generate_html(faq_data: List[Dict], modules: List[str], submodules: Dict[str, List[str]], error_codes: List[str]) -> str: |
| 219 | """生成完整的HTML文件内容""" | 232 | """生成完整的HTML文件内容""" |
| 220 | html_template = get_html_template() | 233 | html_template = get_html_template() |
| 221 | 234 | ||
| 222 | - json_data = json.dumps(faq_data, ensure_ascii=False, indent=2) | 235 | + # 序列化并转义所有槽位 |
| 223 | - modules_json = json.dumps(modules, ensure_ascii=False) | 236 | + slots = { |
| 224 | - submodules_json = json.dumps(submodules, ensure_ascii=False) | 237 | + '{{FAQ_DATA}}': safe_json_dumps(faq_data, ensure_ascii=False, indent=2), |
| 225 | - codes_json = json.dumps(error_codes, ensure_ascii=False) | 238 | + '{{MODULES}}': safe_json_dumps(modules, ensure_ascii=False), |
| 239 | + '{{SUBMODULES}}': safe_json_dumps(submodules, ensure_ascii=False), | ||
| 240 | + '{{ERROR_CODES}}': safe_json_dumps(error_codes, ensure_ascii=False), | ||
| 241 | + } | ||
| 226 | 242 | ||
| 227 | - html_content = html_template.replace('{{FAQ_DATA}}', json_data) | 243 | + # 单次替换:构建正则匹配所有占位符,避免插入值被后续替换再处理 |
| 228 | - html_content = html_content.replace('{{MODULES}}', modules_json) | 244 | + pattern = re.compile('|'.join(re.escape(k) for k in slots.keys())) |
| 229 | - html_content = html_content.replace('{{SUBMODULES}}', submodules_json) | 245 | + html_content = pattern.sub(lambda m: slots[m.group(0)], html_template) |
| 230 | - html_content = html_content.replace('{{ERROR_CODES}}', codes_json) | ||
| 231 | 246 | ||
| 232 | return html_content | 247 | return html_content |
| 233 | 248 | ||
| @@ -55,7 +55,7 @@ def parse_faq_markdown(md_content: str, source_name: str = '') -> List[Dict]: | |||
| 55 | current_submodule = '' | 55 | current_submodule = '' |
| 56 | current_error_code_group = '' | 56 | current_error_code_group = '' |
| 57 | 57 | ||
| 58 | - faq_blocks = re.split(r'\n#### FAQ-', md_content) | 58 | + faq_blocks = re.split(r'(?m)^#### FAQ-', md_content) |
| 59 | 59 | ||
| 60 | for i, block in enumerate(faq_blocks[1:]): | 60 | for i, block in enumerate(faq_blocks[1:]): |
| 61 | faq_id_match = re.match(r'([A-Z]+\d+)', block) | 61 | faq_id_match = re.match(r'([A-Z]+\d+)', block) |
| @@ -64,7 +64,7 @@ def parse_faq_markdown(md_content: str, source_name: str = '') -> List[Dict]: | |||
| 64 | 64 | ||
| 65 | faq_id = faq_id_match.group(1) | 65 | faq_id = faq_id_match.group(1) |
| 66 | 66 | ||
| 67 | - original_block = '\n#### FAQ-' + block | 67 | + original_block = '#### FAQ-' + block |
| 68 | current_module, current_submodule, current_error_code_group = find_context(md_content, original_block) | 68 | current_module, current_submodule, current_error_code_group = find_context(md_content, original_block) |
| 69 | 69 | ||
| 70 | faq_item = parse_faq_block(faq_id, block) | 70 | faq_item = parse_faq_block(faq_id, block) |
| @@ -229,19 +229,34 @@ def extract_diagram(block: str) -> Dict: | |||
| 229 | return {'content': '', 'type': ''} | 229 | return {'content': '', 'type': ''} |
| 230 | 230 | ||
| 231 | 231 | ||
| 232 | +def safe_json_dumps(obj, **kwargs): | ||
| 233 | + """JSON 序列化并转义 HTML/script 危险字符,防止模板注入和 script 提前结束""" | ||
| 234 | + result = json.dumps(obj, **kwargs) | ||
| 235 | + # 转义可能导致 HTML 解析器提前结束 script 的字符 | ||
| 236 | + result = result.replace('<', '\\u003c') | ||
| 237 | + result = result.replace('>', '\\u003e') | ||
| 238 | + result = result.replace('&', '\\u0026') | ||
| 239 | + # 转义 JavaScript 的行/段落分隔符(在 JSON 字符串中合法,但在 JS 中不合法) | ||
| 240 | + result = result.replace('\u2028', '\\u2028') | ||
| 241 | + result = result.replace('\u2029', '\\u2029') | ||
| 242 | + return result | ||
| 243 | + | ||
| 244 | + | ||
| 232 | def generate_html(faq_data: List[Dict], modules: List[str], submodules: Dict[str, List[str]], error_codes: List[str]) -> str: | 245 | def generate_html(faq_data: List[Dict], modules: List[str], submodules: Dict[str, List[str]], error_codes: List[str]) -> str: |
| 233 | """生成完整的HTML文件内容""" | 246 | """生成完整的HTML文件内容""" |
| 234 | html_template = get_html_template() | 247 | html_template = get_html_template() |
| 235 | 248 | ||
| 236 | - json_data = json.dumps(faq_data, ensure_ascii=False, indent=2) | 249 | + # 序列化并转义所有槽位 |
| 237 | - modules_json = json.dumps(modules, ensure_ascii=False) | 250 | + slots = { |
| 238 | - submodules_json = json.dumps(submodules, ensure_ascii=False) | 251 | + '{{FAQ_DATA}}': safe_json_dumps(faq_data, ensure_ascii=False, indent=2), |
| 239 | - codes_json = json.dumps(error_codes, ensure_ascii=False) | 252 | + '{{MODULES}}': safe_json_dumps(modules, ensure_ascii=False), |
| 253 | + '{{SUBMODULES}}': safe_json_dumps(submodules, ensure_ascii=False), | ||
| 254 | + '{{ERROR_CODES}}': safe_json_dumps(error_codes, ensure_ascii=False), | ||
| 255 | + } | ||
| 240 | 256 | ||
| 241 | - html_content = html_template.replace('{{FAQ_DATA}}', json_data) | 257 | + # 单次替换:构建正则匹配所有占位符,避免插入值被后续替换再处理 |
| 242 | - html_content = html_content.replace('{{MODULES}}', modules_json) | 258 | + pattern = re.compile('|'.join(re.escape(k) for k in slots.keys())) |
| 243 | - html_content = html_content.replace('{{SUBMODULES}}', submodules_json) | 259 | + html_content = pattern.sub(lambda m: slots[m.group(0)], html_template) |
| 244 | - html_content = html_content.replace('{{ERROR_CODES}}', codes_json) | ||
| 245 | 260 | ||
| 246 | return html_content | 261 | return html_content |
| 247 | 262 | ||
| @@ -270,6 +285,17 @@ def parse_cli_args(argv: List[str]) -> argparse.Namespace: | |||
| 270 | return parser.parse_args(argv[1:]) | 285 | return parser.parse_args(argv[1:]) |
| 271 | 286 | ||
| 272 | 287 | ||
| 288 | +def extract_faq_ids(md_content: str) -> set: | ||
| 289 | + """从 Markdown 内容中提取所有 FAQ ID""" | ||
| 290 | + faq_ids = set() | ||
| 291 | + faq_blocks = re.split(r'(?m)^#### FAQ-', md_content) | ||
| 292 | + for block in faq_blocks[1:]: | ||
| 293 | + match = re.match(r'([A-Z]+\d+)', block) | ||
| 294 | + if match: | ||
| 295 | + faq_ids.add(f'FAQ-{match.group(1)}') | ||
| 296 | + return faq_ids | ||
| 297 | + | ||
| 298 | + | ||
| 273 | def expand_input_paths(input_args: List[str]) -> List[Path]: | 299 | def expand_input_paths(input_args: List[str]) -> List[Path]: |
| 274 | """展开输入路径,支持 Markdown 文件和目录""" | 300 | """展开输入路径,支持 Markdown 文件和目录""" |
| 275 | input_files: List[Path] = [] | 301 | input_files: List[Path] = [] |
| @@ -288,11 +314,26 @@ def expand_input_paths(input_args: List[str]) -> List[Path]: | |||
| 288 | for child in sorted(path.glob('*.md')): | 314 | for child in sorted(path.glob('*.md')): |
| 289 | if not child.is_file(): | 315 | if not child.is_file(): |
| 290 | continue | 316 | continue |
| 317 | + | ||
| 318 | + # 检测 _en.md 镜像文件:如果对应的 canonical 文件存在且 FAQ ID 集合一致,跳过翻译副本 | ||
| 319 | + if child.stem.endswith('_en'): | ||
| 320 | + canonical = child.with_name(child.stem[:-3] + '.md') | ||
| 321 | + if canonical.exists(): | ||
| 322 | + try: | ||
| 323 | + canonical_content = canonical.read_text(encoding='utf-8') | ||
| 324 | + mirror_content = child.read_text(encoding='utf-8') | ||
| 325 | + canonical_ids = extract_faq_ids(canonical_content) | ||
| 326 | + mirror_ids = extract_faq_ids(mirror_content) | ||
| 327 | + if canonical_ids and canonical_ids == mirror_ids: | ||
| 328 | + continue # 跳过翻译副本 | ||
| 329 | + except OSError: | ||
| 330 | + pass # 读取失败时保留文件,交给后续处理 | ||
| 331 | + | ||
| 291 | try: | 332 | try: |
| 292 | md_content = child.read_text(encoding='utf-8') | 333 | md_content = child.read_text(encoding='utf-8') |
| 293 | except OSError: | 334 | except OSError: |
| 294 | continue | 335 | continue |
| 295 | - if '\n#### FAQ-' not in md_content: | 336 | + if not re.search(r'(?m)^#### FAQ-', md_content): |
| 296 | continue | 337 | continue |
| 297 | resolved = child.resolve() | 338 | resolved = child.resolve() |
| 298 | if resolved in seen: | 339 | if resolved in seen: |
| @@ -268,50 +268,81 @@ ChannelData(见 3.3)。本节保留仅作历史格式参考,读取方不 | |||
| 268 | 268 | ||
| 269 | ### 5.2 HcclTaskMetaData 结构 | 269 | ### 5.2 HcclTaskMetaData 结构 |
| 270 | 270 | ||
| 271 | -**大小**:约 136 字节(含联合体) | 271 | +**大小**:188 字节(pack(1),含联合体;偏移 1~3 为 `HcclTaskProfInfo` 子结构,checker/runner 作为不透明整体透传) |
| 272 | 272 | ||
| 273 | -| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | | 273 | +| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | |
| 274 | -|:------:|:------:|-----------------|----------|------------------------| | 274 | +|:------:|:------:|:----------------|----------|--------------------------------------------| |
| 275 | -| 0 | 1 | int8 | taskType | 任务类型(见枚举) | | 275 | +| 0 | 1 | int8 | taskType | 任务类型(见枚举) | |
| 276 | -| 1 | 2 | uint16 | commId | 通信域 ID | | 276 | +| 1 | 3 | HcclTaskProfInfo| profInfo | profiling 对账信息子结构,见下表 | |
| 277 | -| 3 | 4 | uint32 | rankId | Rank ID | | 277 | +| 4 | 8 | uint64 | commId | 通信域 ID | |
| 278 | -| 7 | 8 | uint64 | streamId | Stream ID | | 278 | +| 12 | 4 | uint32 | rankId | 任务所属 Rank ID | |
| 279 | -| 15 | 4 | uint32 | jettyId | Jetty ID | | 279 | +| 16 | 8 | uint64 | deviceId | 任务所属 Device ID | |
| 280 | -| 19 | 变长 | union | taskData | 任务数据(根据类型解析)| | 280 | +| 24 | 8 | uint64 | streamId | Stream ID | |
| 281 | +| 32 | 4 | uint32 | jettyId | Jetty ID | | ||
| 282 | +| 36 | 16 | uint8[16] | rmEid | 对端 EID(WQE 原始字节序) | | ||
| 283 | +| 52 | 16 | uint8[16] | lcEid | 本端 EID(WQE 字节序,见下方说明) | | ||
| 284 | +| 68 | 120 | union | taskData | 任务数据(根据类型解析) | | ||
| 285 | + | ||
| 286 | +`HcclTaskProfInfo` 子结构(偏移 1~3,定义于 `include/sim_profiling_defs.h`,单源管理): | ||
| 287 | + | ||
| 288 | +| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | | ||
| 289 | +|:------:|:------:|:-------------------|---------------|-----------------------------| | ||
| 290 | +| 1 | 1 | uint8 | profTaskType | 对齐 hcomm TaskParamType | | ||
| 291 | +| 2 | 1 | uint8 | linkType | 对齐 hcomm DfxLinkType | | ||
| 292 | +| 3 | 1 | uint8 | transportType | 对齐 hcomm DfxTransportType | | ||
| 293 | + | ||
| 294 | +**EID 字段说明**: | ||
| 295 | + | ||
| 296 | +- `rmEid` 与 `lcEid` 统一采用 **ranktable.json 十六进制串字节序**(与 EndPoint.eid / | ||
| 297 | + RankEidMap 的入库序一致),可与 DB 表 / ranktable 的 EID 串直接比对,二者亦可直接互比。 | ||
| 298 | +- `rmEid` 来源:WQE 中的 `rmtEid` 为 `uint32[4]` 小端字存储(内存 16 字节与 ranktable | ||
| 299 | + 串整体相反),拷入任务时做整 16 字节翻转。 | ||
| 300 | +- `lcEid` 来源:由 `jettyId → RaJetty → RaContext → EndPoint.eid` 查询本端 EID 直拷, | ||
| 301 | + 天然为该序。 | ||
| 302 | +- `lcEid` 仅设备侧 SQE 解析(`device_sqe_parse_stub.cc`)生成的带 jettyId 的任务填充; | ||
| 303 | + 其余任务保持全 0。 | ||
| 304 | +- **rank 约定(estimate 采集)**:taskData 的 `srcDeviceId`/`dstDeviceId` 字段承载 | ||
| 305 | + 通信域 rank(原 `srcRankId`/`dstRankId` 字段已回退删除,值合并入 deviceId 字段); | ||
| 306 | + 为 `UINT32_MAX`(0xFFFFFFFF)时表示未解析到对应 rank(如非 ranktable/EID 模式), | ||
| 307 | + 0 为合法 rank 值。normal 模式(checker 链路)下 deviceId 字段仍为真实 Device ID, | ||
| 308 | + 两种语义按运行模式隔离(estimate 模式禁用 checker)。 | ||
| 281 | 309 | ||
| 282 | ### 5.3 taskData 联合体 | 310 | ### 5.3 taskData 联合体 |
| 283 | 311 | ||
| 312 | +联合体大小 120 字节(取最大成员 CcuTask)。 | ||
| 313 | + | ||
| 284 | #### 5.3.1 TransMemTask | 314 | #### 5.3.1 TransMemTask |
| 285 | 315 | ||
| 286 | **适用任务类型**:`MEM_CPY (3)`。 | 316 | **适用任务类型**:`MEM_CPY (3)`。 |
| 287 | 317 | ||
| 288 | **大小**:33 字节。 | 318 | **大小**:33 字节。 |
| 289 | 319 | ||
| 290 | -| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | | 320 | +| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | |
| 291 | -|:------:|:------:|--------|-----------|--------------| | 321 | +|:------:|:------:|--------|-------------|---------------------------------------| |
| 292 | -| 0 | 4 | uint32 | srcRankId | 源 Rank ID | | 322 | +| 0 | 4 | uint32 | srcDeviceId | 源端点(estimate: rank / normal: Device ID) | |
| 293 | -| 4 | 8 | uint64 | srcOffset | 源偏移地址 | | 323 | +| 4 | 8 | uint64 | srcOffset | 源偏移地址 | |
| 294 | -| 12 | 4 | uint32 | dstRankId | 目标 Rank ID | | 324 | +| 12 | 4 | uint32 | dstDeviceId | 目标端点(estimate: rank / normal: Device ID) | |
| 295 | -| 16 | 8 | uint64 | dstOffset | 目标偏移地址 | | 325 | +| 16 | 8 | uint64 | dstOffset | 目标偏移地址 | |
| 296 | -| 24 | 8 | uint64 | len | 数据长度 | | 326 | +| 24 | 8 | uint64 | len | 数据长度 | |
| 297 | -| 32 | 1 | uint8 | protocol | 协议类型 | | 327 | +| 32 | 1 | uint8 | protocol | 协议类型 | |
| 298 | 328 | ||
| 299 | #### 5.3.2 ReduceTask | 329 | #### 5.3.2 ReduceTask |
| 300 | 330 | ||
| 301 | **适用任务类型**:`REDUCE (2)`。 | 331 | **适用任务类型**:`REDUCE (2)`。 |
| 302 | 332 | ||
| 303 | -**大小**:35 字节。 | 333 | +**大小**:36 字节。 |
| 304 | 334 | ||
| 305 | -| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | | 335 | +| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | |
| 306 | -|:------:|:------:|--------|-----------|--------------| | 336 | +|:------:|:------:|--------|-------------|---------------------------------------| |
| 307 | -| 0 | 4 | uint32 | srcRankId | 源 Rank ID | | 337 | +| 0 | 4 | uint32 | srcDeviceId | 源端点(estimate: rank / normal: Device ID) | |
| 308 | -| 4 | 8 | uint64 | srcOffset | 源偏移地址 | | 338 | +| 4 | 8 | uint64 | srcOffset | 源偏移地址 | |
| 309 | -| 12 | 4 | uint32 | dstRankId | 目标 Rank ID | | 339 | +| 12 | 4 | uint32 | dstDeviceId | 目标端点(estimate: rank / normal: Device ID) | |
| 310 | -| 16 | 8 | uint64 | dstOffset | 目标偏移地址 | | 340 | +| 16 | 8 | uint64 | dstOffset | 目标偏移地址 | |
| 311 | -| 24 | 8 | uint64 | dataCount | 数据元素个数 | | 341 | +| 24 | 8 | uint64 | dataCount | 数据元素个数 | |
| 312 | -| 32 | 1 | uint8 | dataType | 数据类型 | | 342 | +| 32 | 1 | uint8 | dataType | 数据类型 | |
| 313 | -| 33 | 1 | uint8 | reduceOp | 归约操作类型 | | 343 | +| 33 | 1 | uint8 | reduceOp | 归约操作类型 | |
| 314 | -| 34 | 1 | uint8 | protocol | 协议类型 | | 344 | +| 34 | 1 | uint8 | protocol | 协议类型 | |
| 345 | +| 35 | 1 | uint8 | resv | 保留 | | ||
| 315 | 346 | ||
| 316 | #### 5.3.3 NotifyTask | 347 | #### 5.3.3 NotifyTask |
| 317 | 348 | ||
| @@ -319,13 +350,13 @@ ChannelData(见 3.3)。本节保留仅作历史格式参考,读取方不 | |||
| 319 | 350 | ||
| 320 | **大小**:18 字节。 | 351 | **大小**:18 字节。 |
| 321 | 352 | ||
| 322 | -| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | | 353 | +| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | |
| 323 | -|:------:|:------:|--------|-------------|------------| | 354 | +|:------:|:------:|--------|-------------|---------------------------------------------| |
| 324 | -| 0 | 4 | uint32 | srcRankId | 源 Rank ID | | 355 | +| 0 | 4 | uint32 | srcDeviceId | 记录方端点(estimate: rank / normal: Device ID) | |
| 325 | -| 4 | 8 | uint64 | notifyId | 通知 ID | | 356 | +| 4 | 8 | uint64 | notifyId | 通知 ID | |
| 326 | -| 12 | 4 | uint32 | dstRankId | 目标 Rank ID | | 357 | +| 12 | 4 | uint32 | dstDeviceId | 等待方端点(estimate: rank / normal: Device ID) | |
| 327 | -| 16 | 1 | uint8 | notifyCount | 通知计数 | | 358 | +| 16 | 1 | uint8 | notifyCount | 通知计数 | |
| 328 | -| 17 | 1 | uint8 | protocol | 协议类型 | | 359 | +| 17 | 1 | uint8 | protocol | 协议类型 | |
| 329 | 360 | ||
| 330 | --- | 361 | --- |
| 331 | 362 | ||
| @@ -461,60 +492,173 @@ struct MemLayoutData { | |||
| 461 | // 任务类型枚举 | 492 | // 任务类型枚举 |
| 462 | // ============================================================================ | 493 | // ============================================================================ |
| 463 | enum class HccLTaskMetaType : int8_t { | 494 | enum class HccLTaskMetaType : int8_t { |
| 464 | - NOTIFY_WAIT = 0, | 495 | + NOTIFY_WAIT = 0, |
| 465 | - NOTIFY_RECORD = 1, | 496 | + NOTIFY_RECORD = 1, |
| 466 | - REDUCE = 2, | 497 | + REDUCE = 2, |
| 467 | - MEM_CPY = 3, | 498 | + MEM_CPY = 3, |
| 468 | - CCU_GRAPH = 4, | 499 | + CCU_GRAPH = 4, |
| 469 | - AIV_GRAPH = 5, | 500 | + AIV_GRAPH = 5, |
| 470 | - EVENT_WAIT = 6, | 501 | + SYNC_STREAM = 6, |
| 471 | - EVENT_RECORD = 7 | 502 | + WRITE_WITH_NOTIFY = 7, |
| 503 | + INVALID = 8 | ||
| 472 | }; | 504 | }; |
| 473 | 505 | ||
| 474 | // ============================================================================ | 506 | // ============================================================================ |
| 475 | -// 任务数据联合体 | 507 | +// profiling 任务类型枚举值域与 hcomm TaskParamType 一一对齐 |
| 508 | +// ============================================================================ | ||
| 509 | +enum class ProfTaskParamType : uint8_t { | ||
| 510 | + TASK_SDMA = 0, // Memcpy | ||
| 511 | + TASK_RDMA = 1, // RDMASend | ||
| 512 | + TASK_REDUCE_INLINE = 2, // Reduce_Inline | ||
| 513 | + TASK_REDUCE_TBE = 3, // Reduce_TBE | ||
| 514 | + TASK_NOTIFY_RECORD = 4, // Notify_Record | ||
| 515 | + TASK_NOTIFY_WAIT = 5, // Notify_Wait | ||
| 516 | + TASK_SEND_NOTIFY = 6, // Send_Notify | ||
| 517 | + TASK_SEND_PAYLOAD = 7, // Send_Payload | ||
| 518 | + TASK_WRITE_WITH_NOTIFY = 8, // Write_With_Notify | ||
| 519 | + TASK_WRITE_REDUCE_WITH_NOTIFY = 9, // Reduce_With_Notify | ||
| 520 | + TASK_CCU = 10, // Ccu | ||
| 521 | + TASK_AICPU_KERNEL = 11, // AicpuKernel | ||
| 522 | + TASK_AICPU_REDUCE = 12, // Aicpu_Reduce | ||
| 523 | + TASK_AIV = 13, // AivKernel | ||
| 524 | + TASK_UB_INLINE_WRITE = 14, // Ub_Inline_Write | ||
| 525 | + TASK_UB_REDUCE_INLINE = 15, // Ub_Reduce_Inline | ||
| 526 | + TASK_UB = 16, // Ub_Write_Or_Read | ||
| 527 | + TASK_DPU_KERNEL = 17, // DpuKernel | ||
| 528 | + TASK_DPU_THREAD_FENCE = 18, // Dpu_ThreadFence | ||
| 529 | + TASK_DPU_CHANNEL_FENCE = 19, // Dpu_ChannelFence | ||
| 530 | + TASK_DPU_INLINE_WRITE = 20, // Dpu_Notify_Record | ||
| 531 | + TASK_DPU_NOTIFY_WAIT = 21, // Dpu_Notify_Wait | ||
| 532 | + TASK_DPU_WRITE_WITH_NOTIFY = 22, // Dpu_Write_With_Notify | ||
| 533 | + UNKNOWN = 0xFF | ||
| 534 | +}; | ||
| 535 | + | ||
| 536 | +// ============================================================================ | ||
| 537 | +// profiling 链路类型枚举值域与 hcomm DfxLinkType 一一对齐 | ||
| 538 | +// ============================================================================ | ||
| 539 | +enum class ProfLinkType : uint8_t { | ||
| 540 | + LINK_ONCHIP = 0, // 片上/本地 | ||
| 541 | + LINK_HCCS = 1, // HCCS | ||
| 542 | + LINK_PCIE = 2, // PCIe(跨片 SDMA 通道) | ||
| 543 | + LINK_ROCE = 3, // RoCE | ||
| 544 | + LINK_SIO = 4, // SIO | ||
| 545 | + LINK_HCCS_SW = 5, // HCCS_SW | ||
| 546 | + LINK_STANDARD_ROCE = 6, // 标准RoCE | ||
| 547 | + LINK_UB = 7, // UB | ||
| 548 | + LINK_UBoE = 8, // UB over Ethernet | ||
| 549 | + LINK_RESERVED = 9, // 预留 | ||
| 550 | + UNKNOWN = 0xFF | ||
| 551 | +}; | ||
| 552 | + | ||
| 553 | +// ============================================================================ | ||
| 554 | +// profiling 传输类型枚举值域与 hcomm DfxTransportType/SimpleTaskType 一一对齐 | ||
| 555 | +// ============================================================================ | ||
| 556 | +enum class ProfTransportType : uint8_t { | ||
| 557 | + TRANSPORT_SDMA = 0, // 跨片 SDMA 通道搬运 | ||
| 558 | + TRANSPORT_RDMA = 1, // RDMA | ||
| 559 | + TRANSPORT_LOCAL = 2, // 本地搬运/本地算子 | ||
| 560 | + TRANSPORT_UB = 3, // UB 传输 | ||
| 561 | + TRANSPORT_ROCE = 4, // RoCE 传输 | ||
| 562 | + UNKNOWN = 0xFF | ||
| 563 | +}; | ||
| 564 | + | ||
| 565 | +// ============================================================================ | ||
| 566 | +// 任务数据联合体 (联合体大小 120 字节, 取最大成员 CcuTask) | ||
| 476 | // ============================================================================ | 567 | // ============================================================================ |
| 477 | struct TransMemTask { | 568 | struct TransMemTask { |
| 478 | - uint32_t srcRankId; | 569 | + uint32_t srcDeviceId; |
| 479 | uint64_t srcOffset; | 570 | uint64_t srcOffset; |
| 480 | - uint32_t dstRankId; | 571 | + uint32_t dstDeviceId; |
| 481 | uint64_t dstOffset; | 572 | uint64_t dstOffset; |
| 482 | uint64_t len; | 573 | uint64_t len; |
| 483 | uint8_t protocol; | 574 | uint8_t protocol; |
| 484 | }; | 575 | }; |
| 485 | 576 | ||
| 486 | struct ReduceTask { | 577 | struct ReduceTask { |
| 487 | - uint32_t srcRankId; | 578 | + uint32_t srcDeviceId; |
| 488 | uint64_t srcOffset; | 579 | uint64_t srcOffset; |
| 489 | - uint32_t dstRankId; | 580 | + uint32_t dstDeviceId; |
| 490 | uint64_t dstOffset; | 581 | uint64_t dstOffset; |
| 491 | uint64_t dataCount; | 582 | uint64_t dataCount; |
| 492 | uint8_t dataType; | 583 | uint8_t dataType; |
| 493 | uint8_t reduceOp; | 584 | uint8_t reduceOp; |
| 494 | uint8_t protocol; | 585 | uint8_t protocol; |
| 586 | + uint8_t resv; | ||
| 495 | }; | 587 | }; |
| 496 | 588 | ||
| 497 | struct NotifyTask { | 589 | struct NotifyTask { |
| 498 | - uint32_t srcRankId; | 590 | + uint32_t srcDeviceId; |
| 499 | uint64_t notifyId; | 591 | uint64_t notifyId; |
| 500 | - uint32_t dstRankId; | 592 | + uint32_t dstDeviceId; |
| 501 | uint8_t notifyCount; | 593 | uint8_t notifyCount; |
| 502 | uint8_t protocol; | 594 | uint8_t protocol; |
| 503 | }; | 595 | }; |
| 504 | 596 | ||
| 597 | +struct CcuTask { | ||
| 598 | + uint8_t dieId; | ||
| 599 | + uint8_t missionId; | ||
| 600 | + uint16_t timeout; | ||
| 601 | + uint16_t instStartId; | ||
| 602 | + uint16_t instCnt; | ||
| 603 | + uint32_t key; | ||
| 604 | + uint32_t argSize; | ||
| 605 | + uint64_t args[13]; | ||
| 606 | +}; | ||
| 607 | + | ||
| 608 | +struct AivTask { | ||
| 609 | + uint64_t launchIdx; | ||
| 610 | +}; | ||
| 611 | + | ||
| 612 | +struct SyncStreamTask { | ||
| 613 | + uint64_t syncIdx; | ||
| 614 | +}; | ||
| 615 | + | ||
| 616 | +struct WriteWithNotifyTask { | ||
| 617 | + uint32_t srcDeviceId; | ||
| 618 | + uint64_t srcOffset; | ||
| 619 | + uint32_t dstDeviceId; | ||
| 620 | + uint64_t dstOffset; | ||
| 621 | + uint64_t len; // MEM_CPY: 传输长度; REDUCE: dataCount | ||
| 622 | + uint64_t notifyId; | ||
| 623 | + uint8_t isReduce; // 0: 写部分为MEM_CPY; 1: 写部分为REDUCE | ||
| 624 | + uint8_t dataType; | ||
| 625 | + uint8_t reduceOp; | ||
| 626 | + uint8_t protocol; | ||
| 627 | + uint8_t notifyCount; | ||
| 628 | +}; | ||
| 629 | + | ||
| 505 | // ============================================================================ | 630 | // ============================================================================ |
| 506 | -// 任务元数据 | 631 | +// 任务 profiling 对账信息子结构 (3 字节, checker/runner 作为不透明整体透传) |
| 632 | +// 值域对齐 hcomm TaskParamType/DfxLinkType/DfxTransportType | ||
| 633 | +// ============================================================================ | ||
| 634 | +struct HcclTaskProfInfo { | ||
| 635 | + ProfTaskParamType profTaskType; // 对应 msprof timeline op 名 | ||
| 636 | + ProfLinkType linkType; // 物理链路类型 | ||
| 637 | + ProfTransportType transportType; // 数据面传输方式 | ||
| 638 | +}; | ||
| 639 | + | ||
| 640 | +// ============================================================================ | ||
| 641 | +// 任务元数据 (taskType 后含 HcclTaskProfInfo 子结构, sizeof 189 字节) | ||
| 507 | // ============================================================================ | 642 | // ============================================================================ |
| 508 | struct HcclTaskMetaData { | 643 | struct HcclTaskMetaData { |
| 509 | HccLTaskMetaType taskType; | 644 | HccLTaskMetaType taskType; |
| 510 | - uint16_t commId; | 645 | + HcclTaskProfInfo profInfo; // profiling 对账信息(整体 3 字节) |
| 646 | + uint64_t commId; | ||
| 511 | uint32_t rankId; | 647 | uint32_t rankId; |
| 648 | + uint64_t deviceId; | ||
| 512 | uint64_t streamId; | 649 | uint64_t streamId; |
| 513 | uint32_t jettyId; | 650 | uint32_t jettyId; |
| 651 | + uint8_t sqeGroupId; // UDMA SQE批分组标记, 环形递增1~255 | ||
| 652 | + uint8_t rmEid[16]; | ||
| 653 | + uint8_t lcEid[16]; | ||
| 514 | union { | 654 | union { |
| 515 | - TransMemTask transMem; | 655 | + TransMemTask transMem; |
| 516 | - ReduceTask reduce; | 656 | + ReduceTask reduce; |
| 517 | - NotifyTask notify; | 657 | + NotifyTask notify; |
| 658 | + CcuTask ccu; | ||
| 659 | + AivTask aiv; | ||
| 660 | + SyncStreamTask syncStreamTask; | ||
| 661 | + WriteWithNotifyTask writeWithNotify; | ||
| 518 | } taskData; | 662 | } taskData; |
| 519 | }; | 663 | }; |
| 520 | 664 | ||
| @@ -674,15 +818,15 @@ bool ReadTaskMetaData(const char* filename) { | |||
| 674 | switch (task.taskType) { | 818 | switch (task.taskType) { |
| 675 | case HccLTaskMetaType::MEM_CPY: | 819 | case HccLTaskMetaType::MEM_CPY: |
| 676 | std::cout << "MEM_CPY: " | 820 | std::cout << "MEM_CPY: " |
| 677 | - << "src=" << task.taskData.transMem.srcRankId | 821 | + << "src=" << task.taskData.transMem.srcDeviceId |
| 678 | - << ", dst=" << task.taskData.transMem.dstRankId | 822 | + << ", dst=" << task.taskData.transMem.dstDeviceId |
| 679 | << ", len=" << task.taskData.transMem.len; | 823 | << ", len=" << task.taskData.transMem.len; |
| 680 | break; | 824 | break; |
| 681 | 825 | ||
| 682 | case HccLTaskMetaType::REDUCE: | 826 | case HccLTaskMetaType::REDUCE: |
| 683 | std::cout << "REDUCE: " | 827 | std::cout << "REDUCE: " |
| 684 | - << "src=" << task.taskData.reduce.srcRankId | 828 | + << "src=" << task.taskData.reduce.srcDeviceId |
| 685 | - << ", dst=" << task.taskData.reduce.dstRankId | 829 | + << ", dst=" << task.taskData.reduce.dstDeviceId |
| 686 | << ", count=" << task.taskData.reduce.dataCount; | 830 | << ", count=" << task.taskData.reduce.dataCount; |
| 687 | break; | 831 | break; |
| 688 | 832 | ||
| @@ -268,50 +268,81 @@ ChannelData(见 3.3)。本节保留仅作历史格式参考,读取方不 | |||
| 268 | 268 | ||
| 269 | ### 5.2 HcclTaskMetaData 结构 | 269 | ### 5.2 HcclTaskMetaData 结构 |
| 270 | 270 | ||
| 271 | -**大小**:约 136 字节(含联合体) | 271 | +**大小**:188 字节(pack(1),含联合体;偏移 1~3 为 `HcclTaskProfInfo` 子结构,checker/runner 作为不透明整体透传) |
| 272 | 272 | ||
| 273 | -| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | | 273 | +| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | |
| 274 | -|:------:|:------:|-----------------|----------|------------------------| | 274 | +|:------:|:------:|:----------------|----------|--------------------------------------------| |
| 275 | -| 0 | 1 | int8 | taskType | 任务类型(见枚举) | | 275 | +| 0 | 1 | int8 | taskType | 任务类型(见枚举) | |
| 276 | -| 1 | 2 | uint16 | commId | 通信域 ID | | 276 | +| 1 | 3 | HcclTaskProfInfo| profInfo | profiling 对账信息子结构,见下表 | |
| 277 | -| 3 | 4 | uint32 | rankId | Rank ID | | 277 | +| 4 | 8 | uint64 | commId | 通信域 ID | |
| 278 | -| 7 | 8 | uint64 | streamId | Stream ID | | 278 | +| 12 | 4 | uint32 | rankId | 任务所属 Rank ID | |
| 279 | -| 15 | 4 | uint32 | jettyId | Jetty ID | | 279 | +| 16 | 8 | uint64 | deviceId | 任务所属 Device ID | |
| 280 | -| 19 | 变长 | union | taskData | 任务数据(根据类型解析)| | 280 | +| 24 | 8 | uint64 | streamId | Stream ID | |
| 281 | +| 32 | 4 | uint32 | jettyId | Jetty ID | | ||
| 282 | +| 36 | 16 | uint8[16] | rmEid | 对端 EID(WQE 原始字节序) | | ||
| 283 | +| 52 | 16 | uint8[16] | lcEid | 本端 EID(WQE 字节序,见下方说明) | | ||
| 284 | +| 68 | 120 | union | taskData | 任务数据(根据类型解析) | | ||
| 285 | + | ||
| 286 | +`HcclTaskProfInfo` 子结构(偏移 1~3,定义于 `include/sim_profiling_defs.h`,单源管理): | ||
| 287 | + | ||
| 288 | +| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | | ||
| 289 | +|:------:|:------:|:-------------------|---------------|-----------------------------| | ||
| 290 | +| 1 | 1 | uint8 | profTaskType | 对齐 hcomm TaskParamType | | ||
| 291 | +| 2 | 1 | uint8 | linkType | 对齐 hcomm DfxLinkType | | ||
| 292 | +| 3 | 1 | uint8 | transportType | 对齐 hcomm DfxTransportType | | ||
| 293 | + | ||
| 294 | +**EID 字段说明**: | ||
| 295 | + | ||
| 296 | +- `rmEid` 与 `lcEid` 统一采用 **ranktable.json 十六进制串字节序**(与 EndPoint.eid / | ||
| 297 | + RankEidMap 的入库序一致),可与 DB 表 / ranktable 的 EID 串直接比对,二者亦可直接互比。 | ||
| 298 | +- `rmEid` 来源:WQE 中的 `rmtEid` 为 `uint32[4]` 小端字存储(内存 16 字节与 ranktable | ||
| 299 | + 串整体相反),拷入任务时做整 16 字节翻转。 | ||
| 300 | +- `lcEid` 来源:由 `jettyId → RaJetty → RaContext → EndPoint.eid` 查询本端 EID 直拷, | ||
| 301 | + 天然为该序。 | ||
| 302 | +- `lcEid` 仅设备侧 SQE 解析(`device_sqe_parse_stub.cc`)生成的带 jettyId 的任务填充; | ||
| 303 | + 其余任务保持全 0。 | ||
| 304 | +- **rank 约定(estimate 采集)**:taskData 的 `srcDeviceId`/`dstDeviceId` 字段承载 | ||
| 305 | + 通信域 rank(原 `srcRankId`/`dstRankId` 字段已回退删除,值合并入 deviceId 字段); | ||
| 306 | + 为 `UINT32_MAX`(0xFFFFFFFF)时表示未解析到对应 rank(如非 ranktable/EID 模式), | ||
| 307 | + 0 为合法 rank 值。normal 模式(checker 链路)下 deviceId 字段仍为真实 Device ID, | ||
| 308 | + 两种语义按运行模式隔离(estimate 模式禁用 checker)。 | ||
| 281 | 309 | ||
| 282 | ### 5.3 taskData 联合体 | 310 | ### 5.3 taskData 联合体 |
| 283 | 311 | ||
| 312 | +联合体大小 120 字节(取最大成员 CcuTask)。 | ||
| 313 | + | ||
| 284 | #### 5.3.1 TransMemTask | 314 | #### 5.3.1 TransMemTask |
| 285 | 315 | ||
| 286 | **适用任务类型**:`MEM_CPY (3)`。 | 316 | **适用任务类型**:`MEM_CPY (3)`。 |
| 287 | 317 | ||
| 288 | **大小**:33 字节。 | 318 | **大小**:33 字节。 |
| 289 | 319 | ||
| 290 | -| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | | 320 | +| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | |
| 291 | -|:------:|:------:|--------|-----------|--------------| | 321 | +|:------:|:------:|--------|-------------|---------------------------------------| |
| 292 | -| 0 | 4 | uint32 | srcRankId | 源 Rank ID | | 322 | +| 0 | 4 | uint32 | srcDeviceId | 源端点(estimate: rank / normal: Device ID) | |
| 293 | -| 4 | 8 | uint64 | srcOffset | 源偏移地址 | | 323 | +| 4 | 8 | uint64 | srcOffset | 源偏移地址 | |
| 294 | -| 12 | 4 | uint32 | dstRankId | 目标 Rank ID | | 324 | +| 12 | 4 | uint32 | dstDeviceId | 目标端点(estimate: rank / normal: Device ID) | |
| 295 | -| 16 | 8 | uint64 | dstOffset | 目标偏移地址 | | 325 | +| 16 | 8 | uint64 | dstOffset | 目标偏移地址 | |
| 296 | -| 24 | 8 | uint64 | len | 数据长度 | | 326 | +| 24 | 8 | uint64 | len | 数据长度 | |
| 297 | -| 32 | 1 | uint8 | protocol | 协议类型 | | 327 | +| 32 | 1 | uint8 | protocol | 协议类型 | |
| 298 | 328 | ||
| 299 | #### 5.3.2 ReduceTask | 329 | #### 5.3.2 ReduceTask |
| 300 | 330 | ||
| 301 | **适用任务类型**:`REDUCE (2)`。 | 331 | **适用任务类型**:`REDUCE (2)`。 |
| 302 | 332 | ||
| 303 | -**大小**:35 字节。 | 333 | +**大小**:36 字节。 |
| 304 | 334 | ||
| 305 | -| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | | 335 | +| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | |
| 306 | -|:------:|:------:|--------|-----------|--------------| | 336 | +|:------:|:------:|--------|-------------|---------------------------------------| |
| 307 | -| 0 | 4 | uint32 | srcRankId | 源 Rank ID | | 337 | +| 0 | 4 | uint32 | srcDeviceId | 源端点(estimate: rank / normal: Device ID) | |
| 308 | -| 4 | 8 | uint64 | srcOffset | 源偏移地址 | | 338 | +| 4 | 8 | uint64 | srcOffset | 源偏移地址 | |
| 309 | -| 12 | 4 | uint32 | dstRankId | 目标 Rank ID | | 339 | +| 12 | 4 | uint32 | dstDeviceId | 目标端点(estimate: rank / normal: Device ID) | |
| 310 | -| 16 | 8 | uint64 | dstOffset | 目标偏移地址 | | 340 | +| 16 | 8 | uint64 | dstOffset | 目标偏移地址 | |
| 311 | -| 24 | 8 | uint64 | dataCount | 数据元素个数 | | 341 | +| 24 | 8 | uint64 | dataCount | 数据元素个数 | |
| 312 | -| 32 | 1 | uint8 | dataType | 数据类型 | | 342 | +| 32 | 1 | uint8 | dataType | 数据类型 | |
| 313 | -| 33 | 1 | uint8 | reduceOp | 归约操作类型 | | 343 | +| 33 | 1 | uint8 | reduceOp | 归约操作类型 | |
| 314 | -| 34 | 1 | uint8 | protocol | 协议类型 | | 344 | +| 34 | 1 | uint8 | protocol | 协议类型 | |
| 345 | +| 35 | 1 | uint8 | resv | 保留 | | ||
| 315 | 346 | ||
| 316 | #### 5.3.3 NotifyTask | 347 | #### 5.3.3 NotifyTask |
| 317 | 348 | ||
| @@ -319,13 +350,13 @@ ChannelData(见 3.3)。本节保留仅作历史格式参考,读取方不 | |||
| 319 | 350 | ||
| 320 | **大小**:18 字节。 | 351 | **大小**:18 字节。 |
| 321 | 352 | ||
| 322 | -| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | | 353 | +| 偏移量 | 字节数 | 类型 | 字段名 | 说明 | |
| 323 | -|:------:|:------:|--------|-------------|------------| | 354 | +|:------:|:------:|--------|-------------|---------------------------------------------| |
| 324 | -| 0 | 4 | uint32 | srcRankId | 源 Rank ID | | 355 | +| 0 | 4 | uint32 | srcDeviceId | 记录方端点(estimate: rank / normal: Device ID) | |
| 325 | -| 4 | 8 | uint64 | notifyId | 通知 ID | | 356 | +| 4 | 8 | uint64 | notifyId | 通知 ID | |
| 326 | -| 12 | 4 | uint32 | dstRankId | 目标 Rank ID | | 357 | +| 12 | 4 | uint32 | dstDeviceId | 等待方端点(estimate: rank / normal: Device ID) | |
| 327 | -| 16 | 1 | uint8 | notifyCount | 通知计数 | | 358 | +| 16 | 1 | uint8 | notifyCount | 通知计数 | |
| 328 | -| 17 | 1 | uint8 | protocol | 协议类型 | | 359 | +| 17 | 1 | uint8 | protocol | 协议类型 | |
| 329 | 360 | ||
| 330 | --- | 361 | --- |
| 331 | 362 | ||
| @@ -461,60 +492,173 @@ struct MemLayoutData { | |||
| 461 | // 任务类型枚举 | 492 | // 任务类型枚举 |
| 462 | // ============================================================================ | 493 | // ============================================================================ |
| 463 | enum class HccLTaskMetaType : int8_t { | 494 | enum class HccLTaskMetaType : int8_t { |
| 464 | - NOTIFY_WAIT = 0, | 495 | + NOTIFY_WAIT = 0, |
| 465 | - NOTIFY_RECORD = 1, | 496 | + NOTIFY_RECORD = 1, |
| 466 | - REDUCE = 2, | 497 | + REDUCE = 2, |
| 467 | - MEM_CPY = 3, | 498 | + MEM_CPY = 3, |
| 468 | - CCU_GRAPH = 4, | 499 | + CCU_GRAPH = 4, |
| 469 | - AIV_GRAPH = 5, | 500 | + AIV_GRAPH = 5, |
| 470 | - EVENT_WAIT = 6, | 501 | + SYNC_STREAM = 6, |
| 471 | - EVENT_RECORD = 7 | 502 | + WRITE_WITH_NOTIFY = 7, |
| 503 | + INVALID = 8 | ||
| 472 | }; | 504 | }; |
| 473 | 505 | ||
| 474 | // ============================================================================ | 506 | // ============================================================================ |
| 475 | -// 任务数据联合体 | 507 | +// profiling 任务类型枚举值域与 hcomm TaskParamType 一一对齐 |
| 508 | +// ============================================================================ | ||
| 509 | +enum class ProfTaskParamType : uint8_t { | ||
| 510 | + TASK_SDMA = 0, // Memcpy | ||
| 511 | + TASK_RDMA = 1, // RDMASend | ||
| 512 | + TASK_REDUCE_INLINE = 2, // Reduce_Inline | ||
| 513 | + TASK_REDUCE_TBE = 3, // Reduce_TBE | ||
| 514 | + TASK_NOTIFY_RECORD = 4, // Notify_Record | ||
| 515 | + TASK_NOTIFY_WAIT = 5, // Notify_Wait | ||
| 516 | + TASK_SEND_NOTIFY = 6, // Send_Notify | ||
| 517 | + TASK_SEND_PAYLOAD = 7, // Send_Payload | ||
| 518 | + TASK_WRITE_WITH_NOTIFY = 8, // Write_With_Notify | ||
| 519 | + TASK_WRITE_REDUCE_WITH_NOTIFY = 9, // Reduce_With_Notify | ||
| 520 | + TASK_CCU = 10, // Ccu | ||
| 521 | + TASK_AICPU_KERNEL = 11, // AicpuKernel | ||
| 522 | + TASK_AICPU_REDUCE = 12, // Aicpu_Reduce | ||
| 523 | + TASK_AIV = 13, // AivKernel | ||
| 524 | + TASK_UB_INLINE_WRITE = 14, // Ub_Inline_Write | ||
| 525 | + TASK_UB_REDUCE_INLINE = 15, // Ub_Reduce_Inline | ||
| 526 | + TASK_UB = 16, // Ub_Write_Or_Read | ||
| 527 | + TASK_DPU_KERNEL = 17, // DpuKernel | ||
| 528 | + TASK_DPU_THREAD_FENCE = 18, // Dpu_ThreadFence | ||
| 529 | + TASK_DPU_CHANNEL_FENCE = 19, // Dpu_ChannelFence | ||
| 530 | + TASK_DPU_INLINE_WRITE = 20, // Dpu_Notify_Record | ||
| 531 | + TASK_DPU_NOTIFY_WAIT = 21, // Dpu_Notify_Wait | ||
| 532 | + TASK_DPU_WRITE_WITH_NOTIFY = 22, // Dpu_Write_With_Notify | ||
| 533 | + UNKNOWN = 0xFF | ||
| 534 | +}; | ||
| 535 | + | ||
| 536 | +// ============================================================================ | ||
| 537 | +// profiling 链路类型枚举值域与 hcomm DfxLinkType 一一对齐 | ||
| 538 | +// ============================================================================ | ||
| 539 | +enum class ProfLinkType : uint8_t { | ||
| 540 | + LINK_ONCHIP = 0, // 片上/本地 | ||
| 541 | + LINK_HCCS = 1, // HCCS | ||
| 542 | + LINK_PCIE = 2, // PCIe(跨片 SDMA 通道) | ||
| 543 | + LINK_ROCE = 3, // RoCE | ||
| 544 | + LINK_SIO = 4, // SIO | ||
| 545 | + LINK_HCCS_SW = 5, // HCCS_SW | ||
| 546 | + LINK_STANDARD_ROCE = 6, // 标准RoCE | ||
| 547 | + LINK_UB = 7, // UB | ||
| 548 | + LINK_UBoE = 8, // UB over Ethernet | ||
| 549 | + LINK_RESERVED = 9, // 预留 | ||
| 550 | + UNKNOWN = 0xFF | ||
| 551 | +}; | ||
| 552 | + | ||
| 553 | +// ============================================================================ | ||
| 554 | +// profiling 传输类型枚举值域与 hcomm DfxTransportType/SimpleTaskType 一一对齐 | ||
| 555 | +// ============================================================================ | ||
| 556 | +enum class ProfTransportType : uint8_t { | ||
| 557 | + TRANSPORT_SDMA = 0, // 跨片 SDMA 通道搬运 | ||
| 558 | + TRANSPORT_RDMA = 1, // RDMA | ||
| 559 | + TRANSPORT_LOCAL = 2, // 本地搬运/本地算子 | ||
| 560 | + TRANSPORT_UB = 3, // UB 传输 | ||
| 561 | + TRANSPORT_ROCE = 4, // RoCE 传输 | ||
| 562 | + UNKNOWN = 0xFF | ||
| 563 | +}; | ||
| 564 | + | ||
| 565 | +// ============================================================================ | ||
| 566 | +// 任务数据联合体 (联合体大小 120 字节, 取最大成员 CcuTask) | ||
| 476 | // ============================================================================ | 567 | // ============================================================================ |
| 477 | struct TransMemTask { | 568 | struct TransMemTask { |
| 478 | - uint32_t srcRankId; | 569 | + uint32_t srcDeviceId; |
| 479 | uint64_t srcOffset; | 570 | uint64_t srcOffset; |
| 480 | - uint32_t dstRankId; | 571 | + uint32_t dstDeviceId; |
| 481 | uint64_t dstOffset; | 572 | uint64_t dstOffset; |
| 482 | uint64_t len; | 573 | uint64_t len; |
| 483 | uint8_t protocol; | 574 | uint8_t protocol; |
| 484 | }; | 575 | }; |
| 485 | 576 | ||
| 486 | struct ReduceTask { | 577 | struct ReduceTask { |
| 487 | - uint32_t srcRankId; | 578 | + uint32_t srcDeviceId; |
| 488 | uint64_t srcOffset; | 579 | uint64_t srcOffset; |
| 489 | - uint32_t dstRankId; | 580 | + uint32_t dstDeviceId; |
| 490 | uint64_t dstOffset; | 581 | uint64_t dstOffset; |
| 491 | uint64_t dataCount; | 582 | uint64_t dataCount; |
| 492 | uint8_t dataType; | 583 | uint8_t dataType; |
| 493 | uint8_t reduceOp; | 584 | uint8_t reduceOp; |
| 494 | uint8_t protocol; | 585 | uint8_t protocol; |
| 586 | + uint8_t resv; | ||
| 495 | }; | 587 | }; |
| 496 | 588 | ||
| 497 | struct NotifyTask { | 589 | struct NotifyTask { |
| 498 | - uint32_t srcRankId; | 590 | + uint32_t srcDeviceId; |
| 499 | uint64_t notifyId; | 591 | uint64_t notifyId; |
| 500 | - uint32_t dstRankId; | 592 | + uint32_t dstDeviceId; |
| 501 | uint8_t notifyCount; | 593 | uint8_t notifyCount; |
| 502 | uint8_t protocol; | 594 | uint8_t protocol; |
| 503 | }; | 595 | }; |
| 504 | 596 | ||
| 597 | +struct CcuTask { | ||
| 598 | + uint8_t dieId; | ||
| 599 | + uint8_t missionId; | ||
| 600 | + uint16_t timeout; | ||
| 601 | + uint16_t instStartId; | ||
| 602 | + uint16_t instCnt; | ||
| 603 | + uint32_t key; | ||
| 604 | + uint32_t argSize; | ||
| 605 | + uint64_t args[13]; | ||
| 606 | +}; | ||
| 607 | + | ||
| 608 | +struct AivTask { | ||
| 609 | + uint64_t launchIdx; | ||
| 610 | +}; | ||
| 611 | + | ||
| 612 | +struct SyncStreamTask { | ||
| 613 | + uint64_t syncIdx; | ||
| 614 | +}; | ||
| 615 | + | ||
| 616 | +struct WriteWithNotifyTask { | ||
| 617 | + uint32_t srcDeviceId; | ||
| 618 | + uint64_t srcOffset; | ||
| 619 | + uint32_t dstDeviceId; | ||
| 620 | + uint64_t dstOffset; | ||
| 621 | + uint64_t len; // MEM_CPY: 传输长度; REDUCE: dataCount | ||
| 622 | + uint64_t notifyId; | ||
| 623 | + uint8_t isReduce; // 0: 写部分为MEM_CPY; 1: 写部分为REDUCE | ||
| 624 | + uint8_t dataType; | ||
| 625 | + uint8_t reduceOp; | ||
| 626 | + uint8_t protocol; | ||
| 627 | + uint8_t notifyCount; | ||
| 628 | +}; | ||
| 629 | + | ||
| 505 | // ============================================================================ | 630 | // ============================================================================ |
| 506 | -// 任务元数据 | 631 | +// 任务 profiling 对账信息子结构 (3 字节, checker/runner 作为不透明整体透传) |
| 632 | +// 值域对齐 hcomm TaskParamType/DfxLinkType/DfxTransportType | ||
| 633 | +// ============================================================================ | ||
| 634 | +struct HcclTaskProfInfo { | ||
| 635 | + ProfTaskParamType profTaskType; // 对应 msprof timeline op 名 | ||
| 636 | + ProfLinkType linkType; // 物理链路类型 | ||
| 637 | + ProfTransportType transportType; // 数据面传输方式 | ||
| 638 | +}; | ||
| 639 | + | ||
| 640 | +// ============================================================================ | ||
| 641 | +// 任务元数据 (taskType 后含 HcclTaskProfInfo 子结构, sizeof 189 字节) | ||
| 507 | // ============================================================================ | 642 | // ============================================================================ |
| 508 | struct HcclTaskMetaData { | 643 | struct HcclTaskMetaData { |
| 509 | HccLTaskMetaType taskType; | 644 | HccLTaskMetaType taskType; |
| 510 | - uint16_t commId; | 645 | + HcclTaskProfInfo profInfo; // profiling 对账信息(整体 3 字节) |
| 646 | + uint64_t commId; | ||
| 511 | uint32_t rankId; | 647 | uint32_t rankId; |
| 648 | + uint64_t deviceId; | ||
| 512 | uint64_t streamId; | 649 | uint64_t streamId; |
| 513 | uint32_t jettyId; | 650 | uint32_t jettyId; |
| 651 | + uint8_t sqeGroupId; // UDMA SQE批分组标记, 环形递增1~255 | ||
| 652 | + uint8_t rmEid[16]; | ||
| 653 | + uint8_t lcEid[16]; | ||
| 514 | union { | 654 | union { |
| 515 | - TransMemTask transMem; | 655 | + TransMemTask transMem; |
| 516 | - ReduceTask reduce; | 656 | + ReduceTask reduce; |
| 517 | - NotifyTask notify; | 657 | + NotifyTask notify; |
| 658 | + CcuTask ccu; | ||
| 659 | + AivTask aiv; | ||
| 660 | + SyncStreamTask syncStreamTask; | ||
| 661 | + WriteWithNotifyTask writeWithNotify; | ||
| 518 | } taskData; | 662 | } taskData; |
| 519 | }; | 663 | }; |
| 520 | 664 | ||
| @@ -674,15 +818,15 @@ bool ReadTaskMetaData(const char* filename) { | |||
| 674 | switch (task.taskType) { | 818 | switch (task.taskType) { |
| 675 | case HccLTaskMetaType::MEM_CPY: | 819 | case HccLTaskMetaType::MEM_CPY: |
| 676 | std::cout << "MEM_CPY: " | 820 | std::cout << "MEM_CPY: " |
| 677 | - << "src=" << task.taskData.transMem.srcRankId | 821 | + << "src=" << task.taskData.transMem.srcDeviceId |
| 678 | - << ", dst=" << task.taskData.transMem.dstRankId | 822 | + << ", dst=" << task.taskData.transMem.dstDeviceId |
| 679 | << ", len=" << task.taskData.transMem.len; | 823 | << ", len=" << task.taskData.transMem.len; |
| 680 | break; | 824 | break; |
| 681 | 825 | ||
| 682 | case HccLTaskMetaType::REDUCE: | 826 | case HccLTaskMetaType::REDUCE: |
| 683 | std::cout << "REDUCE: " | 827 | std::cout << "REDUCE: " |
| 684 | - << "src=" << task.taskData.reduce.srcRankId | 828 | + << "src=" << task.taskData.reduce.srcDeviceId |
| 685 | - << ", dst=" << task.taskData.reduce.dstRankId | 829 | + << ", dst=" << task.taskData.reduce.dstDeviceId |
| 686 | << ", count=" << task.taskData.reduce.dataCount; | 830 | << ", count=" << task.taskData.reduce.dataCount; |
| 687 | break; | 831 | break; |
| 688 | 832 | ||
| @@ -0,0 +1,111 @@ | |||
| 1 | +# PyTorch 模式运行指南 | ||
| 2 | + | ||
| 3 | +HCCL-VM 现可运行 PyTorch 的 `hccl` 集合通信脚本。脚本使用 `torch.multiprocessing.spawn` 启动各设备进程。多 server 示例在同一宿主机上启动多个 Python 主进程,分别模拟各 server。 | ||
| 4 | + | ||
| 5 | +## 1. 准备环境 | ||
| 6 | + | ||
| 7 | +先按 [README](../README.md) 完成 HCCL-VM 构建安装和 CANN 环境配置,准备已安装兼容版本 `torch`、`torch_npu` 的 Python 虚拟环境。 | ||
| 8 | + | ||
| 9 | +```bash | ||
| 10 | +cd /path/to/CheckerL2/hccl_vm_install/bin | ||
| 11 | + | ||
| 12 | +# 按需选择通信域配置文件,PyTorch暂时仅支持 Ascend950 系列。 | ||
| 13 | +./hccl-vm start ascend950_cluster_32_server_normal.yaml | ||
| 14 | +``` | ||
| 15 | + | ||
| 16 | +进入 `(hvm)$>` 终端后,执行: | ||
| 17 | + | ||
| 18 | +```bash | ||
| 19 | +# 启动 PyTorch 模式 | ||
| 20 | +export HCCL_VM_ENABLE_PYTORCH=1 | ||
| 21 | +# 激活虚拟环境(如有) | ||
| 22 | +source /path/to/torch_test/bin/activate | ||
| 23 | + | ||
| 24 | +# 需要模拟执行时安装 Runner | ||
| 25 | +hccl-vm plugin install @runner | ||
| 26 | +``` | ||
| 27 | + | ||
| 28 | +后续通信域配置、环境变量设置和 Python 启动均在该 HCCL-VM 终端内执行,使 Python 进程继承模拟环境。 | ||
| 29 | + | ||
| 30 | +## 2. 单 server 运行 | ||
| 31 | + | ||
| 32 | +以 `118` 配置为 1 个 server、8 个设备为例: | ||
| 33 | + | ||
| 34 | +```bash | ||
| 35 | +hccl-vm mock-comm 118 | ||
| 36 | + | ||
| 37 | +# 直接运行用例即可 | ||
| 38 | +python -u /path/to/torch/pytorch_test.py \ | ||
| 39 | + --master_ip 127.0.0.1 \ | ||
| 40 | + --master_port 50001 \ | ||
| 41 | + --dev_num 8 \ | ||
| 42 | + --server_num 1 \ | ||
| 43 | + --server_index 0 \ | ||
| 44 | + --data_list 1024 \ | ||
| 45 | + --dtype int32 \ | ||
| 46 | + --optype sum > server0.log 2>&1 | ||
| 47 | +``` | ||
| 48 | + | ||
| 49 | +## 3. 多 server 运行 | ||
| 50 | + | ||
| 51 | +以 `128` 配置为 2 个 server、每个 server 8 个设备,共 16 个 rank为例。两个 server 需要并发启动,使用相同的 master 地址和端口。 | ||
| 52 | + | ||
| 53 | +```bash | ||
| 54 | +hccl-vm mock-comm 128 | ||
| 55 | +export HCCL_VM_ENABLE_PYTORCH=1 | ||
| 56 | +# 激活虚拟环境(如有) | ||
| 57 | +source /path/to/torch_test/bin/activate | ||
| 58 | + | ||
| 59 | +# 启动 server 0 | ||
| 60 | +( | ||
| 61 | + export HCCL_VM_SERVER_INDEX=0 | ||
| 62 | + python -u /path/to/torch/pytorch_test.py \ | ||
| 63 | + --master_ip 127.0.0.1 \ | ||
| 64 | + --master_port 50001 \ | ||
| 65 | + --dev_num 8 \ | ||
| 66 | + --server_num 2 \ | ||
| 67 | + --server_index 0 \ | ||
| 68 | + --data_list 1024 \ | ||
| 69 | + --dtype int32 \ | ||
| 70 | + --optype sum | ||
| 71 | +) > server0.log 2>&1 & | ||
| 72 | + | ||
| 73 | +# 启动 server 1 | ||
| 74 | +( | ||
| 75 | + export HCCL_VM_SERVER_INDEX=1 | ||
| 76 | + python -u /path/to/torch/pytorch_test.py \ | ||
| 77 | + --master_ip 127.0.0.1 \ | ||
| 78 | + --master_port 50001 \ | ||
| 79 | + --dev_num 8 \ | ||
| 80 | + --server_num 2 \ | ||
| 81 | + --server_index 1 \ | ||
| 82 | + --data_list 1024 \ | ||
| 83 | + --dtype int32 \ | ||
| 84 | + --optype sum | ||
| 85 | +) > server1.log 2>&1 & | ||
| 86 | + | ||
| 87 | +# 分别等待两个 server 运行结束 | ||
| 88 | +``` | ||
| 89 | + | ||
| 90 | +| 配置项 | 说明 | | ||
| 91 | +| --- | --- | | ||
| 92 | +| `HCCL_VM_ENABLE_PYTORCH=1` | 启用 PyTorch 适配;设置为 `1`时 `HCCL_VM_SERVER_INDEX` 才生效 | | ||
| 93 | +| `HCCL_VM_SERVER_INDEX` | 当前通信域配置中从 0 开始的 server 序号;每个 server 的子进程分别设置 | | ||
| 94 | +| `--server_index` | 测试脚本的 server 序号,须与该进程的 `HCCL_VM_SERVER_INDEX` 一致 | | ||
| 95 | +| `--dev_num` / `--server_num` | 每个 server 的设备数和 server 总数,须与 `mock-comm` 配置一致 | | ||
| 96 | +| `--master_ip` / `--master_port` | 所有 server 使用相同的 rendezvous 地址;本例进程在同一宿主机上,使用 `127.0.0.1:50001`,可自行设置 | | ||
| 97 | +| `--data_list` / `--dtype` / `--optype` | 本例执行 1024 个 int32 元素的 AllReduce SUM | | ||
| 98 | + | ||
| 99 | +每个 server 的本地逻辑设备号均为 `0–7`;本例 server 0 对应全局 rank `0–7`,server 1 对应全局 rank `8–15`。括号内设置环境变量可避免两个 server 的索引互相覆盖。脚本按每个 server 相同设备数计算全局 rank,因此其他规模应选择设备数一致的通信域配置。 | ||
| 100 | + | ||
| 101 | +## 4. 查看结果 | ||
| 102 | + | ||
| 103 | +等待全部进程结束后查看 `server0.log`、`server1.log`,关注退出状态、异常和相关日志输出。 | ||
| 104 | + | ||
| 105 | +随后可使用 Checker 进行结果校验: | ||
| 106 | + | ||
| 107 | +```bash | ||
| 108 | +hccl-vm plugin run @checker | ||
| 109 | +``` | ||
| 110 | + | ||
| 111 | +全部用例和校验结束后,执行 `exit` 退出 HCCL-VM 终端。 | ||
| @@ -0,0 +1,111 @@ | |||
| 1 | +# PyTorch 模式运行指南 | ||
| 2 | + | ||
| 3 | +HCCL-VM 现可运行 PyTorch 的 `hccl` 集合通信脚本。脚本使用 `torch.multiprocessing.spawn` 启动各设备进程。多 server 示例在同一宿主机上启动多个 Python 主进程,分别模拟各 server。 | ||
| 4 | + | ||
| 5 | +## 1. 准备环境 | ||
| 6 | + | ||
| 7 | +先按 [README](../README.md) 完成 HCCL-VM 构建安装和 CANN 环境配置,准备已安装兼容版本 `torch`、`torch_npu` 的 Python 虚拟环境。 | ||
| 8 | + | ||
| 9 | +```bash | ||
| 10 | +cd /path/to/CheckerL2/hccl_vm_install/bin | ||
| 11 | + | ||
| 12 | +# 按需选择通信域配置文件,PyTorch暂时仅支持 Ascend950 系列。 | ||
| 13 | +./hccl-vm start ascend950_cluster_32_server_normal.yaml | ||
| 14 | +``` | ||
| 15 | + | ||
| 16 | +进入 `(hvm)$>` 终端后,执行: | ||
| 17 | + | ||
| 18 | +```bash | ||
| 19 | +# 启动 PyTorch 模式 | ||
| 20 | +export HCCL_VM_ENABLE_PYTORCH=1 | ||
| 21 | +# 激活虚拟环境(如有) | ||
| 22 | +source /path/to/torch_test/bin/activate | ||
| 23 | + | ||
| 24 | +# 需要模拟执行时安装 Runner | ||
| 25 | +hccl-vm plugin install @runner | ||
| 26 | +``` | ||
| 27 | + | ||
| 28 | +后续通信域配置、环境变量设置和 Python 启动均在该 HCCL-VM 终端内执行,使 Python 进程继承模拟环境。 | ||
| 29 | + | ||
| 30 | +## 2. 单 server 运行 | ||
| 31 | + | ||
| 32 | +以 `118` 配置为 1 个 server、8 个设备为例: | ||
| 33 | + | ||
| 34 | +```bash | ||
| 35 | +hccl-vm mock-comm 118 | ||
| 36 | + | ||
| 37 | +# 直接运行用例即可 | ||
| 38 | +python -u /path/to/torch/pytorch_test.py \ | ||
| 39 | + --master_ip 127.0.0.1 \ | ||
| 40 | + --master_port 50001 \ | ||
| 41 | + --dev_num 8 \ | ||
| 42 | + --server_num 1 \ | ||
| 43 | + --server_index 0 \ | ||
| 44 | + --data_list 1024 \ | ||
| 45 | + --dtype int32 \ | ||
| 46 | + --optype sum > server0.log 2>&1 | ||
| 47 | +``` | ||
| 48 | + | ||
| 49 | +## 3. 多 server 运行 | ||
| 50 | + | ||
| 51 | +以 `128` 配置为 2 个 server、每个 server 8 个设备,共 16 个 rank为例。两个 server 需要并发启动,使用相同的 master 地址和端口。 | ||
| 52 | + | ||
| 53 | +```bash | ||
| 54 | +hccl-vm mock-comm 128 | ||
| 55 | +export HCCL_VM_ENABLE_PYTORCH=1 | ||
| 56 | +# 激活虚拟环境(如有) | ||
| 57 | +source /path/to/torch_test/bin/activate | ||
| 58 | + | ||
| 59 | +# 启动 server 0 | ||
| 60 | +( | ||
| 61 | + export HCCL_VM_SERVER_INDEX=0 | ||
| 62 | + python -u /path/to/torch/pytorch_test.py \ | ||
| 63 | + --master_ip 127.0.0.1 \ | ||
| 64 | + --master_port 50001 \ | ||
| 65 | + --dev_num 8 \ | ||
| 66 | + --server_num 2 \ | ||
| 67 | + --server_index 0 \ | ||
| 68 | + --data_list 1024 \ | ||
| 69 | + --dtype int32 \ | ||
| 70 | + --optype sum | ||
| 71 | +) > server0.log 2>&1 & | ||
| 72 | + | ||
| 73 | +# 启动 server 1 | ||
| 74 | +( | ||
| 75 | + export HCCL_VM_SERVER_INDEX=1 | ||
| 76 | + python -u /path/to/torch/pytorch_test.py \ | ||
| 77 | + --master_ip 127.0.0.1 \ | ||
| 78 | + --master_port 50001 \ | ||
| 79 | + --dev_num 8 \ | ||
| 80 | + --server_num 2 \ | ||
| 81 | + --server_index 1 \ | ||
| 82 | + --data_list 1024 \ | ||
| 83 | + --dtype int32 \ | ||
| 84 | + --optype sum | ||
| 85 | +) > server1.log 2>&1 & | ||
| 86 | + | ||
| 87 | +# 分别等待两个 server 运行结束 | ||
| 88 | +``` | ||
| 89 | + | ||
| 90 | +| 配置项 | 说明 | | ||
| 91 | +| --- | --- | | ||
| 92 | +| `HCCL_VM_ENABLE_PYTORCH=1` | 启用 PyTorch 适配;设置为 `1`时 `HCCL_VM_SERVER_INDEX` 才生效 | | ||
| 93 | +| `HCCL_VM_SERVER_INDEX` | 当前通信域配置中从 0 开始的 server 序号;每个 server 的子进程分别设置 | | ||
| 94 | +| `--server_index` | 测试脚本的 server 序号,须与该进程的 `HCCL_VM_SERVER_INDEX` 一致 | | ||
| 95 | +| `--dev_num` / `--server_num` | 每个 server 的设备数和 server 总数,须与 `mock-comm` 配置一致 | | ||
| 96 | +| `--master_ip` / `--master_port` | 所有 server 使用相同的 rendezvous 地址;本例进程在同一宿主机上,使用 `127.0.0.1:50001`,可自行设置 | | ||
| 97 | +| `--data_list` / `--dtype` / `--optype` | 本例执行 1024 个 int32 元素的 AllReduce SUM | | ||
| 98 | + | ||
| 99 | +每个 server 的本地逻辑设备号均为 `0–7`;本例 server 0 对应全局 rank `0–7`,server 1 对应全局 rank `8–15`。括号内设置环境变量可避免两个 server 的索引互相覆盖。脚本按每个 server 相同设备数计算全局 rank,因此其他规模应选择设备数一致的通信域配置。 | ||
| 100 | + | ||
| 101 | +## 4. 查看结果 | ||
| 102 | + | ||
| 103 | +等待全部进程结束后查看 `server0.log`、`server1.log`,关注退出状态、异常和相关日志输出。 | ||
| 104 | + | ||
| 105 | +随后可使用 Checker 进行结果校验: | ||
| 106 | + | ||
| 107 | +```bash | ||
| 108 | +hccl-vm plugin run @checker | ||
| 109 | +``` | ||
| 110 | + | ||
| 111 | +全部用例和校验结束后,执行 `exit` 退出 HCCL-VM 终端。 | ||
| @@ -1868,7 +1868,7 @@ HCCP Network API | |||
| 1868 | 1868 | ||
| 1869 | ##### 落库必要性分类(进程私有候选) | 1869 | ##### 落库必要性分类(进程私有候选) |
| 1870 | 1870 | ||
| 1871 | -判定依据是**有没有别的进程/组件在运行期真调用库 API**(`Add`/`Get*`/`Update*`/`Delete*`\<sim::X\>);某实体的名字在别的目录出现不算数——原判据把 `cmd` 的 `PrintTable` 转储、以及同名结构体的局部变量误算成了运行期使用,本节按此修正。 | 1871 | +判定依据是**有没有别的进程/组件在运行期真调用库 API**(`Add`/`Get*`/`Update*`/`Delete*` `<sim::X>`);某实体的名字在别的目录出现不算数——原判据把 `cmd` 的 `PrintTable` 转储、以及同名结构体的局部变量误算成了运行期使用,本节按此修正。 |
| 1872 | 1872 | ||
| 1873 | - **C1 跨进程共享**:`src/device_arm`(独立 aarch64 `device` 可执行,单独链接 `db_sim_sqlite_db.cc`)、`src/plugin/runner`、`src/plugin/checker`、`src/store`(shm 通道)、`src/plugin/hccl_plugin_manager.cc` 中存在真库调用 ⇒ 必须落库。 | 1873 | - **C1 跨进程共享**:`src/device_arm`(独立 aarch64 `device` 可执行,单独链接 `db_sim_sqlite_db.cc`)、`src/plugin/runner`、`src/plugin/checker`、`src/store`(shm 通道)、`src/plugin/hccl_plugin_manager.cc` 中存在真库调用 ⇒ 必须落库。 |
| 1874 | - **C2 拓扑/硬件事实**:由 `src/topo/topo_ascend_cluster_parser.cc` 写入、多进程共读同一份 ⇒ 必须落库。 | 1874 | - **C2 拓扑/硬件事实**:由 `src/topo/topo_ascend_cluster_parser.cc` 写入、多进程共读同一份 ⇒ 必须落库。 |
| @@ -1868,7 +1868,7 @@ HCCP Network API | |||
| 1868 | 1868 | ||
| 1869 | ##### 落库必要性分类(进程私有候选) | 1869 | ##### 落库必要性分类(进程私有候选) |
| 1870 | 1870 | ||
| 1871 | -判定依据是**有没有别的进程/组件在运行期真调用库 API**(`Add`/`Get*`/`Update*`/`Delete*`\<sim::X\>);某实体的名字在别的目录出现不算数——原判据把 `cmd` 的 `PrintTable` 转储、以及同名结构体的局部变量误算成了运行期使用,本节按此修正。 | 1871 | +判定依据是**有没有别的进程/组件在运行期真调用库 API**(`Add`/`Get*`/`Update*`/`Delete*` `<sim::X>`);某实体的名字在别的目录出现不算数——原判据把 `cmd` 的 `PrintTable` 转储、以及同名结构体的局部变量误算成了运行期使用,本节按此修正。 |
| 1872 | 1872 | ||
| 1873 | - **C1 跨进程共享**:`src/device_arm`(独立 aarch64 `device` 可执行,单独链接 `db_sim_sqlite_db.cc`)、`src/plugin/runner`、`src/plugin/checker`、`src/store`(shm 通道)、`src/plugin/hccl_plugin_manager.cc` 中存在真库调用 ⇒ 必须落库。 | 1873 | - **C1 跨进程共享**:`src/device_arm`(独立 aarch64 `device` 可执行,单独链接 `db_sim_sqlite_db.cc`)、`src/plugin/runner`、`src/plugin/checker`、`src/store`(shm 通道)、`src/plugin/hccl_plugin_manager.cc` 中存在真库调用 ⇒ 必须落库。 |
| 1874 | - **C2 拓扑/硬件事实**:由 `src/topo/topo_ascend_cluster_parser.cc` 写入、多进程共读同一份 ⇒ 必须落库。 | 1874 | - **C2 拓扑/硬件事实**:由 `src/topo/topo_ascend_cluster_parser.cc` 写入、多进程共读同一份 ⇒ 必须落库。 |
| @@ -0,0 +1,135 @@ | |||
| 1 | +#!/usr/bin/env python3 | ||
| 2 | +# -*- coding: UTF-8 -*- | ||
| 3 | +# ----------------------------------------------------------------------------------------------------------- | ||
| 4 | +# Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 5 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 6 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 7 | +# Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 8 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 9 | +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 10 | +# See LICENSE in the root of the software repository for the full text of the License. | ||
| 11 | +# ----------------------------------------------------------------------------------------------------------- | ||
| 12 | + | ||
| 13 | +"""light_performance 一键 dump 入口: db → 任务图 → DOT + JSON。 | ||
| 14 | + | ||
| 15 | +用法 (仓库根目录执行): | ||
| 16 | + python3 dump_graph.py hccl_vm_install/data/hccl_vm_data.db | ||
| 17 | + python3 dump_graph.py <db> --device 1 --iter 0 --out graph_dump --no-sim | ||
| 18 | + python3 dump_graph.py <db> --html # 额外输出单文件 HTML | ||
| 19 | + | ||
| 20 | +输出 (默认 graph_dump/ 目录): | ||
| 21 | + graph_comm{X}_iter{Y}_dev{Z}.dot graphviz 任务图 (VSCode Graphviz 插件直接预览) | ||
| 22 | + graph_comm{X}_iter{Y}_dev{Z}.json 固定格式任务图 (nodes/streams/matches) | ||
| 23 | +""" | ||
| 24 | + | ||
| 25 | +import argparse | ||
| 26 | +import os | ||
| 27 | +import sys | ||
| 28 | + | ||
| 29 | +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), | ||
| 30 | + "src", "plugin")) | ||
| 31 | + | ||
| 32 | +from light_performance.__main__ import _find_ranktable | ||
| 33 | +from light_performance.db_reader import load_op_executions | ||
| 34 | +from light_performance.graph_builder import GraphBuilder | ||
| 35 | +from light_performance.graph_dumper import dump_group | ||
| 36 | +from light_performance.sqe_group_merge import merge_sqe_group_tasks, merge_dpu_write_sequences | ||
| 37 | +from light_performance.simulator.config import SimConfig | ||
| 38 | +from light_performance.simulator.simulator import HcclSimulator | ||
| 39 | +from light_performance.simulator.task_model import TRANSFER_TYPES | ||
| 40 | +from light_performance.simulator.topo_resolver import TopoResolver | ||
| 41 | + | ||
| 42 | + | ||
| 43 | +def main(): | ||
| 44 | + parser = argparse.ArgumentParser( | ||
| 45 | + description="读取 hccl_vm_data.db, 生成任务依赖图 dump (JSON + HTML)") | ||
| 46 | + parser.add_argument("db", help="hccl_vm_data.db 路径") | ||
| 47 | + parser.add_argument("--device", type=int, default=None, | ||
| 48 | + help="目标 deviceId (默认取 opDetails 首个设备)") | ||
| 49 | + parser.add_argument("--iter", type=int, default=None, | ||
| 50 | + help="仅处理指定 opIter (默认全部)") | ||
| 51 | + parser.add_argument("--ranktable", | ||
| 52 | + help="ranktable.json (eid→端口解析; 默认取 db 同目录)") | ||
| 53 | + parser.add_argument("--out", default="graph_dump", | ||
| 54 | + help="dump 输出目录 (默认 graph_dump)") | ||
| 55 | + parser.add_argument("--no-sim", action="store_true", | ||
| 56 | + help="不执行仿真 (dump 中不含任务时刻信息)") | ||
| 57 | + parser.add_argument("--html", action="store_true", | ||
| 58 | + help="额外输出单文件 HTML 视图") | ||
| 59 | + args = parser.parse_args() | ||
| 60 | + | ||
| 61 | + if not os.path.isfile(args.db): | ||
| 62 | + print(f"错误: db 文件不存在: {args.db}") | ||
| 63 | + return 1 | ||
| 64 | + | ||
| 65 | + groups = load_op_executions(args.db, target_device=args.device) | ||
| 66 | + if not groups: | ||
| 67 | + print("错误: db 中未读取到算子执行数据") | ||
| 68 | + return 1 | ||
| 69 | + if args.iter is not None: | ||
| 70 | + groups = [g for g in groups if g.op_iter == args.iter] | ||
| 71 | + if not groups: | ||
| 72 | + print(f"错误: 未找到 opIter={args.iter}") | ||
| 73 | + return 1 | ||
| 74 | + | ||
| 75 | + os.makedirs(args.out, exist_ok=True) | ||
| 76 | + config = SimConfig() | ||
| 77 | + topo = None | ||
| 78 | + ranktable = _find_ranktable(args.db, args.ranktable) | ||
| 79 | + if ranktable: | ||
| 80 | + topo = TopoResolver(ranktable_path=ranktable) | ||
| 81 | + outputs = [] | ||
| 82 | + | ||
| 83 | + for group in groups: | ||
| 84 | + # SQE 批合并: 同批同键 UDMA 任务并成 1 个 (见 sqe_group_merge), 与 pipeline 入口口径一致 | ||
| 85 | + group.tasks, merged = merge_sqe_group_tasks(group.tasks) | ||
| 86 | + if merged: | ||
| 87 | + print(f"[MERGE] comm{group.comm_id}/iter{group.op_iter}: " | ||
| 88 | + f"{merged} 个 UDMA 数据任务并入同组 (剩余 {len(group.tasks)})") | ||
| 89 | + # DPU 序列合并: 大消息前块并入 WRITE_WITH_NOTIFY, 与 pipeline 入口口径一致 | ||
| 90 | + group.tasks, merged = merge_dpu_write_sequences(group.tasks) | ||
| 91 | + if merged: | ||
| 92 | + print(f"[MERGE-DPU] comm{group.comm_id}/iter{group.op_iter}: " | ||
| 93 | + f"{merged} 个前块 MEM_CPY 并入 WRITE_WITH_NOTIFY " | ||
| 94 | + f"(剩余 {len(group.tasks)})") | ||
| 95 | + builder = GraphBuilder(group, config) | ||
| 96 | + _, dep = builder.build() | ||
| 97 | + if dep.task_count == 0: | ||
| 98 | + print(f"comm{group.comm_id}/iter{group.op_iter}: 依赖图为空, 跳过") | ||
| 99 | + continue | ||
| 100 | + | ||
| 101 | + meta = {"op_desc": f"comm{group.comm_id}/iter{group.op_iter}" | ||
| 102 | + f"/dev{group.device_id}", | ||
| 103 | + "op_type": group.op_type, "rank_size": group.rank_size} | ||
| 104 | + if not args.no_sim: | ||
| 105 | + has_transfer = any(t.task_type in TRANSFER_TYPES | ||
| 106 | + for t in dep.tasks.values()) | ||
| 107 | + if has_transfer and topo is None: | ||
| 108 | + print(f"comm{group.comm_id}/iter{group.op_iter}: 存在走网任务" | ||
| 109 | + "但无 ranktable, 跳过仿真") | ||
| 110 | + else: | ||
| 111 | + sim = HcclSimulator(config, dep, topo) | ||
| 112 | + result = sim.run() | ||
| 113 | + meta["makespan_us"] = result["makespan"] * 1e6 | ||
| 114 | + | ||
| 115 | + prefix = os.path.join( | ||
| 116 | + args.out, | ||
| 117 | + f"graph_comm{group.comm_id}_iter{group.op_iter}" | ||
| 118 | + f"_dev{group.device_id}") | ||
| 119 | + paths = dump_group(dep, prefix, meta, stats=builder.stats, | ||
| 120 | + stream_labels=builder.stream_labels, | ||
| 121 | + stream_meta=builder.stream_meta, | ||
| 122 | + html=args.html) | ||
| 123 | + outputs.extend(paths) | ||
| 124 | + print(f"[OK] comm{group.comm_id}/iter{group.op_iter}: " | ||
| 125 | + f"{builder.stats.summary()}") | ||
| 126 | + | ||
| 127 | + print("\n输出文件:") | ||
| 128 | + for path in outputs: | ||
| 129 | + tag = " <- VSCode Graphviz 插件预览" if path.endswith(".dot") else "" | ||
| 130 | + print(f" {path}{tag}") | ||
| 131 | + return 0 | ||
| 132 | + | ||
| 133 | + | ||
| 134 | +if __name__ == "__main__": | ||
| 135 | + sys.exit(main()) | ||
| @@ -221,10 +221,8 @@ profile_cann_channel() { profile_row "$1" | cut -d'|' -f5; } # CANN 下载通 | |||
| 221 | show_help() { | 221 | show_help() { |
| 222 | echo "HCCL-VM 一键安装脚本 $(version_line)" | 222 | echo "HCCL-VM 一键安装脚本 $(version_line)" |
| 223 | echo "" | 223 | echo "" |
| 224 | - echo "新手直接运行,无需任何参数(依赖自动安装;需确认的操作有终端时提示、超时按默认继续):" | 224 | + echo "取得完整 CheckerL2 源码后,在仓库根目录直接运行:" |
| 225 | - echo " curl -fsSL https://raw.gitcode.com/cann/hcomm/raw/master/test/hccl_vm/hccl_vm_installer | bash" | 225 | + echo " bash ./hccl_vm_installer" |
| 226 | - echo " curl -fsSL <URL> | bash -s -- --workspace /root/hvm # 一键并指定工作目录" | ||
| 227 | - echo " (或下载后本地运行: bash hccl_vm_installer)" | ||
| 228 | echo "" | 226 | echo "" |
| 229 | echo "脚本将自动完成以下 9 步:" | 227 | echo "脚本将自动完成以下 9 步:" |
| 230 | echo " 1-3. 检查环境、磁盘、安装依赖" | 228 | echo " 1-3. 检查环境、磁盘、安装依赖" |
| @@ -383,7 +381,7 @@ apply_defaults() { | |||
| 383 | ASCEND_PATH=${ASCEND_PATH:-/usr/local/Ascend} | 381 | ASCEND_PATH=${ASCEND_PATH:-/usr/local/Ascend} |
| 384 | HCOMM_PATH=${HCOMM_PATH:-${WORKSPACE}/hcomm} | 382 | HCOMM_PATH=${HCOMM_PATH:-${WORKSPACE}/hcomm} |
| 385 | HCCL_PATH=${HCCL_PATH:-${WORKSPACE}/hccl} | 383 | HCCL_PATH=${HCCL_PATH:-${WORKSPACE}/hccl} |
| 386 | - CHECKER_PATH=${CHECKER_PATH:-${HCOMM_PATH}/test/hccl_vm} | 384 | + CHECKER_PATH=${CHECKER_PATH:-$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)} |
| 387 | # 路径统一绝对化:相对路径会在后续 cd 与 precheck_cann_path 的 dirname 回溯中出错 | 385 | # 路径统一绝对化:相对路径会在后续 cd 与 precheck_cann_path 的 dirname 回溯中出错 |
| 388 | WORKSPACE="$(to_abs "${WORKSPACE}")" | 386 | WORKSPACE="$(to_abs "${WORKSPACE}")" |
| 389 | ASCEND_PATH="$(to_abs "${ASCEND_PATH}")" | 387 | ASCEND_PATH="$(to_abs "${ASCEND_PATH}")" |
| @@ -1330,10 +1328,10 @@ build_hcomm_hccl_pkg() { | |||
| 1330 | info "编译日志: ${pkg_log}" | 1328 | info "编译日志: ${pkg_log}" |
| 1331 | local rc=0 | 1329 | local rc=0 |
| 1332 | if [ "${VERBOSE}" = true ]; then | 1330 | if [ "${VERBOSE}" = true ]; then |
| 1333 | - bash "${pkg_script}" --tool_path "${CHECKER_PATH}" 2>&1 | tee "${pkg_log}" || rc=${PIPESTATUS[0]} | 1331 | + HCCL_VM_PATH="${CHECKER_PATH}" bash "${pkg_script}" --tool_path "${CHECKER_PATH}" 2>&1 | tee "${pkg_log}" || rc=${PIPESTATUS[0]} |
| 1334 | else | 1332 | else |
| 1335 | info "开始执行 build_pkg.sh。实时日志: tail -f ${pkg_log}" | 1333 | info "开始执行 build_pkg.sh。实时日志: tail -f ${pkg_log}" |
| 1336 | - bash "${pkg_script}" --tool_path "${CHECKER_PATH}" > "${pkg_log}" 2>&1 & | 1334 | + HCCL_VM_PATH="${CHECKER_PATH}" bash "${pkg_script}" --tool_path "${CHECKER_PATH}" > "${pkg_log}" 2>&1 & |
| 1337 | local pkg_pid=$! | 1335 | local pkg_pid=$! |
| 1338 | spin_on_pid "${pkg_pid}" "编译子包中" | 1336 | spin_on_pid "${pkg_pid}" "编译子包中" |
| 1339 | wait "${pkg_pid}" || rc=$? | 1337 | wait "${pkg_pid}" || rc=$? |
| @@ -46,7 +46,8 @@ | |||
| 46 | (Version(1), Scope::Static, Field(id, AutoIncrement), Field(pid), Field(deviceId), Field(rankId), \ | 46 | (Version(1), Scope::Static, Field(id, AutoIncrement), Field(pid), Field(deviceId), Field(rankId), \ |
| 47 | Field(commId), Field(opIter), Field(syncIter), Field(streamId), Field(root), Field(opExpansionMode), \ | 47 | Field(commId), Field(opIter), Field(syncIter), Field(streamId), Field(root), Field(opExpansionMode), \ |
| 48 | Field(devType), Field(rankSize), Field(srcRank), Field(dstRank), Field(opDetail), Field(opExtInfo), \ | 48 | Field(devType), Field(rankSize), Field(srcRank), Field(dstRank), Field(opDetail), Field(opExtInfo), \ |
| 49 | - PrimaryKey(id), Index(pid, syncIter), Index(commId, deviceId, id), Index(syncIter), Index(deviceId, id))) \ | 49 | + Field(algorithmName, Text), PrimaryKey(id), Index(pid, syncIter), Index(commId, deviceId, id), \ |
| 50 | + Index(syncIter), Index(deviceId, id))) \ | ||
| 50 | Table( \ | 51 | Table( \ |
| 51 | sim::operation::OpMemInfoTab, \ | 52 | sim::operation::OpMemInfoTab, \ |
| 52 | (Version(1), Scope::Static, Field(id, AutoIncrement), Field(opDetailId), Field(inputAddr), \ | 53 | (Version(1), Scope::Static, Field(id, AutoIncrement), Field(opDetailId), Field(inputAddr), \ |
| @@ -158,6 +159,8 @@ int InsertOpDetail(OpDetailTab& rec); | |||
| 158 | int InsertOpMem(OpMemInfoTab& rec); | 159 | int InsertOpMem(OpMemInfoTab& rec); |
| 159 | // OpDetail 与 OpMem 同事务原子提交(多表流程)。 | 160 | // OpDetail 与 OpMem 同事务原子提交(多表流程)。 |
| 160 | int InsertOpDetailAndMem(OpDetailTab& detail, OpMemInfoTab& mem); | 161 | int InsertOpDetailAndMem(OpDetailTab& detail, OpMemInfoTab& mem); |
| 162 | +// 算法选择结果回填(日志截取): 同一算子多次匹配时后写覆盖 (last-wins),与最终生效算法一致 | ||
| 163 | +int UpdateOpDetailAlgName(const std::string& algName); | ||
| 161 | int QueryNewestOpDeatailIdByPid(uint64_t pid, uint32_t& OpDetailId); | 164 | int QueryNewestOpDeatailIdByPid(uint64_t pid, uint32_t& OpDetailId); |
| 162 | // 同 syncIter 下目标 rank 的最新算子内存信息(组合查询)。 | 165 | // 同 syncIter 下目标 rank 的最新算子内存信息(组合查询)。 |
| 163 | int QueryCurrentOpMemInfoByRank(uint32_t rankId, OpMemInfoTab& out); | 166 | int QueryCurrentOpMemInfoByRank(uint32_t rankId, OpMemInfoTab& out); |
| @@ -48,6 +48,7 @@ struct OpDetailTab { | |||
| 48 | uint32_t dstRank; // dstRank | 48 | uint32_t dstRank; // dstRank |
| 49 | std::vector<uint8_t> opDetail; // BLOB | 49 | std::vector<uint8_t> opDetail; // BLOB |
| 50 | std::vector<uint8_t> opExtInfo; // BLOB | 50 | std::vector<uint8_t> opExtInfo; // BLOB |
| 51 | + char algorithmName[128]; // 算法选择结果(日志截取回填, last-wins) | ||
| 51 | }; | 52 | }; |
| 52 | 53 | ||
| 53 | struct OpMemInfoTab { | 54 | struct OpMemInfoTab { |
| @@ -77,6 +77,8 @@ aclError GetEndPointByEid(const IpAddress& addr, EndPoint& endPoint); | |||
| 77 | // EID精确匹配失败时, 若为v4映射EID(高12字节全0+低4字节IPv4, UBOE IPv4链路地址派生), | 77 | // EID精确匹配失败时, 若为v4映射EID(高12字节全0+低4字节IPv4, UBOE IPv4链路地址派生), |
| 78 | // 按低32位IPv4回退匹配EndPoint.ip_addr(与真实驱动v4->EID解析语义一致) | 78 | // 按低32位IPv4回退匹配EndPoint.ip_addr(与真实驱动v4->EID解析语义一致) |
| 79 | aclError GetEndPointByEidOrIpV4(const IpAddress& addr, EndPoint& endPoint); | 79 | aclError GetEndPointByEidOrIpV4(const IpAddress& addr, EndPoint& endPoint); |
| 80 | +// 按EID查ranktable.json记录的rankId(RankEidMap表); estimate模式Communicator表无对端行, 对端rank以此为准 | ||
| 81 | +bool GetRankIdByEid(const IpAddress& addr, uint32_t& rankId); | ||
| 80 | aclError GetPortById(uint64_t portId, Port& port); | 82 | aclError GetPortById(uint64_t portId, Port& port); |
| 81 | 83 | ||
| 82 | uint32_t GetAICpuCount(uint64_t deviceId); | 84 | uint32_t GetAICpuCount(uint64_t deviceId); |
| @@ -25,6 +25,15 @@ typedef struct { | |||
| 25 | char file_name[128]; // topo_meta yaml文件名(不含.yaml后缀); "ranktable"表示ranktable.json模式 | 25 | char file_name[128]; // topo_meta yaml文件名(不含.yaml后缀); "ranktable"表示ranktable.json模式 |
| 26 | } TopoMetaConfig; | 26 | } TopoMetaConfig; |
| 27 | 27 | ||
| 28 | +// ranktable.json的rank_id与EID映射: 一个rank在每个net_layer/net_instance各有一个EID, 故一rank多行; | ||
| 29 | +// eid按十六进制串字节序存储(与EndPoint.eid一致), mock-comm时随通信域初始化整体重写。 | ||
| 30 | +// estimate模式Communicator表只有本rank一行, 对端rankId以此表为准。 | ||
| 31 | +typedef struct { | ||
| 32 | + uint64_t id; // PK | ||
| 33 | + uint32_t rank_id; // rank_list[].rank_id(文件显式值) | ||
| 34 | + uint8_t eid[URMA_EID_LEN]; // rank_addr_list[].addr | ||
| 35 | +} RankEidMap; | ||
| 36 | + | ||
| 28 | typedef struct { | 37 | typedef struct { |
| 29 | uint64_t id; // PK | 38 | uint64_t id; // PK |
| 30 | uint64_t pod_id; | 39 | uint64_t pod_id; |
| @@ -36,7 +45,7 @@ typedef struct { | |||
| 36 | 45 | ||
| 37 | typedef struct { | 46 | typedef struct { |
| 38 | uint64_t id; // PK | 47 | uint64_t id; // PK |
| 39 | - uint8_t mode; // 0=normal,1=check-only | 48 | + uint8_t mode; // 0=normal,1=check-only,2=estimate (互斥三态) |
| 40 | } RunModeConfig; | 49 | } RunModeConfig; |
| 41 | 50 | ||
| 42 | typedef struct { | 51 | typedef struct { |
| @@ -81,7 +90,9 @@ typedef struct { | |||
| 81 | uint64_t sym_win_addr; | 90 | uint64_t sym_win_addr; |
| 82 | uint64_t sym_win_size; | 91 | uint64_t sym_win_size; |
| 83 | uint8_t sym_win_registered; | 92 | uint8_t sym_win_registered; |
| 84 | - uint8_t status; // CommStatus: 销毁同步状态 | 93 | + uint8_t status; // CommStatus: 销毁同步状态 |
| 94 | + uint64_t dpu_mem_addr; // DPU(DPUTAG)共享内存的 host 侧地址(观测用,HostDPU level1 登记) | ||
| 95 | + uint64_t dpu_mem_size; // DPU(DPUTAG)共享内存实际分配尺寸(观测用) | ||
| 85 | } Communicator; | 96 | } Communicator; |
| 86 | 97 | ||
| 87 | // level 1 专用通信域清理同步机制 | 98 | // level 1 专用通信域清理同步机制 |
| @@ -103,7 +114,7 @@ typedef struct { | |||
| 103 | uint32_t overflow_mode; | 114 | uint32_t overflow_mode; |
| 104 | // 完整SoC型号名(如"Ascend950DT_95A1",16字符)需16+1字节,32对齐hal侧MAX_CHIP_NAME | 115 | // 完整SoC型号名(如"Ascend950DT_95A1",16字符)需16+1字节,32对齐hal侧MAX_CHIP_NAME |
| 105 | char soc_version[32]; | 116 | char soc_version[32]; |
| 106 | - uint32_t status; // 0 可用, 1不可用 | 117 | + uint32_t status; // 设备编域状态:0 未编入通信域, 1 已编入通信域/在线(runner 在线计数、dump 等消费方均按 1 过滤) |
| 107 | } Device; | 118 | } Device; |
| 108 | 119 | ||
| 109 | enum TsDevType { TS_DEV_TYPE_SCALAR = 0, TS_DEV_TYPE_CPU = 1, TS_DEV_TYPE_CCU = 2 }; | 120 | enum TsDevType { TS_DEV_TYPE_SCALAR = 0, TS_DEV_TYPE_CPU = 1, TS_DEV_TYPE_CCU = 2 }; |
| @@ -19,6 +19,8 @@ | |||
| 19 | #include <string> | 19 | #include <string> |
| 20 | #include <vector> | 20 | #include <vector> |
| 21 | 21 | ||
| 22 | +#include "sim_profiling_defs.h" | ||
| 23 | + | ||
| 22 | #define RT_CCU_SQE_ARGS_LEN (13U) | 24 | #define RT_CCU_SQE_ARGS_LEN (13U) |
| 23 | 25 | ||
| 24 | namespace HcclSim { | 26 | namespace HcclSim { |
| @@ -183,9 +185,15 @@ enum class HccLTaskMetaType : char { | |||
| 183 | AIV_GRAPH, | 185 | AIV_GRAPH, |
| 184 | SYNC_STREAM, | 186 | SYNC_STREAM, |
| 185 | MODEL_EXEC, | 187 | MODEL_EXEC, |
| 188 | + WRITE_WITH_NOTIFY, | ||
| 186 | INVALID | 189 | INVALID |
| 187 | }; | 190 | }; |
| 188 | 191 | ||
| 192 | +typedef enum { | ||
| 193 | + TASK_SRC_DEFAULT = 0, | ||
| 194 | + TASK_SRC_DPU = 1, | ||
| 195 | +} HcclTaskSrc; | ||
| 196 | + | ||
| 189 | typedef enum { | 197 | typedef enum { |
| 190 | SUCCESS = 0, | 198 | SUCCESS = 0, |
| 191 | FAILURE = 1, | 199 | FAILURE = 1, |
| @@ -307,6 +315,29 @@ typedef struct { | |||
| 307 | } | 315 | } |
| 308 | } NotifyTask; | 316 | } NotifyTask; |
| 309 | 317 | ||
| 318 | +typedef struct { | ||
| 319 | + uint32_t srcDeviceId; | ||
| 320 | + uint64_t srcOffset; | ||
| 321 | + uint32_t dstDeviceId; | ||
| 322 | + uint64_t dstOffset; | ||
| 323 | + uint64_t len; // MEM_CPY/REDUCE: 传输长度 | ||
| 324 | + uint64_t notifyId; | ||
| 325 | + uint8_t isReduce; // 0: 写部分为MEM_CPY; 1: 写部分为REDUCE | ||
| 326 | + uint8_t dataType; // REDUCE 载荷: HcclDataType | ||
| 327 | + uint8_t reduceOp; // REDUCE 载荷: HcclReduceOp | ||
| 328 | + uint8_t protocol; | ||
| 329 | + uint8_t notifyCount; | ||
| 330 | + | ||
| 331 | + std::string Describe() const | ||
| 332 | + { | ||
| 333 | + std::ostringstream oss; | ||
| 334 | + oss << "srcDeviceId=" << srcDeviceId << " srcOffset=" << srcOffset << " dstDeviceId=" << dstDeviceId | ||
| 335 | + << " dstOffset=" << dstOffset << " len=" << len << " notifyId=" << notifyId | ||
| 336 | + << " isReduce=" << static_cast<uint32_t>(isReduce); | ||
| 337 | + return oss.str(); | ||
| 338 | + } | ||
| 339 | +} WriteWithNotifyTask; | ||
| 340 | + | ||
| 310 | typedef struct { | 341 | typedef struct { |
| 311 | uint8_t dieId; | 342 | uint8_t dieId; |
| 312 | uint8_t missionId; | 343 | uint8_t missionId; |
| @@ -340,12 +371,16 @@ typedef struct { | |||
| 340 | 371 | ||
| 341 | typedef struct HcclTaskMetaData { | 372 | typedef struct HcclTaskMetaData { |
| 342 | HccLTaskMetaType taskType; | 373 | HccLTaskMetaType taskType; |
| 374 | + HcclTaskProfInfo profInfo; // 整体3字节, checker/runner不使用 | ||
| 343 | uint64_t commId; | 375 | uint64_t commId; |
| 344 | uint32_t rankId; | 376 | uint32_t rankId; |
| 345 | uint64_t deviceId; | 377 | uint64_t deviceId; |
| 346 | uint64_t streamId; | 378 | uint64_t streamId; |
| 347 | uint32_t jettyId; | 379 | uint32_t jettyId; |
| 380 | + uint8_t sqeGroupId; // 多wqe分组标记,环形递增1~255(0=未打标) | ||
| 381 | + uint8_t taskSrc; | ||
| 348 | uint8_t rmEid[16]; | 382 | uint8_t rmEid[16]; |
| 383 | + uint8_t lcEid[16]; | ||
| 349 | union { | 384 | union { |
| 350 | TransMemTask transMem; | 385 | TransMemTask transMem; |
| 351 | ReduceTask reduce; | 386 | ReduceTask reduce; |
| @@ -354,27 +389,37 @@ typedef struct HcclTaskMetaData { | |||
| 354 | AivTask aiv; | 389 | AivTask aiv; |
| 355 | SyncStreamTask syncStreamTask; | 390 | SyncStreamTask syncStreamTask; |
| 356 | ModelExecTask modelExec; | 391 | ModelExecTask modelExec; |
| 392 | + WriteWithNotifyTask writeWithNotify; | ||
| 357 | } taskData; | 393 | } taskData; |
| 358 | 394 | ||
| 359 | HcclTaskMetaData() | 395 | HcclTaskMetaData() |
| 360 | { | 396 | { |
| 361 | taskType = HccLTaskMetaType::INVALID; | 397 | taskType = HccLTaskMetaType::INVALID; |
| 398 | + profInfo = HcclTaskProfInfo(); | ||
| 362 | commId = 0; | 399 | commId = 0; |
| 363 | rankId = UINT32_MAX; | 400 | rankId = UINT32_MAX; |
| 364 | deviceId = UINT64_MAX; | 401 | deviceId = UINT64_MAX; |
| 365 | streamId = UINT64_MAX; | 402 | streamId = UINT64_MAX; |
| 366 | jettyId = UINT32_MAX; | 403 | jettyId = UINT32_MAX; |
| 404 | + sqeGroupId = 0; | ||
| 405 | + taskSrc = TASK_SRC_DEFAULT; | ||
| 367 | memset(rmEid, 0, sizeof(rmEid)); | 406 | memset(rmEid, 0, sizeof(rmEid)); |
| 407 | + memset(lcEid, 0, sizeof(lcEid)); | ||
| 368 | memset(&taskData, 0, sizeof(taskData)); | 408 | memset(&taskData, 0, sizeof(taskData)); |
| 369 | } | 409 | } |
| 370 | 410 | ||
| 371 | std::string TaskTypeName() const | 411 | std::string TaskTypeName() const |
| 372 | { | 412 | { |
| 373 | static const std::map<HccLTaskMetaType, std::string> TASK_NAMES{ | 413 | static const std::map<HccLTaskMetaType, std::string> TASK_NAMES{ |
| 374 | - {HccLTaskMetaType::NOTIFY_WAIT, "NOTIFY_WAIT"}, {HccLTaskMetaType::NOTIFY_RECORD, "NOTIFY_RECORD"}, | 414 | + {HccLTaskMetaType::NOTIFY_WAIT, "NOTIFY_WAIT"}, |
| 375 | - {HccLTaskMetaType::REDUCE, "REDUCE"}, {HccLTaskMetaType::MEM_CPY, "MEM_CPY"}, | 415 | + {HccLTaskMetaType::NOTIFY_RECORD, "NOTIFY_RECORD"}, |
| 376 | - {HccLTaskMetaType::CCU_GRAPH, "CCU_GRAPH"}, {HccLTaskMetaType::AIV_GRAPH, "AIV_GRAPH"}, | 416 | + {HccLTaskMetaType::REDUCE, "REDUCE"}, |
| 377 | - {HccLTaskMetaType::SYNC_STREAM, "SYNC_STREAM"}, {HccLTaskMetaType::MODEL_EXEC, "MODEL_EXEC"}, | 417 | + {HccLTaskMetaType::MEM_CPY, "MEM_CPY"}, |
| 418 | + {HccLTaskMetaType::CCU_GRAPH, "CCU_GRAPH"}, | ||
| 419 | + {HccLTaskMetaType::AIV_GRAPH, "AIV_GRAPH"}, | ||
| 420 | + {HccLTaskMetaType::SYNC_STREAM, "SYNC_STREAM"}, | ||
| 421 | + {HccLTaskMetaType::MODEL_EXEC, "MODEL_EXEC"}, | ||
| 422 | + {HccLTaskMetaType::WRITE_WITH_NOTIFY, "WRITE_WITH_NOTIFY"}, | ||
| 378 | }; | 423 | }; |
| 379 | auto it = TASK_NAMES.find(taskType); | 424 | auto it = TASK_NAMES.find(taskType); |
| 380 | return it != TASK_NAMES.end() ? it->second : "INVALID"; | 425 | return it != TASK_NAMES.end() ? it->second : "INVALID"; |
| @@ -383,8 +428,8 @@ typedef struct HcclTaskMetaData { | |||
| 383 | std::string Describe() const | 428 | std::string Describe() const |
| 384 | { | 429 | { |
| 385 | std::ostringstream oss; | 430 | std::ostringstream oss; |
| 386 | - oss << "taskType=" << TaskTypeName() << " commId=" << commId << " rankId=" << rankId << " deviceId=" << deviceId | 431 | + oss << "taskType=" << TaskTypeName() << " " << profInfo.Describe() << " commId=" << commId |
| 387 | - << " streamId=" << streamId << " jettyId=" << jettyId; | 432 | + << " rankId=" << rankId << " deviceId=" << deviceId << " streamId=" << streamId << " jettyId=" << jettyId; |
| 388 | switch (taskType) { | 433 | switch (taskType) { |
| 389 | case HccLTaskMetaType::NOTIFY_WAIT: | 434 | case HccLTaskMetaType::NOTIFY_WAIT: |
| 390 | case HccLTaskMetaType::NOTIFY_RECORD: | 435 | case HccLTaskMetaType::NOTIFY_RECORD: |
| @@ -407,6 +452,8 @@ typedef struct HcclTaskMetaData { | |||
| 407 | break; | 452 | break; |
| 408 | case HccLTaskMetaType::MODEL_EXEC: | 453 | case HccLTaskMetaType::MODEL_EXEC: |
| 409 | oss << " taskData={" << taskData.modelExec.Describe() << "}"; | 454 | oss << " taskData={" << taskData.modelExec.Describe() << "}"; |
| 455 | + case HccLTaskMetaType::WRITE_WITH_NOTIFY: | ||
| 456 | + oss << " taskData={" << taskData.writeWithNotify.Describe() << "}"; | ||
| 410 | break; | 457 | break; |
| 411 | default: | 458 | default: |
| 412 | break; | 459 | break; |
| @@ -427,6 +474,40 @@ typedef struct { | |||
| 427 | 474 | ||
| 428 | #pragma pack(pop) | 475 | #pragma pack(pop) |
| 429 | 476 | ||
| 477 | +// WRITE_WITH_NOTIFY 复合任务展开: 拆为 [写子任务(MEM_CPY/REDUCE), NOTIFY_RECORD] 两个子任务, | ||
| 478 | +inline void SplitWriteWithNotify(const HcclTaskMetaData& task, HcclTaskMetaData& outWrite, HcclTaskMetaData& outNotify) | ||
| 479 | +{ | ||
| 480 | + const WriteWithNotifyTask& wn = task.taskData.writeWithNotify; | ||
| 481 | + outWrite = task; | ||
| 482 | + outNotify = task; | ||
| 483 | + if (wn.isReduce == 1) { | ||
| 484 | + outWrite.taskType = HccLTaskMetaType::REDUCE; | ||
| 485 | + outWrite.taskData.reduce.srcDeviceId = wn.srcDeviceId; | ||
| 486 | + outWrite.taskData.reduce.srcOffset = wn.srcOffset; | ||
| 487 | + outWrite.taskData.reduce.dstDeviceId = wn.dstDeviceId; | ||
| 488 | + outWrite.taskData.reduce.dstOffset = wn.dstOffset; | ||
| 489 | + outWrite.taskData.reduce.dataCount = wn.len; | ||
| 490 | + outWrite.taskData.reduce.dataType = wn.dataType; | ||
| 491 | + outWrite.taskData.reduce.reduceOp = wn.reduceOp; | ||
| 492 | + outWrite.taskData.reduce.protocol = wn.protocol; | ||
| 493 | + outWrite.taskData.reduce.resv = 0; | ||
| 494 | + } else { | ||
| 495 | + outWrite.taskType = HccLTaskMetaType::MEM_CPY; | ||
| 496 | + outWrite.taskData.transMem.srcDeviceId = wn.srcDeviceId; | ||
| 497 | + outWrite.taskData.transMem.srcOffset = wn.srcOffset; | ||
| 498 | + outWrite.taskData.transMem.dstDeviceId = wn.dstDeviceId; | ||
| 499 | + outWrite.taskData.transMem.dstOffset = wn.dstOffset; | ||
| 500 | + outWrite.taskData.transMem.len = wn.len; | ||
| 501 | + outWrite.taskData.transMem.protocol = wn.protocol; | ||
| 502 | + } | ||
| 503 | + outNotify.taskType = HccLTaskMetaType::NOTIFY_RECORD; | ||
| 504 | + outNotify.taskData.notify.srcDeviceId = wn.srcDeviceId; | ||
| 505 | + outNotify.taskData.notify.notifyId = wn.notifyId; | ||
| 506 | + outNotify.taskData.notify.dstDeviceId = wn.dstDeviceId; | ||
| 507 | + outNotify.taskData.notify.notifyCount = wn.notifyCount; | ||
| 508 | + outNotify.taskData.notify.protocol = wn.protocol; | ||
| 509 | +} | ||
| 510 | + | ||
| 430 | enum BufferType { INPUT = 0, OUTPUT, CCL, RESERVED }; | 511 | enum BufferType { INPUT = 0, OUTPUT, CCL, RESERVED }; |
| 431 | 512 | ||
| 432 | class DataSlice { | 513 | class DataSlice { |
| @@ -0,0 +1,167 @@ | |||
| 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 | +/** | ||
| 12 | + * AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 13 | + * for the full text of the License. | ||
| 14 | + */ | ||
| 15 | + | ||
| 16 | +#ifndef SIM_PROFILING_DEFS_H | ||
| 17 | +#define SIM_PROFILING_DEFS_H | ||
| 18 | + | ||
| 19 | +#include <cstdint> | ||
| 20 | +#include <map> | ||
| 21 | +#include <sstream> | ||
| 22 | +#include <string> | ||
| 23 | + | ||
| 24 | +// profiling 任务类型: 与 hcomm TaskParamType(值域 0~22) | ||
| 25 | +enum class ProfTaskParamType : uint8_t { | ||
| 26 | + TASK_SDMA = 0, // profiling op 名: Memcpy | ||
| 27 | + TASK_RDMA, // RDMASend | ||
| 28 | + TASK_REDUCE_INLINE, // Reduce_Inline | ||
| 29 | + TASK_REDUCE_TBE, // Reduce_TBE | ||
| 30 | + TASK_NOTIFY_RECORD, // Notify_Record | ||
| 31 | + TASK_NOTIFY_WAIT, // Notify_Wait | ||
| 32 | + TASK_SEND_NOTIFY, // Send_Notify | ||
| 33 | + TASK_SEND_PAYLOAD, // Send_Payload | ||
| 34 | + TASK_WRITE_WITH_NOTIFY, // Write_With_Notify | ||
| 35 | + TASK_WRITE_REDUCE_WITH_NOTIFY, // Reduce_With_Notify | ||
| 36 | + TASK_CCU, // Ccu | ||
| 37 | + TASK_AICPU_KERNEL, // AicpuKernel | ||
| 38 | + TASK_AICPU_REDUCE, // Aicpu_Reduce | ||
| 39 | + TASK_AIV, // AivKernel | ||
| 40 | + TASK_UB_INLINE_WRITE, // Ub_Inline_Write | ||
| 41 | + TASK_UB_REDUCE_INLINE, // Ub_Reduce_Inline | ||
| 42 | + TASK_UB, // Ub_Write_Or_Read | ||
| 43 | + TASK_DPU_KERNEL, // DpuKernel | ||
| 44 | + TASK_DPU_THREAD_FENCE, // Dpu_ThreadFence | ||
| 45 | + TASK_DPU_CHANNEL_FENCE, // Dpu_ChannelFence | ||
| 46 | + TASK_DPU_INLINE_WRITE, // Dpu_Notify_Record | ||
| 47 | + TASK_DPU_NOTIFY_WAIT, // Dpu_Notify_Wait | ||
| 48 | + TASK_DPU_WRITE_WITH_NOTIFY, // Dpu_Write_With_Notify | ||
| 49 | + UNKNOWN = 0xFF | ||
| 50 | +}; | ||
| 51 | + | ||
| 52 | +// profiling 链路类型: 与 hcomm DfxLinkType(值域 0~9) | ||
| 53 | +enum class ProfLinkType : uint8_t { | ||
| 54 | + LINK_ONCHIP = 0, // 片上/本地 | ||
| 55 | + LINK_HCCS = 1, // HCCS | ||
| 56 | + LINK_PCIE = 2, // PCIe(跨片 SDMA 通道) | ||
| 57 | + LINK_ROCE = 3, // RoCE | ||
| 58 | + LINK_SIO = 4, // SIO | ||
| 59 | + LINK_HCCS_SW = 5, // HCCS_SW | ||
| 60 | + LINK_STANDARD_ROCE = 6, // 标准RoCE | ||
| 61 | + LINK_UB = 7, // UB | ||
| 62 | + LINK_UBoE = 8, // UB over Ethernet | ||
| 63 | + LINK_RESERVED = 9, // 预留 | ||
| 64 | + UNKNOWN = 0xFF | ||
| 65 | +}; | ||
| 66 | + | ||
| 67 | +// profiling 传输类型: 与 hcomm DfxTransportType/SimpleTaskType(值域 0~4) | ||
| 68 | +enum class ProfTransportType : uint8_t { | ||
| 69 | + TRANSPORT_SDMA = 0, // 跨片 SDMA 通道搬运 | ||
| 70 | + TRANSPORT_RDMA = 1, // RDMA | ||
| 71 | + TRANSPORT_LOCAL = 2, // 本地搬运/本地算子 | ||
| 72 | + TRANSPORT_UB = 3, // UB 传输 | ||
| 73 | + TRANSPORT_ROCE = 4, // RoCE 传输 | ||
| 74 | + UNKNOWN = 0xFF | ||
| 75 | +}; | ||
| 76 | + | ||
| 77 | +// 名称与 hcomm PROF_TASK_OP_NAME_V2(profiling_common.h)一致 | ||
| 78 | +inline std::string ProfTaskParamTypeName(ProfTaskParamType type) | ||
| 79 | +{ | ||
| 80 | + static const std::map<ProfTaskParamType, std::string> PROF_TASK_NAMES{ | ||
| 81 | + {ProfTaskParamType::TASK_SDMA, "Memcpy"}, | ||
| 82 | + {ProfTaskParamType::TASK_RDMA, "RDMASend"}, | ||
| 83 | + {ProfTaskParamType::TASK_REDUCE_INLINE, "Reduce_Inline"}, | ||
| 84 | + {ProfTaskParamType::TASK_REDUCE_TBE, "Reduce_TBE"}, | ||
| 85 | + {ProfTaskParamType::TASK_NOTIFY_RECORD, "Notify_Record"}, | ||
| 86 | + {ProfTaskParamType::TASK_NOTIFY_WAIT, "Notify_Wait"}, | ||
| 87 | + {ProfTaskParamType::TASK_SEND_NOTIFY, "Send_Notify"}, | ||
| 88 | + {ProfTaskParamType::TASK_SEND_PAYLOAD, "Send_Payload"}, | ||
| 89 | + {ProfTaskParamType::TASK_WRITE_WITH_NOTIFY, "Write_With_Notify"}, | ||
| 90 | + {ProfTaskParamType::TASK_WRITE_REDUCE_WITH_NOTIFY, "Reduce_With_Notify"}, | ||
| 91 | + {ProfTaskParamType::TASK_CCU, "Ccu"}, | ||
| 92 | + {ProfTaskParamType::TASK_AICPU_KERNEL, "AicpuKernel"}, | ||
| 93 | + {ProfTaskParamType::TASK_AICPU_REDUCE, "Aicpu_Reduce"}, | ||
| 94 | + {ProfTaskParamType::TASK_AIV, "AivKernel"}, | ||
| 95 | + {ProfTaskParamType::TASK_UB_INLINE_WRITE, "Ub_Inline_Write"}, | ||
| 96 | + {ProfTaskParamType::TASK_UB_REDUCE_INLINE, "Ub_Reduce_Inline"}, | ||
| 97 | + {ProfTaskParamType::TASK_UB, "Ub_Write_Or_Read"}, | ||
| 98 | + {ProfTaskParamType::TASK_DPU_KERNEL, "DpuKernel"}, | ||
| 99 | + {ProfTaskParamType::TASK_DPU_THREAD_FENCE, "Dpu_ThreadFence"}, | ||
| 100 | + {ProfTaskParamType::TASK_DPU_CHANNEL_FENCE, "Dpu_ChannelFence"}, | ||
| 101 | + {ProfTaskParamType::TASK_DPU_INLINE_WRITE, "Dpu_Notify_Record"}, | ||
| 102 | + {ProfTaskParamType::TASK_DPU_NOTIFY_WAIT, "Dpu_Notify_Wait"}, | ||
| 103 | + {ProfTaskParamType::TASK_DPU_WRITE_WITH_NOTIFY, "Dpu_Write_With_Notify"}, | ||
| 104 | + }; | ||
| 105 | + auto it = PROF_TASK_NAMES.find(type); | ||
| 106 | + return it != PROF_TASK_NAMES.end() ? it->second : "Unknown"; | ||
| 107 | +} | ||
| 108 | + | ||
| 109 | +// 名称对应 hcomm DfxLinkType 枚举名 | ||
| 110 | +inline std::string ProfLinkTypeName(ProfLinkType type) | ||
| 111 | +{ | ||
| 112 | + static const std::map<ProfLinkType, std::string> PROF_LINK_NAMES{ | ||
| 113 | + {ProfLinkType::LINK_ONCHIP, "ONCHIP"}, | ||
| 114 | + {ProfLinkType::LINK_HCCS, "HCCS"}, | ||
| 115 | + {ProfLinkType::LINK_PCIE, "PCIE"}, | ||
| 116 | + {ProfLinkType::LINK_ROCE, "ROCE"}, | ||
| 117 | + {ProfLinkType::LINK_SIO, "SIO"}, | ||
| 118 | + {ProfLinkType::LINK_HCCS_SW, "HCCS_SW"}, | ||
| 119 | + {ProfLinkType::LINK_STANDARD_ROCE, "STANDARD_ROCE"}, | ||
| 120 | + {ProfLinkType::LINK_UB, "UB"}, | ||
| 121 | + {ProfLinkType::LINK_UBoE, "UBoE"}, | ||
| 122 | + {ProfLinkType::LINK_RESERVED, "RESERVED"}, | ||
| 123 | + }; | ||
| 124 | + auto it = PROF_LINK_NAMES.find(type); | ||
| 125 | + return it != PROF_LINK_NAMES.end() ? it->second : "Unknown"; | ||
| 126 | +} | ||
| 127 | + | ||
| 128 | +// 名称对应 hcomm DfxTransportType/SimpleTaskType 枚举名 | ||
| 129 | +inline std::string ProfTransportTypeName(ProfTransportType type) | ||
| 130 | +{ | ||
| 131 | + static const std::map<ProfTransportType, std::string> PROF_TRANSPORT_NAMES{ | ||
| 132 | + {ProfTransportType::TRANSPORT_SDMA, "SDMA"}, {ProfTransportType::TRANSPORT_RDMA, "RDMA"}, | ||
| 133 | + {ProfTransportType::TRANSPORT_LOCAL, "LOCAL"}, {ProfTransportType::TRANSPORT_UB, "UB"}, | ||
| 134 | + {ProfTransportType::TRANSPORT_ROCE, "ROCE"}, | ||
| 135 | + }; | ||
| 136 | + auto it = PROF_TRANSPORT_NAMES.find(type); | ||
| 137 | + return it != PROF_TRANSPORT_NAMES.end() ? it->second : "Unknown"; | ||
| 138 | +} | ||
| 139 | + | ||
| 140 | +// 任务 profiling 信息: 值域对齐 hcomm TaskParamType/DfxLinkType/DfxTransportType | ||
| 141 | +struct HcclTaskProfInfo { | ||
| 142 | + ProfTaskParamType profTaskType; // profiling 类型 | ||
| 143 | + ProfLinkType linkType; // 物理链路类型 | ||
| 144 | + ProfTransportType transportType; // 数据面传输方式 | ||
| 145 | + | ||
| 146 | + HcclTaskProfInfo() | ||
| 147 | + : profTaskType(ProfTaskParamType::UNKNOWN), | ||
| 148 | + linkType(ProfLinkType::UNKNOWN), | ||
| 149 | + transportType(ProfTransportType::UNKNOWN) | ||
| 150 | + {} | ||
| 151 | + | ||
| 152 | + HcclTaskProfInfo(ProfTaskParamType taskType, ProfLinkType link, ProfTransportType transport) | ||
| 153 | + : profTaskType(taskType), | ||
| 154 | + linkType(link), | ||
| 155 | + transportType(transport) | ||
| 156 | + {} | ||
| 157 | + | ||
| 158 | + std::string Describe() const | ||
| 159 | + { | ||
| 160 | + std::ostringstream oss; | ||
| 161 | + oss << "profTaskType=" << ProfTaskParamTypeName(profTaskType) << " linkType=" << ProfLinkTypeName(linkType) | ||
| 162 | + << " transportType=" << ProfTransportTypeName(transportType); | ||
| 163 | + return oss.str(); | ||
| 164 | + } | ||
| 165 | +}; | ||
| 166 | + | ||
| 167 | +#endif // SIM_PROFILING_DEFS_H | ||
| @@ -109,7 +109,6 @@ private: | |||
| 109 | 109 | ||
| 110 | std::mutex m_mutex; | 110 | std::mutex m_mutex; |
| 111 | std::vector<void*> m_pages; | 111 | std::vector<void*> m_pages; |
| 112 | - BatchCache m_batchCache; | ||
| 113 | }; | 112 | }; |
| 114 | 113 | ||
| 115 | } // namespace sim | 114 | } // namespace sim |
| @@ -11,12 +11,42 @@ | |||
| 11 | #ifndef STORE_SIM_RUN_MODE_H | 11 | #ifndef STORE_SIM_RUN_MODE_H |
| 12 | #define STORE_SIM_RUN_MODE_H | 12 | #define STORE_SIM_RUN_MODE_H |
| 13 | 13 | ||
| 14 | +#include <cstdint> | ||
| 15 | +#include <string> | ||
| 16 | + | ||
| 14 | namespace sim { | 17 | namespace sim { |
| 18 | +// RunModeConfig.mode 的互斥三态取值 | ||
| 19 | +enum RunModeValue : uint8_t { | ||
| 20 | + RUN_MODE_NORMAL = 0, | ||
| 21 | + RUN_MODE_CHECK_ONLY = 1, | ||
| 22 | + RUN_MODE_ESTIMATE = 2, | ||
| 23 | +}; | ||
| 24 | + | ||
| 15 | // 读 DB 的 RunModeConfig,返回是否仅校验模式,不缓存。表为空返回 false。 | 25 | // 读 DB 的 RunModeConfig,返回是否仅校验模式,不缓存。表为空返回 false。 |
| 16 | bool ProbeCheckOnlyMode(); | 26 | bool ProbeCheckOnlyMode(); |
| 17 | 27 | ||
| 18 | // 进程内只读一次并缓存结果。 | 28 | // 进程内只读一次并缓存结果。 |
| 19 | bool IsCheckOnlyMode(); | 29 | bool IsCheckOnlyMode(); |
| 30 | + | ||
| 31 | +// 读 DB 的 RunModeConfig,返回是否评估模式,不缓存。表为空返回 false。 | ||
| 32 | +bool ProbeEstimateMode(); | ||
| 33 | + | ||
| 34 | +// 进程内只读一次并缓存结果。惰性求值:首次调用发生在算子执行期, | ||
| 35 | +// 此时 cmd 层已写入 RunModeConfig,避免了 .so 加载期读空表。 | ||
| 36 | +bool IsEstimateMode(); | ||
| 37 | + | ||
| 38 | +// 重置模式缓存,供 mode 命令切换后刷新。 | ||
| 39 | +void ResetRunModeCache(); | ||
| 40 | + | ||
| 41 | +// mode 值到日志可读名的映射:normal / check-only / estimate。 | ||
| 42 | +const char* ModeName(uint8_t mode); | ||
| 43 | + | ||
| 44 | +// mode 值到子 bash 提示符的单一映射,保证各进程显示一致。 | ||
| 45 | +// 0 -> "(hvm)$> ",1 -> "(chk-only)$> ",2 -> "(estimate)$> ",未知值回退 "(hvm)$> "。 | ||
| 46 | +std::string GetRunModePrompt(uint8_t mode); | ||
| 47 | + | ||
| 48 | +// 读 DB 的 RunModeConfig 后映射提示符。供 checker 等无法访问 cmd 层全局的进程使用。 | ||
| 49 | +std::string GetRunModePrompt(); | ||
| 20 | } // namespace sim | 50 | } // namespace sim |
| 21 | 51 | ||
| 22 | #endif // STORE_SIM_RUN_MODE_H | 52 | #endif // STORE_SIM_RUN_MODE_H |
| @@ -78,13 +78,13 @@ pre-commit run --files path/to/file1.cc path/to/file2.h | |||
| 78 | 78 | ||
| 79 | ```bash | 79 | ```bash |
| 80 | # 检查指定文件 | 80 | # 检查指定文件 |
| 81 | -./pre-commit_check.sh path/to/file1.cc path/to/file2.h | 81 | +bash ./pre-commit_check.sh path/to/file1.cc path/to/file2.h |
| 82 | 82 | ||
| 83 | # 检查 git 中已修改的文件(最常用,--modified 或 -modified 均可) | 83 | # 检查 git 中已修改的文件(最常用,--modified 或 -modified 均可) |
| 84 | -./pre-commit_check.sh --modified | 84 | +bash ./pre-commit_check.sh --modified |
| 85 | 85 | ||
| 86 | # 检查仓库所有 C/C++ 文件(--all 或 -all 均可) | 86 | # 检查仓库所有 C/C++ 文件(--all 或 -all 均可) |
| 87 | -./pre-commit_check.sh --all | 87 | +bash ./pre-commit_check.sh --all |
| 88 | ``` | 88 | ``` |
| 89 | 89 | ||
| 90 | **输出示例:** | 90 | **输出示例:** |
| @@ -78,13 +78,13 @@ pre-commit run --files path/to/file1.cc path/to/file2.h | |||
| 78 | 78 | ||
| 79 | ```bash | 79 | ```bash |
| 80 | # 检查指定文件 | 80 | # 检查指定文件 |
| 81 | -./pre-commit_check.sh path/to/file1.cc path/to/file2.h | 81 | +bash ./pre-commit_check.sh path/to/file1.cc path/to/file2.h |
| 82 | 82 | ||
| 83 | # 检查 git 中已修改的文件(最常用,--modified 或 -modified 均可) | 83 | # 检查 git 中已修改的文件(最常用,--modified 或 -modified 均可) |
| 84 | -./pre-commit_check.sh --modified | 84 | +bash ./pre-commit_check.sh --modified |
| 85 | 85 | ||
| 86 | # 检查仓库所有 C/C++ 文件(--all 或 -all 均可) | 86 | # 检查仓库所有 C/C++ 文件(--all 或 -all 均可) |
| 87 | -./pre-commit_check.sh --all | 87 | +bash ./pre-commit_check.sh --all |
| 88 | ``` | 88 | ``` |
| 89 | 89 | ||
| 90 | **输出示例:** | 90 | **输出示例:** |
| @@ -0,0 +1,77 @@ | |||
| 1 | +#!/usr/bin/env python3 | ||
| 2 | +# -*- coding: UTF-8 -*- | ||
| 3 | +# ----------------------------------------------------------------------------------------------------------- | ||
| 4 | +# Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 5 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 6 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 7 | +# Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 8 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 9 | +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 10 | +# See LICENSE in the root of the software repository for the full text of the License. | ||
| 11 | +# ----------------------------------------------------------------------------------------------------------- | ||
| 12 | + | ||
| 13 | +"""light_performance 一键性能仿真入口: db → 任务图 → 仿真 → perf_profiling.json。 | ||
| 14 | + | ||
| 15 | +pipeline 实现收编于 light_performance/pipeline.py, 与安装树 @estimate 插件入口 | ||
| 16 | +(light_performance/main.py, 由 `hccl-vm plugin run @estimate` 触发) 共用同一 | ||
| 17 | +实现 (设计文档 3.1 节); 本脚本仅为源码树手动调试的 CLI 包装。 | ||
| 18 | + | ||
| 19 | +用法 (仓库根目录执行): | ||
| 20 | + python3 run_perf_sim.py hccl_vm_install/data/hccl_vm_data.db | ||
| 21 | + python3 run_perf_sim.py <db> -o perf.json --config src/plugin/light_performance/sim_config.json | ||
| 22 | + python3 run_perf_sim.py <db> --device 1 --iter 0 --trace-dir trace/ --dump-dir graph_dump/ | ||
| 23 | + | ||
| 24 | +说明: | ||
| 25 | + - ranktable.json 缺省取 db 同目录 (eid→端口解析, 走网任务必需); | ||
| 26 | + 缺失时该算子跳过仿真 (不产生 trace 事件), 仅输出任务图 dump。 | ||
| 27 | + - --dump-dir 额外输出任务图 (DOT/JSON/HTML); --trace-dir 额外输出单算子 | ||
| 28 | + Chrome tracing 文件 (每算子一个, 格式同 perf_profiling.json)。 | ||
| 29 | +""" | ||
| 30 | + | ||
| 31 | +from __future__ import annotations | ||
| 32 | + | ||
| 33 | +import argparse | ||
| 34 | +import os | ||
| 35 | +import sys | ||
| 36 | + | ||
| 37 | +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), | ||
| 38 | + "src", "plugin")) | ||
| 39 | + | ||
| 40 | +from light_performance.pipeline import run_perf_pipeline | ||
| 41 | + | ||
| 42 | + | ||
| 43 | +def main(): | ||
| 44 | + parser = argparse.ArgumentParser( | ||
| 45 | + description="light_performance 一键仿真: db → 任务图 → 仿真 → " | ||
| 46 | + "perf_profiling.json (Chrome tracing 格式, 设计文档 1.1 节)") | ||
| 47 | + parser.add_argument("db", help="hccl_vm_data.db 路径") | ||
| 48 | + parser.add_argument("-o", "--out", default="perf_profiling.json", | ||
| 49 | + help="输出 json 路径 (默认 perf_profiling.json)") | ||
| 50 | + parser.add_argument("--config", help="时延/带宽配置 JSON (单位 us/GBps)") | ||
| 51 | + parser.add_argument("--bw-profile", help="带宽利用率配置 JSON") | ||
| 52 | + parser.add_argument("--ranktable", | ||
| 53 | + help="ranktable.json (默认取 db 同目录)") | ||
| 54 | + parser.add_argument("--device", type=int, default=None, | ||
| 55 | + help="目标 deviceId (默认取 opDetails 首个设备)") | ||
| 56 | + parser.add_argument("--iter", type=int, default=None, | ||
| 57 | + help="仅仿真指定 opIter (默认全部)") | ||
| 58 | + parser.add_argument("--trace-dir", metavar="DIR", | ||
| 59 | + help="额外输出单算子 Chrome tracing (每算子一个文件)") | ||
| 60 | + parser.add_argument("--dump-dir", metavar="DIR", | ||
| 61 | + help="额外输出任务图 dump (DOT/JSON, 每算子)") | ||
| 62 | + args = parser.parse_args() | ||
| 63 | + | ||
| 64 | + return run_perf_pipeline( | ||
| 65 | + args.db, args.out, | ||
| 66 | + config_path=args.config, | ||
| 67 | + bw_profile_path=args.bw_profile, | ||
| 68 | + ranktable_path=args.ranktable, | ||
| 69 | + device=args.device, | ||
| 70 | + iter_filter=args.iter, | ||
| 71 | + trace_dir=args.trace_dir, | ||
| 72 | + dump_dir=args.dump_dir, | ||
| 73 | + ) | ||
| 74 | + | ||
| 75 | + | ||
| 76 | +if __name__ == "__main__": | ||
| 77 | + sys.exit(main()) | ||