如何在程序运行时获取 dpdk-16.04 大页使用情况?
前言
基于 dpdk-16.04 开发的 dpdk 程序需要使用的大页内存总大小可以通过计算得出,但由于 dpdk-16.04 legacy memory 模型只支持物理地址连续的 segment 内存分配方式,在系统启动后再动态设置大页时,物理地址相对离散,则没有较大的 memseg 来分配。
这样如果要分配一块非常大的空间,尽管小于总的大页内存空间,仍有可能因为最大的 memseg 大小不足而分配失败。
为了解决这个问题,大页的预留方式可以修改为通过内核启动参数配置预留。这种方式只能让大页内存的物理地址相较系统启动后分配相对集中,但常常还是需要分配更多的大页来增大单个 segment 能够分配的最大空间。
而当大页内存预留后其它程序能够使用的内存空间减少,大页的数量分配不合理就会造成内存浪费。如果有一种方式能够在运行时观测 dpdk 内部大页的使用情况,并找到最大的 memseg 空间,也许就可以适当减少大页的数量,为其它进程留出更多的内存、使用更少的内存条。
如何在 dpdk 程序运行时获取大页使用情况?
在 lib/librte_eal/common/malloc_heap.c 文件中有如下函数:
int
malloc_heap_get_stats(const struct malloc_heap *heap,struct rte_malloc_socket_stats *socket_stats)
{size_t idx;struct malloc_elem *elem;/* Initialise variables for heap */socket_stats->free_count = 0;socket_stats->heap_freesz_bytes = 0;socket_stats->greatest_free_size = 0;/* Iterate through free list */for (idx = 0; idx < RTE_HEAP_NUM_FREELISTS; idx++) {for (elem = LIST_FIRST(&heap->free_head[idx]);!!elem; elem = LIST_NEXT(elem, free_list)){socket_stats->free_count++;socket_stats->heap_freesz_bytes += elem->size;if (elem->size > socket_stats->greatest_free_size)socket_stats->greatest_free_size = elem->size;}}/* Get stats on overall heap and allocated memory on this heap */socket_stats->heap_totalsz_bytes = heap->total_size;socket_stats->heap_allocsz_bytes = (socket_stats->heap_totalsz_bytes -socket_stats->heap_freesz_bytes);socket_stats->alloc_count = heap->alloc_count;return 0;
}
此函数遍历指定的 malloc_heap 上的 free_list 来 dump 空闲空间及最大可分配的空间,可以在外部程序中调用此函数来 dump 信息。dpdk 中每一个 numa 节点的大页内存都会分配一个 malloc_heap 结构,此结构保存在 rte_config 共享内存中,可以获取到 rte_config 的内容,遍历每一个 malloc_heap 结构,调用 malloc_heap_get_stats 来获取大页的使用数据。
测试方法
修改 l2fwd 程序源码,在 dpdk rte_eal_init 初始化后执行 pause 暂停。同时修改 proc_info 代码,在调用 mem_display 前按照上文描述的方法调用 malloc_heap_get_stats 函数 dump 信息。
先运行 l2fwd 程序,然后运行 proc_info 程序观测大页内存内部使用情况。
测试记录
在系统开机后设置 49 个 2M 大页(都在 numa 0 上),当 l2fwd 运行后,添加 -m 参数运行 proc_info 程序,终端输出信息部分摘录如下:
numa 0 biggest_free_size is 6291392
numa 0 total_len is 102757824 byte, free_size is 100086528 byte
numa 0 total_len is 97m, free_size is 95m
----------- MEMORY_SEGMENTS -----------
Segment 0: phys:0x71c00000, len:2097152, virt:0x7fec3e000000, socket_id:0, hugepage_sz:2097152, nchannel:0, nrank:0
Segment 1: phys:0x74400000, len:4194304, virt:0x7fec3da00000, socket_id:0, hugepage_sz:2097152, nchannel:0, nrank:0
Segment 2: phys:0x75000000, len:2097152, virt:0x7fec3d600000, socket_id:0, hugepage_sz:2097152, nchannel:0, nrank:0
Segment 3: phys:0x75800000, len:2097152, virt:0x7fec3d200000, socket_id:0, hugepage_sz:2097152, nchannel:0, nrank:0
Segment 4: phys:0x75c00000, len:4194304, virt:0x7fec3cc00000, socket_id:0, hugepage_sz:2097152, nchannel:0, nrank:0
Segment 5: phys:0x76400000, len:2097152, virt:0x7fec3c800000, socket_id:0, hugepage_sz:2097152, nchannel:0, nrank:0
Segment 6: phys:0x76e00000, len:2097152, virt:0x7fec3c400000, socket_id:0, hugepage_sz:2097152, nchannel:0, nrank:0
Segment 7: phys:0x77400000, len:2097152, virt:0x7fec3c000000, socket_id:0, hugepage_sz:2097152, nchannel:0, nrank:0
Segment 8: phys:0x77e00000, len:2097152, virt:0x7fec3bc00000, socket_id:0, hugepage_sz:2097152, nchannel:0, nrank:0
Segment 9: phys:0x78c00000, len:4194304, virt:0x7fec3b600000, socket_id:0, hugepage_sz:2097152, nchannel:0, nrank:0
Segment 10: phys:0x79400000, len:4194304, virt:0x7fec3b000000, socket_id:0, hugepage_sz:2097152, nchannel:0, nrank:0
Segment 11: phys:0x79a00000, len:6291456, virt:0x7fec3a800000, socket_id:0, hugepage_sz:2097152, nchannel:0, nrank:0
....................................................................................................................
最大的 free 空间为 6291392(内部数据占了一部分空间,故而小于 6291456),尽管总共有 98M 大页内存能够使用,但由于单次分配的内存必须物理空间连续(位于一个 segment),则最大分配 6291392(5.9M) 空间,说明此时物理内存已经非常离散。
总结
dpdk legacy 内存模型实现有些简陋,按照一般的思路,总的内存足够应该就能够分配出需要的空间,然而在 dpdk legacy 内存模型下却会受限于单块连续物理内存的最大值,使用内核启动参数预留内存算是一种规避方法,最好还是更新 dpdk 版本,新的内存模型已经解决了这一问题。
如何在程序运行时获取 dpdk-16.04 大页使用情况?相关推荐
- 【解决】Python程序运行时所占内存越来越大
1.问题描述 最近在用Python(Pyqt5)编写一个可以获取gpu信息(功耗.显存占用.利用率等)并将这些信息保存成csv文件的程序.在程序编写完成后,运行时却发现,随着程序的运行,所占用的内存每 ...
- java 程序运行时注入方法_Spring入门(九):运行时值注入
Spring提供了2种方式在运行时注入值: 属性占位符(Property placeholder) Spring表达式语言(SpEL) 1. 属性占位符 1.1 注入外部的值 1.1.1 使用Envi ...
- error C2057: expected constant expression (C语言中数组的大小可以在程序运行时定义吗? )
数组的大小可以在程序运行时定义吗? 不.在数组的定义中,数组的大小必须是编译时可知的,不能是在程序运行时才可知的.例如,假设i是一个变量,你就不能用i去定义一个数组的大小: char array[i] ...
- Delphi-TScreen表示应用程序运行时屏幕的状态
TScreen表示应用程序运行时屏幕的状态. 类关系 TObject->TPersistent->TComponent TScreen引进具有表示下列各种情况的属性 什么窗体和数据模块已经 ...
- gettype获取类名_在TypeScript中运行时获取对象的类名
在TypeScript中运行时获取对象的类名 是否可以使用typescript在运行时获取对象的类/类型名称? class MyClass{} var instance = new MyClass() ...
- springboot_通过Actuator了解应用程序运行时的内部状况
Actuator 的端点 Spring Boot Actuator的关键特性是在应用程序里提供众多Web端点,可以分为三大类:配置端点.度量端点和其他端点.通过它们了解应用程序运行时的内部状况.有了A ...
- java hibernate方言_java – 如何在运行时获取Hibernate方言
在我的应用程序中,我使用Hibernate与SQL Server数据库,所以我设置 在我的persistence.xml中. 在某些情况下,我想用NULL包括排序记录,我使用关键字NULLS FIRS ...
- java 获取运行时参数,Java8增强反射可以在运行时获取参数名
技术公众号:Java In Mind(Java_In_Mind),欢迎关注! 原文:Java8增强反射可以在运行时获取参数名 介绍 在JDK增强意见:JPE 118:Access to Paramet ...
- C语言编程练习 2.编写人得票统计程序。设有3个候选人,每次输入一个得票候选人的名字,不考虑弃权情况,要求最后输出各个候选人的得票结果(参加投票人数由程序运行时输入)。
题目完整描述 编写人得票统计程序.设有3个候选人,每次输入一个得票候选人的名字,不考虑弃权情况,要求最后输出各个候选人的得票结果(参加投票人数由程序运行时输入). 这是一道关于 一维数组做函数参数 的 ...
最新文章
- 【洛谷P1816 忠诚】线段树
- ubuntu16.4中创建帐户
- 常见架构TLB miss处理方法(转)
- Fiddler抓取https相关设置
- 219. 单页应用 会话管理(session、cookie、jwt)
- 这个 HTTP 实战项目,帮你理清 Go 网络编程的底层逻辑
- 微信填写服务器配置 php操作方法
- WCF系统内置绑定列表与系统绑定所支持的功能
- 利用百度地图API,在浏览器中找到自己的位置
- win10系统如何查询本机的IP地址和外网IP地址
- Linux(CentOS7)中如何安装QQ
- 转:性、恐惧、爱、信念,管理者一生都逃不掉的课题
- Windows快捷键小记
- 键盘记录工具(支持中文)
- 抖音推荐算法!(教你如何上热门)
- OPPO AI Lab 核心岗位开放招聘:至美之路,等你加入!
- 谁来教我渗透测试——黑客必须掌握的Linux基础
- 《大学章句集注》-读书笔记之一
- MTK平台双卡区分SIM卡1和SIM卡2来电通知
- Linux快捷键汇总(持续更新)
热门文章
- Oracle 12C OUI安装
- PS 的打开文件和自由变换
- Cause: java.sql.SQLSyntaxErrorException: ORA-00911: 无效字符
- 磁珠Ferrite Bead 与电感inductance 的区别
- JavaScript:实现QuickSelectSearch快速选择搜索算法(附完整源码)
- 计算机组装实训台,计算机组装
- 你知道电源内部是怎么工作的吗
- 使用jsoup获取微信公众号文章发布时间
- APC新一代英飞集成系统 “智”关重要
- CAD中的各种Polyline