当前位置:首页>Linux>Linux MM 2026-05-15~17 最新 Feature 分析报告

Linux MM 2026-05-15~17 最新 Feature 分析报告

  • 2026-07-03 15:57:34
Linux MM 2026-05-15~17 最新 Feature 分析报告
目录
  1. swap 表第四阶段:统一分配与消除静态元数据
  2. ZONE_DEVICE memmap 初始化加速
  3. shmem:通过 folio 批量化与无锁读取优化读性能
  4. slab:运行时 sheaf 容量与 barn 限制可调
  5. BPF Arena 内核侧直接访问支持
  6. 移除 CONFIG_READ_ONLY_THP_FOR_FS,为可写文件启用文件透明大页
  7. DAMON 数据属性监测
  8. DAMON 硬件采样访问报告与 AMD IBS 后端
  9. shmem:支持 gnu.* xattr 命名空间以兼容 Hurd
  10. process_vm_readv/writev 支持 pidfd 和 NOWAIT
  11. page_owner:per-fd filter 基础设施与 NUMA 过滤

1. swap 表第四阶段:统一分配与消除静态元数据

系列[PATCH v5 00/12] mm, swap: swap table phase IV: unify allocation and reduce static metadata作者: Kairui Song版本: v5(12个patch)

背景

Linux swap 子系统历史上维护了两套独立的静态元数据数组:swap_cgroup_ctrl(每个 swap 设备一个 vzalloc 分配的数组,记录每个 swap 槽位归属的 memcg ID)和 zeromapkvmalloc 分配的 bitmap,记录零填充页)。这两者都是"全或无"式分配——无论 swap 设备是否被实际使用,挂载时即全额分配。对于 1TB 的 swap 设备,仅 swap_cgroup_ctrl 就需要约 512MB 内存(每个槽位 2 字节)。此外,匿名页(anon)和 shmem 的大页 swapin 走不同的分配路径,各有自己的 fallback 逻辑和 swap cache 检查;memcg 归属检查在缺页异常的页表遍历(page table walk)阶段进行,与 swap 层的 cluster 锁保护脱节,增加竞态窗口。

该系列是 swap 表重构的第四阶段,建立在前期工作(第一阶段引入 per-cluster swap_table 替换全局 swap_map 数组,第二阶段引入 swap_cluster_info 和 cluster 锁,第三阶段支持基于 folio 的 swap cache 操作)之上。

解决的问题

  • 静态元数据内存开销巨大:1TB swap 设备挂载时约 512MB 被立即消耗,不管实际使用了多少 slot。
  • anon 和 shmem 的 large folio swapin 路径重复:各自实现分配、fallback、swap cache 竞态检查,代码分散在 mm/memory.c 和 mm/shmem.c 中。
  • swap cache 分配 API 语义混乱swap_cache_alloc_folio 返回已存在的 folio 或新分配的 folio 或 NULL,调用者需要额外的 bool *alloced 输出参数来区分。
  • memcg 检查与 cluster 锁脱节swap_pte_batch() 在页表遍历时查询 cgroup ID,此时并未持有 cluster 锁,存在 TOCTOU 竞态。
  • zeromap 是独立的 bitmap:每次读写需要额外的 set_bit/clear_bit/test_bit 原子操作。

如何做

该系列的核心设计思想是:将 swap 的所有元数据(swap table entry、zero flag、cgroup ID)全部折叠进 per-cluster 的动态分配结构中,彻底消除全局静态数组。

1. API 重构(patch 1-2)。swap_cache_alloc_folio 不再返回已有 folio 作为成功,而是返回 ERR_PTR。新增 swap_cache_read_folio 封装"读取或返回已有缓存"语义,内部在 -EEXIST 时自动重试。新增 __swap_cache_add_check 独立检查函数,在 cluster 锁下原子地验证整个范围的所有 slot 状态。这为后续统一 large folio 分配铺平道路。

2. Large folio 分配统一(patch 4-5)。 核心是引入 swap_cache_alloc_folio 的带 orders 位掩码版本和新的 swapin_sync 统一入口。swapin_sync(entry, gfp, orders, vmf, mpol, ilx) 替代了原先的 alloc_swap_folio(anon 端在 do_swap_page 中调用)和 shmem_swap_alloc_folio(shmem 端),在紧凑的循环内完成:检查 swap cache 是否已有 folio -> 尝试按最高 order 分配 -> 在 cluster 锁下验证整段 slot 可用 -> 添加 folio 到 swap cache -> 发起 IO。如果遇到 -EEXIST 竞态则重试,如果遇到 -EBUSY(slot 被不兼容的 zeromap 或 memcg 占用)则 fallback 到下一 order。

// 统一入口,anon和shmem均调用此函数
struct folio *swapin_sync(swp_entry_t entry, gfp_t gfp, unsigned long orders,
                           struct vm_fault *vmf, struct mempolicy *mpol, pgoff_t ilx)

3. memcg 数据迁移到 cluster(patch 8, 10, 11)。 在 swap_pte_batch() 中删除了 lookup_swap_cgroup_id() 调用,将 memcg 检查推迟到 __swap_cache_add_check() 中在 cluster 锁保护下执行。新增 per-cluster 的 swap_memcg_table 结构(unsigned short id[SWAPFILE_CLUSTER],大小 512/1024 字节,通过 kzalloc 分配),提供 __swap_cgroup_set__swap_cgroup_get__swap_cgroup_clear 三个 cluster 锁保护的访问函数。最后完全删除 mm/swap_cgroup.c 和 include/linux/swap_cgroup.h

4. zeromap 内联(patch 12)。 在 64 位系统上,swap table entry 有足够的 bit 空间同时容纳 PFN 和 flag,因此将 zero flag 作为 SWP_TB_ZERO_FLAG 存入 entry 的高 bits 中。在 32 位系统上,PFN 可能占据过多 bit 导致没有剩余空间,此时回退到 per-cluster 的 zero_bitmap。zeromap 的设置和清除需要持有 folio 锁和 cluster 锁(由 swap_zeromap_folio_set/clear 内部获取),保证了与 swap cache 操作的一致性。

5. 批量 memcg 释放优化(patch 7)。__swap_cluster_free_entries 在释放 slot 时,对连续相同 memcg 的 slot 进行批处理,减少 mem_cgroup_uncharge_swap 调用次数。

收益

测试场景
配置
Before
After
改善
静态内存开销(1TB swap)
free -m
 used
805 MB
277 MB
-528 MB (65.6%)
每槽位静态开销
理论值
~2 bytes/slot
~0.094 bytes/slot
-95.3%
Redis GET benchmark
2G VM + 6G ZRAM
3,385,017 RPS
3,433,309 RPS
+1.42%
Kernel build (make -j96)
48c96t + 8G RAM + 12G ZRAM + THP
sys 4773.99s
sys 4641.55s
-2.77%
usemem throughput
32c + 48G brd + 16G RAM
6482.58 MB/s
6539.28 MB/s
+0.87%
VM_FAULT_OOM 错误数
高压测试
18 次
0 次
完全消除

作者指出:"挂载 1TB swap 设备可节省约 512MB 内存",且"现在每个槽位约 0.09375 字节(每个 cluster 48 字节 ci info,覆盖 512 个 slot)"。在高压测试中,"不再看到任何 'Huh VM_FAULT_OOM leaked out to the #PF handler' 错误"。

值得注意的是,该系列删除了整个 swap_cgroup.c 文件,将元数据管理从全局静态分配彻底转为按需动态分配。未使用(空闲)的 cluster 完全不分配元数据表,进一步压缩了实际开销。


2. ZONE_DEVICE memmap 初始化加速

系列[PATCH 0/4] mm: speed up ZONE_DEVICE memmap initialization作者: Li Zhe版本: v1(4个patch)

背景

memmap_init_zone_device() 负责初始化 ZONE_DEVICE 类型内存区域(如 PMEM、DAX 设备)的 struct page 元数据。对于大容量设备(例如 100GB 的 PMEM 命名空间),这意味着对数十万乃至上百万个 PFN 逐一调用 __init_zone_device_page(),每次调用重复设置几乎完全相同的 struct page 字段——包括 __init_single_page 的基本初始化、zone 和 node 设置、pgmap 指针赋值等。在热路径(如 nd_pmem 驱动的 bind/rebind)中,这个初始化延迟可达数百毫秒,影响设备的启动和重配置响应时间。

解决的问题

  • 逐 PFN 初始化重复无效工作:每个 struct page 的绝大部分字段在同一个 ZONE_DEVICE 区域内是完全相同的,但现有代码对每个 PFN 都重新计算和写入一遍。
  • compound page 的 tail page 初始化同样走慢路径:当 pfns_per_compound > 1 时(如 devdax 的 2MB 对齐),每个 tail page 也独立调用完整初始化流程。
  • 编译器生成的运行时复制循环效率不足:简单的模板复制可能导致编译器发出低效的 memcpy-like 循环。

如何做

该系列采用"模板复制 + 架构优化存储指令"策略,分四步实现加速。

1. 函数拆分(patch 1)。 将 __init_zone_device_page 拆分为三个独立部件:zone_device_page_init_refcount() 根据 pgmap->type 决定初始 refcount、generic_init_zone_device_page_slow() 执行通用 struct page 字段初始化(调用 __init_single_page、设置 zone/node/pgmap 等)、zone_device_page_init_pageblock() 处理 pageblock 的 migratetype 标记。拆分后的函数保持慢路径行为不变,但各个部件可被快路径复用。

2. 模板化头页快路径(patch 2)。 在 64 位系统上,先用慢路径构建一个"模板 page",然后在热路径循环中将模板直接复制到每个目标 page。复制后仅修复 PFN 相关的两个字段:SECTION_IN_PAGE_FLAGS 中的 section 编号和 WANT_PAGE_VIRTUAL 中的 page->virtual。构建时检查 sizeof(struct page) 是 u64 对齐的(BUILD_BUG_ON)。当 page_ref_set tracepoint 活跃时自动退回到慢路径,因为模板复制绕过了 set_page_count()

3. 模板化 compound tail 快路径(patch 3)。 为 compound page 的 tail pages 构建独立的 tail 模板(通过 prep_compound_tail() 设置 compound 链接信息)。由于同一 compound 内所有 tail 共享相同的 compound 状态,一个 tail 模板可复用于整个 compound 的 tail 范围。每个 tail page 的初始化简化为模板复制 + PFN 字段修复。

4. 架构优化存储指令(patch 4)。 引入 arch_optimize_store_u64() 和 arch_optimize_store_drain() 接口及 x86-64 MOVNTI/SFENCE 实现。模板复制采用展开的固定偏移量 u64 存储序列(switch (sizeof(struct page)) fallthrough 展开),而非运行时循环。这确保编译器生成固定偏移的存储指令链而非 memcpy 调用。x86-64 的 MOVNTI(Move Non-Temporal)指令是流式写入模式,避免常规缓存存储对 CPU 缓存的污染——这对"写入一次、几乎不再读取"的 ZONE_DEVICE struct page 非常合适。SFENCE 确保在 compound head 初始化前和函数返回前所有 non-temporal 存储已排空。在 KASAN/KMSAN 构建下退回到通用版本(普通存储),因为 sanitizer 依赖编译器插桩的存储。

收益

测试环境:Intel Ice Lake 服务器上的虚拟机,两个 PMEM 配置各 rebind 30 次取稳态平均值。

测试配置
指标
Base (v7.1-rc3)
完整系列
改善
nd_pmem rebind, 100 GB fsdax, map=dev
首次绑定
1486 ms
1272 ms
-14.4%
nd_pmem rebind, 100 GB fsdax, map=dev
稳态 rebind 平均
273.52 ms
104.59 ms
-61.8%
dax_pmem rebind, 100 GB devdax, align=2MB
首次绑定
1515 ms
1286 ms
-15.1%
dax_pmem rebind, 100 GB devdax, align=2MB
稳态 rebind 平均
313.45 ms
116.93 ms
-62.7%

作者在封面信中总结:"memmap_init_zone_device() 在初始化大容量 ZONE_DEVICE 范围时会花费大量时间,因为它对每个 PFN 都重复几乎完全相同的 struct page 设置。" 经过优化后,100GB 设备的稳态 rebind 延迟从约 300ms 降至约 110ms,加速比约 2.6 倍。

该系列的优化仅限于 64 位系统("有意限制在 64 位构建"),因为模板复制依赖 struct page 的固定布局和 u64 对齐存储。作者指出 arm64 等架构可以在后续工作中添加自己的优化后端。


3. shmem:通过 folio 批量化与无锁读取优化读性能

系列[RFC PATCH 0/4] mm/shmem: optimize read performance with folio batching作者: Chi Zhiling版本: RFC v1(4个patch)

背景

shmem(tmpfs)是 Linux 内核中广泛应用的内存文件系统,其读路径 shmem_file_read_iter() 长期以来以逐页(per-page)方式获取 folio 并立即解锁后执行 copy 操作。由于 shmem 读取发生在 i_rwsem 保护之外,folio_lock 在获取 folio 后立刻锁-解锁的模式实际提供了极为有限的保护——folio_lock 虽然能在持锁期间防止 truncate 并发,但一旦解锁,truncate 同样可以发生。在这种情况下,"作者指出 folio 引用计数才是真正在访问期间阻止回收的机制,lock 是多余的"。此外,这一逐页获取的模式意味着每次迭代都需要一次 shmem_get_folio() 调用,涉及 page cache 查找和锁操作,在高吞吐场景下成为瓶颈。

解决的问题

  • 冗余的 folio lock/unlock 开销shmem_file_read_iter()shmem_file_splice_read() 和 shmem_get_link() 三个函数在获取 folio 后立即解锁然后再读数据,lock 保护无实际意义却引入了不必要的原子操作开销。
  • 逐页获取导致的 page cache 查找放大:在大块顺序读场景下,每次迭代都单独查找 page cache,无法利用 xarray 的顺序遍历能力,cache miss 和锁争用随块大小减小而加剧。
  • SGP_NOALLOC 语义不一致SGP_READ/SGP_GET 在空洞(hole)时返回 0 和 NULL folio,而 SGP_NOALLOC 却返回 -ENOENT,调用方(khugepaged、userfaultfd)需要特殊处理。

如何做

该系列的核心思路是两阶段优化:先消除不必要的锁操作,再在解耦后的读路径上实现批量 folio 获取。

阶段一:引入 SGP_GET 无锁模式(Patch 1-2)。新增 sgp_type SGP_GET,它与 SGP_READ 的区别在于跳过 folio_lock() 和 mapping 一致性检查,仅依赖 refcount 和 Uptodate 标志保障安全。关键代码路径在 shmem_get_folio_gfp() 中:当 folio 存在且 sgp == SGP_GET 时,检查 folio_test_uptodate() 后直接跳转到 out 标签返回,不执行锁操作。作者明确说明这一设计的约束:"调用方不得依赖 folio->mapping 的有效性,因为它在并发 truncate 下可能已经失效"。然后 Patch 2 将三个读函数中的 SGP_READ 替换为 SGP_GET,并移除后续的 folio_unlock() 调用。

阶段二:实现 folio 批量化读取(Patch 3)。引入两个新的辅助函数。shmem_get_read_batch() 利用 XA_STATE 和 xas_for_each() 在 RCU 读锁保护下遍历 page cache xarray,收集连续的已 uptodate folio 放入 struct folio_batch。关键细节:遇到 xa_is_value()(swap entry)时停止批量化;通过 folio_try_get() + xas_reload() 双重确认避免竞态;只收集已 uptodate 的 folio,保证批内的所有 folio 立即可用。shmem_get_folio_from_batch() 则作为统一接口:先尝试从已有的 fbatch 中获取 folio,若批已耗尽则调用 shmem_get_read_batch() 重新填充,只有当批填充也失败时才回退到单次 shmem_get_folio()。在 shmem_file_read_iter() 中,folio_put() 被推迟——单个 folio 不再在每次迭代结束时释放,而是在整个读循环结束后对 fbatch 做统一释放。

阶段三:统一 hole 语义(Patch 4)。将 SGP_NOALLOC 改为在空洞时同样返回 0 和 NULL folio,与 SGP_READ/SGP_GET 一致。shmem_get_folio_gfp() 中的条件从 if (sgp == SGP_READ || sgp == SGP_GET) 简化为 if (sgp <= SGP_NOALLOC),利用枚举值顺序消除分支。

收益

测试环境:fio,配置 --ioengine=sync --rw=read --size=1G --runtime=120

场景
块大小
基准带宽
+fbatch 后
提升
shmem (THP 关闭)
1M
11.4 GiB/s
12.8 GiB/s
+12%
shmem (THP 关闭)
64K
11.1 GiB/s
12.3 GiB/s
+11%
shmem (THP 关闭)
4K
3814 MiB/s
3783 MiB/s
-0.8%
shmem (THP 开启)
1M
13.8 GiB/s
14.0 GiB/s
+1%
shmem (THP 开启)
64K
13.1 GiB/s
13.4 GiB/s
+2%
fallocate 预分配 (THP 关闭)
1M
24.0 GiB/s
29.3 GiB/s
+22%
fallocate 预分配 (THP 关闭)
64K
22.5 GiB/s
26.7 GiB/s
+19%
fallocate 预分配 (THP 开启)
1M
24.0 GiB/s
34.3 GiB/s
+43%
fallocate 预分配 (THP 开启)
64K
22.9 GiB/s
31.5 GiB/s
+38%

4. slab:运行时 sheaf 容量与 barn 限制可调

系列[PATCH RFC 0/8] mm/slab: enable runtime sheaves tuning作者: Harry Yoo版本: RFC v1(8个patch)

背景

Sheaf 机制于 v6.18 引入内核,自 v7.0 起对所有 slab cache(除 kmem_cache 和 kmem_cache_node 外)默认启用。Sheaf 取代了原先的 cpu_partial 机制,将 per-CPU 缓存对象组织为固定容量的 "束"(sheaf),通过 cpu 本地锁保护的无锁快速路径进行分配和释放,大幅提升了 slab 分配器的 per-CPU 缓存效率。然而,sheaf 的容量(sheaf_capacity)在缓存创建时确定后不可更改,且管理 barn(全局空/满 sheaf 池)的 MAX_FULL_SHEAVES 和 MAX_EMPTY_SHEAVES 两个阈值为硬编码常量 10,用户无法根据工作负载特征调优。作者的明确目标是"在下一个 LTS 之前使 sheaf 可以运行时调优"。

解决的问题

  • sheaf_capacity 不可调:pre-sheaf 时代有 cpu_partial 参数可供调节每 CPU 缓存的对象数量,sheaf 没有等价机制,"sheaf 容量在内核代码中确定且之后无法更改"。
  • MAX_FULL_SHEAVES / MAX_EMPTY_SHEAVES 为硬编码常量:作者指出需要让用户可调以便测量影响。
  • 结构体 slab_sheaf 膨胀:原始设计中每个 sheaf 存储了 struct kmem_cache *cache 指针(32字节占一个指针位),且容量使用 unsigned int(4字节),对高频分配释放的每个 sheaf 都存在空间浪费。

如何做

该系列从数据结构精简入手,逐步构建运行时容量切换的安全机制,最终暴露 sysfs 接口。

数据结构精简(Patch 1-3)。首先从 struct slab_sheaf 中删除 cache 指针——它仅在 RCU 释放慢路径中使用,通过 virt_to_slab(sheaf->objects[0])->slab_cache 即可获取,无需在每个 sheaf 中存储。然后将 capacity 从 unsigned int 改为 unsigned short(2字节),因为单个 sheaf 容量不可能超过约 2^15 个对象(受 slab order 限制)。最后将 capacity 字段提升为 per-sheaf 通用字段(而非仅 prefilled sheaf 使用),并消除与 pfmemalloc 的 union 共享。最终 struct slab_sheaf 从 32 字节缩减到 24 字节(不含变长 objects[] 数组)。

运行时容量切换的安全框架(Patch 4-6)。在 struct slub_percpu_sheaves 中新增 capacity 字段,实现 per-CPU 容量副本。切换流程为:(1) 禁用 sheaf——对所有在线 CPU,在 local_lock 保护下将 pcs->main 替换为 bootstrap_sheaf;(2) 等待 RCU 回调完成——rcu_barrier() 确保所有飞行中的 RCU sheaf 已返回 barn;(3) 收缩缓存——__kmem_cache_do_shrink() 刷新并释放所有现有 sheaf;(4) 重新启用——为每个 CPU 预分配新容量的 sheaf 并通过 workqueue 安装。

解决并发竞态的核心机制是 per-CPU 容量副本 + local_lock 生涯规则。三条新规则:(a) 存取 barn 时必须持有 local_lock;(b) 分配新 sheaf 后在重新获取 local_lock 后检查 pcs->capacity == sheaf->capacity;(c) 若 local_trylock 失败则刷新并释放 sheaf。由此保证"过程中不留下任何具有过期容量的 sheaf"。

cache_has_sheaves() 重构(Patch 5)。拆分为 cache_supports_sheaves()(基于不可变属性)和 pcs_has_sheaves()(检查 CPU 是否实际启用了 sheaf),解决了两个不同问题的混淆。

sysfs 接口暴露(Patch 6 & 8)。sheaf_capacity 从只读改为可写,写入新值时执行上述四步切换流程,使用 slab_mutex 串行化并发写入。max_full_sheaves 和 max_empty_sheaves 作为新的 per-cache 字段和 sysfs 属性直接可写。默认值保持为 10,保持向后兼容。

收益

作者未提供性能数据。封面信中明确说明:"这些可调参数的性能影响测量待完成"。从代码逻辑推断的预期收益:

  • 数据结构内存节省:每个 sheaf 从 32 字节缩减到 24 字节,节省 25% 的元数据开销。对于拥有数千活跃 sheaf 的大型系统,累计节省可达到数十到数百 KB。
  • 可调优性sheaf_capacity 运行时可调允许管理员在吞吐量与内存占用之间取得平衡;max_{full,empty}_sheaves 可调允许控制全局 barn 池的大小和周转行为。
  • 无性能退步保证:容量切换走 workqueue + rcu_barrier + shrink 的完全同步路径,确保常规快速路径不受影响。新增的 pcs_capacity_match() 检查在快速路径中仅比较两个 unsigned short,开销可忽略。

5. BPF Arena 内核侧直接访问支持

系列[PATCHSET v2 sched_ext/for-7.2] bpf/arena: Direct kernel-side access作者: Tejun Heo, Kumar Kartikeya Dwivedi版本: v2(8个patch)

背景

BPF arena 是一种允许 BPF 程序使用 __arena 指针直接解引用的大块内存映射区域,其页表是稀疏填充的——只有 BPF 程序通过 bpf_arena_alloc_pages() 分配后的地址才有真实物理页,未分配的 PTE 保持为空,访问会触发缺页异常。在此之前,内核代码无法安全地写入 arena 内存:内核侧的 arena 解引用如果命中空 PTE 会直接触发 Oops,导致内核崩溃。这迫使内核与 BPF 之间通过 arena 共享数据时采用笨拙的方案:内核将数据放在自己的内存中,以 "trusted pointer" 形式传递给 BPF 程序,BPF 程序通过 probe_read 逐字拷贝到 arena 内存中。sched_ext 的 ops.set_cmask() 正是这样一个典型案例——内核构造好 cpumask 后,BPF 侧必须通过 cmask_copy_from_kernel() 逐字节探测读取,效率低下且代码臃肿。

解决的问题

  • 内核 kfunc 和 struct_ops 回调无法直接写入 BPF arena 内存,未分配地址的内核访问会导致 Oops
  • BPF 程序需要在 arena 和非 arena 内存之间做额外的数据拷贝(如 cmask_copy_from_kernel() 探测读取循环)
  • 缺乏一种通用机制让内核 struct_ops 子系统自动发现 BPF 程序使用的 arena

如何做

该系列的核心思想是为每个 arena 分配一个 scratch page(单页,per-arena 共享),当内核代码访问 arena 内未分配的地址时,通过架构层面的缺页处理 hook 原子地为空 PTE 安装 scratch page,使访问指令能够重试执行,同时将违规访问通过 BPF stream 上报给程序。

具体实现分为三个层次:

第一层:无锁 PTE 安装基础设施。 Patch 1 引入 ptep_try_install(ptep, new_pte),原子地将一个空的 PTE 设置为新值当且仅当 PTE 当前为 pte_none()。x86 和 arm64 使用 try_cmpxchg 实现覆盖版本,其他架构返回 false(后续流程回退到正常 Oops)。这种无锁设计至关重要——缺页处理可能与缺页调用者已持有的锁冲突。

第二层:内核缺页恢复路径。 Patch 2 实现了核心函数 bpf_arena_handle_page_fault(),分别在 x86 的 page_fault_oops() 和 arm64 的 __do_kernel_fault() 中、KFENCE 处理之后被调用。该函数通过 bpf_prog_find_from_stack() 从内核栈回溯当前运行的 BPF 程序及其 arena,然后检查故障地址是否落在 arena 映射区 + 上半 guard(GUARD_SZ / 2)范围内。如果命中,则将 scratch page 安装到目标 PTE。违规访问通过 __bpf_prog_report_arena_violation() 上报给程序的 bpf_stream。用户侧对 scratched 地址的访问会触发 SIGSEGV。

第三层:sched_ext 集成。 Patches 4-5 添加了 bpf_struct_ops_for_each_prog() 和 bpf_prog_arena() 两个辅助函数,供 struct_ops 注册回调发现 BPF 程序引用的 arena map。Patch 6 强制要求 cid-form 调度器必须引用恰好一个 arena。Patch 7 构建了一个基于 gen_pool 的子分配器,让内核在 arena 内部管理自己的内存。Patch 8 将 set_cmask 转换为直接写入 arena 内存。

作者将这种 kfunc 合约总结为:"因此,被传递了 arena 指针的 kfunc 可以访问超出 arena 边界最多 GUARD_SZ / 2 的范围而无需进行边界检查。更大的访问必须显式验证范围。"

收益

作者未提供性能数据。从代码逻辑推断的预期收益:

  • 消除了 sched_ext 中 cmask_copy_from_kernel() 的逐字节探测读取开销
  • 为未来更多 sched_ext 回调通过 arena 直接传递结构化数据奠定了基础
  • 任何 kfunc 或 struct_ops 回调都可以安全地内联写入 arena,无需额外的边界检查和拷贝,简化了内核-BPF 共享内存编程模型
  • 保留了稀疏 PTE 设计的全部调试特性——BPF 程序侧的缺页语义不变,内核侧首次触碰未分配地址会通过 bpf_stream 上报违规

6. 移除 CONFIG_READ_ONLY_THP_FOR_FS,为可写文件启用文件透明大页

系列[PATCH v6 00/14] Remove CONFIG_READ_ONLY_THP_FOR_FS and enable file THP for writable files作者: Zi Yan版本: v6(14个patch)

背景

CONFIG_READ_ONLY_THP_FOR_FS 是早期为不支持大页(large folio)的文件系统提供文件级透明大页支持的配置选项。它允许 khugepaged 和 MADV_COLLAPSE 在只读文件上创建 PMD 级别的文件映射大页。然而该机制与原生支持 large folio 的文件系统走的是两套不同路径:前者的文件 THP 通过 mapping->nr_thps 计数器和 inode->i_writecount 保护,在文件变为可写时截断所有只读 THP;后者由文件系统自身的 page fault 路径分配 large folio,但 khugepaged 和 MADV_COLLAPSE 却无法对这些大型页文件系统创建的文件 THP 进行collapse。这导致了能力分布不均的割裂局面:

配置
Page Fault
MADV_COLLAPSE
khugepaged
仅 large folio 文件系统
仅 READ_ONLY_THP_FOR_FS
两者都配置

解决的问题

  • 不配备大页支持的文件系统通过 READ_ONLY_THP_FOR_FS 能创建只读文件 THP,而本身支持 large folio 的文件系统反而不支持 khugepaged/MADV_COLLAPSE collapse,造成语义混乱
  • 内核同时维护两套文件 THP 创建机制(nr_thps 跟踪 vs. mapping folio order 检查),代码复杂度高
  • 可写文件的干净 pagecache folio 无法被 khugepaged collapse
  • truncate_inode_partial_folio() 中必须通过 try_folio_split_to_order() 处理 "非统一 split" 的边界情况

如何做

该系列采用渐进式策略:先启用功能保证不退化,再删除配置选项,最后扩展到可写文件。

统一 THP 判定逻辑。 Patch 1 用新引入的 mapping_pmd_folio_support(mapping) 替换 collapse_file() 中的 CONFIG_READ_ONLY_THP_FOR_FS 检查。新函数检查 mapping_min_folio_order() <= PMD_ORDER && mapping_max_folio_order() >= PMD_ORDER,确保该文件系统的 large folio 支持范围覆盖 PMD 阶。Patch 2 在 collapse_file() 中添加脏页检查——在 folio 锁定且已从所有 PTE 卸载后,再次检查 folio_test_dirty(),跳过脏 folio。

删除配置并清理。 Patch 5 正式删除 CONFIG_READ_ONLY_THP_FOR_FS Kconfig。Patches 6-7 删除 filemap_nr_thps*() 函数族和 struct address_space 中的 nr_thps 字段。Patch 9 将 truncate_inode_partial_folio() 中的 try_folio_split_to_order() 替换为直接调用 folio_split(),因为 READ_ONLY_THP_FOR_FS 删除后所有大 pagecache folio 必然出现在支持 large folio 的文件系统上。

扩展到可写文件。 Patch 13 是关键扩展:从 file_thp_enabled() 中删除 inode_is_open_for_write() 检查,使 khugepaged 和 MADV_COLLAPSE 可以对可写文件操作。collapse_file() 中的 filemap_flush() 调用被条件化为仅对只读文件执行——避免对可写文件的脏页进行系统级 writeback。对于可写文件,用户空间必须显式刷回脏数据,或使用 MADV_COLLAPSE,后者通过其 writeback-and-retry 路径自动处理 flush。

删除后的最终兼容矩阵:

场景
PF
MADV_COLLAPSE
khugepaged
large folio FS (只读 fd)
large folio FS (可写 fd)
✓*
无 large folio FS

*可写文件仅 clean folio 能被 khugepaged collapse。

收益

作者未提供性能数据。从代码逻辑推断的预期收益:

  • nr_thps 机制和 try_folio_split_to_order() 等专用函数被移除
  • 将两套并行的文件 THP 机制统一为基于 mapping folio order 的单一判定逻辑,降低了维护负担和出错概率
  • 原本不支持 MADV_COLLAPSE 和 khugepaged 的 large folio 文件系统现在获得了完整的文件 THP collapse支持,可有效减少文件映射的 TLB miss
  • 可写文件的干净 pagecache 现在可以被 khugepaged collapse,这对数据库等需要定期 flush 并使用文件映射的工作负载尤为有利

7. DAMON 数据属性监测

系列[RFC PATCH v3 00/28] mm/damon: introduce data attributes monitoring作者: SeongJae Park版本: RFC v3(28个patch)

背景

DAMON(Data Access MONitor)最初设计为只监控内存访问模式(冷/热分布),并被扩展到基于访问信息的数据访问感知系统操作(DAMOS)。然而实际用户需要更全面的内存视图,例如:想了解 DAMON 发现的热区域中有多少是由大页(huge page)后盾的,或者特定 cgroup 中有多少热/冷内存。为此,社区在 6.14 内核中合入了基于 DAMOS 的页级别属性监控——通过对 DAMON 区域内每个 folio 应用 DAMOS 过滤器来确定属性归属。但这种方法以页粒度遍历,开销与内存大小成正比,作者指出:"它显然太重了,无法在所有运行真实用户工作负载的机器上持续启用。" 用户被迫采用采样控制(如每小时仅在一台机器上运行一次),而这对于忙碌的运维团队来说实现成本太高。

解决的问题

  • 现有的 DAMOS 页级别属性监控开销与内存量成正比,无法在所有生产机器上持续启用
  • 用户缺少一种轻量级的手段来了解 DAMON 监控的热/冷内存背后的内存类型信息(如大页归属、cgroup 归属)
  • DAMON 架构设计上只将访问作为一等信息,缺乏通用数据属性框架,限制了未来扩展(如 page fault 事件、PMU 事件作为访问源)

如何做

核心设计理念是复用 DAMON 已有的采样机制来实现零额外采样开销的数据属性监控。DAMON 每次采样都是随机选取区域内某个物理地址检查其访问位,本系列在此采样点上同时应用用户注册的 "data probe"。

新的核心数据结构。 Patch 1 引入 struct damon_probe,初始只是一个链表节点,后续扩展为包含 damon_filter 过滤器链表的数据属性探针。Patch 2 在 damon_ctx 中嵌入 probes 链表头,提供 damon_new_probe()damon_add_probe() 等管理 API。Patch 3 引入 struct damon_filter,其结构与 DAMOS filter 类似,支持按类型(匿名页、大页、memcg 等)和匹配函数过滤。

区域级别计数器。 Patch 5 在 damon_region 中新增 probe_hits 数组——每个区域维护每个 probe 的正采样计数器,与 nr_accesses 并行更新和重置。Patch 6 在 struct damon_operations 中新增 apply_probes 回调。Patch 7 是核心调度变更:在 kdamond_fn() 的每个采样周期中,当进行访问检查时同步调用 ops->apply_probes(ctx),对每个采样地址的内存应用所有已注册的 probes。Patch 8 在 paddr ops 中实现了完整的 probe 应用逻辑。

用户接口。 Patches 9-18 实现了完整的 sysfs 接口:在 /sys/kernel/mm/damon/admin/kdamonds/<N>/contexts/<N>/ 下新增 monitoring_attrs/probes/ 目录,每个 probe 目录下包含 filters/ 目录用于配置探测条件,并在 tried_regions/<R>/probes/ 下通过 hits 文件暴露每个区域的 probe 命中数。

Memcg 支持。 Patches 22-28 新增 DAMON_FILTER_TYPE_MEMCG:该 filter 匹配属于特定 memory cgroup 的 folio。用户通过 sysfs 的 path 文件设置目标 cgroup 路径,系统将其解析为 memcg_id。这使得用户可以了解热/冷内存在各 cgroup 间的分布比例。

在长期规划中,作者设想 DAMON 将演化为 "Data Attributes Monitoring and Operations eNgine"——用户可以将任何数据属性(page fault 确认的访问、PMU 事件确认的访问)设为 "primary" 属性,DAMON 据此拆分/合并区域,DAMOS 据此选择操作目标。

收益

作者未提供性能数据(RFC 阶段)。从设计原则推断的预期收益:

  • 属性监控开销与 DAMON 访问监控采样开销相同——即 bounded and best-effort minimum overhead,因为采样时机被复用,无额外缺页或遍历;
  • 对 100% 的生产机器持续启用成为可能,无需用户空间采样控制,显著降低运维复杂度;
  • 为 DAMON 的多源访问采样提供统一的属性框架。

8. DAMON 硬件采样访问报告与 AMD IBS 后端

系列[RFC PATCH 0/7] mm/damon: hardware-sampled access reports + AMD IBS Op example作者: Ravi Jonnalagadda版本: RFC v1(7个patch)

背景

DAMON 现有的访问检测原语(PTE Accessed-bit 扫描和缺页采样)全部通过软件路径观测内存访问:PTE A-bit 扫描依赖 TLB 缺失时硬件设置 Accessed 位后 DAMON 周期性清空并读取,对 TLB 驻留的翻译会产生"盲区";缺页采样则需要先解映射(unmap)页面才能触发缺页。这两种原语产生的热页视图需要在一个聚合间隔(aggregation interval)内逐渐收敛到真实分布。在大规模异构内存系统上,当闭环比率控制器(goal-driven schemes)需要快速收敛到目标分布时,这种收敛延迟会导致"ramp duration 和 oscillation amplitude"增大。如作者所言:"一个互补的低延迟访问视图可以收紧控制环路——减少 DAMON 的 nr_accesses 反映工作负载实际访问分布所需的时间"。

解决的问题

  • DAMON 现有的软件访问观测原语在 TLB 常驻场景下低估访问频率,对大容量异构内存系统的闭环比率收敛造成延迟
  • damon_report_access() 原有的 mutex 保护固定数组无法从 NMI 上下文中调用,无法接收硬件采样器的报告
  • 报告排空循环为 O(reports x regions) 复杂度,在大 CPU 数 x 大 region 数的情况下会导致无界积压
  • 模块化的 ops 后端可能在卸载时造成 use-after-free(UAF)

如何做

基础设施改造(Patch 1/3/4):

Patch 1 在 struct damon_operations 中加入 struct module *owner 字段,通过 try_module_get()/module_put() 确保模块卸载与 ctx 安全解耦。

Patch 3 将原来的 mutex 保护固定大小数组(DAMON_ACCESS_REPORTS_CAP=1000)替换为每 CPU 无锁环形缓冲区。设计要点:每个 CPU 的生产者通过 per-CPU damon_report_ring_busy 计数器检测 NMI-on-process 嵌套;head 由生产者通过 smp_wmb() 后推进;tail 由消费者(kdamond)读取 entries[] 后推进;head/tail/entries[] 分别置于独立 cache line(____cacheline_aligned_in_smp)。

Patch 4 将 drain 循环从 O(reports x regions) 线性扫描优化为 O(reports x log2(regions))。drain 开始时将每个 target 的 region 数组快照到扁平数组,region 天然按 r->ar.start 升序排列,使用二分查找定位 ring entry 对应的 region。

IBS 后端(Patch 2/5/6/7):

Patch 7 是核心的 AMD IBS 后端(mm/damon/damon_ibs.c)。利用 perf_event_create_kernel_counter() 创建 per-CPU IBS Op 采样事件,通过 cpuhp notifier 管理 CPU 热插拔。采样回调 damon_ibs_overflow_handler() 在 NMI 上下文运行:通过检测 data->sample_flags & PERF_SAMPLE_PHYS_ADDR 判断 IBS_OP_DATA3.dc_phy_addr_valid;从 data->data_src.mem_op 解码 load/store 方向;填充 struct damon_access_report 后调用 damon_report_access() 提交。模块参数 max_cnt 可写(默认值 262144,约 4K samples/sec/core)。

收益

作者在 AMD EPYC 双路服务器、CXL.mem 独立 NUMA 节点、32GB 热工作集的配置上进行了闭环验证:

测试场景
目标 DRAM 占比
实测均值
偏差
标准差
冷启动收敛
70% DRAM
69.73%
-0.27pp
0.70pp
冷启动收敛
30% DRAM
31.00%
+1.00pp
1.28pp
在线目标切换
90% DRAM
89.74%
-0.26pp
0.64pp
在线目标切换
85% DRAM
84.61%
-0.39pp
0.60pp

所有场景在 15-30 分钟持续运行中,实测 DRAM 占比稳定在目标值的 1.3 个百分点以内,标准差不超过 1.3 个百分点。配置参数:256-entry per-CPU report ring、512 MiB per-scheme quota、1 秒 reset interval。


9. shmem:支持 gnu.* xattr 命名空间以兼容 Hurd

系列[PATCH] shmem: support xattr gnu.* namespace for the Hurd作者: Janneke Nieuwenhuizen版本: v1(1个patch)

背景

GNU Hurd 正在将 translator 和 author 字段从 inode 内移出并放到 "gnu.*" xattr 命名空间中存储。Linux 内核为此预留了 xattr INDEX(XATTR_HURD_PREFIX,commit 3980bd3b406a),Hurd 自身已完成合规改造,ext4 也已支持(commit 88ee9d571b6d)。但 tmpfs(shmem)尚未实现该命名空间支持。GNU Guix 使用 tmpfs 创建 Hurd 初始文件系统镜像时需要用 setfattr/getfattr 设置管道 translator 等属性,作者描述:"现在可以做类似...的事情来设置管道 translator,这正被用于从 GNU Guix 创建 Hurd 的初始文件系统镜像"。

解决的问题

  • tmpfs 不支持 gnu.translator 等 gnu.* 扩展属性,阻碍了 Hurd 从 Linux tmpfs 上引导的用例
  • 其他文件系统(如 ext4)已具备 gnu.* xattr 支持,而 tmpfs 是该生态系统中的缺口

如何做

在 mm/shmem.c 中新增一个 shmem_hurd_xattr_handler,其 prefix 设为 XATTR_HURD_PREFIX(即 "gnu."),get 和 set 复用已有的通用 shmem xattr 处理函数 shmem_xattr_handler_get 和 shmem_xattr_handler_set。将该 handler 注册到 shmem 的 xattr handler 数组 shmem_xattr_handlers[] 中,排在 security、trusted、user 之后。这是对现有 shmem xattr 机制的纯增量扩展——shmem 本身已有一套基于 simple_xattrs 的完整 xattr 存储、读取、写入路径,新增 gnu.* 命名空间只需要注册一个 handler 告诉 VFS:"我可以处理此前缀的 xattr"。

收益

作者未提供性能数据。这是一个纯功能启用(feature enablement)patch,不涉及性能路径变化。收益在于:Linux tmpfs 现在可以作为 Hurd 启动过程中的文件系统镜像创建工具,支持 setfattr --name=gnu.translator 等操作,消除了 Hurd/GNU Guix 从 Linux 交叉构建的生态系统障碍。


10. process_vm_readv/writev 支持 pidfd 和 NOWAIT

系列[PATCH v4 0/2] mm/process_vm_access: pidfd and nowait support for process_vm_readv/writev作者: Alban Crequy版本: v4(2个patch,含 selftest)

背景

process_vm_readv(2) / process_vm_writev(2) 有两类用户。第一类是调试器(如 GDB、strace),它们需要精确解析目标内存内容,page fault 必须被解决,且通常附着于单个进程。第二类是 profiler(如 OpenTelemetry eBPF Profiler),以 20Hz 频率从所有进程中采样栈回溯,对解释型语言(Ruby、Python 等)需要用 process_vm_readv 获取符号信息。在此场景下,"性能是最重要的。只要在统计上不显著,部分栈回溯无法解析是可以接受的。" profiler 不能忍受因某一个目标进程的后端文件系统慢速 IO 而阻塞所有其他目标进程的监控。此外,profiler 场景中 PID 重用可能导致读取到错误进程的内存。

解决的问题

  • 现有 process_vm_readv 无条件等待 page fault 解决,不适合 profiler 的低延迟需求
  • PID 参数可能被重用(尤其在 profiler 监控所有进程的场景),缺少 PID 文件描述符(pidfd)的稳定引用方式
  • 缺少内核级 flag 支持,用户态无法检测内核是否支持新 flag(flags != 0 直接返回 EINVAL

如何做

新增两个标志定义于 include/uapi/linux/process_vm_access.h

  • PROCESS_VM_PIDFD (1UL << 0):使用 pidfd 替代 PID 引用目标进程
  • PROCESS_VM_NOWAIT (1UL << 1):不阻塞等待 IO 完成 page fault

核心实现位于 mm/process_vm_access.c

Flag 校验与路由。 引入内核内部宏 PROCESS_VM_SUPPORTED_FLAGSprocess_vm_rw() 中将 flags & ~PROCESS_VM_SUPPORTED_FLAGS 替换原来的 flags != 0 检查,既保持向后兼容又允许用户态探测 flag 支持。

PIDFD 路径。 在 process_vm_rw_core() 中,当 flags & PROCESS_VM_PIDFD 时,调用 pidfd_get_task(pid, &f_flags) 获取任务引用(与 process_madvise() 风格一致)。如果 pidfd 无效,返回 EBADF

NOWAIT 路径。 在 process_vm_rw_single_vec() 中,当 pvm_flags & PROCESS_VM_NOWAIT 时设置 FOLL_NOWAIT 标志传递给 GUP。对于非驻留页面,返回短读(已成功读取的字节数)或 EFAULT(一个字节都没读到),语义与 O_NONBLOCK 惯例一致。

selftest。 新增 process_vm_readv 自测文件,覆盖:基本读、无效 flag、pidfd、NOWAIT、userfaultfd 阻塞/非阻塞、部分读等 10+ 场景。所有新 flag 测试在旧内核上通过 EINVAL 优雅 SKIP。

收益

作者未提供性能数据。从代码逻辑推断的预期收益:

  • PROCESS_VM_NOWAIT 避免了因后端文件系统慢速 IO 导致的 page fault 阻塞,保证 profiler 对多个目标进程的采样延迟不会因某个进程的单次 IO 而被放大
  • PROCESS_VM_PIDFD 消除了 PID 重用竞争
  • 用户态可通过 process_vm_readv(pid, NULL, 1, NULL, 1, PROCESS_VM_PIDFD) 检测内核是否支持新 flag(返回 EINVAL = 不支持,返回 EFAULT = 支持)

11. page_owner:per-fd filter 基础设施与 NUMA 过滤

系列[PATCH v7 0/4] mm/page_owner: add per-fd filter infrastructure for print_mode and NUMA filtering作者: Zhen Ni版本: v7(4个patch)

背景

在生产环境中,大内存配置(250GB+)下收集 page_owner 信息经常产生数 GB 到 10GB+ 的输出文件。作者指出:"在大内存配置(例如 250GB+)的生产环境中,收集 page_owner 信息经常产生数 GB 到超过 10GB 的输出文件。" 主要问题有三个方面:(1)存储压力——生产系统上生成的大文件难以存放;(2)传输困难——从生产环境拷贝大文件代价高昂;(3)后处理开销——tools/mm/page_owner_sort.c 需要对已在内核中通过 stackdepot 做过栈去重的数据再次去重。此外,在 DPDK 等 NUMA 绑定的云部署中,OOM 事件往往是节点级别的,但 page_owner 无法按 NUMA 节点过滤,只能收集全量数据。

解决的问题

  • page_owner 输出文件过大(可超 10GB),导致存储、传输、后处理三项开销
  • 每个页面都打印完整栈回溯,而 stackdepot 已在记录层面做了去重——输出时再次展开栈是冗余的
  • 无法按 NUMA 节点过滤,在 NUMA 感知的部署中无法针对特定节点定位 OOM 根因
  • 全局状态(之前的实现)无法支持多个并发读取者使用不同过滤条件

如何做

核心设计是 per-file-descriptor 过滤状态:每个 open() 持有独立的 struct page_owner_filter_state(存储于 file->private_data),通过 debugfs_create_file("page_owner", 0600, ...) 新增的 .write 文件操作接收过滤命令。

print_mode 过滤器(Patch 1)。 定义三种模式枚举 PAGE_OWNER_PRINT_{STACK,HANDLE,STACK_HANDLE},对应字符串 "stack""handle""stack_handle"。默认模式为 PAGE_OWNER_PRINT_STACK(向后兼容)。.write 解析 "mode=xxx" 命令(使用 sysfs_match_string() 匹配)。print_page_owner() 函数根据 state->print_mode 选择性地调用 stack_depot_snprint() 和 scnprintf("handle: %d\n", handle)

NUMA 节点过滤器(Patch 2)。 在 struct page_owner_filter_state 中加入 nodemask_t nid_filter 和 bool nid_filter_enabled.write 解析 "nid=..." 命令,使用 nodelist_parse() 支持灵活格式(单节点 0、多节点 0,2,3、范围 0-3、混合 0,2-4,7)。通过 nodes_subset(new_nid_filter, node_states[N_MEMORY]) 校验节点有效性。在 read_page_owner() 的 page 迭代循环中,通过 page_to_nid(page) 获取页面节点号后用 node_isset() 过滤。关键性能优化:nodemask_t(128 字节)在页面迭代循环外读取,避免每个 PFN 迭代都复制 128 字节结构体。

用户态工具(Patch 3)。 新增 tools/mm/page_owner_filter.c,提供命令行接口 ./page_owner_filter -m handle -n "0,2-3" -o output.txt。工具内建输入校验(模式合法性、NID 范围检查、start <= end),通过 write() 向 debugfs 文件发送过滤命令后 read() 输出到文件或 stdout。

文档(Patch 4)。 更新 Documentation/mm/page_owner.rst,加入过滤功能说明、使用示例和并发使用场景。

收益

作者在 4 节点 NUMA 系统上的测试显示:

指标
stack 模式
handle 模式
改善
输出大小
244MB
84MB
减少 ~66%
读取性能
1x(基线)
~4.4x
提升约 4.4 倍

NUMA 过滤的正确性通过了 26 项测试验证,包括单节点、多节点、范围、混合格式、越界拒绝、范围起始大于结束拒绝、handle+NUMA 组合过滤等。per-fd 设计允许在不同终端中并发运行不同的过滤命令(例如终端 1 过滤 node 0,终端 2 过滤 node 1),无协调冲突。


总结

性能优化

#
系列
量化数据
1
swap table phase IV
 [v5, 12p]
1TB swap 节省 528MB (65.6%);redis +1.4%;kernel build -2.8%
2
ZONE_DEVICE memmap 初始化加速
 [v1, 4p]
100GB PMEM 稳态 rebind 从 300ms 降至 110ms(-62%),加速比 2.6x
3
shmem folio batching
 [RFC, 4p]
fallocate+THP 场景大块读带宽提升 38-43%;无 THP 提升 11-12%
4
slab runtime sheaves tuning
 [RFC, 8p]
struct slab_sheaf 从 32B 缩减至 24B(-25%);capacity 和 barn 阈值运行时可调

新机制 / 新接口

#
系列
要点
5
BPF Arena 内核侧访问
 [v2, 8p]
新增 ptep_try_install() 无锁 PTE 安装 + scratch page 缺页恢复;消除内核-BPF 数据拷贝
6
文件 THP 可写文件支持
 [v6, 14p]
删除 CONFIG_READ_ONLY_THP_FOR_FS;统一 large folio 文件系统 THP collapse能力
7
DAMON data attributes
 [RFC v3, 28p]
复用采样点实现零额外开销属性监控;Probe + Filter 框架;sysfs/tracepoint 接口
8
DAMON 硬件采样 + AMD IBS
 [RFC, 7p]
每 CPU 无锁环形缓冲区;O(logN) drain;闭环验证偏差 <1.3pp
9
shmem gnu. xattr
* [v1, 1p]
支持 Hurd pipe translator 设置,消除生态系统缺口
10
process_vm_access pidfd+nowait
 [v4, 2p]
PROCESS_VM_PIDFD/NOWAIT 标志;FOLL_NOWAIT GUP
11
page_owner per-fd filter
 [v7, 4p]
handle 模式输出减少 66%,读取提升 4.4x;NUMA 节点过滤;per-fd 并发安全

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-03 18:01:06 HTTP/2.0 GET : https://f.mffb.com.cn/a/494327.html
  2. 运行时间 : 0.154600s [ 吞吐率:6.47req/s ] 内存消耗:4,913.40kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=2ec8a70d0ca95edc9271bd06ff520766
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000493s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000896s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.005095s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.009698s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000860s ]
  6. SELECT * FROM `set` [ RunTime:0.001223s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000579s ]
  8. SELECT * FROM `article` WHERE `id` = 494327 LIMIT 1 [ RunTime:0.000550s ]
  9. UPDATE `article` SET `lasttime` = 1783072866 WHERE `id` = 494327 [ RunTime:0.008972s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000278s ]
  11. SELECT * FROM `article` WHERE `id` < 494327 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000431s ]
  12. SELECT * FROM `article` WHERE `id` > 494327 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000433s ]
  13. SELECT * FROM `article` WHERE `id` < 494327 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.002085s ]
  14. SELECT * FROM `article` WHERE `id` < 494327 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.043407s ]
  15. SELECT * FROM `article` WHERE `id` < 494327 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.009923s ]
0.156166s