已合并
feat(libtorch_npu): add HCCL test case for libtorch_npu #31741
kuhn7创建于 3月12日
feat(libtorch_npu): add HCCL test case for libtorch_npu #31741
已合并
共 8 个文件变更+305-9
| @@ -228,9 +228,10 @@ def copy_hpp(): | |||
| 228 | "torch_npu/csrc/libs/*.h", | 228 | "torch_npu/csrc/libs/*.h", |
| 229 | "torch_npu/csrc/inductor/**/*.h", | 229 | "torch_npu/csrc/inductor/**/*.h", |
| 230 | "torch_npu/csrc/distributed/*.h", | 230 | "torch_npu/csrc/distributed/*.h", |
| 231 | - "torch_npu/csrc/distributed/*/*.h", | ||
| 232 | "torch_npu/csrc/distributed/*.hpp", | 231 | "torch_npu/csrc/distributed/*.hpp", |
| 233 | - "torch_npu/csrc/distributed/*/*.hpp", | 232 | + "third_party/acl/inc/*/*.h", |
| 233 | + "third_party/acl/inc/*/*/*.h", | ||
| 234 | + "third_party/hccl/inc/*/*.h", | ||
| 234 | ] | 235 | ] |
| 235 | glob_header_files = [] | 236 | glob_header_files = [] |
| 236 | for regex_pattern in header_files: | 237 | for regex_pattern in header_files: |
| @@ -0,0 +1,76 @@ | |||
| 1 | +cmake_minimum_required(VERSION 3.18 FATAL_ERROR) | ||
| 2 | + | ||
| 3 | +project(HCCLAllreduceExample CXX C) | ||
| 4 | + | ||
| 5 | +set(CMAKE_CXX_STANDARD 17) | ||
| 6 | +set(CMAKE_C_STANDARD 11) | ||
| 7 | +set(CMAKE_CXX_EXTENSIONS OFF) | ||
| 8 | + | ||
| 9 | +# 定义构建类型 | ||
| 10 | +IF(CMAKE_BUILD_TYPE MATCHES Debug) | ||
| 11 | + message("Debug构建") | ||
| 12 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_DEBUG") | ||
| 13 | +ELSEIF(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo) | ||
| 14 | + message("RelWithDebInfo构建") | ||
| 15 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG") | ||
| 16 | +ELSE() | ||
| 17 | + message("Release构建") | ||
| 18 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG") | ||
| 19 | +ENDIF() | ||
| 20 | + | ||
| 21 | +SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") | ||
| 22 | +SET(CMAKE_CXX_FLAGS_RELEASE "-O2") | ||
| 23 | +SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") | ||
| 24 | + | ||
| 25 | +# 自动查找libtorch路径 | ||
| 26 | +# 优先使用环境变量,如果未设置则自动从Python获取 | ||
| 27 | +if(DEFINED ENV{TORCH_INSTALL_DIR}) | ||
| 28 | + set(torch_path "$ENV{TORCH_INSTALL_DIR}") | ||
| 29 | +else() | ||
| 30 | + execute_process( | ||
| 31 | + COMMAND ${PYTHON_EXECUTABLE} -c "import torch; import os; print(os.path.dirname(torch.__file__))" | ||
| 32 | + OUTPUT_VARIABLE torch_path | ||
| 33 | + OUTPUT_STRIP_TRAILING_WHITESPACE | ||
| 34 | + ERROR_QUIET | ||
| 35 | + ) | ||
| 36 | +endif() | ||
| 37 | + | ||
| 38 | +if(NOT EXISTS ${torch_path}) | ||
| 39 | + message(FATAL_ERROR "未找到libtorch安装目录,请设置环境变量TORCH_INSTALL_DIR或确保Python环境中已安装torch") | ||
| 40 | +endif() | ||
| 41 | +message(STATUS "libtorch路径: ${torch_path}") | ||
| 42 | +include_directories(${torch_path}/include) | ||
| 43 | +# c10d/ProcessGroup.hpp | ||
| 44 | +include_directories(${torch_path}/include/torch/csrc/distributed) | ||
| 45 | +# torch/torch.h | ||
| 46 | +include_directories(${torch_path}/include/torch/csrc/api/include) | ||
| 47 | +link_directories(${torch_path}/lib) | ||
| 48 | + | ||
| 49 | + | ||
| 50 | +# 使用环境变量查找libtorch_npu路径 | ||
| 51 | +if(DEFINED ENV{TORCH_NPU_INSTALL_DIR}) | ||
| 52 | + set(torch_npu_path "$ENV{TORCH_NPU_INSTALL_DIR}") | ||
| 53 | +endif() | ||
| 54 | + | ||
| 55 | + | ||
| 56 | +if(NOT EXISTS ${torch_npu_path}) | ||
| 57 | + message(WARNING "未找到libtorch_npu安装目录,请设置环境变量TORCH_NPU_INSTALL_DIR") | ||
| 58 | +else() | ||
| 59 | + message(STATUS "libtorch_npu路径: ${torch_npu_path}") | ||
| 60 | + include_directories(${torch_npu_path}/include) | ||
| 61 | + link_directories(${torch_npu_path}/lib) | ||
| 62 | +endif() | ||
| 63 | + | ||
| 64 | +# arm环境构建依赖torch.libs/*.so库,需要手动加载 | ||
| 65 | +# link_directories(<python path>/site-packages/torch.libs) | ||
| 66 | + | ||
| 67 | +# 添加可执行文件 | ||
| 68 | +add_executable(example_allreduce_hccl allreduce_hccl.cpp) | ||
| 69 | + | ||
| 70 | +# 链接库 | ||
| 71 | +target_link_libraries(example_allreduce_hccl | ||
| 72 | + -ltorch | ||
| 73 | + -ltorch_cpu | ||
| 74 | + -lc10 | ||
| 75 | + -ltorch_npu | ||
| 76 | +) | ||
| @@ -0,0 +1,85 @@ | |||
| 1 | +# HCCL AllReduce 示例 | ||
| 2 | + | ||
| 3 | +这是一个独立的HCCL集合通信测试用例,用于验证NPU设备上的ProcessGroupHCCL功能。 | ||
| 4 | + | ||
| 5 | +## 文件说明 | ||
| 6 | + | ||
| 7 | +- `allreduce_hccl.cpp` - HCCL allreduce示例代码 | ||
| 8 | +- `CMakeLists.txt` - 独立的CMake构建文件 | ||
| 9 | +- `libtorch_hccl.sh` - 运行脚本 | ||
| 10 | + | ||
| 11 | +## 构建 | ||
| 12 | + | ||
| 13 | +### 1. 环境准备 | ||
| 14 | + | ||
| 15 | +CMakeLists.txt会自动从Python环境检测libtorch的安装路径。 | ||
| 16 | + | ||
| 17 | +**自动检测**(推荐): | ||
| 18 | +- 确保Python环境中已安装torch | ||
| 19 | +- CMake会自动从Python获取路径 | ||
| 20 | + | ||
| 21 | +**手动指定**(可选): | ||
| 22 | +```bash | ||
| 23 | +# 如果自动检测失败,可以手动设置环境变量 | ||
| 24 | +export TORCH_INSTALL_DIR=/path/to/torch # 通常在 site-packages/torch | ||
| 25 | +export TORCH_NPU_INSTALL_DIR=/path/to/torch_npu | ||
| 26 | +``` | ||
| 27 | + | ||
| 28 | +### 2. 构建示例 | ||
| 29 | + | ||
| 30 | +```bash | ||
| 31 | +cd examples/libtorch_hccl | ||
| 32 | +mkdir build && cd build | ||
| 33 | +cmake .. | ||
| 34 | +make | ||
| 35 | +``` | ||
| 36 | + | ||
| 37 | +## 运行 | ||
| 38 | + | ||
| 39 | +### 方法: | ||
| 40 | + | ||
| 41 | +```bash | ||
| 42 | +cd examples/libtorch_hccl | ||
| 43 | +chmod +x libtorch_hccl.sh | ||
| 44 | +./libtorch_hccl.sh | ||
| 45 | +``` | ||
| 46 | + | ||
| 47 | +自定义进程数: | ||
| 48 | +```bash | ||
| 49 | +NUM_PROCESSES=4 ./libtorch_hccl.sh | ||
| 50 | +``` | ||
| 51 | + | ||
| 52 | +## 预期输出 | ||
| 53 | + | ||
| 54 | +``` | ||
| 55 | +启动HCCL allreduce示例: rank=0, size=2 | ||
| 56 | +NPU设备 0 初始化完成 | ||
| 57 | +在NPU设备 0 上创建了 10 个张量 | ||
| 58 | +已提交 10 个allreduce操作 | ||
| 59 | +所有操作已完成! | ||
| 60 | +张量 0 第一个元素: 2.0 | ||
| 61 | +张量 1 第一个元素: 2.0 | ||
| 62 | +张量 2 第一个元素: 2.0 | ||
| 63 | +HCCL allreduce示例运行成功! | ||
| 64 | +``` | ||
| 65 | + | ||
| 66 | +值 `2.0` 是2个进程对全1张量进行allreduce求和的结果 (1+1=2)。 | ||
| 67 | + | ||
| 68 | +## 代码说明 | ||
| 69 | + | ||
| 70 | +示例演示了以下关键步骤: | ||
| 71 | + | ||
| 72 | +1. **NPU设备初始化**: 使用 `torch_npu::init_npu("npu:0")` 初始化设备 | ||
| 73 | +2. **创建ProcessGroupHCCL**: 用于NPU集合通信 | ||
| 74 | +3. **创建张量**: 在NPU设备上创建张量 | ||
| 75 | +4. **执行allreduce**: 对张量进行全局归约操作 | ||
| 76 | +5. **验证结果**: 检查归约结果是否正确 | ||
| 77 | +6. **资源清理**: 调用 `torch_npu::finalize_npu()` 释放资源 | ||
| 78 | + | ||
| 79 | +## 注意事项 | ||
| 80 | + | ||
| 81 | +- 确保NPU设备可用且CANN已正确安装 | ||
| 82 | +- 使用NPU设备结束后必须调用 `torch_npu::finalize_npu()` 释放资源 | ||
| 83 | +- 所有进程需要同时启动才能正常工作 | ||
| 84 | +- libtorch通常安装在Python的site-packages/torch目录下 | ||
| 85 | +- libtorch_npu通常使用build_libtorch_npu.py脚本构建安装 | ||
| @@ -0,0 +1,87 @@ | |||
| 1 | + | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + | ||
| 5 | + | ||
| 6 | + | ||
| 7 | + | ||
| 8 | + | ||
| 9 | + | ||
| 10 | +using namespace c10d; | ||
| 11 | +using namespace c10d_npu; | ||
| 12 | + | ||
| 13 | +const int g_rank = []() { | ||
| 14 | + const char* env = std::getenv("RANK"); | ||
| 15 | + return env ? std::stoi(std::string(env)) : 0; | ||
| 16 | +}(); | ||
| 17 | + | ||
| 18 | +const int g_size = []() { | ||
| 19 | + const char* env = std::getenv("SIZE"); | ||
| 20 | + return env ? std::stoi(std::string(env)) : 1; | ||
| 21 | +}(); | ||
| 22 | + | ||
| 23 | +int main(int argc, char** argv) | ||
| 24 | +{ | ||
| 25 | + int rank = g_rank; | ||
| 26 | + int size = g_size; | ||
| 27 | + | ||
| 28 | + std::cout << "启动 HCCL allreduce 示例: rank=" << rank << ", size=" << size << std::endl; | ||
| 29 | + | ||
| 30 | + // 初始化NPU设备 - 使用npu字符串格式 | ||
| 31 | + std::string device_str = "npu:" + std::to_string(rank); | ||
| 32 | + torch_npu::init_npu(device_str); | ||
| 33 | + std::cout << "NPU设备 " << rank << " 初始化完成" << std::endl; | ||
| 34 | + | ||
| 35 | + // 创建FileStore用于进程间通信协调 | ||
| 36 | + auto store = c10::make_intrusive<FileStore>("/tmp/c10d_hccl_example", size); | ||
| 37 | + | ||
| 38 | + // 创建ProcessGroupHCCL选项 | ||
| 39 | + auto options = ProcessGroupHCCL::Options::create(); | ||
| 40 | + | ||
| 41 | + // 创建ProcessGroupHCCL实例 | ||
| 42 | + auto pg = c10::make_intrusive<ProcessGroupHCCL>(store, rank, size, options); | ||
| 43 | + | ||
| 44 | + // 通过传NPU字符串构造NPU设备 | ||
| 45 | + auto device = at::Device(device_str); | ||
| 46 | + | ||
| 47 | + // 创建10个张量用于测试 | ||
| 48 | + const auto ntensors = 10; | ||
| 49 | + std::vector<at::Tensor> tensors; | ||
| 50 | + | ||
| 51 | + for (const auto i : c10::irange(ntensors)) { | ||
| 52 | + // 在NPU设备上创建全1张量 | ||
| 53 | + auto x = at::ones({1000, 16 * (i + 1)}, at::TensorOptions(device).dtype(at::kFloat)); | ||
| 54 | + tensors.push_back(x); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + std::cout << "在NPU设备 " << rank << " 上创建了 " << ntensors << " 个张量" << std::endl; | ||
| 58 | + | ||
| 59 | + // 提交所有allreduce操作 | ||
| 60 | + std::vector<c10::intrusive_ptr<Work>> pending; | ||
| 61 | + for (const auto i : c10::irange(ntensors)) { | ||
| 62 | + std::vector<at::Tensor> tmp = {tensors[i]}; | ||
| 63 | + pending.push_back(pg->allreduce(tmp)); | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + std::cout << "已提交 " << ntensors << " 个allreduce操作" << std::endl; | ||
| 67 | + | ||
| 68 | + // 等待所有操作完成 | ||
| 69 | + for (auto& work : pending) { | ||
| 70 | + work->wait(); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + std::cout << "所有操作已完成!" << std::endl; | ||
| 74 | + | ||
| 75 | + // 验证结果 - 打印前3个张量的第一个元素 | ||
| 76 | + for (const auto i : c10::irange(std::min(ntensors, 3))) { | ||
| 77 | + auto cpu_tensor = tensors[i].to(at::kCPU); | ||
| 78 | + std::cout << "张量 " << i << " 第一个元素: " << cpu_tensor.data_ptr<float>()[0] << std::endl; | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + std::cout << "HCCL allreduce示例运行成功!" << std::endl; | ||
| 82 | + | ||
| 83 | + // 使用NPU设备结束需进行反初始化 | ||
| 84 | + torch_npu::finalize_npu(); | ||
| 85 | + | ||
| 86 | + return 0; | ||
| 87 | +} | ||
| @@ -0,0 +1,44 @@ | |||
| 1 | +#!/bin/bash | ||
| 2 | + | ||
| 3 | +set -e | ||
| 4 | + | ||
| 5 | +# 默认使用2个进程 | ||
| 6 | +NUM_PROCESSES=${NUM_PROCESSES:-2} | ||
| 7 | + | ||
| 8 | +# 获取脚本所在目录 | ||
| 9 | +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| 10 | + | ||
| 11 | +# 检查二进制文件是否存在 | ||
| 12 | +if [ ! -f "${SCRIPT_DIR}/build/example_allreduce_hccl" ]; then | ||
| 13 | + echo "错误: 未找到example_allreduce_hccl二进制文件" | ||
| 14 | + echo "请先构建项目:" | ||
| 15 | + echo " cd ${SCRIPT_DIR}" | ||
| 16 | + echo " mkdir build && cd build" | ||
| 17 | + echo " cmake .." | ||
| 18 | + echo " make" | ||
| 19 | + exit 1 | ||
| 20 | +fi | ||
| 21 | + | ||
| 22 | +echo "运行HCCL allreduce示例,进程数: ${NUM_PROCESSES}" | ||
| 23 | +echo "二进制文件: ${SCRIPT_DIR}/build/example_allreduce_hccl" | ||
| 24 | + | ||
| 25 | +# 清理之前的临时文件 | ||
| 26 | +rm -f /tmp/c10d_hccl_example | ||
| 27 | + | ||
| 28 | +# 启动多个进程 | ||
| 29 | +pids=() | ||
| 30 | +for ((rank=0; rank<NUM_PROCESSES; rank++)); do | ||
| 31 | + echo "启动进程 ${rank}" | ||
| 32 | + RANK=${rank} SIZE=${NUM_PROCESSES} \ | ||
| 33 | + "${SCRIPT_DIR}/build/example_allreduce_hccl" & | ||
| 34 | + pids+=($!) | ||
| 35 | +done | ||
| 36 | + | ||
| 37 | +# 等待所有进程完成 | ||
| 38 | +for pid in "${pids[@]}"; do | ||
| 39 | + wait ${pid} | ||
| 40 | +done | ||
| 41 | + | ||
| 42 | +echo "所有进程已完成!" | ||
| 43 | +# 清理临时文件 | ||
| 44 | +rm -f /tmp/c10d_hccl_example | ||
| @@ -57,9 +57,7 @@ | |||
| 57 | 57 | ||
| 58 | 58 | ||
| 59 | 59 | ||
| 60 | - | ||
| 61 | 60 | ||
| 62 | - | ||
| 63 | namespace py = pybind11; | 61 | namespace py = pybind11; |
| 64 | using namespace py::literals; | 62 | using namespace py::literals; |
| 65 | 63 | ||
| @@ -3455,11 +3453,9 @@ std::string ProcessGroupHCCL::getMstxHcclMsg( | |||
| 3455 | {HCCL_DATA_TYPE_BFP16, "bfp16"} | 3453 | {HCCL_DATA_TYPE_BFP16, "bfp16"} |
| 3456 | }; | 3454 | }; |
| 3457 | static std::map<HcclComm, std::string> commNames; | 3455 | static std::map<HcclComm, std::string> commNames; |
| 3458 | - | ||
| 3459 | if (!torch_npu::profiler::mstxEnable()) { | 3456 | if (!torch_npu::profiler::mstxEnable()) { |
| 3460 | return ""; | 3457 | return ""; |
| 3461 | } | 3458 | } |
| 3462 | - | ||
| 3463 | std::unordered_map<std::string, std::string> msgDict; | 3459 | std::unordered_map<std::string, std::string> msgDict; |
| 3464 | msgDict["opName"] = opName; | 3460 | msgDict["opName"] = opName; |
| 3465 | auto nameIter = commNames.find(comm); | 3461 | auto nameIter = commNames.find(comm); |
| @@ -6,6 +6,9 @@ | |||
| 6 | 6 | ||
| 7 | 7 | ||
| 8 | 8 | ||
| 9 | + | ||
| 10 | + | ||
| 11 | + | ||
| 9 | 12 | ||
| 10 | 13 | ||
| 11 | 14 | ||
| @@ -14,7 +17,7 @@ | |||
| 14 | 17 | ||
| 15 | 18 | ||
| 16 | 19 | ||
| 17 | -#include "torch_npu/csrc/npu/Event.h" | 20 | +#include "torch_npu/csrc/core/npu/NPUEvent.h" |
| 18 | 21 | ||
| 19 | 22 | ||
| 20 | namespace c10d_npu { | 23 | namespace c10d_npu { |
| @@ -104,6 +107,7 @@ struct ProcessGroupStatus { | |||
| 104 | size_t lastStartedNumelOut; | 107 | size_t lastStartedNumelOut; |
| 105 | }; | 108 | }; |
| 106 | 109 | ||
| 110 | + | ||
| 107 | struct DumpPipe { | 111 | struct DumpPipe { |
| 108 | DumpPipe(int rank) | 112 | DumpPipe(int rank) |
| 109 | { | 113 | { |
| @@ -148,6 +152,7 @@ struct DumpPipe { | |||
| 148 | private: | 152 | private: |
| 149 | int fd_ = -1; | 153 | int fd_ = -1; |
| 150 | }; | 154 | }; |
| 155 | + | ||
| 151 | 156 | ||
| 152 | // A shelf for stashing tensors between op call and `work.wait()`. | 157 | // A shelf for stashing tensors between op call and `work.wait()`. |
| 153 | // Used in case of async ops. | 158 | // Used in case of async ops. |
| @@ -392,11 +392,13 @@ DEFINE_CONSTANT(started_state, "started") | |||
| 392 | // Current pg_status is not in FR. | 392 | // Current pg_status is not in FR. |
| 393 | all_pg_status_[pg_id] = std::move(pg_status); | 393 | all_pg_status_[pg_id] = std::move(pg_status); |
| 394 | } | 394 | } |
| 395 | - std::lock_guard<std::mutex> guard(mutex_); | ||
| 396 | - | ||
| 397 | 395 | ||
| 398 | auto traceback = | 396 | auto traceback = |
| 399 | torch::CapturedTraceback::gather(true, true, capture_cpp_stack_); | 397 | torch::CapturedTraceback::gather(true, true, capture_cpp_stack_); |
| 398 | + | ||
| 399 | + std::lock_guard<std::mutex> guard(mutex_); | ||
| 400 | + | ||
| 401 | + | ||
| 400 | auto te = Entry{ | 402 | auto te = Entry{ |
| 401 | id_, | 403 | id_, |
| 402 | pg_id, | 404 | pg_id, |
torch_npu/csrc/distributed/ProcessGroupHCCL.hpp此评论由代码审查工具自动生成