已合并
统一样例 #173
wanghan创建于 9月12日
统一样例 #173
已合并
共 75 个文件变更+3240-3799
| @@ -112,7 +112,7 @@ docs/zh/guide/ ──首次引入API──→ docs/zh/api/README.md | |||
| 112 | ──涉及样例────→ examples/README.md | 112 | ──涉及样例────→ examples/README.md |
| 113 | 113 | ||
| 114 | docs/zh/api/ ───使用流程──→ docs/zh/guide/hcomm_usage.md | 114 | docs/zh/api/ ───使用流程──→ docs/zh/guide/hcomm_usage.md |
| 115 | - ───调用示例──→ examples/hcomm_write_read_nbi/README.md | 115 | + ───调用示例──→ examples/aicore/hcomm/01_hcomm_write_read_nbi/README.md |
| 116 | ``` | 116 | ``` |
| 117 | 117 | ||
| 118 | ## 更多信息 | 118 | ## 更多信息 |
| @@ -112,7 +112,7 @@ docs/en/guide/ ──First API reference──→ docs/en/api/README.md | |||
| 112 | ──Sample reference──→ examples/README_en.md | 112 | ──Sample reference──→ examples/README_en.md |
| 113 | 113 | ||
| 114 | docs/en/api/ ──Usage workflow──→ docs/en/guide/hcomm_usage.md | 114 | docs/en/api/ ──Usage workflow──→ docs/en/guide/hcomm_usage.md |
| 115 | - ──Invocation sample──→ examples/hcomm_write_read_nbi/README_en.md | 115 | + ──Invocation sample──→ examples/aicore/hcomm/01_hcomm_write_read_nbi/README_en.md |
| 116 | ``` | 116 | ``` |
| 117 | 117 | ||
| 118 | ## More Information | 118 | ## More Information |
| @@ -69,5 +69,5 @@ AICore side: | |||
| 69 | ## Related Documents | 69 | ## Related Documents |
| 70 | 70 | ||
| 71 | - [Hcomm Usage Guide](../guide/hcomm_usage.md) | 71 | - [Hcomm Usage Guide](../guide/hcomm_usage.md) |
| 72 | -- [AIV Direct-driven URMA WriteNbi/ReadNbi Sample](../../../examples/hcomm_write_read_nbi/README_en.md) | 72 | +- [AIV Direct-driven URMA WriteNbi/ReadNbi Sample](../../../examples/aicore/hcomm/01_hcomm_write_read_nbi/README_en.md) |
| 73 | -- [Ain Basic Ring Sample](../../../examples/ain/basic_ring/README_en.md) | 73 | +- [Ain Basic Ring Sample](../../../examples/aicore/ain/01_basic_ring/README_en.md) |
| @@ -82,4 +82,4 @@ See [MakeMultiChannelHandle](../../host/hcomm/MakeMultiChannelHandle.md) for the | |||
| 82 | 82 | ||
| 83 | ## Related Sample | 83 | ## Related Sample |
| 84 | 84 | ||
| 85 | -[hcomm_write_read_nbi](../../../../../examples/hcomm_write_read_nbi/README_en.md) demonstrates ordinary `WriteNbi` and `ReadNbi` calls over the `COMM_PROTOCOL_UBC_CTP` path in a two-card scenario. It does not cover the RoCE or BatchHandle workflow. | 85 | +[hcomm_write_read_nbi](../../../../../examples/aicore/hcomm/01_hcomm_write_read_nbi/README_en.md) demonstrates ordinary `WriteNbi` and `ReadNbi` calls over the `COMM_PROTOCOL_UBC_CTP` path in a two-card scenario. It does not cover the RoCE or BatchHandle workflow. |
| @@ -73,6 +73,6 @@ __aicore__ inline int32_t ReadNbi( | |||
| 73 | 73 | ||
| 74 | ## Related Sample | 74 | ## Related Sample |
| 75 | 75 | ||
| 76 | -[hcomm_write_read_nbi](../../../../../examples/hcomm_write_read_nbi/README_en.md) demonstrates the ordinary AIV direct-driven URMA read/write workflow. See the [Hcomm Usage Guide](../../../guide/hcomm_usage.md) for the basic BatchHandle workflow. | 76 | +[hcomm_write_read_nbi](../../../../../examples/aicore/hcomm/01_hcomm_write_read_nbi/README_en.md) demonstrates the ordinary AIV direct-driven URMA read/write workflow. See the [Hcomm Usage Guide](../../../guide/hcomm_usage.md) for the basic BatchHandle workflow. |
| 77 | 77 | ||
| 78 | See [GetHandleRef](./GetHandleRef.md) for the multi-channel interface. | 78 | See [GetHandleRef](./GetHandleRef.md) for the multi-channel interface. |
| @@ -73,6 +73,6 @@ __aicore__ inline int32_t WriteNbi( | |||
| 73 | 73 | ||
| 74 | ## Related Sample | 74 | ## Related Sample |
| 75 | 75 | ||
| 76 | -[hcomm_write_read_nbi](../../../../../examples/hcomm_write_read_nbi/README_en.md) demonstrates the ordinary AIV direct-driven URMA read/write workflow. [hcomm_batch_write](../../../../../examples/hcomm_batch_write/README_en.md) demonstrates multi-channel batch writes. See the [Hcomm Usage Guide](../../../guide/hcomm_usage.md) for the basic BatchHandle workflow. | 76 | +[hcomm_write_read_nbi](../../../../../examples/aicore/hcomm/01_hcomm_write_read_nbi/README_en.md) demonstrates the ordinary AIV direct-driven URMA read/write workflow. [hcomm_batch_write](../../../../../examples/aicore/hcomm/02_hcomm_batch_write/README_en.md) demonstrates multi-channel batch writes. See the [Hcomm Usage Guide](../../../guide/hcomm_usage.md) for the basic BatchHandle workflow. |
| 77 | 77 | ||
| 78 | See [GetHandleRef](./GetHandleRef.md) for the multi-channel interface. | 78 | See [GetHandleRef](./GetHandleRef.md) for the multi-channel interface. |
| @@ -201,11 +201,11 @@ bash build.sh -t --cann_3rd_lib_path=<path-to-third-party> | |||
| 201 | 201 | ||
| 202 | ## Build and Run Samples | 202 | ## Build and Run Samples |
| 203 | 203 | ||
| 204 | -`examples/hcomm_write_read_nbi` provides a point-to-point communication sample using AIV direct-driven URMA `WriteNbi` and `ReadNbi`. This sample adopts an independent CMake project for building: | 204 | +`examples/aicore/hcomm/01_hcomm_write_read_nbi` provides a point-to-point communication sample using AIV direct-driven URMA `WriteNbi` and `ReadNbi`. This sample adopts an independent CMake project for building: |
| 205 | 205 | ||
| 206 | ```bash | 206 | ```bash |
| 207 | source /usr/local/Ascend/cann/set_env.sh | 207 | source /usr/local/Ascend/cann/set_env.sh |
| 208 | -cd examples/hcomm_write_read_nbi | 208 | +cd examples/aicore/hcomm/01_hcomm_write_read_nbi |
| 209 | mkdir -p build | 209 | mkdir -p build |
| 210 | cd build | 210 | cd build |
| 211 | cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. | 211 | cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. |
| @@ -19,7 +19,7 @@ The in-repository build of asc-comm is mainly used for environment verification, | |||
| 19 | | Scenario | Dependency | Version | Acquisition & Configuration | | 19 | | Scenario | Dependency | Version | Acquisition & Configuration | |
| 20 | | --- | --- | --- | --- | | 20 | | --- | --- | --- | --- | |
| 21 | | UT | googletest | 1.14.0 | System GTest is preferred. If unavailable, point `CANN_3RD_LIB_PATH` to the CANN third_party directory. | | 21 | | UT | googletest | 1.14.0 | System GTest is preferred. If unavailable, point `CANN_3RD_LIB_PATH` to the CANN third_party directory. | |
| 22 | -| Samples | CANN ASC CMake utilities and hcomm library | CANN 9.1.0 or later | After running `source ${install_path}/cann/set_env.sh`, build via CMake under `examples/hcomm_write_read_nbi`. | | 22 | +| Samples | CANN ASC CMake utilities and hcomm library | CANN 9.1.0 or later | After running `source ${install_path}/cann/set_env.sh`, build via CMake under `examples/aicore/hcomm/01_hcomm_write_read_nbi`. | |
| 23 | | Code Formatting | clang-format | v18.1.8 | Pulled from `pre-commit-clang/mirrors-clang-format` defined in `pre-commit-config.yaml`. | | 23 | | Code Formatting | clang-format | v18.1.8 | Pulled from `pre-commit-clang/mirrors-clang-format` defined in `pre-commit-config.yaml`. | |
| 24 | | Open Source Compliance Check | oat-py | >= 1.0.1 | `scripts/oat_check.sh` attempts automatic installation. Run `pip install oat-py>=1.0.1` manually upon failure. | | 24 | | Open Source Compliance Check | oat-py | >= 1.0.1 | `scripts/oat_check.sh` attempts automatic installation. Run `pip install oat-py>=1.0.1` manually upon failure. | |
| 25 | 25 | ||
| @@ -27,14 +27,14 @@ The in-repository build of asc-comm is mainly used for environment verification, | |||
| 27 | 27 | ||
| 28 | ## Sample Runtime Dependencies | 28 | ## Sample Runtime Dependencies |
| 29 | 29 | ||
| 30 | -The `examples/hcomm_write_read_nbi` sample supports Ascend 950PR / Ascend 950DT and requires at least two NPUs for runtime. Compilation verification can be completed on single-NPU environments, whereas two-card point-to-point communication runtime verification is unavailable. | 30 | +The `examples/aicore/hcomm/01_hcomm_write_read_nbi` sample supports Ascend 950PR / Ascend 950DT and requires at least two NPUs for runtime. Compilation verification can be completed on single-NPU environments, whereas two-card point-to-point communication runtime verification is unavailable. |
| 31 | This sample uses `COMM_ENGINE_AIV` and `COMM_PROTOCOL_UBC_CTP` exclusively and does not cover the RoCE path. | 31 | This sample uses `COMM_ENGINE_AIV` and `COMM_PROTOCOL_UBC_CTP` exclusively and does not cover the RoCE path. |
| 32 | 32 | ||
| 33 | Sample build commands: | 33 | Sample build commands: |
| 34 | 34 | ||
| 35 | ```bash | 35 | ```bash |
| 36 | source /usr/local/Ascend/cann/set_env.sh | 36 | source /usr/local/Ascend/cann/set_env.sh |
| 37 | -cd examples/hcomm_write_read_nbi | 37 | +cd examples/aicore/hcomm/01_hcomm_write_read_nbi |
| 38 | mkdir -p build | 38 | mkdir -p build |
| 39 | cd build | 39 | cd build |
| 40 | cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. | 40 | cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. |
| @@ -184,6 +184,6 @@ The lock is not reentrant. Every successful `Lock` must be followed by `Unlock` | |||
| 184 | 184 | ||
| 185 | ## Samples | 185 | ## Samples |
| 186 | 186 | ||
| 187 | -See [hcomm_write_read_nbi](../../../examples/hcomm_write_read_nbi/README_en.md) for the ordinary AIV Kernel-side API workflow and Host-side communication resource creation. See [hcomm_batch_write](../../../examples/hcomm_batch_write/README_en.md) for the multi-channel batch write workflow. | 187 | +See [hcomm_write_read_nbi](../../../examples/aicore/hcomm/01_hcomm_write_read_nbi/README_en.md) for the ordinary AIV Kernel-side API workflow and Host-side communication resource creation. See [hcomm_batch_write](../../../examples/aicore/hcomm/02_hcomm_batch_write/README_en.md) for the multi-channel batch write workflow. |
| 188 | 188 | ||
| 189 | Both samples require Ascend 950PR/Ascend 950DT and at least two NPUs for runtime verification. A single-device environment supports compilation only. | 189 | Both samples require Ascend 950PR/Ascend 950DT and at least two NPUs for runtime verification. A single-device environment supports compilation only. |
| @@ -151,7 +151,7 @@ CANN包分为CANN toolkit包和CANN ops包。 | |||
| 151 | 151 | ||
| 152 | > [!IMPORTANT] | 152 | > [!IMPORTANT] |
| 153 | > 安装说明 | 153 | > 安装说明 |
| 154 | - > 当前[Hcomm AIV直驱URMA样例](../examples/hcomm_write_read_nbi/README.md)不依赖ops包;仅在后续使用依赖算子包的功能时按需安装。 | 154 | + > 当前[Hcomm AIV直驱URMA样例](../examples/aicore/hcomm/01_hcomm_write_read_nbi/README.md)不依赖ops包;仅在后续使用依赖算子包的功能时按需安装。 |
| 155 | 155 | ||
| 156 | | 参数 | 说明 | | 156 | | 参数 | 说明 | |
| 157 | | :--- | :-------------------------------- | | 157 | | :--- | :-------------------------------- | |
| @@ -264,13 +264,13 @@ cmake --build build/ut-hcomm | |||
| 264 | 264 | ||
| 265 | ### 🧩 样例验证<a name="sample-verify"></a> | 265 | ### 🧩 样例验证<a name="sample-verify"></a> |
| 266 | 266 | ||
| 267 | -[hcomm_write_read_nbi](../examples/hcomm_write_read_nbi/README.md)提供AIV直驱URMA `WriteNbi`和`ReadNbi`点对点通信样例。样例支持Ascend 950PR/Ascend 950DT,要求CANN 9.1.0或以上版本。运行样例需要至少2张NPU;单卡环境仅支持编译验证。 | 267 | +[hcomm_write_read_nbi](../examples/aicore/hcomm/01_hcomm_write_read_nbi/README.md)提供AIV直驱URMA `WriteNbi`和`ReadNbi`点对点通信样例。样例支持Ascend 950PR/Ascend 950DT,要求CANN 9.1.0或以上版本。运行样例需要至少2张NPU;单卡环境仅支持编译验证。 |
| 268 | 268 | ||
| 269 | 进入样例目录后执行: | 269 | 进入样例目录后执行: |
| 270 | 270 | ||
| 271 | ```bash | 271 | ```bash |
| 272 | source /usr/local/Ascend/cann/set_env.sh | 272 | source /usr/local/Ascend/cann/set_env.sh |
| 273 | -cd examples/hcomm_write_read_nbi | 273 | +cd examples/aicore/hcomm/01_hcomm_write_read_nbi |
| 274 | mkdir -p build | 274 | mkdir -p build |
| 275 | cd build | 275 | cd build |
| 276 | cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. | 276 | cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. |
| @@ -148,7 +148,7 @@ CANN packages include the CANN toolkit package and CANN ops package. | |||
| 148 | 148 | ||
| 149 | > [!IMPORTANT] | 149 | > [!IMPORTANT] |
| 150 | > Installation Note | 150 | > Installation Note |
| 151 | - > The [AIV direct-driven URMA Hcomm sample](../examples/hcomm_write_read_nbi/README_en.md) does not depend on the ops package. Install it later only when you require features relying on the operator package. | 151 | + > The [AIV direct-driven URMA Hcomm sample](../examples/aicore/hcomm/01_hcomm_write_read_nbi/README_en.md) does not depend on the ops package. Install it later only when you require features relying on the operator package. |
| 152 | 152 | ||
| 153 | | Parameter | Description | | 153 | | Parameter | Description | |
| 154 | | :--- | :-------------------------------- | | 154 | | :--- | :-------------------------------- | |
| @@ -261,14 +261,14 @@ Third-party open-source software used for UT execution: | |||
| 261 | 261 | ||
| 262 | ### 🧩 Sample Verification<a name="sample-verify"></a> | 262 | ### 🧩 Sample Verification<a name="sample-verify"></a> |
| 263 | 263 | ||
| 264 | -[hcomm_write_read_nbi](../examples/hcomm_write_read_nbi/README_en.md) provides a point-to-point communication sample using AIV direct-driven URMA `WriteNbi` and `ReadNbi`. | 264 | +[hcomm_write_read_nbi](../examples/aicore/hcomm/01_hcomm_write_read_nbi/README_en.md) provides a point-to-point communication sample using AIV direct-driven URMA `WriteNbi` and `ReadNbi`. |
| 265 | The sample supports Ascend 950PR / Ascend 950DT and requires CANN 9.1.0 or newer. At least two NPUs are required for runtime; single-NPU environments only support compilation verification. | 265 | The sample supports Ascend 950PR / Ascend 950DT and requires CANN 9.1.0 or newer. At least two NPUs are required for runtime; single-NPU environments only support compilation verification. |
| 266 | 266 | ||
| 267 | Navigate to the sample directory and run: | 267 | Navigate to the sample directory and run: |
| 268 | 268 | ||
| 269 | ```bash | 269 | ```bash |
| 270 | source /usr/local/Ascend/cann/set_env.sh | 270 | source /usr/local/Ascend/cann/set_env.sh |
| 271 | -cd examples/hcomm_write_read_nbi | 271 | +cd examples/aicore/hcomm/01_hcomm_write_read_nbi |
| 272 | mkdir -p build | 272 | mkdir -p build |
| 273 | cd build | 273 | cd build |
| 274 | cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. | 274 | cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. |
| @@ -69,5 +69,5 @@ AICore侧: | |||
| 69 | ## 相关文档 | 69 | ## 相关文档 |
| 70 | 70 | ||
| 71 | - [Hcomm使用说明](../guide/hcomm_usage.md) | 71 | - [Hcomm使用说明](../guide/hcomm_usage.md) |
| 72 | -- [AIV直驱URMA WriteNbi/ReadNbi样例](../../../examples/hcomm_write_read_nbi/README.md) | 72 | +- [AIV直驱URMA WriteNbi/ReadNbi样例](../../../examples/aicore/hcomm/01_hcomm_write_read_nbi/README.md) |
| 73 | -- [Ain Basic Ring样例](../../../examples/ain/basic_ring/README.md) | 73 | +- [Ain Basic Ring样例](../../../examples/aicore/ain/01_basic_ring/README.md) |
| @@ -84,4 +84,4 @@ class Hcomm; | |||
| 84 | 84 | ||
| 85 | ## 相关样例 | 85 | ## 相关样例 |
| 86 | 86 | ||
| 87 | -[hcomm_write_read_nbi](../../../../../examples/hcomm_write_read_nbi/README.md)演示两卡场景下,AIV Kernel通过`COMM_PROTOCOL_UBC_CTP`路径调用普通`WriteNbi`和`ReadNbi`。该样例不覆盖RoCE路径和BatchHandle流程。 | 87 | +[hcomm_write_read_nbi](../../../../../examples/aicore/hcomm/01_hcomm_write_read_nbi/README.md)演示两卡场景下,AIV Kernel通过`COMM_PROTOCOL_UBC_CTP`路径调用普通`WriteNbi`和`ReadNbi`。该样例不覆盖RoCE路径和BatchHandle流程。 |
| @@ -75,6 +75,6 @@ __aicore__ inline int32_t ReadNbi( | |||
| 75 | 75 | ||
| 76 | ## 相关样例 | 76 | ## 相关样例 |
| 77 | 77 | ||
| 78 | -[hcomm_write_read_nbi](../../../../../examples/hcomm_write_read_nbi/README.md)演示普通接口的AIV直驱URMA两卡读写流程。BatchHandle基本流程见[Hcomm使用说明](../../../guide/hcomm_usage.md)。 | 78 | +[hcomm_write_read_nbi](../../../../../examples/aicore/hcomm/01_hcomm_write_read_nbi/README.md)演示普通接口的AIV直驱URMA两卡读写流程。BatchHandle基本流程见[Hcomm使用说明](../../../guide/hcomm_usage.md)。 |
| 79 | 79 | ||
| 80 | 多通道接口见[GetHandleRef](./GetHandleRef.md)。 | 80 | 多通道接口见[GetHandleRef](./GetHandleRef.md)。 |
| @@ -75,6 +75,6 @@ __aicore__ inline int32_t WriteNbi( | |||
| 75 | 75 | ||
| 76 | ## 相关样例 | 76 | ## 相关样例 |
| 77 | 77 | ||
| 78 | -[hcomm_write_read_nbi](../../../../../examples/hcomm_write_read_nbi/README.md)演示普通接口的AIV直驱URMA两卡读写流程;[hcomm_batch_write](../../../../../examples/hcomm_batch_write/README.md)演示多通道批量写流程。BatchHandle基本流程见[Hcomm使用说明](../../../guide/hcomm_usage.md)。 | 78 | +[hcomm_write_read_nbi](../../../../../examples/aicore/hcomm/01_hcomm_write_read_nbi/README.md)演示普通接口的AIV直驱URMA两卡读写流程;[hcomm_batch_write](../../../../../examples/aicore/hcomm/02_hcomm_batch_write/README.md)演示多通道批量写流程。BatchHandle基本流程见[Hcomm使用说明](../../../guide/hcomm_usage.md)。 |
| 79 | 79 | ||
| 80 | 多通道接口见[GetHandleRef](./GetHandleRef.md)。 | 80 | 多通道接口见[GetHandleRef](./GetHandleRef.md)。 |
| @@ -8,5 +8,5 @@ | |||
| 8 | 8 | ||
| 9 | ## 样例代码 | 9 | ## 样例代码 |
| 10 | 10 | ||
| 11 | -- [AIV直驱URMA WriteNbi/ReadNbi样例](../../../examples/hcomm_write_read_nbi/README.md):展示如何在AIV Kernel中通过Hcomm的WriteNbi/ReadNbi接口实现NPU间低时延点对点通信,包含Host侧通信域创建、通道建立及Kernel侧Init → WriteNbi/ReadNbi → Drain的完整流程,支持Ascend 950PR/Ascend 950DT多卡环形拓扑。 | 11 | +- [AIV直驱URMA WriteNbi/ReadNbi样例](../../../examples/aicore/hcomm/01_hcomm_write_read_nbi/README.md):展示如何在AIV Kernel中通过Hcomm的WriteNbi/ReadNbi接口实现NPU间低时延点对点通信,包含Host侧通信域创建、通道建立及Kernel侧Init → WriteNbi/ReadNbi → Drain的完整流程,支持Ascend 950PR/Ascend 950DT多卡环形拓扑。 |
| 12 | -- [Ain Basic Ring样例](../../../examples/ain/basic_ring/README.md):展示如何通过AIN接口在AIV Kernel中实现多rank环形通信,包括Put写入对端window、Get读取对端window、Flush等待通信完成及AinBarrierSession::Sync同步,支持Ascend 950PR/Ascend 950DT单机多卡场景。 | 12 | +- [Ain Basic Ring样例](../../../examples/aicore/ain/01_basic_ring/README.md):展示如何通过AIN接口在AIV Kernel中实现多rank环形通信,包括Put写入对端window、Get读取对端window、Flush等待通信完成及AinBarrierSession::Sync同步,支持Ascend 950PR/Ascend 950DT单机多卡场景。 |
| @@ -201,11 +201,11 @@ bash build.sh -t --cann_3rd_lib_path=<path-to-third-party> | |||
| 201 | 201 | ||
| 202 | ## 样例构建与运行 | 202 | ## 样例构建与运行 |
| 203 | 203 | ||
| 204 | -`examples/hcomm_write_read_nbi`提供AIV直驱URMA `WriteNbi`和`ReadNbi`点对点通信样例。该样例使用独立CMake工程构建: | 204 | +`examples/aicore/hcomm/01_hcomm_write_read_nbi`提供AIV直驱URMA `WriteNbi`和`ReadNbi`点对点通信样例。该样例使用独立CMake工程构建: |
| 205 | 205 | ||
| 206 | ```bash | 206 | ```bash |
| 207 | source /usr/local/Ascend/cann/set_env.sh | 207 | source /usr/local/Ascend/cann/set_env.sh |
| 208 | -cd examples/hcomm_write_read_nbi | 208 | +cd examples/aicore/hcomm/01_hcomm_write_read_nbi |
| 209 | mkdir -p build | 209 | mkdir -p build |
| 210 | cd build | 210 | cd build |
| 211 | cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. | 211 | cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. |
| @@ -19,7 +19,7 @@ asc-comm当前仓内构建主要用于环境检查、AICore Hcomm接口UT验证 | |||
| 19 | | 场景 | 依赖 | 版本 | 获取或配置方式 | | 19 | | 场景 | 依赖 | 版本 | 获取或配置方式 | |
| 20 | | --- | --- | --- | --- | | 20 | | --- | --- | --- | --- | |
| 21 | | UT | googletest | 1.14.0 | 优先使用系统GTest;没有系统GTest时,通过`CANN_3RD_LIB_PATH`指向CANN third_party目录。 | | 21 | | UT | googletest | 1.14.0 | 优先使用系统GTest;没有系统GTest时,通过`CANN_3RD_LIB_PATH`指向CANN third_party目录。 | |
| 22 | -| 样例 | CANN ASC CMake能力和hcomm库 | CANN 9.1.0或以上 | 执行`source ${install_path}/cann/set_env.sh`后,在`examples/hcomm_write_read_nbi`目录下使用CMake构建。 | | 22 | +| 样例 | CANN ASC CMake能力和hcomm库 | CANN 9.1.0或以上 | 执行`source ${install_path}/cann/set_env.sh`后,在`examples/aicore/hcomm/01_hcomm_write_read_nbi`目录下使用CMake构建。 | |
| 23 | | 代码格式化 | clang-format | v18.1.8 | `pre-commit-config.yaml`从`pre-commit-clang/mirrors-clang-format`拉取。 | | 23 | | 代码格式化 | clang-format | v18.1.8 | `pre-commit-config.yaml`从`pre-commit-clang/mirrors-clang-format`拉取。 | |
| 24 | | 开源合规检查 | oat-py | >= 1.0.1 | `scripts/oat_check.sh`会尝试自动安装;失败时手动执行`pip install oat-py>=1.0.1`。 | | 24 | | 开源合规检查 | oat-py | >= 1.0.1 | `scripts/oat_check.sh`会尝试自动安装;失败时手动执行`pip install oat-py>=1.0.1`。 | |
| 25 | 25 | ||
| @@ -27,13 +27,13 @@ asc-comm当前仓内构建主要用于环境检查、AICore Hcomm接口UT验证 | |||
| 27 | 27 | ||
| 28 | ## 样例运行依赖 | 28 | ## 样例运行依赖 |
| 29 | 29 | ||
| 30 | -`examples/hcomm_write_read_nbi`样例支持Ascend 950PR/Ascend 950DT,运行时需要至少2张NPU。单卡环境可完成编译验证,但无法完成两卡点对点通信运行验证。该样例固定使用`COMM_ENGINE_AIV`和`COMM_PROTOCOL_UBC_CTP`,不覆盖RoCE路径。 | 30 | +`examples/aicore/hcomm/01_hcomm_write_read_nbi`样例支持Ascend 950PR/Ascend 950DT,运行时需要至少2张NPU。单卡环境可完成编译验证,但无法完成两卡点对点通信运行验证。该样例固定使用`COMM_ENGINE_AIV`和`COMM_PROTOCOL_UBC_CTP`,不覆盖RoCE路径。 |
| 31 | 31 | ||
| 32 | 样例编译命令如下: | 32 | 样例编译命令如下: |
| 33 | 33 | ||
| 34 | ```bash | 34 | ```bash |
| 35 | source /usr/local/Ascend/cann/set_env.sh | 35 | source /usr/local/Ascend/cann/set_env.sh |
| 36 | -cd examples/hcomm_write_read_nbi | 36 | +cd examples/aicore/hcomm/01_hcomm_write_read_nbi |
| 37 | mkdir -p build | 37 | mkdir -p build |
| 38 | cd build | 38 | cd build |
| 39 | cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. | 39 | cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. |
| @@ -184,6 +184,6 @@ if (lockRet == 0) { | |||
| 184 | 184 | ||
| 185 | ## 样例 | 185 | ## 样例 |
| 186 | 186 | ||
| 187 | -可参考[hcomm_write_read_nbi](../../../examples/hcomm_write_read_nbi/README.md)了解普通接口的AIV Kernel侧调用方式和Host侧通信资源创建流程;参考[hcomm_batch_write](../../../examples/hcomm_batch_write/README.md)了解多通道批量写流程。 | 187 | +可参考[hcomm_write_read_nbi](../../../examples/aicore/hcomm/01_hcomm_write_read_nbi/README.md)了解普通接口的AIV Kernel侧调用方式和Host侧通信资源创建流程;参考[hcomm_batch_write](../../../examples/aicore/hcomm/02_hcomm_batch_write/README.md)了解多通道批量写流程。 |
| 188 | 188 | ||
| 189 | 两个样例均依赖Ascend 950PR/Ascend 950DT和至少2张NPU完成运行验证;单卡环境仅支持编译验证。 | 189 | 两个样例均依赖Ascend 950PR/Ascend 950DT和至少2张NPU完成运行验证;单卡环境仅支持编译验证。 |
| @@ -57,7 +57,7 @@ | |||
| 57 | - 远端地址和访问长度用于描述对端内存中的目标范围。 | 57 | - 远端地址和访问长度用于描述对端内存中的目标范围。 |
| 58 | - 访问凭据用于表明本次操作获得了目标内存范围的访问授权。 | 58 | - 访问凭据用于表明本次操作获得了目标内存范围的访问授权。 |
| 59 | 59 | ||
| 60 | -具体的通信内存注册、Channel创建和远端内存获取流程,可参考[Hcomm AIV直驱URMA样例](../../../examples/hcomm_write_read_nbi/README.md)。 | 60 | +具体的通信内存注册、Channel创建和远端内存获取流程,可参考[Hcomm AIV直驱URMA样例](../../../examples/aicore/hcomm/01_hcomm_write_read_nbi/README.md)。 |
| 61 | 61 | ||
| 62 | ### 访问凭据 | 62 | ### 访问凭据 |
| 63 | 63 | ||
| @@ -8,30 +8,19 @@ | |||
| 8 | 8 | ||
| 9 | | 样例 | 说明 | 支持产品 | | 9 | | 样例 | 说明 | 支持产品 | |
| 10 | | --- | --- | --- | | 10 | | --- | --- | --- | |
| 11 | -| [ain/basic_ring](./ain/basic_ring/README.md) | 演示多卡环形场景下AIV Kernel通过AIN接口调用`Put`/`Get`进行点对点单边通信,并通过`AinBarrierSession`完成同步与结果校验。 | Ascend 950PR/Ascend 950DT | | 11 | +| [aicore/ain/01_basic_ring](./aicore/ain/01_basic_ring/README.md) | 演示多卡环形场景下AIV Kernel通过AIN接口调用`Put`/`Get`进行点对点单边通信,并通过`AinBarrierSession`完成同步与结果校验。 | Ascend 950PR/Ascend 950DT | |
| 12 | -| [hcomm_batch_write](./hcomm_batch_write/README.md) | 演示多个URMA Channel共享Jetty,并通过`MakeBatchHandle`、`GetHandleRef`、`BatchCommit`和`Drain`批量提交跨peer写任务。 | Ascend 950PR/Ascend 950DT | | 12 | +| [aicore/hcomm/01_hcomm_write_read_nbi](./aicore/hcomm/01_hcomm_write_read_nbi/README.md) | 演示多卡场景下AIV Kernel通过URMA路径调用`Hcomm::WriteNbi`和`Hcomm::ReadNbi`,并校验通信结果。 | Ascend 950PR/Ascend 950DT | |
| 13 | +| [aicore/hcomm/02_hcomm_batch_write](./aicore/hcomm/02_hcomm_batch_write/README.md) | 演示多个URMA Channel共享Jetty,并通过`MakeBatchHandle`、`GetHandleRef`、`BatchCommit`和`Drain`批量提交跨peer写任务。 | Ascend 950PR/Ascend 950DT | | ||
| 14 | +| [aicore/hcomm/03_one_multi_path](./aicore/hcomm/03_one_multi_path/README.md) | 查询`UB_MEM`链路,为每个peer创建one path/multi path Channel,逐个处理peer,并通过双Stream并发搬运和校验该peer的远端数据。 | Ascend 950PR/Ascend 950DT | | ||
| 15 | +| [aicore/hcomm/04_simt_urma](./aicore/hcomm/04_simt_urma/README.md) | 演示并验证全部 SIMT URMA 接口:`WriteNbi`、`WriteValueNbi`、`WriteWithNotifyNbi`、`AtomicFAA` 和 `AtomicCAS`,覆盖立即提交与批量提交。 | Ascend 950PR / Ascend 950DT | | ||
| 16 | +| [aicore/hcomm/05_simt_urma_perftest](./aicore/hcomm/05_simt_urma_perftest/README.md) | 测量上述五个 SIMT URMA 接口的下发时延与完成带宽,覆盖立即提交/延迟提交两种发布策略。 | Ascend 950PR / Ascend 950DT | | ||
| 13 | | [hcomm_jetty_write](./hcomm_jetty_write/README.md) | 演示多卡场景下AIV Kernel通过`HcommJetty::Write`和`HcommJetty::WriteValue`直接向Jetty SQ提交WQE,并通过`Drain`等待完成与校验结果。 | Ascend 950PR/Ascend 950DT | | 17 | | [hcomm_jetty_write](./hcomm_jetty_write/README.md) | 演示多卡场景下AIV Kernel通过`HcommJetty::Write`和`HcommJetty::WriteValue`直接向Jetty SQ提交WQE,并通过`Drain`等待完成与校验结果。 | Ascend 950PR/Ascend 950DT | |
| 14 | -| [hcomm_write_read_nbi](./hcomm_write_read_nbi/README.md) | 演示多卡场景下AIV Kernel通过URMA路径调用`Hcomm::WriteNbi`和`Hcomm::ReadNbi`,并校验通信结果。 | Ascend 950PR/Ascend 950DT | | 18 | +| [ccu/ccu_direct](./ccu/ccu_direct/01_allgather/README.md) | 演示基于HCCL通信域和CCU数据面接口,以直调`<<<>>>`方式实现AllGather等集合通信操作。 | Ascend 950PR/Ascend 950DT | |
| 15 | -| [one_multi_path](./one_multi_path/README.md) | 查询`UB_MEM`链路,为每个peer创建one path/multi path Channel,逐个处理peer,并通过双Stream并发搬运和校验该peer的远端数据。 | Ascend 950PR/Ascend 950DT | | ||
| 16 | -| [simt_urma](./simt_urma/README.md) | 演示并验证全部 SIMT URMA 接口:`WriteNbi`、`WriteValueNbi`、`WriteWithNotifyNbi`、`AtomicFAA` 和 `AtomicCAS`,覆盖立即提交与批量提交。 | Ascend 950PR / Ascend 950DT | | ||
| 17 | -| [simt_urma_perftest](./simt_urma_perftest/README.md) | 测量上述五个 SIMT URMA 接口的下发时延与完成带宽,覆盖立即提交/延迟提交两种发布策略。 | Ascend 950PR / Ascend 950DT | | ||
| 18 | 19 | ||
| 19 | -## simt_urma | 20 | +各样例的编译与运行方式参见对应目录下的README。 |
| 20 | - | ||
| 21 | -`simt_urma`验证SIMT Kernel通过URMA路径调用`WriteNbi`、`WriteValueNbi`、`WriteWithNotifyNbi`、 | ||
| 22 | -`AtomicFAA`和`AtomicCAS`。样例包含单接口用例,以及串行提交和batch-last提交场景,共十种模式。 | ||
| 23 | - | ||
| 24 | -编译运行方式参见[simt_urma/README.md](./simt_urma/README.md)。 | ||
| 25 | - | ||
| 26 | -## simt_urma_perftest | ||
| 27 | - | ||
| 28 | -`simt_urma_perftest`测量上述五个接口的性能,分别统计下发时延与完成带宽,并对`write`和`notify` | ||
| 29 | -支持payload扫描。 | ||
| 30 | - | ||
| 31 | -性能测试方式参见[simt_urma_perftest/README.md](./simt_urma_perftest/README.md)。 | ||
| 32 | 21 | ||
| 33 | ## 运行约束 | 22 | ## 运行约束 |
| 34 | 23 | ||
| 35 | - 样例支持Ascend 950PR/Ascend 950DT,CANN软件版本要求为9.1.0或以上。 | 24 | - 样例支持Ascend 950PR/Ascend 950DT,CANN软件版本要求为9.1.0或以上。 |
| 36 | - 样例运行需要至少2张NPU;单卡环境仅支持编译验证。 | 25 | - 样例运行需要至少2张NPU;单卡环境仅支持编译验证。 |
| 37 | -- 样例编译依赖CANN ASC CMake能力,并在链接阶段依赖CANN `hcomm`库。 | 26 | +- 样例编译依赖CANN ASC CMake能力,并在链接阶段依赖CANN `hcomm`库。 |
| @@ -8,27 +8,19 @@ This directory contains usage samples for asc-comm APIs. | |||
| 8 | 8 | ||
| 9 | | Sample | Description | Supported Products | | 9 | | Sample | Description | Supported Products | |
| 10 | | --- | --- | --- | | 10 | | --- | --- | --- | |
| 11 | -| [ain/basic_ring](./ain/basic_ring/README_en.md) | Demonstrates AIV Kernel invoking `Put`/`Get` over the AIN interface for point-to-point one-sided communication in a multi-card ring scenario, with synchronization and result verification through `AinBarrierSession`. | Ascend 950PR / Ascend 950DT | | 11 | +| [aicore/ain/01_basic_ring](./aicore/ain/01_basic_ring/README_en.md) | Demonstrates AIV Kernel invoking `Put`/`Get` over the AIN interface for point-to-point one-sided communication in a multi-card ring scenario, with synchronization and result verification through `AinBarrierSession`. | Ascend 950PR / Ascend 950DT | |
| 12 | -| [hcomm_batch_write](./hcomm_batch_write/README_en.md) | Demonstrates multiple URMA channels sharing a Jetty and submitting cross-peer writes through `MakeBatchHandle`, `GetHandleRef`, `BatchCommit`, and `Drain`. | Ascend 950PR / Ascend 950DT | | 12 | +| [aicore/hcomm/01_hcomm_write_read_nbi](./aicore/hcomm/01_hcomm_write_read_nbi/README_en.md) | Demonstrates AIV Kernel invoking `Hcomm::WriteNbi` and `Hcomm::ReadNbi` over the URMA path in a multi-card scenario, with communication result verification. | Ascend 950PR / Ascend 950DT | |
| 13 | +| [aicore/hcomm/02_hcomm_batch_write](./aicore/hcomm/02_hcomm_batch_write/README_en.md) | Demonstrates multiple URMA channels sharing a Jetty and submitting cross-peer writes through `MakeBatchHandle`, `GetHandleRef`, `BatchCommit`, and `Drain`. | Ascend 950PR / Ascend 950DT | | ||
| 14 | +| [aicore/hcomm/03_one_multi_path](./aicore/hcomm/03_one_multi_path/README_en.md) | Queries a `UB_MEM` link, creates one path/multi path channels for every peer, processes peers serially, and concurrently moves and verifies each peer's remote data over two streams. | Ascend 950PR / Ascend 950DT | | ||
| 15 | +| [aicore/hcomm/04_simt_urma](./aicore/hcomm/04_simt_urma/README_en.md) | Demonstrates and validates every SIMT URMA interface: `WriteNbi`, `WriteValueNbi`, `WriteWithNotifyNbi`, `AtomicFAA`, and `AtomicCAS`, with immediate and batched submission. | Ascend 950PR / Ascend 950DT | | ||
| 16 | +| [aicore/hcomm/05_simt_urma_perftest](./aicore/hcomm/05_simt_urma_perftest/README_en.md) | Measures issue latency and completion bandwidth for those five SIMT URMA interfaces under immediate and deferred publication. | Ascend 950PR / Ascend 950DT | | ||
| 13 | | [hcomm_jetty_write](./hcomm_jetty_write/README_en.md) | Demonstrates an AIV Kernel submitting WQEs directly to the Jetty SQ through `HcommJetty::Write` and `HcommJetty::WriteValue` in a multi-card scenario, with `Drain` used for completion and verification. | Ascend 950PR / Ascend 950DT | | 17 | | [hcomm_jetty_write](./hcomm_jetty_write/README_en.md) | Demonstrates an AIV Kernel submitting WQEs directly to the Jetty SQ through `HcommJetty::Write` and `HcommJetty::WriteValue` in a multi-card scenario, with `Drain` used for completion and verification. | Ascend 950PR / Ascend 950DT | |
| 14 | -| [hcomm_write_read_nbi](./hcomm_write_read_nbi/README_en.md) | Demonstrates AIV Kernel invoking `Hcomm::WriteNbi` and `Hcomm::ReadNbi` over the URMA path in a multi-card scenario, with communication result verification. | Ascend 950PR / Ascend 950DT | | 18 | +| [ccu/ccu_direct](./ccu/ccu_direct/01_allgather/README_en.md) | Demonstrates AllGather and other collective communication operations using HCCL communicators and CCU dataplane interfaces with direct `<<<>>>` invocation. | Ascend 950PR/Ascend 950DT | |
| 15 | -| [one_multi_path](./one_multi_path/README_en.md) | Queries a `UB_MEM` link, creates one path/multi path channels for every peer, processes peers serially, and concurrently moves and verifies each peer's remote data over two streams. | Ascend 950PR / Ascend 950DT | | ||
| 16 | -| [simt_urma](./simt_urma/README_en.md) | Demonstrates and validates every SIMT URMA interface: `WriteNbi`, `WriteValueNbi`, `WriteWithNotifyNbi`, `AtomicFAA`, and `AtomicCAS`, with immediate and batched submission. | Ascend 950PR / Ascend 950DT | | ||
| 17 | -| [simt_urma_perftest](./simt_urma_perftest/README_en.md) | Measures issue latency and completion bandwidth for those five SIMT URMA interfaces under immediate and deferred publication. | Ascend 950PR / Ascend 950DT | | ||
| 18 | 19 | ||
| 19 | -## simt_urma | 20 | +See the README in each sample directory for build and run instructions. |
| 20 | - | ||
| 21 | -`simt_urma` validates SIMT URMA `WriteNbi`, `WriteValueNbi`, `WriteWithNotifyNbi`, `AtomicFAA`, and `AtomicCAS`, covering isolated interface cases plus serialized and batch-last submission across ten modes. | ||
| 22 | - | ||
| 23 | -See [simt_urma/README_en.md](./simt_urma/README_en.md) for build and run instructions. | ||
| 24 | - | ||
| 25 | -## simt_urma_perftest | ||
| 26 | - | ||
| 27 | -`simt_urma_perftest` measures those five interfaces, reporting issue latency and completion bandwidth, with payload sweeps for `write` and `notify`. | ||
| 28 | - | ||
| 29 | -See [simt_urma_perftest/README_en.md](./simt_urma_perftest/README_en.md) for performance testing instructions. | ||
| 30 | 21 | ||
| 31 | ## Runtime Constraints | 22 | ## Runtime Constraints |
| 23 | + | ||
| 32 | - Supported chips: Ascend 950PR / Ascend 950DT. CANN version 9.1.0 or later is required. | 24 | - Supported chips: Ascend 950PR / Ascend 950DT. CANN version 9.1.0 or later is required. |
| 33 | - At least two NPUs are required for runtime execution; single-NPU environments only support compilation verification. | 25 | - At least two NPUs are required for runtime execution; single-NPU environments only support compilation verification. |
| 34 | -- Sample build relies on CANN ASC CMake utilities and links against the CANN `hcomm` library at link time. | 26 | +- Sample build relies on CANN ASC CMake utilities and links against the CANN `hcomm` library. |
| @@ -10,50 +10,37 @@ | |||
| 10 | 10 | ||
| 11 | cmake_minimum_required(VERSION 3.16) | 11 | cmake_minimum_required(VERSION 3.16) |
| 12 | 12 | ||
| 13 | -set(CMAKE_ASC_ARCHITECTURES "dav-3510" CACHE STRING "NPU architecture") | 13 | +set(CMAKE_ASC_ARCHITECTURES "dav-3510" CACHE STRING "NPU architecture: dav-3510") |
| 14 | - | ||
| 15 | -if(NOT CMAKE_ASC_ARCHITECTURES STREQUAL "dav-3510") | ||
| 16 | - message(FATAL_ERROR "ain_basic_ring_sample only supports dav-3510, but got ${CMAKE_ASC_ARCHITECTURES}") | ||
| 17 | -endif() | ||
| 18 | 14 | ||
| 19 | find_package(ASC REQUIRED) | 15 | find_package(ASC REQUIRED) |
| 20 | - | 16 | +project(basic_ring_demo LANGUAGES ASC CXX) |
| 21 | -project(ain_basic_ring_sample LANGUAGES ASC CXX) | ||
| 22 | - | ||
| 23 | -set(CMAKE_CXX_STANDARD 17) | ||
| 24 | -set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||
| 25 | - | ||
| 26 | -set_source_files_properties( | ||
| 27 | - basic_ring.asc | ||
| 28 | - PROPERTIES LANGUAGE ASC | ||
| 29 | -) | ||
| 30 | 17 | ||
| 31 | add_executable(basic_ring_demo | 18 | add_executable(basic_ring_demo |
| 32 | basic_ring.asc | 19 | basic_ring.asc |
| 33 | ) | 20 | ) |
| 34 | 21 | ||
| 22 | +set_target_properties(basic_ring_demo PROPERTIES | ||
| 23 | + LINKER_LANGUAGE ASC | ||
| 24 | +) | ||
| 25 | + | ||
| 35 | target_include_directories(basic_ring_demo PRIVATE | 26 | target_include_directories(basic_ring_demo PRIVATE |
| 36 | - ${ASCEND_CANN_PACKAGE_PATH}/pkg_inc | 27 | + ${CMAKE_CURRENT_SOURCE_DIR} |
| 37 | - ${ASCEND_CANN_PACKAGE_PATH}/include | 28 | + ${CMAKE_CURRENT_SOURCE_DIR}/../.. |
| 38 | - ${ASCEND_CANN_PACKAGE_PATH}/include/hcomm | 29 | + $ENV{ASCEND_HOME_PATH}/include |
| 39 | - ${ASCEND_CANN_PACKAGE_PATH}/asc/include/comm_api/aicore | 30 | + $ENV{ASCEND_HOME_PATH}/asc/include/comm_api/aicore |
| 31 | + $ENV{ASCEND_HOME_PATH}/asc/include/comm_api/hcomm | ||
| 40 | ) | 32 | ) |
| 41 | 33 | ||
| 42 | target_link_directories(basic_ring_demo PRIVATE | 34 | target_link_directories(basic_ring_demo PRIVATE |
| 43 | - ${ASCEND_CANN_PACKAGE_PATH}/lib64 | 35 | + $ENV{ASCEND_HOME_PATH}/lib64 |
| 36 | + $ENV{ASCEND_HOME_PATH}/${CMAKE_SYSTEM_PROCESSOR}-linux/lib64 | ||
| 44 | ) | 37 | ) |
| 45 | 38 | ||
| 46 | target_link_libraries(basic_ring_demo PRIVATE | 39 | target_link_libraries(basic_ring_demo PRIVATE |
| 47 | - -Wl,--no-as-needed | ||
| 48 | - hccl | ||
| 49 | hcomm | 40 | hcomm |
| 50 | - -Wl,--as-needed | 41 | + hccl |
| 51 | - ascendcl | ||
| 52 | - runtime | ||
| 53 | - stdc++ | ||
| 54 | - dl | ||
| 55 | ) | 42 | ) |
| 56 | 43 | ||
| 57 | -set_target_properties(basic_ring_demo PROPERTIES | 44 | +target_compile_options(basic_ring_demo PRIVATE |
| 58 | - BUILD_RPATH "${ASCEND_CANN_PACKAGE_PATH}/lib64;${ASCEND_CANN_PACKAGE_LINUX_PATH}/lib64" | 45 | + $<$<COMPILE_LANGUAGE:ASC>:--npu-arch=${CMAKE_ASC_ARCHITECTURES}> |
| 59 | ) | 46 | ) |
| @@ -0,0 +1,121 @@ | |||
| 1 | +# AIN Basic Ring样例 | ||
| 2 | + | ||
| 3 | +## 概述 | ||
| 4 | + | ||
| 5 | +本样例展示如何在Ascend C AIV Kernel中通过`ain/ain.h`接口使用AIN基础通信能力。样例采用多rank | ||
| 6 | +对称执行方式:每个rank向下一个rank执行`Put`,并对上一个rank执行`Get`,最后通过 | ||
| 7 | +`AinBarrierSession`完成同步。 | ||
| 8 | + | ||
| 9 | +Host侧负责内存申请、初始化HCCL通信域、创建HCCL Team、注册对称window并创建AIV通信channel; | ||
| 10 | +Kernel侧只通过AIN接口提交数据面通信任务。 | ||
| 11 | + | ||
| 12 | +## 本样例支持的产品及CANN软件版本 | ||
| 13 | + | ||
| 14 | +| 产品 | CANN软件版本 | | ||
| 15 | +| --- | --- | | ||
| 16 | +| Ascend 950PR/Ascend 950DT | >= CANN 9.1.0 | | ||
| 17 | + | ||
| 18 | +## 目录结构介绍 | ||
| 19 | + | ||
| 20 | +```text | ||
| 21 | +basic_ring | ||
| 22 | +├── CMakeLists.txt // 编译工程文件 | ||
| 23 | +├── basic_ring.asc // Host侧资源准备、AICore侧AIN调用和共享定义 | ||
| 24 | +├── README.md // 中文样例说明 | ||
| 25 | +└── README_en.md // 英文样例说明 | ||
| 26 | +``` | ||
| 27 | + | ||
| 28 | +## 样例描述 | ||
| 29 | + | ||
| 30 | +### 功能说明 | ||
| 31 | + | ||
| 32 | +`nranks`个rank组成环形拓扑,当前rank `r`执行两次单边通信: | ||
| 33 | + | ||
| 34 | +- `Put`:将本rank标识写入下一个rank(`(r + 1) % nranks`)的`recvWindow[rankId]` | ||
| 35 | +- `Get`:从上一个rank(`(r - 1 + nranks) % nranks`)的`sendWindow[0]`读取数据到本rank的 | ||
| 36 | + `recvWindow[rankNum + rankId]` | ||
| 37 | + | ||
| 38 | +通信完成后每个rank回读`recvBuf`并校验`Put`和`Get`的结果。 | ||
| 39 | + | ||
| 40 | +### 样例规格 | ||
| 41 | + | ||
| 42 | +| 项目 | 说明 | | ||
| 43 | +| --- | --- | | ||
| 44 | +| 通信模式 | 环形拓扑AIN点对点单边通信 | | ||
| 45 | +| 通信引擎 | `COMM_ENGINE_AIV`,协议`COMM_PROTOCOL_UB_CTP` | | ||
| 46 | +| 部署形态 | 单机多卡 | | ||
| 47 | +| 支持rank数 | >= 2,且不超过当前可用NPU数量 | | ||
| 48 | + | ||
| 49 | +### 实现流程 | ||
| 50 | + | ||
| 51 | +1. 可执行文件直接拉起全部rank进程(进程内fork,参见`examples/aicore/utils/process_manager.h`); | ||
| 52 | + rank间通过命令行指定的TCP控制通道(`examples/aicore/utils/rank_sync.h`)交换root info并 | ||
| 53 | + 创建多rank HCCL通信域。 | ||
| 54 | +2. 每个rank初始化ACL运行环境,通过`HcclTeamCreateDescInit`配置team描述(包括`barrierCount`、 | ||
| 55 | + `rankIds`、通信引擎`COMM_ENGINE_AIV`、协议`COMM_PROTOCOL_UB_CTP`和`channelCnt`), | ||
| 56 | + 调用`HcclTeamCreate`创建team并自动建立AIV + UB_CTP通信channel。 | ||
| 57 | +3. 分别将`sendBuf`和`recvBuf`通过`HcclCommSymWinRegister`注册为对称window。 | ||
| 58 | +4. 下发`team`、`sendWin`、`recvWin`到Kernel。 | ||
| 59 | +5. Kernel侧构造`AscendC::Ain`对象并初始化Hcomm UB临时工作区,执行`Put`和`Get`后调用`Flush` | ||
| 60 | + 等待通信任务完成,最后通过`AinBarrierSession::Sync`完成rank间同步。 | ||
| 61 | + | ||
| 62 | +## 编译运行 | ||
| 63 | + | ||
| 64 | +在本样例根目录下执行如下步骤,编译并运行样例。本样例仅支持NPU运行模式。 | ||
| 65 | + | ||
| 66 | +- 配置环境变量 | ||
| 67 | + | ||
| 68 | + 请根据当前环境上CANN开发套件包的安装方式配置环境变量。 | ||
| 69 | + | ||
| 70 | + ```bash | ||
| 71 | + source ${install_path}/cann/set_env.sh | ||
| 72 | + ``` | ||
| 73 | + | ||
| 74 | + > **说明:** `${install_path}`为CANN包安装目录,未指定安装目录时默认安装至`/usr/local/Ascend`。 | ||
| 75 | + | ||
| 76 | +- 样例执行 | ||
| 77 | + | ||
| 78 | + 在本样例目录下执行如下命令。可执行文件内部fork出全部rank进程,直接运行即可: | ||
| 79 | + | ||
| 80 | + ```bash | ||
| 81 | + mkdir -p build | ||
| 82 | + cd build | ||
| 83 | + cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. | ||
| 84 | + make -j | ||
| 85 | + cd .. && ./build/basic_ring_demo tcp://127.0.0.1:29622 <nranks> | ||
| 86 | + ``` | ||
| 87 | + | ||
| 88 | +- 启动参数说明 | ||
| 89 | + | ||
| 90 | + | 参数 | 默认值 | 说明 | | ||
| 91 | + | --- | --- | --- | | ||
| 92 | + | `<ip:port>` | 无默认 | rank 0监听的控制通道地址(`tcp://ip:port`格式),用于root info交换;并行运行多个实例时错开端口 | | ||
| 93 | + | `<nranks>` | 无默认 | 启动的rank数量,必须为不小于2的整数,且不超过当前可用NPU数量 | | ||
| 94 | + | ||
| 95 | +- 编译选项说明 | ||
| 96 | + | ||
| 97 | + | 选项 | 可选值 | 说明 | | ||
| 98 | + | --- | --- | --- | | ||
| 99 | + | `CMAKE_ASC_RUN_MODE` | `npu`(默认) | 运行模式,本样例仅支持NPU运行 | | ||
| 100 | + | `CMAKE_ASC_ARCHITECTURES` | `dav-3510` | NPU架构,对应Ascend 950PR/Ascend 950DT | | ||
| 101 | + | ||
| 102 | +- 执行结果 | ||
| 103 | + | ||
| 104 | + 每个rank会回读`recvBuf`并打印`Put`和`Get`结果,例如: | ||
| 105 | + | ||
| 106 | + ```text | ||
| 107 | + [rank 0] basic_ring | PUT recvBuf[1]=1, GET recvBuf[2]=1 | PASS | ||
| 108 | + [rank 1] basic_ring | PUT recvBuf[0]=0, GET recvBuf[3]=0 | PASS | ||
| 109 | + RESULT | Example=basic_ring | Status=PASS | ||
| 110 | + ``` | ||
| 111 | + | ||
| 112 | + 所有rank均输出`PASS`且最终输出`Status=PASS`表示样例执行成功。 | ||
| 113 | + | ||
| 114 | +## 注意事项 | ||
| 115 | + | ||
| 116 | +- 运行样例需要至少2张NPU;单卡环境仅支持编译验证。 | ||
| 117 | +- 编译和运行前必须先加载CANN环境变量,确保`ASCEND_CANN_PACKAGE_PATH`、ASC CMake模块和运行时 | ||
| 118 | + 动态库可用。 | ||
| 119 | +- 样例依赖CANN中的`hccl`、`hcomm`、`ascendcl`和`runtime`库。 | ||
| 120 | +- 运行时rank数量不能超过当前可用NPU数量。 | ||
| 121 | +- 样例仅支持单机多卡运行,不支持跨节点多机运行。 | ||
| @@ -26,8 +26,7 @@ basic_ring | |||
| 26 | ├── CMakeLists.txt // Build project file | 26 | ├── CMakeLists.txt // Build project file |
| 27 | ├── README.md // Chinese README | 27 | ├── README.md // Chinese README |
| 28 | ├── README_en.md // English README | 28 | ├── README_en.md // English README |
| 29 | -├── basic_ring.asc // Host-side setup, AICore-side AIN calls, and shared definitions | 29 | +└── basic_ring.asc // Host-side setup, AICore-side AIN calls, and shared definitions |
| 30 | -└── run.sh // Multi-rank launch script | ||
| 31 | ``` | 30 | ``` |
| 32 | 31 | ||
| 33 | ## Sample Flow | 32 | ## Sample Flow |
| @@ -35,11 +34,10 @@ basic_ring | |||
| 35 | ### Host-Side Resource Setup | 34 | ### Host-Side Resource Setup |
| 36 | 35 | ||
| 37 | 1. Call `aclInit`, `aclrtSetDevice`, and `aclrtCreateStream` to initialize the runtime environment. | 36 | 1. Call `aclInit`, `aclrtSetDevice`, and `aclrtCreateStream` to initialize the runtime environment. |
| 38 | -2. Create the multi-rank HCCL communicator through `HcclGetRootInfo` and `HcclCommInitRootInfo`. | 37 | +2. Create the multi-rank HCCL communicator through the `RankSyncContext` helper (which exchanges root info over a TCP control channel) and `examples::InitCommByRootInfo`. |
| 39 | -3. Configure `barrierCount` and call `HcclWorldTeamCreate` to create the world team. | 38 | +3. Initialize a team descriptor via `HcclTeamCreateDescInit` (including `barrierCount`, `rankIds`, engine `COMM_ENGINE_AIV`, protocol `COMM_PROTOCOL_UB_CTP`, and `channelCnt`), then call `HcclTeamCreate` to create the team with AIV + UB_CTP communication channels. |
| 40 | -4. Register `sendBuf` and `recvBuf` as symmetric windows through `HcclTeamWindowRegister`. | 39 | +4. Register `sendBuf` and `recvBuf` as symmetric windows through `HcclCommSymWinRegister`. |
| 41 | -5. Call `HcclTeamChannelsCreate` to create AIV + UB_CTP communication channels. | 40 | +5. Pass `team`, `sendWin`, and `recvWin` to the Kernel. |
| 42 | -6. Pass `worldTeam`, `sendWin`, and `recvWin` to the Kernel. | ||
| 43 | 41 | ||
| 44 | ### Kernel-Side AIN Communication | 42 | ### Kernel-Side AIN Communication |
| 45 | 43 | ||
| @@ -74,28 +72,28 @@ make -j | |||
| 74 | After the build completes, run the following command in the sample directory: | 72 | After the build completes, run the following command in the sample directory: |
| 75 | 73 | ||
| 76 | ```bash | 74 | ```bash |
| 77 | -./run.sh <nranks> | 75 | +./build/basic_ring_demo tcp://127.0.0.1:29622 <nranks> |
| 78 | ``` | 76 | ``` |
| 79 | 77 | ||
| 80 | For example, run with two cards: | 78 | For example, run with two cards: |
| 81 | 79 | ||
| 82 | ```bash | 80 | ```bash |
| 83 | -./run.sh 2 | 81 | +./build/basic_ring_demo tcp://127.0.0.1:29622 2 |
| 84 | ``` | 82 | ``` |
| 85 | 83 | ||
| 86 | -`run.sh` starts one `basic_ring_demo` process for each rank and uses a temporary file to exchange the HCCL root info. The default script timeout is 300 seconds. | 84 | +The executable forks all rank processes internally and uses a TCP control channel to exchange the HCCL root info. |
| 87 | 85 | ||
| 88 | ## Expected Result | 86 | ## Expected Result |
| 89 | 87 | ||
| 90 | Each rank reads back `recvBuf` and prints the `Put` and `Get` results, for example: | 88 | Each rank reads back `recvBuf` and prints the `Put` and `Get` results, for example: |
| 91 | 89 | ||
| 92 | ```text | 90 | ```text |
| 93 | -PUT RES rank 0 recvBuf[1]=1 expect=1 | 91 | +[rank 0] basic_ring | PUT recvBuf[1]=1, GET recvBuf[2]=1 | PASS |
| 94 | -GET RES rank 0 recvBuf[2]=1 expect=1 | 92 | +[rank 1] basic_ring | PUT recvBuf[0]=0, GET recvBuf[3]=0 | PASS |
| 95 | -rank 0 test pass | 93 | +RESULT | Example=basic_ring | Status=PASS |
| 96 | ``` | 94 | ``` |
| 97 | 95 | ||
| 98 | -The sample succeeds when all ranks print `test pass`. | 96 | +The sample succeeds when all ranks print `PASS` and the final status is `PASS`. |
| 99 | 97 | ||
| 100 | ## Build Option | 98 | ## Build Option |
| 101 | 99 | ||
| @@ -13,19 +13,13 @@ | |||
| 13 | * \brief AIN basic ring 样例. | 13 | * \brief AIN basic ring 样例. |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | -#include <chrono> | ||
| 17 | #include <cstdint> | 16 | #include <cstdint> |
| 18 | -#include <cstdio> | ||
| 19 | #include <cstdlib> | 17 | #include <cstdlib> |
| 20 | -#include <fstream> | ||
| 21 | #include <iostream> | 18 | #include <iostream> |
| 22 | #include <string> | 19 | #include <string> |
| 23 | -#include <thread> | ||
| 24 | #include <vector> | 20 | #include <vector> |
| 25 | -#include <sys/stat.h> | ||
| 26 | 21 | ||
| 27 | #include "acl/acl.h" | 22 | #include "acl/acl.h" |
| 28 | -#include "acl/acl_rt.h" | ||
| 29 | #include "hccl/hccl.h" | 23 | #include "hccl/hccl.h" |
| 30 | #include "hccl/hccl_comm.h" | 24 | #include "hccl/hccl_comm.h" |
| 31 | #include "hccl/hccl_types.h" | 25 | #include "hccl/hccl_types.h" |
| @@ -34,123 +28,15 @@ | |||
| 34 | #include "kernel_operator.h" | 28 | #include "kernel_operator.h" |
| 35 | #include "ain/ain.h" | 29 | #include "ain/ain.h" |
| 36 | 30 | ||
| 37 | -#define ACL_CHECK(expr) \ | 31 | +#include "utils/process_manager.h" |
| 38 | - do { \ | 32 | +#include "utils/check.h" |
| 39 | - aclError ret = (expr); \ | 33 | +#include "utils/hccl_comm_init.h" |
| 40 | - if (ret != ACL_SUCCESS) { \ | 34 | +#include "utils/rank_sync.h" |
| 41 | - std::cout << "acl error " << __FILE__ << ":" << __LINE__ << " ret=" << static_cast<int32_t>(ret) \ | 35 | +#include "utils/arg_parser.h" |
| 42 | - << std::endl; \ | ||
| 43 | - return ret; \ | ||
| 44 | - } \ | ||
| 45 | - } while (0) | ||
| 46 | - | ||
| 47 | -#define HCCL_CHECK(expr) \ | ||
| 48 | - do { \ | ||
| 49 | - HcclResult ret = (expr); \ | ||
| 50 | - if (ret != HCCL_SUCCESS) { \ | ||
| 51 | - std::cout << "hccl error " << __FILE__ << ":" << __LINE__ << " ret=" << static_cast<int32_t>(ret) \ | ||
| 52 | - << std::endl; \ | ||
| 53 | - return ret; \ | ||
| 54 | - } \ | ||
| 55 | - } while (0) | ||
| 56 | - | ||
| 57 | -#define HCOMM_CHECK(expr) \ | ||
| 58 | - do { \ | ||
| 59 | - HcommResult ret = (expr); \ | ||
| 60 | - if (ret != HCCL_SUCCESS) { \ | ||
| 61 | - std::cout << "hcomm error " << __FILE__ << ":" << __LINE__ << " ret=" << static_cast<int32_t>(ret) \ | ||
| 62 | - << std::endl; \ | ||
| 63 | - return ret; \ | ||
| 64 | - } \ | ||
| 65 | - } while (0) | ||
| 66 | 36 | ||
| 67 | namespace { | 37 | namespace { |
| 68 | 38 | ||
| 69 | constexpr size_t COMM_BUF_SIZE = 2U * 1024U * 1024U; | 39 | constexpr size_t COMM_BUF_SIZE = 2U * 1024U * 1024U; |
| 70 | -constexpr uint32_t ROOT_INFO_WAIT_SECONDS = 60U; | ||
| 71 | -constexpr uint32_t ROOT_INFO_POLL_MS = 100U; | ||
| 72 | - | ||
| 73 | -bool IsRootInfoFileReady(const std::string& path) | ||
| 74 | -{ | ||
| 75 | - struct stat st {}; | ||
| 76 | - return stat(path.c_str(), &st) == 0 && st.st_size >= static_cast<off_t>(sizeof(HcclRootInfo)); | ||
| 77 | -} | ||
| 78 | - | ||
| 79 | -HcclResult WriteRootInfoFile(const std::string& path, const HcclRootInfo& rootInfo) | ||
| 80 | -{ | ||
| 81 | - const std::string tmpPath = path + ".tmp"; | ||
| 82 | - std::ofstream ofs(tmpPath, std::ios::binary | std::ios::trunc); | ||
| 83 | - if (!ofs.is_open()) { | ||
| 84 | - std::cout << "open root info tmp file failed: " << tmpPath << std::endl; | ||
| 85 | - return HCCL_E_OPEN_FILE_FAILURE; | ||
| 86 | - } | ||
| 87 | - ofs.write(reinterpret_cast<const char*>(&rootInfo), sizeof(rootInfo)); | ||
| 88 | - ofs.close(); | ||
| 89 | - if (!ofs) { | ||
| 90 | - std::cout << "write root info file failed: " << tmpPath << std::endl; | ||
| 91 | - return HCCL_E_SYSCALL; | ||
| 92 | - } | ||
| 93 | - if (std::rename(tmpPath.c_str(), path.c_str()) != 0) { | ||
| 94 | - std::cout << "rename root info file failed: " << tmpPath << " -> " << path << std::endl; | ||
| 95 | - return HCCL_E_SYSCALL; | ||
| 96 | - } | ||
| 97 | - return ::HCCL_SUCCESS; | ||
| 98 | -} | ||
| 99 | - | ||
| 100 | -HcclResult ReadRootInfoFile(const std::string& path, HcclRootInfo* rootInfo) | ||
| 101 | -{ | ||
| 102 | - const uint32_t maxPollTimes = ROOT_INFO_WAIT_SECONDS * 1000U / ROOT_INFO_POLL_MS; | ||
| 103 | - for (uint32_t i = 0; i < maxPollTimes; ++i) { | ||
| 104 | - if (!IsRootInfoFileReady(path)) { | ||
| 105 | - std::this_thread::sleep_for(std::chrono::milliseconds(ROOT_INFO_POLL_MS)); | ||
| 106 | - continue; | ||
| 107 | - } | ||
| 108 | - std::ifstream ifs(path, std::ios::binary); | ||
| 109 | - if (!ifs.is_open()) { | ||
| 110 | - return HCCL_E_OPEN_FILE_FAILURE; | ||
| 111 | - } | ||
| 112 | - ifs.read(reinterpret_cast<char*>(rootInfo), sizeof(*rootInfo)); | ||
| 113 | - if (ifs.gcount() == static_cast<std::streamsize>(sizeof(*rootInfo))) { | ||
| 114 | - return ::HCCL_SUCCESS; | ||
| 115 | - } | ||
| 116 | - std::this_thread::sleep_for(std::chrono::milliseconds(ROOT_INFO_POLL_MS)); | ||
| 117 | - } | ||
| 118 | - std::cout << "wait root info file timeout: " << path << std::endl; | ||
| 119 | - return HCCL_E_TIMEOUT; | ||
| 120 | -} | ||
| 121 | - | ||
| 122 | -HcclResult InitCommByRootInfo(uint32_t rank, uint32_t nranks, const std::string& rootInfoFile, HcclComm* comm) | ||
| 123 | -{ | ||
| 124 | - HcclRootInfo rootInfo{}; | ||
| 125 | - HcclResult ret = HCCL_SUCCESS; | ||
| 126 | - if (rank == 0U) { | ||
| 127 | - HCCL_CHECK(HcclGetRootInfo(&rootInfo)); | ||
| 128 | - ret = WriteRootInfoFile(rootInfoFile, rootInfo); | ||
| 129 | - if (ret != HCCL_SUCCESS) { | ||
| 130 | - return ret; | ||
| 131 | - } | ||
| 132 | - } else { | ||
| 133 | - ret = ReadRootInfoFile(rootInfoFile, &rootInfo); | ||
| 134 | - if (ret != HCCL_SUCCESS) { | ||
| 135 | - return ret; | ||
| 136 | - } | ||
| 137 | - } | ||
| 138 | - HCCL_CHECK(HcclCommInitRootInfo(nranks, &rootInfo, rank, comm)); | ||
| 139 | - return HCCL_SUCCESS; | ||
| 140 | -} | ||
| 141 | - | ||
| 142 | -int32_t ParseInt32(const char* arg) | ||
| 143 | -{ | ||
| 144 | - if (arg == nullptr) { | ||
| 145 | - return -1; | ||
| 146 | - } | ||
| 147 | - char* end = nullptr; | ||
| 148 | - long value = std::strtol(arg, &end, 10); | ||
| 149 | - if (end == arg || *end != '\0') { | ||
| 150 | - return -1; | ||
| 151 | - } | ||
| 152 | - return static_cast<int32_t>(value); | ||
| 153 | -} | ||
| 154 | 40 | ||
| 155 | } // namespace | 41 | } // namespace |
| 156 | 42 | ||
| @@ -181,53 +67,83 @@ extern "C" [[bisheng::core_ratio(0, 1)]] __global__ __aicore__ void basic_ring_k | |||
| 181 | ainBarrier.Sync(AscendC::AinMemoryOrder::AIN_MEMORY_ORDER_RELAX, hcommUbuf); | 67 | ainBarrier.Sync(AscendC::AinMemoryOrder::AIN_MEMORY_ORDER_RELAX, hcommUbuf); |
| 182 | } | 68 | } |
| 183 | 69 | ||
| 70 | +int32_t RunBasicRingRank(uint32_t rank, uint32_t nranks, const std::string& ctrlEndpoint); | ||
| 71 | + | ||
| 184 | int32_t main(int32_t argc, char* argv[]) | 72 | int32_t main(int32_t argc, char* argv[]) |
| 185 | { | 73 | { |
| 186 | - if (argc < 4) { | 74 | + if (argc != 3) { |
| 187 | - std::cout << "Usage: " << argv[0] << " <rank> <nranks> <root_info_file>" << std::endl; | 75 | + std::fprintf(stderr, "Usage: %s <tcp://ip:port> <nranks>\n", argv[0]); |
| 76 | + return 1; | ||
| 77 | + } | ||
| 78 | + uint32_t nranks = 0; | ||
| 79 | + if (!examples::ParseUint32(argv[2], nranks, 2)) { | ||
| 80 | + std::fprintf(stderr, "invalid nranks: %s, expected an integer >= 2\n", argv[2]); | ||
| 81 | + return 1; | ||
| 82 | + } | ||
| 83 | + const std::string endpoint = argv[1]; | ||
| 84 | + | ||
| 85 | + std::vector<examples::ArgsOf<decltype(RunBasicRingRank)>> perRankArgs; | ||
| 86 | + perRankArgs.reserve(nranks); | ||
| 87 | + for (uint32_t rank = 0; rank < nranks; ++rank) { | ||
| 88 | + perRankArgs.emplace_back(rank, nranks, endpoint); | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + examples::ProcessGroup group; | ||
| 92 | + if (!group.Launch(nranks, RunBasicRingRank, std::move(perRankArgs))) { | ||
| 93 | + return 1; | ||
| 94 | + } | ||
| 95 | + const bool pass = group.WaitAll(); | ||
| 96 | + | ||
| 97 | + if (group.Interrupted()) { | ||
| 98 | + std::cout << "RESULT | Example=basic_ring | Status=INTERRUPTED" << std::endl; | ||
| 99 | + return 1; | ||
| 100 | + } | ||
| 101 | + std::cout << "RESULT | Example=basic_ring | Status=" << (pass ? "PASS" : "FAIL") << std::endl; | ||
| 102 | + return pass ? 0 : 1; | ||
| 103 | +} | ||
| 104 | + | ||
| 105 | +// 单个rank的完整流程。由ProcessGroup在每个子进程中调用。 | ||
| 106 | +// 本样例host侧无barrier(rank间同步由设备侧AinBarrierSession完成)。 | ||
| 107 | +int32_t RunBasicRingRank(uint32_t rank, uint32_t nranks, const std::string& ctrlEndpoint) | ||
| 108 | +{ | ||
| 109 | + examples::RankSyncContext sync = rank == 0U ? examples::RankSyncContext::Listen(ctrlEndpoint, nranks) : | ||
| 110 | + examples::RankSyncContext::Connect(rank, nranks, ctrlEndpoint); | ||
| 111 | + if (!sync.Ok()) { | ||
| 112 | + std::cout << "[rank " << rank << "] control channel setup failed" << std::endl; | ||
| 188 | return 1; | 113 | return 1; |
| 189 | } | 114 | } |
| 190 | 115 | ||
| 191 | - int32_t rank = ParseInt32(argv[1]); | 116 | + EXAMPLES_ACLCHECK(aclInit(nullptr)); |
| 192 | - int32_t nranks = ParseInt32(argv[2]); | ||
| 193 | - std::string rootInfoFile = argv[3]; | ||
| 194 | - if (rank < 0 || nranks < 2 || rank >= nranks) { | ||
| 195 | - std::cout << "Invalid rank arguments: rank=" << argv[1] << " nranks=" << argv[2] << std::endl; | ||
| 196 | - return 1; | ||
| 197 | - } | ||
| 198 | - | ||
| 199 | - ACL_CHECK(aclInit(nullptr)); | ||
| 200 | uint32_t devCount = 0; | 117 | uint32_t devCount = 0; |
| 201 | - ACL_CHECK(aclrtGetDeviceCount(&devCount)); | 118 | + EXAMPLES_ACLCHECK(aclrtGetDeviceCount(&devCount)); |
| 202 | - std::cout << "Found " << devCount << " NPU device(s), rank=" << rank << "/" << nranks << std::endl; | 119 | + EXAMPLES_ACLCHECK(aclrtSetDevice(static_cast<uint32_t>(rank))); |
| 203 | - ACL_CHECK(aclrtSetDevice(static_cast<uint32_t>(rank))); | ||
| 204 | aclrtStream stream = nullptr; | 120 | aclrtStream stream = nullptr; |
| 205 | - ACL_CHECK(aclrtCreateStream(&stream)); | 121 | + EXAMPLES_ACLCHECK(aclrtCreateStream(&stream)); |
| 206 | 122 | ||
| 207 | HcclComm hcclComm = nullptr; | 123 | HcclComm hcclComm = nullptr; |
| 208 | // 创建通信域 | 124 | // 创建通信域 |
| 209 | - HCCL_CHECK(InitCommByRootInfo(static_cast<uint32_t>(rank), static_cast<uint32_t>(nranks), rootInfoFile, &hcclComm)); | 125 | + EXAMPLES_HCCLCHECK(examples::InitCommByRootInfo(sync, &hcclComm)); |
| 210 | 126 | ||
| 211 | // 初始化本地数据 | 127 | // 初始化本地数据 |
| 212 | void* sendBuf = nullptr; | 128 | void* sendBuf = nullptr; |
| 213 | - HCOMM_CHECK(HcommMemAlloc(&sendBuf, COMM_BUF_SIZE)); | 129 | + EXAMPLES_HCOMMCHECK(HcommMemAlloc(&sendBuf, COMM_BUF_SIZE)); |
| 214 | std::vector<int8_t> sendHost(COMM_BUF_SIZE, static_cast<int8_t>(rank)); | 130 | std::vector<int8_t> sendHost(COMM_BUF_SIZE, static_cast<int8_t>(rank)); |
| 215 | - ACL_CHECK(aclrtMemcpy(sendBuf, COMM_BUF_SIZE, sendHost.data(), COMM_BUF_SIZE, ACL_MEMCPY_HOST_TO_DEVICE)); | 131 | + EXAMPLES_ACLCHECK(aclrtMemcpy(sendBuf, COMM_BUF_SIZE, sendHost.data(), COMM_BUF_SIZE, ACL_MEMCPY_HOST_TO_DEVICE)); |
| 216 | 132 | ||
| 217 | void* recvBuf = nullptr; | 133 | void* recvBuf = nullptr; |
| 218 | - HCOMM_CHECK(HcommMemAlloc(&recvBuf, COMM_BUF_SIZE)); | 134 | + EXAMPLES_HCOMMCHECK(HcommMemAlloc(&recvBuf, COMM_BUF_SIZE)); |
| 219 | - ACL_CHECK(aclrtMemset(recvBuf, COMM_BUF_SIZE, 0, COMM_BUF_SIZE)); | 135 | + EXAMPLES_ACLCHECK(aclrtMemset(recvBuf, COMM_BUF_SIZE, 0, COMM_BUF_SIZE)); |
| 220 | 136 | ||
| 221 | // 将本地内存注册为window | 137 | // 将本地内存注册为window |
| 222 | HcclCommSymWindow sendWin{nullptr}; | 138 | HcclCommSymWindow sendWin{nullptr}; |
| 223 | - HCCL_CHECK(HcclCommSymWinRegister(hcclComm, sendBuf, COMM_BUF_SIZE, &sendWin, 1)); | 139 | + EXAMPLES_HCCLCHECK(HcclCommSymWinRegister(hcclComm, sendBuf, COMM_BUF_SIZE, &sendWin, 1)); |
| 224 | 140 | ||
| 225 | HcclCommSymWindow recvWin{nullptr}; | 141 | HcclCommSymWindow recvWin{nullptr}; |
| 226 | - HCCL_CHECK(HcclCommSymWinRegister(hcclComm, recvBuf, COMM_BUF_SIZE, &recvWin, 1)); | 142 | + EXAMPLES_HCCLCHECK(HcclCommSymWinRegister(hcclComm, recvBuf, COMM_BUF_SIZE, &recvWin, 1)); |
| 227 | 143 | ||
| 228 | // 创建team | 144 | // 创建team |
| 229 | HcclTeamCreateDesc desc; | 145 | HcclTeamCreateDesc desc; |
| 230 | - HCCL_CHECK(HcclTeamCreateDescInit(&desc)); | 146 | + EXAMPLES_HCCLCHECK(HcclTeamCreateDescInit(&desc)); |
| 231 | std::vector<uint32_t> worldRankIds; | 147 | std::vector<uint32_t> worldRankIds; |
| 232 | for (uint32_t idx = 0; idx < nranks; idx++) { | 148 | for (uint32_t idx = 0; idx < nranks; idx++) { |
| 233 | worldRankIds.emplace_back(idx); | 149 | worldRankIds.emplace_back(idx); |
| @@ -241,35 +157,32 @@ int32_t main(int32_t argc, char* argv[]) | |||
| 241 | desc.protocol = COMM_PROTOCOL_UB_CTP; | 157 | desc.protocol = COMM_PROTOCOL_UB_CTP; |
| 242 | desc.channelCnt = 1; | 158 | desc.channelCnt = 1; |
| 243 | HcommTeamHandle team{nullptr}; | 159 | HcommTeamHandle team{nullptr}; |
| 244 | - HCCL_CHECK(HcclTeamCreate(hcclComm, &desc, &team)); | 160 | + EXAMPLES_HCCLCHECK(HcclTeamCreate(hcclComm, &desc, &team)); |
| 245 | 161 | ||
| 246 | basic_ring_kernel<<<1U, nullptr, stream>>>(team, sendWin, recvWin, nranks, rank); | 162 | basic_ring_kernel<<<1U, nullptr, stream>>>(team, sendWin, recvWin, nranks, rank); |
| 247 | - ACL_CHECK(aclrtSynchronizeStream(stream)); | 163 | + EXAMPLES_ACLCHECK(aclrtSynchronizeStream(stream)); |
| 248 | 164 | ||
| 249 | // 结果校验 | 165 | // 结果校验 |
| 250 | int32_t prev = (rank - 1 + nranks) % nranks; | 166 | int32_t prev = (rank - 1 + nranks) % nranks; |
| 251 | int32_t getOffset = nranks + rank; | 167 | int32_t getOffset = nranks + rank; |
| 252 | int8_t* testBuf = nullptr; | 168 | int8_t* testBuf = nullptr; |
| 253 | - ACL_CHECK(aclrtMallocHost(reinterpret_cast<void**>(&testBuf), COMM_BUF_SIZE)); | 169 | + EXAMPLES_ACLCHECK(aclrtMallocHost(reinterpret_cast<void**>(&testBuf), COMM_BUF_SIZE)); |
| 254 | - ACL_CHECK(aclrtMemcpy(testBuf, COMM_BUF_SIZE, recvBuf, COMM_BUF_SIZE, ACL_MEMCPY_DEVICE_TO_HOST)); | 170 | + EXAMPLES_ACLCHECK(aclrtMemcpy(testBuf, COMM_BUF_SIZE, recvBuf, COMM_BUF_SIZE, ACL_MEMCPY_DEVICE_TO_HOST)); |
| 255 | - std::cout << "PUT RES rank " << rank << " recvBuf[" << prev << "]=" << static_cast<int32_t>(testBuf[prev]) | ||
| 256 | - << " expect=" << prev << std::endl; | ||
| 257 | - std::cout << "GET RES rank " << rank << " recvBuf[" << getOffset << "]=" << static_cast<int32_t>(testBuf[getOffset]) | ||
| 258 | - << " expect=" << prev << std::endl; | ||
| 259 | - | ||
| 260 | bool pass = testBuf[prev] == static_cast<int8_t>(prev) && testBuf[getOffset] == static_cast<int8_t>(prev); | 171 | bool pass = testBuf[prev] == static_cast<int8_t>(prev) && testBuf[getOffset] == static_cast<int8_t>(prev); |
| 261 | - std::cout << "rank " << rank << " test " << (pass ? "pass" : "failed") << std::endl; | 172 | + std::cout << "[rank " << rank << "] basic_ring | PUT recvBuf[" << prev |
| 173 | + << "]=" << static_cast<int32_t>(testBuf[prev]) << ", GET recvBuf[" << getOffset | ||
| 174 | + << "]=" << static_cast<int32_t>(testBuf[getOffset]) << " | " << (pass ? "PASS" : "FAIL") << std::endl; | ||
| 262 | 175 | ||
| 263 | - HCCL_CHECK(HcclTeamDestroy(team)); | 176 | + EXAMPLES_HCCLCHECK(HcclTeamDestroy(team)); |
| 264 | - HCCL_CHECK(HcclCommSymWinDeregister(recvWin)); | 177 | + EXAMPLES_HCCLCHECK(HcclCommSymWinDeregister(recvWin)); |
| 265 | - HCCL_CHECK(HcclCommSymWinDeregister(sendWin)); | 178 | + EXAMPLES_HCCLCHECK(HcclCommSymWinDeregister(sendWin)); |
| 266 | - ACL_CHECK(aclrtFreeHost(testBuf)); | 179 | + EXAMPLES_ACLCHECK(aclrtFreeHost(testBuf)); |
| 267 | - HCOMM_CHECK(HcommMemFree(sendBuf)); | 180 | + EXAMPLES_HCOMMCHECK(HcommMemFree(sendBuf)); |
| 268 | - HCOMM_CHECK(HcommMemFree(recvBuf)); | 181 | + EXAMPLES_HCOMMCHECK(HcommMemFree(recvBuf)); |
| 269 | - HCCL_CHECK(HcclCommDestroy(hcclComm)); | 182 | + EXAMPLES_HCCLCHECK(HcclCommDestroy(hcclComm)); |
| 270 | - ACL_CHECK(aclrtDestroyStream(stream)); | 183 | + EXAMPLES_ACLCHECK(aclrtDestroyStream(stream)); |
| 271 | - ACL_CHECK(aclrtResetDevice(static_cast<uint32_t>(rank))); | 184 | + EXAMPLES_ACLCHECK(aclrtResetDevice(static_cast<uint32_t>(rank))); |
| 272 | - ACL_CHECK(aclFinalize()); | 185 | + EXAMPLES_ACLCHECK(aclFinalize()); |
| 273 | 186 | ||
| 274 | - return 0; | 187 | + return pass ? 0 : 1; |
| 275 | } | 188 | } |
Rexamples/hcomm_write_read_nbi/CMakeLists.txt→examples/aicore/hcomm/01_hcomm_write_read_nbi/CMakeLists.txt+54-49
| @@ -1,49 +1,54 @@ | |||
| 1 | -# ---------------------------------------------------------------------------------------------------------- | 1 | +# ---------------------------------------------------------------------------------------------------------- |
| 2 | -# Copyright (c) 2026 Huawei Technologies Co., Ltd. | 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 | 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"). | 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. | 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, | 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. | 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. | 8 | +# See LICENSE in the root of the software repository for the full text of the License. |
| 9 | -# ---------------------------------------------------------------------------------------------------------- | 9 | +# ---------------------------------------------------------------------------------------------------------- |
| 10 | - | 10 | + |
| 11 | -cmake_minimum_required(VERSION 3.16) | 11 | +cmake_minimum_required(VERSION 3.16) |
| 12 | - | 12 | + |
| 13 | -set(CMAKE_ASC_ARCHITECTURES "dav-3510" CACHE STRING "NPU architecture: dav-3510") | 13 | +set(CMAKE_ASC_ARCHITECTURES "dav-3510" CACHE STRING "NPU architecture: dav-3510") |
| 14 | - | 14 | + |
| 15 | -if(NOT CMAKE_ASC_ARCHITECTURES STREQUAL "dav-3510") | 15 | +find_package(ASC REQUIRED) |
| 16 | - message(FATAL_ERROR "hcomm_write_read_nbi only supports dav-3510, but got ${CMAKE_ASC_ARCHITECTURES}") | 16 | +project(hcomm_write_read_nbi LANGUAGES ASC CXX) |
| 17 | -endif() | 17 | + |
| 18 | - | 18 | +option(ASCENDC_DEBUG "Enable AscendC/Hcomm kernel debug logs" OFF) |
| 19 | -find_package(ASC REQUIRED) | 19 | + |
| 20 | - | 20 | +set_source_files_properties(hcomm_write_read_nbi_kernel.cpp PROPERTIES LANGUAGE ASC) |
| 21 | -project(kernel_samples LANGUAGES ASC CXX) | 21 | + |
| 22 | - | 22 | +add_executable(hcomm_write_read_nbi |
| 23 | -option(ASCENDC_DEBUG "Enable AscendC/Hcomm kernel debug logs" OFF) | 23 | + hcomm_write_read_nbi.asc |
| 24 | - | 24 | + hcomm_write_read_nbi_kernel.cpp |
| 25 | -set_source_files_properties( | 25 | +) |
| 26 | - hcomm_write_read_nbi_kernel.cpp | 26 | + |
| 27 | - utils.cpp | 27 | +set_target_properties(hcomm_write_read_nbi PROPERTIES |
| 28 | - PROPERTIES LANGUAGE ASC | 28 | + LINKER_LANGUAGE ASC |
| 29 | -) | 29 | +) |
| 30 | - | 30 | + |
| 31 | -add_executable(demo | 31 | +target_include_directories(hcomm_write_read_nbi PRIVATE |
| 32 | - hcomm_write_read_nbi.asc | 32 | + ${CMAKE_CURRENT_SOURCE_DIR} |
| 33 | - hcomm_write_read_nbi_kernel.cpp | 33 | + ${CMAKE_CURRENT_SOURCE_DIR}/../.. |
| 34 | - utils.cpp | 34 | +) |
| 35 | -) | 35 | + |
| 36 | - | 36 | +target_link_directories(hcomm_write_read_nbi PRIVATE |
| 37 | -target_link_libraries(demo PRIVATE | 37 | + $ENV{ASCEND_HOME_PATH}/lib64 |
| 38 | - hcomm | 38 | + $ENV{ASCEND_HOME_PATH}/${CMAKE_SYSTEM_PROCESSOR}-linux/lib64 |
| 39 | -) | 39 | +) |
| 40 | - | 40 | + |
| 41 | -target_compile_options(demo PRIVATE | 41 | +target_link_libraries(hcomm_write_read_nbi PRIVATE |
| 42 | - $<$<COMPILE_LANGUAGE:ASC>:--npu-arch=${CMAKE_ASC_ARCHITECTURES}> | 42 | + hcomm |
| 43 | -) | 43 | + hccl |
| 44 | - | 44 | +) |
| 45 | -if(ASCENDC_DEBUG) | 45 | + |
| 46 | - target_compile_definitions(demo PRIVATE | 46 | +target_compile_options(hcomm_write_read_nbi PRIVATE |
| 47 | - ASCENDC_DEBUG | 47 | + $<$<COMPILE_LANGUAGE:ASC>:--npu-arch=${CMAKE_ASC_ARCHITECTURES}> |
| 48 | - ) | 48 | +) |
| 49 | -endif() | 49 | + |
| 50 | +if(ASCENDC_DEBUG) | ||
| 51 | + target_compile_definitions(hcomm_write_read_nbi PRIVATE | ||
| 52 | + ASCENDC_DEBUG | ||
| 53 | + ) | ||
| 54 | +endif() | ||
| @@ -0,0 +1,143 @@ | |||
| 1 | +# Hcomm AIV直驱URMA WriteNbi/ReadNbi点对点通信样例 | ||
| 2 | + | ||
| 3 | +## 概述 | ||
| 4 | + | ||
| 5 | +本样例展示如何在Ascend C AIV Kernel中,基于**AIV直驱URMA**架构,使用`Hcomm`类的`WriteNbi`和 | ||
| 6 | +`ReadNbi`接口实现NPU间低时延的点对点(P2P)通信。样例采用多rank环形拓扑:每个rank与前后相邻rank | ||
| 7 | +建立P2P通道,通过地址偏移区分数据段,Kernel侧直接提交通信任务,最后在Host侧校验通信结果。 | ||
| 8 | + | ||
| 9 | +Host侧只负责创建通信域、注册通信内存和建立通道;通信任务由AIV Kernel直接提交,数据面执行期间 | ||
| 10 | +不需要Host逐次参与。该模式适用于MoE Dispatch/Combine、Pipeline并行等对通信时延敏感的场景。 | ||
| 11 | + | ||
| 12 | +## 本样例支持的产品及CANN软件版本 | ||
| 13 | + | ||
| 14 | +| 产品 | CANN软件版本 | | ||
| 15 | +|------|-------------| | ||
| 16 | +| Ascend 950PR / Ascend 950DT | >= CANN 9.1.0 | | ||
| 17 | + | ||
| 18 | +## 目录结构介绍 | ||
| 19 | + | ||
| 20 | +```text | ||
| 21 | +hcomm_write_read_nbi | ||
| 22 | +├── CMakeLists.txt // 编译工程文件 | ||
| 23 | +├── hcomm_write_read_nbi.asc // Host侧资源准备与Kernel调用 | ||
| 24 | +├── hcomm_write_read_nbi_kernel.cpp // AIV Kernel侧Hcomm调用 | ||
| 25 | +├── hcomm_rw_def.h // Host与Kernel共享定义 | ||
| 26 | +├── README.md // 中文样例说明 | ||
| 27 | +└── README_en.md // 英文样例说明 | ||
| 28 | +``` | ||
| 29 | + | ||
| 30 | +## 样例描述 | ||
| 31 | + | ||
| 32 | +### 功能说明 | ||
| 33 | + | ||
| 34 | +| API | 数据流向 | 语义说明(AIV直驱URMA) | | ||
| 35 | +|------|---------|------| | ||
| 36 | +| `WriteNbi` | 本地GM → 远端GM | AIV直驱URMA写接口:将本地Global Memory数据直接写入远端NPU指定地址,无需远端CPU介入。 | | ||
| 37 | +| `ReadNbi` | 远端GM → 本地GM | AIV直驱URMA读接口:直接从远端NPU指定地址读取数据到本地Global Memory,无需远端CPU介入。 | | ||
| 38 | + | ||
| 39 | +每个rank的通信缓冲区划分为三段,通过地址偏移区分: | ||
| 40 | + | ||
| 41 | +- **seg0** `[0, DATA_SIZE)`:本卡pattern(Host侧以`rank + index`模式预初始化,首字节为rankId,确保不同rank的数据来源可区分) | ||
| 42 | +- **seg1** `[DATA_SIZE, 2*DATA_SIZE)`:接收`prev`通过`WriteNbi`写入的数据 | ||
| 43 | +- **seg2** `[2*DATA_SIZE, 3*DATA_SIZE)`:接收本卡通过`ReadNbi`从`next`读回的数据 | ||
| 44 | + | ||
| 45 | +Kernel执行完毕后,Host侧回读结果并校验seg1和seg2是否与对端pattern完全一致。 | ||
| 46 | + | ||
| 47 | +### 样例规格 | ||
| 48 | + | ||
| 49 | +| 项目 | 说明 | | ||
| 50 | +|------|------| | ||
| 51 | +| 通信模式 | 环形拓扑AIV直驱URMA点对点通信 | | ||
| 52 | +| 调用方式 | AIV Kernel内`Hcomm::WriteNbi`/`ReadNbi` | | ||
| 53 | +| 进程启动 | 可执行文件直接拉起,内部fork多rank | | ||
| 54 | +| 支持rank数 | >= 2,且不超过当前可用NPU数量 | | ||
| 55 | + | ||
| 56 | +### 实现流程 | ||
| 57 | + | ||
| 58 | +1. 可执行文件直接拉起全部rank进程(进程内fork,参见`examples/aicore/utils/process_manager.h`); | ||
| 59 | + rank间通过命令行指定的TCP控制通道(`examples/aicore/utils/rank_sync.h`)交换root info并 | ||
| 60 | + 创建通信域。**注意:AIV直驱模式下,无需配置`hcclOpExpansionMode`。** | ||
| 61 | +2. 调用`HcclCommMemReg`向通信域注册本卡通信buffer,Channel创建时内存信息自动交换给对端。 | ||
| 62 | +3. 通过`HcclRankGraphGetLayers`和`HcclRankGraphGetLinks`获取到`prev`和`next`的链路Endpoint。 | ||
| 63 | +4. 调用`HcclChannelAcquire`创建P2P通道,指定引擎为`COMM_ENGINE_AIV`、协议为`COMM_PROTOCOL_UB_CTP`(URMA协议)。 | ||
| 64 | +5. 调用`HcclChannelGetRemoteMems`获取对端注册内存地址,作为Kernel侧`WriteNbi`/`ReadNbi`的远端目标地址。 | ||
| 65 | +6. Host预初始化seg0,将`ChannelHandle`和buffer地址封装到`CommContext`下发到各卡GM。 | ||
| 66 | +7. Kernel侧执行`Init()`分配UB工作空间后提交通信任务:将本卡seg0通过`WriteNbi`写入`next`的 | ||
| 67 | + seg1,并通过`ReadNbi`从`next`的seg0读到本卡seg2,最后`Drain()`等待通信任务完成。 | ||
| 68 | +8. Host侧通过控制通道barrier同步后,回读结果并校验seg1和seg2的pattern。 | ||
| 69 | + | ||
| 70 | +```cpp | ||
| 71 | +// 单个rank上的AIV直驱URMA通信操作示例: | ||
| 72 | +// 1. 本卡seg0 → 对端seg1 (WriteNbi) | ||
| 73 | +hcomm_.WriteNbi(channel, remoteBuf + DATA_SIZE, localBuf, DATA_SIZE); | ||
| 74 | + | ||
| 75 | +// 2. 对端seg0 → 本卡seg2 (ReadNbi) | ||
| 76 | +hcomm_.ReadNbi(channel, localBuf + 2 * DATA_SIZE, remoteBuf, DATA_SIZE); | ||
| 77 | + | ||
| 78 | +// 3. 等待AIV硬件通信任务完成 | ||
| 79 | +hcomm_.Drain(channel); | ||
| 80 | +``` | ||
| 81 | + | ||
| 82 | +## 编译运行 | ||
| 83 | + | ||
| 84 | +在本样例根目录下执行如下步骤,编译并运行样例。本样例仅支持NPU运行模式。 | ||
| 85 | + | ||
| 86 | +- 配置环境变量 | ||
| 87 | + | ||
| 88 | + 请根据当前环境上CANN开发套件包的安装方式配置环境变量。 | ||
| 89 | + | ||
| 90 | + ```bash | ||
| 91 | + source ${install_path}/cann/set_env.sh | ||
| 92 | + ``` | ||
| 93 | + | ||
| 94 | + > **说明:** `${install_path}`为CANN包安装目录,未指定安装目录时默认安装至`/usr/local/Ascend`。 | ||
| 95 | + | ||
| 96 | +- 样例执行 | ||
| 97 | + | ||
| 98 | + 在本样例目录下执行如下命令。可执行文件内部fork出全部rank进程,直接运行即可: | ||
| 99 | + | ||
| 100 | + ```bash | ||
| 101 | + mkdir -p build | ||
| 102 | + cd build | ||
| 103 | + cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. | ||
| 104 | + make -j | ||
| 105 | + cd .. && ./build/hcomm_write_read_nbi tcp://127.0.0.1:29623 <nranks> | ||
| 106 | + ``` | ||
| 107 | + | ||
| 108 | +- 启动参数说明 | ||
| 109 | + | ||
| 110 | + | 参数 | 默认值 | 说明 | | ||
| 111 | + |------|--------|------| | ||
| 112 | + | `<ip:port>` | 无默认 | rank 0监听的控制通道地址(`tcp://ip:port`格式),用于root info交换与Host侧barrier;并行运行多个实例时错开端口 | | ||
| 113 | + | `<nranks>` | 无默认 | 启动的rank数量,必须 >= 2,且不超过当前可用NPU数量 | | ||
| 114 | + | ||
| 115 | +- 编译选项说明 | ||
| 116 | + | ||
| 117 | + | 选项 | 可选值 | 说明 | | ||
| 118 | + |------|--------|------| | ||
| 119 | + | `CMAKE_ASC_RUN_MODE` | `npu`(默认) | 运行模式,本样例仅支持NPU运行 | | ||
| 120 | + | `CMAKE_ASC_ARCHITECTURES` | `dav-3510`(默认) | NPU架构:`dav-3510`对应Ascend 950PR/Ascend 950DT | | ||
| 121 | + | ||
| 122 | +- 执行结果 | ||
| 123 | + | ||
| 124 | + 多卡执行成功后,终端将输出如下信息,说明AIV直驱URMA通信成功(写入读出结果一致): | ||
| 125 | + | ||
| 126 | + ```text | ||
| 127 | + [rank 0] hcomm_write_read_nbi | sent to rank 1, received from rank 1 | PASS | ||
| 128 | + [rank 1] hcomm_write_read_nbi | sent to rank 0, received from rank 0 | PASS | ||
| 129 | + RESULT | Example=hcomm_write_read_nbi | Status=PASS | ||
| 130 | + ``` | ||
| 131 | + | ||
| 132 | +## 注意事项 | ||
| 133 | + | ||
| 134 | +- 运行样例需要至少2张NPU;单卡环境仅支持编译验证。 | ||
| 135 | +- Kernel侧`Init()`分配的UB工作空间需 >= 512字节,用于存放Hcomm内部WQE/CQE等状态。 | ||
| 136 | +- `WriteNbi`/`ReadNbi`默认`commit=true`,入队后立即触发doorbell;如需批量优化,可改用 | ||
| 137 | + `commit=false`多次入队后统一调用`Commit()`。`Drain()`返回后数据可见性才有保证。 | ||
| 138 | +- 当`nranks == 2`时,`prev`和`next`指向同一个对端rank,seg1和seg2会校验同一个对端pattern。 | ||
| 139 | +- 当前样例已建立`prev`和`next`两个方向的P2P通道,但默认只执行`next`方向的数据面操作。若要 | ||
| 140 | + 扩展为完整的all-to-neighbor通信,可复用已建立的`prev`通道:执行两次Kernel,第一次使用`prev` | ||
| 141 | + 通道执行`ReadNbi`从`prev`的seg0读到本卡seg2,第二次使用`next`通道执行`WriteNbi`将本卡seg0 | ||
| 142 | + 写入`next`的seg1,使每个rank的seg1和seg2都匹配`prev`的pattern。扩展时需保留Kernel前后的 | ||
| 143 | + Host侧barrier;若调整数据段偏移,需同步更新Host侧pattern校验的期望rank和offset。 | ||
| @@ -0,0 +1,132 @@ | |||
| 1 | +# Hcomm AIV Direct-Drive URMA WriteNbi/ReadNbi Point-to-Point Communication Sample | ||
| 2 | + | ||
| 3 | +## Overview | ||
| 4 | + | ||
| 5 | +This sample demonstrates how to use the `WriteNbi` and `ReadNbi` APIs of the `Hcomm` class to implement low-latency point-to-point (P2P) communication between NPUs from an Ascend C AIV Kernel, based on the **AIV direct-drive URMA** architecture. The sample adopts a multi-rank ring topology: each rank establishes P2P channels with its neighboring ranks, separates data segments via address offsets, submits communication tasks directly from the Kernel side, and validates the communication results on the Host side. | ||
| 6 | + | ||
| 7 | +The Host side is only responsible for creating the communication domain, registering communication memory, and acquiring channels; communication tasks are submitted directly by the AIV Kernel, and the Host does not need to participate in each data-plane transfer. This mode is suitable for latency-sensitive scenarios such as MoE Dispatch/Combine and pipeline parallelism. | ||
| 8 | + | ||
| 9 | +## Supported Products and CANN Software Versions | ||
| 10 | + | ||
| 11 | +| Product | CANN Software Version | | ||
| 12 | +|---------|-----------------------| | ||
| 13 | +| Ascend 950PR / Ascend 950DT | >= CANN 9.1.0 | | ||
| 14 | + | ||
| 15 | +## Directory Structure | ||
| 16 | + | ||
| 17 | +```text | ||
| 18 | +hcomm_write_read_nbi | ||
| 19 | +├── CMakeLists.txt // CMake build file | ||
| 20 | +├── hcomm_write_read_nbi.asc // Host resource setup and Kernel invocation | ||
| 21 | +├── hcomm_write_read_nbi_kernel.cpp // Hcomm calls from the AIV Kernel | ||
| 22 | +├── hcomm_rw_def.h // Definitions shared by Host and Kernel | ||
| 23 | +├── README.md // Chinese sample documentation | ||
| 24 | +└── README_en.md // English sample documentation | ||
| 25 | +``` | ||
| 26 | + | ||
| 27 | +## Sample Description | ||
| 28 | + | ||
| 29 | +### Functionality Description | ||
| 30 | + | ||
| 31 | +| API | Data Flow | Semantic Description (AIV Direct-Drive URMA) | | ||
| 32 | +|-----|-----------|----------------------------------------------| | ||
| 33 | +| `WriteNbi` | Local GM → Remote GM | AIV direct-drive URMA write API: directly writes local Global Memory data to a specified address on the remote NPU, without requiring remote CPU intervention. | | ||
| 34 | +| `ReadNbi` | Remote GM → Local GM | AIV direct-drive URMA read API: directly reads data from a specified address on the remote NPU into local Global Memory, without requiring remote CPU intervention. | | ||
| 35 | + | ||
| 36 | +Each rank's communication buffer is divided into three segments, distinguished by address offsets: | ||
| 37 | + | ||
| 38 | +- **seg0** `[0, DATA_SIZE)`: Local pattern (pre-initialized by the Host using a `rank + index` pattern, with the first byte set to rankId, ensuring that data sources from different ranks are distinguishable) | ||
| 39 | +- **seg1** `[DATA_SIZE, 2*DATA_SIZE)`: Receives data written by `prev` through `WriteNbi` | ||
| 40 | +- **seg2** `[2*DATA_SIZE, 3*DATA_SIZE)`: Receives data read back from `next` by the local `ReadNbi` | ||
| 41 | + | ||
| 42 | +After Kernel execution, the Host reads back the results and validates whether seg1 and seg2 match the peer patterns exactly. | ||
| 43 | + | ||
| 44 | +### Sample Specifications | ||
| 45 | + | ||
| 46 | +| Item | Description | | ||
| 47 | +|------|-------------| | ||
| 48 | +| Communication Mode | Ring topology AIV direct-drive URMA point-to-point communication | | ||
| 49 | +| Invocation Method | `Hcomm::WriteNbi`/`ReadNbi` within AIV Kernel | | ||
| 50 | +| Process Launch | Executable directly launches, internally forks multiple ranks | | ||
| 51 | +| Supported Rank Count | >= 2, not exceeding the number of available NPUs | | ||
| 52 | + | ||
| 53 | +### Implementation Flow | ||
| 54 | + | ||
| 55 | +1. The executable directly launches all rank processes (in-process fork, see `examples/aicore/utils/process_manager.h`); ranks exchange root info and create the communication domain through the TCP control channel specified on the command line (`examples/aicore/utils/rank_sync.h`). **Note: In AIV direct-drive mode, there is no need to configure `hcclOpExpansionMode`.** | ||
| 56 | +2. Call `HcclCommMemReg` to register the local communication buffer with the communication domain; memory information is automatically exchanged with the peer during channel creation. | ||
| 57 | +3. Use `HcclRankGraphGetLayers` and `HcclRankGraphGetLinks` to obtain link endpoints for `prev` and `next`. | ||
| 58 | +4. Call `HcclChannelAcquire` to create P2P channels, specifying `COMM_ENGINE_AIV` as the engine and `COMM_PROTOCOL_UB_CTP` as the protocol (URMA protocol). | ||
| 59 | +5. Call `HcclChannelGetRemoteMems` to retrieve the memory addresses registered by peer ranks, which serve as remote target addresses for `WriteNbi`/`ReadNbi` in the Kernel. | ||
| 60 | +6. The Host pre-initializes seg0, encapsulates the `ChannelHandle` and buffer addresses into `CommContext`, and downloads it to the GM of each card. | ||
| 61 | +7. The Kernel side executes `Init()` to allocate UB workspace, then submits communication tasks: writes local seg0 to `next`'s seg1 through `WriteNbi`, and reads `next`'s seg0 into local seg2 through `ReadNbi`, finally calling `Drain()` to wait for communication tasks to complete. | ||
| 62 | +8. The Host synchronizes via control channel barrier, then reads back results and validates seg1 and seg2 patterns. | ||
| 63 | + | ||
| 64 | +```cpp | ||
| 65 | +// Example AIV direct-drive URMA operations on one rank: | ||
| 66 | +// 1. Local seg0 → Peer seg1 (WriteNbi) | ||
| 67 | +hcomm_.WriteNbi(channel, remoteBuf + DATA_SIZE, localBuf, DATA_SIZE); | ||
| 68 | + | ||
| 69 | +// 2. Peer seg0 → Local seg2 (ReadNbi) | ||
| 70 | +hcomm_.ReadNbi(channel, localBuf + 2 * DATA_SIZE, remoteBuf, DATA_SIZE); | ||
| 71 | + | ||
| 72 | +// 3. Wait for AIV hardware communication tasks to complete | ||
| 73 | +hcomm_.Drain(channel); | ||
| 74 | +``` | ||
| 75 | + | ||
| 76 | +## Compilation and Execution | ||
| 77 | + | ||
| 78 | +Follow the steps below in the root directory of this sample to compile and run it. This sample only supports NPU execution mode. | ||
| 79 | + | ||
| 80 | +- Configure environment variables | ||
| 81 | + | ||
| 82 | + Configure the environment variables according to the installation method of the CANN development kit on your current environment. | ||
| 83 | + | ||
| 84 | + ```bash | ||
| 85 | + source ${install_path}/cann/set_env.sh | ||
| 86 | + ``` | ||
| 87 | + | ||
| 88 | + > **Note:** `${install_path}` is the CANN package installation directory. If not specified, it defaults to `/usr/local/Ascend`. | ||
| 89 | + | ||
| 90 | +- Run the sample | ||
| 91 | + | ||
| 92 | + Execute the following commands in the sample directory. The executable internally forks all rank processes, so it can be run directly: | ||
| 93 | + | ||
| 94 | + ```bash | ||
| 95 | + mkdir -p build | ||
| 96 | + cd build | ||
| 97 | + cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. | ||
| 98 | + make -j | ||
| 99 | + cd .. && ./build/hcomm_write_read_nbi tcp://127.0.0.1:29623 <nranks> | ||
| 100 | + ``` | ||
| 101 | + | ||
| 102 | +- Launch parameter description | ||
| 103 | + | ||
| 104 | + | Parameter | Default | Description | | ||
| 105 | + |-----------|---------|-------------| | ||
| 106 | + | `<ip:port>` | None | Control channel address (`tcp://ip:port` format) that rank 0 listens on, used for root info exchange and Host-side barriers; use different ports when running multiple instances in parallel | | ||
| 107 | + | `<nranks>` | None | Number of ranks to launch; must be >= 2 and not exceed the number of available NPUs | | ||
| 108 | + | ||
| 109 | +- Build options description | ||
| 110 | + | ||
| 111 | + | Option | Allowed Values | Description | | ||
| 112 | + |--------|----------------|-------------| | ||
| 113 | + | `CMAKE_ASC_RUN_MODE` | `npu` (default) | Execution mode; this sample only supports NPU execution | | ||
| 114 | + | `CMAKE_ASC_ARCHITECTURES` | `dav-3510` (default) | NPU architecture: `dav-3510` corresponds to Ascend 950PR / Ascend 950DT | | ||
| 115 | + | ||
| 116 | +- Expected output | ||
| 117 | + | ||
| 118 | + After a successful multi-card run, the terminal will output the following, indicating that AIV direct-drive URMA communication completed successfully (write/read results are consistent): | ||
| 119 | + | ||
| 120 | + ```text | ||
| 121 | + [rank 0] hcomm_write_read_nbi | sent to rank 1, received from rank 1 | PASS | ||
| 122 | + [rank 1] hcomm_write_read_nbi | sent to rank 0, received from rank 0 | PASS | ||
| 123 | + RESULT | Example=hcomm_write_read_nbi | Status=PASS | ||
| 124 | + ``` | ||
| 125 | + | ||
| 126 | +## Notes | ||
| 127 | + | ||
| 128 | +- Running the sample requires at least 2 NPUs; a single-card environment only supports compilation verification. | ||
| 129 | +- The UB workspace allocated by `Init()` on the Kernel side must be >= 512 bytes, used to store internal Hcomm states such as WQE/CQE. | ||
| 130 | +- `WriteNbi`/`ReadNbi` defaults to `commit=true`, triggering the doorbell immediately after enqueueing; for batch optimization, use `commit=false` to enqueue multiple tasks and call `Commit()` uniformly. Data visibility is only guaranteed after `Drain()` returns. | ||
| 131 | +- When `nranks == 2`, `prev` and `next` refer to the same peer rank, so seg1 and seg2 are validated against the same peer pattern. | ||
| 132 | +- The current sample has established P2P channels in both the `prev` and `next` directions, but only executes data-plane operations in the `next` direction by default. To extend to full all-to-neighbor communication, reuse the established `prev` channel: launch the Kernel twice, first using the `prev` channel to execute `ReadNbi` reading `prev`'s seg0 into local seg2, then using the `next` channel to execute `WriteNbi` writing local seg0 into `next`'s seg1, so that each rank's seg1 and seg2 both match `prev`'s pattern. When extending, keep the Host-side barriers before and after Kernel execution; if data segment offsets are adjusted, update the expected rank and offset used by Host-side pattern validation accordingly. | ||
Rexamples/hcomm_write_read_nbi/hcomm_rw_def.h→examples/aicore/hcomm/01_hcomm_write_read_nbi/hcomm_rw_def.h+67-66
| @@ -1,66 +1,67 @@ | |||
| 1 | -/** | 1 | +/** |
| 2 | - * Copyright (c) 2026 Huawei Technologies Co., Ltd. | 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 | 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"). | 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. | 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, | 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. | 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. | 8 | + * See LICENSE in the root of the software repository for the full text of the License. |
| 9 | - */ | 9 | + */ |
| 10 | - | 10 | + |
| 11 | -#ifndef HCOMM_RW_DEF_H | 11 | +#ifndef HCOMM_RW_DEF_H |
| 12 | -#define HCOMM_RW_DEF_H | 12 | +#define HCOMM_RW_DEF_H |
| 13 | - | 13 | + |
| 14 | -#include <cstdint> | 14 | +#include <cstdint> |
| 15 | - | 15 | + |
| 16 | -#include "adv_api/hcomm/hcomm.h" | 16 | +#include "adv_api/hcomm/hcomm.h" |
| 17 | -#include "hccl/hccl.h" | 17 | +#include "hccl/hccl.h" |
| 18 | -#include "hccl/hccl_comm.h" | 18 | + |
| 19 | - | 19 | +// Host侧流程的返回值与错误检查宏(原TCP环工具utils.h中仅剩的被使用部分)。 |
| 20 | -constexpr uint32_t DATA_SIZE = 256U; | 20 | +constexpr int32_t SUCCESS = 0; |
| 21 | -constexpr uint64_t COMM_BUF_SIZE = 4096U; | 21 | +constexpr int32_t FAIL = -1; |
| 22 | -constexpr uint64_t SEND_DATA_OFFSET = 0U; | 22 | + |
| 23 | -constexpr uint64_t WRITE_RESULT_OFFSET = DATA_SIZE; | 23 | +constexpr uint32_t DATA_SIZE = 256U; |
| 24 | -constexpr uint64_t READ_RESULT_OFFSET = 2U * DATA_SIZE; | 24 | +constexpr uint64_t COMM_BUF_SIZE = 4096U; |
| 25 | - | 25 | +constexpr uint64_t SEND_DATA_OFFSET = 0U; |
| 26 | -constexpr uint32_t NRANKS = 2U; | 26 | +constexpr uint64_t WRITE_RESULT_OFFSET = DATA_SIZE; |
| 27 | -constexpr uint16_t BASE_PORT = 29620U; | 27 | +constexpr uint64_t READ_RESULT_OFFSET = 2U * DATA_SIZE; |
| 28 | -constexpr uint32_t ROOT_SERVER_RANK = 0U; | 28 | + |
| 29 | -constexpr CommProtocol HOST_COMM_PROTOCOL = COMM_PROTOCOL_UB_CTP; | 29 | +constexpr uint32_t NRANKS = 2U; |
| 30 | -constexpr AscendC::CommProtocol KERNEL_COMM_PROTOCOL = AscendC::COMM_PROTOCOL_UB_CTP; | 30 | +constexpr CommProtocol HOST_COMM_PROTOCOL = COMM_PROTOCOL_UB_CTP; |
| 31 | -static_assert( | 31 | +constexpr AscendC::CommProtocol KERNEL_COMM_PROTOCOL = AscendC::COMM_PROTOCOL_UB_CTP; |
| 32 | - static_cast<int32_t>(HOST_COMM_PROTOCOL) == static_cast<int32_t>(KERNEL_COMM_PROTOCOL), | 32 | +static_assert( |
| 33 | - "Host and Kernel communication protocols must match"); | 33 | + static_cast<int32_t>(HOST_COMM_PROTOCOL) == static_cast<int32_t>(KERNEL_COMM_PROTOCOL), |
| 34 | -constexpr uint32_t HCOMM_WORKSPACE_SIZE = 512U; | 34 | + "Host and Kernel communication protocols must match"); |
| 35 | - | 35 | +constexpr uint32_t HCOMM_WORKSPACE_SIZE = 512U; |
| 36 | -enum TestResult : uint32_t { | 36 | + |
| 37 | - TEST_SUCCESS = 0U, | 37 | +enum TestResult : uint32_t { |
| 38 | - TEST_HCOMM_INIT_FAILED = 1U, | 38 | + TEST_SUCCESS = 0U, |
| 39 | - TEST_WRITE_FAILED = 2U, | 39 | + TEST_HCOMM_INIT_FAILED = 1U, |
| 40 | - TEST_READ_FAILED = 3U, | 40 | + TEST_WRITE_FAILED = 2U, |
| 41 | - TEST_DRAIN_FAILED = 4U, | 41 | + TEST_READ_FAILED = 3U, |
| 42 | -}; | 42 | + TEST_DRAIN_FAILED = 4U, |
| 43 | -static_assert(sizeof(TestResult) == sizeof(uint32_t), "TestResult must remain uint32_t-sized"); | 43 | +}; |
| 44 | - | 44 | +static_assert(sizeof(TestResult) == sizeof(uint32_t), "TestResult must remain uint32_t-sized"); |
| 45 | -constexpr uint32_t HCOMM_READ_ONLY = 0x01U; | 45 | + |
| 46 | -constexpr uint32_t HCOMM_WRITE_ONLY = 0x02U; | 46 | +constexpr uint32_t HCOMM_READ_ONLY = 0x01U; |
| 47 | -constexpr uint32_t HCOMM_READ_WRITE = HCOMM_READ_ONLY | HCOMM_WRITE_ONLY; | 47 | +constexpr uint32_t HCOMM_WRITE_ONLY = 0x02U; |
| 48 | - | 48 | +constexpr uint32_t HCOMM_READ_WRITE = HCOMM_READ_ONLY | HCOMM_WRITE_ONLY; |
| 49 | -namespace HcommExample { | 49 | + |
| 50 | - | 50 | +namespace HcommExample { |
| 51 | -struct CommContext { | 51 | + |
| 52 | - uint64_t channelHandle; | 52 | +struct CommContext { |
| 53 | - uint64_t localBufferAddr; | 53 | + uint64_t channelHandle; |
| 54 | - uint64_t remoteBufferAddr; | 54 | + uint64_t localBufferAddr; |
| 55 | - TestResult testResult; | 55 | + uint64_t remoteBufferAddr; |
| 56 | -}; | 56 | + TestResult testResult; |
| 57 | - | 57 | +}; |
| 58 | -} // namespace HcommExample | 58 | + |
| 59 | - | 59 | +} // namespace HcommExample |
| 60 | -extern "C" __vector__ __global__ __aicore__ void kernel_hcomm_read_nbi(GM_ADDR context); | 60 | + |
| 61 | - | 61 | +extern "C" __vector__ __global__ __aicore__ void kernel_hcomm_read_nbi(GM_ADDR context); |
| 62 | -extern "C" __vector__ __global__ __aicore__ void kernel_hcomm_write_nbi(GM_ADDR context); | 62 | + |
| 63 | - | 63 | +extern "C" __vector__ __global__ __aicore__ void kernel_hcomm_write_nbi(GM_ADDR context); |
| 64 | -extern "C" __vector__ __global__ __aicore__ void kernel_hcomm_write_read_nbi(GM_ADDR context); | 64 | + |
| 65 | - | 65 | +extern "C" __vector__ __global__ __aicore__ void kernel_hcomm_write_read_nbi(GM_ADDR context); |
| 66 | -#endif // HCOMM_RW_DEF_H | 66 | + |
| 67 | +#endif // HCOMM_RW_DEF_H | ||
Rexamples/hcomm_write_read_nbi/hcomm_write_read_nbi.asc→examples/aicore/hcomm/01_hcomm_write_read_nbi/hcomm_write_read_nbi.asc+445-504
Rexamples/hcomm_write_read_nbi/hcomm_write_read_nbi_kernel.cpp→examples/aicore/hcomm/01_hcomm_write_read_nbi/hcomm_write_read_nbi_kernel.cpp+0-0
文件重命名但无更改。
Rexamples/hcomm_batch_write/CMakeLists.txt→examples/aicore/hcomm/02_hcomm_batch_write/CMakeLists.txt+14-29
| @@ -11,52 +11,37 @@ | |||
| 11 | cmake_minimum_required(VERSION 3.16) | 11 | cmake_minimum_required(VERSION 3.16) |
| 12 | 12 | ||
| 13 | set(CMAKE_ASC_ARCHITECTURES "dav-3510" CACHE STRING "NPU architecture: dav-3510") | 13 | set(CMAKE_ASC_ARCHITECTURES "dav-3510" CACHE STRING "NPU architecture: dav-3510") |
| 14 | -if(NOT CMAKE_ASC_ARCHITECTURES STREQUAL "dav-3510") | ||
| 15 | - message(FATAL_ERROR "hcomm_batch_write only supports dav-3510, but got ${CMAKE_ASC_ARCHITECTURES}") | ||
| 16 | -endif() | ||
| 17 | 14 | ||
| 18 | find_package(ASC REQUIRED) | 15 | find_package(ASC REQUIRED) |
| 19 | project(hcomm_batch_write LANGUAGES ASC CXX) | 16 | project(hcomm_batch_write LANGUAGES ASC CXX) |
| 20 | 17 | ||
| 21 | -set(CMAKE_CXX_STANDARD 17) | 18 | +set_source_files_properties(hcomm_batch_write_kernel.cpp PROPERTIES LANGUAGE ASC) |
| 22 | -set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||
| 23 | - | ||
| 24 | -if(NOT ASCEND_CANN_PACKAGE_LINUX_PATH) | ||
| 25 | - if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64") | ||
| 26 | - set(ASCEND_CANN_PACKAGE_LINUX_PATH "${ASCEND_CANN_PACKAGE_PATH}/x86_64-linux") | ||
| 27 | - else() | ||
| 28 | - set(ASCEND_CANN_PACKAGE_LINUX_PATH "${ASCEND_CANN_PACKAGE_PATH}/aarch64-linux") | ||
| 29 | - endif() | ||
| 30 | -endif() | ||
| 31 | - | ||
| 32 | -set_source_files_properties( | ||
| 33 | - hcomm_batch_write_kernel.cpp | ||
| 34 | - PROPERTIES LANGUAGE ASC | ||
| 35 | -) | ||
| 36 | 19 | ||
| 37 | add_executable(hcomm_batch_write | 20 | add_executable(hcomm_batch_write |
| 38 | hcomm_batch_write.asc | 21 | hcomm_batch_write.asc |
| 39 | hcomm_batch_write_kernel.cpp | 22 | hcomm_batch_write_kernel.cpp |
| 40 | ) | 23 | ) |
| 41 | 24 | ||
| 25 | +set_target_properties(hcomm_batch_write PROPERTIES | ||
| 26 | + LINKER_LANGUAGE ASC | ||
| 27 | +) | ||
| 28 | + | ||
| 42 | target_include_directories(hcomm_batch_write PRIVATE | 29 | target_include_directories(hcomm_batch_write PRIVATE |
| 43 | - "${ASCEND_CANN_PACKAGE_LINUX_PATH}/pkg_inc" | 30 | + ${CMAKE_CURRENT_SOURCE_DIR} |
| 44 | - "${ASCEND_CANN_PACKAGE_LINUX_PATH}/include" | 31 | + ${CMAKE_CURRENT_SOURCE_DIR}/../.. |
| 45 | - "${ASCEND_CANN_PACKAGE_LINUX_PATH}/include/hcomm" | 32 | + $ENV{ASCEND_HOME_PATH}/asc/include/comm_api |
| 46 | - "${ASCEND_CANN_PACKAGE_LINUX_PATH}/asc/include/adv_api" | ||
| 47 | ) | 33 | ) |
| 48 | 34 | ||
| 49 | target_link_directories(hcomm_batch_write PRIVATE | 35 | target_link_directories(hcomm_batch_write PRIVATE |
| 50 | - "${ASCEND_CANN_PACKAGE_PATH}/lib64" | 36 | + $ENV{ASCEND_HOME_PATH}/lib64 |
| 51 | - "${ASCEND_CANN_PACKAGE_LINUX_PATH}/lib64" | 37 | + $ENV{ASCEND_HOME_PATH}/${CMAKE_SYSTEM_PROCESSOR}-linux/lib64 |
| 52 | ) | 38 | ) |
| 53 | 39 | ||
| 54 | -target_link_libraries(hcomm_batch_write PRIVATE hcomm) | 40 | +target_link_libraries(hcomm_batch_write PRIVATE |
| 41 | + hcomm | ||
| 42 | + hccl | ||
| 43 | +) | ||
| 55 | 44 | ||
| 56 | target_compile_options(hcomm_batch_write PRIVATE | 45 | target_compile_options(hcomm_batch_write PRIVATE |
| 57 | $<$<COMPILE_LANGUAGE:ASC>:--npu-arch=${CMAKE_ASC_ARCHITECTURES}> | 46 | $<$<COMPILE_LANGUAGE:ASC>:--npu-arch=${CMAKE_ASC_ARCHITECTURES}> |
| 58 | ) | 47 | ) |
| 59 | - | ||
| 60 | -set_target_properties(hcomm_batch_write PROPERTIES | ||
| 61 | - BUILD_RPATH "${ASCEND_CANN_PACKAGE_PATH}/lib64;${ASCEND_CANN_PACKAGE_LINUX_PATH}/lib64" | ||
| 62 | -) | ||
| @@ -0,0 +1,112 @@ | |||
| 1 | +# Hcomm Batch Write样例 | ||
| 2 | + | ||
| 3 | +## 概述 | ||
| 4 | + | ||
| 5 | +本样例演示如何使用Hcomm批量写接口,在单机多卡环境中由rank 0向其他rank批量写入数据。多个URMA | ||
| 6 | +Channel共享同一个Jetty,通过`MakeBatchHandle`、`GetHandleRef`、`BatchCommit`和`Drain`批量提交 | ||
| 7 | +跨peer写任务。程序会准备待发送数据,提交一批写操作并等待完成;接收rank随后校验收到的数据,主进程 | ||
| 8 | +最后汇总所有rank的执行结果。 | ||
| 9 | + | ||
| 10 | +## 本样例支持的产品及CANN软件版本 | ||
| 11 | + | ||
| 12 | +| 产品 | CANN软件版本 | | ||
| 13 | +| --- | --- | | ||
| 14 | +| Ascend 950PR/Ascend 950DT | >= CANN 9.1.0 | | ||
| 15 | + | ||
| 16 | +## 目录结构介绍 | ||
| 17 | + | ||
| 18 | +```text | ||
| 19 | +hcomm_batch_write | ||
| 20 | +├── CMakeLists.txt // 编译工程文件 | ||
| 21 | +├── hcomm_batch_write.asc // Host侧资源准备与Kernel调用 | ||
| 22 | +├── hcomm_batch_write_kernel.cpp // AIV Kernel侧批量写调用 | ||
| 23 | +├── hcomm_batch_write_def.h // Host与Kernel共享定义 | ||
| 24 | +├── README.md // 中文样例说明 | ||
| 25 | +└── README_en.md // 英文样例说明 | ||
| 26 | +``` | ||
| 27 | + | ||
| 28 | +## 样例描述 | ||
| 29 | + | ||
| 30 | +### 功能说明 | ||
| 31 | + | ||
| 32 | +rank 0将一段本端数据通过批量写接口同时写入其他所有rank的接收缓冲区。批量提交将多个写任务打包为 | ||
| 33 | +一个batch handle,通过一次`BatchCommit`统一下发,减少提交次数;`Drain`等待整批任务完成后,各 | ||
| 34 | +接收rank校验落地的数据是否与本端发送数据一致。 | ||
| 35 | + | ||
| 36 | +### 样例规格 | ||
| 37 | + | ||
| 38 | +| 项目 | 说明 | | ||
| 39 | +| --- | --- | | ||
| 40 | +| 通信模式 | rank 0到其他所有rank的一对多批量写 | | ||
| 41 | +| 调用方式 | AIV Kernel内`MakeBatchHandle`/`GetHandleRef`/`BatchCommit`/`Drain` | | ||
| 42 | +| 数据校验 | 每个接收rank校验落地数据 | | ||
| 43 | +| 支持rank数 | 2至16,且不超过本机可用NPU数量 | | ||
| 44 | + | ||
| 45 | +### 实现流程 | ||
| 46 | + | ||
| 47 | +1. 可执行文件直接拉起全部rank进程(进程内fork,参见`examples/aicore/utils/process_manager.h`); | ||
| 48 | + rank间通过命令行指定的TCP控制通道(`examples/aicore/utils/rank_sync.h`)交换root info并 | ||
| 49 | + 创建通信域,rank 0准备待发送数据。 | ||
| 50 | +2. 各rank注册通信内存并通过控制通道交换缓冲区地址,rank 0与每个peer建立共享Jetty的URMA Channel。 | ||
| 51 | +3. Kernel侧构造batch handle,为每个peer填充一个写任务引用后统一`BatchCommit`。 | ||
| 52 | +4. `Drain`等待整批任务完成。 | ||
| 53 | +5. 各接收rank校验落地数据,主进程汇总所有rank的执行结果。 | ||
| 54 | + | ||
| 55 | +## 编译运行 | ||
| 56 | + | ||
| 57 | +在本样例根目录下执行如下步骤,编译并运行样例。本样例仅支持NPU运行模式。 | ||
| 58 | + | ||
| 59 | +- 配置环境变量 | ||
| 60 | + | ||
| 61 | + 请根据当前环境上CANN开发套件包的安装方式配置环境变量。 | ||
| 62 | + | ||
| 63 | + ```bash | ||
| 64 | + source ${install_path}/cann/set_env.sh | ||
| 65 | + ``` | ||
| 66 | + | ||
| 67 | + > **说明:** `${install_path}`为CANN包安装目录,未指定安装目录时默认安装至`/usr/local/Ascend`。 | ||
| 68 | + | ||
| 69 | +- 样例执行 | ||
| 70 | + | ||
| 71 | + 在本样例目录下执行如下命令。可执行文件内部fork出全部rank进程,直接运行即可。 | ||
| 72 | + | ||
| 73 | + ```bash | ||
| 74 | + mkdir -p build | ||
| 75 | + cd build | ||
| 76 | + cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. | ||
| 77 | + make -j | ||
| 78 | + cd .. && ./build/hcomm_batch_write tcp://127.0.0.1:29624 <rank_num> | ||
| 79 | + ``` | ||
| 80 | + | ||
| 81 | +- 启动参数说明 | ||
| 82 | + | ||
| 83 | + | 参数 | 默认值 | 说明 | | ||
| 84 | + | --- | --- | --- | | ||
| 85 | + | `<ip:port>` | 无默认 | rank 0监听的控制通道地址(`tcp://ip:port`格式),用于root info交换与Host侧barrier;并行运行多个实例时错开端口 | | ||
| 86 | + | `<rank_num>` | 无默认 | 启动的rank数量,取值范围`2-16`,不能超过本机可用NPU数量 | | ||
| 87 | + | ||
| 88 | +- 编译选项说明 | ||
| 89 | + | ||
| 90 | + | 选项 | 可选值 | 说明 | | ||
| 91 | + | --- | --- | --- | | ||
| 92 | + | `CMAKE_ASC_RUN_MODE` | `npu`(默认) | 运行模式,本样例仅支持NPU运行 | | ||
| 93 | + | `CMAKE_ASC_ARCHITECTURES` | `dav-3510` | NPU架构,对应Ascend 950PR/Ascend 950DT | | ||
| 94 | + | ||
| 95 | +- 执行结果 | ||
| 96 | + | ||
| 97 | + 4卡运行成功时,每个接收rank输出校验通过信息,主进程最终输出: | ||
| 98 | + | ||
| 99 | + ```text | ||
| 100 | + [rank 1] hcomm_batch_write | received and verified data from rank 0 | PASS | ||
| 101 | + [rank 2] hcomm_batch_write | received and verified data from rank 0 | PASS | ||
| 102 | + [rank 3] hcomm_batch_write | received and verified data from rank 0 | PASS | ||
| 103 | + RESULT | Example=hcomm_batch_write | Status=PASS | ||
| 104 | + ``` | ||
| 105 | + | ||
| 106 | + 主进程输出`Status=FAIL`或任一rank报错时,表示本次批量写入或数据校验未通过。 | ||
| 107 | + | ||
| 108 | +## 注意事项 | ||
| 109 | + | ||
| 110 | +- 运行样例需要至少2张NPU;单卡环境仅支持编译验证。 | ||
| 111 | +- rank数量不能超过本机可用NPU数量,且运行用户需具备设备访问权限。 | ||
| 112 | +- 编译依赖CANN ASC CMake能力,并在链接阶段依赖CANN `hcomm`库。 | ||
Rexamples/hcomm_batch_write/README_en.md→examples/aicore/hcomm/02_hcomm_batch_write/README_en.md+10-13
| @@ -23,17 +23,11 @@ source ${install_path}/cann/set_env.sh | |||
| 23 | Build and run with two NPUs by default, or pass a rank count from `2` to `16`: | 23 | Build and run with two NPUs by default, or pass a rank count from `2` to `16`: |
| 24 | 24 | ||
| 25 | ```bash | 25 | ```bash |
| 26 | -bash examples/hcomm_batch_write/run.sh | 26 | +mkdir -p build |
| 27 | -bash examples/hcomm_batch_write/run.sh 4 | 27 | +cd build |
| 28 | -``` | 28 | +cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. |
| 29 | - | 29 | +make -j |
| 30 | -To build and run manually: | 30 | +cd .. && ./build/hcomm_batch_write tcp://127.0.0.1:29624 4 |
| 31 | - | ||
| 32 | -```bash | ||
| 33 | -cmake -S examples/hcomm_batch_write -B build/examples/hcomm_batch_write \ | ||
| 34 | - -DCMAKE_ASC_ARCHITECTURES=dav-3510 | ||
| 35 | -cmake --build build/examples/hcomm_batch_write -j | ||
| 36 | -./build/examples/hcomm_batch_write/hcomm_batch_write 4 | ||
| 37 | ``` | 31 | ``` |
| 38 | 32 | ||
| 39 | The final command starts four ranks. Before running, make sure the requested number of NPUs is available and that the current user can access them. | 33 | The final command starts four ranks. Before running, make sure the requested number of NPUs is available and that the current user can access them. |
| @@ -43,7 +37,10 @@ The final command starts four ranks. Before running, make sure the requested num | |||
| 43 | Each receiving rank prints a verification message when its data is correct. A successful four-rank run ends with: | 37 | Each receiving rank prints a verification message when its data is correct. A successful four-rank run ends with: |
| 44 | 38 | ||
| 45 | ```text | 39 | ```text |
| 46 | -hcomm 4-rank grouped batch write test passed | 40 | +[rank 1] hcomm_batch_write | received and verified data from rank 0 | PASS |
| 41 | +[rank 2] hcomm_batch_write | received and verified data from rank 0 | PASS | ||
| 42 | +[rank 3] hcomm_batch_write | received and verified data from rank 0 | PASS | ||
| 43 | +RESULT | Example=hcomm_batch_write | Status=PASS | ||
| 47 | ``` | 44 | ``` |
| 48 | 45 | ||
| 49 | -`failed` in the parent-process summary or an error from any rank means that the batch write or data verification did not complete successfully. | 46 | +`Status=FAIL` in the parent-process summary or an error from any rank means that the batch write or data verification did not complete successfully. |
Rexamples/hcomm_batch_write/hcomm_batch_write.asc→examples/aicore/hcomm/02_hcomm_batch_write/hcomm_batch_write.asc+82-258
| @@ -14,14 +14,9 @@ | |||
| 14 | #include <cstring> | 14 | #include <cstring> |
| 15 | #include <signal.h> | 15 | #include <signal.h> |
| 16 | #include <string> | 16 | #include <string> |
| 17 | -#include <sys/socket.h> | ||
| 18 | -#include <sys/time.h> | ||
| 19 | -#include <sys/wait.h> | ||
| 20 | -#include <unistd.h> | ||
| 21 | #include <vector> | 17 | #include <vector> |
| 22 | 18 | ||
| 23 | #include "acl/acl.h" | 19 | #include "acl/acl.h" |
| 24 | -#include "acl/acl_rt.h" | ||
| 25 | #include "hccl/hccl_res.h" | 20 | #include "hccl/hccl_res.h" |
| 26 | #include "hccl/hccl.h" | 21 | #include "hccl/hccl.h" |
| 27 | #include "hccl/hccl_comm.h" | 22 | #include "hccl/hccl_comm.h" |
Rexamples/hcomm_batch_write/hcomm_batch_write_def.h→examples/aicore/hcomm/02_hcomm_batch_write/hcomm_batch_write_def.h+0-0
文件重命名但无更改。
Rexamples/hcomm_batch_write/hcomm_batch_write_kernel.cpp→examples/aicore/hcomm/02_hcomm_batch_write/hcomm_batch_write_kernel.cpp+0-0
文件重命名但无更改。
Rexamples/one_multi_path/CMakeLists.txt→examples/aicore/hcomm/03_one_multi_path/CMakeLists.txt+16-17
| @@ -10,24 +10,11 @@ | |||
| 10 | 10 | ||
| 11 | cmake_minimum_required(VERSION 3.16) | 11 | cmake_minimum_required(VERSION 3.16) |
| 12 | 12 | ||
| 13 | -set(CMAKE_ASC_RUN_MODE "npu" CACHE STRING "Run mode: npu, sim") | ||
| 14 | set(CMAKE_ASC_ARCHITECTURES "dav-3510" CACHE STRING "NPU architecture: dav-3510") | 13 | set(CMAKE_ASC_ARCHITECTURES "dav-3510" CACHE STRING "NPU architecture: dav-3510") |
| 15 | 14 | ||
| 16 | find_package(ASC REQUIRED) | 15 | find_package(ASC REQUIRED) |
| 17 | - | ||
| 18 | project(one_multi_path LANGUAGES ASC CXX) | 16 | project(one_multi_path LANGUAGES ASC CXX) |
| 19 | 17 | ||
| 20 | -set(CMAKE_CXX_STANDARD 17) | ||
| 21 | -set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||
| 22 | - | ||
| 23 | -if(NOT DEFINED ASCEND_HOME_PATH) | ||
| 24 | - if(DEFINED ENV{ASCEND_HOME_PATH}) | ||
| 25 | - set(ASCEND_HOME_PATH $ENV{ASCEND_HOME_PATH}) | ||
| 26 | - else() | ||
| 27 | - set(ASCEND_HOME_PATH /usr/local/Ascend/ascend-toolkit/latest) | ||
| 28 | - endif() | ||
| 29 | -endif() | ||
| 30 | - | ||
| 31 | add_executable(one_multi_path | 18 | add_executable(one_multi_path |
| 32 | main.cpp | 19 | main.cpp |
| 33 | ubmem_data_copy.asc | 20 | ubmem_data_copy.asc |
| @@ -38,15 +25,27 @@ set_target_properties(one_multi_path PROPERTIES | |||
| 38 | ) | 25 | ) |
| 39 | 26 | ||
| 40 | target_include_directories(one_multi_path PRIVATE | 27 | target_include_directories(one_multi_path PRIVATE |
| 41 | - ${ASCEND_HOME_PATH}/include | 28 | + ${CMAKE_CURRENT_SOURCE_DIR} |
| 29 | + ${CMAKE_CURRENT_SOURCE_DIR}/../.. | ||
| 30 | + $ENV{ASCEND_HOME_PATH}/include | ||
| 42 | ) | 31 | ) |
| 43 | 32 | ||
| 44 | target_link_directories(one_multi_path PRIVATE | 33 | target_link_directories(one_multi_path PRIVATE |
| 45 | - ${ASCEND_HOME_PATH}/lib64 | 34 | + $ENV{ASCEND_HOME_PATH}/lib64 |
| 46 | - ${ASCEND_HOME_PATH}/runtime/lib64 | 35 | + $ENV{ASCEND_HOME_PATH}/${CMAKE_SYSTEM_PROCESSOR}-linux/lib64 |
| 47 | ) | 36 | ) |
| 48 | 37 | ||
| 49 | -target_link_libraries(one_multi_path PRIVATE hccl hcomm ascendcl c_sec pthread) | 38 | +target_link_libraries(one_multi_path PRIVATE |
| 39 | + hcomm | ||
| 40 | + hccl | ||
| 41 | + ascendcl | ||
| 42 | + acl_rt | ||
| 43 | + runtime | ||
| 44 | + c_sec | ||
| 45 | + stdc++ | ||
| 46 | + dl | ||
| 47 | + pthread | ||
| 48 | +) | ||
| 50 | 49 | ||
| 51 | target_compile_options(one_multi_path PRIVATE | 50 | target_compile_options(one_multi_path PRIVATE |
| 52 | $<$<COMPILE_LANGUAGE:ASC>:--npu-arch=${CMAKE_ASC_ARCHITECTURES}> | 51 | $<$<COMPILE_LANGUAGE:ASC>:--npu-arch=${CMAKE_ASC_ARCHITECTURES}> |
| @@ -2,11 +2,13 @@ | |||
| 2 | 2 | ||
| 3 | ## 概述 | 3 | ## 概述 |
| 4 | 4 | ||
| 5 | -本样例演示如何通过HCCL Resource API查询`COMM_PROTOCOL_UB_MEM`链路,在同一个通信域中为每个peer创建`pathMode=1`和`pathMode=2`两条Channel。各peer按顺序处理;处理单个peer时,通过两个Stream并发搬运 | 5 | +本样例演示如何通过HCCL Resource API查询`COMM_PROTOCOL_UB_MEM`链路,在同一个通信域中为每个peer |
| 6 | -不同的数据分片。 | 6 | +创建`pathMode=1`和`pathMode=2`两条Channel。各peer按顺序处理;处理单个peer时,通过两个Stream |
| 7 | +并发搬运不同的数据分片。 | ||
| 7 | 8 | ||
| 8 | -样例采用一进程一Device的运行方式。每个rank使用自己的rank ID填充本端HCCL Buffer,再从其他rank读取 | 9 | +样例采用一进程一Device的运行方式。每个rank使用自己的rank ID填充本端HCCL Buffer,再从其他rank |
| 9 | -4 KB数据并校验。`run.sh`负责启动本机rank进程,rank 0进程负责分发`HcclRootInfo`。 | 10 | +读取4 KB数据并校验。可执行文件直接拉起本机全部rank进程;多机部署时每台机器各起一个进程, |
| 11 | +rank 0进程负责分发`HcclRootInfo`。 | ||
| 10 | 12 | ||
| 11 | ## 本样例支持的产品及CANN软件版本 | 13 | ## 本样例支持的产品及CANN软件版本 |
| 12 | 14 | ||
| @@ -18,20 +20,20 @@ | |||
| 18 | 20 | ||
| 19 | ```text | 21 | ```text |
| 20 | one_multi_path | 22 | one_multi_path |
| 21 | -├── CMakeLists.txt // 编译工程文件 | 23 | +├── CMakeLists.txt // 编译工程文件 |
| 22 | -├── main.cpp // Host侧通信域、Channel和校验流程 | 24 | +├── main.cpp // Host侧通信域、Channel和校验流程 |
| 23 | -├── README.md // 中文样例说明 | 25 | +├── ubmem_data_copy.asc // Ascend C数据搬运Kernel |
| 24 | -├── README_en.md // 英文样例说明 | 26 | +├── README.md // 中文样例说明 |
| 25 | -├── run.sh // 多rank启动脚本 | 27 | +└── README_en.md // 英文样例说明 |
| 26 | -└── ubmem_data_copy.asc // Ascend C数据搬运Kernel | ||
| 27 | ``` | 28 | ``` |
| 28 | 29 | ||
| 29 | ## 样例描述 | 30 | ## 样例描述 |
| 30 | 31 | ||
| 31 | ### 功能说明 | 32 | ### 功能说明 |
| 32 | 33 | ||
| 33 | -每个rank先获取本端HCCL Buffer,并使用自己的rank ID填充前4 KB。Channel创建完成后,每个rank通过每个 | 34 | +每个rank先获取本端HCCL Buffer,并使用自己的rank ID填充前4 KB。Channel创建完成后,每个rank |
| 34 | -peer对应的两条Channel读取对端HCCL Buffer,将读取结果写入本端校验Buffer,最后拷贝到Host侧逐字节校验。 | 35 | +通过每个peer对应的两条Channel读取对端HCCL Buffer,将读取结果写入本端校验Buffer,最后拷贝到 |
| 36 | +Host侧逐字节校验。 | ||
| 35 | 37 | ||
| 36 | ```text | 38 | ```text |
| 37 | 对端HCCL Buffer -> UB_MEM链路 -> Ascend C DataCopy -> 本端校验Buffer -> Host校验 | 39 | 对端HCCL Buffer -> UB_MEM链路 -> Ascend C DataCopy -> 本端校验Buffer -> Host校验 |
| @@ -44,19 +46,28 @@ peer对应的两条Channel读取对端HCCL Buffer,将读取结果写入本端 | |||
| 44 | | 1 | `COMM_PROTOCOL_UB_MEM` | `1` | one path | 前2 KB | | 46 | | 1 | `COMM_PROTOCOL_UB_MEM` | `1` | one path | 前2 KB | |
| 45 | | 2 | `COMM_PROTOCOL_UB_MEM` | `2` | multi path | 后2 KB | | 47 | | 2 | `COMM_PROTOCOL_UB_MEM` | `2` | multi path | 后2 KB | |
| 46 | 48 | ||
| 49 | +### 样例规格 | ||
| 50 | + | ||
| 51 | +| 项目 | 说明 | | ||
| 52 | +| --- | --- | | ||
| 53 | +| 通信模式 | 每peer两条`COMM_PROTOCOL_UB_MEM`路径(one path/multi path)并发读取 | | ||
| 54 | +| 调用方式 | Host侧Resource API创建Channel + Ascend C DataCopy Kernel | | ||
| 55 | +| 数据规模 | 每peer读取4 KB(两条path各2 KB) | | ||
| 56 | +| 部署形态 | 单机多卡/多机多卡 | | ||
| 57 | + | ||
| 47 | ### 实现流程 | 58 | ### 实现流程 |
| 48 | 59 | ||
| 49 | -1. rank 0生成并分发一份`HcclRootInfo`,各rank初始化同一个通信域。 | 60 | +1. 可执行文件直接拉起本机rank进程(进程内fork,参见`examples/aicore/utils/process_manager.h`); |
| 61 | + rank间通过命令行指定的TCP控制通道(`examples/aicore/utils/rank_sync.h`)交换`HcclRootInfo`, | ||
| 62 | + 各rank初始化同一个通信域。 | ||
| 50 | 2. 每个rank获取本端HCCL Buffer并写入rank ID,再通过`HcclCommMemReg`注册Channel所需的内存资源。 | 63 | 2. 每个rank获取本端HCCL Buffer并写入rank ID,再通过`HcclCommMemReg`注册Channel所需的内存资源。 |
| 51 | 3. 每个rank遍历RankGraph各层,为每个peer筛选一条`COMM_PROTOCOL_UB_MEM`链路。 | 64 | 3. 每个rank遍历RankGraph各层,为每个peer筛选一条`COMM_PROTOCOL_UB_MEM`链路。 |
| 52 | 4. 每个peer基于同一组Endpoint构造`pathMode=1`和`pathMode=2`两个描述。 | 65 | 4. 每个peer基于同一组Endpoint构造`pathMode=1`和`pathMode=2`两个描述。 |
| 53 | 5. 将所有peer的Channel描述一次性传入`HcclChannelAcquire`,批量创建Channel。 | 66 | 5. 将所有peer的Channel描述一次性传入`HcclChannelAcquire`,批量创建Channel。 |
| 54 | -6. 各peer按顺序处理;单个peer的两条Channel分别在两个Stream上读取前后两个2 KB分片,两个Kernel均下发后 | 67 | +6. 各peer按顺序处理;单个peer的两条Channel分别在两个Stream上读取前后两个2 KB分片,两个Kernel |
| 55 | - 再同步Stream,因此并发范围仅限同一peer的两条path。 | 68 | + 均下发后再同步Stream,因此并发范围仅限同一peer的两条path。 |
| 56 | 7. 将本端校验Buffer拷贝到Host,检查每个字节是否等于对端rank ID。 | 69 | 7. 将本端校验Buffer拷贝到Host,检查每个字节是否等于对端rank ID。 |
| 57 | -8. 所有peer的数据校验完成后执行`HcclBarrier`,确保全部rank完成远端读取后再销毁通信资源。 | 70 | +8. 所有peer的数据校验完成后通过控制通道barrier同步,确保全部rank完成远端读取后再销毁通信资源。 |
| 58 | - | ||
| 59 | -`rank_graph_topo`日志只显示所选UB_MEM链路所在的RankGraph层,不参与`pathMode`选择。 | ||
| 60 | 71 | ||
| 61 | ## 编译运行 | 72 | ## 编译运行 |
| 62 | 73 | ||
| @@ -64,8 +75,7 @@ peer对应的两条Channel读取对端HCCL Buffer,将读取结果写入本端 | |||
| 64 | 75 | ||
| 65 | - 配置环境变量 | 76 | - 配置环境变量 |
| 66 | 77 | ||
| 67 | - 请根据当前环境上CANN开发套件包的[安装方式](../../docs/quick_start.md)配置 | 78 | + 请根据当前环境上CANN开发套件包的[安装方式](../../../../docs/quick_start.md)配置环境变量。 |
| 68 | - 环境变量。 | ||
| 69 | 79 | ||
| 70 | ```bash | 80 | ```bash |
| 71 | source ${install_path}/cann/set_env.sh | 81 | source ${install_path}/cann/set_env.sh |
| @@ -75,38 +85,55 @@ peer对应的两条Channel读取对端HCCL Buffer,将读取结果写入本端 | |||
| 75 | 85 | ||
| 76 | - 单机两卡运行 | 86 | - 单机两卡运行 |
| 77 | 87 | ||
| 78 | - 默认启动两个进程,分别使用Device 0和Device 1。 | 88 | + 可执行文件内部fork出全部rank进程,Device与rank一一对应: |
| 79 | 89 | ||
| 80 | ```bash | 90 | ```bash |
| 81 | - cmake -S . -B build -DCMAKE_ASC_ARCHITECTURES=dav-3510 | 91 | + mkdir -p build |
| 82 | - cmake --build build -j | 92 | + cd build |
| 83 | - bash run.sh | 93 | + cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. |
| 94 | + make -j | ||
| 95 | + cd .. && ./build/one_multi_path tcp://127.0.0.1:29625 <nranks> | ||
| 84 | ``` | 96 | ``` |
| 85 | 97 | ||
| 86 | - 启动参数说明 | 98 | - 启动参数说明 |
| 87 | 99 | ||
| 100 | + 单机模式: | ||
| 101 | + | ||
| 102 | + ```bash | ||
| 103 | + ./build/one_multi_path <ip:port> <nranks> | ||
| 104 | + ``` | ||
| 105 | + | ||
| 88 | | 参数 | 默认值 | 说明 | | 106 | | 参数 | 默认值 | 说明 | |
| 89 | | --- | --- | --- | | 107 | | --- | --- | --- | |
| 90 | - | `-pes` | `2` | 通信域中的总rank数,必须为不小于2的整数 | | 108 | + | `<ip:port>` | 无默认 | rank 0监听的控制通道地址(`tcp://ip:port`格式),用于root info交换与Host侧barrier;并行运行多个实例时错开端口 | |
| 91 | - | `-ipport` | `tcp://127.0.0.1:8899` | rank 0分发`HcclRootInfo`使用的地址;IPv6地址使用`tcp://[地址]:端口`格式 | | 109 | + | `<nranks>` | 无默认 | 通信域中的总rank数,必须为不小于2的整数,且不超过本机可用NPU数量 | |
| 92 | - | `-gnpus` | `2` | 当前机器启动的rank进程数 | | ||
| 93 | - | `-fpe` | `0` | 当前机器的起始rank ID | | ||
| 94 | - | `-fnpu` | `0` | 当前机器的起始Device ID | | ||
| 95 | 110 | ||
| 96 | - 跨机运行 | 111 | - 跨机运行 |
| 97 | 112 | ||
| 98 | - 两机各4卡、总共8卡时,先在rank 0所在机器执行第一条命令,再在另一台机器执行第二条命令: | 113 | + 多机部署时每台机器直接运行可执行文件,逐rank指定全局rank与Device: |
| 114 | + | ||
| 115 | + ```bash | ||
| 116 | + ./build/one_multi_path <ip:port> <rank_size> <rank> <device> | ||
| 117 | + ``` | ||
| 118 | + | ||
| 119 | + 两机各4卡、总共8卡时,先在rank 0所在机器执行第一条命令,再在另一台机器执行: | ||
| 99 | 120 | ||
| 100 | ```bash | 121 | ```bash |
| 101 | # 机器A:rank 0-3,Device 0-3 | 122 | # 机器A:rank 0-3,Device 0-3 |
| 102 | - bash run.sh -pes 8 -ipport tcp://<机器A_IP>:8899 -gnpus 4 -fpe 0 -fnpu 0 | 123 | + ./build/one_multi_path tcp://<机器A_IP>:8899 8 0 0 |
| 124 | + ./build/one_multi_path tcp://<机器A_IP>:8899 8 1 1 | ||
| 125 | + ./build/one_multi_path tcp://<机器A_IP>:8899 8 2 2 | ||
| 126 | + ./build/one_multi_path tcp://<机器A_IP>:8899 8 3 3 | ||
| 103 | 127 | ||
| 104 | # 机器B:rank 4-7,Device 0-3 | 128 | # 机器B:rank 4-7,Device 0-3 |
| 105 | - bash run.sh -pes 8 -ipport tcp://<机器A_IP>:8899 -gnpus 4 -fpe 4 -fnpu 0 | 129 | + ./build/one_multi_path tcp://<机器A_IP>:8899 8 4 0 |
| 130 | + ./build/one_multi_path tcp://<机器A_IP>:8899 8 5 1 | ||
| 131 | + ./build/one_multi_path tcp://<机器A_IP>:8899 8 6 2 | ||
| 132 | + ./build/one_multi_path tcp://<机器A_IP>:8899 8 7 3 | ||
| 106 | ``` | 133 | ``` |
| 107 | 134 | ||
| 108 | - 两机各8卡、总共16卡时,将`-pes`和`-gnpus`分别设置为`16`和`8`,两台机器的`-fpe`分别设置为 | 135 | + 其中`<ip:port>`统一指向rank 0所在机器;`<rank_size>`为全局rank总数,`<rank>`为本进程的全局 |
| 109 | - `0`和`8`。 | 136 | + rank,`<device>`为本机Device ID。 |
| 110 | 137 | ||
| 111 | - 编译选项说明 | 138 | - 编译选项说明 |
| 112 | 139 | ||
| @@ -120,19 +147,21 @@ peer对应的两条Channel读取对端HCCL Buffer,将读取结果写入本端 | |||
| 120 | 日志顺序可能因多进程并发而不同。每个rank都应完成到其他rank的数据校验,例如: | 147 | 日志顺序可能因多进程并发而不同。每个rank都应完成到其他rank的数据校验,例如: |
| 121 | 148 | ||
| 122 | ```text | 149 | ```text |
| 123 | - rank 0/2: device=0, channels_per_peer=2, channel_descs=2 | 150 | + [rank 0] one_multi_path | channels_per_peer=2, channel_descs=2 |
| 124 | rank 0: peer=1, rank_graph_topo=5, protocol=UB_MEM, path_modes=1/2 | 151 | rank 0: peer=1, rank_graph_topo=5, protocol=UB_MEM, path_modes=1/2 |
| 125 | rank 0: dual-path data copy from remote rank 1 passed, bytes=4096 | 152 | rank 0: dual-path data copy from remote rank 1 passed, bytes=4096 |
| 126 | - rank 0: dual-path validation passed | 153 | + [rank 0] one_multi_path | dual-path validation | PASS |
| 127 | ``` | 154 | ``` |
| 128 | 155 | ||
| 129 | - 所有rank均为每个peer取得两条不同的Channel Handle、完成数据校验且脚本返回0,表示样例执行成功。 | 156 | + 所有rank均输出`PASS`且最终输出`RESULT | Example=one_multi_path | Status=PASS`,表示样例执行成功。 |
| 130 | 157 | ||
| 131 | ## 注意事项 | 158 | ## 注意事项 |
| 132 | 159 | ||
| 133 | -- 默认场景需要Device 0和Device 1可用,且两个Device之间存在`COMM_PROTOCOL_UB_MEM`链路。 | 160 | +- 运行样例需要至少2张NPU;单卡环境仅支持编译验证。 |
| 134 | -- 多机运行时,所有机器必须使用相同的`-pes`,rank范围必须完整且不能重复。 | 161 | +- 默认场景需要Device 0和Device 1可用,且两个Device之间存在`COMM_PROTOCOL_UB_MEM`链路;出现 |
| 135 | -- `-ipport`只用于分发`HcclRootInfo`,不参与HCCL数据链路选择。 | 162 | + `no UB_MEM link found`时,表示当前rank与目标rank之间不存在可用的`COMM_PROTOCOL_UB_MEM`链路。 |
| 163 | +- `rank_graph_topo`日志只显示所选UB_MEM链路所在的RankGraph层,不参与`pathMode`选择。 | ||
| 164 | +- 多机运行时,所有机器必须使用相同的`<rank_size>`与`<ip:port>`(指向rank 0),rank范围必须 | ||
| 165 | + 完整且不能重复。 | ||
| 166 | +- `<ip:port>`控制通道只用于分发`HcclRootInfo`与Host侧同步,不参与HCCL数据链路选择。 | ||
| 136 | - `HcclChannelAcquire`失败时,可根据前序`peer`链路筛选日志定位失败范围。 | 167 | - `HcclChannelAcquire`失败时,可根据前序`peer`链路筛选日志定位失败范围。 |
| 137 | -- 出现`no UB_MEM link found`时,表示当前rank与目标rank之间不存在可用的 | ||
| 138 | - `COMM_PROTOCOL_UB_MEM`链路。 | ||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | This sample demonstrates how to query a `COMM_PROTOCOL_UB_MEM` link through HCCL Resource APIs and create two channels with `pathMode=1` and `pathMode=2` for every peer in one communication domain. Peers are processed serially; for each peer, separate data shards are copied concurrently on two streams. | 5 | This sample demonstrates how to query a `COMM_PROTOCOL_UB_MEM` link through HCCL Resource APIs and create two channels with `pathMode=1` and `pathMode=2` for every peer in one communication domain. Peers are processed serially; for each peer, separate data shards are copied concurrently on two streams. |
| 6 | 6 | ||
| 7 | -The sample uses one process per device. Each rank fills its local HCCL Buffer with its rank ID, reads 4 KB from every peer, and verifies the data. `run.sh` starts the local rank processes, and rank 0 distributes | 7 | +The sample uses one process per device. Each rank fills its local HCCL Buffer with its rank ID, reads 4 KB from every peer, and verifies the data. The executable forks all local rank processes internally, and rank 0 distributes |
| 8 | `HcclRootInfo`. | 8 | `HcclRootInfo`. |
| 9 | 9 | ||
| 10 | ## Supported Products and CANN Software Versions | 10 | ## Supported Products and CANN Software Versions |
| @@ -21,7 +21,6 @@ one_multi_path | |||
| 21 | ├── main.cpp // Host-side communication domain, channel, and verification flow | 21 | ├── main.cpp // Host-side communication domain, channel, and verification flow |
| 22 | ├── README.md // Chinese documentation | 22 | ├── README.md // Chinese documentation |
| 23 | ├── README_en.md // English documentation | 23 | ├── README_en.md // English documentation |
| 24 | -├── run.sh // Multi-rank launch script | ||
| 25 | └── ubmem_data_copy.asc // Ascend C data copy kernel | 24 | └── ubmem_data_copy.asc // Ascend C data copy kernel |
| 26 | ``` | 25 | ``` |
| 27 | 26 | ||
| @@ -45,14 +44,14 @@ For the same peer, the two channels use the same communication endpoints and are | |||
| 45 | 44 | ||
| 46 | ### Implementation Flow | 45 | ### Implementation Flow |
| 47 | 46 | ||
| 48 | -1. Rank 0 creates and distributes one `HcclRootInfo`, and every rank initializes the same communication domain. | 47 | +1. The executable forks all rank processes (via `examples/aicore/utils/process_manager.h`); ranks exchange `HcclRootInfo` through a TCP control channel (`examples/aicore/utils/rank_sync.h`) and initialize the same communication domain. |
| 49 | 2. Each rank obtains its local HCCL Buffer, fills it with the rank ID, and registers the memory resource required by the channels through `HcclCommMemReg`. | 48 | 2. Each rank obtains its local HCCL Buffer, fills it with the rank ID, and registers the memory resource required by the channels through `HcclCommMemReg`. |
| 50 | 3. Each rank scans the RankGraph layers and selects one `COMM_PROTOCOL_UB_MEM` link for every peer. | 49 | 3. Each rank scans the RankGraph layers and selects one `COMM_PROTOCOL_UB_MEM` link for every peer. |
| 51 | 4. For every peer, the sample builds two descriptors with the same endpoints and `pathMode=1` and `pathMode=2`. | 50 | 4. For every peer, the sample builds two descriptors with the same endpoints and `pathMode=1` and `pathMode=2`. |
| 52 | 5. All peer channel descriptors are passed to one `HcclChannelAcquire` call to create the channels in one batch. | 51 | 5. All peer channel descriptors are passed to one `HcclChannelAcquire` call to create the channels in one batch. |
| 53 | 6. Peers are processed serially. For each peer, the two channels read the first and second 2 KB shards on separate streams, and both kernels are submitted before either stream is synchronized. Concurrency is limited to the two paths of that peer. | 52 | 6. Peers are processed serially. For each peer, the two channels read the first and second 2 KB shards on separate streams, and both kernels are submitted before either stream is synchronized. Concurrency is limited to the two paths of that peer. |
| 54 | 7. The local verification buffer is copied to the host, where every byte is checked against the peer rank ID. | 53 | 7. The local verification buffer is copied to the host, where every byte is checked against the peer rank ID. |
| 55 | -8. After all peer data is verified, `HcclBarrier` ensures that every rank has completed its remote reads before communication resources are destroyed. | 54 | +8. After all peer data is verified, a barrier (via `RankSyncContext`) ensures that every rank has completed its remote reads before communication resources are destroyed. |
| 56 | 55 | ||
| 57 | The `rank_graph_topo` log reports only the RankGraph layer containing the selected UB_MEM link. It does not | 56 | The `rank_graph_topo` log reports only the RankGraph layer containing the selected UB_MEM link. It does not |
| 58 | select `pathMode`. | 57 | select `pathMode`. |
| @@ -64,7 +63,7 @@ Perform the following steps in the sample root directory. This sample supports N | |||
| 64 | - Set Environment Variables | 63 | - Set Environment Variables |
| 65 | 64 | ||
| 66 | Configure the environment variables according to the CANN development toolkit | 65 | Configure the environment variables according to the CANN development toolkit |
| 67 | - [installation method](../../docs/quick_start_en.md). | 66 | + [installation method](../../../../docs/quick_start_en.md). |
| 68 | 67 | ||
| 69 | ```bash | 68 | ```bash |
| 70 | source ${install_path}/cann/set_env.sh | 69 | source ${install_path}/cann/set_env.sh |
| @@ -73,39 +72,48 @@ Perform the following steps in the sample root directory. This sample supports N | |||
| 73 | > **Note:** `${install_path}` is the CANN installation directory. The default installation directory is | 72 | > **Note:** `${install_path}` is the CANN installation directory. The default installation directory is |
| 74 | > `/usr/local/Ascend`. | 73 | > `/usr/local/Ascend`. |
| 75 | 74 | ||
| 76 | -- Run on Two Devices | 75 | +- Single-machine run |
| 77 | 76 | ||
| 78 | - By default, the script starts two processes on devices 0 and 1. | 77 | + The executable forks all rank processes internally; each rank is assigned to the corresponding NPU device: |
| 79 | 78 | ||
| 80 | ```bash | 79 | ```bash |
| 81 | - cmake -S . -B build -DCMAKE_ASC_ARCHITECTURES=dav-3510 | 80 | + mkdir -p build |
| 82 | - cmake --build build -j | 81 | + cd build |
| 83 | - bash run.sh | 82 | + cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. |
| 83 | + make -j | ||
| 84 | + cd .. && ./build/one_multi_path tcp://127.0.0.1:29625 <nranks> | ||
| 84 | ``` | 85 | ``` |
| 85 | 86 | ||
| 86 | -- Launch Options | 87 | + | Parameter | Default | Description | |
| 87 | - | ||
| 88 | - | Option | Default | Description | | ||
| 89 | | --- | --- | --- | | 88 | | --- | --- | --- | |
| 90 | - | `-pes` | `2` | Total number of ranks; it must be an integer greater than or equal to 2 | | 89 | + | `<ip:port>` | Required | Control channel address that rank 0 listens on (`tcp://ip:port`); use different ports for parallel instances | |
| 91 | - | `-ipport` | `tcp://127.0.0.1:8899` | Address used by rank 0 to distribute `HcclRootInfo`; use `tcp://[address]:port` for IPv6 | | 90 | + | `<nranks>` | Required | Total number of ranks; must be >= 2 and not exceed available NPU count | |
| 92 | - | `-gnpus` | `2` | Number of rank processes started on the current host | | ||
| 93 | - | `-fpe` | `0` | First rank ID on the current host | | ||
| 94 | - | `-fnpu` | `0` | First device ID on the current host | | ||
| 95 | 91 | ||
| 96 | -- Run on Multiple Hosts | 92 | +- Multi-machine run |
| 97 | 93 | ||
| 98 | - For eight devices across two hosts, start the first command on the rank 0 host, followed by the second command on the other host: | 94 | + Each host runs the executable with per-rank arguments: |
| 95 | + | ||
| 96 | + ```bash | ||
| 97 | + ./build/one_multi_path <tcp://ip:port> <rank_size> <rank> <device> | ||
| 98 | + ``` | ||
| 99 | + | ||
| 100 | + For eight devices across two hosts: | ||
| 99 | 101 | ||
| 100 | ```bash | 102 | ```bash |
| 101 | # Host A: ranks 0-3, devices 0-3 | 103 | # Host A: ranks 0-3, devices 0-3 |
| 102 | - bash run.sh -pes 8 -ipport tcp://<host_A_IP>:8899 -gnpus 4 -fpe 0 -fnpu 0 | 104 | + ./build/one_multi_path tcp://<host_A_IP>:8899 8 0 0 |
| 105 | + ./build/one_multi_path tcp://<host_A_IP>:8899 8 1 1 | ||
| 106 | + ./build/one_multi_path tcp://<host_A_IP>:8899 8 2 2 | ||
| 107 | + ./build/one_multi_path tcp://<host_A_IP>:8899 8 3 3 | ||
| 103 | 108 | ||
| 104 | # Host B: ranks 4-7, devices 0-3 | 109 | # Host B: ranks 4-7, devices 0-3 |
| 105 | - bash run.sh -pes 8 -ipport tcp://<host_A_IP>:8899 -gnpus 4 -fpe 4 -fnpu 0 | 110 | + ./build/one_multi_path tcp://<host_A_IP>:8899 8 4 0 |
| 111 | + ./build/one_multi_path tcp://<host_A_IP>:8899 8 5 1 | ||
| 112 | + ./build/one_multi_path tcp://<host_A_IP>:8899 8 6 2 | ||
| 113 | + ./build/one_multi_path tcp://<host_A_IP>:8899 8 7 3 | ||
| 106 | ``` | 114 | ``` |
| 107 | 115 | ||
| 108 | - For 16 devices with eight devices per host, set `-pes` to `16`, `-gnpus` to `8`, and use `-fpe 0` and `-fpe 8` on the two hosts. | 116 | + `<ip:port>` must point to the rank 0 host on every machine; `<rank_size>` is the global rank count; `<rank>` is this process's global rank ID; `<device>` is the local device ID. |
| 109 | 117 | ||
| 110 | - Build Options | 118 | - Build Options |
| 111 | 119 | ||
| @@ -119,20 +127,20 @@ Perform the following steps in the sample root directory. This sample supports N | |||
| 119 | Log order can vary because the rank processes run concurrently. Every rank should validate every peer: | 127 | Log order can vary because the rank processes run concurrently. Every rank should validate every peer: |
| 120 | 128 | ||
| 121 | ```text | 129 | ```text |
| 122 | - rank 0/2: device=0, channels_per_peer=2, channel_descs=2 | 130 | + [rank 0] one_multi_path | channels_per_peer=2, channel_descs=2 |
| 123 | rank 0: peer=1, rank_graph_topo=5, protocol=UB_MEM, path_modes=1/2 | 131 | rank 0: peer=1, rank_graph_topo=5, protocol=UB_MEM, path_modes=1/2 |
| 124 | rank 0: dual-path data copy from remote rank 1 passed, bytes=4096 | 132 | rank 0: dual-path data copy from remote rank 1 passed, bytes=4096 |
| 125 | - rank 0: dual-path validation passed | 133 | + [rank 0] one_multi_path | dual-path validation | PASS |
| 126 | ``` | 134 | ``` |
| 127 | 135 | ||
| 128 | The sample succeeds when every rank obtains two different channel handles for every peer, verifies the data, | 136 | The sample succeeds when every rank obtains two different channel handles for every peer, verifies the data, |
| 129 | - and the script exits with 0. | 137 | + and the final output is `RESULT | Example=one_multi_path | Status=PASS`. |
| 130 | 138 | ||
| 131 | ## Notes | 139 | ## Notes |
| 132 | 140 | ||
| 133 | - The default run requires devices 0 and 1 and a `COMM_PROTOCOL_UB_MEM` link between them. | 141 | - The default run requires devices 0 and 1 and a `COMM_PROTOCOL_UB_MEM` link between them. |
| 134 | -- For a multi-host run, every host must use the same `-pes`, and the rank ranges must be complete and unique. | 142 | +- For a multi-host run, every host must use the same `<rank_size>` and `<ip:port>` (pointing to rank 0), and the rank ranges must be complete and unique. |
| 135 | -- `-ipport` distributes `HcclRootInfo` only. It does not select the HCCL data link. | 143 | +- `<ip:port>` is used only for distributing `HcclRootInfo` and host-side synchronization. It does not select the HCCL data link. |
| 136 | - If `HcclChannelAcquire` fails, use the preceding peer link-selection logs to narrow down the failing range. | 144 | - If `HcclChannelAcquire` fails, use the preceding peer link-selection logs to narrow down the failing range. |
| 137 | - `no UB_MEM link found` means that no `COMM_PROTOCOL_UB_MEM` link is available between the local and target | 145 | - `no UB_MEM link found` means that no `COMM_PROTOCOL_UB_MEM` link is available between the local and target |
| 138 | ranks. | 146 | ranks. |
| @@ -8,7 +8,6 @@ | |||
| 8 | * See LICENSE in the root of the software repository for the full text of the License. | 8 | * See LICENSE in the root of the software repository for the full text of the License. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | -#include <chrono> | ||
| 12 | #include <cerrno> | 11 | #include <cerrno> |
| 13 | #include <cstdio> | 12 | #include <cstdio> |
| 14 | #include <cstdint> | 13 | #include <cstdint> |
| @@ -17,37 +16,19 @@ | |||
| 17 | #include <iostream> | 16 | #include <iostream> |
| 18 | #include <limits> | 17 | #include <limits> |
| 19 | #include <string> | 18 | #include <string> |
| 20 | -#include <thread> | ||
| 21 | #include <vector> | 19 | #include <vector> |
| 22 | 20 | ||
| 23 | -#include <netdb.h> | ||
| 24 | -#include <sys/socket.h> | ||
| 25 | -#include <sys/time.h> | ||
| 26 | -#include <unistd.h> | ||
| 27 | - | ||
| 28 | #include "acl/acl.h" | 21 | #include "acl/acl.h" |
| 29 | #include "hccl/hccl.h" | 22 | #include "hccl/hccl.h" |
| 30 | #include "hccl/hccl_rank_graph.h" | 23 | #include "hccl/hccl_rank_graph.h" |
| 31 | #include "hccl/hccl_res.h" | 24 | #include "hccl/hccl_res.h" |
| 32 | #include "hccl/hccl_types.h" | 25 | #include "hccl/hccl_types.h" |
| 33 | 26 | ||
| 34 | -#define HCCLCHECK(ret) \ | 27 | +#include "utils/check.h" |
| 35 | - do { \ | 28 | +#include "utils/hccl_comm_init.h" |
| 36 | - const HcclResult checkRet = (ret); \ | 29 | +#include "utils/process_manager.h" |
| 37 | - if (checkRet != HCCL_SUCCESS) { \ | 30 | +#include "utils/rank_sync.h" |
| 38 | - std::fprintf(stderr, "%s:%d: %s return %d.\n", __FILE__, __LINE__, #ret, checkRet); \ | 31 | +#include "utils/arg_parser.h" |
| 39 | - return checkRet; \ | ||
| 40 | - } \ | ||
| 41 | - } while (0) | ||
| 42 | - | ||
| 43 | -#define ACLCHECK(ret) \ | ||
| 44 | - do { \ | ||
| 45 | - const aclError checkRet = (ret); \ | ||
| 46 | - if (checkRet != ACL_SUCCESS) { \ | ||
| 47 | - std::fprintf(stderr, "%s:%d: %s return %d.\n", __FILE__, __LINE__, #ret, checkRet); \ | ||
| 48 | - return HCCL_E_RUNTIME; \ | ||
| 49 | - } \ | ||
| 50 | - } while (0) | ||
| 51 | 32 | ||
| 52 | extern "C" aclError LaunchUbmemDataCopy(void* dst, void* src, uint32_t byteSize, aclrtStream stream); | 33 | extern "C" aclError LaunchUbmemDataCopy(void* dst, void* src, uint32_t byteSize, aclrtStream stream); |
| 53 | 34 | ||
| @@ -60,9 +41,10 @@ constexpr uint8_t PATH_MODE_ONE = 1; | |||
| 60 | constexpr uint8_t PATH_MODE_MULTI = 2; | 41 | constexpr uint8_t PATH_MODE_MULTI = 2; |
| 61 | constexpr CommProtocol TARGET_PROTOCOL = COMM_PROTOCOL_UB_MEM; | 42 | constexpr CommProtocol TARGET_PROTOCOL = COMM_PROTOCOL_UB_MEM; |
| 62 | constexpr uint32_t PATH_COUNT = 2; | 43 | constexpr uint32_t PATH_COUNT = 2; |
| 63 | -constexpr time_t SOCKET_IO_TIMEOUT_SECONDS = 30; | ||
| 64 | constexpr uint8_t TARGET_PATH_MODES[PATH_COUNT] = {PATH_MODE_ONE, PATH_MODE_MULTI}; | 44 | constexpr uint8_t TARGET_PATH_MODES[PATH_COUNT] = {PATH_MODE_ONE, PATH_MODE_MULTI}; |
| 65 | static_assert(VERIFY_BYTES % PATH_COUNT == 0, "VERIFY_BYTES must be divisible by PATH_COUNT"); | 45 | static_assert(VERIFY_BYTES % PATH_COUNT == 0, "VERIFY_BYTES must be divisible by PATH_COUNT"); |
| 46 | +// 收尾barrier的tag:本样例只有这一个host侧同步点。 | ||
| 47 | +constexpr uint32_t kTagFinalRelease = examples::kTagUserBase; | ||
| 66 | 48 | ||
| 67 | struct Options { | 49 | struct Options { |
| 68 | uint32_t rankSize = 0; | 50 | uint32_t rankSize = 0; |
| @@ -78,7 +60,6 @@ struct CommResources { | |||
| 78 | void* verifyBuffer = nullptr; | 60 | void* verifyBuffer = nullptr; |
| 79 | }; | 61 | }; |
| 80 | 62 | ||
| 81 | -int ExchangeRootInfo(uint32_t rank, uint32_t rankSize, const std::string& ipPort, HcclRootInfo& rootInfo); | ||
| 82 | int ReportError(uint32_t rank, const char* operation, int result); | 63 | int ReportError(uint32_t rank, const char* operation, int result); |
| 83 | int BuildChannelDescs( | 64 | int BuildChannelDescs( |
| 84 | HcclComm comm, uint32_t rank, uint32_t peerRank, HcclMemHandle& memHandle, HcclChannelDesc* descs); | 65 | HcclComm comm, uint32_t rank, uint32_t peerRank, HcclMemHandle& memHandle, HcclChannelDesc* descs); |
| @@ -86,14 +67,14 @@ int TransferAndVerifyShards( | |||
| 86 | uint32_t rank, uint32_t peerRank, HcclComm comm, const ChannelHandle* channels, CommResources& resources); | 67 | uint32_t rank, uint32_t peerRank, HcclComm comm, const ChannelHandle* channels, CommResources& resources); |
| 87 | int CleanupCommRes(CommResources& resources, int status); | 68 | int CleanupCommRes(CommResources& resources, int status); |
| 88 | 69 | ||
| 89 | -int TestDualPath(const Options& options, const HcclRootInfo& rootInfo) | 70 | +int TestDualPath(const Options& options, examples::RankSyncContext& sync) |
| 90 | { | 71 | { |
| 91 | CommResources resources; | 72 | CommResources resources; |
| 92 | HcclMemHandle memHandle = nullptr; | 73 | HcclMemHandle memHandle = nullptr; |
| 93 | std::vector<uint32_t> peerRanks; | 74 | std::vector<uint32_t> peerRanks; |
| 94 | 75 | ||
| 95 | // Initialize the communication domain and prepare data in the local HCCL Buffer. | 76 | // Initialize the communication domain and prepare data in the local HCCL Buffer. |
| 96 | - int result = HcclCommInitRootInfo(options.rankSize, &rootInfo, options.rank, &resources.comm); | 77 | + int result = examples::InitCommByRootInfo(sync, &resources.comm); |
| 97 | if (result != HCCL_SUCCESS) { | 78 | if (result != HCCL_SUCCESS) { |
| 98 | return CleanupCommRes(resources, ReportError(options.rank, "HcclCommInitRootInfo", result)); | 79 | return CleanupCommRes(resources, ReportError(options.rank, "HcclCommInitRootInfo", result)); |
| 99 | } | 80 | } |
| @@ -188,14 +169,11 @@ int TestDualPath(const Options& options, const HcclRootInfo& rootInfo) | |||
| 188 | } | 169 | } |
| 189 | } | 170 | } |
| 190 | 171 | ||
| 191 | - // Keep every rank's HCCL Buffer valid until all remote reads have completed. | 172 | + // Keep every rank's HCCL Buffer valid until all remote reads have completed. Each rank has |
| 192 | - result = HcclBarrier(resources.comm, resources.streams[0]); | 173 | + // already synchronized its own streams above, so the host-side barrier suffices: once every |
| 193 | - if (result != HCCL_SUCCESS) { | 174 | + // rank passes it, all remote reads in the group are done and freeing is safe. |
| 194 | - return CleanupCommRes(resources, ReportError(options.rank, "HcclBarrier", result)); | 175 | + if (!sync.Barrier(kTagFinalRelease)) { |
| 195 | - } | 176 | + return CleanupCommRes(resources, ReportError(options.rank, "Barrier", HCCL_E_INTERNAL)); |
| 196 | - result = aclrtSynchronizeStream(resources.streams[0]); | ||
| 197 | - if (result != ACL_SUCCESS) { | ||
| 198 | - return CleanupCommRes(resources, ReportError(options.rank, "aclrtSynchronizeStream after HcclBarrier", result)); | ||
| 199 | } | 177 | } |
| 200 | return CleanupCommRes(resources, HCCL_SUCCESS); | 178 | return CleanupCommRes(resources, HCCL_SUCCESS); |
| 201 | } | 179 | } |
| @@ -368,301 +346,37 @@ int CleanupCommRes(CommResources& resources, int status) | |||
| 368 | return status != HCCL_SUCCESS ? status : cleanupStatus; | 346 | return status != HCCL_SUCCESS ? status : cleanupStatus; |
| 369 | } | 347 | } |
| 370 | 348 | ||
| 371 | -bool ParseNonNegativeInt(const char* text, int& value) | ||
| 372 | -{ | ||
| 373 | - if (text == nullptr || *text == '\0') { | ||
| 374 | - return false; | ||
| 375 | - } | ||
| 376 | - | ||
| 377 | - char* parseEnd = nullptr; | ||
| 378 | - errno = 0; | ||
| 379 | - const long parsed = std::strtol(text, &parseEnd, 10); | ||
| 380 | - if (errno == ERANGE || parseEnd == text || *parseEnd != '\0' || parsed < 0 || | ||
| 381 | - parsed > std::numeric_limits<int>::max()) { | ||
| 382 | - return false; | ||
| 383 | - } | ||
| 384 | - value = static_cast<int>(parsed); | ||
| 385 | - return true; | ||
| 386 | -} | ||
| 387 | - | ||
| 388 | -bool ParseIpPort(const std::string& ipPort, std::string& host, uint16_t& port) | ||
| 389 | -{ | ||
| 390 | - constexpr const char* TCP_PREFIX = "tcp://"; | ||
| 391 | - std::string value = ipPort; | ||
| 392 | - if (value.compare(0, std::strlen(TCP_PREFIX), TCP_PREFIX) == 0) { | ||
| 393 | - value = value.substr(std::strlen(TCP_PREFIX)); | ||
| 394 | - } | ||
| 395 | - | ||
| 396 | - size_t separator = value.rfind(':'); | ||
| 397 | - if (separator == std::string::npos || separator == 0 || separator + 1 >= value.size()) { | ||
| 398 | - return false; | ||
| 399 | - } | ||
| 400 | - | ||
| 401 | - const std::string portText = value.substr(separator + 1); | ||
| 402 | - char* parseEnd = nullptr; | ||
| 403 | - errno = 0; | ||
| 404 | - const long parsedPort = std::strtol(portText.c_str(), &parseEnd, 10); | ||
| 405 | - if (errno == ERANGE || parseEnd == portText.c_str() || *parseEnd != '\0' || parsedPort <= 0 || | ||
| 406 | - parsedPort > UINT16_MAX) { | ||
| 407 | - return false; | ||
| 408 | - } | ||
| 409 | - host = value.substr(0, separator); | ||
| 410 | - if (host.front() == '[') { | ||
| 411 | - if (host.size() < 3 || host.back() != ']') { | ||
| 412 | - return false; | ||
| 413 | - } | ||
| 414 | - host = host.substr(1, host.size() - 2); | ||
| 415 | - } | ||
| 416 | - port = static_cast<uint16_t>(parsedPort); | ||
| 417 | - return true; | ||
| 418 | -} | ||
| 419 | - | ||
| 420 | -bool SendAll(int fd, const void* data, size_t size) | ||
| 421 | -{ | ||
| 422 | - const char* buffer = static_cast<const char*>(data); | ||
| 423 | - size_t sent = 0; | ||
| 424 | - while (sent < size) { | ||
| 425 | - const ssize_t count = send(fd, buffer + sent, size - sent, MSG_NOSIGNAL); | ||
| 426 | - if (count < 0 && errno == EINTR) { | ||
| 427 | - continue; | ||
| 428 | - } | ||
| 429 | - if (count < 0) { | ||
| 430 | - std::cerr << "send failed, errno=" << errno << std::endl; | ||
| 431 | - return false; | ||
| 432 | - } | ||
| 433 | - if (count == 0) { | ||
| 434 | - std::cerr << "send returned 0 before all data was sent" << std::endl; | ||
| 435 | - return false; | ||
| 436 | - } | ||
| 437 | - sent += static_cast<size_t>(count); | ||
| 438 | - } | ||
| 439 | - return true; | ||
| 440 | -} | ||
| 441 | - | ||
| 442 | -bool RecvAll(int fd, void* data, size_t size) | ||
| 443 | -{ | ||
| 444 | - char* buffer = static_cast<char*>(data); | ||
| 445 | - size_t received = 0; | ||
| 446 | - while (received < size) { | ||
| 447 | - const ssize_t count = recv(fd, buffer + received, size - received, 0); | ||
| 448 | - if (count < 0 && errno == EINTR) { | ||
| 449 | - continue; | ||
| 450 | - } | ||
| 451 | - if (count < 0) { | ||
| 452 | - std::cerr << "recv failed, errno=" << errno << std::endl; | ||
| 453 | - return false; | ||
| 454 | - } | ||
| 455 | - if (count == 0) { | ||
| 456 | - std::cerr << "peer closed the connection before all data was received" << std::endl; | ||
| 457 | - return false; | ||
| 458 | - } | ||
| 459 | - received += static_cast<size_t>(count); | ||
| 460 | - } | ||
| 461 | - return true; | ||
| 462 | -} | ||
| 463 | - | ||
| 464 | -bool SetSocketTimeouts(int fd) | ||
| 465 | -{ | ||
| 466 | - timeval timeout{}; | ||
| 467 | - timeout.tv_sec = SOCKET_IO_TIMEOUT_SECONDS; | ||
| 468 | - if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) != 0) { | ||
| 469 | - std::cerr << "setsockopt SO_RCVTIMEO failed, errno=" << errno << std::endl; | ||
| 470 | - return false; | ||
| 471 | - } | ||
| 472 | - if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) != 0) { | ||
| 473 | - std::cerr << "setsockopt SO_SNDTIMEO failed, errno=" << errno << std::endl; | ||
| 474 | - return false; | ||
| 475 | - } | ||
| 476 | - return true; | ||
| 477 | -} | ||
| 478 | - | ||
| 479 | -int CreateListenSocket(const std::string& host, uint16_t port) | ||
| 480 | -{ | ||
| 481 | - addrinfo hints{}; | ||
| 482 | - hints.ai_family = AF_UNSPEC; | ||
| 483 | - hints.ai_socktype = SOCK_STREAM; | ||
| 484 | - hints.ai_flags = AI_PASSIVE; | ||
| 485 | - const std::string portText = std::to_string(port); | ||
| 486 | - addrinfo* addresses = nullptr; | ||
| 487 | - const int resolveResult = getaddrinfo(host.c_str(), portText.c_str(), &hints, &addresses); | ||
| 488 | - if (resolveResult != 0) { | ||
| 489 | - std::cerr << "getaddrinfo for listen address failed: " << gai_strerror(resolveResult) << std::endl; | ||
| 490 | - return -1; | ||
| 491 | - } | ||
| 492 | - | ||
| 493 | - int listenFd = -1; | ||
| 494 | - int lastError = 0; | ||
| 495 | - for (const addrinfo* address = addresses; address != nullptr; address = address->ai_next) { | ||
| 496 | - int fd = socket(address->ai_family, address->ai_socktype, address->ai_protocol); | ||
| 497 | - if (fd < 0) { | ||
| 498 | - lastError = errno; | ||
| 499 | - continue; | ||
| 500 | - } | ||
| 501 | - if (!SetSocketTimeouts(fd)) { | ||
| 502 | - lastError = errno; | ||
| 503 | - close(fd); | ||
| 504 | - continue; | ||
| 505 | - } | ||
| 506 | - int reuseAddress = 1; | ||
| 507 | - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseAddress, sizeof(reuseAddress)) != 0) { | ||
| 508 | - lastError = errno; | ||
| 509 | - close(fd); | ||
| 510 | - continue; | ||
| 511 | - } | ||
| 512 | - if (bind(fd, address->ai_addr, address->ai_addrlen) != 0 || listen(fd, 64) != 0) { | ||
| 513 | - lastError = errno; | ||
| 514 | - close(fd); | ||
| 515 | - continue; | ||
| 516 | - } | ||
| 517 | - listenFd = fd; | ||
| 518 | - break; | ||
| 519 | - } | ||
| 520 | - freeaddrinfo(addresses); | ||
| 521 | - if (listenFd < 0) { | ||
| 522 | - std::cerr << "listen on " << host << ":" << port << " failed, errno=" << lastError << std::endl; | ||
| 523 | - } | ||
| 524 | - return listenFd; | ||
| 525 | -} | ||
| 526 | - | ||
| 527 | -int ConnectToRoot(const std::string& host, uint16_t port) | ||
| 528 | -{ | ||
| 529 | - constexpr int RETRY_TIMES = 300; | ||
| 530 | - constexpr int RETRY_INTERVAL_MS = 100; | ||
| 531 | - | ||
| 532 | - addrinfo hints{}; | ||
| 533 | - hints.ai_family = AF_UNSPEC; | ||
| 534 | - hints.ai_socktype = SOCK_STREAM; | ||
| 535 | - const std::string portText = std::to_string(port); | ||
| 536 | - addrinfo* addresses = nullptr; | ||
| 537 | - const int resolveResult = getaddrinfo(host.c_str(), portText.c_str(), &hints, &addresses); | ||
| 538 | - if (resolveResult != 0) { | ||
| 539 | - std::cerr << "getaddrinfo for root address failed: " << gai_strerror(resolveResult) << std::endl; | ||
| 540 | - return -1; | ||
| 541 | - } | ||
| 542 | - | ||
| 543 | - for (int retry = 0; retry < RETRY_TIMES; ++retry) { | ||
| 544 | - for (const addrinfo* address = addresses; address != nullptr; address = address->ai_next) { | ||
| 545 | - int fd = socket(address->ai_family, address->ai_socktype, address->ai_protocol); | ||
| 546 | - if (fd < 0) { | ||
| 547 | - continue; | ||
| 548 | - } | ||
| 549 | - if (!SetSocketTimeouts(fd)) { | ||
| 550 | - close(fd); | ||
| 551 | - continue; | ||
| 552 | - } | ||
| 553 | - if (connect(fd, address->ai_addr, address->ai_addrlen) == 0) { | ||
| 554 | - freeaddrinfo(addresses); | ||
| 555 | - return fd; | ||
| 556 | - } | ||
| 557 | - close(fd); | ||
| 558 | - } | ||
| 559 | - if (retry + 1 < RETRY_TIMES) { | ||
| 560 | - std::this_thread::sleep_for(std::chrono::milliseconds(RETRY_INTERVAL_MS)); | ||
| 561 | - } | ||
| 562 | - } | ||
| 563 | - freeaddrinfo(addresses); | ||
| 564 | - return -1; | ||
| 565 | -} | ||
| 566 | - | ||
| 567 | -int ExchangeRootInfo(uint32_t rank, uint32_t rankSize, const std::string& ipPort, HcclRootInfo& rootInfo) | ||
| 568 | -{ | ||
| 569 | - std::string host; | ||
| 570 | - uint16_t port = 0; | ||
| 571 | - if (!ParseIpPort(ipPort, host, port)) { | ||
| 572 | - std::cerr << "invalid ipport: " << ipPort << std::endl; | ||
| 573 | - return -1; | ||
| 574 | - } | ||
| 575 | - | ||
| 576 | - if (rank == 0) { | ||
| 577 | - int listenFd = CreateListenSocket(host, port); | ||
| 578 | - if (listenFd < 0) { | ||
| 579 | - return -1; | ||
| 580 | - } | ||
| 581 | - for (uint32_t peer = 1; peer < rankSize; ++peer) { | ||
| 582 | - int connectionFd = -1; | ||
| 583 | - do { | ||
| 584 | - connectionFd = accept(listenFd, nullptr, nullptr); | ||
| 585 | - } while (connectionFd < 0 && errno == EINTR); | ||
| 586 | - if (connectionFd < 0) { | ||
| 587 | - std::cerr << "accept failed, errno=" << errno << std::endl; | ||
| 588 | - close(listenFd); | ||
| 589 | - return -1; | ||
| 590 | - } | ||
| 591 | - if (!SetSocketTimeouts(connectionFd)) { | ||
| 592 | - close(connectionFd); | ||
| 593 | - close(listenFd); | ||
| 594 | - return -1; | ||
| 595 | - } | ||
| 596 | - if (!SendAll(connectionFd, &rootInfo, sizeof(rootInfo))) { | ||
| 597 | - std::cerr << "send root info failed" << std::endl; | ||
| 598 | - close(connectionFd); | ||
| 599 | - close(listenFd); | ||
| 600 | - return -1; | ||
| 601 | - } | ||
| 602 | - close(connectionFd); | ||
| 603 | - } | ||
| 604 | - close(listenFd); | ||
| 605 | - return 0; | ||
| 606 | - } | ||
| 607 | - | ||
| 608 | - int fd = ConnectToRoot(host, port); | ||
| 609 | - if (fd < 0) { | ||
| 610 | - std::cerr << "connect ipport failed: " << ipPort << std::endl; | ||
| 611 | - return -1; | ||
| 612 | - } | ||
| 613 | - if (!RecvAll(fd, &rootInfo, sizeof(rootInfo))) { | ||
| 614 | - std::cerr << "recv root info failed" << std::endl; | ||
| 615 | - close(fd); | ||
| 616 | - return -1; | ||
| 617 | - } | ||
| 618 | - close(fd); | ||
| 619 | - return 0; | ||
| 620 | -} | ||
| 621 | - | ||
| 622 | } // namespace | 349 | } // namespace |
| 623 | 350 | ||
| 624 | -int main(int argc, char* argv[]) | 351 | +// 单个rank的完整流程,单机与多机模式共用。由ProcessGroup(单机)或main的5参数分支 |
| 352 | +// (多机)调用。 | ||
| 353 | +int RunOneMultiPathRank(uint32_t rankSize, uint32_t rank, const std::string& ipPort, uint32_t device) | ||
| 625 | { | 354 | { |
| 626 | - if (argc != 5) { | 355 | + Options options{rankSize, rank, device, ipPort}; |
| 627 | - std::cerr << "invalid arguments" << std::endl; | 356 | + |
| 357 | + examples::RankSyncContext sync = rank == 0U ? examples::RankSyncContext::Listen(ipPort, rankSize) : | ||
| 358 | + examples::RankSyncContext::Connect(rank, rankSize, ipPort); | ||
| 359 | + if (!sync.Ok()) { | ||
| 360 | + std::cerr << "[rank " << rank << "] control channel setup failed" << std::endl; | ||
| 628 | return 1; | 361 | return 1; |
| 629 | } | 362 | } |
| 630 | 363 | ||
| 631 | - int rankSize = 0; | 364 | + EXAMPLES_ACLCHECK(aclInit(nullptr)); |
| 632 | - int rank = 0; | ||
| 633 | - int device = 0; | ||
| 634 | - if (!ParseNonNegativeInt(argv[1], rankSize) || !ParseNonNegativeInt(argv[2], rank) || | ||
| 635 | - !ParseNonNegativeInt(argv[4], device) || rankSize < 2 || rank >= rankSize) { | ||
| 636 | - std::cerr << "invalid arguments: rank_size must be at least 2, rank must be in [0, rank_size), and device " | ||
| 637 | - "must be a non-negative integer" | ||
| 638 | - << std::endl; | ||
| 639 | - return 1; | ||
| 640 | - } | ||
| 641 | - Options options{ | ||
| 642 | - static_cast<uint32_t>(rankSize), static_cast<uint32_t>(rank), static_cast<uint32_t>(device), argv[3]}; | ||
| 643 | - | ||
| 644 | - ACLCHECK(aclInit(nullptr)); | ||
| 645 | uint32_t deviceCount = 0; | 365 | uint32_t deviceCount = 0; |
| 646 | - ACLCHECK(aclrtGetDeviceCount(&deviceCount)); | 366 | + EXAMPLES_ACLCHECK(aclrtGetDeviceCount(&deviceCount)); |
| 647 | if (options.device >= deviceCount) { | 367 | if (options.device >= deviceCount) { |
| 648 | std::cerr << "device " << options.device << " is out of range, device_count=" << deviceCount << std::endl; | 368 | std::cerr << "device " << options.device << " is out of range, device_count=" << deviceCount << std::endl; |
| 649 | return 1; | 369 | return 1; |
| 650 | } | 370 | } |
| 651 | - ACLCHECK(aclrtSetDevice(static_cast<int32_t>(options.device))); | 371 | + EXAMPLES_ACLCHECK(aclrtSetDevice(static_cast<int32_t>(options.device))); |
| 652 | - | ||
| 653 | - HcclRootInfo rootInfo{}; | ||
| 654 | - if (options.rank == 0) { | ||
| 655 | - HCCLCHECK(HcclGetRootInfo(&rootInfo)); | ||
| 656 | - } | ||
| 657 | 372 | ||
| 658 | int status = HCCL_E_INTERNAL; | 373 | int status = HCCL_E_INTERNAL; |
| 659 | - if (ExchangeRootInfo(options.rank, options.rankSize, options.ipPort, rootInfo) == 0) { | 374 | + { |
| 660 | - std::cout << "rank " << options.rank << "/" << options.rankSize << ": device=" << options.device | 375 | + std::cout << "[rank " << options.rank << "] one_multi_path | channels_per_peer=" << PATH_COUNT |
| 661 | - << ", channels_per_peer=" << PATH_COUNT << ", channel_descs=" << (options.rankSize - 1) * PATH_COUNT | 376 | + << ", channel_descs=" << (options.rankSize - 1) * PATH_COUNT << std::endl; |
| 662 | - << std::endl; | 377 | + status = TestDualPath(options, sync); |
| 663 | - status = TestDualPath(options, rootInfo); | ||
| 664 | if (status == HCCL_SUCCESS) { | 378 | if (status == HCCL_SUCCESS) { |
| 665 | - std::cout << "rank " << options.rank << ": dual-path validation passed" << std::endl; | 379 | + std::cout << "[rank " << options.rank << "] one_multi_path | dual-path validation | PASS" << std::endl; |
| 666 | } | 380 | } |
| 667 | } | 381 | } |
| 668 | 382 | ||
| @@ -674,3 +388,57 @@ int main(int argc, char* argv[]) | |||
| 674 | } | 388 | } |
| 675 | return status == HCCL_SUCCESS ? 0 : 1; | 389 | return status == HCCL_SUCCESS ? 0 : 1; |
| 676 | } | 390 | } |
| 391 | + | ||
| 392 | +// 单机模式:one_multi_path <tcp://ip:port> <nranks>,父进程fork全部rank进程, | ||
| 393 | +// device固定为rank对应的NPU。多机模式:one_multi_path <tcp://ip:port> <rank_size> <rank> <device>, | ||
| 394 | +// 每台机器各自启动本机的rank进程,endpoint统一指向rank 0所在机器。 | ||
| 395 | +int main(int argc, char* argv[]) | ||
| 396 | +{ | ||
| 397 | + // 单机:endpoint + nranks。 | ||
| 398 | + if (argc == 3) { | ||
| 399 | + uint32_t uRankSize = 0; | ||
| 400 | + if (!examples::ParseUint32(argv[2], uRankSize, 2)) { | ||
| 401 | + std::cerr << "invalid nranks: " << argv[2] << ", expected an integer >= 2" << std::endl; | ||
| 402 | + return 1; | ||
| 403 | + } | ||
| 404 | + const std::string endpoint = argv[1]; | ||
| 405 | + | ||
| 406 | + std::vector<examples::ArgsOf<decltype(RunOneMultiPathRank)>> perRankArgs; | ||
| 407 | + perRankArgs.reserve(uRankSize); | ||
| 408 | + for (uint32_t rank = 0; rank < uRankSize; ++rank) { | ||
| 409 | + perRankArgs.emplace_back(uRankSize, rank, endpoint, rank); | ||
| 410 | + } | ||
| 411 | + | ||
| 412 | + examples::ProcessGroup group; | ||
| 413 | + if (!group.Launch(uRankSize, RunOneMultiPathRank, std::move(perRankArgs))) { | ||
| 414 | + return 1; | ||
| 415 | + } | ||
| 416 | + const bool pass = group.WaitAll(); | ||
| 417 | + if (group.Interrupted()) { | ||
| 418 | + std::cerr << "RESULT | Example=one_multi_path | Status=INTERRUPTED" << std::endl; | ||
| 419 | + return 1; | ||
| 420 | + } | ||
| 421 | + std::cout << "RESULT | Example=one_multi_path | Status=" << (pass ? "PASS" : "FAIL") << std::endl; | ||
| 422 | + return pass ? 0 : 1; | ||
| 423 | + } | ||
| 424 | + | ||
| 425 | + // 多机:每rank一进程,参数为 <endpoint> <rank_size> <rank> <device>。 | ||
| 426 | + if (argc != 5) { | ||
| 427 | + std::cerr << "Usage: " << argv[0] << " <tcp://ip:port> <nranks> (single machine)" << std::endl; | ||
| 428 | + std::cerr << " " << argv[0] << " <tcp://ip:port> <rank_size> <rank> <device> (per-rank, multi machine)" | ||
| 429 | + << std::endl; | ||
| 430 | + return 1; | ||
| 431 | + } | ||
| 432 | + | ||
| 433 | + uint32_t uRankSize = 0; | ||
| 434 | + uint32_t uRank = 0; | ||
| 435 | + uint32_t uDevice = 0; | ||
| 436 | + if (!examples::ParseUint32(argv[2], uRankSize, 2) || !examples::ParseUint32(argv[3], uRank) || | ||
| 437 | + !examples::ParseUint32(argv[4], uDevice) || uRank >= uRankSize) { | ||
| 438 | + std::cerr << "invalid arguments: rank_size must be at least 2, rank must be in [0, rank_size), and device " | ||
| 439 | + "must be a non-negative integer" | ||
| 440 | + << std::endl; | ||
| 441 | + return 1; | ||
| 442 | + } | ||
| 443 | + return RunOneMultiPathRank(uRankSize, uRank, argv[1], uDevice); | ||
| 444 | +} | ||
Rexamples/one_multi_path/ubmem_data_copy.asc→examples/aicore/hcomm/03_one_multi_path/ubmem_data_copy.asc+0-0
文件重命名但无更改。
| @@ -12,23 +12,12 @@ cmake_minimum_required(VERSION 3.16) | |||
| 12 | 12 | ||
| 13 | set(CMAKE_ASC_ARCHITECTURES "dav-3510" CACHE STRING "NPU architecture: dav-3510") | 13 | set(CMAKE_ASC_ARCHITECTURES "dav-3510" CACHE STRING "NPU architecture: dav-3510") |
| 14 | 14 | ||
| 15 | -if(NOT CMAKE_ASC_ARCHITECTURES STREQUAL "dav-3510") | ||
| 16 | - message(FATAL_ERROR "simt_urma only supports dav-3510, but got ${CMAKE_ASC_ARCHITECTURES}") | ||
| 17 | -endif() | ||
| 18 | - | ||
| 19 | find_package(ASC REQUIRED) | 15 | find_package(ASC REQUIRED) |
| 20 | - | ||
| 21 | project(simt_urma LANGUAGES ASC CXX) | 16 | project(simt_urma LANGUAGES ASC CXX) |
| 22 | 17 | ||
| 23 | -set(CMAKE_CXX_STANDARD 17) | ||
| 24 | -set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||
| 25 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) | 18 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) |
| 26 | 19 | ||
| 27 | -# Only the kernel is compiled as ASC. main.cpp remains on the host C++ toolchain. | 20 | +set_source_files_properties(op_kernel.cpp PROPERTIES LANGUAGE ASC) |
| 28 | -set_source_files_properties( | ||
| 29 | - op_kernel.cpp | ||
| 30 | - PROPERTIES LANGUAGE ASC | ||
| 31 | -) | ||
| 32 | 21 | ||
| 33 | add_executable(simt_urma | 22 | add_executable(simt_urma |
| 34 | main.cpp | 23 | main.cpp |
| @@ -43,13 +32,12 @@ set_target_properties(simt_urma PROPERTIES | |||
| 43 | LINKER_LANGUAGE ASC | 32 | LINKER_LANGUAGE ASC |
| 44 | ) | 33 | ) |
| 45 | 34 | ||
| 46 | -target_include_directories(simt_urma BEFORE PRIVATE | 35 | +target_include_directories(simt_urma PRIVATE |
| 47 | ${CMAKE_CURRENT_SOURCE_DIR} | 36 | ${CMAKE_CURRENT_SOURCE_DIR} |
| 37 | + ${CMAKE_CURRENT_SOURCE_DIR}/../.. | ||
| 48 | $ENV{ASCEND_HOME_PATH}/include | 38 | $ENV{ASCEND_HOME_PATH}/include |
| 49 | - $<$<COMPILE_LANGUAGE:ASC>:$ENV{ASCEND_HOME_PATH}/asc/include/adv_api> | ||
| 50 | ) | 39 | ) |
| 51 | 40 | ||
| 52 | -# Host-side communication-domain, memory-registration and channel APIs are provided by libhcomm.so. | ||
| 53 | target_link_directories(simt_urma PRIVATE | 41 | target_link_directories(simt_urma PRIVATE |
| 54 | $ENV{ASCEND_HOME_PATH}/lib64 | 42 | $ENV{ASCEND_HOME_PATH}/lib64 |
| 55 | $ENV{ASCEND_HOME_PATH}/${CMAKE_SYSTEM_PROCESSOR}-linux/lib64 | 43 | $ENV{ASCEND_HOME_PATH}/${CMAKE_SYSTEM_PROCESSOR}-linux/lib64 |
| @@ -0,0 +1,163 @@ | |||
| 1 | +# Hcomm SIMT URMA 功能样例 | ||
| 2 | + | ||
| 3 | +## 概述 | ||
| 4 | + | ||
| 5 | +本样例验证`hcomm/hcomm_simt.h`中全部SIMT URMA点对点通信接口:`WriteNbi`、`WriteValueNbi`、 | ||
| 6 | +`WriteWithNotifyNbi`、`AtomicFAA`和`AtomicCAS`,并覆盖立即提交和延迟提交两种发布方式。 | ||
| 7 | + | ||
| 8 | +拓扑为环形:每个rank把操作发送到`next = (rank + 1) % nranks`的注册内存,并校验 | ||
| 9 | +`prev = (rank - 1 + nranks) % nranks`写入的结果。每个rank既是发送方也是接收方,两侧都校验: | ||
| 10 | +`sendBuf`保存本rank原子操作取回的旧值,`recvBuf`保存prev写入的数据,环上每个`recvBuf`恰好只有 | ||
| 11 | +一个写者,因此期望值都是确定的。 | ||
| 12 | + | ||
| 13 | +所有操作均由单个SIMT线程发起。一个channel必须由一个lane驱动:延迟提交的WQE停留在发送队列中, | ||
| 14 | +由后续`commit=true`的提交发布覆盖整批PI,因此同一批任务必须由同一个lane提交。 | ||
| 15 | + | ||
| 16 | +## 本样例支持的产品及CANN软件版本 | ||
| 17 | + | ||
| 18 | +| 产品 | CANN软件版本 | | ||
| 19 | +| --- | --- | | ||
| 20 | +| Ascend 950PR/Ascend 950DT | >= CANN 9.1.0 | | ||
| 21 | + | ||
| 22 | +## 目录结构介绍 | ||
| 23 | + | ||
| 24 | +```text | ||
| 25 | +simt_urma | ||
| 26 | +├── CMakeLists.txt // 编译工程文件 | ||
| 27 | +├── main.cpp // Host侧通信域、内存注册和校验流程 | ||
| 28 | +├── op_kernel.cpp // SIMT Kernel侧URMA接口调用 | ||
| 29 | +├── simt_urma_common.h // Host与Kernel共享定义 | ||
| 30 | +├── README.md // 中文样例说明 | ||
| 31 | +└── README_en.md // 英文样例说明 | ||
| 32 | +``` | ||
| 33 | + | ||
| 34 | +## 样例描述 | ||
| 35 | + | ||
| 36 | +### 功能说明 | ||
| 37 | + | ||
| 38 | +样例提供十种测试模式,覆盖五个接口各自的立即提交与延迟提交: | ||
| 39 | + | ||
| 40 | +**Write系列** | ||
| 41 | + | ||
| 42 | +`WriteNbi`从本地缓冲区取数据,WQE中是指向该缓冲区的SGE。第`i`个slot携带值`i + 1`,因此接收侧 | ||
| 43 | +任何错值都能直接定位到它本该来自哪个slot。 | ||
| 44 | + | ||
| 45 | +`WriteValueNbi`把待写值直接内联在WQE中,不读发送缓冲区。要求`config`开启inline(默认即 | ||
| 46 | +`URMA_INLINE_CFG`),且`sizeof(T)`不超过WQE内联负载区,两者均有编译期检查。 | ||
| 47 | + | ||
| 48 | +| `mode` | 提交方式 | | ||
| 49 | +| --- | --- | | ||
| 50 | +| `write_single` | 32次独立的`WriteNbi<commit=true>` | | ||
| 51 | +| `write_batch_last` | 31次串行`WriteNbi<false>`,最后1次`WriteNbi<true>` | | ||
| 52 | +| `write_value_single` | 32次独立的`WriteValueNbi<commit=true>` | | ||
| 53 | +| `write_value_batch_last` | 31次串行`WriteValueNbi<false>`,最后1次`WriteValueNbi<true>` | | ||
| 54 | + | ||
| 55 | +**Notify/Atomic系列** | ||
| 56 | + | ||
| 57 | +| `mode` | 说明 | | ||
| 58 | +| --- | --- | | ||
| 59 | +| `notify` | 提交一次Notify操作并调用`Drain` | | ||
| 60 | +| `faa` | 提交一次FAA操作,校验远端累加结果和本地取回的旧值 | | ||
| 61 | +| `cas` | 提交一次CAS操作,校验远端交换结果和本地取回的旧值 | | ||
| 62 | +| `single`(默认) | 串行提交Notify、FAA和CAS,每次操作后分别调用`Drain` | | ||
| 63 | +| `batch_last` | Notify和FAA使用`commit=false`延迟提交,最后由`commit=true`的CAS提交整批 | | ||
| 64 | +| `notify_immediate_repeat` | 单lane连续提交`kNotifyImmediateRepeatCount`个`WriteWithNotifyNbi<true>`(当前为100),最后统一调用一次`Drain` | | ||
| 65 | + | ||
| 66 | +两个系列使用互不重叠的slot布局,缓冲区按两者中较大的布局分配。SIMT没有`Commit`接口,延迟提交 | ||
| 67 | +的任务只能由后续一次`commit=true`的提交带出;所有模式最后都调用`Drain`,确保kernel返回前CQ已被 | ||
| 68 | +消费。 | ||
| 69 | + | ||
| 70 | +### 样例规格 | ||
| 71 | + | ||
| 72 | +| 项目 | 说明 | | ||
| 73 | +| --- | --- | | ||
| 74 | +| 通信模式 | 环形拓扑SIMT URMA点对点通信 | | ||
| 75 | +| 调用方式 | SIMT Kernel内直接调用URMA接口 | | ||
| 76 | +| 测试模式 | `write_single`、`write_batch_last`、`write_value_single`、`write_value_batch_last`、`notify`、`faa`、`cas`、`single`、`batch_last`、`notify_immediate_repeat` | | ||
| 77 | +| 支持rank数 | 任意 >= 2 | | ||
| 78 | + | ||
| 79 | +### 实现流程 | ||
| 80 | + | ||
| 81 | +1. 可执行文件直接拉起全部rank进程(进程内fork,参见`examples/aicore/utils/process_manager.h`); | ||
| 82 | + rank间通过命令行指定的TCP控制通道(`examples/aicore/utils/rank_sync.h`)交换root info | ||
| 83 | + 并创建通信域。 | ||
| 84 | +2. 每个rank通过`HcclCommMemReg`注册`sendBuf`和`recvBuf`。 | ||
| 85 | +3. 通过`HcclRankGraphGetLayers`/`HcclRankGraphGetLinks`获取到`next`的链路Endpoint,调用 | ||
| 86 | + `HcclChannelAcquire`创建Channel,并通过`HcclChannelGetRemoteMems`获取对端内存地址。 | ||
| 87 | +4. Kernel侧按选定模式提交URMA操作,最后调用`Drain`等待完成。 | ||
| 88 | +5. Host侧通过控制通道的两次barrier(`ready`、`sent`)保证所有rank完成注册和写入后再回读校验。 | ||
| 89 | +6. 校验`sendBuf`取回值和`recvBuf`落地数据,输出PASS/FAIL。 | ||
| 90 | + | ||
| 91 | +## 编译运行 | ||
| 92 | + | ||
| 93 | +在本样例根目录下执行如下步骤,编译并运行样例。本样例仅支持NPU运行模式。 | ||
| 94 | + | ||
| 95 | +- 配置环境变量 | ||
| 96 | + | ||
| 97 | + 样例编译时使用已安装到CANN目录的asc-comm头文件。若尚未安装,先在仓库根目录生成并安装开发验证 | ||
| 98 | + run包,参数说明参见[`docs/zh/guide/build_and_test.md`](../../../../docs/zh/guide/build_and_test.md): | ||
| 99 | + | ||
| 100 | + ```bash | ||
| 101 | + bash build.sh --pkg | ||
| 102 | + ./build_out/cann-asc-comm_1.0.0_linux-<arch>.run --full | ||
| 103 | + ``` | ||
| 104 | + | ||
| 105 | + 然后加载CANN环境变量: | ||
| 106 | + | ||
| 107 | + ```bash | ||
| 108 | + source ${install_path}/cann/set_env.sh | ||
| 109 | + ``` | ||
| 110 | + | ||
| 111 | + > **说明:** `${install_path}`为CANN包安装目录,未指定安装目录时默认安装至`/usr/local/Ascend`。 | ||
| 112 | + | ||
| 113 | +- 样例执行 | ||
| 114 | + | ||
| 115 | + 在本样例目录下执行如下命令。可执行文件内部fork出全部rank进程,直接运行即可: | ||
| 116 | + | ||
| 117 | + ```bash | ||
| 118 | + mkdir -p build | ||
| 119 | + cd build | ||
| 120 | + cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. | ||
| 121 | + make -j | ||
| 122 | + cd .. && ./build/simt_urma tcp://127.0.0.1:29620 <nranks> [mode] | ||
| 123 | + ``` | ||
| 124 | + | ||
| 125 | +- 启动参数说明 | ||
| 126 | + | ||
| 127 | + | 参数 | 默认值 | 说明 | | ||
| 128 | + | --- | --- | --- | | ||
| 129 | + | `<ip:port>` | 无默认 | rank 0监听的控制通道地址(`tcp://ip:port`格式),用于root info交换与Host侧barrier;并行运行多个实例时错开端口 | | ||
| 130 | + | `<nranks>` | 无默认 | 通信域rank数,必须为不小于2的整数 | | ||
| 131 | + | `[mode]` | `single` | 测试模式,取值见样例描述;无法识别的mode会直接报错,不会静默回退 | | ||
| 132 | + | ||
| 133 | +- 编译选项说明 | ||
| 134 | + | ||
| 135 | + | 选项 | 可选值 | 说明 | | ||
| 136 | + | --- | --- | --- | | ||
| 137 | + | `CMAKE_ASC_RUN_MODE` | `npu`(默认) | 运行模式,本样例仅支持NPU运行 | | ||
| 138 | + | `CMAKE_ASC_ARCHITECTURES` | `dav-3510` | NPU架构,对应Ascend 950PR/Ascend 950DT | | ||
| 139 | + | ||
| 140 | +- 执行结果 | ||
| 141 | + | ||
| 142 | + 以2卡运行`write_single`为例,每个rank打印一组结果: | ||
| 143 | + | ||
| 144 | + ```text | ||
| 145 | + [rank 0] simt_urma write_single | sent to rank 1, received from rank 1 | PASS | ||
| 146 | + [rank 1] simt_urma write_single | sent to rank 0, received from rank 0 | PASS | ||
| 147 | + RESULT | Example=simt_urma Mode=write_single | Status=PASS | ||
| 148 | + ``` | ||
| 149 | + | ||
| 150 | + 所有rank均输出PASS且最终输出`Status=PASS`,表示样例执行成功。 | ||
| 151 | + | ||
| 152 | +## 注意事项 | ||
| 153 | + | ||
| 154 | +- 运行样例需要至少2张NPU;单卡环境仅支持编译验证。 | ||
| 155 | +- Kernel侧通过`AscendC::simt::LocalBufferAddr`和`RemoteBufferAddr`解析缓冲区基址时,传入的是 | ||
| 156 | + 通道缓冲区表的下标,而不是`memHandles`数组下标:本地表下标0由CCL buffer预留,第一个显式注册的 | ||
| 157 | + 缓冲区使用下标1;远端缓冲区下标通过`HcclChannelGetRemoteMems`按tag查找。直接传`memHandles` | ||
| 158 | + 下标会解析到CCL buffer,此时CQE正常返回但接收方看到的是CCL buffer内容而非payload。 | ||
| 159 | +- Host侧`sent` barrier是校验结果可信的关键:没有它,某rank会在写入方kernel尚未完成时读到清零的 | ||
| 160 | + 缓冲区。 | ||
| 161 | +- 可执行文件捕获`SIGINT`/`SIGTERM`并终止全部rank进程,Ctrl+C不会留下阻塞在Host barrier上、 | ||
| 162 | + 仍占用设备的进程。 | ||
| 163 | +- 编译依赖CANN ASC CMake能力,并在链接阶段依赖CANN `hcomm`库。 | ||
| @@ -72,71 +72,64 @@ sized to whichever layout is larger. | |||
| 72 | SIMT has no `Commit` interface, so a deferred task can only be carried out by a later `commit=true` | 72 | SIMT has no `Commit` interface, so a deferred task can only be carried out by a later `commit=true` |
| 73 | post. Every mode ends with `Drain` to make sure the CQ has been consumed before the kernel returns. | 73 | post. Every mode ends with `Drain` to make sure the CQ has been consumed before the kernel returns. |
| 74 | 74 | ||
| 75 | -## Preparing the Development Verification Environment | 75 | +## Build and Run |
| 76 | 76 | ||
| 77 | -The sample builds against the asc-comm headers installed into the CANN directory. Generate and | 77 | +Perform the following steps in the sample root directory. This sample supports NPU run mode only. |
| 78 | -install the development verification run package from the repository root first: | ||
| 79 | 78 | ||
| 80 | -```bash | 79 | +- Set Environment Variables |
| 81 | -source /usr/local/Ascend/cann/set_env.sh | ||
| 82 | -bash build.sh --pkg | ||
| 83 | -./build_out/cann-asc-comm_1.0.0_linux-<arch>.run --full | ||
| 84 | -``` | ||
| 85 | 80 | ||
| 86 | -Pass `--install-path=/path/to/cann` to select a different CANN directory. See | 81 | + The sample builds against the asc-comm headers installed into the CANN directory. If not yet |
| 87 | -[`docs/en/guide/build_and_test.md`](../../docs/en/guide/build_and_test.md) for the full option list. | 82 | + installed, generate and install the development verification run package from the repository root |
| 83 | + (see [`docs/en/guide/build_and_test.md`](../../../../docs/en/guide/build_and_test.md)): | ||
| 88 | 84 | ||
| 89 | -## Build | 85 | + ```bash |
| 86 | + bash build.sh --pkg | ||
| 87 | + ./build_out/cann-asc-comm_1.0.0_linux-<arch>.run --full | ||
| 88 | + ``` | ||
| 90 | 89 | ||
| 91 | -```bash | 90 | + Then load the CANN environment: |
| 92 | -cd examples/simt_urma | ||
| 93 | -bash build.sh | ||
| 94 | -``` | ||
| 95 | 91 | ||
| 96 | -`build.sh` removes the existing `build` directory before reconfiguring and rebuilding, so stale | 92 | + ```bash |
| 97 | -headers and object files are never reused. | 93 | + source ${install_path}/cann/set_env.sh |
| 94 | + ``` | ||
| 98 | 95 | ||
| 99 | -The output is `examples/simt_urma/build/simt_urma`. | 96 | + > **Note:** `${install_path}` is the CANN installation directory. If not specified, the default is |
| 97 | + > `/usr/local/Ascend`. | ||
| 100 | 98 | ||
| 101 | -## Run | 99 | +- Run the Sample |
| 102 | 100 | ||
| 103 | -The communicator is created with `HcclGetRootInfo` and `HcclCommInitRootInfo`, so no rank table is | 101 | + The executable forks all rank processes internally: |
| 104 | -required. `run.sh` creates a temporary root info file for each run, written by rank 0 and read by the | ||
| 105 | -other ranks. Rank `i` runs on device `i`. | ||
| 106 | 102 | ||
| 107 | -```bash | 103 | + ```bash |
| 108 | -examples/simt_urma/run.sh <nranks> [mode] | 104 | + mkdir -p build |
| 109 | -``` | 105 | + cd build |
| 106 | + cmake -DCMAKE_ASC_ARCHITECTURES=dav-3510 .. | ||
| 107 | + make -j | ||
| 108 | + cd .. && ./build/simt_urma tcp://127.0.0.1:29620 <nranks> [mode] | ||
| 109 | + ``` | ||
| 110 | 110 | ||
| 111 | -`nranks` may be any value >= 2: every rank sends and receives on the ring. | 111 | + | Parameter | Default | Description | |
| 112 | + | --- | --- | --- | | ||
| 113 | + | `<ip:port>` | Required | Control channel address that rank 0 listens on (`tcp://ip:port`); use different ports for parallel instances | | ||
| 114 | + | `<nranks>` | Required | Number of ranks; must be >= 2 | | ||
| 115 | + | `[mode]` | `single` | Test mode; see Test Modes above; unrecognized modes are rejected outright | | ||
| 112 | 116 | ||
| 113 | -An unrecognized `mode` is rejected outright rather than silently falling back to the default. | 117 | +- Build Options |
| 114 | 118 | ||
| 115 | -```bash | 119 | + | Option | Values | Description | |
| 116 | -examples/simt_urma/run.sh 2 write_single | 120 | + | --- | --- | --- | |
| 117 | -examples/simt_urma/run.sh 2 write_batch_last | 121 | + | `CMAKE_ASC_RUN_MODE` | `npu` (default) | Run mode; this sample supports NPU execution only | |
| 118 | -examples/simt_urma/run.sh 2 write_value_single | 122 | + | `CMAKE_ASC_ARCHITECTURES` | `dav-3510` | NPU architecture for Ascend 950PR/Ascend 950DT | |
| 119 | -examples/simt_urma/run.sh 2 write_value_batch_last | ||
| 120 | -examples/simt_urma/run.sh 2 notify | ||
| 121 | -examples/simt_urma/run.sh 2 faa | ||
| 122 | -examples/simt_urma/run.sh 2 cas | ||
| 123 | -examples/simt_urma/run.sh 2 single | ||
| 124 | -examples/simt_urma/run.sh 2 batch_last | ||
| 125 | -examples/simt_urma/run.sh 2 notify_immediate_repeat | ||
| 126 | -``` | ||
| 127 | 123 | ||
| 128 | -Expected output (two cards, one group printed per rank): | 124 | +- Expected Output |
| 129 | 125 | ||
| 130 | -```text | 126 | + ```text |
| 131 | -[rank 0] simt_urma mode=<mode> sending to rank 1 | 127 | + [rank 0] simt_urma write_single | sent to rank 1, received from rank 1 | PASS |
| 132 | -[rank 1] simt_urma mode=<mode> sending to rank 0 | 128 | + [rank 1] simt_urma write_single | sent to rank 0, received from rank 0 | PASS |
| 133 | -[rank 0] simt_urma <mode> PASS | sent to rank 1, received from rank 1 | 129 | + RESULT | Example=simt_urma Mode=write_single | Status=PASS |
| 134 | -[rank 1] simt_urma <mode> PASS | sent to rank 0, received from rank 0 | 130 | + ``` |
| 135 | -RESULT | Mode=<mode> | Status=PASS | ||
| 136 | -``` | ||
| 137 | 131 | ||
| 138 | -`run.sh` traps `SIGINT`/`SIGTERM` and kills the rank processes it started, so Ctrl+C does not leave | 132 | + The sample succeeds when all ranks print `PASS` and the final status is `PASS`. |
| 139 | -processes blocked on a host barrier still holding devices. | ||
| 140 | 133 | ||
| 141 | ## Buffer Index Constraints | 134 | ## Buffer Index Constraints |
| 142 | 135 | ||
| @@ -153,8 +146,8 @@ receiver observes the CCL buffer's contents rather than the payload. | |||
| 153 | 146 | ||
| 154 | ## Host-side Synchronization | 147 | ## Host-side Synchronization |
| 155 | 148 | ||
| 156 | -Two host barriers make the verification trustworthy. They use marker files in a temporary directory | 149 | +Two host barriers make the verification trustworthy. They use the `RankSyncContext` barrier |
| 157 | -created fresh for each run. | 150 | +primitives over the TCP control channel. |
| 158 | 151 | ||
| 159 | | Barrier | Purpose | | 152 | | Barrier | Purpose | |
| 160 | |---|---| | 153 | |---|---| |
| @@ -165,14 +158,10 @@ The `sent` barrier is what makes the result trustworthy. Without it a rank runs | |||
| 165 | to `aclrtMemcpy` with no ordering constraint against the kernel of the rank writing into it, reads | 158 | to `aclrtMemcpy` with no ordering constraint against the kernel of the rank writing into it, reads |
| 166 | the zeroed buffer, and reports every slot as never landed even though all CQEs returned cleanly. | 159 | the zeroed buffer, and reports every slot as never landed even though all CQEs returned cleanly. |
| 167 | 160 | ||
| 168 | -The directory path is passed as a command-line argument rather than an environment variable: an | ||
| 169 | -exported variable is easy to lose across a shell wrapper or a scheduler, and once lost every rank | ||
| 170 | -silently falls back to the same default directory, where markers left by an earlier run can let a | ||
| 171 | -barrier pass immediately. | ||
| 172 | - | ||
| 173 | ## Runtime Constraints | 161 | ## Runtime Constraints |
| 174 | 162 | ||
| 175 | - Supported chips: Ascend 950PR / Ascend 950DT. CANN version 9.1.0 or later is required. | 163 | - Supported chips: Ascend 950PR / Ascend 950DT. CANN version 9.1.0 or later is required. |
| 176 | -- At least two NPUs on the same host are required to run; single-NPU environments only support | 164 | +- At least two NPUs are required to run; single-NPU environments only support compilation verification. |
| 177 | - compilation verification. | 165 | +- The executable captures `SIGINT`/`SIGTERM` and terminates all rank processes, so Ctrl+C does not |
| 166 | + leave processes blocked on a host barrier still holding devices. | ||
| 178 | - The build relies on CANN ASC CMake utilities and links against the CANN `hcomm` library. | 167 | - The build relies on CANN ASC CMake utilities and links against the CANN `hcomm` library. |
| @@ -13,44 +13,29 @@ | |||
| 13 | * \brief Hcomm SIMT URMA功能样例Host侧流程:通信域创建、内存注册、P2P通道创建与结果校验 | 13 | * \brief Hcomm SIMT URMA功能样例Host侧流程:通信域创建、内存注册、P2P通道创建与结果校验 |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | -#include <cerrno> | ||
| 17 | #include <chrono> | 16 | #include <chrono> |
| 18 | #include <cstdint> | 17 | #include <cstdint> |
| 19 | #include <cstdio> | 18 | #include <cstdio> |
| 20 | #include <cstdlib> | 19 | #include <cstdlib> |
| 21 | #include <cstring> | 20 | #include <cstring> |
| 22 | -#include <fstream> | ||
| 23 | #include <iostream> | 21 | #include <iostream> |
| 24 | #include <string> | 22 | #include <string> |
| 25 | #include <thread> | 23 | #include <thread> |
| 26 | #include <vector> | 24 | #include <vector> |
| 27 | 25 | ||
| 28 | -#include <sys/stat.h> | ||
| 29 | -#include <sys/types.h> | ||
| 30 | - | ||
| 31 | #include "hccl/hccl.h" | 26 | #include "hccl/hccl.h" |
| 32 | #include "hccl/hccl_res.h" | 27 | #include "hccl/hccl_res.h" |
| 33 | #include "hccl/hccl_types.h" | 28 | #include "hccl/hccl_types.h" |
| 34 | #include "hccl/hccl_rank_graph.h" | 29 | #include "hccl/hccl_rank_graph.h" |
| 35 | 30 | ||
| 31 | +#include "utils/check.h" | ||
| 32 | +#include "utils/hccl_comm_init.h" | ||
| 33 | +#include "utils/process_manager.h" | ||
| 34 | +#include "utils/rank_sync.h" | ||
| 35 | +#include "utils/arg_parser.h" | ||
| 36 | + | ||
| 36 | #include "simt_urma_common.h" | 37 | #include "simt_urma_common.h" |
| 37 | 38 | ||
| 38 | -#define ACLCHECK(ret) \ | ||
| 39 | - do { \ | ||
| 40 | - if ((ret) != ACL_SUCCESS) { \ | ||
| 41 | - printf("acl interface return err %s:%d, retcode: %d \n", __FILE__, __LINE__, (ret)); \ | ||
| 42 | - return (ret); \ | ||
| 43 | - } \ | ||
| 44 | - } while (0) | ||
| 45 | - | ||
| 46 | -#define HCCLCHECK(ret) \ | ||
| 47 | - do { \ | ||
| 48 | - if ((ret) != HCCL_SUCCESS) { \ | ||
| 49 | - printf("hccl interface return err %s:%d, retcode: %d \n", __FILE__, __LINE__, (ret)); \ | ||
| 50 | - return (ret); \ | ||
| 51 | - } \ | ||
| 52 | - } while (0) | ||
| 53 | - | ||
| 54 | extern void LaunchSimtUrma(void* stream, uint64_t channel, uint32_t sendBufIdx, uint32_t recvBufIdx, uint32_t mode); | 39 | extern void LaunchSimtUrma(void* stream, uint64_t channel, uint32_t sendBufIdx, uint32_t recvBufIdx, uint32_t mode); |
| 55 | 40 | ||
| 56 | namespace { | 41 | namespace { |
Rexamples/simt_urma_perftest/CMakeLists.txt→examples/aicore/hcomm/05_simt_urma_perftest/CMakeLists.txt+26-10
| @@ -10,34 +10,50 @@ | |||
| 10 | 10 | ||
| 11 | cmake_minimum_required(VERSION 3.16) | 11 | cmake_minimum_required(VERSION 3.16) |
| 12 | 12 | ||
| 13 | -set(CMAKE_ASC_ARCHITECTURES "dav-3510" CACHE STRING "NPU architecture") | 13 | +set(CMAKE_ASC_ARCHITECTURES "dav-3510" CACHE STRING "NPU architecture: dav-3510") |
| 14 | + | ||
| 14 | find_package(ASC REQUIRED) | 15 | find_package(ASC REQUIRED) |
| 15 | project(simt_urma_perftest LANGUAGES ASC CXX) | 16 | project(simt_urma_perftest LANGUAGES ASC CXX) |
| 16 | 17 | ||
| 17 | -set(CMAKE_CXX_STANDARD 17) | ||
| 18 | -set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||
| 19 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) | 18 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) |
| 20 | 19 | ||
| 21 | set_source_files_properties(op_kernel.cpp PROPERTIES LANGUAGE ASC) | 20 | set_source_files_properties(op_kernel.cpp PROPERTIES LANGUAGE ASC) |
| 22 | -add_executable(simt_urma_perftest main.cpp op_kernel.cpp) | 21 | + |
| 22 | +add_executable(simt_urma_perftest | ||
| 23 | + main.cpp | ||
| 24 | + op_kernel.cpp | ||
| 25 | +) | ||
| 23 | 26 | ||
| 24 | target_compile_definitions(simt_urma_perftest PRIVATE | 27 | target_compile_definitions(simt_urma_perftest PRIVATE |
| 25 | USE_SIMT | 28 | USE_SIMT |
| 26 | ) | 29 | ) |
| 27 | -set_target_properties(simt_urma_perftest PROPERTIES LINKER_LANGUAGE ASC) | ||
| 28 | 30 | ||
| 29 | -target_include_directories(simt_urma_perftest BEFORE PRIVATE | 31 | +set_target_properties(simt_urma_perftest PROPERTIES |
| 30 | - ${CMAKE_CURRENT_SOURCE_DIR} | 32 | + LINKER_LANGUAGE ASC |
| 31 | - $ENV{ASCEND_HOME_PATH}/include | ||
| 32 | - $<$<COMPILE_LANGUAGE:ASC>:$ENV{ASCEND_HOME_PATH}/asc/include/adv_api> | ||
| 33 | ) | 33 | ) |
| 34 | + | ||
| 35 | +target_include_directories(simt_urma_perftest PRIVATE | ||
| 36 | + ${CMAKE_CURRENT_SOURCE_DIR} | ||
| 37 | + ${CMAKE_CURRENT_SOURCE_DIR}/../.. | ||
| 38 | + $ENV{ASCEND_HOME_PATH}/include | ||
| 39 | +) | ||
| 40 | + | ||
| 34 | target_link_directories(simt_urma_perftest PRIVATE | 41 | target_link_directories(simt_urma_perftest PRIVATE |
| 35 | $ENV{ASCEND_HOME_PATH}/lib64 | 42 | $ENV{ASCEND_HOME_PATH}/lib64 |
| 36 | $ENV{ASCEND_HOME_PATH}/${CMAKE_SYSTEM_PROCESSOR}-linux/lib64 | 43 | $ENV{ASCEND_HOME_PATH}/${CMAKE_SYSTEM_PROCESSOR}-linux/lib64 |
| 37 | ) | 44 | ) |
| 45 | + | ||
| 38 | target_link_libraries(simt_urma_perftest PRIVATE | 46 | target_link_libraries(simt_urma_perftest PRIVATE |
| 39 | - hcomm hccl ascendcl acl_rt runtime c_sec dl pthread | 47 | + hcomm |
| 48 | + hccl | ||
| 49 | + ascendcl | ||
| 50 | + acl_rt | ||
| 51 | + runtime | ||
| 52 | + c_sec | ||
| 53 | + dl | ||
| 54 | + pthread | ||
| 40 | ) | 55 | ) |
| 56 | + | ||
| 41 | target_compile_options(simt_urma_perftest PRIVATE | 57 | target_compile_options(simt_urma_perftest PRIVATE |
| 42 | $<$<COMPILE_LANGUAGE:ASC>:--npu-arch=${CMAKE_ASC_ARCHITECTURES}> | 58 | $<$<COMPILE_LANGUAGE:ASC>:--npu-arch=${CMAKE_ASC_ARCHITECTURES}> |
| 43 | $<$<COMPILE_LANGUAGE:ASC>:--cce-auto-infer-kernel-type=false> | 59 | $<$<COMPILE_LANGUAGE:ASC>:--cce-auto-infer-kernel-type=false> |
Rexamples/simt_urma_perftest/README_en.md→examples/aicore/hcomm/05_simt_urma_perftest/README_en.md+67-35
Rexamples/simt_urma_perftest/op_kernel.cpp→examples/aicore/hcomm/05_simt_urma_perftest/op_kernel.cpp+0-0
Rexamples/simt_urma_perftest/simt_urma_perftest_common.h→examples/aicore/hcomm/05_simt_urma_perftest/simt_urma_perftest_common.h+0-0


为什么统一成最麻烦的方式呢