description/memory: MEMCG LRU lock

This commit is contained in:
Cheng Jian
2022-03-14 23:18:25 +08:00
parent 17b812eb16
commit 7ddac9ede6
3 changed files with 31 additions and 6 deletions
+14 -5
View File
@@ -3893,21 +3893,30 @@ git://github.com/glommer/linux.git kmemcg-slab
## 9.4 memcg LRU
-------
自 2008 年 v2.6.25-rc1, Balbir Singh 实现 MEMCG 时, 就支持了 per-memcg 的 LRU, 不过当时每个 MEMECG 只有一个唯一的 LRU, 且区分 active_list 和 inactive_list(Per cgroup active and inactive list). [Memory controller: add per cgroup LRU and reclaim](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=66e1707bc34609f626e2e7b4fe7e454c9748bad5). 并标记了 [TODO: Consider making these lists per zone](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=78fb74669e80883323391090e4d26d17fe29488f). 此时, per-memcg 的 lru_lock 也是 mem_cgroup 级别的.
自 2008 年 v2.6.25-rc1, Balbir Singh 实现 MEMCG 时, 就支持了 per-memcg 的 LRU, [Memory controller: add per cgroup LRU and reclaim](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=66e1707bc34609f626e2e7b4fe7e454c9748bad5). 不过当时每个 MEMECG 只有一个唯一的 LRU, 且区分 active_list 和 inactive_list(Per cgroup active and inactive list). 引入了 [page_cgroup](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=8cdea7c05454260c0d4d83503949c358eb131d17) 维护了 mem_cgroup 和 lru 的联系,. 并标记了 [TODO: Consider making these lists per zone](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=78fb74669e80883323391090e4d26d17fe29488f). 此时, per-memcg 的 lru_lock 也是 mem_cgroup 级别的.
而当时正是 per-Zone LRU 的时代, 随即 KAMEZAWA Hiroyuki 就为 per-memcg 的唯一 LRU 也完成了 per-Zone 的支持. 为了完成这个功能, 引入了 mem_cgroup_per_zone 等结构, 并添加了 [mem_cgroup_per_zone 的 active_list 和 inactive_list](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1ecaab2bd221251a3fd148abb08e8b877f1e93c8), 同样完成了 [mem_cgroup_per_zone 的 lru_lock](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=072c56c13e1302fcdc39961dc64e76485731ad67).
而当时正是 per-Zone LRU 的时代, 随即 KAMEZAWA Hiroyuki 就为 per-memcg 的唯一 LRU 也完成了 per-Zone 的支持, 参见 [per-zone and reclaim enhancements for memory controller take 3](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=072c56c13e1302fcdc39961dc64e76485731ad6). 为了完成这个功能, 引入了 mem_cgroup_per_zone 等结构, 通过 `__mem_cgroup_add_list()``__mem_cgroup_remove_list()` 将每个 page_cgroup.lru 节点添加或者移除其对应 [mem_cgroup_per_zone 的 active_list 和 inactive_list](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1ecaab2bd221251a3fd148abb08e8b877f1e93c8), 同样完成了 [mem_cgroup_per_zone 的 lru_lock](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=072c56c13e1302fcdc39961dc64e76485731ad67).
至此内核为 per-memcg 实现了 per-Zone 的 LRU. v2.6.29-rc1 [memcg: synchronized LRU](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=08e552c69c6930d64722de3ec18c51844d06ee28) 发现了当前 memcg per-Zone LRU 的诸多问题. 当前通过 page_cgroup.lru 将 mem_cgroup 链接到自己 per-Zone LRU 的 active_list 和 inactive_list 上, 但是
至此内核为 per-memcg 实现了 per-Zone 的 LRU.
1. page_cgroup 的 LRU 与 global LRU 不同步.
2. page 和 page_cgroup 一对一, 静态分配.
[memcg lru lock 血泪史](https://blog.csdn.net/bjchenxu/article/details/112504932)
3. 要找到 page_cgroup(pc) 是什么 LRU, 你必须检查 pc->mem_cgroup as - lru = page_cgroup_zoneinfo(pc, nid_of_pc, zid_of_pc);
4. 复杂的 mem_cgroup_per_zone lru_lock 和 zone lru_lock 的嵌套处理, 非常容易导致死锁.
因此为了简化处理, 这个补丁移除了 mem_cgroup_per_zone 的 lru(即 MEMCG 的 Per-Zone LRU) lock, 全部采用 zone->lru_lock 来处理. 这样 MEMCG 的 Per-Zone LRU lock 就又变成了全局的 zone->lru_lock. 简而言之, 就是这个补丁合入后, 内核没有了 per memcg lru lock, 依旧使用旧的全局 lru lock 来管理全部 memcg lru lists. 这就造成了本来可以自治的 MEMCG, 却要等待其他 MEMCG 释放使用的 lru lock, 在一些场景往往会造成严重的性能问题.
由此而引发了 memcg lru lock 漫长的合入, 参见 [memcg lru lock 血泪史](https://blog.csdn.net/bjchenxu/article/details/112504932).
| 时间 | 作者 | 特性 | 描述 | 是否合入主线 | 链接 |
|:----:|:----:|:---:|:----:|:---------:|:----:|
| 2007/08/24 | Balbir Singh <balbir@linux.vnet.ibm.com> | [Memory controller: add per cgroup LRU and reclaim](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=66e1707bc34609f626e2e7b4fe7e454c9748bad5) | 实现 [Memory controller containers setup (v7)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=e1a1cd590e3fcb0d2e230128daf2337ea55387dc) 时引入了 [per cgroup 的 LRU 和 页面 reclaim](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=66e1707bc34609f626e2e7b4fe7e454c9748bad5) 和 | v7 ☑ [2.6.25-rc1](https://kernelnewbies.org/Linux_2_6_25) | [PatchWork v7](https://lore.kernel.org/lkml/20070824152009.16582.78904.sendpatchset@balbir-laptop), [关注 commit](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=66e1707bc34609f626e2e7b4fe7e454c9748bad5). |
| 2007/11/26 | KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> | [per-zone and reclaim enhancements for memory controller take 3](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=072c56c13e1302fcdc39961dc64e76485731ad6) | per-zone LRU for memcg, per-zone 的页面回收感知 MEMCG. 其中引入了 mem_cgroup_per_zone, mem_cgroup_per_node 等结构. | v3 ☑ 2.6.25-rc1 | [LORE v3,00/10](https://lore.kernel.org/lkml/20071127115525.e9779108.kamezawa.hiroyu@jp.fujitsu.com) |
| 2011/12/08 | Johannes Weiner <jweiner@redhat.com> | [memcg naturalization -rc5](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=6b208e3f6e35aa76d254c395bdcd984b17c6b626) | 参见 [LWN: Integrating memory control groups](https://lwn.net/Articles/443241). 引入 per-memcg lru, 消除重复的 LRU 列表, [全局 LRU 不再存在, page 只存在于 per-memcg LRU list 中](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=925b7673cce39116ce61e7a06683a4a0dad1e72a).<br>它使传统的页面回收能够从每个memcg LRU列表中查找页面, 从而消除了双LRU模式(除了每个memcg区域外, 每个全局区域)和系统中每个页面所需的额外列表头. <br>该补丁引入了 lruvec 结构. | v5 ☑ [3.3-rv1](https://kernelnewbies.org/Linux_3.3#Memory_management) | [PatchWork v5](https://lore.kernel.org/lkml/1320787408-22866-1-git-send-email-jweiner@redhat.com), |
| 2008/11/21 | KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> | [memcg updates (14/Nov/2008)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=08e552c69c6930d64722de3ec18c51844d06ee28) | 关键 [commit 08e552c69c69 ("memcg: synchronized LRU")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=08e552c69c6930d64722de3ec18c51844d06ee28) 移除了 mem_cgroup_per_zone 的 lru(即 MEMCG 的 Per-Zone LRU) lock, 再次回退到 MEMCG 也使用 zone->lru_lock 来处理的时代. | v1 ☐☑✓ | [LORE v1,0/9](https://lkml.kernel.org/lkml/20081114191246.4f69ff31.kamezawa.hiroyu@jp.fujitsu.com) |
| 2011/12/08 | Johannes Weiner <jweiner@redhat.com> | [memcg naturalization -rc5](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=6b208e3f6e35aa76d254c395bdcd984b17c6b626) | 参见 [LWN: Integrating memory control groups](https://lwn.net/Articles/443241). 引入 per-memcg lru, 消除重复的 LRU 列表, [全局 LRU 不再存在, page 只存在于 per-memcg LRU list 中](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=925b7673cce39116ce61e7a06683a4a0dad1e72a).<br>它使传统的页面回收能够从每个memcg LRU列表中查找页面, 从而消除了双LRU模式(除了每个memcg区域外, 每个全局区域)和系统中每个页面所需的额外列表头. <br>该补丁引入了 lruvec 结构. | v5 ☑ [3.3-rv1](https://kernelnewbies.org/Linux_3.3#Memory_management) | [LORE v5,00/10](https://lore.kernel.org/lkml/1320787408-22866-1-git-send-email-jweiner@redhat.com) |
| 2012/02/20 | Hugh Dickins <hughd@google.com> | [mm/memcg: per-memcg per-zone lru locking](https://lore.kernel.org/patchwork/cover/288055) | per-memcg lru lock | v1 ☐ | [PatchWork v1](https://lore.kernel.org/patchwork/cover/288055) |
| 2020/12/05 | Alex Shi <alex.shi@linux.alibaba.com> | [per memcg lru lock](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=15b447361794271f4d03c04d82276a841fe06328) | per memcg LRU lock | v21 ☑ [5.11](https://kernelnewbies.org/Linux_5.11#Memory_management) | [LORE v21,00/19](https://lore.kernel.org/all/1604566549-62481-1-git-send-email-alex.shi@linux.alibaba.com) |
| 2011/05/26 | KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> | [memcg async reclaim](https://lore.kernel.org/patchwork/cover/251835) | 实现 MEMCG 的异步回收机制(Asynchronous memory reclaim)<br>1. 当使用 memc g时, 应用程序可以看到由 memcg 限制引起的内存回收延迟. 一般来说, 这是不可避免的. 有一类应用程序, 它使用许多干净的文件缓存并执行一些交互式工作.<br>2. 如果内核能够帮助后台回收内存, 那么应用程序的延迟就会在一定程度上被隐藏(这取决于应用程序的睡眠方式). 这组补丁程序添加了控制开关 memory.async_control 启用异步回收. 采用动态计算的方法计算了边缘的大小. 该值被确定为减少应用程序达到限制的机会.<br>使用了新引入的 WQ_IDLEPRI 类型(使用 SCHED_IDLE 调度策略)的 kworker(memcg_async_shrinker) 来完整回收的操作. 通过使用 SCHED_IDLE, 系统繁忙的时候异步内存回收只能消耗 0.3% 的 CPU, 但如果cpu空闲, 可以使用很多cpu. | v3 ☐ | [PatchWork RFC,v3,0/10](https://lore.kernel.org/patchwork/cover/251835) |
@@ -64,6 +64,8 @@ blogexcerpt: 虚拟化 & KVM 子系统
| 2021/06/01 | Shaokun Zhang <zhangshaokun@hisilicon.com> | [fs: Optimized file struct to improve performance](https://patchwork.kernel.org/project/linux-fsdevel/patch%20/1622513557-46189-1-git-send-email-zhangshaokun@hisilicon.com) | 通过调整 struct file 中各字段的布局来提升性能. 在系统调用过程中, 经常使用 struct file 结构体中 `f_count``f_mod` 两个[字段](https://patchwork.kernel.org/project/linux-fsdevel/patch/1592987548-8653-1-git-send-email-zhangshaokun@hisilicon.com), 如果我们将它们放在一起, 将能有效地共享同一 cache line, 这对性能非常有用. intel 0-day CI 工程发现该补丁可以提升 UnixBench System Call Overhead 子项的性能, 参见 [aec499039e: unixbench.score 19.2% improvement](https://lkml.org/lkml/2021/4/20/28). | v1 ☐ | [2021/04/09 Patchwork RESEND](https://patchwork.kernel.org/project/linux-fsdevel/patch/1617940057-52843-1-git-send-email-zhangshaokun@hisilicon.com)<br>*-*-*-*-*-*-*-* <br>[2021/06/01 Patchwork RESEND](https://patchwork.kernel.org/project/linux-fsdevel/patch%20/1622513557-46189-1-git-send-email-zhangshaokun@hisilicon.com) |
| 2021/08/03 | Peter Oskolkov <posk@google.com> | [5-10% increase in IO latencies with nohz balance patch](https://lkml.org/lkml/2021/11/29/1108) | [7fd7a9e0caba ("sched/fair: Trigger nohz.next_balance updates when a CPU goes NOHZ-idle")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7fd7a9e0caba) 这个补丁导致了 FIO 性能测试劣化. | v1 ☐ | [PatchWork v4,00/10](https://lore.kernel.org/patchwork/cover/1471548) |
| 2021/08/03 | Peter Oskolkov <posk@google.com> | [New Linux Scheduler Patches Can Improve AMD Zen Performance For Some Workloads](https://www.phoronix.com/scan.php?page=news_item&px=Linux-Sched-NUMA-Imbalance-Zen) | NA | v1 ☐ | [PatchWork v4,00/10](https://lore.kernel.org/patchwork/cover/1471548) |
| 2018/11/05 | Patrick Bellasi <patrick.bellasi@arm.com> | [sched/fair: Fix cpu_util_wake() for 'execl' type workloads](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c469933e772132aad040bd6a2adc8edf9ad6f825) | TODO | v1 ☐☑✓ | [LORE](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c469933e772132aad040bd6a2adc8edf9ad6f825) |
| 2019/10/22 | Vincent Guittot <vincent.guittot@linaro.org> | [sched/fair: Fix rework of find_idlest_group()](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3318544b721d3072fdd1f85ee0f1f214c0b211ee) | TODO | v1 ☐☑✓ | [LORE](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3318544b721d3072fdd1f85ee0f1f214c0b211ee) |
# 2 网络
+15 -1
View File
@@ -1405,7 +1405,6 @@ Oracle 数据库具有类似的虚拟化功能, 称为 Oracle Multitenant, 其
| 2020/04/15 | Valentin Schneider | [sched: Streamline select_task_rq() & select_task_rq_fair()](https://lore.kernel.org/patchwork/patch/1224733) | 选核流程上的重构和优化, 当然除此之外还做了其他操作, 比如清理了 sd->flags 信息, 甚至 sysfs 接口都变成只读了 | v3 ☑ 5.8-rc1 | [PatchWork](https://lore.kernel.org/patchwork/cover/1224733) |
| 2021/03/26 | Rik van Riel | [Throttle select_idle_sibling when a target domain is overloaded](https://lore.kernel.org/patchwork/patch/1213189) | 这是 CPU/NUMA 负载平衡器协调的后续工作. 补丁中做了如下的优化<br>1. 补丁1-2 添加了 schedstats 来跟踪 select_idle_sibling() 的效率. 默认是禁用的<br>2. 补丁3 是一个细微的优化, 如果一个 CPU 已经找到, 避免清除部分 cpumask.<br>3. 补丁 4 跟踪在 select_idle_cpu() 期间域是否出现重载, 以便将来的扫描可以在必要时尽早终止. 这减少了在域超载时无用扫描的运行队列数量. | v2 ☐ | [PatchWork](https://lore.kernel.org/patchwork/patch/1213189) |
| 2021/03/26 | Rik van Riel | [sched/fair: bring back select_idle_smt, but differently](https://lore.kernel.org/patchwork/patch/1402916) | Mel Gorman 上面的补丁在 9fe1f127b913("sched/fair: Merge select_idle_core/cpu()") 中做了一些出色的工作, 从而提高了内核查找空闲cpu的效率, 可以有效地降低任务等待运行的时间. 但是较多的均衡和迁移, 减少的局部性和相应的 L2 缓存丢失的增加会带来一些负面的效应. 这个补丁重新将 `select_idle_smt` 引入回来, 并做了优化, 修复了性能回归, 在搜索所有其他 CPU 之前, 检查 prev 的兄弟 CPU 是否空闲. | v2 ☐ | [PatchWork](https://lore.kernel.org/patchwork/patch/1402916) |
| 2022/02/07 | Chen Yu <yu.c.chen@intel.com> | [sched: Stop searching for idle cpu if the LLC domain is overloaded](https://lore.kernel.org/all/20220207034013.599214-1-yu.c.chen@intel.com) | 当 LLC 域相对繁忙时, 在 LLC 域中搜索空闲的 CPU 是非常耗时的. 更糟糕的是, 如果 domain 域内所有 CPU 都过载, 那么在迭代整个 LLC 域之后, 它可能仍然无法找到空闲的 CPU. 在 select_idle_cpu() 中花费的时间对某些工作负载是可见的, 如果这个好诗过长, 可能会对性能带来负面影响. 这组补丁判断如果 sd_llc_shared 域已经 overloaded, 则跳过 select_idle_cpu() 不再在 LLC 域内扫描空闲 CPU. 基于 Mel Gorman 的补丁 [sched/fair: Track efficiency of select_idle_sibling](https://lore.kernel.org/lkml/20210726102247.21437-2-mgorman@techsingularity.net) 测试了 select_idle_sibling() 的效率. | v1 ☐☑✓ | [LORE](https://lore.kernel.org/all/20220207034013.599214-1-yu.c.chen@intel.com) |
### 5.3.3 SIS_AVG_CPU
@@ -1438,6 +1437,21 @@ Oracle 数据库具有类似的虚拟化功能, 称为 Oracle Multitenant, 其
| 2021/07/26 | Mel Gorman <mgorman@techsingularity.net> | [Modify and/or delete SIS_PROP](https://lore.kernel.org/patchwork/cover/1467090) | NA | RFC | [PatchWork RFC,0/9](https://lore.kernel.org/patchwork/cover/1467090) |
| 2021/08/04 | Mel Gorman <mgorman@techsingularity.net> | [Reduce SIS scanning](https://lore.kernel.org/patchwork/cover/1472054) | 将 [Modify and/or delete SIS_PROP](https://lore.kernel.org/patchwork/cover/1467090) 拆开进行提交. | RFC ☐ | [PatchWork 0/2](https://lore.kernel.org/patchwork/cover/1472054) |
* SIS_PROP to search idle CPU based on sum of util_avg
当前 select_idle_cpu() 使用 Per CPU 的平均空闲时间来估计 LLC 域总的空闲时间, 并计算需要扫描的 CPU 数量. 这可能是不一致的, 因为 CPU 的空闲时间不一定与域的空闲时间相关. 因此, 当系统非常繁忙时, 负载可能会被低估, 从而导致过度搜索.
当 LLC 域相对繁忙时, 在 LLC 域中搜索空闲的 CPU 是非常耗时的. 更糟糕的是, 如果 domain 域内所有 CPU 都过载, 那么在迭代整个 LLC 域之后, 它可能仍然无法找到空闲的 CPU. 通过测试发现 netperf 的 99th 分位延迟 与 select_idle_cpu() 所花费的时间相当. 也就是说, 当系统过载时, 搜索空闲 CPU 可能成为瓶颈. 因此 Chen Yu 建议 [sched: Stop searching for idle cpu if the LLC domain is overloaded](https://lore.kernel.org/all/20220207034013.599214-1-yu.c.chen@intel.com). 通过判断如果 sd_llc_shared 域已经 overloaded, 则跳过 select_idle_cpu() 不再在 LLC 域内扫描空闲 CPU. 基于 Mel Gorman 的补丁 [sched/fair: Track efficiency of select_idle_sibling](https://lore.kernel.org/lkml/20210726102247.21437-2-mgorman@techsingularity.net) 测试了 select_idle_sibling() 的效率.
随后[在 Peter 的建议](https://lore.kernel.org/lkml/20220207135253.GF23216@worktop.programming.kicks-ass.net)下, Chen Yu 在 V2 实现了一种 [util_avg 到扫描 CPU 数量 nr_idle_scan 的线性映射 f(x)](https://lore.kernel.org/all/20220310005228.11737-1-yu.c.chen@intel.com). 算法改进为了一种[基于 util_avg 来处理 SIS_PROP 的方法](https://lore.kernel.org/all/20220207034013.599214-1-yu.c.chen@intel.com), 其主要思想是用基于域的度量来代替平均 CPU 空闲时间. 选择平均 CPU 利用率 (util_avg) 作为候选者.
通常, 要扫描的 CPU 数量应该与该域中 util_avg 的总和成反比. 也就是说, util_avg 越低, select_idle_cpu() 应该扫描更多空闲 CPU, 反之亦然. 选择 util_avg 的好处是, 它是累计历史活动的度量, 似乎比瞬时度量 (如 rq->nr_running) 更准确. 此外, 还可以从周期性负载平衡中借用 util_avg, 这可以减轻 select_idle_cpu() 的开销.
| 时间 | 作者 | 特性 | 描述 | 是否合入主线 | 链接 |
|:----:|:----:|:----:|:---:|:----------:|:---:|
| 2022/03/10 | Chen Yu <yu.c.chen@intel.com> | [sched/fair: Change SIS_PROP to search idle CPU based on sum of util_avg](https://lore.kernel.org/all/20220310005228.11737-1-yu.c.chen@intel.com) | | v2 ☐☑✓ | [LORE v1](https://lore.kernel.org/all/20220207034013.599214-1-yu.c.chen@intel.com)<br>*-*-*-*-*-*-*-* <br>[LORE v2](https://lore.kernel.org/all/20220310005228.11737-1-yu.c.chen@intel.com) |
### 5.3.5 SIS avg_idle
-------