1. 加权交错内存策略和sysfs文件系统扩展(weighted interleave mempolicy and sysfs extension)
1.1 重构一次读机制,以便支持可重入
[PATCH v5 0/4] mm/mempolicy: weighted interleave mempolicy and sysfs extension
强制policy->nodemask移到栈上,以便重入。
1.2 加权交错介绍( MPOL_WEIGHTED_INTERLEAVE)
[PATCH v5 0/4] mm/mempolicy: weighted interleave mempolicy and sysfs extension
当系统有多个NUMA(非一致性内存访问)节点,且 带宽匮乏(bandwidth hungry);那么使用加权交叉策略可能是一个明智的选择。然而,如果这些NUMA节点由不同类型的内存组成,比如 通过插座连接的内存条(socket-attached DRAM)和CXL/PCIe连接的内存条(CXL/PCIe attached DRAM), 基于轮转的交叉策略无法利用不同的带宽特性较优地分发数据。 相反,以遵循每个NUMA节点的带宽权重而不是均匀的分配策略(allocation policy),交错会更高效。
这笔修改引入了一种新的内存策略(memory policy, MPOL_WEIGHTED_INTERLEAVE), 该策略在不同的NUMA节点之间启用加权交错。加权交错允许在NUMA节点间按比例分派内存(proportional distribution of memory ), 以便更好的匹配每个节点的带宽。比如,一个系统有一个处理器节点,两个内存节点,带宽分别为(100GB/s和50GB/s),那么分配的比例权重为(2,1)。
每个节点的权重可以通过sysfs指定:/sys/kernel/mm/mempolicy/weighted_interleave/
默认情况下,每个节点的权重为1,匹配标准的1:1轮转交错策略。后续会扩展以便在内核和设备启动时可以注册默认值。
该策略根据权重分配一定数量的物理页面。比如,如果权重为(2,1),那么2个物理页面会被分配给节点0,一个页面会被分配给节点1.
新标志:MPOL_WEIGHTED_INTERLEAVE,可以在set_mempolicy(2) 和mbind(2)中使用。
加权交错需要注意的点:
- current->il_prev,跟踪以前分配过的节点(从该节点分配)
- current->il_weight,当前节点(current->il_prev)有效的权重,如果该值达到0,current->il_prev 会被设置为下一个节点,且current->il_weight也会被设置为下一个节点的权重。
- weighted_interleave_nodes,统计应用当前节点权重,已发生的分配数量。如果权重达到0,则切换到下一个节点,操作基于task->mempolicy.
- weighted_interleave_nid,获取节点掩码上的总权重,以及每个单独节点的权重,然后按照指定的索引计算. 操作基于VMA策略。
- bulk_array_weighted_interleave,获取节点掩码上的总权重,以及每个单独节点的权重,然后计算交叉轮替(interleave rounds),以及任意差异(partial round)。如果一个节点通过交错节点(interleave_nodes)被调度交错,那么当前权重会首先被分配。操作基于task->mempolicy.
复杂的是,在最近的重构和实际应用的交错之间获取ilx。如果使用交错策略调用alloc_pages_mpol(),且ilx设置为NO_INTERLEAVE_INDEX, 那么weighted_interleave_nodes() 会作用在VMA 策略。
检查alloc_pages_mpol() 的所有调用者,显示所有的外部调用者设置ilx为0,或者调用 get_vma_policy()获取ilx。
1.3 基于sysfs的权重交错接口
[PATCH v5 0/4] mm/mempolicy: weighted interleave mempolicy and sysfs extension
[PATCH v5 0/4] mm/mempolicy: weighted interleave mempolicy and sysfs extension
2. 连续页面映射(Transparent Contiguous PTEs for User Mappings)
2.1 实现新的写保护API
[PATCH v6 00/18] Transparent Contiguous PTEs for User Mappings
优化连续PTE实现,以便修复一些fork性能回归问题。fork()执行过程中,父进程的任何私有内存必须被写保护。之前,一次实现一个页表(PTE)的写保护。通过新的wrprotect_tes接口,内存管理核心(core-mm)可以批量写保护,因此不需要再展开连续的页表(PTE)。该修改有两个收益:
1)减少展开,减少必须发送的TLBIS数量。
2) 父进程可以保持连续页面映射(contpte-mapped),因此可以在fork函数执行完成后,继续高效的使用TLB。
使用不展开的方式,对整个连续块进行写保护的优化,应该感谢ARM提供定义了架构层面的支持:https://developer.arm.com/documentation/102105/ja-07/
2.2 减少扫描
[PATCH v6 00/18] Transparent Contiguous PTEs for User Mappings
如果后续的页表(PTE)也是具有相同页面保护属性的(pgprot)连续物理内存映射,一些架构可以通过查看页表辨别。可以利用这一特点优化folio_pte_batch(),在扫描时,可以跳过这些具有相同页面保护属性的页表。
2.3 总是内联部分接口,以便提升fork性能
[PATCH v6 00/18] Transparent Contiguous PTEs for User Mappings
由于set_ptes() 和 wrprotect_ptes()变得有些复杂,编译器可能选择不内联这两个接口。如果这两个接口不内联,会严重影响fork性能。因此,将这个接口标记为总是内联(__always_inline)
2.4 整理pte_next_pfn定义
[PATCH v6 00/18] Transparent Contiguous PTEs for User Mappings
所有架构都已使用pte_advance_pfn替换pte_next_pfn,可以简化pte_next_pfn() 宏。