内存访问监控
1. 概述
通过对进程内存访问数据采样,计算进程对remote内存访问产生的带宽流量来间接推断跨numa访问的严重程度,从而实现带宽感知调度决策、RTD间调度优化,并向带宽分配功能提供反馈,从而实现对内存带宽的控制
2. 硬件方案
2.1 cpu支持
- Intel RDT
- https://cloud-atlas.readthedocs.io/zh-cn/latest/kernel/cpu/intel/intel_rdt/intel_rdt_arch.html
- https://www.intel.cn/content/www/cn/zh/content-details/851356/intel-resource-director-technology-intel-rdt-architecture-specification.html
- https://eci.intel.com/docs/3.0/development/intel-pqos.html
- AMD PQos(与RDT对等的)
- 海光类似AMD,我在机器上看也是有相关cpu feature的
- 鲲鹏 PMU,应该也是支持这个内存访问采样的,他们有提供对应的用户态库。但是对跨numa内存访问的功能似乎不能指定进程进行才采样
- arm MPAM(Memmory Partitioning and Monitoring)
2.2 内核resctrl支持
2.2.1 概述
概述: resctrl问津啊系统通过sysfs暴露给用户态,能够在用户态使用这些接口文件。此功能需要开启CONFIG_X86_CPU_RESCTRL编译配置
cpuinfo flag:
| 特性 | flag |
|---|---|
| RDT(Resource Director Technology) Allocation | rdt_a |
| CAT(Cache Allocation Technology) | cat_l3、cat_l2 |
| CDP(Code and Data Prioritization) | cdp_l3、cdp_l2 |
| CQM(Cache QoS Monitoring) | cqm_llc、cqm_occup_llc |
| MBM(Memory Bandwidth Monitoring)【采样内存访问所需的特性】 | cqm_mbm_total、cqm_mbm_local |
| MBA(Memory Bandwidth Allocation) | Mba |
| SMBA(Slow Memory Bandwidth Allocation) | |
| BMEC(Bandwidth Monitoring Event Configuration) | |
| ABMC(Assignable Bandwidth Monitoring Counters) |
每个接口文件的详细介绍看linux doc: https://docs.kernel.org/filesystems/resctrl.html
arm MAPM较新,内核支持的较晚,相关链接:
- 将x86/resctrl抽象为公共接口以便arm MPAM接入:https://lwn.net/Articles/1021264/
- arm mpam引入:https://lwn.net/Articles/1042576/
- arm MAPM介绍:https://developer.arm.com/documentation/108032/0100/A-closer-look-at-MPAM-software/Linux-MPAM-overview
2.2.2 使用
1. 使用此功能需要挂载该文件系统:
1 | |
2. 在mon_group下创建监控组:
1 | |
3. 设置要监控的cpu和进程:
1 | |
4. 查看内存访问数据量:
1 | |
如果cpu不属于这个L3 cache domain,读取这两个接口文件会返回Unavailable
想要知道cpu0跟哪些cpu共享L3 cache,可以执行cat /sys/devices/system/cpu/cpu0/cache/index3/shared_cpu_list,看其他cpu类似
5. 删除子group:
1 | |
2.3 用户态工具
2.3.1 pqos
2.3.1.1 编译安装
仓库代码: https://eci.intel.com/docs/3.0/development/intel-pqos.html
概述: 该工具可以不需要内核支持,直接使用CAT、CMT、MBM、CDP功能,直接访问msr寄存器。支持Intel RDT和AMD PQoS,我觉得海光cpu应该也是可以使用这个工具
1. 添加动态库链接目录:
1 | |
2. 修改lib/pqos.h的enum pqos_vendor,添加PQOS_VENDOR_HYGON
1 | |
3. 修改lib/cpuinfo.c的detect_vendor(),添加PQOS_VENDOR_HYGON的检测:
1 | |
4. 修改lib/cpuinfo.c的init_config(),添加对PQOS_VENDOR_HYGON的处理:
1 | |
5. 编译安装:
要求gcc 9及以上
1 | |
2.3.1.2 使用
MBM的使用方法: MBL表示本地内存带宽,MBR表示远程内存带宽
监控指定核心的内存带宽使用情况:
1
pqos -m 'mbl:cores;mbr:cores示例:
1
pqos -m 'mbl:1,3-4;mbr:1,3-4'输出示例如下:
1
2
3
4
5TIME 2019-05-07 08:01:16
CORE IPC MISSES MBL\[MB/s\] MBR\[MB/s\]
1 1.17 124254k 15161.8 0.1
3 1.54 38010k 4595.0 0.1
4 1.41 135584k 8210.6 0.2监控每个进程/任务的内存带宽使用情况:
1
pqos -I -p 'mbl:pids;mbr:pids'示例:
1
pqos -I -p 'mbl:65627;mbr:65627'
在海光cpu上的测试: 需要修改intel-cmt-cat源码使其支持海光cpu的vendor
执行测试程序:
1
taskset -c 4 memtester 1000M监控指定核心:
1
2
3pqos -I -p 'mbl:77614;mbr:77614'
pqos -I -p 'mbl:69943;mbr:69943'结果:

2.3.1.3 MBM监控结果说明
通过写入IA32_QM_EVTSEL MSR设置RMID和Event ID,硬件就会查看特定数据,并通过IA32_QM_CTR MSR返回结果。
MBM监控的是L3 cache到主内存的内存请求带宽
MBM计数器记录的值是累积值,cpu代理和非cpu代理发出的每个内存请求都会被应将标记上相应的RMID tag,硬件会根据这些RMID收集资源监控要遥测数据
pqos工具输出的结果是每秒读msr的值,然后跟上一秒读的值作差值算出带宽(pqos工具如果使用的是resctrl接口,会通过创建子group,如果是核心模式,指定多少个核心就创建多少个子group分别监控指定核心;如果是进程模式,就只创建一个,然后会累积所有L3 cache domain统计的内存访问带宽)
如果不想使用pqos工具,可以直接使用linux提供的resctrl接口。跟cgroup差不多,详见2.2 内核resctrl支持
2.3.2 鲲鹏libkperf库
2.3.3.1 PMU检查
应该是只要支持鲲鹏的PMU特性就可以使用该库,检查是否支持PMU:
1 | |
输入如下说明支持: 
如果如下,一些性能指标没有采集到说明不支持: 
2.3.3.2 使用
仓库代码: https://gitee.com/openeuler/libkperf.git
采集每个numa的跨nuam访问HHA的操作比例示例代码: 似乎是不能以进程为粒度的,而是以整个numa节点为粒度的
1 | |
详见:https://gitee.com/openeuler/libkperf/blob/master/docs/Details_Usage.md#%E9%87%87%E9%9B%86%E8%B7%A8numa%E8%B7%A8socket%E8%AE%BF%E9%97%AEhha%E6%AF%94%E4%BE%8B
标题是《采集跨numa/跨socket访问HHA比例》
2.3.3 perf mem
需要硬件支持:
- intel TPEBS
- AMD IBS Op
- Arm64 SPE
3. 软件方案
目前没有调研到纯软件来实现内存访问监控比较好的方法。似乎内核只能通过page fault来感知到内存访问,所以监控page fault是一个方法
- 使用内核提供的tracepoint事件追踪page fault
- 编写bpf程序,根据虚拟地址address转换为pfn,从pfn中获取struct page,然后获取page所属的nuam id,维护计数器统计该访问是本地访问还是远程访问(统计结果通过ebpf map传到用户态)
- 将page更新到epbf map中,然后用户态程序定义一个时间窗口,定时将这些page通过mprotect() syscall修改页面保护为PROT_NONE,则后面进程再次访问该page会触发page fault