On Fri, Apr 1, 2022 at 11:11 AM Zi Yan <zi.yan@xxxxxxxx> wrote: > > Whenever the buddy of a page is found from __find_buddy_pfn(), > page_is_buddy() should be used to check its validity. Add a helper > function find_buddy_page_pfn() to find the buddy page and do the check > together. Well, this certainly looks nicer, except now: > +extern struct page *find_buddy_page_pfn(struct page *page, unsigned int order); that 'pfn' no longer makes sense in the name, and > @@ -1075,11 +1118,11 @@ static inline void __free_one_page(struct page *page, > migratetype); > return; > } > - buddy_pfn = __find_buddy_pfn(pfn, order); > - buddy = page + (buddy_pfn - pfn); > > - if (!page_is_buddy(page, buddy, order)) > + buddy = find_buddy_page_pfn(page, order); > + if (!buddy) > goto done_merging; > + buddy_pfn = page_to_pfn(buddy); This case now does two "page_to_pfn()" calls (one inside find_buddy_page_pfn(), and one explicitly on the buddy). And those page_to_pfn() things can actually be fairly expensive. It *looks* like just a subtraction, but it's a pointer subtraction that can end up generating a divide by a non-power-of-two size. NORMALLY we try very hard to make 'sizeof struct page' be exactly 8 words, but I do not believe this is actually guaranteed. And yeah, the divide-by-a-constant can be turned into a multiply, but even that is not necessarily always cheap. Now, two out of three use-cases didn't actually want the buddy_pfn(), but this one use-case does look like it might be performance-critical and a problem. Linus