子系統跟蹤點: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 還是不用於 percpu_refill。

當每個 CPU 的列表太滿時,會釋放許多頁面,每個頁面都會觸發 mm_page_pcpu_drain 事件。

事件的單獨性質是為了可以在分配和釋放之間跟蹤頁面。 連續發生的許多 drain 或 refill 頁面意味著 zone->lock 被獲取一次。 大量的每個 CPU 的 refill 和 drain 可能意味著 CPU 之間的不平衡,其中太多的工作集中在一個地方。 這也可能表明每個 CPU 的列表應該更大。 最後,一個 CPU 上的大量 refill 和另一個 CPU 上的 drain 可能是導致大量快取行反彈的一個因素,如果可以透過一些演算法更改在同一 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 通常是預設巨型頁面大小的大小。