# HMC **Repository Path**: skyzoon/HMC ## Basic Information - **Project Name**: HMC - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-12-30 - **Last Updated**: 2026-03-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 什么是 HMC?

HMC 是一个面向异构系统(CPU / GPU / 各类加速器)的通信框架。它提供: * **统一的内存抽象**:`Memory` 一个与设备无关的接口,用于申请/释放缓冲区,并在不同设备之间拷贝数据。 * **统一的注册 IO 缓冲区**:`ConnBuffer` 一个稳定、已注册的缓冲区,作为所有网络传输的数据“暂存区”(staging area)。 * **统一的传输抽象**:`Communicator` 以同一套接口实现对端缓冲区之间的单边数据读写: * `ConnType.RDMA`(依赖平台/设备能力) * `ConnType.UCX`(常用于 CPU,以及部分 GPU-direct 配置) * **控制面(Control plane)用于同步与小消息** 一个基于 rank 的控制信道,支持 **TCP** 和/或 **UDS**(同机)。 ### 支持的设备 HMC 支持 CPU 内存以及多种加速器后端,包括: * **NVIDIA GPU**(CUDA) * **AMD GPU**(ROCm) * **海光平台 / GPU**(依赖具体平台;当你的构建产物中启用了对应后端时可用) * **寒武纪 MLU**(CNRT / Neuware) * **摩尔线程 GPU**(MUSA) > 实际可用性取决于 HMC 的构建方式(例如是否启用 CUDA/ROCm/CNRT/MUSA)以及你本机的运行时/驱动环境。 > 我们当前在英伟达Connect-x系列网卡上开发和支持。 ### 核心模型 > 数据移动始终发生在两端已注册缓冲区(`ConnBuffer`)之间,使用 `(offset, size)` 来定位。 > 偏移(offset)由你的应用自行规划,并通过控制消息(tag)来做协同与同步。 # 第 1 部分 — Python(推荐) ## 1. 安装(Python) HMC 的 Python 绑定基于 C++ 核心,通过 **pybind11** 构建。 ### 1.1 前置条件 * Python 3.8+ * C++14+ * CMake ≥ 3.18 * UCX(必需,用于 ConnType.UCX) * 请用户自行安装 UCX,并将其安装到:/usr/local/ucx * 对于 NVIDIA / AMD GPU 场景,建议安装启用 GPU-Direct(GDR)支持的 UCX 版本(需与你的 CUDA/ROCm 环境匹配) > 提示:HMC 的 UCX 后端依赖你的系统 UCX 安装路径与运行时库可见性;请确保 /usr/local/ucx/lib 在运行时动态库搜索路径中(例如通过 LD_LIBRARY_PATH 或系统 linker 配置)。 ### 1.2 从源码构建并安装 ```bash git clone https://github.com/IIC-SIG-MLsys/HMC.git cd HMC git submodule update --init --recursive ``` 启用 Python 模块进行构建: ```bash mkdir -p build && cd build cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_PYTHON_MOD=ON make -j ``` 构建 wheel 并安装: ```bash cd .. python -m build pip install dist/hmc-*.whl ``` 验证安装: ```bash python -c "import hmc; print('hmc imported:', hmc.__file__)" ``` ### 1.3(可选)GPU/加速器后端 如果你启用了 CUDA/ROCm/CNRT/MUSA 等后端,请确保在构建 wheel 时同一套工具链与环境变量对构建过程可见。 ## 2. 关键概念 * `Session` 是推荐使用的高层 API。 * 所有传输都采用 **缓冲区暂存(buffer-staged)** 模式: 1. 将 payload 拷贝到本地 `ConnBuffer`(通过 `sess.buf.put(...)`) 2. 使用 `sess.put_remote(...)` / `sess.get_remote(...)` 发送/接收字节 3. 再将数据从本地 `ConnBuffer` 拷贝到目标对象(通过 `sess.buf.get_into(...)`) * 文档和代码里,偏移通常称为 `bias/offset`。 ## 3. 示例:CPU 到 CPU 传输(UCX) ### 3.1 服务端 ```python import hmc ip = "192.168.2.244" rank = 0 sess = hmc.create_session( device_id=0, buffer_size=128 * 1024 * 1024, mem_type=hmc.MemoryType.CPU, num_chs=1, local_ip=ip, ) sess.init_server( bind_ip=ip, ucx_port=2025, rdma_port=2026, ctrl_tcp_port=5001, self_id=rank, ctrl_uds_dir="/tmp", ) print("UCX server ready") ``` ### 3.2 客户端 ```python import hmc server_ip = "192.168.2.244" my_ip = "192.168.2.248" sess = hmc.create_session(mem_type=hmc.MemoryType.CPU, local_ip=my_ip) sess.connect( peer_id=0, self_id=1, peer_ip=server_ip, data_port=2025, ctrl_tcp_port=5001, conn=hmc.ConnType.UCX, ) payload = b"hello hmc" # 暂存到本地 ConnBuffer n = sess.buf.put(payload, offset=0) # put:本地 [0, n) -> 远端 [0, n) sess.put_remote(server_ip, 2025, local_off=0, remote_off=0, nbytes=n, conn=hmc.ConnType.UCX) print("sent", n, "bytes") ``` ### 3.3 协调“数据就绪”(推荐) 通常会加一个简单的 tag 握手,让服务端知道什么时候去读: ```python # 发送方 sess.ctrl_send(peer=0, tag=1) ``` ```python # 接收方 tag = sess.ctrl_recv(peer=1) assert tag == 1 # 然后在服务端通过 sess.buf.get_into(...) 从 ConnBuffer 读出数据 ``` ## 4. NumPy 与 PyTorch(CPU) ### 4.1 NumPy 发送/接收 ```python import hmc, numpy as np x = np.arange(1024, dtype=np.int32) n = sess.buf.put(x, offset=0) sess.put_remote(server_ip, 2025, local_off=0, remote_off=0, nbytes=n, conn=hmc.ConnType.UCX) y = np.empty_like(x) sess.get_remote(server_ip, 2025, local_off=0, remote_off=0, nbytes=y.nbytes, conn=hmc.ConnType.UCX) sess.buf.get_into(y, nbytes=y.nbytes, offset=0) ``` 说明: * 源数组建议为 C-contiguous;必要时包装层可能会进行拷贝。 * 目标数组必须可写且 contiguous。 ### 4.2 PyTorch CPU Tensor ```python import torch t = torch.arange(4096, dtype=torch.int32) n = sess.buf.put(t, offset=0) sess.put_remote(server_ip, 2025, local_off=0, remote_off=0, nbytes=n, conn=hmc.ConnType.UCX) out = torch.empty_like(t) sess.get_remote(server_ip, 2025, local_off=0, remote_off=0, nbytes=out.numel() * out.element_size(), conn=hmc.ConnType.UCX) sess.buf.get_into(out, nbytes=out.numel() * out.element_size(), offset=0) ``` ## 5. GPU Tensor(高级) HMC 可以通过使用 tensor 指针(内部 `data_ptr()`)来调用 `writeFromGpu/readToGpu`,从而暂存 CUDA tensor。 ```python import torch t = torch.randn(1024 * 1024, device="cuda") n = sess.buf.put(t, offset=0, device="cuda") # GPU -> ConnBuffer sess.put_remote(server_ip, 2026, local_off=0, remote_off=0, nbytes=n, conn=hmc.ConnType.RDMA) recv = torch.empty_like(t) sess.get_remote(server_ip, 2026, local_off=0, remote_off=0, nbytes=n, conn=hmc.ConnType.RDMA) sess.buf.get_into(recv, nbytes=n, offset=0, device="cuda") ``` 注意事项: * GPU-direct 依赖平台/驱动/NIC/UCX/RDMA 配置。 * 建议先从 CPU 路径开始,验证协议与正确性后再上 GPU 路径。 ## 6. 故障排查(Python) ### 常见错误 * **缓冲区溢出**:`offset + nbytes > buffer_size` * 增大 `buffer_size` 或调整 offset * **未建立连接**:未调用 `connect()` 或 `data_port/conn` 配置错误 * **控制面不匹配(UDS vs TCP)** * 使用 `CTRL_TRANSPORT=tcp` 或 `CTRL_TRANSPORT=uds` 强制选择 * **UDS 路径理解错误** * UDS 需要的是**完整 socket 文件路径**,不是目录 ### 最佳实践 * 定义清晰的协议(offset 布局 + tag 含义)。 * 未收到 ack/同步前,避免覆盖远端 offset。 * 在需要计算通信重叠或并发时,使用 `put_nb/get_nb + wait`。 --- # 第 2 部分 — C++ 核心库(高级 / 集成) ## 7. 安装(C++) ### 7.1 前置条件 * C++14+ * CMake ≥ 3.18 可选: ```bash sudo apt-get install -y libgtest-dev ``` ### 7.2 构建 ```bash git clone https://github.com/IIC-SIG-MLsys/HMC.git cd HMC mkdir -p build && cd build cmake .. -DCMAKE_BUILD_TYPE=Release make -j ``` ## 8. 使用(C++) ### 8.1 核心组件 * `Memory`:跨设备统一申请/拷贝 * `ConnBuffer`:稳定注册缓冲区;所有传输使用 `(offset, size)` * `CtrlSocketManager`:控制面,基于 rank,TCP/UDS,HELLO 绑定 * `Communicator`:数据面 + 控制面集成:`put/get/putNB/getNB/wait`、`connectTo/initServer` ### 8.2 最小数据面示例(UCX put) ```cpp #include #include #include #include using namespace hmc; int main() { auto buf = std::make_shared(0, 128ull * 1024 * 1024, MemoryType::CPU); Communicator comm(buf); std::string server_ip = "192.168.2.244"; uint16_t data_port = 2025; uint16_t ctrl_tcp_port = 5001; Communicator::CtrlLink link; link.transport = Communicator::CtrlTransport::TCP; link.ip = server_ip; link.port = ctrl_tcp_port; comm.connectTo(/*peer_id=*/0, /*self_id=*/1, server_ip, data_port, link, ConnType::UCX); std::vector payload(1024, 'A'); buf->writeFromCpu(payload.data(), payload.size(), 0); comm.put(server_ip, data_port, /*local_off=*/0, /*remote_off=*/0, payload.size(), ConnType::UCX); return 0; } ``` ## 9. 附录:API 速查表 ### Python * `create_session(...) -> Session` * `Session.init_server(...)` * `Session.connect(...)` * `Session.put_remote(...) / get_remote(...)` * `Session.put_nb(...) / get_nb(...) / wait(...)` * `Session.ctrl_send(...) / ctrl_recv(...)` * `sess.buf.put(...) / sess.buf.get_into(...) / buffer_copy_within(...)` ### C++ * `ConnBuffer::{writeFromCpu/readToCpu/writeFromGpu/readToGpu/copyWithin}` * `Communicator::{initServer/connectTo/put/get/putNB/getNB/wait/ctrlSend/ctrlRecv}` * `CtrlSocketManager::{start/connectTcp/connectUds/sendU64/recvU64/...}` --- © 2025 SDU spgroup Holding Limited. All rights reserved.