DPDK以两种方式对外提供内存管理方法,一个是rte_mempool,主要用于网卡数据包的收发;一个是rte_malloc,主要为应用程序提供内存使用接口。本文讨论rte_mempool。rte_mempool由函数rte_mempool_create()负责创建,从rte_config.mem_config->free_memseg[]中取出合适大小的内存,放到rte_config.mem_config->memzone[]中。

本文中,以l2fwd为例,说明rte_mempool的创建及使用。

一、rte_mempool的创建

1 l2fwd_pktmbuf_pool =
2 rte_mempool_create("mbuf_pool", NB_MBUF,
3 MBUF_SIZE, 32,
4 sizeof(struct rte_pktmbuf_pool_private),
5 rte_pktmbuf_pool_init, NULL,
6 rte_pktmbuf_init, NULL,
7 rte_socket_id(), 0);

“mbuf_pool”:创建的rte_mempool的名称。

NB_MBUF:rte_mempool包含的rte_mbuf元素的个数。

MBUF_SIZE:每个rte_mbuf元素的大小。

1 #define RTE_PKTMBUF_HEADROOM    128
2 #define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
3 #define NB_MBUF 8192
1 struct rte_pktmbuf_pool_private {
2 uint16_t mbuf_data_room_size; /**< Size of data space in each mbuf.*/
3 };

rte_mempool由函数rte_mempool_create()负责创建。首先创建rte_ring,再创建rte_mempool,并建立两者之间的关联。

   

1、rte_ring_create()创建rte_ring无锁队列

1 r = rte_ring_create(rg_name, rte_align32pow2(n+1), socket_id, rg_flags);

  具体步骤如下:

  a、需要保证创建的队列数可以被2整除,即,count = rte_align32pow2(n + 1);

  b、计算需要为count个队列分配的内存空间,即,ring_size = count * sizeof(void *) + sizeof(struct rte_ring);

  struct rte_ring的数据结构如下,

 1 struct rte_ring {
2 TAILQ_ENTRY(rte_ring) next; /**< Next in list. */
3
4 char name[RTE_RING_NAMESIZE]; /**< Name of the ring. */
5 int flags; /**< Flags supplied at creation. */
6
7 /** Ring producer status. */
8 struct prod {
9 uint32_t watermark; /**< Maximum items before EDQUOT. */
10 uint32_t sp_enqueue; /**< True, if single producer. */
11 uint32_t size; /**< Size of ring. */
12 uint32_t mask; /**< Mask (size-1) of ring. */
13 volatile uint32_t head; /**< Producer head. */
14 volatile uint32_t tail; /**< Producer tail. */
15 } prod __rte_cache_aligned;
16
17 /** Ring consumer status. */
18 struct cons {
19 uint32_t sc_dequeue; /**< True, if single consumer. */
20 uint32_t size; /**< Size of the ring. */
21 uint32_t mask; /**< Mask (size-1) of ring. */
22 volatile uint32_t head; /**< Consumer head. */
23 volatile uint32_t tail; /**< Consumer tail. */
24 #ifdef RTE_RING_SPLIT_PROD_CONS
25 } cons __rte_cache_aligned;
26 #else
27 } cons;
28 #endif
29
30 #ifdef RTE_LIBRTE_RING_DEBUG
31 struct rte_ring_debug_stats stats[RTE_MAX_LCORE];
32 #endif
33
34 void * ring[0] __rte_cache_aligned; /**< Memory space of ring starts here.
35 * not volatile so need to be careful
36 * about compiler re-ordering */
37 };

  c、调用rte_memzone_reserve(),在rte_config.mem_config->free_memseg[]中查找一个合适的free_memseg(查找规则是free_memseg中剩余内存大于等于需要分配的内存,但是多余的部分是最小的),从该free_memseg中分配指定大小的内存,然后将分配的内存记录在rte_config.mem_config->memzone[]中。

  d、初始化新分配的rte_ring。

 1 r->flags = flags;
2 r->prod.watermark = count;
3 r->prod.sp_enqueue = !!(flags & RING_F_SP_ENQ);
4 r->cons.sc_dequeue = !!(flags & RING_F_SC_DEQ);
5 r->prod.size = r->cons.size = count;
6 r->prod.mask = r->cons.mask = count-1;
7 r->prod.head = r->cons.head = 0;
8 r->prod.tail = r->cons.tail = 0;
9
10 TAILQ_INSERT_TAIL(ring_list, r, next); // 挂到rte_config.mem_config->tailq_head[RTE_TAILQ_RING]队列中

2、创建并初始化rte_mempool

  a、计算需要为rte_mempool申请的内存空间。包含:sizeof(struct rte_mempool)、private_data_size,以及n * objsz.total_size。

1 mempool_size = MEMPOOL_HEADER_SIZE(mp, pg_num) + private_data_size;
2 if (vaddr == NULL)
3 mempool_size += (size_t)objsz.total_size * n;

  objsz.total_size = objsz.header_size + objsz.elt_size + objsz.trailer_size; 其中,

  objsz.header_size = sizeof(struct rte_mempool *);

  objsz.elt_size = MBUF_SIZE;

  objsz.trailer_size = ????

  b、调用rte_memzone_reserve(),在rte_config.mem_config->free_memseg[]中查找一个合适的free_memseg,在该free_memseg中分配mempool_size大小的内存,然后将新分配的内存记录到rte_config.mem_config->memzone[]中。

  c、初始化新创建的rte_mempool,并调用rte_pktmbuf_pool_init()初始化rte_mempool的私有数据结构。

 1 /* init the mempool structure */
2 mp = mz->addr;
3 memset(mp, 0, sizeof(*mp));
4 snprintf(mp->name, sizeof(mp->name), "%s", name);
5 mp->phys_addr = mz->phys_addr;
6 mp->ring = r;
7 mp->size = n;
8 mp->flags = flags;
9 mp->elt_size = objsz.elt_size;
10 mp->header_size = objsz.header_size;
11 mp->trailer_size = objsz.trailer_size;
12 mp->cache_size = cache_size;
13 mp->cache_flushthresh = (uint32_t)
14 (cache_size * CACHE_FLUSHTHRESH_MULTIPLIER);
15 mp->private_data_size = private_data_size;
16
17 /* calculate address of the first element for continuous mempool. */
18 obj = (char *)mp + MEMPOOL_HEADER_SIZE(mp, pg_num) +
19 private_data_size;
20
21 /* populate address translation fields. */
22 mp->pg_num = pg_num;
23 mp->pg_shift = pg_shift;
24 mp->pg_mask = RTE_LEN2MASK(mp->pg_shift, typeof(mp->pg_mask));
25
26 /* mempool elements allocated together with mempool */
27 mp->elt_va_start = (uintptr_t)obj;
28 mp->elt_pa[0] = mp->phys_addr +
29 (mp->elt_va_start - (uintptr_t)mp);
30
31 mp->elt_va_end = mp->elt_va_start;
32
33 RTE_EAL_TAILQ_INSERT_TAIL(RTE_TAILQ_MEMPOOL, rte_mempool_list, mp); //挂到rte_config.mem_config->tailq_head[RTE_TAILQ_MEMPOOL]队列中

  d、调用mempool_populate(),以及rte_pktmbuf_init()初始化rte_mempool的每个rte_mbuf元素。

3、总结

相关数据结构的关联关系如下图:

rte_mempool内存管理的更多相关文章

  1. DPDK内存管理-----(二)rte_mempool内存管理

    DPDK以两种方式对外提供内存管理方法,一个是rte_mempool,主要用于网卡数据包的收发:一个是rte_malloc,主要为应用程序提供内存使用接口.本文讨论rte_mempool.rte_me ...

  2. DPDK内存管理(1)

    1 前言 DPDK将利用hugepage预留的物理内存统一的组织管理起来,然后以库的方式对外提供使用的接口.下图展示了DPDK中内存有关的模块的相互关系. rte_eal            是统一 ...

  3. DPDK内存管理(1)(转)

    1 前言 DPDK将利用hugepage预留的物理内存统一的组织管理起来,然后以库的方式对外提供使用的接口.下图展示了DPDK中内存有关的模块的相互关系. rte_eal            是统一 ...

  4. .NET基础拾遗(1)类型语法基础和内存管理基础

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开发基 ...

  5. PHP扩展-生命周期和内存管理

    1. PHP源码结构 PHP的内核子系统有两个,ZE(Zend Engine)和PHP Core.ZE负责将PHP脚本解析成机器码(也成为token符)后,在进程空间执行这些机器码:ZE还负责内存管理 ...

  6. linux2.6 内存管理——逻辑地址转换为线性地址(逻辑地址、线性地址、物理地址、虚拟地址)

    Linux系统中的物理存储空间和虚拟存储空间的地址范围分别都是从0x00000000到0xFFFFFFFF,共4GB,但物理存储空间与虚拟存储空间布局完全不同.Linux运行在虚拟存储空间,并负责把系 ...

  7. linux2.6 内存管理——概述

    在紧接着相当长的篇幅中,都是围绕着Linux如何管理内存进行阐述,在内核中分配内存并不是一件非常容易的事情,因为在此过程中必须遵从内核特定的状态约束.linux内存管理建立在基本的分页机制基础上,在l ...

  8. Objective-C内存管理之引用计数

    初学者在学习Objective-c的时候,很容易在内存管理这一部分陷入混乱状态,很大一部分原因是没有弄清楚引用计数的原理,搞不明白对象的引用数量,这样就当然无法彻底释放对象的内存了,苹果官方文档在内存 ...

  9. Quartz2D内存管理

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px "PingFang SC"; color: #239619 } p.p2 ...

随机推荐

  1. IceMx.Mvc 我的js MVC 框架 开篇

    开篇 这篇文章是后补的,前端时间想写一些对于js开发的一些理解,就直接写了,后来发现很唐突,所以今天在这里补一个开篇. 我的js Mvc 框架 基于实用设计,过分设计等于没设计.本着简单的原则,它只实 ...

  2. Redis系统学习 一、基础知识

    1.数据库 select 1  select 0 2.命令.关键字和值 redis不仅仅是一种简单的关键字-值型存储,从其核心概念来看,Redsi的5种数据结构中的每一个都至少有一个关键字和一个值.在 ...

  3. revel框架教程之权限控制

    Go语言实战 - revel框架教程之权限控制 一个站点上面最基本都会有三种用户角色,未登录用户.已登录用户和管理员.这一次我们就来看看在revel框架下如何进行权限控制. 因为revel是MVC结构 ...

  4. appfog java jdbc mysql连接

    本来用得好好的openshift被墙了,无奈只能找过一个免费的空间.同学推荐appfog,appfog的确是一个很好用的空间,支持几乎所有主流的技术.我自己喜欢写点java,刚好我就开始使用了.app ...

  5. Dragon Balls(hdu3635带权并查集)

    题意:n个城市有n个龙珠,T  a,b 代表将龙珠a移动到b城市,Q a代表查询龙珠a所在城市,该城市有多少颗龙珠,该龙珠移动了多少次. 注意:移动时是将龙珠所在该城市所有龙珠都移动,每个龙珠不会再回 ...

  6. andoid x项目的优化 1

    通常我们写程序,都是在项目计划的压力下完成的,此时完成的代码可以完成具体业务逻辑,但是性能不一定是最优化的,一般来说,一般来说,优秀的程序员在写完代码之后都会不断的对代码进行重构.重构的好处有很多,其 ...

  7. wireshark查看sip协议流

    选择中你要查看的sip消息-----右键--follow udp stream,就可以查看出消息流的整个流程.

  8. 从一般分布式设计看HDFS设计思想与架构

     要想深入学习HDFS就要先了解其设计思想和架构,这样才能继续深入使用HDFS或者深入研究源代码.懂得了"所以然"才能在实际使用中灵活运用.快速解决遇到的问题.下面这篇博文我们就先 ...

  9. ajax的分页查询(不刷新页面)

    既然是分页查询,那么就要有张数据很多的表,可以让它进行分页显示,用普通的方法进行分页查询必然是要刷新页面的,这里要实现不刷新页面进行分页显示数据,就要用到ajax方式.进行编写代码 (1)先写个显示数 ...

  10. java中outer的使用

    outer多用于嵌套循环的情况 outer: for (int i = 2 ; i <= 10 ; i++) { for (int j = 2 ; j <=10 ; j++) { if(i ...