需求
现代服务器上运行多个用户的多个程序,硬件资源是共享的。我们可以通过类似cgroup的技
术对共享的硬件资源做调控,比如cgroup可以调控CPU和内存等资源。但是诸如cache使用、
内存带宽使用,软件难以直接做调控,这就需要引入新硬件,软件通过新硬件提供的接口做
资源调控。ARM上引入MPAM(memory partition and monitor)对内存相关的资源做控制和监
测。
对应的内存相关资源有:1. cache;2. 内部总线;3. 内存。控制的角度有使用大小和优先
级等。
概念和模型
MPAM使用一个全局唯一的三元组标记每个内存访问的源头,对于PE,这些信息需要配置到
MPAMx_ELn相关系统寄存器里,可以看到如果partition ID的语意就是PE本身,配置一次就
好,如果partition ID表示线程,就需要在线程切换的时候更新这个配置。在cache/内存控制器/
SMMU上增加MPAM控制节点(MSC(memory system compoment)),节点提供MMIO寄存器接口,这
些接口接受三元组的资源控制和监控的配置。相关配置提前配置好,系统运行的时候,访问
cache或者内存的请求根据提前配置的信息进行资源控制和监控。
三元组的三个元素是:partition ID space,partition ID,PMG(performance monitor group)。
partition ID space是安全态,主要用partition ID区分资源类型,PMG用来聚集一组监测
资源。MSC集成在各个内存相关的部件里,由专门的ACPI或者DTS MPAM表格报给OS。(todo)
MPAM协议里还定义了一些MPAM内部传递控制信息的概念(第四章),感觉这些概念以及相关的
部件是软件较少感知的。
MPAM协议里简单描述了下硬件内部partitioning control的逻辑,简单讲就是当前使用的资
源和提前配置好的资源不断的做比较,如果还有余量就给分资源,反之就不给分资源。更近
一步看,capacity-based partitioning才需要这种动态调整,portion-based partitioning
(比如,直接配置可以用哪几个cache way的情况)的调整逻辑就可以比较简单。可以看到硬件
内部会用表格记录各种资源配置,如果这个表格在硬件内部,那么这个部件在使用中有低功
耗的上下电动作时,这些内容都要做保存和恢复。
MPAM只有两种类型中断:1. 报告错误的中断;2. monitor计数溢出中断。
MPAM的软硬件接口寄存器大致分为四类:ID寄存器,系统寄存器,control相关寄存器和monitor
相关的寄存器。ID寄存器配置MPAM MSC的各种规格,系统寄存器配置从流量源头带上的partition
ID和PMG。
注意,现代处理器实现都采用流水线技术,在单点控制相当于控制流水线中的一个点,容易
引发系统问题。另外,一旦系统里有共享部件,硬件逻辑综合起来就容易冲突,也可能引发
问题。
ID和系统寄存器
系统寄存器就是如上提到的:MPAMx_ELn
ID寄存器整理如下:
1 2 3 4 5 6 7 8 9 10
| MPAMF_AIDR 版本信息 MPAMF_IIDR 厂商信息 MPAMF_IMPL_IDR 自定义特性信息 MPAMF_SIDR 安全相关特性支持情况
MPAMF_IDR 特性总体支持信息 MPAMF_CCAP/CPOR/CSUMON_IDR cache相关信息 MPAMF_MBW/MBWUMON_IDR memory相关信息 MPAMF_PRI_IDR 优先级相关信息 MPAMF_PARTID_NRW_IDR partition ID narrow相关信息
|
resource partitioning control
软件需要配置MSC上各种资源的配置,这些配置用partition ID和RIS做标记。一个MSC上可能
同时支持多种不同类型的控制和监控,比如,同时支持memory和cache,RIS(resource instance
selection)就是对支持类型的标记。
软件需要用MPAMCFG_PART_SEL选择当前要配置的partition ID和RIS,然后配置对应的寄存,
配置选中partition ID和RIS对应的资源限制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| MPAMCFG_PART_SEL 配置partition ID和RIS
MPAMCFG_CASSOC Cache Maximum Associativity Partition MPAMCFG_CMAX Cache Maximum Capacity Partition 配置cache使用的最大百分比 MPAMCFG_CMIN Cache Minimum Capacity Partition 配置cache使用的最小百分比, 小于这个百分比的partition ID的优先级被提高,优先分cache。 MPAMCFG_CPBM<n> Cache Portion Bitmap Partition 按照portion的配置寄存器。配置的方式: 1. 最大bit数,2. select出要配置的partition ID,3. 执行配置。
MPAMCFG_MBW_MAX Memory Bandwidth Maximum Partition MPAMCFG_MBW_MIN Memory Bandwidth Minimum Partition MPAMCFG_MBW_PBM<n> Bandwidth Portion Bitmap Partition MPAMCFG_MBW_PROP Memory Bandwidth Proportional Stride Partition MPAMCFG_MBW_WINWD Memory Bandwidth Partitioning Window Width
MPAMCFG_PRI Priority Partition todo: 怎么搞的优先级?
|
resource monitor
一个MSC上可能既有cache又有内存的monitor,相同种类里需要监控的partid和PMG又不一样,
对于某个type,特定partid和PMG的监控,需要先配置对应的监控控制寄存器,然后从对应的
counter里读监控得到的数据。
每个MSC中,某种类型实际的monitor counter又可以有多个。这个配置可以在对应的ID寄存器
里查到,比如memory的MPAMF_MBWUMON_IDR.NUM_NON定义这个MSC有多少个内部的counter,
MPAM里叫做monitor instance。
MPAM定义了一组控制寄存器和一个counter对外接口。所以,对于一个MSC,对于每个type,
每个instance,软件要先通过这些控制寄存器选择要配置的具体type/instance/partid+PMG,
再进行配置,或者读counter信息。
比如,先配置MSMON_CFG_MON_SEL.RIS选择type,MSMON_CFG_MON_SEL.MON_SEL选择instance,
MSMON_CFG_MBWU_FLT.PARTID/PMG选择partid+PMG。然后配置MSMON_CFG_MBWU_CTL启动对应
的监控行为,读MSMON_MBWU得到监控数据。
寄存器的具体定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| MSMON_CFG_MON_SEL monitor选择寄存器,MON_SEL选择instance,RIS选择type
MSMON_CAPT_EVNT 提供了一个软件控制接口把counter里的值保存到CAPTURE寄存 器里,写NOW触发这个保存动作。通过如下CTL寄存器可以配置
MSMON_CSU_CAPTURE 上次capture事件保存的cache使用量 MSMON_MBWU_CAPTURE 上次capture事件保存的带宽使用量 MSMON_MBWU_L_CAPTURE MBWU长counter capture值
MSMON_CFG_CSU_CTL CSU控制寄存器,TYPE配置触发capture的源头,写如上NOW是其中一种 PARTID/PMG过滤使能,EN使能monitor MSMON_CFG_CSU_FLT CSU过滤寄存器,PARTID/PMG配置要过滤的参数,XCL配置是否只记录被修改的cache line MSMON_CFG_MBWU_CTL MBWU控制寄存器,TYPE语义如上,各种overflow标记,EN使能monitor MSMON_CFG_MBWU_FLT MBWU过滤寄存器,PARTID/PMG语义如上,RWBW配置过滤只读/只写/读写
MSMON_CSU CSU counter,VALUE为cache使用量,NRDY指示数据是否就绪 MSMON_MBWU MBWU counter(31位),VALUE为带宽使用量,NRDY语义如上 MSMON_MBWU_L MBWU长counter(44/63位),用于长时间监控减少溢出,L_NRDY语义如上
MSMON_OFLOW_MSI_ADDR_L/H 溢出中断MSI地址 MSMON_OFLOW_MSI_ATTR MSI属性配置 MSMON_OFLOW_MSI_DATA MSI数据 MSMON_OFLOW_MSI_MPAM MSI MPAM标识 MSMON_OFLOW_MSI_SR MSI状态寄存器
|
todo: PMG怎么配置?1. 硬件上是怎么过滤的partid和PMG都一样才能过滤。2. resctrl
怎么配置过滤多个对象。
SMMU MPAM
SMMU上只是配置partid,联合内存或者cache上的控制单元实现内存或者cache资源的控制。
SMMU上的STE/CD可以看作是具体外设在SMMU上的代理,所以对一个具体的外设只需要把partid
配置到SMMU上即可。
Partid Narrow
所谓Partid Narrow是进入MSC的partid可以通过提前配置好的映射被映射成另外一个partid,
后面的控制和检测都基于新的partid。
todo: 创建/配置/查询,主要使用场景。
MPAM虚拟化
- partition ID预留,2. 虚拟物理partition ID映射,3. MSC模拟。
Linux软件接口
Intel最早实现了MPAM类似的功能(RDT),软件上用一个独立的文件系统resctrl向外导出使用接口。
文件系统层次结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| /sys/fs/resctrl/ ├── cpus # 整个resctrl系统的CPU列表 ├── cpus_list # 人类可读的CPU列表格式 ├── mon_groups/ # 监控组目录 ├── info/ # 系统资源信息 │ ├── L3/ │ │ ├── cbm_mask │ │ ├── min_cbm_bits │ │ ├── num_closids │ │ └── shareable_bits │ ├── MB/ │ │ ├── bandwidth_gran │ │ ├── delay_linear │ │ └── min_bandwidth │ └── last_cmd_status # 最后一次命令执行状态 ├── mon_data/ # 根控制组的监控数据 │ ├── mon_L3_00/ │ │ ├── llc_occupancy │ │ ├── mbm_total_bytes │ │ └── mbm_local_bytes │ └── ... ├── schemata # 资源分配方案 ├── size # 根控制组的缓存大小 ├── tasks # 根控制组的进程列表 ├── <用户创建的目录>/ # 用户自定义控制组 │ ├── cpus │ ├── cpus_list │ ├── schemata │ ├── size │ ├── mon_groups/ # 该控制组的监控组 │ ├── mon_data/ # 该控制组的监控数据 │ └── tasks └── <mon_groups创建的目录>/ # 监控组目录 ├── mon_data/ # 监控组的具体监控数据 └── ... (AI生成)
|
resctrl使用层次化的结构控制资源,resctrl的根目录是全局资源,用户通过在resctrl
目录下创建目录,创建对应的控制组和监控组,可以看到在用户创建的目录下会新创建一整
套resctrl相关的控制和监控目录和文件。可以看到,用户创建的目录和对应的partition ID
对应起来,partition ID和CPU/线程的绑定关系通过配置cpus/cpus_list/tasks来实现。
控制组创建后,会在控制组目录自动生成监控组控制目录(mon_groups)和监控组数据目录
(mon_data)。需要手动在mon_group里创建自定义监控组,监控组监控的事件要如何配置? todo
Linux内核实现
MPAM对外使用resctrl文件系统作为接口。以openEuler v6.6内核为例,驱动代码在
drivers/platform/mpam/。这个驱动是一个平台设备驱动,但是但是真正probe的地方在注
册的cpu online的会调函数里。
核心数据结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| /* MPAM设备的分类,比如,cache/memory/IOMMU等 */ struct mpam_class +-> components list
/* 表示一个MSC设备 */ struct mpam_msc +-> ris list
/* 表示一个MSC上的一个resource type */ struct mpam_msc_ris
/* ? */ struct mpam_component +-> ris list
/* 和resctrl fs的交互的数据结构,怎么建立联系的?*/ struct mpam_resctrl_res
|
MSC设备解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| mpam_msc_drv_probe <-- probe以及创建MSC +-> acpi_mpam_parse_resources <-- 创建mpam_ris +-> mpam_ris_create +-> mpam_class_get <-- 如果还没有,就创建一个 /* * class和component_id为入参,对于cache是ACPI表中的cache_reference, * 对于memory是proximity_domain。所以compoment的语意是什么? * */ +-> mpam_component_get
mpam_discovery_cpu_online +-> mpam_msc_hw_probe <-- probe MSC硬件 /* work queue里执行 */ +-> mpam_resctrl_setup +-> mpam_resctrl_resource_init <-- 创建mpam_resctrl_res数组 +-> resctrl_init <-- 创建resctrl相关文件
|
resctrl文件创建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| /* fs/resctrl/rdtgroup.c */ resctrl_init +-> register_filesystem +-> rdt_init_fs_context /* 创建resctrl各个文件的逻辑在get_tree里 */ +-> rdt_fs_context_ops.get_tree
rdt_get_tree /* * 增加resctrl下创建/销毁目录的回调函数: rdtgroup_mkdir/rdtgroup_rmdir * * resctrl增加控制和监控项目的时候,需要在resctrl sysfs下新增目录,resctrl * 会在新增的目录中增加和顶层一样的目录和文件,相关代码逻辑就在rdtgroup_mkdir。 */ +-> rdtgroup_setup_root +-> rdt_enable_ctx +-> schemata_list_create +-> closid_init /* * resctrl把所有要增加的公共文件都定义在res_common_files数组里,每个文件一个 * 数组项,数组项中的fflags标记该文件增加到哪里。 */ +-> rdtgroup_add_files +-> rdtgroup_create_info_dir +-> mongroup_create_dir +-> mkdir_mondata_all
rdtgroup_mkdir +-> rdtgroup_mkdir_ctrl_mon +-> mkdir_rdt_prepare +-> rdtgroup_mkdir_mon
|
resctrl和驱动的接口似乎是直接arch实现函数调用的… 如此粗暴…
MPAM资源配置的一般逻辑是,用户已经知道整个系统的cache和memory相关控制节点的拓扑,
相关控制节点直接呈现在resctrl文件系统中。用户实际上通过resctrl把特性CPU或线程和
partid绑定,用户通过在各个控制节点上配置partid对应的控制和监控信息达到控制和监控
的功能。partid最终呈现对应的可能是一个个独立的目录。