Infiniband RDMA程序随机挂起
有谁使用RDMA_CM库进行过RDMA编程 我很难找到哪怕是简单的例子来学习。librdmacm中有一个rdma_客户端&rdma_服务器示例,但它不是在循环中运行的(rping是循环的,但它是直接使用IB动词而不是rdma_cm函数编写的) 我制作了一个简单的乒乓球程序,但它在1-100次弹跳后锁定在任何地方。我发现在客户端中添加睡眠会使它在挂起之前工作更长时间,这表明存在竞争条件 客户端卡在rdma_get_send_comp()中,服务器卡在rdma_get_recv_comp()中 我有限的理解是,在每次rdma_post_send()之前,您需要在发送之后发出rdma_post_recv()。同样,在每次发送之前(第一次客户端发送除外),您需要等待一条消息(rdma_get_recv()),指示另一方已准备好接收 有什么不对劲吗Infiniband RDMA程序随机挂起,infiniband,rdma,Infiniband,Rdma,有谁使用RDMA_CM库进行过RDMA编程 我很难找到哪怕是简单的例子来学习。librdmacm中有一个rdma_客户端&rdma_服务器示例,但它不是在循环中运行的(rping是循环的,但它是直接使用IB动词而不是rdma_cm函数编写的) 我制作了一个简单的乒乓球程序,但它在1-100次弹跳后锁定在任何地方。我发现在客户端中添加睡眠会使它在挂起之前工作更长时间,这表明存在竞争条件 客户端卡在rdma_get_send_comp()中,服务器卡在rdma_get_recv_comp()中 我有
Server(rdma_cm_id *id)
{
ibv_wc wc;
int ret;
uint8_t recvBuffer[MESSAGE_BUFFER_SIZE],
sendBuffer[MESSAGE_BUFFER_SIZE];
ibv_mr *recvMemRegion = rdma_reg_msgs(id, recvBuffer, MESSAGE_BUFFER_SIZE);
if (!recvMemRegion)
throw 0;
ibv_mr *sendMemRegion = rdma_reg_msgs(id, sendBuffer, MESSAGE_BUFFER_SIZE);
if (!sendMemRegion)
throw 0;
if (ret = rdma_post_recv(id, NULL, recvBuffer, 1, recvMemRegion))
throw 0;
if (ret = rdma_accept(id, NULL))
throw 0;
do
{
if ((ret = rdma_get_recv_comp(id, &wc)) <= 0)
throw 0;
if (ret = rdma_post_recv(id, NULL, recvBuffer, 1, recvMemRegion))
throw 0;
if (ret = rdma_post_send(id, NULL, sendBuffer, 1, sendMemRegion, 0))
throw 0;
printf(".");
fflush(stdout);
if ((ret = rdma_get_send_comp(id, &wc)) <= 0)
throw 0;
}
while (true);
}
Client() // sends the 1st message
{
// queue-pair parameters are:
attr.cap.max_send_wr = attr.cap.max_recv_wr = 4;
attr.cap.max_send_sge = attr.cap.max_recv_sge = 2;
attr.cap.max_inline_data = 16;
attr.qp_context = id;
attr.sq_sig_all = 1;
attr.qp_type = IBV_QPT_RC;
<create connection boiler plate>
uint8_t recvBuffer[MESSAGE_BUFFER_SIZE],
sendBuffer[MESSAGE_BUFFER_SIZE];
recvMemRegion = rdma_reg_msgs(id, recvBuffer, MESSAGE_BUFFER_SIZE);
if (!recvMemRegion)
throw 0;
sendMemRegion = rdma_reg_msgs(id, sendBuffer, MESSAGE_BUFFER_SIZE);
if (!sendMemRegion)
throw 0;
if (ret = rdma_connect(id, NULL))
throw 0;
do
{
if (ret = rdma_post_recv(id, NULL, recvBuffer, 1, recvMemRegion))
throw 0;
//usleep(5000);
if (ret = rdma_post_send(id, NULL, sendBuffer, 1, sendMemRegion, 0))
throw 0;
if ((ret = rdma_get_send_comp(id, &wc)) <= 0)
throw 0;
if ((ret = rdma_get_recv_comp(id, &wc)) <= 0)
throw 0;
printf(".");
fflush(stdout);
}
while (true);
}
服务器(rdma\u cm\u id*id)
{
ibv_wc;
int ret;
uint8\u t recvBuffer[消息缓冲区大小],
sendBuffer[消息缓冲区大小];
ibv_mr*recvMemRegion=rdma_reg_msgs(id、recvBuffer、消息缓冲区大小);
if(!recvMemRegion)
掷0;
ibv_mr*sendMemRegion=rdma_reg_msgs(id、sendBuffer、消息缓冲区大小);
如果(!sendMemRegion)
掷0;
if(ret=rdma_post_recv(id,NULL,recvBuffer,1,recvMemRegion))
掷0;
if(ret=rdma_accept(id,NULL))
掷0;
做
{
如果((ret=rdma_get_recv_comp(id,&wc))诅咒!我被SUSE 11附带的librdmacm-1.0.15-1(从2012年起)中的一个bug咬了一口。我知道我的发送/接收顺序没有问题
我首先尝试将我的代码与其他示例进行比较
while (!ibv_poll_cq(id->send_cq, 1, &wc));
而不是rdma_get_send_comp()和rdma_get_recv_comp()。我尝试替换我的示例中的那些,奇迹般地,悬挂消失了
嗯,也许rdma_get_send_comp()没有达到我的预期。我最好看看代码。我得到了1.0.15和1.0.18的代码,我在rdma_.h中看到了什么
2个非常不同的IB动词序列:
// 1.0.15
rdma_get_send_comp(struct rdma_cm_id *id, struct ibv_wc *wc)
{
struct ibv_cq *cq;
void *context;
int ret;
ret = ibv_poll_cq(id->send_cq, 1, wc);
if (ret)
goto out;
ret = ibv_req_notify_cq(id->send_cq, 0);
if (ret)
return rdma_seterrno(ret);
while (!(ret = ibv_poll_cq(id->send_cq, 1, wc))) {
ret = ibv_get_cq_event(id->send_cq_channel, &cq, &context);
if (ret)
return rdma_seterrno(ret);
assert(cq == id->send_cq && context == id);
ibv_ack_cq_events(id->send_cq, 1);
}
out:
return (ret < 0) ? rdma_seterrno(ret) : ret;
}
vs
// 1.0.18
rdma_get_send_comp(struct rdma_cm_id *id, struct ibv_wc *wc)
{
struct ibv_cq *cq;
void *context;
int ret;
do {
ret = ibv_poll_cq(id->send_cq, 1, wc);
if (ret)
break;
ret = ibv_req_notify_cq(id->send_cq, 0);
if (ret)
return rdma_seterrno(ret);
ret = ibv_poll_cq(id->send_cq, 1, wc);
if (ret)
break;
ret = ibv_get_cq_event(id->send_cq_channel, &cq, &context);
if (ret)
return ret;
assert(cq == id->send_cq && context == id);
ibv_ack_cq_events(id->send_cq, 1);
} while (1);
return (ret < 0) ? rdma_seterrno(ret) : ret;
}
//1.0.15
rdma_get_send_comp(结构rdma_cm_id*id,结构ibv_wc*wc)
{
结构ibv_cq*cq;
无效*上下文;
int ret;
ret=ibv_poll_cq(id->send_cq,1,wc);
如果(ret)
出去;
ret=ibv\U req\U notify\U cq(id->send\U cq,0);
如果(ret)
返回rdma_设置错误号(ret);
而(!(ret=ibv_poll_cq(id->send_cq,1,wc))){
ret=ibv\u get\u cq\u事件(id->send\u cq\u channel,&cq,&context);
如果(ret)
返回rdma_设置错误号(ret);
断言(cq==id->sendcq&&context==id);
ibv_ack_cq_事件(id->send_cq,1);
}
输出:
返回(ret<0)?rdma_设置错误号(ret):返回;
}
vs
// 1.0.18
rdma_get_send_comp(结构rdma_cm_id*id,结构ibv_wc*wc)
{
结构ibv_cq*cq;
无效*上下文;
int ret;
做{
ret=ibv_poll_cq(id->send_cq,1,wc);
如果(ret)
打破
ret=ibv\U req\U notify\U cq(id->send\U cq,0);
如果(ret)
返回rdma_设置错误号(ret);
ret=ibv_poll_cq(id->send_cq,1,wc);
如果(ret)
打破
ret=ibv\u get\u cq\u事件(id->send\u cq\u channel,&cq,&context);
如果(ret)
返回ret;
断言(cq==id->sendcq&&context==id);
ibv_ack_cq_事件(id->send_cq,1);
}而(1),;
返回(ret<0)?rdma_设置错误号(ret):返回;
}
有人能解释为什么1.0.18可以正常工作,而1.0.15可以随机挂起吗?在这个网站上回答问题不是一个好主意,但我相信你正在寻找的承诺是。