子系统跟踪点:kmem¶
kmem 跟踪系统捕获与内核中对象和页面分配相关的事件。 广义上讲,有五个主要子标题。
未知类型的小对象的 Slab 分配 (kmalloc)
已知类型的小对象的 Slab 分配
页面分配
每个 CPU 分配器活动
外部碎片
本文档描述了每个跟踪点是什么以及它们为什么可能有用。
1. 未知类型的小对象的 Slab 分配¶
kmalloc call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s
kmalloc_node call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s node=%d
kfree call_site=%lx ptr=%p
这些事件的频繁活动可能表明需要一个特定的缓存,特别是如果 kmalloc slab 页面由于分配模式而导致内部碎片化严重。通过将 kmalloc 与 kfree 相关联,可以识别内存泄漏以及分配位置。
2. 已知类型的小对象的 Slab 分配¶
kmem_cache_alloc call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s
kmem_cache_alloc_node call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s node=%d
kmem_cache_free call_site=%lx ptr=%p
这些事件的用法与 kmalloc 相关事件类似,只不过更容易将事件锁定到特定缓存。在撰写本文时,没有关于正在从哪个 slab 分配的信息,但通常可以使用 call_site 来推断该信息。
3. 页面分配¶
mm_page_alloc page=%p pfn=%lu order=%d migratetype=%d gfp_flags=%s
mm_page_alloc_zone_locked page=%p pfn=%lu order=%u migratetype=%d cpu=%d percpu_refill=%d
mm_page_free page=%p pfn=%lu order=%d
mm_page_free_batched page=%p pfn=%lu order=%d cold=%d
这四个事件处理页面分配和释放。 mm_page_alloc 是页面分配器活动的简单指示器。 可以从每个 CPU 分配器(高性能)或伙伴分配器分配页面。
如果页面直接从伙伴分配器分配,则会触发 mm_page_alloc_zone_locked 事件。 此事件非常重要,因为高活动量意味着 zone->lock 上的高活动量。 获取此锁会通过禁用中断、污染 CPU 之间的缓存行和序列化许多 CPU 来降低性能。
当页面由调用者直接释放时,只会触发 mm_page_free 事件。 此处的大量活动可能表明调用者应该批量处理其活动。
当页面批量释放时,也会触发 mm_page_free_batched。 广义上讲,页面会从 LRU 锁中批量取出,并使用页面列表批量释放。 此处的大量活动可能表明系统处于内存压力之下,也可能表明 lruvec->lru_lock 上存在争用。
4. 每个 CPU 分配器活动¶
mm_page_alloc_zone_locked page=%p pfn=%lu order=%u migratetype=%d cpu=%d percpu_refill=%d
mm_page_pcpu_drain page=%p pfn=%lu order=%d cpu=%d migratetype=%d
在页面分配器前面有一个每个 CPU 页面分配器。 它仅存在于 order-0 页面,减少了 zone->lock 上的争用,并减少了 struct page 上的写入量。
当每个 CPU 列表为空或分配了错误类型的页面时,将获取一次 zone->lock,并重新填充每个 CPU 列表。 对于分配的每个页面,触发的事件是 mm_page_alloc_zone_locked,该事件指示它是用于 percpu_refill 还是不用于。
当每个 CPU 列表太满时,会释放许多页面,每个页面都会触发 mm_page_pcpu_drain 事件。
事件的单独性质是为了可以在分配和释放之间跟踪页面。 连续发生的大量 drain 或 refill 页面意味着 zone->lock 被获取一次。 大量的每个 CPU refill 和 drain 可能意味着 CPU 之间的不平衡,其中过多的工作集中在一个地方。 它也可能表明每个 CPU 列表应该更大。 最后,一个 CPU 上的大量 refill 和另一个 CPU 上的 drain 可能是导致 CPU 之间写入导致大量缓存行弹跳的一个因素,并且如果可以通过某种算法更改在同一 CPU 上分配和释放页面,则值得研究。
5. 外部碎片¶
mm_page_alloc_extfrag page=%p pfn=%lu alloc_order=%d fallback_order=%d pageblock_order=%d alloc_migratetype=%d fallback_migratetype=%d fragmenting=%d change_ownership=%d
外部碎片会影响高阶分配是否成功。 对于某些类型的硬件,这很重要,尽管尽可能避免这种情况。 如果系统正在使用巨型页面,并且需要在系统的生命周期内调整池的大小,则此值很重要。
大量此事件意味着内存正在碎片化,并且高阶分配将在未来的某个时间开始失败。 减少此事件发生的一种方法是以 3*pageblock_size*nr_online_nodes 的增量增加 min_free_kbytes 的大小,其中 pageblock_size 通常是默认巨型页面大小的大小。