本文基于CANN开源社区的hcomm仓库进行技术解读

CANN组织地址:https://atomgit.com/cann

hcomm仓库地址:https://atomgit.com/cann/hcomm

前言

HCCL提供了高性能的集合通信能力,但如何管理通信域和通信资源?如何保证通信的可靠性和高效性?

HCOMM(Huawei Communication)是HCCL的通信基础库,提供通信域以及通信资源的管理能力,是HCCL运行的重要基础设施。

什么是HCOMM

HCOMM是CANN的通信基础库:

没有HCOMM:
应用直接调用HCCL → 没有统一管理 → 资源混乱

有HCOMM:
应用 → HCOMM管理 → HCCL通信 → 有序高效

架构:

应用层
    ↓
HCCL API(集合通信操作)
    ↓
HCOMM层(通信域管理、资源管理)
    ↓
底层通信硬件

核心概念

1. 通信域(Comm)

通信域是通信的上下文,定义了参与通信的进程集合:

#include "hcomm/hcomm.h"

// 初始化HCOMM
hcomm_handle_t handle;
hcomm_init(&handle, rank, nranks);

// 创建通信域
hcomm_comm_t comm;
hcomm_comm_create(&comm, handle, HCOMM_COMM_WORLD);

// 使用通信域进行通信
// ...

// 销毁通信域
hcomm_comm_destroy(comm);

2. 资源(Resource)

资源包括内存资源、网络资源、计算资源等:

// 分配内存资源
void *buffer = NULL;
size_t buffer_size = 1024 * 1024;  // 1MB

hcomm_result_t ret = hcomm_malloc(
    &buffer,           // 输出:内存指针
    buffer_size,       // 内存大小
    handle             // hcomm句柄
);

// 使用资源
// ...

// 释放资源
hcomm_free(buffer, handle);

3. 句柄(Handle)

句柄是资源的抽象表示:

// hcomm句柄
hcomm_handle_t handle;

// 通信域句柄
hcomm_comm_t comm;

// 资源池句柄
hcomm_pool_t pool;

// 请求句柄
hcomm_request_t request;

核心API

1. 初始化和清理

#include "hcomm/hcomm.h"

int main() {
    int rank = 0;
    int nranks = 0;

    // 获取rank和nranks
    hcomm_get_rank(&rank);
    hcomm_get_nranks(&nranks);

    printf("Rank: %d, Total ranks: %d\n", rank, nranks);

    // 初始化HCOMM
    hcomm_handle_t handle;
    hcomm_result_t ret = hcomm_init(&handle, rank, nranks);

    if (ret != HCOMM_SUCCESS) {
        fprintf(stderr, "Failed to initialize hcomm: %d\n", ret);
        return -1;
    }

    // 获取设备信息
    int device_id = 0;
    hcomm_get_device_id(&device_id);

    printf("Device ID: %d\n", device_id);

    // 使用HCOMM
    // ...

    // 清理
    hcomm_finalize(handle);

    return 0;
}

2. 通信域管理

// 创建通信域
hcomm_comm_t comm;
hcomm_result_t ret = hcomm_comm_create(
    &comm,             // 输出:通信域句柄
    handle,            // hcomm句柄
    HCOMM_COMM_WORLD   // 通信域类型
);

if (ret != HCOMM_SUCCESS) {
    fprintf(stderr, "Failed to create comm: %d\n", ret);
    return -1;
}

// 查询通信域信息
hcomm_comm_info_t info;
hcomm_comm_query(comm, &info);

printf("Comm size: %d\n", info.size);
printf("Comm rank: %d\n", info.rank);

// 划分子通信域
hcomm_comm_t sub_comm;
int color = rank % 2;  // 按奇偶分组
int key = rank;        // 在子通信域中的rank

ret = hcomm_comm_split(
    &sub_comm,         // 输出:子通信域
    comm,              // 父通信域
    color,             // 颜色
    key                // 键
);

// 复制通信域
hcomm_comm_t new_comm;
ret = hcomm_comm_dup(
    &new_comm,         // 输出:新通信域
    comm               // 源通信域
);

// 销毁通信域
hcomm_comm_destroy(comm);

3. 资源管理

// 分配内存资源
void *buffer = NULL;
size_t buffer_size = 1024 * 1024;  // 1MB

hcomm_result_t ret = hcomm_malloc(
    &buffer,           // 输出:内存指针
    buffer_size,       // 内存大小
    handle             // hcomm句柄
);

if (ret != HCOMM_SUCCESS) {
    fprintf(stderr, "Failed to allocate memory: %d\n", ret);
    return -1;
}

// 查询资源使用情况
hcomm_resource_info_t info;
ret = hcomm_resource_query(handle, &info);

if (ret == HCOMM_SUCCESS) {
    printf("Memory used: %zu MB\n", info.memory_used / 1024 / 1024);
    printf("Memory total: %zu MB\n", info.memory_total / 1024 / 1024);
    printf("Buffer count: %d / %d\n", info.buffer_count, info.buffer_max);
}

// 释放内存资源
hcomm_free(buffer, handle);

4. 资源池管理

// 创建资源池
hcomm_pool_t pool;
hcomm_result_t ret = hcomm_pool_create(
    &pool,             // 输出:资源池句柄
    handle,            // hcomm句柄
    1024,              // 池大小(MB)
    4                  // 最大并发数
);

if (ret != HCOMM_SUCCESS) {
    fprintf(stderr, "Failed to create pool: %d\n", ret);
    return -1;
}

// 从资源池获取资源
hcomm_resource_t resource;
ret = hcomm_pool_acquire(
    &resource,         // 输出:资源句柄
    pool,              // 资源池
    HCOMM_RESOURCE_MEMORY  // 资源类型
);

if (ret == HCOMM_SUCCESS) {
    printf("Acquired resource: %p\n", resource.ptr);
}

// 使用资源
// ...

// 归还资源到池
hcomm_pool_release(resource, pool);

// 销毁资源池
hcomm_pool_destroy(pool);

5. 同步操作

// Barrier同步
hcomm_result_t ret = hcomm_barrier(
    comm               // 通信域
);

if (ret != HCOMM_SUCCESS) {
    fprintf(stderr, "Barrier failed: %d\n", ret);
    return -1;
}

// Fence操作
ret = hcomm_fence(
    comm               // 通信域
);

// 锁操作
hcomm_lock_t lock;
ret = hcomm_lock_create(&lock, handle);

ret = hcomm_lock_acquire(lock);
if (ret == HCOMM_SUCCESS) {
    // 临界区代码
    printf("Critical section\n");

    // 释放锁
    hcomm_lock_release(lock);
}

hcomm_lock_destroy(lock);

使用场景

场景一:多租户场景

// 多租户:为每个租户创建独立的通信域
void multi_tenant_setup(int num_tenants) {
    hcomm_comm_t *tenant_comms = malloc(num_tenants * sizeof(hcomm_comm_t));

    for (int i = 0; i < num_tenants; i++) {
        // 为每个租户创建通信域
        hcomm_result_t ret = hcomm_comm_create(
            &tenant_comms[i],
            handle,
            HCOMM_COMM_WORLD
        );

        if (ret != HCOMM_SUCCESS) {
            fprintf(stderr, "Failed to create comm for tenant %d\n", i);
            continue;
        }

        // 设置租户资源配额
        hcomm_set_quota(tenant_comms[i], 1024);  // 1GB
    }

    // 租户可以使用各自的通信域
    for (int i = 0; i < num_tenants; i++) {
        run_tenant_workload(tenant_comms[i], i);
    }

    // 清理
    for (int i = 0; i < num_tenants; i++) {
        hcomm_comm_destroy(tenant_comms[i]);
    }
    free(tenant_comms);
}

场景二:分层训练

// 分层训练:使用多级通信域
void hierarchical_training() {
    // 全局通信域
    hcomm_comm_t global_comm;
    hcomm_comm_create(&global_comm, handle, HCOMM_COMM_WORLD);

    // 节点内通信域
    hcomm_comm_t node_comm;
    int node_id = rank / 8;  // 每节点8卡
    int node_rank = rank % 8;
    hcomm_comm_split(&node_comm, global_comm, node_id, node_rank);

    // 先在节点内同步
    hcomm_barrier(node_comm);

    // 再全局同步
    hcomm_barrier(global_comm);

    // 清理
    hcomm_comm_destroy(node_comm);
    hcomm_comm_destroy(global_comm);
}

场景三:动态资源分配

// 动态资源分配
void dynamic_resource_allocation() {
    hcomm_pool_t pool;
    hcomm_pool_create(&pool, handle, 1024, 10);

    // 根据需求动态获取资源
    for (int i = 0; i < num_tasks; i++) {
        hcomm_resource_t resource;
        hcomm_result_t ret = hcomm_pool_acquire(
            &resource,
            pool,
            HCOMM_RESOURCE_MEMORY
        );

        if (ret == HCOMM_SUCCESS) {
            // 执行任务
            execute_task(resource);

            // 归还资源
            hcomm_pool_release(resource, pool);
        } else {
            printf("Failed to acquire resource for task %d\n", i);
        }
    }

    hcomm_pool_destroy(pool);
}

性能优化

1. 资源复用

// 不好:每次都分配新资源
for (int i = 0; i < 1000; i++) {
    void *buffer = malloc(1024);
    // 使用buffer
    free(buffer);
}

// 好:使用资源池复用
hcomm_pool_t pool;
hcomm_pool_create(&pool, handle, 1024, 10);

for (int i = 0; i < 1000; i++) {
    hcomm_resource_t resource;
    hcomm_pool_acquire(&resource, pool, HCOMM_RESOURCE_MEMORY);
    // 使用resource
    hcomm_pool_release(resource, pool);
}

2. 通信域复用

// 不好:每次都创建新通信域
for (int i = 0; i < 100; i++) {
    hcomm_comm_t comm;
    hcomm_comm_create(&comm, handle, HCOMM_COMM_WORLD);
    // 使用comm
    hcomm_comm_destroy(comm);
}

// 好:复用通信域
hcomm_comm_t comm;
hcomm_comm_create(&comm, handle, HCOMM_COMM_WORLD);

for (int i = 0; i < 100; i++) {
    // 使用comm
}

hcomm_comm_destroy(comm);

3. 批量操作

// 不好:多次小操作
for (int i = 0; i < 100; i++) {
    hcomm_resource_t resource;
    hcomm_pool_acquire(&resource, pool, HCOMM_RESOURCE_MEMORY);
    hcomm_pool_release(resource, pool);
}

// 好:批量操作
hcomm_resource_t resources[100];
for (int i = 0; i < 100; i++) {
    hcomm_pool_acquire(&resources[i], pool, HCOMM_RESOURCE_MEMORY);
}

// 使用所有资源

for (int i = 0; i < 100; i++) {
    hcomm_pool_release(resources[i], pool);
}

与HCCL的关系

功能 HCOMM HCCL
通信域管理
资源管理
集合通信
同步操作

关系:

HCOMM(基础设施):
- 通信域管理
- 资源管理
- 同步操作
    ↓
HCCL(集合通信):
- AllReduce
- AllGather
- Broadcast

调试技巧

1. 检查通信域创建

// 确保通信域创建成功
hcomm_result_t ret = hcomm_comm_create(&comm, handle, HCOMM_COMM_WORLD);
if (ret != HCOMM_SUCCESS) {
    fprintf(stderr, "PE %d: Failed to create comm: %d\n", rank, ret);
    hcomm_finalize(handle);
    return -1;
}

2. 监控资源使用

// 定期监控资源使用
void monitor_resources() {
    hcomm_resource_info_t info;
    hcomm_result_t ret = hcomm_resource_query(handle, &info);

    if (ret == HCOMM_SUCCESS) {
        printf("Memory used: %zu / %zu MB\n",
               info.memory_used / 1024 / 1024,
               info.memory_total / 1024 / 1024);
        printf("Buffer count: %d / %d\n",
               info.buffer_count,
               info.buffer_max);
    }
}

3. 性能分析

// 分析通信性能
void analyze_communication() {
    hcomm_perf_info_t perf_info;
    hcomm_result_t ret = hcomm_perf_query(handle, &perf_info);

    if (ret == HCOMM_SUCCESS) {
        printf("Total bytes sent: %zu MB\n",
               perf_info.bytes_sent / 1024 / 1024);
        printf("Total bytes received: %zu MB\n",
               perf_info.bytes_received / 1024 / 1024);
        printf("Total time: %.2f ms\n", perf_info.total_time);
        printf("Average bandwidth: %.2f GB/s\n",
               perf_info.average_bandwidth);
    }
}

常见问题

问题1:通信域未创建

// 错误:未创建通信域就使用
hcomm_comm_t comm;
hcomm_barrier(comm);  // 错误!

// 正确:先创建通信域
hcomm_comm_create(&comm, handle, HCOMM_COMM_WORLD);
hcomm_barrier(comm);

问题2:资源泄漏

// 错误:分配资源但未释放
void *buffer = NULL;
hcomm_malloc(&buffer, size, handle);
// 使用buffer
// 忘记释放!

// 正确:及时释放
void *buffer = NULL;
hcomm_malloc(&buffer, size, handle);
// 使用buffer
hcomm_free(buffer, handle);

问题3:通信域冲突

// 错误:同时使用多个通信域可能导致冲突
hcomm_comm_t comm1, comm2;
hcomm_comm_create(&comm1, handle, HCOMM_COMM_WORLD);
hcomm_comm_create(&comm2, handle, HCOMM_COMM_WORLD);

hcomm_barrier(comm1);  // 可能与comm2冲突
hcomm_barrier(comm2);

// 正确:明确使用哪个通信域
hcomm_comm_t comm;
hcomm_comm_create(&comm, handle, HCOMM_COMM_WORLD);

hcomm_barrier(comm);  // 只使用一个通信域

应用场景总结

场景一:多租户系统

为不同租户提供隔离的通信环境。

场景二:分层训练

实现节点内和全局的多级同步。

场景三:资源管理

统一管理通信资源,提高利用率。

场景四:性能监控

监控通信性能,指导优化。

总结

HCOMM是HCCL的通信基础库:

  • 通信域管理
  • 资源管理
  • 多租户支持
  • 性能监控
  • 错误处理

是HCCL运行的重要基础设施,为上层提供了可靠的通信环境。

相关链接

hcomm仓库地址:https://atomgit.com/cann/hcomm

CANN组织地址:https://atomgit.com/cann

hccl仓库地址:https://atomgit.com/cann/hccl

runtime仓库地址:https://atomgit.com/cann/runtime


这篇是我学习HCOMM时的笔记,如有错误欢迎指正。

Logo

昇腾计算产业是基于昇腾系列(HUAWEI Ascend)处理器和基础软件构建的全栈 AI计算基础设施、行业应用及服务,https://devpress.csdn.net/organization/setting/general/146749包括昇腾系列处理器、系列硬件、CANN、AI计算框架、应用使能、开发工具链、管理运维工具、行业应用及服务等全产业链

更多推荐