Skip to content

Commit d8dfe60

Browse files
Alex ShiH. Peter Anvin
authored andcommitted
x86/tlb: fall back to flush all when meet a THP large page
We don't need to flush large pages by PAGE_SIZE step, that just waste time. and actually, large page don't need 'invlpg' optimizing according to our micro benchmark. So, just flush whole TLB is enough for them. The following result is tested on a 2CPU * 4cores * 2HT NHM EP machine, with THP 'always' setting. Multi-thread testing, '-t' paramter is thread number: without this patch with this patch ./mprotect -t 1 14ns 13ns ./mprotect -t 2 13ns 13ns ./mprotect -t 4 12ns 11ns ./mprotect -t 8 14ns 10ns ./mprotect -t 16 28ns 28ns ./mprotect -t 32 54ns 52ns ./mprotect -t 128 200ns 200ns Signed-off-by: Alex Shi <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: H. Peter Anvin <[email protected]>
1 parent e7b52ff commit d8dfe60

File tree

1 file changed

+34
-0
lines changed

1 file changed

+34
-0
lines changed

arch/x86/mm/tlb.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,12 +318,42 @@ void flush_tlb_mm(struct mm_struct *mm)
318318

319319
#define FLUSHALL_BAR 16
320320

321+
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
322+
static inline unsigned long has_large_page(struct mm_struct *mm,
323+
unsigned long start, unsigned long end)
324+
{
325+
pgd_t *pgd;
326+
pud_t *pud;
327+
pmd_t *pmd;
328+
unsigned long addr = ALIGN(start, HPAGE_SIZE);
329+
for (; addr < end; addr += HPAGE_SIZE) {
330+
pgd = pgd_offset(mm, addr);
331+
if (likely(!pgd_none(*pgd))) {
332+
pud = pud_offset(pgd, addr);
333+
if (likely(!pud_none(*pud))) {
334+
pmd = pmd_offset(pud, addr);
335+
if (likely(!pmd_none(*pmd)))
336+
if (pmd_large(*pmd))
337+
return addr;
338+
}
339+
}
340+
}
341+
return 0;
342+
}
343+
#else
344+
static inline unsigned long has_large_page(struct mm_struct *mm,
345+
unsigned long start, unsigned long end)
346+
{
347+
return 0;
348+
}
349+
#endif
321350
void flush_tlb_range(struct vm_area_struct *vma,
322351
unsigned long start, unsigned long end)
323352
{
324353
struct mm_struct *mm;
325354

326355
if (!cpu_has_invlpg || vma->vm_flags & VM_HUGETLB) {
356+
flush_all:
327357
flush_tlb_mm(vma->vm_mm);
328358
return;
329359
}
@@ -346,6 +376,10 @@ void flush_tlb_range(struct vm_area_struct *vma,
346376
if ((end - start)/PAGE_SIZE > act_entries/FLUSHALL_BAR)
347377
local_flush_tlb();
348378
else {
379+
if (has_large_page(mm, start, end)) {
380+
preempt_enable();
381+
goto flush_all;
382+
}
349383
for (addr = start; addr < end;
350384
addr += PAGE_SIZE)
351385
__flush_tlb_single(addr);

0 commit comments

Comments
 (0)