DPDK memory学习

总体结构

自定向下分别是物理内存,memzone,mempool和pktmbuf。

启动时heap内存分配的API

关键的数据结构是: 
struct malloc_heap跟踪空闲的空间。 
struct malloc_elem作为基本的alloc/free的单元。每一个block都是2的指数大小。 
代码是:

 
 
memzone_reserve_aligned_thread_unsafe

->malloc_heap_alloc

->malloc_heap_alloc_on_heap_id

-> heap_alloc

-> find_suitable_element

-> malloc_elem_free_list_index(size) // 在free list找到可用的.

https://doc.dpdk.org/guides-2.0/prog_guide/malloc_lib.html

rte_malloc相关的API

不推荐在实时核(RT core)使用,因为rte_malloc本身有spin lock。分配出来的内存是在同一个DPDK instance里共享的,使用的是hugepage的内存,比malloc性能更好,rte_malloc的方式比pool内存池的方式更慢一些。可以在配置的代码使用,或者启动时使用,而不是运行时大量收发包的代码。

类型 malloc rte_malloc
huge page 不强制 默认
numa node pin 不强制 默认
访问IOVA
支持IOVA连续内存 不强制
cache align分配 不强制 强制
分配时align
多处理器共享
多进程安全
 
 
rte_malloc

->rte_malloc_socket

->malloc_socket

->malloc_heap_alloc(type, size, socket_arg, 0, align == 0 ? 1 : align, 0, false);

mempool相关的API

DPDK mempool是固定size的object,性能优化做了很多。 
rte_mempool_create() // 分配N个可用size为elt_size的buffer,里面会调用rte_mempool_create_empty() 
如果有1GB的page,先用1GB的,因为有RTE_MEMZONE_1GB。否则可以用其他的比如2MB的,因为有RTE_MEMZONE_SIZE_HINT_ONLY。 
rte_mempool_get() // consumer uses this for geting one memory entity out of memory pool of N entities 
rte_mempool_put() // return back (free) the memory entity back to mempool 
如果要替换mempool相关的操作,可以用rte_mempool_set_ops_byname(mp, NAME, NULL)。 
mempool manager的库是一个框架,独立的。 
mempool_cache_init()用于分配cache。 
rte_mempool_ops_table()会注册一系列函数。 
rte_mempool_register_ops()会注册mempool的操作函数。 
rte_mempool_generic_get()可以拿到多个object。

 
 
rte_mempool_create_empty

->rte_mempool_calc_obj_size

->rte_mcfg_mempool_write_lock

->rte_zmalloc("MEMPOOL_TAILQ_ENTRY", sizeof(*te), 0);

->rte_zmalloc_socket(type, size, align, SOCKET_ID_ANY);

->rte_memzone_reserve(mz_name, mempool_size, socket_id, mz_flags);

->rte_memzone_reserve_thread_safe()

->memzone_reserve_aligned_thread_unsafe()

// check alignment

// alloc memory from heap

// if no size constraints

->malloc_heap_alloc_biggest(NULL, socket_id, flags, align, contig);

// or

->malloc_heap_alloc(NULL, requested_len, socket_id, flags, align, bound, contig);

->malloc_elem *elem = malloc_elem_from_data(mz_addr)

/* fill the zone in config */

->mz_idx = rte_fbarray_find_next_free(arr, 0);

// fill memzone info, iova, addr, len, hugepage_sz, socket_id, flags.

->rte_mcfg_tailq_write_lock();

->TAILQ_INSERT_TAIL(mempool_list, te, next);

->rte_mcfg_tailq_write_unlock();

->rte_mcfg_mempool_write_unlock();

每个obj都有header和trailer,obj的size是elt_size。

mbuf相关的API

mbuf ==> eth packet,是针对以太网的包设计的,不建议作为本地的buffer使用。本地buffer可以用自定义的mempool的block,从而避免额外的mbuf header消耗。 
rte_pktmbuf_pool_create_by_ops(), ops_name可以把operation替换掉,比如改为使用lf_stack。就是用了rte_mempool_stack.c里的stack方式,而不是默认的ring方式。dpdk/drivers/mempool/目录下有相关的处理函数。 
rte_pktmbuf_raw_alloc是从pktmbuf_pool里取一个mbuf,因为是raw_alloc,所以不用初始化很多field,速度非常快。

rte_pktmbuf_pool_private()是私有的空间,size是data_room的大小。

data_len是每个mbuf的有效数据长度,buf_len是每个mbuf的总长度,pkt_len是多个mbuf的data_len之和。mbuf里的buf_len字段大小是u16,所以最大只支持64kB,除非使用mbuf chain,pkt_len最大可以达到u32,4GB。

mbuf external buffer

mbuf加上external data buffer,就像车子拉了一个后备的小拖车。 
rte_pktmbuf_attach/detach_extbuf() 
目前不在DPDK的主分支。

DPDK eal关于mem的配置参数

18.11后有这3个参数。 
–single-file-segment,表示map的地址都放在一个文件里,节约文件句柄。 
–socket-mem,表示这个socket一启动就分配这么多内存。动态模式下,这些内存是固定分配好的,app退出才会释放。 
–socket-limit,这个socket最多只能分配这么多内存。legacy模式不支持。

IOMMU的IOVA模式

通过–iova=pa或者–iova=va即可选择。默认是PA模式。 
IOVA as VA,可以确保不连续的PA地址段被连续使用。

IOVA as PA,虚拟地址连续的,物理地址也要连续。

有些驱动不支持iommu为iova=va的模式,可能是PMD的限制,也可能是有服务必须要用PA。 
18.11版本后,在IOVA as VA的模式下,VA连续不一定IOVA也连续。ring,mempool,hash表只需要VA连续。

调试时显示内存情况

这些API可以用于调试,看DPDK的内存使用情况。

 
 

rte_dump_physmem_layout(stdout); // MEMORY_SEGMENTS,看用了几个hugepage

rte_memzone_dump(stdout); // MEMORY_ZONES,可以看zone间是否连续

rte_dump_tailq(stdout); // TAIL_QUEUES,RTE_RING和RTE_MEMPOOL的一般有first和last,其它的tail q一般只有last

/* MALLOC_STATS, 看每个heap,各自的alloc和free的size/count是多少。

Heap_size是总共的(=Free_size+Alloc_size)。

Free_size是可用的。

Alloc_size是已申请的。

Alloc_count是当前申请的(allocated and used),对应rte_malloc status BUSY。

Free_count是DPDK用rte_malloc申请过,又释放了的(allocated and freed),对应rte_free status FREE。总的list size是Alloc_count+Free_count

如果type是NULL,表示dump所有类型的memory。这里的heap id对应NUMA。比如heap id 1(从1开始)对NUMA 0(从0开始)。如果只有一个NUMA,那么就heap id 1的数据有效,后续的是空的。*/

rte_malloc_dump_stats(stdout, NULL);

rte_malloc_dump_heaps(stdout); // MALLOC_HEAPS,看哪些是FREE的,哪些是BUSY的。

rte_malloc_dump_stats_no_numa(stdout, "socket_mem"); // MALLOC_TOTAL_STATS,注意Free_size的也是被DPDK reserve的,不能被linux直接使用的。

原文链接:https://mp.weixin.qq.com/s/9gm8tJgtsPJ7BL8AJx4jvw 

 
学习更多dpdk视频
Dpdk/网络协议栈/ vpp /OvS/DDos/NFV/虚拟化/高性能专家 学习地址: https://ke.qq.com/course/5066203?flowToken=1043799
DPDK开发学习资料和学习路线图分享有需要的可以自行添加学习交流q 君羊909332607备注(XMG) 获取

猜你喜欢

转载自blog.csdn.net/weixin_60043341/article/details/126608109