From: "Kiryl Shutsemau (Meta)" <[email protected]> A round is the unit the engine actually works in, and nothing reports one. The per-candidate events say which windows were taken and which were refused. They do not say how large the batch was, how much of it landed, or the number that matters most for whether batching was the right idea: how long a faulter on a source is held up.
That wait has a definite span. A thread touching a source sleeps on the folio lock the freeze took, and wakes when the putback drops it. So the interval from the first freeze to the last putback is what the round costs anyone unlucky enough to touch it. Add mm_collapse_round: that interval in microseconds, with the candidates collected, the ones installed, and the outcome. It is the thing to watch if a larger batch is ever proposed. collapse_finish() returns the number of candidates installed, and this is its first consumer. Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: Kiryl Shutsemau (Meta) <[email protected]> --- include/trace/events/huge_memory.h | 31 ++++++++++++++++++++++++++++++ mm/collapse.c | 17 +++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/include/trace/events/huge_memory.h b/include/trace/events/huge_memory.h index c2314e26111c..d7c0195ace92 100644 --- a/include/trace/events/huge_memory.h +++ b/include/trace/events/huge_memory.h @@ -160,6 +160,37 @@ TRACE_EVENT(mm_collapse_scan, __print_symbolic(__entry->result, SCAN_STATUS)) ); +TRACE_EVENT(mm_collapse_round, + + TP_PROTO(struct mm_struct *mm, unsigned int nr_candidates, + unsigned int nr_installed, int result, u64 freeze_to_wake_us), + + TP_ARGS(mm, nr_candidates, nr_installed, result, freeze_to_wake_us), + + TP_STRUCT__entry( + __field(struct mm_struct *, mm) + __field(unsigned int, nr_candidates) + __field(unsigned int, nr_installed) + __field(int, result) + __field(u64, freeze_to_wake_us) + ), + + TP_fast_assign( + __entry->mm = mm; + __entry->nr_candidates = nr_candidates; + __entry->nr_installed = nr_installed; + __entry->result = result; + __entry->freeze_to_wake_us = freeze_to_wake_us; + ), + + TP_printk("mm=%p, nr_candidates=%u, nr_installed=%u, result=%s, freeze_to_wake_us=%llu", + __entry->mm, + __entry->nr_candidates, + __entry->nr_installed, + __print_symbolic(__entry->result, SCAN_STATUS), + __entry->freeze_to_wake_us) +); + TRACE_EVENT(mm_collapse_faultin, TP_PROTO(struct mm_struct *mm, unsigned int nr_faults, int result), diff --git a/mm/collapse.c b/mm/collapse.c index 1b5db42b6991..d0d28e8dfcea 100644 --- a/mm/collapse.c +++ b/mm/collapse.c @@ -8,6 +8,7 @@ #include <linux/huge_mm.h> #include <linux/hugetlb.h> /* x86 flush_tlb_range() uses hstate_vma() */ #include <linux/leafops.h> +#include <linux/math64.h> #include <linux/memcontrol.h> #include <linux/mm.h> #include <linux/mmu_notifier.h> @@ -20,6 +21,7 @@ #include <linux/sizes.h> #include <linux/slab.h> #include <linux/swap.h> +#include <linux/timekeeping.h> #include <linux/userfaultfd_k.h> #include <linux/vmstat.h> @@ -1803,6 +1805,8 @@ static void collapse_round(struct mm_struct *mm, unsigned long pmd_addr, struct mmu_notifier_range range; struct vm_area_struct *vma; enum scan_result result; + unsigned int nr_installed; + u64 latency = 0; pmd_t *pmd; collapse_reserve(mm, cc); @@ -1838,6 +1842,13 @@ static void collapse_round(struct mm_struct *mm, unsigned long pmd_addr, cc->batch_start, cc->batch_end); mmu_notifier_invalidate_range_start(&range); + /* + * What the faulters on this batch's sources are made to wait: they sleep + * from the freeze that took their folio's lock to the putback that drops + * it. Measured per round rather than argued about. + */ + latency = ktime_get_ns(); + /* * None of these can fail as a whole: the freeze takes the sources it * can and drops the candidates it cannot, and each pass after it works @@ -1849,12 +1860,16 @@ static void collapse_round(struct mm_struct *mm, unsigned long pmd_addr, collapse_install(vma, cc, pmd); collapse_putback(vma, cc); + latency = ktime_get_ns() - latency; + mmu_notifier_invalidate_range_end(&range); out_unlock: mmap_read_unlock(mm); out: - collapse_finish(mm, cc, result); + nr_installed = collapse_finish(mm, cc, result); + trace_mm_collapse_round(mm, cc->nr_candidates, nr_installed, result, + div_u64(latency, NSEC_PER_USEC)); } /* -- 2.54.0
