Commit deedad80 authored by Yin Fengwei's avatar Yin Fengwei Committed by Andrew Morton

THP: avoid lock when check whether THP is in deferred list

free_transhuge_page() acquires split queue lock then check whether the THP
was added to deferred list or not.  It brings high deferred queue lock
contention.

It's safe to check whether the THP is in deferred list or not without
holding the deferred queue lock in free_transhuge_page() because when code
hit free_transhuge_page(), there is no one tries to add the folio to
_deferred_list.

Running page_fault1 of will-it-scale + order 2 folio for anonymous
mapping with 96 processes on an Ice Lake 48C/96T test box, we could
see the 61% split_queue_lock contention:
-   63.02%     0.01%  page_fault1_pro  [kernel.kallsyms]         [k] free_transhuge_page
   - 63.01% free_transhuge_page
      + 62.91% _raw_spin_lock_irqsave

With this patch applied, the split_queue_lock contention is less
than 1%.

Link: https://lkml.kernel.org/r/20230429082759.1600796-2-fengwei.yin@intel.comSigned-off-by: default avatarYin Fengwei <fengwei.yin@intel.com>
Acked-by: default avatarKirill A. Shutemov <kirill.shutemov@linux.intel.com>
Reviewed-by: default avatar"Huang, Ying" <ying.huang@intel.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Yu Zhao <yuzhao@google.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent a95722a0
...@@ -2792,12 +2792,19 @@ void free_transhuge_page(struct page *page) ...@@ -2792,12 +2792,19 @@ void free_transhuge_page(struct page *page)
struct deferred_split *ds_queue = get_deferred_split_queue(folio); struct deferred_split *ds_queue = get_deferred_split_queue(folio);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&ds_queue->split_queue_lock, flags); /*
if (!list_empty(&folio->_deferred_list)) { * At this point, there is no one trying to add the folio to
ds_queue->split_queue_len--; * deferred_list. If folio is not in deferred_list, it's safe
list_del(&folio->_deferred_list); * to check without acquiring the split_queue_lock.
*/
if (data_race(!list_empty(&folio->_deferred_list))) {
spin_lock_irqsave(&ds_queue->split_queue_lock, flags);
if (!list_empty(&folio->_deferred_list)) {
ds_queue->split_queue_len--;
list_del(&folio->_deferred_list);
}
spin_unlock_irqrestore(&ds_queue->split_queue_lock, flags);
} }
spin_unlock_irqrestore(&ds_queue->split_queue_lock, flags);
free_compound_page(page); free_compound_page(page);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment