summaryrefslogtreecommitdiffstats
path: root/sys/vm
diff options
context:
space:
mode:
authoralc <alc@FreeBSD.org>2013-08-29 15:49:05 +0000
committeralc <alc@FreeBSD.org>2013-08-29 15:49:05 +0000
commitaa9a7bb9e6c374d0ee2f00489abd48f856d79aee (patch)
tree548fcd5f51d9d645c37a8a20f515a3b39c70329c /sys/vm
parent4212d5ac38bc35cd7d1671a7a93ad65425dbdded (diff)
downloadFreeBSD-src-aa9a7bb9e6c374d0ee2f00489abd48f856d79aee.zip
FreeBSD-src-aa9a7bb9e6c374d0ee2f00489abd48f856d79aee.tar.gz
Significantly reduce the cost, i.e., run time, of calls to madvise(...,
MADV_DONTNEED) and madvise(..., MADV_FREE). Specifically, introduce a new pmap function, pmap_advise(), that operates on a range of virtual addresses within the specified pmap, allowing for a more efficient implementation of MADV_DONTNEED and MADV_FREE. Previously, the implementation of MADV_DONTNEED and MADV_FREE relied on per-page pmap operations, such as pmap_clear_reference(). Intuitively, the problem with this implementation is that the pmap-level locks are acquired and released and the page table traversed repeatedly, once for each resident page in the range that was specified to madvise(2). A more subtle flaw with the previous implementation is that pmap_clear_reference() would clear the reference bit on all mappings to the specified page, not just the mapping in the range specified to madvise(2). Since our malloc(3) makes heavy use of madvise(2), this change can have a measureable impact. For example, the system time for completing a parallel "buildworld" on a 6-core amd64 machine was reduced by about 1.5% to 2.0%. Note: This change only contains pmap_advise() implementations for a subset of our supported architectures. I will commit implementations for the remaining architectures after further testing. For now, a stub function is sufficient because of the advisory nature of pmap_advise(). Discussed with: jeff, jhb, kib Tested by: pho (i386), marcel (ia64) Sponsored by: EMC / Isilon Storage Division
Diffstat (limited to 'sys/vm')
-rw-r--r--sys/vm/pmap.h2
-rw-r--r--sys/vm/vm_map.c21
-rw-r--r--sys/vm/vm_page.c9
3 files changed, 21 insertions, 11 deletions
diff --git a/sys/vm/pmap.h b/sys/vm/pmap.h
index c0f80a7..911298f 100644
--- a/sys/vm/pmap.h
+++ b/sys/vm/pmap.h
@@ -98,6 +98,8 @@ struct thread;
extern vm_offset_t kernel_vm_end;
void pmap_activate(struct thread *td);
+void pmap_advise(pmap_t pmap, vm_offset_t sva, vm_offset_t eva,
+ int advice);
void pmap_align_superpage(vm_object_t, vm_ooffset_t, vm_offset_t *,
vm_size_t);
void pmap_change_wiring(pmap_t, vm_offset_t, boolean_t);
diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c
index 71c44ad..1be62af 100644
--- a/sys/vm/vm_map.c
+++ b/sys/vm/vm_map.c
@@ -2125,7 +2125,7 @@ vm_map_madvise(
(current != &map->header) && (current->start < end);
current = current->next
) {
- vm_offset_t useStart;
+ vm_offset_t useEnd, useStart;
if (current->eflags & MAP_ENTRY_IS_SUB_MAP)
continue;
@@ -2133,17 +2133,34 @@ vm_map_madvise(
pstart = OFF_TO_IDX(current->offset);
pend = pstart + atop(current->end - current->start);
useStart = current->start;
+ useEnd = current->end;
if (current->start < start) {
pstart += atop(start - current->start);
useStart = start;
}
- if (current->end > end)
+ if (current->end > end) {
pend -= atop(current->end - end);
+ useEnd = end;
+ }
if (pstart >= pend)
continue;
+ /*
+ * Perform the pmap_advise() before clearing
+ * PGA_REFERENCED in vm_page_advise(). Otherwise, a
+ * concurrent pmap operation, such as pmap_remove(),
+ * could clear a reference in the pmap and set
+ * PGA_REFERENCED on the page before the pmap_advise()
+ * had completed. Consequently, the page would appear
+ * referenced based upon an old reference that
+ * occurred before this pmap_advise() ran.
+ */
+ if (behav == MADV_DONTNEED || behav == MADV_FREE)
+ pmap_advise(map->pmap, useStart, useEnd,
+ behav);
+
vm_object_madvise(current->object.vm_object, pstart,
pend, behav);
if (behav == MADV_WILLNEED) {
diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c
index 7d8ecfa..7b4b57c 100644
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -2634,7 +2634,6 @@ vm_page_advise(vm_page_t m, int advice)
* But we do make the page is freeable as we can without
* actually taking the step of unmapping it.
*/
- pmap_clear_modify(m);
m->dirty = 0;
m->act_count = 0;
} else if (advice != MADV_DONTNEED)
@@ -2654,15 +2653,7 @@ vm_page_advise(vm_page_t m, int advice)
/*
* Clear any references to the page. Otherwise, the page daemon will
* immediately reactivate the page.
- *
- * Perform the pmap_clear_reference() first. Otherwise, a concurrent
- * pmap operation, such as pmap_remove(), could clear a reference in
- * the pmap and set PGA_REFERENCED on the page before the
- * pmap_clear_reference() had completed. Consequently, the page would
- * appear referenced based upon an old reference that occurred before
- * this function ran.
*/
- pmap_clear_reference(m);
vm_page_aflag_clear(m, PGA_REFERENCED);
if (advice != MADV_FREE && m->dirty == 0 && pmap_is_modified(m))
OpenPOWER on IntegriCloud