首页 > 其他分享 >krping学习笔记 (1)

krping学习笔记 (1)

时间:2022-12-06 13:11:54浏览次数:36  
标签:krping rkey 笔记 学习 rdma wr cb recv ret

krping

Kriping是一个内核态的rdma ping-pong程序 , 其使用rdma读写的方式实现了数据在server-client间的ping-pong式传递. 如下图所示, 在开始数据传输前, client

会先将ping data写入到事先准备好的start buff中, 在第2步中, server会主动发起rdma read将ping data从start buff中读取到自己的rdma buff中. 第3步, 将buff

中的ping data rdma write 到 client的rdma buff中. 至此一次完整的rdma ping-pong数据传输就完成了.

image

原理

krping的工作过程如下所示:

image

1.client 通过 send-recv 模式 将 start buf (client会写入原始的ping data) 的地址, 发放给server进行rdma read的rkey, 每次传递给对端的payload大小.

static void krping_format_send(struct krping_cb *cb, u64 buf)
{
	struct krping_rdma_info *info = &cb->send_buf;
	u32 rkey;

	if (!cb->server || cb->wlat || cb->rlat || cb->bw) {
        //发放给server进行rdma read的rkey
		rkey = krping_rdma_rkey(cb, buf, !cb->server_invalidate);
		//start buf (client会写入原始的ping data) 的地址
		info->buf = htonll(buf);
		info->rkey = htonl(rkey);
		//传递给对端的payload大小
		info->size = htonl(cb->size);
		DEBUG_LOG("RDMA addr %llx rkey %x len %d\n",
			  (unsigned long long)buf, rkey, cb->size);
	}
}

//post_send
ret = ib_post_send(cb->qp, &cb->sq_wr, &bad_wr);

2.server 在recv操作的completion里, server获取到client传递过来的 start buf的总线地址(DMA分配的) , 还有操作start buf 的rkey, 以及start buf的大小.

P("read from recvq\n");
ret = ib_post_recv(cb->qp, &cb->rq_wr, &bad_wr);
if (ret) {
    printk(KERN_ERR PFX "ib_post_recv failed: %d\n", ret);
    goto err2;
}

krping_cq_event_handler:
		case IB_WC_RECV:
			DEBUG_LOG("recv completion\n");
			cb->stats.recv_bytes += sizeof(cb->recv_buf);
			cb->stats.recv_msgs++;
			if (cb->wlat || cb->rlat || cb->bw) {
				P("call server_recv\n");
				ret = server_recv(cb, &wc);
			} else {
				P("call client recv\n");
				ret = cb->server ? server_recv(cb, &wc) :
					client_recv(cb, &wc);
			}

			if (ret) {
				printk(KERN_ERR PFX "recv wc error: %d\n", ret);
				goto error;
			}

			ret = ib_post_recv(cb->qp, &cb->rq_wr, &bad_wr);
			if (ret) {
				printk(KERN_ERR PFX "post recv error: %d\n", 
				       ret);
				goto error;
			}
			wake_up_interruptible(&cb->sem);
			break;

static int server_recv(struct krping_cb *cb, struct ib_wc *wc)
{
	if (wc->byte_len != sizeof(cb->recv_buf)) {
		printk(KERN_ERR PFX "Received bogus data, size %d\n", 
		       wc->byte_len);
		return -1;
	}

	cb->remote_rkey = ntohl(cb->recv_buf.rkey);
	cb->remote_addr = ntohll(cb->recv_buf.buf);
	cb->remote_len  = ntohl(cb->recv_buf.size);
	DEBUG_LOG("Received rkey %x addr %llx len %d from peer\n",
		  cb->remote_rkey, (unsigned long long)cb->remote_addr, 
		  cb->remote_len);

	if (cb->state <= CONNECTED || cb->state == RDMA_WRITE_COMPLETE)
		cb->state = RDMA_READ_ADV;
	else
		cb->state = RDMA_WRITE_ADV;

	return 0;
}

3.server 构造rdma读请求, 开始从client的start buf中读取ping data

P("setup rdma_sq_wr and reset rkey\n");
cb->rdma_sq_wr.rkey = cb->remote_rkey; //设置rkey
cb->rdma_sq_wr.remote_addr = cb->remote_addr; //设置为client的start buff地址
cb->rdma_sq_wr.wr.sg_list->length = cb->remote_len; //
cb->rdma_sgl.lkey = krping_rdma_rkey(cb, cb->rdma_dma_addr, !cb->read_inv); //设置rdma_sgl的lkey
cb->rdma_sq_wr.wr.next = NULL; 

/* 发起一个INV Read */
if (cb->read_inv) {
    P("send read with inv cmd\n");
    cb->rdma_sq_wr.wr.opcode = IB_WR_RDMA_READ_WITH_INV;
} else {
    P("send read cmd\n");
    cb->rdma_sq_wr.wr.opcode = IB_WR_RDMA_READ;

    //链上一个opcode=local inv类型的WR
    cb->rdma_sq_wr.wr.next = &inv;
    memset(&inv, 0, sizeof inv);
    inv.opcode = IB_WR_LOCAL_INV;
    inv.ex.invalidate_rkey = cb->reg_mr->rkey;
    inv.send_flags = IB_SEND_FENCE;
}

//post send wr list到qp
ret = ib_post_send(cb->qp, &cb->rdma_sq_wr.wr, &bad_wr);
if (ret) {
    printk(KERN_ERR PFX "post send error %d\n", ret);
    break;
}
cb->rdma_sq_wr.wr.next = NULL;

wait_event_interruptible(cb->sem, cb->state >= RDMA_READ_COMPLETE);

4.server 收到 rdma read 的WC之后, 就会主动调度一把等待队列里的进程

case IB_WC_RDMA_READ:
    DEBUG_LOG("rdma read completion\n");
    cb->stats.read_bytes += cb->rdma_sq_wr.wr.sg_list->length;
    cb->stats.read_msgs++;
    cb->state = RDMA_READ_COMPLETE;
    wake_up_interruptible(&cb->sem);
    break;

5.server从client rdma读取到ping data后, 会再次通过send-recv的方式发送一个go-ahead消息给client, 通知阻塞的client继续工作.

//等待wc
ret = wait_event_interruptible(cb->sem, cb->state >= 
                               RDMA_WRITE_COMPLETE);
if (cb->state != RDMA_WRITE_COMPLETE) {
    printk(KERN_ERR PFX 
           "wait for RDMA_WRITE_COMPLETE state %d\n",
           cb->state);
    break;
}

//重置状态为connected
cb->state = CONNECTED;

if (cb->server && cb->server_invalidate) {
    cb->sq_wr.ex.invalidate_rkey = cb->remote_rkey;
    cb->sq_wr.opcode = IB_WR_SEND_WITH_INV;
    DEBUG_LOG("send-w-inv rkey 0x%x\n", cb->remote_rkey);
} 

//post send to qp
ret = ib_post_send(cb->qp, &cb->sq_wr, &bad_wr);
if (ret) {
    printk(KERN_ERR PFX "post send error %d\n", ret);
    break;
}
DEBUG_LOG("server posted go ahead\n");

6.client 收到 go-ahead消息的 WC

case IB_WC_RECV:
	DEBUG_LOG("recv completion\n");
	cb->stats.recv_bytes += sizeof(cb->recv_buf);
	cb->stats.recv_msgs++;
	if (cb->wlat || cb->rlat || cb->bw) {
    	P("call server_recv\n");
    	ret = server_recv(cb, &wc);
	} else {
    	P("call client recv\n");
    	ret = cb->server ? server_recv(cb, &wc) :
   	 	client_recv(cb, &wc);
	}

	if (ret) {
    	printk(KERN_ERR PFX "recv wc error: %d\n", ret);
    	goto error;
	}
	
	//
	ret = ib_post_recv(cb->qp, &cb->rq_wr, &bad_wr);
	if (ret) {
    	printk(KERN_ERR PFX "post recv error: %d\n", ret);
    	goto error;
	}
    wake_up_interruptible(&cb->sem);
    break;

static int client_recv(struct krping_cb *cb, struct ib_wc *wc)
{
	if (wc->byte_len != sizeof(cb->recv_buf)) {
		printk(KERN_ERR PFX "Received bogus data, size %d\n", 
		       wc->byte_len);
		return -1;
	}

	if (cb->state == RDMA_READ_ADV)
		cb->state = RDMA_WRITE_ADV;
	else
		cb->state = RDMA_WRITE_COMPLETE;

	return 0;
}

标签:krping,rkey,笔记,学习,rdma,wr,cb,recv,ret
From: https://www.cnblogs.com/dennis-wong/p/16954934.html

相关文章

  • Linux基础学习
    Linux基础Lesson1-常用基本命令​1.Ctrlc:取消命令,并且换行Ctrlu:清空本行命令tab键:可以补全命令和文件名,如果补全不了快速按两下tab键,可以显示备选选项ls......
  • 刷题笔记——2997.梯形面积
    题目2997.梯形面积代码h=(2*150)/15s=((15+25)*h)/2print('%.2f'%s)笔记使用占位符方法保留小数%g,科学计数法输出小数,会舍弃无效的部分print(......
  • HTML-学习笔记02
    HTML13、样式器+标签选择器内部样式表<html> <head> <metacharset="utf-8"> <title></title> <!--内部样式表--> <style> /*标签选择器*/ h1{ ......
  • ES6笔记 - 函数参数扩展 与 箭头函数
    函数的扩展目录函数的扩展1.函数的默认值1.1解构赋值默认值与函数默认值1.2参数默认值的位置2.rest参数3.箭头函数3.1基础用法3.2箭头函数中的this3.3用途1.函......
  • 云原生架构学习计划
    一、背景云原生已经是架构师躲不开的一个门槛,有必要拿下。这里列一下博主对云原生的学习之路。也可以给各位同学打个样,找到入门一个架构的方法。二、计划2.1总耗时一......
  • React学习路上的绊脚石Router
    Routerreact-router:核心库react-router-dom:路由的软件包react-router-nattive:用于开发RN应用的绑定React-router-domHashRouter:http://xxx.com/#/aboutBrowserRou......
  • 【论文导读】- Communication-Efficient Learning of Deep Networks from Decentraliz
    文章目录​​论文信息​​​​摘要​​​​主要内容(contributions)​​​​FederatedAveraging​​​​联邦学习​​​​隐私​​​​联邦优化​​​​联邦平均算法(FedAVG)​......
  • 学成在线项目-head学习
    学成在线项目-head学习1、先看看原图2、我们先看看html的源码<!DOCTYPEhtml><htmllang="en"><head><!--在项目中我们一般都是通过引入外部css链接的形式-->......
  • 深度学习中的两种anchor算法anchor-based 和anchor free 的区别
    anchor-based:这里基于fasterrcnn中选择anchor的方法##RPN阶段(anchortarget):1.计算所有样本点(wxh)与9个anchor拼在一起形成wxhx9个框,得到all_anchors(以图像为单......
  • 为机器学习模型设置最佳阈值:0.5是二元分类的最佳阈值吗
    对于二元分类,分类器输出一个实值分数,然后通过对该值进行阈值的区分产生二元的相应。例如,逻辑回归输出一个概率(一个介于0.0和1.0之间的值);得分等于或高于0.5的观察结果产......