【verbs】ibv_create_cq()

原文:https://www.rdmamojo.com/2012/11/03/ibv_create_cq/

描述


ibv_create_cq()为RDMA设备上下文创建完成队列(CQ)。
当发送或接收队列中的未完成工作请求完成时,会将【工作完成】添加到该工作队列的CQ中。此【工作完成】指示未完成的工作请求已完成(不再视为未完成),并提供有关此请求的详细信息(状态,方向,操作码等)。
一个CQ 可以在多个QP之间共享用于发送和接收。WC(工作完成)保存 QP编号以及它来自的(发送或接收)队列。
用户可以定义CQ的最小尺寸。实际创建的大小可以等于或大于此值。

 

参数

context入参

从ibv_open_device()返回的RDMA设备上下文

cqe入参

The minimum requested capacity of the CQ, value can be [1..dev_cap.max_cqe]

CQ的最小请求容量值可以是[1..dev_cap.max_cqe]

cq_context入参

(可选)用户定义的值,将在cq-> cq_context中可用。在使用ibv_get_cq_event()等待完成事件通知时,将返回此值

channel入参

(可选)完成事件通道,将用于指示新的WC(工作完成)已添加到此CQ。 NULL表示将不使用任何完成事件通道

comp_vector入参

MSI-X完成向量,将用于发信号通知完成事件。如果这些中断的IRQ关联掩码已配置为将要由不同内核处理每个MSI-X中断,则可以使用此参数在多个内核上 配置工作负载。值可以是[0..context-> num_comp_vectors)。

(MSI-X completion vector that will be used for signaling Completion events. If the IRQ affinity masks of these interrupts have been configured to spread each MSI-X interrupt to be handled by a different core, this parameter can be used to spread the completion workload over multiple cores. Value can be [0..context->num_comp_vectors).)

 

返回值

ValueDescription
CQ

指向新分配的完成队列(CQ)的指针。
该指针还包含以下字段:

 

cq_context提供给ibv_create_cq()的值cq_context
cqeCQ的实际大小
NULL

 

发生错误时,errno指示错误原因:

 

EINVAL

无效的cqe,channel 或comp_vector

ENOMEM

没有足够的资源来完成此操作

例子

 

  • 创建一个包含100个entry的CQ并将其销毁:
struct ibv_cq *cq;
 
cq = ibv_create_cq(context, 100, NULL, NULL, 0);
if (!cq) {
	fprintf(stderr, "Error, ibv_create_cq() failed\n");
	return -1;
}
 
if (ibv_destroy_cq(cq)) {
	fprintf(stderr, "Error, ibv_destroy_cq() failed\n");
	return -1;
}

创建一个带有100个与“完成”事件通道相关联的entry的CQ:
(在此示例中,我们假设完成事件通道之前已经创建):

struct ibv_cq *cq;
struct ibv_comp_channel *channel;
 
cq = ibv_create_cq(context, 100, NULL, channel, 0);
if (!cq) {
	fprintf(stderr, "Error, ibv_create_cq() failed\n");
	return -1;
} 

 

 

常见问题

  • 为何CQ有益呢?

CQ用于为已完成的任何工作请求保留WC(工作完成,WC能提供详细信息)。

  • 我可以在同一QP中对发送/接收队列使用不同的CQ吗?

是的。在任何QP中,发送队列的CQ和接收队列的CQ可以相同或不同。这是灵活的,由用户决定。

  • 几个QP可以与同一个CQ相关联吗?

是的。多个QP可以在它们的发送或接收队列中或在两个队列中与同一个CQ相关联。

  • CQ大小应该是多少?

A CQ should have enough room to hold all of Work Completions of the Outstanding Work Requests of the Queues that are associated with that CQ, so the CQ size shouldn't be less than the total number of Work Request that may be outstanding.

一个CQ应该有足够的空间来容纳与该CQ相关的队列中未完成的工作请求的所有工作完成,因此CQ的大小不应小于可能未完成的工作请求的总数。

  • 如果我选择的CQ尺寸太小会发生什么?

If there will be a case that the CQ will be full and a new Work Completion is going to be added to that CQ, there will be a CQ overrun. A Completion with error will be added to the CQ and an asynchronous event IBV_EVENT_CQ_ERR will be generated.

如果可能出现CQ满的情况,并且要向该CQ添加新的工作完成,则CQ会超支。有错误的完成将添加到CQ中,并生成一个异步事件IBV_EVENT_CQ_ERR。

  • 我可以将哪个值用作cq_context?

由于cq_context  void*,因此您使用任何值。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RDMA HCA/TCA是一种高速网络适配器,它使用RDMA技术来提高数据传输的效率和性能。HCA代表Host Channel Adapter,而TCA代表Target Channel Adapter。HCA通常安装在主机上,而TCA通常安装在存储设备上。这两种适配器都支持RDMA技术,可以通过RDMA协议进行高速数据传输。 RDMA技术是一种零拷贝技术,它可以直接在内存中传输数据,而不需要将数据从内存复制到网络适配器的缓冲区中。这种技术可以显著提高数据传输的效率和性能,减少CPU的负载,降低网络延迟和网络拥塞。 RDMA HCA/TCA通常使用InfiniBand或者RoCE(RDMA over Converged Ethernet)网络来进行高速数据传输。这些网络可以提供非常低的延迟和高的带宽,适用于高性能计算、云计算、大数据分析等领域。 以下是一个使用RDMA Write with Immediate Data的例子: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <infiniband/verbs.h> #define MSG_SIZE 1024 #define RDMA_BUF_SIZE 1024 struct rdma_context { struct ibv_context *ctx; struct ibv_pd *pd; struct ibv_mr *mr; struct ibv_cq *cq; struct ibv_qp *qp; struct ibv_comp_channel *comp_channel; struct ibv_port_attr port_attr; char *rdma_buf; uint32_t rkey; uint64_t remote_addr; }; int main(int argc, char *argv[]) { struct rdma_context ctx; struct ibv_device **dev_list; struct ibv_device *ib_dev; struct ibv_qp_init_attr qp_init_attr; struct ibv_qp_attr qp_attr; struct ibv_wc wc; int num_devices; int ret; int i; /* 获取IB设备列表 */ dev_list = ibv_get_device_list(&num_devices); if (!dev_list) { perror("ibv_get_device_list"); return -1; } /* 选择第一个IB设备 */ ib_dev = dev_list[0]; if (!ib_dev) { fprintf(stderr, "No IB devices found\n"); return -1; } /* 打开IB设备 */ ctx.ctx = ibv_open_device(ib_dev); if (!ctx.ctx) { perror("ibv_open_device"); return -1; } /* 创建PD */ ctx.pd = ibv_alloc_pd(ctx.ctx); if (!ctx.pd) { perror("ibv_alloc_pd"); return -1; } /* 分配内存 */ ctx.rdma_buf = malloc(RDMA_BUF_SIZE); if (!ctx.rdma_buf) { perror("malloc"); return -1; } /* 注册内存 */ ctx.mr = ibv_reg_mr(ctx.pd, ctx.rdma_buf, RDMA_BUF_SIZE, IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE); if (!ctx.mr) { perror("ibv_reg_mr"); return -1; } /* 创建CQ */ ctx.cq = ibv_create_cq(ctx.ctx, 1, NULL, NULL, 0); if (!ctx.cq) { perror("ibv_create_cq"); return -1; } /* 创建QP */ memset(&qp_init_attr, 0, sizeof(qp_init_attr)); qp_init_attr.send_cq = ctx.cq; qp_init_attr.recv_cq = ctx.cq; qp_init_attr.qp_type = IBV_QPT_RC; qp_init_attr.cap.max_send_wr = 1; qp_init_attr.cap.max_recv_wr = 1; qp_init_attr.cap.max_send_sge = 1; qp_init_attr.cap.max_recv_sge = 1; ctx.qp = ibv_create_qp(ctx.pd, &qp_init_attr); if (!ctx.qp) { perror("ibv_create_qp"); return -1; } /* 修改QP状态 */ memset(&qp_attr, 0, sizeof(qp_attr)); qp_attr.qp_state = IBV_QPS_INIT; qp_attr.pkey_index = 0; qp_attr.port_num = 1; qp_attr.qp_access_flags = IBV_ACCESS_REMOTE_WRITE; ret = ibv_modify_qp(ctx.qp, &qp_attr, IBV_QP_STATE | IBV_QP_PKEY_INDEX | IBV_QP_PORT | IBV_QP_ACCESS_FLAGS); if (ret) { perror("ibv_modify_qp"); return -1; } /* 获取端口属性 */ ret = ibv_query_port(ctx.ctx, 1, &ctx.port_attr); if (ret) { perror("ibv_query_port"); return -1; } /* 创建Completion Channel */ ctx.comp_channel = ibv_create_comp_channel(ctx.ctx); if (!ctx.comp_channel) { perror("ibv_create_comp_channel"); return -1; } /* 将CQ绑定到Completion Channel */ ret = ibv_req_notify_cq(ctx.cq, 0); if (ret) { perror("ibv_req_notify_cq"); return -1; } /* 等待CQ事件 */ ret = ibv_get_cq_event(ctx.comp_channel, &ctx.cq, &ctx.ctx); if (ret) { perror("ibv_get_cq_event"); return -1; } /* 请求下一个CQ事件 */ ret = ibv_req_notify_cq(ctx.cq, 0); if (ret) { perror("ibv_req_notify_cq"); return -1; } /* 获取远程节点的rkey和地址 */ ctx.rkey = 0x12345678; ctx.remote_addr = 0xdeadbeef; /* 向远程节点发送数据 */ memset(ctx.rdma_buf, 0, RDMA_BUF_SIZE); strcpy(ctx.rdma_buf, "Hello RDMA!"); struct ibv_send_wr wr, *bad_wr; struct ibv_sge sge; memset(&wr, 0, sizeof(wr)); wr.wr_id = 0; wr.opcode = IBV_WR_RDMA_WRITE_WITH_IMM; wr.send_flags = IBV_SEND_SIGNALED; wr.imm_data = 0x1234; wr.wr.rdma.remote_addr = ctx.remote_addr; wr.wr.rdma.rkey = ctx.rkey; wr.sg_list = &sge; wr.num_sge = 1; sge.addr = (uintptr_t)ctx.rdma_buf; sge.length = strlen(ctx.rdma_buf) + 1; sge.lkey = ctx.mr->lkey; ret = ibv_post_send(ctx.qp, &wr, &bad_wr); if (ret) { perror("ibv_post_send"); return -1; } /* 等待发送完成 */ do { ret = ibv_poll_cq(ctx.cq, 1, &wc); if (ret < 0) { perror("ibv_poll_cq"); return -1; } } while (ret == 0); /* 检查发送状态 */ if (wc.status != IBV_WC_SUCCESS) { fprintf(stderr, "Send failed with status %d\n", wc.status); return -1; } /* 关闭QP */ ret = ibv_destroy_qp(ctx.qp); if (ret) { perror("ibv_destroy_qp"); return -1; } /* 关闭Completion Channel */ ret = ibv_destroy_comp_channel(ctx.comp_channel); if (ret) { perror("ibv_destroy_comp_channel"); return -1; } /* 关闭CQ */ ret = ibv_destroy_cq(ctx.cq); if (ret) { perror("ibv_destroy_cq"); return -1; } /* 注销内存 */ ret = ibv_dereg_mr(ctx.mr); if (ret) { perror("ibv_dereg_mr"); return -1; } /* 释放内存 */ free(ctx.rdma_buf); /* 释放PD */ ret = ibv_dealloc_pd(ctx.pd); if (ret) { perror("ibv_dealloc_pd"); return -1; } /* 关闭IB设备 */ ret = ibv_close_device(ctx.ctx); if (ret) { perror("ibv_close_device"); return -1; } /* 释放IB设备列表 */ ibv_free_device_list(dev_list); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值