description/memory: PCP batch-free free_pcppages_bulk

This commit is contained in:
Cheng Jian
2022-04-15 21:38:19 +08:00
parent b56332f03f
commit f6b5e372ab
+162 -23
View File
@@ -203,11 +203,6 @@ cgit 上查看 MM 所有的 log 信息 :
# 1 页表管理
-------
| 时间 | 作者 | 特性 | 描述 | 是否合入主线 | 链接 |
|:----:|:----:|:---:|:----:|:---------:|:----:|
| 2020/04/28 | Matthew Wilcox <willy@infradead.org> | [Record the mm_struct in the page table pages](https://lore.kernel.org/patchwork/patch/1232723) | NA| v1 ☐ | [PatchWork 0/6](https://lore.kernel.org/patchwork/patch/1232723) |
## 1.1 多级页表
-------
@@ -601,6 +596,13 @@ github 地址: [Mitosis Project](https://github.com/mitosis-project), [linux 内
| 2020 | [Mitosis: Transparently Self-Replicating Page-Tables for Large-Memory Machines; March, 2020; aspl0359a-achermanna.pdf](https://research.vmware.com/files/attachments/0/0/0/0/1/0/3/aspl0359a-achermanna.pdf) |
| 2021 | [Fast Local Page-Tables for Virtualized NUMA Servers with vMitosis; April, 2021; asplos21_vmitosis.pdf](https://research.vmware.com/files/attachments/0/0/0/0/1/3/8/asplos21_vmitosis.pdf)<br>[Fast Local Page-Tables for Virtualized NUMA Servers with vMitosis; April, 2021; vmitosis_ext_abstract.pdf](https://research.vmware.com/files/attachments/0/0/0/0/1/3/1/vmitosis_ext_abstract.pdf) |
## 1.11 其他页面页表相关
-------
| 时间 | 作者 | 特性 | 描述 | 是否合入主线 | 链接 |
|:----:|:----:|:---:|:----:|:---------:|:----:|
| 2020/04/28 | Matthew Wilcox <willy@infradead.org> | [Record the mm_struct in the page table pages](https://lore.kernel.org/patchwork/patch/1232723) | NA| v1 ☐ | [PatchWork 0/6](https://lore.kernel.org/patchwork/patch/1232723) |
| 2022/02/14 | David Hildenbrand <david@redhat.com> | [mm: enforce pageblock_order < MAX_ORDER](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=b3d40a2b6d10c9d0424d2b398bf962fb6adad87e) | 20220214174132.219303-1-david@redhat.com | v1 ☑✓ 5.18-rc1 | [LORE v1,0/2](https://lore.kernel.org/all/20220214174132.219303-1-david@redhat.com) |
# 2 内存分配
@@ -955,8 +957,6 @@ void free_hot_cold_page(struct page *page, bool cold)
}
```
其中 [commit 44110fe385af ("hot-n-cold pages: bulk page freeing")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1d2652dd2c3e942e75dc3137b3cb1774b43ae377) 实现了 free_pages_bulk()(后来[改名叫 free_pcppages_bulk](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5f8dcc21211a3d4e3a7a5ca366b469fb88117f61)) 完成 PCP 页面的批量.
内核默认从 PCP 分配页面都是倾向于分配热页(队头)的, 但是有一些路径下, 可能存在冷页面分配的诉求, 因此内核提供了 `__GFP_COLD` 用来显式从 PCP 中分配冷页面. 最普遍的比如 Page Cache 等页面, page_cache_read() 以及 do_read_cache_page() 中 `__page_cache_alloc()` 中都传递了 `__GFP_COLD` 分配冷页面. 内核甚至提供了 [page_cache_alloc_cold()](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=44110fe385af23ca5eee8a6ad4ff55d50339097a) 来从冷页中分配 Page Cache.
但是, 从上面的实现可以发现, PCP 中的页面其实并没有明确的冷热页面区分, 当前空闲列表中没有真正有用的页面冷热排序, 分配请求无法利用这些冷热排序, `__GFP_COLD` 其实并没有太大的意义. 因此 v4.15 直接将 `__GFP_COLD` 标记删掉 [mm: remove `__GFP_COLD`](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=453f85d43fa9ee243f0fc3ac4e1be45615301e3f). 删除 `__GFP_COLD` 参数还简化了页面分配器中的一些路径.
@@ -1004,9 +1004,129 @@ PCP 页面对内存碎片可能有潜在的冲击, 它可能会意外导致碎
| 2017/02/24 | Mel Gorman <mgorman@techsingularity.net> | [mm, page_alloc: use static global work_struct for draining per-cpu](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=bd233f538d51c2cae6f0bfc2cf7f0960e1683b8a) | 使用静态的 per-cpu 的 work_struct pcpu_drain 来替代之前 drain_all_pages() 中每次动态通过 alloc_percpu_gfp() 申请的 workqueue. | v1 ☑✓ 4.11-rc1 | [LORE](https://lore.kernel.org/lkml/20170125083038.rzb5f43nptmk7aed@techsingularity.net/), [commit](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=bd233f538d51c2cae6f0bfc2cf7f0960e1683b8a) |
| 2017/03/07 | Michal Hocko <mhocko@kernel.org> | [mm: move pcp and lru-pcp drainging into single wq](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ce612879ddc78ea7e4de4be80cba4ebf9caa07ee) | 引入一个统一名为 mm_percpu_wq 的 WQ_MEM_RECLAIM workqueue 来接管当前 MM 下存在的 vmstat_work, lru_add_drain_per_cpu 和 drain_local_pages_wq. | v1 ☑✓ 4.11-rc6 | [LORE RFC](https://lore.kernel.org/all/20170207210908.530-1-mhocko@kernel.org)<br>*-*-*-*-*-*-*-* <br>[LORE v1](https://lore.kernel.org/all/20170307131751.24936-1-mhocko@kernel.org) |
#### 2.2.5.3 PCP Batch-Free free_pcppages_bulk
-------
* free_pages_bulk() 批量释放整个 list
内核最早引入冷热页的时候, [commit 44110fe385af ("hot-n-cold pages: bulk page freeing")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1d2652dd2c3e942e75dc3137b3cb1774b43ae377) 实现了 free_pages_bulk() 完成一整个 list page 的页面, 这个被用于 PCP 页面的批量释放.
* 引入 MIGRATETYPE 后, round-robin fashion 与 batch-free
由于 free_pages_bulk() 一直用来释放 PCP 的页面, 因此 v2.6.24-rc1, 优化 PCP 的 MIGRATETYPE 感知的时候, 直接将该函数[重命名为 free_pcppages_bulk()](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=5f8dcc21211a3d4e3a7a5ca366b469fb88117f61). 通过 pcp->list 按照 MIGRATETYPE 拆分成了多个 list, 分配的时候按照 MIGRATETYPE 分配, 那么批量释放的时候, 由于不能明确每个 MIGRATETYPE 应该释放多少页面, 因此实现了一个 [round-robin fashion](https://elixir.bootlin.com/linux/v2.6.32/source/mm/page_alloc.c#L545) 的模式, 循环着为每种 MIGRATETYPE 依次释放页面, 其中 [COMMIT1](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5f8dcc21211a3d4e3a7a5ca366b469fb88117f61) 引入了 round-robin fashion, [COMMIT2](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a6f9edd65beaef24836e8934c8912c1e974dd45c) 在函数中引入了一个 batch_free 的计数, 记录遇到空 PCP MIGRATETYPE list 时需要释放的页面数量, 从而一定程度上减少了在空 PCP MIGRATETYPE list 上遍历的次数.
随后 v2.6.39-rc1, 对 batch_free 进一步做了优化, 如果当前 PCP list 上一个非空的 lists[MIGRATETYPE], 则不用再频繁地做 round-robin fashion 遍历了, 直接对这个 lists[MIGRATETYPE] 做批量释放就可以了. 参见 [commit 1d16871d8c96 ("mm: batch-free pcp list if possible")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1d16871d8c96deadc5f9753b6b096074f2cbcbe1).
* 减少 zone->lock 的持锁时间 以及 prefetch_buddy
free_pcppages_bulk() 中批量释放页面的过程可能会耗时比较久, 这个过程一直持有 zone->lock 这个热锁是非常不合适的. 因此 v4.17-rc1 [mm: improve zone->lock scalability](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=97334162e4d79f866edd7308aac0ab3ab7a103f7) 对此现状进行了优化. 其中
[COMMIT2](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0a5f4e5b45625e75db85b4968fc4c232d8091143) 将 PCP 上待释放页面查找的动作放到了锁外, 引入了一个临时的 LIST_HEAD(head), 在不持有 zone->lock 的情况下将待释放的页面缓存到这个链表上, 然后再在持锁的情况下, 遍历链表对页面进行释放.
[COMMIT3](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=97334162e4d79f866edd7308aac0ab3ab7a103f7) 则实现了 prefetch_buddy 机制. 当一个页面被释放回全局池时, 它的伙伴将被检查是否有可能进行合并. 这需要访问 Buddy 的页面结构, 如果是缓存冷的, 访问可能需要很长时间. 在没有持有 zone->lock 的时候增加了一个预取, 希望以后在 zone->lock 下访问 buddy 的页面结构会更快. 由于伙伴系统 "总是" 会合并临近的兄弟页面, 并检查 order-0 页面的好友, 以便在它进入主分配器时尝试合并它, cacheline 总是会进来, 也就是说, 预取的数据将总是会被用到的.
**关于预取的数量**, 通常情况下, 预取次数为 pcp->batch(默认为 31, 在 x86_64 上的上限为 (PAGE_SHIFT * 8) = 96), 但当 PCP 的页面全部耗尽时, 预取次数为 pcp->count, 上限为 pcp->high. pcp->high, 虽然有一个默认值 186 (pcp->batch = 31 * 6), 可以由用户通过 `/proc/sys/vm/percpu_pagelist_fraction` 更改, 并且没有软件上限, 所以可以很大, 比如几千. 因此, 只预取页面 buddy 结构前 pcp->batch 张页面, 避免预取过多.
**关于预取带来的收益和引入的开销**, 有两个问题:
1. 预取可能会移除现有的 cacheline, 特别是对于 L1D 缓存, 因为它不是很大.
2. 还有一些额外的指令开销, 即计算 BUDDY PFN 两次.
对于问题 1, 这很难说, 虽然通过性能测试显示了很好的结果, 但是其实实际的好处依旧取决于当前 CPU 上实际的工作负载.
对于问题 2, 因为计算是对两个局部变量的异或, 所以在许多情况下, 预期所花费的周期将会被后来减少的内存延迟所抵消. 这对于 NUMA 机器来说尤其如此, 其中多个 CPU 在 zone->lock 上竞争, zone->lock 锁下最耗时的部分是等待被释放的页面及其同伴的 "struct page" 的 cacheline.
* Scale batch-free 的页面数量(free_factor)
v5.14 的时候, [commit 3b12e7e97938 ("mm/page_alloc: scale the number of pages that are batch freed")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3b12e7e97938424de2bb1b95ba0bd6a49bad39f9) 当任务释放大量 order-0 页面时, 可能会多次获取 zone->lock, 批量释放页面. 当释放大量页面时, 这可能会不必要地争夺 zone->lock. 这个补丁根据最近的模式调整 PCP 页面批量释放(batch-free)的页面大小, 提高了扩展性.
具体调整(Scale)的策略如下:
1. 每次在没有任何分配的情况下释放页面时, 将[释放的页面数增加一倍](https://elixir.bootlin.com/linux/v5.14/source/mm/page_alloc.c#L3358).
2. 在 rmqueue_pcplist() 进行分配时, 将批量释放的页面数[减少一半](https://elixir.bootlin.com/linux/v5.14/source/mm/page_alloc.c#L3673).
3. 释放时至少[保证有 pcp->batch 张页面](https://elixir.bootlin.com/linux/v5.14/source/mm/page_alloc.c#L3350)在 PCP list 上.
* High-Order PCP 时代的 round-robin fashion 与 batch-free
依旧是 v5.14, [commit 44042b449872 ("mm/page_alloc: allow high-order pages to be stored on the per-cpu lists")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=44042b4498728f4376e84bae1ac8016d146d850b) 实现 High-Order PCP 页面的时候, 同样采用了 round-robin fashion 的 batch-free, 只不过当前会不光要保持 MIGRATE_PCPTYPES 的平衡, 还有考虑不同 Order 页面的平衡.
* 回退到 single pass zone->lock 与 prefetch_buddy
v5.18 的时候, free_pcppages_bulk() 又做了较多的优化.
这个时候, 从 PCP 列表中选择页面的操作已经足够简单, 选择期间的主要开销是 bulkfree_pcp_prepare(), 在通常情况下, 它是一个简单的检查和预取. 考虑到 list 操作本身有成本, 所以回到单次释放页面的流程. 参见 [commit 8b10b465d0e1 ("mm/page_alloc: free pages in a single pass during bulk free")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=8b10b465d0e18b002b290b2162145abc7167e53d).
这个过程中还有一个关键的改动是移除了 prefetch_buddy(). 因为由于现在所有的遍历和释放[现在都是在 zone->lock 下进行的](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=8b10b465d0e18b002b290b2162145abc7167e53d), 而预取当年也是伴随着将[页面选择放在 zone->lock 外, zone->lock 之保护页面释放所引入的]((https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0a5f4e5b45625e75db85b4968fc4c232d8091143)), 因此不太清楚预取这是否总能带来好处, 直接回退了 [prefetch_buddy() 的 COMMIT](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=97334162e4d79f866edd7308aac0ab3ab7a103f7) 特性. 参见 [commit 2a791f4412cb ("mm/page_alloc: do not prefetch buddies during bulk free")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2a791f4412cba41330453527a3045cf39818e72a).
#### 2.2.5.3 [Bulk memory allocation](https://lwn.net/Articles/711075)
| 时间 | 作者 | 特性 | 描述 | 是否合入主线 | 链接 |
|:-----:|:----:|:---:|:---:|:----------:|:----:|
| 2009/08/28 | Mel Gorman <mel@csn.ul.ie> | [Reduce searching in the page allocator fast-path](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=a6f9edd65beaef24836e8934c8912c1e974dd45c) | [COMMIT1](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=5f8dcc21211a3d4e3a7a5ca366b469fb88117f61) 新增了 PCP 对 MIGRATETYPE 的感知, pcp->list 按照 MIGRATETYPE 拆分成了多个 list, 这优化了每次查找对应 MIGRATTYPE 的开销(之前需要遍历 pcp->list 去找, 现在直接从对应 list[MIGRATETYPE] 中去取即可). 同样批量释放页面的时候, 为了保证公平性, 这个补丁为 free_pcppages_bulk() 实现了一个 [round-robin fashion](https://elixir.bootlin.com/linux/v2.6.32/source/mm/page_alloc.c#L545) 的模式, 循环着为每种 MIGRATETYPE 依次释放页面. | v1 ☑✓ 2.6.32-rc1 | [LORE RFC,0/3](https://lore.kernel.org/lkml/1250594162-17322-1-git-send-email-mel@csn.ul.ie)<br>*-*-*-*-*-*-*-* <br>[LORE 0/3](https://lore.kernel.org/lkml/1251449067-3109-1-git-send-email-mel@csn.ul.ie) |
| 2010/09/09 | Mel Gorman <mel@csn.ul.ie> | [mm: page allocator: update free page counters after pages are placed](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=72853e2991a2702ae93aaf889ac7db743a415dd3) | [to_free 被删除](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=72853e2991a2702ae93aaf889ac7db743a415dd3e5b31ac2ca2cd0cf6bf2fcbb708ed01466c89aaa) | v1 ☑✓ 2.6.36-rc4 | [LORE](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=72853e2991a2702ae93aaf889ac7db743a415dd3) |
| 2011/03/22 | Namhyung Kim <namhyung@gmail.com> | [mm: batch-free pcp list if possible](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1d16871d8c96deadc5f9753b6b096074f2cbcbe1) | TODO | v1 ☑✓ 2.6.39-rc1 | [LORE](https://lore.kernel.org/lkml/1297257677-12287-1-git-send-email-namhyung@gmail.com), [COMMIT](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1d16871d8c96deadc5f9753b6b096074f2cbcbe1) |
| 2018/03/01 | Aaron Lu <aaron.lu@intel.com> | [mm: improve zone->lock scalability](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=97334162e4d79f866edd7308aac0ab3ab7a103f7) | 优化了 free_pcppages_bulk() 中对 zone->lock 的持锁. | v4 ☑✓ 4.17-rc1 | [LORE v4,0/3](https://lore.kernel.org/all/20180301062845.26038-1-aaron.lu@intel.com) |
| 2021/05/25 | Mel Gorman <mgorman@techsingularity.net> | [mm/page_alloc: scale the number of pages that are batch freed](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3b12e7e97938424de2bb1b95ba0bd6a49bad39f9) | [Calculate pcp->high based on zone sizes and active CPUs](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=74f44822097c665041010994502b5971d6cd9f04) 的其中一个补丁. 整个补丁集 pcp->high 和 pcp->batch 根据 zone 内内存的大小进行调整. 当前补丁对 free_pcppages_bulk() 的页面数量做了 scale. 当任务释放大量 order-0 页面时, 可能会多次获取 zone->lock, 批量释放页面. 当释放大量页面时, 这可能会不必要地争夺 zone->lock. 这个补丁根据最近的模式调整 PCP 页面批量释放(batch-free)的页面大小, 从而提高了扩展性. | v2 ☑✓ 5.14-rc1 | [LORE v1,0/6](https://lore.kernel.org/all/20210521102826.28552-1-mgorman@techsingularity.net)<br>*-*-*-*-*-*-*-* <br>[LORE v2,0/6](https://lore.kernel.org/lkml/20210525080119.5455-1-mgorman@techsingularity.net) |
| 2021/06/11 | Mel Gorman <mgorman@techsingularity.net> | [mm/page_alloc: allow high-order pages to be stored on the per-cpu lists](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=44042b4498728f4376e84bae1ac8016d146d850b) | 20210611135753.GC30378@techsingularity.net | v2 ☑✓ 5.14-rc1 | [LORE](https://lore.kernel.org/all/20210611135753.GC30378@techsingularity.net) |
| 2022/02/16 | Mel Gorman <mgorman@techsingularity.net> | [Follow-up on high-order PCP caching](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=2a791f4412cba41330453527a3045cf39818e72a) | commit 44042b449872 ("mm/page_alloc: allow high-order pages to storage on the per-cpu list") 的主要目的是通过两种方式降低高阶页面的 SLUB 缓存重新填充的成本. 首先, 区域锁获取减少, 其次, 好友列表修改减少. 这是一个后续系列, 修复了合并后出现的一些问题.<br>补丁 1 是一个功能补丁. 这是无害的, 但效率低下.<br>补丁 2-4 减少了大量释放 PCP 页面的开销. 虽然开销很小, 但在截断大文件时, 它是累积的, 并且是可以注意到的.<br>它可以删除带有页面缓存中的数据的大型稀疏文件, 稀疏文件用于消除文件系统开销.<br>补丁 5 解决了高阶 PCP 页面在 PCP 列表中存储时间过长的问题. CPU 上释放的页面可能无法快速重用, 在某些情况下, 这可能会增加缓存未命中率. 详细信息包含在变更日志中. | v1 ☐☑ 5.18-rc1 | [LORE v1,0/5](https://lore.kernel.org/r/20220215145111.27082-1-mgorman@techsingularity.net)<br>*-*-*-*-*-*-*-* <br>[LORE v2,0/6](https://lore.kernel.org/r/20220217002227.5739-1-mgorman@techsingularity.net)<br>*-*-*-*-*-*-*-* <br>[LORE 1/1](https://patchwork.kernel.org/project/linux-mm/patch/20220221094119.15282-2-mgorman@techsingularity.net) |
* free_pcppages_bulk Caller
[commit e7c8d5c9955a ("hot-n-cold pages: page allocator core")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=a206231bbe6ffb988cdf9fcbdfd98e49abaf4819) 引入 PCP 框架的时候
1. 首先是 free_unref_page_list() 和 free_unref_page(), 早期分别是 free_hot_cold_page() 和 free_hot_cold_page_list(). 内核的 PCP 早已没有了当初 HOT COLD 的概念. 因此叫 hot_cold 已经不那么恰当了. 参见 [COMMIT](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=2d4894b5d2ae0fe1725ea7abd57b33bfbbe45492).
free_the_page() 是一个非常底层的页面释放回收, 用于释放任意 Order 的页面到 PCP 或者伙伴系统中. 如果可以使用 PCP, 则直接使用 free_unref_page() 将页面交给 PCP list. 否则就使用 `__free_pages_ok()` 将其归还给伙伴系统. 参见 [commit 742aa7fb52c5 ("mm/page_alloc.c: use a single function to free page")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=742aa7fb52c56fb3b307e704f93e67b698959cc2).
`put_page() -=> __put_single_page()``free_unref_page()` 的另一个用户, 最早引入冷热页的时候, 就使用 [`__page_cache_release()` 来释放](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a206231bbe6ffb988cdf9fcbdfd98e49abaf4819) Page Cache 的页面到 PCP 中. 随后引入 THP 的时候, 将 `free_unref_page()``__page_cache_release()` 中移除, 而封装了 [`__put_single_page()`](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9180706344487700b40da9eca5dedd3d11cb33b4) 来完成页面的释放, 执行路径 `put_page()` -=> `__put_page()` -=> `__put_single_page()` -=> `free_unref_page()`.
[free_unref_page_list()(早期叫 free_hot_cold_page_list())](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=cc59850ef940e4ee6a765d28b439b9bafe07cf63) 用于释放一整个 list 的页面. 这也是一个非常广泛的页面释放接口. LRU 或者 PCP 释放页面的过程中, 为了将遍历查询页面和释放页面的操作分开, 减少持锁的时间. 普遍采用的方式是将页面加入到一个临时的 list 中, 然后再通过 free_unref_page_list() 释放整个 list 中所有的页面. 由于所有的页面都是 Order-0 的, 因此每张页面依旧是通过 free_unref_page_prepare() 和 free_unref_page_commit() 来归还给 PCP 的.
| 时间 | 作者 | 特性 | 描述 | 是否合入主线 | 链接 |
|:----:|:----:|:---:|:----:|:---------:|:----:|
| 2017/10/18 | Mel Gorman <mgorman@techsingularity.net> | [mm, page_alloc: enable/disable IRQs once when freeing a list of pages](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=453f85d43fa9ee243f0fc3ac4e1be45615301e3f) | [Follow-up for speed up page cache truncation v2](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=453f85d43fa9ee243f0fc3ac4e1be45615301e3f) 的其中一个补丁. 将原来的 free_hot_cold_page() 拆成了 free_unref_page_prepare() 和 free_unref_page_commit(). | v2 ☑ 4.15-rc1 | [LORE v2,1/8](https://lore.kernel.org/all/20171018075952.10627-2-mgorman@techsingularity.net), [COMMIT](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9cca35d42eb61b69e108a17215756c46173a5e6f) |
| 2018/11/19 | Aaron Lu <aaron.lu@intel.com> | [free order-0 pages through PCP in page_frag_free() and cleanup](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=742aa7fb52c56fb3b307e704f93e67b698959cc2) | page_frag_free() 支持释放页面到 PCP 中. page_frag_free() 是用来释放任意 Order 的普通页或者复合页. page_frag_free() 调用 `__free_pages_ok()` 将页面释放回 Buddy, 但是却不考虑使用 PCP. 这对于高阶页面是可以的, 但是对于 Order-0 的页面, 它错过了使用 PCP 的优化机会, 如果频繁调用时可能导致 zone->lock 争用.<br>Pawel Staszewski 最近分享了他的 "Linux 内核如何处理正常流量" 的结果 [1] 和从性能数据, Jesper Dangaard Brouer 发现锁争用来自页面分配器. 通过在 page_frag_free() 中增加对 PCP 页面的支持. Pawel 和 Jesper 的场景性能提高了 7%, 锁争用消失了. 此外 Ilias 在 cortex-a53 上的 "低" 速度 1Gbit 接口上的测试显示 ~11% 的性能提升. 测试 64 字节数据包 `__free_pages_ok()` 函数的不再是 perf top 的热点.<br>函数接口上, 之前释放 PCP 页面的路径和函数太多了, 这里引入了一个统一的接口 free_the_page() 来释放 PCP 页面. 其中对于满足 PCP 要求的页面, 直接使用 free_unref_page() 回收到了 PCP list 中. | v1 ☑✓ 5.0-rc1 | [LORE v1,0/2](https://lore.kernel.org/all/20181119134834.17765-1-aaron.lu@intel.com) |
2. 接着是 drain_pages_zone(cpu, zone), 该函数用于回收指定 CPU 指定 zone 上的 PCP list 页面.
很多情况下, 直接 Drain 掉一个 CPU 上所有 zone 的 PCP 页面相对来说是非常不合适的, 因此 v3.19 实现了单个 zone 的 pcplist Draining, 引入了 drain_pages_zone(cpu, zone) 来清理掉指定 CPU 上指定 drain 的 page 页面. 参见 [commit 93481ff0e5a0 ("mm: introduce single zone pcplists drain")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=93481ff0e5a0c7636359a7ee52248856da5e7859).
内存规整时, 3.19-rc1 时, compact_zone() 中添加 check_drain 标签, 如果页面分配慢速路径下进行直接规整, 并且当前区域已经完成了页面规整, 则通过 drain_local_pages(zone)(后面修正为 lru_add_drain_cpu_zone()) 将当前 zone 的 PCP 页面释放掉, 从而让伙伴系统合并出足够的连续页面块, 来完成当前高阶页面的分配, 参见 [COMMIT1](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fdaf7f5c40f3d20690c236298418acf72eb664b5), [COMMIT2](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b01b2141999936ac3e4746b7f76c0f204ae4b445). 随后 v4.17-rc1 时, 进一步做了优化. 当 kcompactd 无法规整出足够的连续内存块来完成 cc.order 的页面分配时, 会将该 zone 的所有 pcps 页面通过 [drain_all_pages(zone)](https://elixir.bootlin.com/linux/v4.17/source/mm/compaction.c#L1996) 归还到伙伴系统, 这提高了高阶页面分配成功的概率. 参见 [COMMIT3](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=bc3106b26cf6a6f214fd1a8538736afc39ae1b5c),
页面隔离时, 在 pageblock 上设置 MIGRATETYPE_ISOLATE 时, 也会把当前 zone 的 pcplists 清空, 以便有更好的机会将所有页面成功隔离, 而不是留在 PCP 缓存中. 由于隔离始终与单个 zone 有关, 所以可以将 pcplists 的 drain 减少到单个区域. 这一变化将使内存隔离更快, 并且不影响其他不相关的 pcplists. 参见 [COMMIT1](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ec25af84b23b6862341b5b5b68d24be3f53b8d2c), [COMMIT2](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7612921f2376d51d020ae2f06ffb7da40422b75b).
CPU offline 时, 同样需要释放当前 CPU 上 PCP 缓存的页面. [2014/12/10, COMMIT1](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c05543293e0bf586842844c14fd8c598f494a107), [2019/03/05, COMMIT2](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c52e75935f8ded2bd4a75eb08e914bd96802725b), [2020/09/18, COMMIT3](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9683182612214aa5f5e709fad49444b847cd866a), [2020/12/14, COMMIT4](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ec6e8c7e03147c65380e6c04c4cf4290e96280b6)
| 时间 | 作者 | 特性 | 描述 | 是否合入主线 | 链接 |
|:----:|:----:|:---:|:----:|:---------:|:----:|
| 2014/10/02 | Vlastimil Babka <vbabka@suse.cz> | [Single zone pcpclists drain](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c05543293e0bf586842844c14fd8c598f494a107) | 支持单个 zone 的 pcplist Draining. 在很多情况下, 只 drain 一个 zone 的 pcplist 就足够了, drain 掉所有 zone 的 pcplist 是浪费, 然后会导致更多的 pcplist 重新填充.<br> [COMMIT1] 为 drain_local_pages() 和 drain_all_pages() 引入了 "struct zone *" 参数, 传入 NULL 值意味着所有 zone 都像往常一样被 drain. 剩余的补丁在适当的地方将现有的调用者转换为单一 zone Draining 的操作. 注意内存规整上单个 zone 的 pcplist Draining, 将在下一个补丁集 [Further compaction tuning](https://lore.kernel.org/all/1412696019-21761-1-git-send-email-vbabka@suse.cz) | 1412696019-21761-1-git-send-email-vbabka@suse.cz) 提供. | v1 ☑✓ 3.19-rc1 | [LORE v1,0/4](https://lore.kernel.org/all/1412264940-15738-1-git-send-email-vbabka@suse.cz) |
| 2014/10/07 | Vlastimil Babka <vbabka@suse.cz> | [Further compaction tuning](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=fdaf7f5c40f3d20690c236298418acf72eb664b5) | NA | v1 ☑✓ 3.19-rc1 | [LORE v1,0/5](https://lore.kernel.org/all/1412696019-21761-1-git-send-email-vbabka@suse.cz) |
| 2015/12/03 | Vlastimil Babka <vbabka@suse.cz> | [mm, compaction: reduce spurious pcplist drains](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a34753d275576896b06af9baa6f54bee258368c2) | [reduce latency of direct async compaction](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=fdd048e12c9a46d058f69822cb15641adae181e1) 的其中一个补丁. | v1 ☑✓ 4.7-rc1 | [LORE v1,0/3](https://lore.kernel.org/all/1449130247-8040-1-git-send-email-vbabka@suse.cz)<br>*-*-*-*-*-*-*-* <br>[LORE v2,0/4](https://lore.kernel.org/lkml/1459414236-9219-1-git-send-email-vbabka@suse.cz), [关注 COMMIT](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a34753d275576896b06af9baa6f54bee258368c2) |
| 2018/03/01 | David Rientjes <rientjes@google.com> | [mm, compaction: drain pcps for zone when kcompactd fails](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=bc3106b26cf6a6f214fd1a8538736afc39ae1b5c) | 内存规整通过内存的碎片化整理在 zone 内规整出一块连续的空闲页面, 从而满足高阶页面(甚至是 MAX_ORDER) 的分配请求, 但是 PCP 对此是个冲击, 空闲页面可能会滞留在 PCP 上, 从而组织当前 zone 上的伙伴页面合并. 当 kcompactd 无法整理内存以便分配 cc.order 页面时, 将该区域的所有 pcps 页面通过 [drain_all_pages(zone)](https://elixir.bootlin.com/linux/v4.17/source/mm/compaction.c#L1996) 归还到伙伴系统, 这样就不会发生这种搁浅. 该顺序的内存规整随后将被推迟, 从而限制 Draining 的速率. 测试发现, 没有这个补丁, 就很难有 order-9 或 order-10 页面空闲. | v1 ☑✓ 4.17-rc1 | [LORE](https://lore.kernel.org/all/alpine.DEB.2.20.1803010340100.88270@chino.kir.corp.google.com) |
* 最后是 drain_zone_pages
在大型 NUMA 系统上, PCP 中可能缓存了大量内存. 在一个拥有 512 个处理器和 256 个节点的系统上, 将会有 `256*512` 个页面集. 如果每个页面集只能保存 5 个页面, 那么我们讨论的是 655360 个页面. 在 IA64 上, 如果页面大小为 16K, 这可能会导致 10 GB 的内存被困在 PCP 中. 对于较小的系统来说, 典型的情况要少得多, 但仍然存在内存被困在非节点页面集中的可能性.
v2.6.13-rc1, [commit 4ae7c03943fc ("Periodically drain non local pagesets")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4ae7c03943fca73f23bc0cdb938070f41b98101f) 引入了 PCP 页面的周期性回收. 通过将 Drain PCP 的操作添加到 SLAB 的刷新过程中, cache_reap() -=> drain_remote_pages(). SLAB 分配器每 2 秒刷新一次它的 PCP 缓存. 如果本地内存可用, offline 的节点内存可能很少使用. 没有这个补丁, 类似这种很少使用的页面集中依旧会被留有较多的内存.
随后 v2.6.16-rc6, `next_reap_node() -=> drain_node_pages()`, 参见 [COMMIT1](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=8fce4d8e3b9e3cf47cc8afeb6077e22ab795d989), [COMMIT2](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=879336c3930ae9273ea1c45214cb8adae0ce494a), [COMMIT3](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=bc4ba393c007248f76c05945abb7b7b892cdd1cc).
最后, 将 drain_node_pages() 从 SLAB cache_reap() 流程中移除, 转而转换为 drain_zone_pages(), 并加入到 refresh_cpu_vm_stats() 流程中. 参见 [COMMIT](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4037d452202e34214e8a939fa5621b2b3bbb45b7).
| 时间 | 作者 | 特性 | 描述 | 是否合入主线 | 链接 |
|:----:|:----:|:---:|:----:|:---------:|:----:|
| 2006/06/12 | Christoph Lameter <clameter@sgi.com> | [Zoned VM counters V3](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=ed11d9eb2228acc483c819ab353e3c41bcb158fa) | NA | v3 ☑✓ 2.6.18-rc1 | [LORE v1,0/21](https://lore.kernel.org/all/20060612211244.20862.41106.sendpatchset@schroedinger.engr.sgi.com) |
#### 2.2.5.4 [Bulk memory allocation](https://lwn.net/Articles/711075)
-------
* Order-0 批量页面分配器
@@ -1031,7 +1151,7 @@ Mel Gorman 认为最好基于现有的 Per CPU Allocator/PCP 针对这种情况
| 时间 | 作者 | 特性 | 描述 | 是否合入主线 | 链接 |
|:----:|:----:|:---:|:----:|:---------:|:----:|
| 2021/03/25 | Mel Gorman | [Introduce a bulk order-0 page allocator with two in-tree users](https://lore.kernel.org/patchwork/patch/1399888) | 批量 order-0 页面分配器, 目前 sunrpc 和 network 页面池是这个特性的第一个用户 | v6 ☑ 5.13-rc1 | [RFC](https://lore.kernel.org/patchwork/patch/1383906)<br>*-*-*-*-*-*-*-* <br>[v1](https://lore.kernel.org/patchwork/patch/1385629)<br>*-*-*-*-*-*-*-* <br>[v2](https://lore.kernel.org/patchwork/patch/1392670)<br>*-*-*-*-*-*-*-* <br>[v3](https://lore.kernel.org/patchwork/patch/1393519)<br>*-*-*-*-*-*-*-* <br>[v4](https://lore.kernel.org/patchwork/patch/1394347)<br>*-*-*-*-*-*-*-* <br>[v5](https://lore.kernel.org/patchwork/patch/1399888)<br>*-*-*-*-*-*-*-* <br>[LORE v6,0/9](https://lore.kernel.org/all/20210325114228.27719-1-mgorman@techsingularity.net) |
| 2021/03/25 | Mel Gorman | [Introduce a bulk order-0 page allocator with two in-tree users](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=be5dba25b4b27f262626ddc9079d4858a75462fd) | 批量 Order-0 页面分配器, 目前 sunrpc 和 network 页面池是这个特性的第一个用户 | v6 ☑ 5.13-rc1 | [RFC](https://lore.kernel.org/patchwork/patch/1383906)<br>*-*-*-*-*-*-*-* <br>[v1](https://lore.kernel.org/patchwork/patch/1385629)<br>*-*-*-*-*-*-*-* <br>[v2](https://lore.kernel.org/patchwork/patch/1392670)<br>*-*-*-*-*-*-*-* <br>[v3](https://lore.kernel.org/patchwork/patch/1393519)<br>*-*-*-*-*-*-*-* <br>[v4](https://lore.kernel.org/patchwork/patch/1394347)<br>*-*-*-*-*-*-*-* <br>[v5](https://lore.kernel.org/patchwork/patch/1399888)<br>*-*-*-*-*-*-*-* <br>[LORE v6,0/9](https://lore.kernel.org/all/20210325114228.27719-1-mgorman@techsingularity.net) |
| 2021/03/29 | Mel Gorman | [Use local_lock for pcp protection and reduce stat overhead](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=902499937e3a82156dcb5069b6df27640480e204) | Bulk memory allocation 的第一组修复补丁, PCP 与 vmstat 共享锁定要求, 这很不方便, 并且会导致一些问题. 可能因为这个原因, PCP 链表和 vmstat 共享相同的 Per CPU 空间, 这意味着 vmstat 可能跨 CPU 更新包含 Per CPU 列表的脏缓存行, 除非使用填充. 该补丁集拆分该结构并分离了锁. | v6 ☑ 5.14-rc1 | [LORE RFC,0/6](https://lore.kernel.org/lkml/20210329120648.19040-1-mgorman@techsingularity.net)<br>*-*-*-*-*-*-*-* <br>[LORE v2,00/11](https://lore.kernel.org/lkml/20210407202423.16022-1-mgorman@techsingularity.net)<br>*-*-*-*-*-*-*-* <br>[LORE v3,00/11](https://lore.kernel.org/lkml/20210414133931.4555-1-mgorman@techsingularity.net)<br>*-*-*-*-*-*-*-* <br>[LORE v4,00/10](https://lore.kernel.org/lkml/20210419141341.26047-1-mgorman@techsingularity.net)<br>*-*-*-*-*-*-*-* <br>[LORE v6,0/9](https://lore.kernel.org/lkml/20210512095458.30632-1-mgorman@techsingularity.net) |
| 2021/03/30 | Mel Gorman | [mm/page_alloc: Add a bulk page allocator -fix -fix](https://lore.kernel.org/patchwork/patch/1405057) | Bulk memory allocation 的第二组修复补丁 | v6 ☐ | [LORE](https://lore.kernel.org/lkml/20210330114847.GX3697@techsingularity.net) |
| 2021/07/16 | Mel Gorman | [mm/page_alloc: enable alloc bulk when page owner is on](https://lore.kernel.org/lkml/20210716081756.25419-1-link@vivo.com/) | 上一个 alloc bulk 版本有一个bug, 当 page_owner 打开时, 系统可能会由于 irq 禁用上下文中的 alloc bulk 调用 prep_new_page() 而崩溃, 这个问题是由于 set_page_owner() 在 local_irq 关闭的情况下通过 GFP_KERNEL 标志分配内存来保存栈信息导致的. 所以, 我们不能假设 alloc 标志应该与 new page 相同, prep_new_page() 应该准备/跟踪页面 gfp, 但不应该使用相同的gfp来获取内存, 这取决于调用方. 现在, 这里有两个gfp标志, alloc_gfp 用于分配内存, 取决于调用方, page_gfp 是 page 的 gfp, 用于跟踪/准备自身. 在大多数情况下, 两个 flag 相同是可以的, 在 alloc_pages_bulk() 中, 使用 GFP_ATOMIC, 因为 irq 被禁用. | v1 ☐ | [RFC](https://lore.kernel.org/lkml/20210716081756.25419-1-link@vivo.com/) |
@@ -1054,7 +1174,7 @@ Mel Gorman 认为最好基于现有的 Per CPU Allocator/PCP 针对这种情况
| 2016/12/01 | Mel Gorman | [mm: page_alloc: High-order per-cpu page allocator v4](https://lore.kernel.org/patchwork/patch/740275) | 为高阶内存分配提供 Per CPU Pages 缓存 | v4 ☐ | [LORE v4](https://lore.kernel.org/lkml/20161201002440.5231-1-mgorman@techsingularity.net) |
| 2020/08/14 | Minchan Kim <minchan@kernel.org> | [Support high-order page bulk allocation](https://lore.kernel.org/all/20200814173131.2803002-1-minchan@kernel.org) | 20200814173131.2803002-1-minchan@kernel.org | v1 ☐☑✓ | [LORE RFC,0/7](https://lore.kernel.org/all/20200814173131.2803002-1-minchan@kernel.org) |
| 2021/06/03 | Mel Gorman <mgorman@techsingularity.net> | [Allow high order pages to be stored on PCP v2](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=44042b4498728f4376e84bae1ac8016d146d850b) | PCP 支持缓存高 order 的页面. | v2 ☑ 5.14-rc1 | [OLD v6](https://lore.kernel.org/patchwork/patch/740779)<br>*-*-*-*-*-*-*-* <br>[OLD v7](https://lore.kernel.org/patchwork/patch/741937)<br>*-*-*-*-*-*-*-* <br>[LORE v2](https://lore.kernel.org/lkml/20210603142220.10851-1-mgorman@techsingularity.net)<br>*-*-*-*-*-*-*-* <br>[LORE v2](https://lore.kernel.org/all/20210611135753.GC30378@techsingularity.net) |
| 2022/02/16 | Mel Gorman <mgorman@techsingularity.net> | [Follow-up on high-order PCP caching](https://patchwork.kernel.org/project/linux-mm/cover/20220215145111.27082-1-mgorman@techsingularity.net/) | commit 44042b449872 ("mm/page_alloc: allow high-order pages to storage on the per-cpu list") 的主要目的是通过两种方式降低高阶页面的 SLUB 缓存重新填充的成本. 首先, 区域锁获取减少, 其次, 好友列表修改减少. 这是一个后续系列, 修复了合并后出现的一些问题.<br>补丁 1 是一个功能补丁. 这是无害的, 但效率低下.<br>补丁 2-4 减少了大量释放 PCP 页面的开销. 虽然开销很小, 但在截断大文件时, 它是累积的, 并且是可以注意到的.<br>它可以删除带有页面缓存中的数据的大型稀疏文件, 稀疏文件用于消除文件系统开销.<br>补丁 5 解决了高阶 PCP 页面在 PCP 列表中存储时间过长的问题. CPU 上释放的页面可能无法快速重用, 在某些情况下, 这可能会增加缓存未命中率. 详细信息包含在变更日志中. | v1 ☐☑ | [LORE v1,0/5](https://lore.kernel.org/r/20220215145111.27082-1-mgorman@techsingularity.net)<br>*-*-*-*-*-*-*-* <br>[LORE v2,0/6](https://lore.kernel.org/r/20220217002227.5739-1-mgorman@techsingularity.net)<br>*-*-*-*-*-*-*-* <br>[LORE 1/1](https://patchwork.kernel.org/project/linux-mm/patch/20220221094119.15282-2-mgorman@techsingularity.net) |
| 2022/02/16 | Mel Gorman <mgorman@techsingularity.net> | [Follow-up on high-order PCP caching](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=2a791f4412cba41330453527a3045cf39818e72a) | commit 44042b449872 ("mm/page_alloc: allow high-order pages to storage on the per-cpu list") 的主要目的是通过两种方式降低高阶页面的 SLUB 缓存重新填充的成本. 首先, 区域锁获取减少, 其次, 好友列表修改减少. 这是一个后续系列, 修复了合并后出现的一些问题.<br>补丁 1 是一个功能补丁. 这是无害的, 但效率低下.<br>补丁 2-4 减少了大量释放 PCP 页面的开销. 虽然开销很小, 但在截断大文件时, 它是累积的, 并且是可以注意到的.<br>它可以删除带有页面缓存中的数据的大型稀疏文件, 稀疏文件用于消除文件系统开销.<br>补丁 5 解决了高阶 PCP 页面在 PCP 列表中存储时间过长的问题. CPU 上释放的页面可能无法快速重用, 在某些情况下, 这可能会增加缓存未命中率. 详细信息包含在变更日志中. | v1 ☐☑ | [LORE v1,0/5](https://lore.kernel.org/r/20220215145111.27082-1-mgorman@techsingularity.net)<br>*-*-*-*-*-*-*-* <br>[LORE v2,0/6](https://lore.kernel.org/r/20220217002227.5739-1-mgorman@techsingularity.net)<br>*-*-*-*-*-*-*-* <br>[LORE 1/1](https://patchwork.kernel.org/project/linux-mm/patch/20220221094119.15282-2-mgorman@techsingularity.net) |
| 2022/03/10 | Mel Gorman <mgorman@techsingularity.net> | [mm/page_alloc: check high-order pages for corruption during PCP operations](https://patchwork.kernel.org/project/linux-mm/patch/20220310092456.GJ15701@techsingularity.net) | Eric Dumazet 指出, [commit 44042b449872 ("mm/page_alloc: allow high-order pages to storage to the per-cpu list")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=44042b4498728f4376e84bae1ac8016d146d850b) 仅在 PCP 重新填充和分配操作期间检查首页. 这是一个疏忽, 所有页面都应该检查. 这将导致一个小的性能损失, 但这对正确性是必要的. | v1 ☑ | [LORE v1,0/1](https://lore.kernel.org/r/20220310092456.GJ15701@techsingularity.net) |
@@ -1109,7 +1229,7 @@ v2.6.16-rc1 时, 大家发现 pcp->low 水线貌似并没有什么太大的用
v2.6.25-rc1, PCP 不再明确用 2 个数组区分冷热页, 而是使用单一列表管理. 参见 [Page allocator: get rid of the list of cold pages](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3dfa5721f12c3d5a441448086bee156887daa961), 此时 struct per_cpu_pageset 结构中 struct per_cpu_pages pcp[2] 变成 pcp.
v2.6.24-rc1, 引入 migratetype 来环节内存碎片化的时候, [commit 535131e6925b ("Choose pages from the per-cpu list based on migration type")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=535131e6925b4a95f321148ad7293f496e0e58d7) 新增了 PCP 对 migratetype 的感知, 不过此时每次需要遍历 pcp->list 查找到对应 migratetype 的页面, 如果 PCP 中没有对应 migratetype 的页面, 则通过 rmqueue_bulk() 从 Buddy 中继续缓存一些出来. 这种遍历查找的方式效率较低. 因此 v2.6.32-rc1 时 [commit 5f8dcc21211a ("page-allocator: split per-cpu list into one-list-per-migrate-type")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=5f8dcc21211a3d4e3a7a5ca366b469fb88117f61), 将 PCP 的页面列表也按照 migratetype 分开管理. 不过并不是所有的 migratetype 都会缓存在 PCP 中. 因此使用 MIGRATE_PCPTYPES 管理, 至此 per_cpu_pages 中维护 PCP 页面的 list 演变为 lists[MIGRATE_PCPTYPES].每次要从 PCP 获取某个 migratetype 的时候, 直接从对应 migratetype 的 pcp->list[migratetype] 去获取就行, 不用再费劲地区遍历 pcp->list, 归还的时候也按照 migratetype 归还.
v2.6.24-rc1, 引入 migratetype 来缓解内存碎片化的时候, [commit 535131e6925b ("Choose pages from the per-cpu list based on migration type")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=535131e6925b4a95f321148ad7293f496e0e58d7) 新增了 PCP 对 migratetype 的感知, 不过此时每次需要遍历 pcp->list 查找到对应 migratetype 的页面, 如果 PCP 中没有对应 migratetype 的页面, 则通过 rmqueue_bulk() 从 Buddy 中继续缓存一些出来. 这种遍历查找的方式效率较低. 因此 v2.6.32-rc1 时 [commit 5f8dcc21211a ("page-allocator: split per-cpu list into one-list-per-migrate-type")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=5f8dcc21211a3d4e3a7a5ca366b469fb88117f61), 将 PCP 的页面列表也按照 migratetype 分开管理. 不过并不是所有的 migratetype 都会缓存在 PCP 中. 因此使用 MIGRATE_PCPTYPES 管理, 至此 per_cpu_pages 中维护 PCP 页面的 list 演变为 lists[MIGRATE_PCPTYPES].每次要从 PCP 获取某个 migratetype 的时候, 直接从对应 migratetype 的 pcp->list[migratetype] 去获取就行, 不用再费劲地区遍历 pcp->list, 归还的时候也按照 migratetype 归还.
v2.6.34-rc1, [commit 99dcc3e5a94e ("this_cpu: Page allocator conversion")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=99dcc3e5a94ed491fbef402831d8c0bbb267f995) 开始使用了 PER CPU 变量替代 NR_CPUS 的数组. 于是 boot_pageset 被定义为 DEFINE_PER_CPU, zone->pageset 变成了一个指针, 而是用 alloc_percpu() 来分配. 然后直接使用 per_cpu_ptr(zone->pageset, cpu) 访问指定的 PCP 页面集. 以及 [commit](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=43cf38eb5cea91245502df3fcee4dbfc1c74dd1c).
@@ -1214,7 +1334,7 @@ Date: Wed Sep 11 14:20:35 2013 -0700
| 时间 | 作者 | 特性 | 描述 | 是否合入主线 | 链接 |
|:----:|:----:|:---:|:----:|:---------:|:----:|
| 2016/04/15 | Mel Gorman <mgorman@techsingularity.net> | [Optimise page alloc/free fast paths v3](https://lore.kernel.org/patchwork/patch/668967) | 优化 page 申请和释放的快速路径. 优化后<br>1. 在 free 路径中, 调试检查和页面区域/页面块仍然查找占主导地位, 目前仍没有明显的解决方案. 在 alloc 路径中, 主要的耗时操作是处理 zonelist、新页面准备和 fair zone 分配以及无数的统计更新. | v3 ☑ 4.7-rc1 | [PatchWork v6 00/28](https://lore.kernel.org/patchwork/patch/668967) |
| 2016/04/15 | Mel Gorman <mgorman@techsingularity.net> | [Optimise page alloc/free fast paths v3](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=4741526b83c5d3a3d661d1896f9e7414c5730bcb) | 优化 page 申请和释放的快速路径. 优化后<br>1. 在 free 路径中, 调试检查和页面区域/页面块仍然查找占主导地位, 目前仍没有明显的解决方案. 在 alloc 路径中, 主要的耗时操作是处理 zonelist、新页面准备和 fair zone 分配以及无数的统计更新. | v3 ☑ 4.7-rc1 | [PatchWork v6 00/28](https://lore.kernel.org/patchwork/patch/668967) |
### 2.1.9 重构
@@ -1274,7 +1394,9 @@ https://lore.kernel.org/patchwork/patch/408914
| 2005/11/18 | Christoph Lameter <clameter@engr.sgi.com> | [NUMA policies in the slab allocator V2](https://lore.kernel.org/patchwork/patch/38309) | SLAB 分配器感知 NUMA | v3 ☑ 2.6.16-rc2 | [PatchWork v2](https://lore.kernel.org/patchwork/patch/38309) |
| 2007/02/28 | Mel Gorman | [mm/slab: reduce lock contention in alloc path](https://lore.kernel.org/patchwork/patch/667440) | 优化 SLAB 分配的路径, 减少对 lock 的争抢, 实现 lockless. | v2 ☑ 2.6.22-rc1 | [PatchWork v2](https://lore.kernel.org/patchwork/patch/667440) |
| 2018/07/09 | [Improve shrink_slab() scalability (old complexity was O(n^2), new is O(n))](http://lore.kernel.org/patchwork/patch/960597) | 内存镜像的功能 | RFC v2 ☐ | [PatchWork](https://lore.kernel.org/patchwork/patch/960597) |
| 2007/05/04 | clameter@sgi.com <clameter@sgi.com> | [Slab Defrag / Slab Targeted Reclaim and general Slab API changes](https://lore.kernel.org/all/20070504221555.642061626@sgi.com) | 20070504221555.642061626@sgi.com | v1 ☐☑✓ | [LORE v1,0/3](https://lore.kernel.org/all/20070504221555.642061626@sgi.com) |
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=0aa817f078b655d0ae36669169d73a5c8a388016
**2.0 版本时代(1996年引入)**
@@ -1784,7 +1906,7 @@ Mel Gorman 观察到, 所有使用的内存页有三种情形:
| 2007/09/10 | Mel Gorman <mel@csn.ul.ie> | [Reduce external fragmentation by grouping pages by mobility v30](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=467c996c1e1910633fa8e7adc9b052aa3ed5f97c) | 基于页面可移动性的页面聚类来抗(外部)碎片化. 引入 CONFIG_PAGE_GROUP_BY_MOBILITY 控制 | v30 ☑ 2.6.24-rc1 | [2006/11/01 PatchWork v26,0/11](https://lore.kernel.org/patchwork/patch/67812)<br>*-*-*-*-*-*-*-* <br>[2006/11/21 PatchWork v27,0/11](https://lore.kernel.org/patchwork/patch/68969)<br>*-*-*-*-*-*-*-* <br>[Patchwork v28,0/12](https://lore.kernel.org/patchwork/patch/75208)<br>*-*-*-*-*-*-*-* <br>[Patchwork v30,0/13](https://lore.kernel.org/lkml/20070910112011.3097.8438.sendpatchset@skynet.skynet.ie) |
| 2007/05/17 | Mel Gorman <mel@csn.ul.ie> | [Annotation fixes for grouping pages by mobility v2](https://lore.kernel.org/patchwork/patch/81511) | NA | v1 ☐ | [PatchWork 0/5](https://lore.kernel.org/patchwork/patch/81511) |
| 2007/05/25 | Mel Gorman <mel@csn.ul.ie> | [Arbitrary grouping and statistics for grouping pages by mobility](https://lore.kernel.org/patchwork/patch/82099) | NA | v1 ☐ | [PatchWork 0/5](https://lore.kernel.org/patchwork/patch/82099))<br>*-*-*-*-*-*-*-* <br>[2007/06/01 Patchwork v4, 0/3](https://lore.kernel.org/patchwork/patch/82585) |
| 2015/02/12 | Joonsoo Kim <iamjoonsoo.kim@lge.com> | [mm/page_alloc: factor out fallback freepage checking](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4eb7dce62007113f1a2778213980fd6d8034ef5e) | 1423725305-3726-2-git-send-email-iamjoonsoo.kim@lge.com | v4 ☑✓ 4.1-rc1 | [LORE v4,0/3](https://lore.kernel.org/all/1423725305-3726-2-git-send-email-iamjoonsoo.kim@lge.com), [COMMIT](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4eb7dce62007113f1a2778213980fd6d8034ef5e) |
| 2015/02/12 | Joonsoo Kim <iamjoonsoo.kim@lge.com> | [mm/page_alloc: factor out fallback freepage checking](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4eb7dce62007113f1a2778213980fd6d8034ef5e) | [enhance compaction success rate](https://lore.kernel.org/lkml/1422621252-29859-1-git-send-email-iamjoonsoo.kim@lge.com) 的其中一个补丁. | v4 ☑✓ 4.1-rc1 | [LORE v4,0/3](https://lore.kernel.org/all/1423725305-3726-2-git-send-email-iamjoonsoo.kim@lge.com), [COMMIT](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4eb7dce62007113f1a2778213980fd6d8034ef5e) |
内核按照 pageblock 为粒度对页面按照 MIGRATE_TYPE 划分, 因此只有[当页面总数 vm_total_pages 比 MAX_ORDER_NR_PAGES * MIGRATE_TYPES 多](https://elixir.bootlin.com/linux/v2.6.32/source/mm/page_alloc.c#L2777)时, 才能成功地对页面进行分组. 当区域中的内存不足时, 就不能使用 page_group_by_mobility 机制. 参见 [commit 9ef9acb05a74 ("Do not group pages by mobility type on low memory systems")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9ef9acb05a741ec10a5e9122717736de12adced9).
@@ -1831,18 +1953,10 @@ v2.6.24 实现迁移类型 MIGRATETYPE 的时候, 在从伙伴系统中内存分
|:----:|:----:|:---:|:----:|:---------:|:----:|
| 2010/04/20 | Mel Gorman <mel@csn.ul.ie> | [Memory Compaction](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=4f92e2586b43a2402e116055d4edda704f911b5b) | 内存规整, 参见 [LWN: Memory compaction](https://lwn.net/Articles/368869) | v8 ☑ 2.6.35-rc1 | [PatchWork v8](https://lore.kernel.org/lkml/1271797276-31358-1-git-send-email-mel@csn.ul.ie) |
| 2010/11/22 | Mel Gorman <mel@csn.ul.ie> | [Use memory compaction instead of lumpy reclaim during high-order allocations V2](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=f3a310bc4e5ce7e55e1c8e25c31e63af017f3e50) | 在分配大内存时, 不再使用成块回收(lumpy reclaim)策略, 而是使用内存规整(memory compaction) | v2 ☑ 2.6.38-rc1 | [2010/11/11 LORE RFC v1,0/3](https://lore.kernel.org/all/1289502424-12661-1-git-send-email-mel@csn.ul.ie)<br>*-*-*-*-*-*-*-* <br>[2010/11/22 LORE v2,0/7](https://lore.kernel.org/lkml/1290440635-30071-1-git-send-email-mel@csn.ul.ie) |
| 2011/02/25 | Mel Gorman <mel@csn.ul.ie> | [Reduce the amount of time compaction disables IRQs for V2](https://lore.kernel.org/patchwork/patch/238585) | 减少内存规整关中断的时间, 降低其开销. | v2 ☑ 2.6.39-rc1 | [PatchWork v2](https://lore.kernel.org/patchwork/patch/238585) |
| 2012/04/11 | Mel Gorman <mel@csn.ul.ie> | [Removal of lumpy reclaim V2](https://lore.kernel.org/patchwork/patch/296609) | 移除成块回收(lumpy reclaim) 的代码. | v2 ☑ [3.5-rc1](https://kernelnewbies.org/Linux_3.5#Memory_Management) | [PatchWork v2](https://lore.kernel.org/patchwork/patch/296609) |
| 2012/09/21 | Mel Gorman <mgorman@suse.de> | [Reduce compaction scanning and lock contention](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=62997027ca5b3d4618198ed8b1aba40b61b1137b) | 进一步优化内存规整的扫描耗时和锁开销. | v1 ☑✓ 3.7-rc1 | [LORE 0/6](https://lore.kernel.org/all/1348149875-29678-1-git-send-email-mgorman@suse.de)<br>*-*-*-*-*-*-*-* <br>[LORE v1,0/9](https://lore.kernel.org/all/1348224383-1499-1-git-send-email-mgorman@suse.de) |
| 2013/12/05 | Mel Gorman <mel@csn.ul.ie> | [Removal of lumpy reclaim V2](https://lore.kernel.org/patchwork/patch/296609) | 添加了 start 和 end 两个 tracepoint, 用于内存规整的开始和结束. 通过这两个 tracepoint 可以计算工作负载在规整过程中花费了多少时间, 并可能调试与用于扫描的缓存 pfns 相关的问题. 结合直接回收和 slab 跟踪点, 应该可以估计工作负载的大部分与分配相关的开销. | v2 ☑ 3.14-rc1 | [PatchWork v2](https://lore.kernel.org/patchwork/patch/296609) |
| 2014/02/14 | Joonsoo Kim <iamjoonsoo.kim@lge.com> | [compaction related commits](https://lore.kernel.org/patchwork/patch/441817) | 内存规整相关清理和优化. 降低了内存规整 9% 的运行时间. | v2 ☑ 3.15-rc1 | [PatchWork v2 0/5](https://lore.kernel.org/patchwork/patch/441817) |
| 2014/07/28 | Vlastimil Babka <vbabka@suse.cz> | [compaction: balancing overhead and success rates](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=99c0fd5e51c447917264154cb01a967804ace745) | 优化内存规整的整体效率, 它试图同时朝着两个相互排斥的目标工作, 即减少规整的开销和提高成功率. 它包括一些清理和或多或少的琐碎(微观)优化, 希望是更智能的锁争用管理, 以及一些准备修补程序, 最终生成最后两个修补程序, 这些修补程序将提高成功率, 并将不太可能成功分配 THP 页面错误的工作降至最低. | v6 ☑✓ 3.18-rc1 | [LORE v3,00/13](https://lore.kernel.org/all/1403279383-5862-1-git-send-email-vbabka@suse.cz)<br>*-*-*-*-*-*-*-* <br>[LORE v4,00/15](https://lore.kernel.org/all/1405518503-27687-1-git-send-email-vbabka@suse.cz)<br>*-*-*-*-*-*-*-* <br>[LORE v5,0/14](https://lore.kernel.org/all/1406553101-29326-1-git-send-email-vbabka@suse.cz)<br>*-*-*-*-*-*-*-* <br>[LORE v6,00/13](https://lore.kernel.org/all/1407142524-2025-1-git-send-email-vbabka@suse.cz) |
| 2015/07/02 | Mel Gorman <mel@csn.ul.ie> | [Outsourcing compaction for THP allocations to kcompactd](https://lore.kernel.org/patchwork/patch/650051) | 实现 per node 的 kcompactd 内核线程来定期触发内存规整. | RFC v2 ☑ 4.6-rc1 | [PatchWork RFC v2](https://lore.kernel.org/patchwork/patch/650051) |
| 2016/07/21 | Vlastimil Babka <vbabka@suse.cz> | [compaction-related cleanups v5](https://lore.kernel.org/all/20160721073614.24395-1-vbabka@suse.cz) | 20160721073614.24395-1-vbabka@suse.cz | v5 ☐☑✓ | [LORE v5,0/8](https://lore.kernel.org/all/20160721073614.24395-1-vbabka@suse.cz) |
| 2016/08/10 | Mel Gorman <mel@csn.ul.ie> | [make direct compaction more deterministic](https://lore.kernel.org/patchwork/patch/692460) | 更有效地直接规整(压缩迁移). 在内存分配的慢速路径 `__alloc_pages_slowpath` 中的之前一直会先尝试直接回收和规整, 直到分配成功或返回失败.<br>1. 当回收先于压缩时更有可能成功, 因为压缩需要满足某些苛刻的条件和水线要求, 并且在有更多的空闲页面时会增加压缩成功的概率.<br>2. 另一方面, 从轻异步压缩(如果水线允许的话)开始也可能更有效, 特别是对于较小 order 的申请. 因此[这个补丁])(https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a8161d1ed6098506303c65b3701dedba876df42a)将慢速路径下的尝试流程修正为将先进行 MIGRATE_ASYNC 异步迁移(规整), 再尝试内存直接回收, 接着进行 MIGRATE_SYNC_LIGHT 轻度同步迁移(规整). 并引入了[直接规整的优先级](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a5508cd83f10f663e05d212cb81f600a3af46e40). | RFC v2 ☑ 4.8-rc1 & 4.9-rc1 | [PatchWork v3](https://lore.kernel.org/patchwork/patch/692460)<br>*-*-*-*-*-*-*-* <br>[PatchWork series 1 v5](https://lore.kernel.org/patchwork/patch/700017)<br>*-*-*-*-*-*-*-* <br>[PatchWork series 2 v6](https://lore.kernel.org/patchwork/patch/705827) |
| 2017/03/07 | Vlastimil Babka <vbabka@suse.cz> | [try to reduce fragmenting fallbacks](https://lore.kernel.org/patchwork/patch/766804) | 修复 [Regression in mobility grouping?](https://lkml.org/lkml/2016/9/28/94) 上报的碎片化问题, 通过修改 fallback 机制和 compaction 机制来减少永久随便化的可能性. 其中 fallback 修改时, 仅尝试从不同 migratetype 的 pageblock 中窃取的页面中挑选最小(但足够)的页面. | v3 ☑ [4.12-rc1](https://kernelnewbies.org/Linux_4.12#Memory_management) | [PatchWork v6](https://lore.kernel.org/patchwork/patch/766804), [KernelNewbies](https://kernelnewbies.org/Linux_4.12#Memory_management), [关键 commit 3bc48f96cf11 ("mm, page_alloc: split least stolen page in fallback")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3bc48f96cf11ce8699e419d5e47ae0d456403274) |
| 2019/01/18 |Mel Gorman <mgorman@techsingularity.net> | [Increase success rates and reduce latency of compaction v3](https://lore.kernel.org/patchwork/patch/1033508) | 提高内存规整成功率并减少规整的延迟, 将用于迁移的扫描页面数减少 65%, 将用于迁移目标的可用页面数减少97%, 同时显著提高透明的hugepage分配成功率.<br>这组补丁通过使用自由列表来缩短扫描, 更好地控制跳过信息, 以及是否多个扫描可以瞄准同一块并在被并行请求窃取之前捕获页块, 从而降低了扫描率和压缩成功率.<br>使用了 THPscale 来衡量和测试这组补丁的影响. 基准测试创建一个大文件, 映射它, 使它出错, 在映射中打洞, 使虚拟地址空间碎片化, 然后试图分配THP. 对于不同数量的线程, 它将重新执行. 从碎片的角度来看, 工作负载是相对良性的, 但它会压缩压力. 为迁移而扫描的页面数量减少了65%, 空闲扫描器减少了97.5%. 更少的工作换来更低的延迟和更高的成功率.<br>这组补丁还使用了严重碎片内存的工作负载进行了评估, 但也有很大的好处. | v3 ☑ [5.1-rc1](https://kernelnewbies.org/Linux_5.1#Memory_management) | [PatchWork 00/22](https://lore.kernel.org/patchwork/patch/1033508) |
### 3.4.2 慢速路径的内存规整
@@ -1970,7 +2084,28 @@ v3.6 [commit 7db8889ab05b ("mm: have order > 0 compaction start off where it lef
| 2012/12/11 | Marek Szyprowski <m.szyprowski@samsung.com> | [mm: cma: remove watermark hacks](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=bc357f431c836c6631751e3ef7dfe7882394ad67) | TODO | v1 ☑✓ 3.8-rc1 | [LORE](https://lore.kernel.org/lkml/1352357985-14869-1-git-send-email-m.szyprowski@samsung.com), [COMMIT](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=bc357f431c836c6631751e3ef7dfe7882394ad67) |
### 3.4.3 主动规整
### 3.4.3 内存规整中的抗碎片化逻辑
-------
#### 3.4.3.1 内存规整的开销以及成功率
-------
| 时间 | 作者 | 特性 | 描述 | 是否合入主线 | 链接 |
|:----:|:----:|:---:|:----:|:---------:|:----:|
| 2011/02/25 | Mel Gorman <mel@csn.ul.ie> | [Reduce the amount of time compaction disables IRQs for V2](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=b2eef8c0d09101bbbff2531c097543aedde0b525) | 减少内存规整关中断的时间, 降低其开销. | v2 ☑ 2.6.39-rc1 | [PatchWork v2](https://lore.kernel.org/lkml/1298664299-10270-1-git-send-email-mel@csn.ul.ie) |
| 2014/02/14 | Joonsoo Kim <iamjoonsoo.kim@lge.com> | [compaction related commits](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=b6c750163c0d138f5041d95fcdbd1094b6928057) | 内存规整相关清理和优化. 降低了内存规整 9% 的运行时间. 而成功率没有下降. | v2 ☑ 3.15-rc1 | [LORE v1,0/5](https://lore.kernel.org/lkml/1391749726-28910-1-git-send-email-iamjoonsoo.kim@lge.com)<br>*-*-*-*-*-*-*-* <br>[LORE v2 0/5](https://lore.kernel.org/lkml/1392360843-22261-1-git-send-email-iamjoonsoo.kim@lge.com) |
| 2014/07/28 | Vlastimil Babka <vbabka@suse.cz> | [compaction: balancing overhead and success rates](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=99c0fd5e51c447917264154cb01a967804ace745) | 优化内存规整的整体效率, 它试图同时朝着两个相互排斥的目标工作, 即减少规整的开销和提高成功率. 它包括一些清理和或多或少的琐碎(微观)优化, 希望是更智能的锁争用管理, 以及一些准备修补程序, 最终生成最后两个修补程序, 这些修补程序将提高成功率, 并将不太可能成功分配 THP 页面错误的工作降至最低. | v6 ☑✓ 3.18-rc1 | [LORE v3,00/13](https://lore.kernel.org/all/1403279383-5862-1-git-send-email-vbabka@suse.cz)<br>*-*-*-*-*-*-*-* <br>[LORE v4,00/15](https://lore.kernel.org/all/1405518503-27687-1-git-send-email-vbabka@suse.cz)<br>*-*-*-*-*-*-*-* <br>[LORE v5,0/14](https://lore.kernel.org/all/1406553101-29326-1-git-send-email-vbabka@suse.cz)<br>*-*-*-*-*-*-*-* <br>[LORE v6,00/13](https://lore.kernel.org/all/1407142524-2025-1-git-send-email-vbabka@suse.cz) |
| 2014/12/08 | Joonsoo Kim <iamjoonsoo.kim@lge.com> | [enhance compaction success rate](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2149cdaef6c0eb59a9edf3b152027392cd66b41f) | 1418022980-4584-1-git-send-email-iamjoonsoo.kim@lge.com | v1 ☐☑✓ | [LORE v1,0/4](https://lore.kernel.org/all/1418022980-4584-1-git-send-email-iamjoonsoo.kim@lge.com)<br>*-*-*-*-*-*-*-* <br>[LORE v2,0/4](https://lore.kernel.org/lkml/1422621252-29859-1-git-send-email-iamjoonsoo.kim@lge.com)<br>*-*-*-*-*-*-*-* <br>[LORE v3,1/4](https://lore.kernel.org/lkml/1422861348-5117-1-git-send-email-iamjoonsoo.kim@lge.com)<br>*-*-*-*-*-*-*-* <br>[LORE v4,1/3](https://lore.kernel.org/lkml/1423725305-3726-1-git-send-email-iamjoonsoo.kim@lge.com) |
| 2015/07/02 | Mel Gorman <mel@csn.ul.ie> | [Outsourcing compaction for THP allocations to kcompactd](https://lore.kernel.org/patchwork/patch/650051) | 实现 per node 的 kcompactd 内核线程来定期触发内存规整. | RFC v2 ☑ 4.6-rc1 | [PatchWork RFC v2](https://lore.kernel.org/patchwork/patch/650051) |
| 2016/07/21 | Vlastimil Babka <vbabka@suse.cz> | [compaction-related cleanups v5](https://lore.kernel.org/all/20160721073614.24395-1-vbabka@suse.cz) | 20160721073614.24395-1-vbabka@suse.cz | v5 ☐☑✓ | [LORE v5,0/8](https://lore.kernel.org/all/20160721073614.24395-1-vbabka@suse.cz) |
| 2017/03/07 | Vlastimil Babka <vbabka@suse.cz> | [try to reduce fragmenting fallbacks](https://lore.kernel.org/patchwork/patch/766804) | 修复 [Regression in mobility grouping?](https://lkml.org/lkml/2016/9/28/94) 上报的碎片化问题, 通过修改 fallback 机制和 compaction 机制来减少永久随便化的可能性. 其中 fallback 修改时, 仅尝试从不同 migratetype 的 pageblock 中窃取的页面中挑选最小(但足够)的页面. | v3 ☑ [4.12-rc1](https://kernelnewbies.org/Linux_4.12#Memory_management) | [PatchWork v6](https://lore.kernel.org/patchwork/patch/766804), [KernelNewbies](https://kernelnewbies.org/Linux_4.12#Memory_management), [关键 commit 3bc48f96cf11 ("mm, page_alloc: split least stolen page in fallback")](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3bc48f96cf11ce8699e419d5e47ae0d456403274) |
| 2019/01/18 |Mel Gorman <mgorman@techsingularity.net> | [Increase success rates and reduce latency of compaction v3](https://lore.kernel.org/patchwork/patch/1033508) | 提高内存规整成功率并减少规整的延迟, 将用于迁移的扫描页面数减少 65%, 将用于迁移目标的可用页面数减少97%, 同时显著提高透明的hugepage分配成功率.<br>这组补丁通过使用自由列表来缩短扫描, 更好地控制跳过信息, 以及是否多个扫描可以瞄准同一块并在被并行请求窃取之前捕获页块, 从而降低了扫描率和压缩成功率.<br>使用了 THPscale 来衡量和测试这组补丁的影响. 基准测试创建一个大文件, 映射它, 使它出错, 在映射中打洞, 使虚拟地址空间碎片化, 然后试图分配THP. 对于不同数量的线程, 它将重新执行. 从碎片的角度来看, 工作负载是相对良性的, 但它会压缩压力. 为迁移而扫描的页面数量减少了65%, 空闲扫描器减少了97.5%. 更少的工作换来更低的延迟和更高的成功率.<br>这组补丁还使用了严重碎片内存的工作负载进行了评估, 但也有很大的好处. | v3 ☑ [5.1-rc1](https://kernelnewbies.org/Linux_5.1#Memory_management) | [PatchWork 00/22](https://lore.kernel.org/patchwork/patch/1033508) |
#### 3.4.3.2 内存规整的 Anti Fragmentation
-------
### 3.4.4 主动规整
-------
[主动规整, 而不是按需规整](https://lwn.net/Articles/817905).
@@ -1987,6 +2122,8 @@ v3.6 [commit 7db8889ab05b ("mm: have order > 0 compaction start off where it lef
| 2021/07/30 | Nitin Gupta <nigupta@nvidia.com> | [mm: compaction: support triggering of proactive compaction by user](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?id=65d759c8f9f57b96c199f3fe5cfb93ac7da095e9) | 主动压缩每 500ms 触发一次, 并基于设置为 sysctl.compression_proactiveness 的值, 在节点上运行压缩 COMPACTION_HPAGE_ORDER(通常为 ORDER-9) 的页面. 并非所有应用程序都需要每 500ms 触发一次压缩以搜索压缩页面, 特别是在可能只有很少 MB RAM 的嵌入式系统用例上. 这些默认设置将导致嵌入式系统中主动压缩几乎总是在运行.<br>另一方面, 主动压缩对于获取一组高阶页面仍然非常有用. 因此, 在不需要启用主动压缩的系统上, 可以在写入其 sysctl 接口时从用户空间触发主动压缩. 例如, 假设 AppLauncher 决定启动内存密集型应用程序, 如果它获得更多高阶页面, 则可以快速启动该应用程序, 这样 launcher 就可以通过从用户空间触发主动压缩来提前准备系统. | v5 ☑ 5.15-rc1 | [PatchWork v5](https://patchwork.kernel.org/project/linux-mm/patch/1627653207-12317-1-git-send-email-charante@codeaurora.org), [LORE v5](https://lore.kernel.org/all/1627653207-12317-1-git-send-email-charante@codeaurora.org) |
## 3.5 抗碎片化优化
-------
@@ -5896,7 +6033,7 @@ DAMON 利用两个核心机制 : **基于区域的采样**和**自适应区域
| 2021/10/01 | SeongJae Park <sjpark@amazon.com> | [Implement Data Access Monitoring-based Memory Operation Schemes](https://patchwork.kernel.org/project/linux-mm/cover/20211001125604.29660-1-sj@kernel.org) | 实现了 DAMON 的基于数据访问监视的操作方案 (DAMOS).<br>DAMON 可以用作支持数据访问的内存管理优化的原语. 因此, 希望进行此类优化的用户应该运行 DAMON, 读取监视结果, 分析并优化内存管理方案.<br>然而, 在许多其他情况下, 用户只是希望系统对具有特定时间的特定访问频率的特定大小的内存区域应用内存管理操作. 例如, "page out a memory region than 100mib only rare visits more than 2 minutes", 或者 "Do not use THP For a memory region than 2mib rarely visits more than 1 seconds". 为了使工作更容易且不冗余, 这个补丁集实现了 DAMON 的一个新特性, 称为基于数据访问监视的操作方案 (DAMOS). 使用该特性, 用户可以以简单的方式描述常规方案, 并要求 DAMON 自行执行这些方案.<br>DAMOS 对于内存管理优化是准确和有用的.<br>1. THP 的一个实验性的基于 damon 的操作方案 'ethp' 减少了 76.15% 的 THP 内存开销, 同时保留了 51.25% 的 THP 加速.<br>2. 另一个实验性的基于 damon 的 "主动回收" 实现 "prcl", 减少了 93.38% 的 residential sets 和 23.63% 的内存占用, 而在最好的情况下只产生 1.22% 的运行时开销 (parsec3/freqmine). | v1 ☑ 5.16-rc1 | [2020/12/16 PatchWork RFC,v15.1,0/8](https://patchwork.kernel.org/project/linux-mm/cover/20201216084404.23183-1-sjpark@amazon.com)<br>*-*-*-*-*-*-*-* <br>[2021/10/01 PatchWork 0/7](https://patchwork.kernel.org/project/linux-mm/cover/20211001125604.29660-1-sj@kernel.org) |
| 2021/10/08 | SeongJae Park <sjpark@amazon.com> | [mm/damon/dbgfs: Implement recording feature](https://patchwork.kernel.org/project/linux-mm/patch/20211008094509.16179-1-sj@kernel.org) | 为 'damon-dbgfs' 实现 'recording' 特性<br>用户空间可以通过 'damon_aggregate' 跟踪点事件获得监视结果. 为了简单起见, 跟踪点事件有一些重复的信息, 比如 'target_id' 和 'nr_regions'. 这造成它的大小比实际需要的要大. 另外, 对于一些简单的用例, 处理跟踪点可能会很复杂. 为了给用户空间提供一种更有效和简单的监控结果的方法, 这个提交实现了 'damon-dbgfs' 中的 'recording' 特性. 该特性通过一个名为 'record' 的新 debugfs 文件导出到用户空间, 该文件位于 '/damon/' 目录下. 该文件允许用户以简单格式在常规二进制文件中记录监视的访问模式. 记录的结果首先写入内存缓冲区并批处理刷新到文件中. 用户可以通过读取和写入 record 文件来获取和设置缓冲区的大小和结果文件的路径. | v1 ☐ | [PatchWork 1/4](https://patchwork.kernel.org/project/linux-mm/patch/20211008094509.16179-1-sj@kernel.org) |
| 2021/10/12 | SeongJae Park <sjpark@amazon.com> | [DAMON: Support Physical Memory Address Space Monitoring](https://www.phoronix.com/scan.php?page=news_item&px=DAMON-Physical-Monitoring) | 允许物理地址空间监控. | v1 ☑ 5.16-rc1 | [PatchWork RFC,v9,00/10](https://patchwork.kernel.org/project/linux-mm/cover/20201007071409.12174-1-sjpark@amazon.com)<br>*-*-*-*-*-*-*-* <br>[PatchWork RFC,v10,00/13](https://patchwork.kernel.org/project/linux-mm/cover/20201216094221.11898-1-sjpark@amazon.com))<br>*-*-*-*-*-*-*-* <br>[PatchWork 0/7](https://patchwork.kernel.org/project/linux-mm/cover/20211012205711.29216-1-sj@kernel.org)|
| 2021/10/12 | Xin Hao <xhao@linux.alibaba.com> | [mm/damon/dbgfs: add region_stat interface](https://patchwork.kernel.org/project/linux-mm/patch/20211012054948.90381-1-xhao@linux.alibaba.com) | DAMON 中使用 damon-dbgfs 操作带来了很大的便利, 有时候如果我希望能够查看任务的划分区域 nr_access 等值, 当前这不能直接通过 dbgfs 接口查看, 所以添加一个接口 "region_stat" 来显示. | v1 ☐ | [PatchWork](https://patchwork.kernel.org/project/linux-mm/patch/20211012054948.90381-1-xhao@linux.alibaba.com/) |
| 2021/10/12 | Xin Hao <xhao@linux.alibaba.com> | [mm/damon/dbgfs: add region_stat interface](https://patchwork.kernel.org/project/linux-mm/patch/20211012054948.90381-1-xhao@linux.alibaba.com) | DAMON 中使用 damon-dbgfs 操作带来了很大的遍历, 有时候如果我希望能够查看任务的划分区域 nr_access 等值, 当前这不能直接通过 dbgfs 接口查看, 所以添加一个接口 "region_stat" 来显示. | v1 ☐ | [PatchWork](https://patchwork.kernel.org/project/linux-mm/patch/20211012054948.90381-1-xhao@linux.alibaba.com/) |
| 2021/10/13 | Xin Hao <xhao@linux.alibaba.com> | [mm/damon: Adjust the size of kbuf array to avoid overflow](https://patchwork.kernel.org/project/linux-mm/patch/20211013114854.15705-1-xhao@linux.alibaba.com) | NA | v1 ☐ | [PatchWork](https://patchwork.kernel.org/project/linux-mm/patch/20211013114854.15705-1-xhao@linux.alibaba.com) |
| 2021/10/16 | Xin Hao <xhao@linux.alibaba.com> | [mm/damon/core: Optimize kdamod.%d thread creation code](https://patchwork.kernel.org/project/linux-mm/patch/20211016165914.96049-1-xhao@linux.alibaba.com) | 当 ctx->adaptive_targets 列表为空, 无需创建并调用kdamond. 只有当 ctx->adaptive_targets 列表不为空, 且 ctx->kdamond 指针为 NULL 时, 才调用__damon_start函数. | v1 ☐ | [PatchWork v1](https://patchwork.kernel.org/project/linux-mm/patch/20211016165616.95849-1-xhao@linux.alibaba.com)<br>*-*-*-*-*-*-*-* <br>[PatchWork v2](https://patchwork.kernel.org/project/linux-mm/patch/20211016165914.96049-1-xhao@linux.alibaba.com) |
| 2021/10/21 | Xin Hao <xhao@linux.alibaba.com> | [mm/damon/dbgfs: Optimize target_ids interface write operation](https://patchwork.kernel.org/project/linux-mm/patch/bc341f48b5558f6816dcef22eca4f4a590efdc67.1634834628.git.xhao@linux.alibaba.com) | NA | v2 ☐ | [PatchWork v1](https://patchwork.kernel.org/project/linux-mm/patch/20211021085611.81211-1-xhao@linux.alibaba.com)<br>*-*-*-*-*-*-*-* <br>[PatchWork v2](https://patchwork.kernel.org/project/linux-mm/patch/bc341f48b5558f6816dcef22eca4f4a590efdc67.1634834628.git.xhao@linux.alibaba.com) |
@@ -6073,6 +6210,8 @@ DAMON 利用两个核心机制 : **基于区域的采样**和**自适应区域
## 14.6 PER_CPU
-------
[PERCPU 变量实现](https://zhuanlan.zhihu.com/p/260986194)
| 时间 | 作者 | 特性 | 描述 | 是否合入主线 | 链接 |
|:----:|:----:|:---:|:----:|:---------:|:----:|
| 2009/02/18 | Tejun Heo <tj@kernel.org> | [implement new dynamic percpu allocator](https://lore.kernel.org/patchwork/patch/144750) | 实现了 [vm_area_register_early()](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f0aa6617903648077dffe5cfcf7c4458f4610fa7) 以支持在启动阶段注册 vmap 区域. 基于此特性实现了可伸缩的动态 percpu 分配器(CONFIG_HAVE_DYNAMIC_PER_CPU_ARE), 可用于静态(pcpu_setup_static/pcpu_setup_first_chunk)和动态(`__alloc_percpu`) percpu 区域, 这将允许静态和动态区域共享更快的直接访问方法. | v1 ☑ 2.6.30-rc1 | [PatchWork](https://lore.kernel.org/patchwork/patch/144750) |