cann组织链接:https://atomgit.com/cann
hcomm仓库链接:https://atomgit.com/cann/hcomm
前言
在异构计算与大规模分布式训练场景中,底层通信能力直接影响系统性能与可移植性。CANN(Compute Architecture for Neural Networks)开源项目中的 hcomm (Huawei Communication)仓库(https://atomgit.com/cann/hcomm)作为其通信栈的基础组件,提供了一套通用、高性能的点对点通信抽象层 。其核心设计亮点在于后端插件化架构(Backend Plugin Architecture),使得同一套上层接口可无缝适配多种物理网络(如 PCIe、RoCE、自研互连)与传输协议(如 RDMA、TCP、共享内存)。
1. hcomm 的定位与整体架构
hcomm 并非直接面向最终用户,而是作为 中间通信层,服务于 hccl(集合通信)、hixl(低延迟通信)等组件。其目标是:
- 屏蔽底层差异:上层无需关心是 RoCE 还是 PCIe;
- 最大化性能:选择最优后端执行通信;
- 支持扩展:第三方可开发新后端插件。
架构概览
调用
hccl / hixl
hcomm API
Backend Manager
Plugin: RoCE
Plugin: Shared Memory
Plugin: TCP
libibverbs / RDMA Core
POSIX shm / mmap
Socket API
关键创新在于 Backend Manager 的插件调度机制。
2. 插件接口定义与抽象层设计
hcomm 通过纯虚类定义后端插件接口。
2.1 核心通信接口
cpp
// hcomm/include/backend/backend_interface.h
class ICommBackend {
public:
virtual ~ICommBackend() = default;
// 初始化通信上下文
virtual Status Init(const CommContext& ctx) = 0;
// 异步发送
virtual Status ISend(
void* buffer,
size_t size,
int dest_rank,
int tag,
CommRequest* req
) = 0;
// 异步接收
virtual Status IRecv(
void* buffer,
size_t size,
int src_rank,
int tag,
CommRequest* req
) = 0;
// 等待请求完成
virtual Status Wait(CommRequest* req) = 0;
// 查询是否支持当前设备拓扑
virtual bool IsSupported(const TopologyInfo& topo) const = 0;
// 返回后端名称(用于日志与调试)
virtual std::string Name() const = 0;
};
所有后端插件必须继承此接口。
2.2 内存注册接口(用于零拷贝)
为支持 RDMA 等零拷贝技术,hcomm 额外定义内存管理接口:
cpp
struct IMemoryRegion {
virtual void* ptr() = 0;
virtual size_t size() = 0;
virtual ~IMemoryRegion() = default;
};
class ICommBackend {
public:
virtual std::unique_ptr<IMemoryRegion> RegisterMemory(
void* ptr, size_t size, MemType type
) = 0;
};
3. 插件注册与动态加载机制
3.1 静态注册(编译时链接)
对于内置后端(如 RoCE、SHMEM),hcomm 使用 工厂模式 + 静态初始化:
cpp
// hcomm/plugins/roce/roce_backend.cpp
class RoceBackend : public ICommBackend { /* ... */ };
// 全局工厂注册
static BackendRegistrar g_roce_registrar("roce", []() {
return std::make_unique<RoceBackend>();
});
其中 BackendRegistrar 定义如下:
cpp
// hcomm/core/backend_factory.h
class BackendFactory {
public:
using CreatorFunc = std::function<std::unique_ptr<ICommBackend>()>;
static void Register(const std::string& name, CreatorFunc creator) {
instance().creators_[name] = std::move(creator);
}
static std::unique_ptr<ICommBackend> Create(const std::string& name) {
auto it = instance().creators_.find(name);
return it != instance().creators_.end() ? it->second() : nullptr;
}
private:
std::unordered_map<std::string, CreatorFunc> creators_;
};
3.2 动态插件(运行时加载)
hcomm 支持 .so 插件动态加载:
cpp
// hcomm/core/plugin_loader.cpp
std::unique_ptr<ICommBackend> LoadPlugin(const std::string& path) {
void* handle = dlopen(path.c_str(), RTLD_LAZY);
if (!handle) return nullptr;
// 查找符号:create_backend
auto create_func = (ICommBackend*(*)())dlsym(handle, "create_backend");
if (!create_func) {
dlclose(handle);
return nullptr;
}
return std::unique_ptr<ICommBackend>(create_func());
}
插件需提供 extern "C" ICommBackend* create_backend(); 入口。
✅ 优势:用户可不重新编译 hcomm 即扩展新后端。
4. 后端选择与上下文管理
4.1 多后端共存与优先级
hcomm 允许多个后端同时注册,并按优先级排序:
yaml
# config/hcomm_backends.yaml
backends:
- name: "roce"
priority: 100 # 越高越优先
enabled: true
- name: "shmem"
priority: 90
enabled: true
- name: "tcp"
priority: 50
enabled: true
加载时按优先级排序:
cpp
// hcomm/core/backend_manager.cpp
void BackendManager::LoadBackendsFromConfig() {
auto configs = ParseYaml("hcomm_backends.yaml");
std::sort(configs.begin(), configs.end(),
[](auto& a, auto& b) { return a.priority > b.priority; });
for (auto& cfg : configs) {
if (cfg.enabled) {
auto backend = BackendFactory::Create(cfg.name);
if (backend && backend->IsSupported(current_topology_)) {
backends_.push_back(std::move(backend));
}
}
}
}
4.2 通信上下文(CommContext)绑定
每次通信操作通过 CommContext 指定目标后端:
cpp
// hcomm/api/hcomm_api.cpp
HcclResult hcomm_isend(
void* buf, size_t size, int dest, int tag, aclrtStream stream
) {
// 获取当前上下文(隐式或显式)
auto ctx = CommContextManager::GetCurrent();
// 由 BackendManager 选择最优后端
auto backend = BackendManager::Instance().SelectBackend(ctx);
CommRequest req;
backend->ISend(buf, size, dest, tag, &req);
// 将请求绑定到 stream(用于异步等待)
StreamRequestBinder::Bind(stream, req);
return HCCL_SUCCESS;
}
若未指定上下文,hcomm 自动使用最高优先级可用后端。
5. 典型后端插件实现剖析
5.1 RoCE 后端(RDMA over Converged Ethernet)
基于 libibverbs 实现零拷贝通信:
cpp
// hcomm/plugins/roce/roce_backend.cpp
Status RoceBackend::ISend(
void* buffer, size_t size, int dest, int tag, CommRequest* req
) {
// 1. 获取已注册的 MR(Memory Region)
auto mr = memory_registry_.Find(buffer);
if (!mr) {
return ERROR_NOT_REGISTERED;
}
// 2. 构造 RDMA SEND WR
ibv_sge sge;
sge.addr = reinterpret_cast<uint64_t>(buffer);
sge.length = size;
sge.lkey = mr->lkey();
ibv_send_wr wr{};
wr.wr_id = reinterpret_cast<uint64_t>(req);
wr.sg_list = &sge;
wr.num_sge = 1;
wr.opcode = IBV_WR_SEND;
// 3. 提交至 QP
ibv_send_wr* bad_wr;
if (ibv_post_send(qp_, &wr, &bad_wr)) {
return ERROR_RDMA_POST;
}
return SUCCESS;
}
💡 关键优化 :QP(Queue Pair)按
(src, dst)缓存,避免重复创建。
5.2 共享内存后端(SHMEM)
适用于单机多卡场景:
cpp
// hcomm/plugins/shmem/shmem_backend.cpp
Status ShmemBackend::Init(const CommContext& ctx) {
// 创建命名共享内存段
std::string name = "/hcomm_shm_" + std::to_string(ctx.comm_id);
int fd = shm_open(name.c_str(), O_CREAT | O_RDWR, 0666);
ftruncate(fd, kShmemBufferSize);
shmem_ptr_ = mmap(nullptr, kShmemBufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// 初始化环形缓冲区控制块
ring_buffer_ = new (shmem_ptr_) RingBuffer(kShmemBufferSize - sizeof(RingBuffer));
return SUCCESS;
}
Status ShmemBackend::ISend(void* buf, size_t size, int dest, int tag, CommRequest* req) {
// 直接拷贝至共享内存环形缓冲区
ring_buffer_->Push(buf, size, dest, tag);
req->status = REQUEST_COMPLETED; // 同步完成
return SUCCESS;
}
✅ 优势:零系统调用,延迟 < 1μs。
6. 性能隔离与故障恢复
6.1 后端健康检查
hcomm 定期探测后端状态:
cpp
// hcomm/core/health_monitor.cpp
void HealthMonitor::CheckBackends() {
for (auto& backend : backends_) {
if (!backend->Ping()) {
LOG(WARNING) << "Backend " << backend->Name() << " failed";
backend->MarkUnhealthy();
}
}
}
失败后端自动降级至次优选项。
6.2 请求超时与重试
每个 CommRequest 支持超时设置:
cpp
req->timeout_ms = 5000; // 5秒
if (backend->Wait(req) == ERROR_TIMEOUT) {
// 切换至备用后端重试
auto fallback = GetFallbackBackend(backend);
fallback->Resend(original_request);
}
结语
CANN hcomm 通过精心设计的插件化架构,成功实现了通信能力的解耦、复用与扩展。其不仅支持 RoCE、共享内存等主流后端,更通过动态加载、优先级调度与故障恢复机制,确保了在复杂异构环境下的鲁棒性与高性能。作为 CANN 通信栈的基石,hcomm 的抽象层设计为上层 hccl、hixl 等组件提供了坚实支撑,同时也为社区贡献新后端(如 InfiniBand、自研 NoC)打开了大门。随着 AI 集群规模持续扩大,hcomm 的插件化模型将成为构建高效、可移植分布式系统的关键基础设施。
cann组织链接:https://atomgit.com/cann
hcomm仓库链接:https://atomgit.com/cann/hcomm