![[LWN Logo]](/images/lcorner.png) |
|
![[LWN.net]](/images/Included.png) |
From: Ben LaHaise <bcrl@redhat.com>
To: <torvalds@transmeta.com>, <alan@redhat.com>
Subject: [PATCH] final merging patch -- significant mozilla speedup.
Date: Thu, 16 Aug 2001 17:02:24 -0400 (EDT)
Cc: <linux-mm@kvack.org>, Chris Blizzard <blizzard@redhat.com>
Hello again,
This should be the final variant of the vma merging patch: it does tail
merging for mmap and runs the same code after an mprotect syscall via the
merge_anon_vmas and attempt_merge_next functions. This also includes a
fix to the mremap merging to avoid merge attempts on non-private mappings.
All told, mozilla now uses ~220 vmas for a few quick page loads that would
previously reach ~1650 vmas or more. This really boosts the speed of
mozilla -- give it a try! Patch is against 2.4.9 and applies cleanly to
2.4.8-ac5 too.
-ben
.... v2.4.9-merge-full.diff
diff -urN /md0/kernels/2.4/v2.4.9/include/linux/mm.h foo/include/linux/mm.h
--- /md0/kernels/2.4/v2.4.9/include/linux/mm.h Tue Aug 7 17:52:06 2001
+++ foo/include/linux/mm.h Thu Aug 16 16:59:34 2001
@@ -515,6 +515,7 @@
extern int do_munmap(struct mm_struct *, unsigned long, size_t);
extern unsigned long do_brk(unsigned long, unsigned long);
+extern void merge_anon_vmas(struct mm_struct *mm, unsigned long start, unsigned long end);
struct zone_t;
/* filemap.c */
diff -urN /md0/kernels/2.4/v2.4.9/mm/mmap.c foo/mm/mmap.c
--- /md0/kernels/2.4/v2.4.9/mm/mmap.c Fri May 25 22:48:10 2001
+++ foo/mm/mmap.c Thu Aug 16 16:59:35 2001
@@ -17,6 +17,8 @@
#include <asm/uaccess.h>
#include <asm/pgalloc.h>
+static inline void attempt_merge_next(struct mm_struct *mm, struct vm_area_struct *vma);
+
/* description of effects of mapping type and prot in current implementation.
* this is due to the limited x86 page protection hardware. The expected
* behavior is in parens:
@@ -309,7 +311,7 @@
/* Can we just expand an old anonymous mapping? */
if (addr && !file && !(vm_flags & VM_SHARED)) {
- struct vm_area_struct * vma = find_vma(mm, addr-1);
+ vma = find_vma(mm, addr-1);
if (vma && vma->vm_end == addr && !vma->vm_file &&
vma->vm_flags == vm_flags) {
vma->vm_end = addr + len;
@@ -365,12 +367,17 @@
if (correct_wcount)
atomic_inc(&file->f_dentry->d_inode->i_writecount);
-out:
+out:
mm->total_vm += len >> PAGE_SHIFT;
if (vm_flags & VM_LOCKED) {
mm->locked_vm += len >> PAGE_SHIFT;
make_pages_present(addr, addr + len);
}
+
+ /* Can we merge this anonymous mapping with the one following it? */
+ if (!file && !(vm_flags & VM_SHARED))
+ attempt_merge_next(mm, vma);
+
return addr;
unmap_and_free_vma:
@@ -1004,4 +1011,34 @@
__insert_vm_struct(mm, vmp);
spin_unlock(¤t->mm->page_table_lock);
unlock_vma_mappings(vmp);
+}
+
+static inline void attempt_merge_next(struct mm_struct *mm, struct vm_area_struct *vma)
+{
+ struct vm_area_struct *next = vma->vm_next;
+ if (next && vma->vm_end == next->vm_start && !next->vm_file &&
+ vma->vm_flags == next->vm_flags) {
+ spin_lock(&mm->page_table_lock);
+ vma->vm_next = next->vm_next;
+ if (mm->mmap_avl)
+ avl_remove(next, &mm->mmap_avl);
+ vma->vm_end = next->vm_end;
+ mm->mmap_cache = vma; /* Kill the cache. */
+ mm->map_count--;
+ spin_unlock(&mm->page_table_lock);
+
+ kmem_cache_free(vm_area_cachep, next);
+ }
+}
+
+void merge_anon_vmas(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+ struct vm_area_struct *vma;
+ if (start)
+ start--;
+
+ for (vma = find_vma(mm, start); vma && vma->vm_start <= end;
+ vma = vma->vm_next)
+ if (!vma->vm_file && !(vma->vm_flags & VM_SHARED))
+ attempt_merge_next(mm, vma);
}
diff -urN /md0/kernels/2.4/v2.4.9/mm/mprotect.c foo/mm/mprotect.c
--- /md0/kernels/2.4/v2.4.9/mm/mprotect.c Thu Apr 5 11:53:46 2001
+++ foo/mm/mprotect.c Thu Aug 16 16:59:35 2001
@@ -278,6 +278,7 @@
break;
}
}
+ merge_anon_vmas(current->mm, start, end);
out:
up_write(¤t->mm->mmap_sem);
return error;
diff -urN /md0/kernels/2.4/v2.4.9/mm/mremap.c foo/mm/mremap.c
--- /md0/kernels/2.4/v2.4.9/mm/mremap.c Thu May 3 11:22:20 2001
+++ foo/mm/mremap.c Thu Aug 16 16:59:35 2001
@@ -128,10 +128,23 @@
unsigned long new_addr)
{
struct vm_area_struct * new_vma;
+ int allocated_vma = 0;
- new_vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
- if (new_vma) {
- if (!move_page_tables(current->mm, new_addr, addr, old_len)) {
+ /* First, check if we can merge a mapping. -ben */
+ new_vma = find_vma(current->mm, new_addr-1);
+ if (new_vma && !vma->vm_file && !(vma->vm_flags & VM_SHARED) &&
+ new_vma->vm_end == new_addr && !new_vma->vm_file &&
+ new_vma->vm_flags == vma->vm_flags) {
+ new_vma->vm_end = new_addr + new_len;
+ } else {
+ new_vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+ if (!new_vma)
+ goto no_mem;
+ allocated_vma = 1;
+ }
+
+ if (!move_page_tables(current->mm, new_addr, addr, old_len)) {
+ if (allocated_vma) {
*new_vma = *vma;
new_vma->vm_start = new_addr;
new_vma->vm_end = new_addr+new_len;
@@ -142,17 +155,20 @@
if (new_vma->vm_ops && new_vma->vm_ops->open)
new_vma->vm_ops->open(new_vma);
insert_vm_struct(current->mm, new_vma);
- do_munmap(current->mm, addr, old_len);
- current->mm->total_vm += new_len >> PAGE_SHIFT;
- if (new_vma->vm_flags & VM_LOCKED) {
- current->mm->locked_vm += new_len >> PAGE_SHIFT;
- make_pages_present(new_vma->vm_start,
- new_vma->vm_end);
- }
- return new_addr;
}
- kmem_cache_free(vm_area_cachep, new_vma);
+ do_munmap(current->mm, addr, old_len);
+ current->mm->total_vm += new_len >> PAGE_SHIFT;
+ if (new_vma->vm_flags & VM_LOCKED) {
+ current->mm->locked_vm += new_len >> PAGE_SHIFT;
+ make_pages_present(new_vma->vm_start,
+ new_vma->vm_end);
+ }
+ return new_addr;
}
+ if (allocated_vma)
+ kmem_cache_free(vm_area_cachep, new_vma);
+
+no_mem:
return -ENOMEM;
}
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/