RDMA WITH GPU MEMORY VIA DMA-BUF

Jianxin Xiong, Intel Corporation

目录

RDMA 概述

RDMA与系统内存

Page 3: RDMA与系统内存工作流程图
Page 3: RDMA与系统内存工作流程图

RDMA与GPU内存

Page 4: RDMA与GPU内存协作示意图
Page 4: RDMA与GPU内存协作示意图

DMA-BUF 概述

Dma-buf 是 Linux 内核中的一种标准机制,用于在不同设备驱动程序之间共享缓冲区。

其工作流程如下:
* 导出方 (Exporter): 拥有内存分配的驱动程序。它创建一个 dma-buf 对象并导出一个文件描述符(fd)。
* 导入方 (Importer): 需要访问该内存的驱动程序。它通过文件描述符获取 dma-buf 对象的引用,将其附加(attach)到自己的设备上,并将其映射(map)为设备可访问的DMA地址。

Page 6: DMA-BUF 概述图
Page 6: DMA-BUF 概述图

DMA-BUF API (导出方)

struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info);

struct dma_buf_export_info {
    const char *exp_name;
    struct module *owner;
    const struct dma_buf_ops *ops; // 操作函数集
    size_t size;
    int flags;
    struct dma_resv *resv;
    void *priv;
};

dma_buf_ops 结构体中定义了多种回调函数,其中加粗的为强制实现项:

struct dma_buf_ops {
                                   /* 加粗为强制实现项 */
    bool cache_sgt_mapping;
    bool dynamic_mapping;
    int (*attach)(struct dma_buf *, struct dma_buf_attachment *);
    void (*detach)(struct dma_buf *, struct dma_buf_attachment *);
    struct sg_table * (*map_dma_buf)(struct dma_buf_attachment *, enum dma_data_direction);
    void (*unmap_dma_buf)(struct dma_buf_attachment *, struct sg_table *, enum dma_data_direction);
    void (*release)(struct dma_buf *);
    int (*begin_cpu_access)(struct dma_buf *, enum dma_data_direction);
    int (*end_cpu_access)(struct dma_buf *, enum dma_data_direction);
    int (*mmap)(struct dma_buf *, struct vm_area_struct *vma);
    void *(*map)(struct dma_buf *, unsigned long);
    void (*unmap)(struct dma_buf *, void *);
    void *(*vmap)(struct dma_buf *);
    void (*vunmap)(struct dma_buf *, void *vaddr);
};
int dma_buf_fd(struct dma_buf *dmabuf, int flags);

DMA-BUF API (导入方)

struct dma_buf *dma_buf_get(int fd);
void dma_buf_put(struct dma_buf *dma_buf);
struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dma_buf, struct device *dev);
// 动态附加
struct dma_buf_attachment *dma_buf_dynamic_attach(struct dma_buf *dma_buf, struct device *dev, bool allow_dynamic, void *priv);
void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach);
struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, enum dma_data_direction direction);
void dma_buf_unmap_attachment(struct dma_buf_attachment *attach, struct sg_table *sg_table, enum dma_data_direction direction);
int dma_buf_begin_cpu_access();
int dma_buf_end_cpu_access();
void *dma_buf_kmap();
void dma_buf_kunmap();
int dma_buf_mmap();
void *dma_buf_vmap();
void dma_buf_vunmap();

使用 DMA-BUF 进行 GPU 内存 RDMA

内存注册工作流

下图展示了使用 dma-buf 进行 GPU 内存 RDMA 注册的完整流程:
1. 应用程序 (Application) 调用 GPU 库 (GPU library) 来分配 GPU 内存。
2. GPU 库返回内存地址、大小以及一个代表该内存的 文件描述符 (fd)
3. 应用程序调用 RDMA 库 (RDMA library) (例如 OFI 或 Verbs) 的内存注册函数 (如 ibv_reg_mr_fd),并将文件描述符 fd 传入。
4. 调用链最终到达内核态的 RDMA 驱动 (RDMA driver)
5. 在内核中,GPU 驱动 作为 导出方 (exporter),将 GPU 内存导出为 dma-buf 对象。
6. RDMA 驱动 作为 导入方 (importer),通过文件描述符导入该 dma-buf,并将其映射为可供 NIC 进行 点对点 DMA (peer-to-peer DMA) 的物理地址。
7. 这样,NIC 就可以通过 PCIe 直接访问 GPU 内存,实现 RDMA 操作。

Page 10: 内存注册工作流图
Page 10: 内存注册工作流图

GPU 软件变更

RDMA 驱动程序变更

// 原有函数
struct ib_umem *
ib_umem_get(
    struct ib_ucontext *ucontext,
    unsigned long addr,
    size_t size,
    int access);
// 新增函数
struct ib_umem *
ib_umem_dmabuf_get(
    struct ib_ucontext *ucontext,
    unsigned long addr,
    size_t size,
    int dmabuf_fd,
    int access);

RDMA 驱动程序变更 (续)

struct ib_device {
    ......
    struct ib_mr * (*reg_user_mr_fd)(....., int fd_type, int fd, int acc, ..... );
    int (*rereg_user_mr_fd)(....., int fd_type, int fd, int acc, ..... );
};

RDMA 库变更

struct ibv_mr *ibv_reg_mr_fd (
    struct ibv_pd *pd,
    void *addr,
    size_t length,
    enum ibv_mr_fd_type,
    int fd,
    int access);
int ibv_rereg_mr_fd (
    struct ibv_mr *mr,
    int flags,
    struct ibv_pd *pd,
    void *addr,
    size_t length,
    enum ibv_mr_fd_type,
    int fd,
    int access);

RDMA 库变更 (续)

int ibv_cmd_reg_mr_fd(....., int fd_type, int fd, int access, .....);
int ibv_cmd_rereg_mr_fd(....., int fd_type, int fd, int access, .....);
struct verbs_context_ops {
    ......
    struct ibv_mr *(*reg_mr_fd)(....., enum ibv_mr_fd_type, int fd, int access );
    int (*rereg_mr_fd)(....., enum ibv_mr_fd_type, int fd, int access );
};

OFI 变更

fi_mr_attr 结构中增加了新字段,以便在进行内存注册时可以传递文件描述符(fd)。

struct fi_mr_attr {
    ......
    enum fi_hmem_iface iface;   /* 用于内存分配的API */
    union {
        uint64_t reserved;
        ......
        int fd;
    } device;
};

状态与未来工作

软件原型实现

一个软件原型已经完成,其特性如下:
- 基于上游 Linux 内核 5.6 和最新的用户空间 rdma-core 库。
- GPU:使用 i915 驱动程序的 Intel GPU。
- RDMA NIC:Mellanox ConnectX-4 EDR,使用上游驱动程序。

后续步骤