DPDK ring简单说明

1.ring提供的接口

对于一个模块而言,其对外提供的接口直接表明了它所提供的功能,也是我们分析一个模块最初的入口。ring是一个环形无锁队列,支持多生产者多消费者操作,所以对于队列的操作构成了模块的主要接口。ring的实现在文件rte_ring.crte_ring.h中。

rte_ring_create() //ring的创建

rte_ring_init() //ring的初始化

rte_ring_lookup() //ring的查找

rte_ring_free() //ring的释放

rte_ring_dump() //获取ring的使用信息

rte_ring_set_water_mark() //设置ring的水标

以上的几个大的接口提供了ring的开始和结束以及查找。同时对于一个队列来说,还有更多的入队,出队操作。如函数

rte_ring_mp_enqueue_burst()//多生产者批量入队

此处就省略其他很多单(多)生产者,单(多)消费者的操作函数接口了。

2.ring的创建及初始化

rte ring的创建是通过rte_ring_create()函数来实现的,这个函数的原型struct rte_ring * rte_ring_create(const char *name, unsigned count, int socket_id,unsigned flags)

这里需要注意的是socket_idflags,在多个进程同时访问同一个ring时,要改善性能,可以创建多个ring,同时要注意多个进程绑定在同一个socket上。另一个参数flags则是表明创建的ring是否安全支持多生产者多消费者模型。接下来就来看看创建及初始化中的一些细节。

首先找到ring_listring_list是挂接在队列中的,根据ring不跨socket的原则,推断是每个socket都维护有一个这样的队列,具体就不去抠代码了,先主后次。

接下来就是两个准备操作:

  • 获取创建的ring的空间大小,为后面分配空间做准备。

  • 分配一个struct rte_tailq_entry *te;结构,在创建完成ring后,挂接这个队列元素到队列中去。此时不妨先看一下这个结构体的定义。

    struct rte_tailq_entry {
    	TAILQ_ENTRY(rte_tailq_entry) next; 
    	/**< Pointer entries for a tailq list */
    	void *data; /**< Pointer to the data referenced by this 	tailq entry */
    };
    

其中的data指针就指向了创建的ring的地址。

然后就是为新创建的ring分配内存空间咯,使用了rte_memzone_reserve()函数分配,这个函数在内存部分详细说明,但是需要注意:

rte_memzone_reserve()只能用于primary进程中内存分配,也暗含了对于多生产者多消费者使用的ring,其ring的创建要在 primary进程中。

最后就是把分配的ring初始化-rte_ring_init(),并填充te元素,把te挂接在队列中。

3.ring的出入队

ring的出入队操作,我们重点来关注几个接口:

__rte_ring_mp_do_enqueue()
__rte_ring_sp_do_enqueue()
__rte_ring_mc_do_dequeue()
__rte_ring_sc_do_dequeue()

无论使用的哪个上层接口,最终调用的就是这4个函数。在使用多生产者多消费者时,函数中会有rte_pause()的操作,里面使用了__mm_pause()指令,看注释意思是避免忙等待,主要应用在短时的loops。至于具体的头和尾指针的移动,可以参考prog_guide中的ring一节,图文并茂。

4.ring的使用范围以及潜在问题

  • 1.ring的调试信息在non_EAL线程中是不支持获取的。

  • 2.ring支持多生产者入队和多消费者出队,但是都是不可抢占的。不可抢占的意思是:

    • 一个线程在做多生产者入队操作,此时,禁止被另一个做多生产者入队的线程抢占。
    • 一个线程在做多消费者出队操作,此时,禁止被另一个做多消费者出队的县城抢占。

    这意味着如果两个线程在同一个core上操作,那么2th线程则必须等到1th线程调度后才能访问,因此,尽量不要在同一个core上对同一个ring做多生产者同时入队或者出队。更详细的说明,请参考 prog_guide 3.3.4章节。

5.关于水标的使用

在初始化ring的时候,可以设置对应的水标位置,但感觉它并未提供设置接口,用的地方不是很多。比如,当入队已经达到水标位置时,就可以返回对应的错误值,上层调用就可以做些处理。

x.关于无锁队列的链接:

无锁队列顶层设计

无锁队列到底有没有锁

posted @ 2017-05-26 22:45  AISEED  阅读(7354)  评论(0编辑  收藏  举报