Commit a600388d authored by Zachary Amsden's avatar Zachary Amsden Committed by Linus Torvalds

[PATCH] x86: ptep_clear optimization

Add a new accessor for PTEs, which passes the full hint from the mmu_gather
struct; this allows architectures with hardware pagetables to optimize away
atomic PTE operations when destroying an address space.  Removing the
locked operation should allow better pipelining of memory access in this
loop.  I measured an average savings of 30-35 cycles per zap_pte_range on
the first 500 destructions on Pentium-M, but I believe the optimization
would win more on older processors which still assert the bus lock on xchg
for an exclusive cacheline.

Update: I made some new measurements, and this saves exactly 26 cycles over
ptep_get_and_clear on Pentium M.  On P4, with a PAE kernel, this saves 180
cycles per ptep_get_and_clear, for a whopping 92160 cycles savings for a
full address space destruction.

pte_clear_full is not yet used, but is provided for future optimizations
(in particular, when running inside of a hypervisor that queues page table
updates, the full hint allows us to avoid queueing unnecessary page table
update for an address space in the process of being destroyed.

This is not a huge win, but it does help a bit, and sets the stage for
further hypervisor optimization of the mm layer on all architectures.
Signed-off-by: default avatarZachary Amsden <zach@vmware.com>
Cc: Christoph Lameter <christoph@lameter.com>
Cc: <linux-mm@kvack.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent fa5b08d5
...@@ -101,6 +101,22 @@ do { \ ...@@ -101,6 +101,22 @@ do { \
}) })
#endif #endif
#ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
#define ptep_get_and_clear_full(__mm, __address, __ptep, __full) \
({ \
pte_t __pte; \
__pte = ptep_get_and_clear((__mm), (__address), (__ptep)); \
__pte; \
})
#endif
#ifndef __HAVE_ARCH_PTE_CLEAR_FULL
#define pte_clear_full(__mm, __address, __ptep, __full) \
do { \
pte_clear((__mm), (__address), (__ptep)); \
} while (0)
#endif
#ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH #ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH
#define ptep_clear_flush(__vma, __address, __ptep) \ #define ptep_clear_flush(__vma, __address, __ptep) \
({ \ ({ \
......
...@@ -260,6 +260,18 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned ...@@ -260,6 +260,18 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned
return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low); return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low);
} }
static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long addr, pte_t *ptep, int full)
{
pte_t pte;
if (full) {
pte = *ptep;
*ptep = __pte(0);
} else {
pte = ptep_get_and_clear(mm, addr, ptep);
}
return pte;
}
static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{ {
clear_bit(_PAGE_BIT_RW, &ptep->pte_low); clear_bit(_PAGE_BIT_RW, &ptep->pte_low);
...@@ -417,6 +429,7 @@ extern void noexec_setup(const char *str); ...@@ -417,6 +429,7 @@ extern void noexec_setup(const char *str);
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR #define __HAVE_ARCH_PTEP_GET_AND_CLEAR
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
#define __HAVE_ARCH_PTEP_SET_WRPROTECT #define __HAVE_ARCH_PTEP_SET_WRPROTECT
#define __HAVE_ARCH_PTE_SAME #define __HAVE_ARCH_PTE_SAME
#include <asm-generic/pgtable.h> #include <asm-generic/pgtable.h>
......
...@@ -562,7 +562,8 @@ static void zap_pte_range(struct mmu_gather *tlb, pmd_t *pmd, ...@@ -562,7 +562,8 @@ static void zap_pte_range(struct mmu_gather *tlb, pmd_t *pmd,
page->index > details->last_index)) page->index > details->last_index))
continue; continue;
} }
ptent = ptep_get_and_clear(tlb->mm, addr, pte); ptent = ptep_get_and_clear_full(tlb->mm, addr, pte,
tlb->fullmm);
tlb_remove_tlb_entry(tlb, pte, addr); tlb_remove_tlb_entry(tlb, pte, addr);
if (unlikely(!page)) if (unlikely(!page))
continue; continue;
...@@ -590,7 +591,7 @@ static void zap_pte_range(struct mmu_gather *tlb, pmd_t *pmd, ...@@ -590,7 +591,7 @@ static void zap_pte_range(struct mmu_gather *tlb, pmd_t *pmd,
continue; continue;
if (!pte_file(ptent)) if (!pte_file(ptent))
free_swap_and_cache(pte_to_swp_entry(ptent)); free_swap_and_cache(pte_to_swp_entry(ptent));
pte_clear(tlb->mm, addr, pte); pte_clear_full(tlb->mm, addr, pte, tlb->fullmm);
} while (pte++, addr += PAGE_SIZE, addr != end); } while (pte++, addr += PAGE_SIZE, addr != end);
pte_unmap(pte - 1); pte_unmap(pte - 1);
} }
......
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