aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZachary Amsden <zach@vmware.com>2005-09-03 18:55:04 -0400
committerLinus Torvalds <torvalds@evo.osdl.org>2005-09-05 03:05:48 -0400
commita600388d28419305aad3c4c0af52c223cf6fa0af (patch)
treec70d3d80275f189c49311183472367f45d1a1ef2
parentfa5b08d5f818063d18433194f20359ef2ae50254 (diff)
[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: Zachary Amsden <zach@vmware.com> Cc: Christoph Lameter <christoph@lameter.com> Cc: <linux-mm@kvack.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--include/asm-generic/pgtable.h16
-rw-r--r--include/asm-i386/pgtable.h13
-rw-r--r--mm/memory.c5
3 files changed, 32 insertions, 2 deletions
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index f40593565173..f86c1e549466 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -101,6 +101,22 @@ do { \
101}) 101})
102#endif 102#endif
103 103
104#ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
105#define ptep_get_and_clear_full(__mm, __address, __ptep, __full) \
106({ \
107 pte_t __pte; \
108 __pte = ptep_get_and_clear((__mm), (__address), (__ptep)); \
109 __pte; \
110})
111#endif
112
113#ifndef __HAVE_ARCH_PTE_CLEAR_FULL
114#define pte_clear_full(__mm, __address, __ptep, __full) \
115do { \
116 pte_clear((__mm), (__address), (__ptep)); \
117} while (0)
118#endif
119
104#ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH 120#ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH
105#define ptep_clear_flush(__vma, __address, __ptep) \ 121#define ptep_clear_flush(__vma, __address, __ptep) \
106({ \ 122({ \
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
index f51fd2c956bb..d74185aee15b 100644
--- a/include/asm-i386/pgtable.h
+++ b/include/asm-i386/pgtable.h
@@ -260,6 +260,18 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned
260 return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low); 260 return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low);
261} 261}
262 262
263static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long addr, pte_t *ptep, int full)
264{
265 pte_t pte;
266 if (full) {
267 pte = *ptep;
268 *ptep = __pte(0);
269 } else {
270 pte = ptep_get_and_clear(mm, addr, ptep);
271 }
272 return pte;
273}
274
263static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) 275static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
264{ 276{
265 clear_bit(_PAGE_BIT_RW, &ptep->pte_low); 277 clear_bit(_PAGE_BIT_RW, &ptep->pte_low);
@@ -417,6 +429,7 @@ extern void noexec_setup(const char *str);
417#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG 429#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
418#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY 430#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
419#define __HAVE_ARCH_PTEP_GET_AND_CLEAR 431#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
432#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
420#define __HAVE_ARCH_PTEP_SET_WRPROTECT 433#define __HAVE_ARCH_PTEP_SET_WRPROTECT
421#define __HAVE_ARCH_PTE_SAME 434#define __HAVE_ARCH_PTE_SAME
422#include <asm-generic/pgtable.h> 435#include <asm-generic/pgtable.h>
diff --git a/mm/memory.c b/mm/memory.c
index b25f5e58a14c..788a62810340 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -562,7 +562,8 @@ static void zap_pte_range(struct mmu_gather *tlb, pmd_t *pmd,
562 page->index > details->last_index)) 562 page->index > details->last_index))
563 continue; 563 continue;
564 } 564 }
565 ptent = ptep_get_and_clear(tlb->mm, addr, pte); 565 ptent = ptep_get_and_clear_full(tlb->mm, addr, pte,
566 tlb->fullmm);
566 tlb_remove_tlb_entry(tlb, pte, addr); 567 tlb_remove_tlb_entry(tlb, pte, addr);
567 if (unlikely(!page)) 568 if (unlikely(!page))
568 continue; 569 continue;
@@ -590,7 +591,7 @@ static void zap_pte_range(struct mmu_gather *tlb, pmd_t *pmd,
590 continue; 591 continue;
591 if (!pte_file(ptent)) 592 if (!pte_file(ptent))
592 free_swap_and_cache(pte_to_swp_entry(ptent)); 593 free_swap_and_cache(pte_to_swp_entry(ptent));
593 pte_clear(tlb->mm, addr, pte); 594 pte_clear_full(tlb->mm, addr, pte, tlb->fullmm);
594 } while (pte++, addr += PAGE_SIZE, addr != end); 595 } while (pte++, addr += PAGE_SIZE, addr != end);
595 pte_unmap(pte - 1); 596 pte_unmap(pte - 1);
596} 597}