DPDK内存管理-----(一)初始化

1 前言

DPDK通过使用hugetlbfs,减少CPU TLB表的Miss次数,提高性能。

2 初始化

DPDK的内存初始化工作,主要是将hugetlbfs的配置的大内存页,根据其映射的物理地址是否连续、属于哪个Socket等,有效的组织起来,为后续管理提供便利。

2.1 eal_hugepage_info_init()

eal_hugepage_info_init()主要是获取配置好的Hugetlbfs的相关信息,并将其保存在struct internal_config数据结构中。

主要工作如下:

  1、读取/sys/kernel/mm/hugepages目录下的各个子目录,通过判断目录名称中包含"hugepages-"字符串,获取hugetlbfs的相关子目录,并获取hugetlbfs配置的内存页大小。例如:  

  [[email protected]_DEFAULT ~]# ls -ltr /sys/kernel/mm/hugepages/  total 0  drwxr-xr-x 2 root root 0 2014-11-04 15:54 hugepages-2048kB

  2、通过读取/proc/mounts信息,找到hugetlbfs的挂载点。例如:    

  [email protected]:~# cat /proc/mounts   rootfs / rootfs rw 0 0  sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0  proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0  udev /dev devtmpfs rw,relatime,size=1016836k,nr_inodes=254209,mode=755 0 0  devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000 0 0  tmpfs /run tmpfs rw,nosuid,noexec,relatime,size=205128k,mode=755 0 0  /dev/disk/by-uuid/fd1dbca3-ac30-4bac-b93a-0d89b0fd152c / ext4 rw,relatime,errors=remount-ro,user_xattr,barrier=1,data=ordered 0 0  none /sys/fs/fuse/connections fusectl rw,relatime 0 0  none /sys/kernel/debug debugfs rw,relatime 0 0  none /sys/kernel/security securityfs rw,relatime 0 0  none /run/lock tmpfs rw,nosuid,nodev,noexec,relatime,size=5120k 0 0  none /run/shm tmpfs rw,nosuid,nodev,relatime 0 0  none /media/sf_F_DRIVE vboxsf rw,nodev,relatime 0 0  gvfs-fuse-daemon /home/chuanxinji/.gvfs fuse.gvfs-fuse-daemon rw,nosuid,nodev,relatime,user_id=1000,group_id=1000 0 0  /dev/sr0 /media/VBOXADDITIONS_4.3.10_93012 iso9660 ro,nosuid,nodev,relatime,uid=1000,gid=1000,iocharset=utf8,mode=0400,dmode=0500 0 0  none /mnt/huge hugetlbfs rw,relatime 0 0  [email protected]:~#

  3、通过读取/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages,获取配置的hugepages个数。

  [email protected]:~# cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages  64  [email protected]:~#

  4、以打开文件的方式,打开挂载点目录,为其FD设置互斥锁,Why??

上述所有获取的信息,都保存在internal_config.hugepage_info[MAX_HUGEPAGES_SIZE]中,hugepage_info数据结构如下:

1 struct hugepage_info {
2   size_t hugepage_sz; /**< size of a huge page */
3   const char *hugedir; /**< dir where hugetlbfs is mounted */
4   uint32_t num_pages[RTE_MAX_NUMA_NODES];
5   /**< number of hugepages of that size on each socket */
6   int lock_descriptor; /**< file descriptor for hugepage dir */
7 };

  具体赋值如下,

  hpi->hugepage_sz = 2M;
  hpi->hugedir = /mnt/huge;
  hpi->num_pages[0] = 64; // 由于此时还不知道哪些内存页分处在哪个socket上,故,都先放在socket-0上。
  hpi->lock_descriptor = open(hpi->hugedir, O_RONLY);

  5、将internal_config.hugepage_info[MAX_HUGEPAGES_SIZE]按内存页的大小排序。

2.2 rte_eal_config_create()

rte_eal_config_create()主要是初始化rte_config.mem_config。如果是以root用户运行dpdk程序的话,rte_config.mem_config指向/var/run/.rte_config文件mmap的一段sizeof(struct rte_mem_config)大小的内存。

rte_config.mem_config = /var/run/.rte_config文件mmap的首地址;

1 struct rte_config {
2     uint32_t master_lcore;       /**< Id of the master lcore */
3
4         ... ...
5
6     struct rte_mem_config *mem_config;
7 } __attribute__((__packed__));

struct rte_mem_config数据结构如下:

 1 struct rte_mem_config {
 2     volatile uint32_t magic;   /**< Magic number - Sanity check. */
 3
 4     /* memory topology */
 5     uint32_t nchannel;    /**< Number of channels (0 if unknown). */
 6     uint32_t nrank;       /**< Number of ranks (0 if unknown). */
 7
 8     /**
 9      * current lock nest order
10      *  - qlock->mlock (ring/hash/lpm)
11      *  - mplock->qlock->mlock (mempool)
12      * Notice:
13      *  *ALWAYS* obtain qlock first if having to obtain both qlock and mlock
14      */
15     rte_rwlock_t mlock;   /**< only used by memzone LIB for thread-safe. */
16     rte_rwlock_t qlock;   /**< used for tailq operation for thread safe. */
17     rte_rwlock_t mplock;  /**< only used by mempool LIB for thread-safe. */
18
19     uint32_t memzone_idx; /**< Index of memzone */
20
21     /* memory segments and zones */
22     struct rte_memseg memseg[RTE_MAX_MEMSEG];    /**< Physmem descriptors. */
23     struct rte_memzone memzone[RTE_MAX_MEMZONE]; /**< Memzone descriptors. */
24
25     /* Runtime Physmem descriptors. */
26     struct rte_memseg free_memseg[RTE_MAX_MEMSEG];
27
28     struct rte_tailq_head tailq_head[RTE_MAX_TAILQ]; /**< Tailqs for objects */
29
30     /* Heaps of Malloc per socket */
31     struct malloc_heap malloc_heaps[RTE_MAX_NUMA_NODES];
32 } __attribute__((__packed__));

2.3 rte_eal_hugepage_init()

rte_eal_hugepage_init()主要是在/mnt/huge目录下创建hugetlbfs配置的内存页数(在本文中就是64)的rtemap_xx文件,并为每个rtemap_xx文件做mmap映射,保证mmap后的虚拟地址与实际的物理地址是一样的。

具体如下:

1、创建nr_hugepages个struct hugepage_file数组,即有多少个内存页,创建多少个struct hugepage_file数据结构。struct hugepage_file数据结构如下:

 1 struct hugepage_file {
 2     void *orig_va;      /**< virtual addr of first mmap() */
 3     void *final_va;     /**< virtual addr of 2nd mmap() */
 4     uint64_t physaddr;  /**< physical addr */
 5     size_t size;        /**< the page size */
 6     int socket_id;      /**< NUMA socket ID */
 7     int file_id;        /**< the ‘%d‘ in HUGEFILE_FMT */
 8     int memseg_id;      /**< the memory segment to which page belongs */
 9 #ifdef RTE_EAL_SINGLE_FILE_SEGMENTS
10     int repeated;       /**< number of times the page size is repeated */
11 #endif
12     char filepath[MAX_HUGEPAGE_PATH]; /**< path to backing file on filesystem */
13 };

2、有多少个内存页,在挂载点目录下创建多少个rtemap_xx文件,如下所示,并为每一个文件mmap一个hugepage_sz大小的内存区域。其中,

     hugepage_file->orig_va = 记录每个rtemap_xx文件mmap的首地址;

     hugepage_file->file_id = 创建的rtemap_xx的顺序,就是xx的值;

     hugepage_file->filepath = /mnt/huge/rtemap_xx;

     hugepage_file->size = hugepage_sz,也就是2M;

     [email protected]:~# ls -tlr /mnt/huge/	total 131072	-rwxr-xr-x 1 root root 2097152 Nov  5 14:53 rtemap_2	-rwxr-xr-x 1 root root 2097152 Nov  5 14:53 rtemap_1	-rwxr-xr-x 1 root root 2097152 Nov  5 14:53 rtemap_0	-rwxr-xr-x 1 root root 2097152 Nov  5 14:53 rtemap_8	-rwxr-xr-x 1 root root 2097152 Nov  5 14:53 rtemap_7	-rwxr-xr-x 1 root root 2097152 Nov  5 14:53 rtemap_6

              ... ...

	-rwxr-xr-x 1 root root 2097152 Nov  5 14:53 rtemap_60	-rwxr-xr-x 1 root root 2097152 Nov  5 14:53 rtemap_59	-rwxr-xr-x 1 root root 2097152 Nov  5 14:53 rtemap_58	-rwxr-xr-x 1 root root 2097152 Nov  5 14:53 rtemap_63	-rwxr-xr-x 1 root root 2097152 Nov  5 14:53 rtemap_62	-rwxr-xr-x 1 root root 2097152 Nov  5 14:53 rtemap_61	[email protected]:~# 

3、通过读取/proc/self/pagemap页表文件,得到本进程中虚拟地址与物理地址的映射关系。使用上一步中,每个rtemap_xx文件mmap得到的虚拟地址,除以操作系统内存页的大小4k,得到一个偏移量。根据这个偏移量,在/prox/self/pagemap中,得到物理地址的页框,假设为page,那么,物理页框page乘以操作系统内存页的大小4K,再加上虚拟地址的页偏移,就是物理地址。每个rtemap_xx映射的物理地址保存在对应的hugepage_file->physaddr中。

1 physaddr = ((page & 0x7fffffffffffffULL) * page_size) + ((unsigned long)virtaddr % page_size);

4、读取/proc/self/numa_maps,得到每个rtemap_xx文件mmap得到的虚拟地址在哪个Socket上,即,哪个CPU上。其socketid保存在对应的hugepage_file->socket_id中。

[email protected]:~# cat /proc/self/numa_maps 00400000 default file=/bin/cat mapped=7 mapmax=2 N0=70060a000 default file=/bin/cat anon=1 dirty=1 N0=10060b000 default file=/bin/cat anon=1 dirty=1 N0=1025c1000 default heap anon=3 dirty=3 active=0 N0=37fdf0222c000 default file=/usr/lib/locale/locale-archive mapped=10 mapmax=61 N0=107fdf0290f000 default file=/lib/x86_64-linux-gnu/libc-2.15.so mapped=82 mapmax=128 N0=827fdf02ac4000 default file=/lib/x86_64-linux-gnu/libc-2.15.so7fdf02cc3000 default file=/lib/x86_64-linux-gnu/libc-2.15.so anon=4 dirty=4 N0=47fdf02cc7000 default file=/lib/x86_64-linux-gnu/libc-2.15.so anon=2 dirty=2 N0=27fdf02cc9000 default anon=3 dirty=3 active=1 N0=37fdf02cce000 default file=/lib/x86_64-linux-gnu/ld-2.15.so mapped=27 mapmax=122 N0=277fdf02ed7000 default anon=3 dirty=3 N0=37fdf02eee000 default anon=2 dirty=2 N0=27fdf02ef0000 default file=/lib/x86_64-linux-gnu/ld-2.15.so anon=1 dirty=1 N0=17fdf02ef1000 default file=/lib/x86_64-linux-gnu/ld-2.15.so anon=2 dirty=2 N0=27fff09be1000 default stack anon=3 dirty=3 N0=37fff09cc2000 default[email protected]:~#

5、在hugepage_file数组中,根据物理地址,按从小到大的顺序,将hugepage_file排序。

6、根据按物理地址排序后的结果,判断物理地址是否连续,重新mmap /mnt/huge/retmap_xx文件,使得物理地址等于第二次mmap后的虚拟地址。第二次mmap得到的虚拟地址保存在对应的hugepage_file->final_va中。

7、munmap释放第一步中各个rtemap_xx文件首次mmap得到的内存地址。

8、计算每个socket上包含多少个hugepage,信息保存在internal_config.hugepage_info[0].num_pages[socket]中。

9、calc_num_pages_per_socket(),目的是什么???

10、为/var/run/.rte_hugepage_info文件mmap一段nr_hugepages * sizeof(struct hugepage_file)大小的内存块,并将第一步中创建的hugepage_file数组中的所有内容,都copy到这一块内存中。

11、rte_config.mem_config->memseg[]数组记录创建的hugepage_file的物理地址是连续的,hugepage_file->memseg_id为该huepage_file的物理地址在哪个rte_config.mem_config->memseg[]数组中。

2.4 rte_eal_memzone_init()

rte_eal_memzone_init()主要负责初始化rte_config.mem_config->free_memseg[]及rte_config.mem_config->memzone[]。其中,rte_config.mem_config->free_memseg[]记录空闲的rte_config.mem_config->memseg[]。

时间: 2024-11-01 16:16:43

DPDK内存管理-----(一)初始化的相关文章

[转]dpdk内存管理

转自 dpdk内存管理 --初始化(hugepage)    https://www.cnblogs.com/MerlinJ/p/4074391.html dpdk内存管理--rte_mempool内存管理  https://www.cnblogs.com/MerlinJ/p/4081986.html dpdk内存管理-- rte_malloc内存管理   https://www.cnblogs.com/MerlinJ/p/4092432.html 原文地址:https://www.cnblog

启动期间的内存管理之初始化过程概述----Linux内存管理(九)

日期 内核版本 架构 作者 GitHub CSDN 2016-06-14 Linux-4.7 X86 & arm gatieme LinuxDeviceDrivers Linux内存管理 在内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换到保护模式, 然后内核才能检测到可用内存和寄存器. 而我们今天要讲的boot阶段就是系统初始化阶段使用的内存分配器. 1 前景回顾 1.1

DPDK内存管理(1)

1 前言 DPDK将利用hugepage预留的物理内存统一的组织管理起来,然后以库的方式对外提供使用的接口.下图展示了DPDK中内存有关的模块的相互关系. rte_eal            是统一的组织管理者(当然rte_eal不只是做内存的工作) rte_malloc       对外提供分配释放内存的API,分配的内存都是rte_eal中管理的内存 rte_ring          提供无锁队列,他之间使用了rte_eal管理的内存 rte_mempool  利用rte_eal中的内存

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

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的创建及使

DPDK内存管理(1)(转)

1 前言 DPDK将利用hugepage预留的物理内存统一的组织管理起来,然后以库的方式对外提供使用的接口.下图展示了DPDK中内存有关的模块的相互关系. rte_eal            是统一的组织管理者(当然rte_eal不只是做内存的工作) rte_malloc       对外提供分配释放内存的API,分配的内存都是rte_eal中管理的内存 rte_ring          提供无锁队列,他之间使用了rte_eal管理的内存 rte_mempool  利用rte_eal中的内存

DPDK内存管理-----(四)rte_mbuf

本文主要介绍rte_mbuf与rte_mempool数据结构之间的组织关系.以及网卡接收到的数据是如何存储在rte_mbuf中的. 一.rte_mbuf.rte_mempool及网卡收到的数据包在内存中的组织结构 调用rte_mempool_create()函数创建rte_mempool的时候,指定申请多少个rte_mbuff及每个rte_mbuf中elt_size的大小.elt_size是为网卡接收的数据包预先分配的内存的大小,该内存块就是rte_mbuf->pkt.data的实际存储区域.具

DPDK内存管理-----(三)rte_malloc内存管理

rte_malloc()为程序运行过程中分配内存,模拟从堆中动态分配内存空间. 1 void * 2 rte_malloc(const char *type, size_t size, unsigned align) 3 { 4 return rte_malloc_socket(type, size, align, SOCKET_ID_ANY); 5 } rte_malloc()函数调用关系如下图: rte_malloc_socket():指定从哪个socket上分配内存空间,默认是指定SOCK

内存管理初始化源码2:setup_arch

PFN相关宏说明: /* kernel/include/linux/pfn.h */ PFN : Page Frame Number(物理页帧) /* * PFN_ALIGN:返回地址x所在那一页帧的下一页帧的起始地址. * 例如:PFN_ALIGN(0x00000800) = 0x00001000 : PFN_ALIGN(0x00001800) = 0x00002000; * 理解:假如我们认为一页大小是0x0f,那么当前地址是0x08,如何通过0x08获得0x10呢? 0x08 + (0x1

Linux0.11内核--内存管理之1.初始化

[版权所有,转载请注明出处.出处:http://www.cnblogs.com/joey-hua/p/5597705.html ] Linux内核因为使用了内存分页机制,所以相对来说好理解些.因为内存分页就是为了方便管理内存. 说到内存分页,最根部的要属页目录表了,head.h中: extern unsigned long pg_dir[1024]; // 内存页目录数组.每个目录项为4 字节.从物理地址0 开始. 然后再看head.s: /* * head.s 含有32 位启动代码. * 注意