summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Bushnell <thomas@gnu.org>1999-06-27 23:52:11 +0000
committerThomas Bushnell <thomas@gnu.org>1999-06-27 23:52:11 +0000
commit6339d07d670de57411d1825e300f2a78bfaf01f7 (patch)
tree49fb264a1f470becc74967a1651f8b2348d72032
parent3ad230669bd394f4e77a3c2fada222ba60daf861 (diff)
1999-06-27 Thomas Bushnell, BSG <tb@mit.edu>
* vm/vm_resident.c (vm_page_external_count): Define variable. (vm_page_grab): New argument `external'. All callers changed. Keep track of number of externally managed pages. Don't let non-privileged threads exceed the externally-managed page limit. (vm_page_grab_contiguous_pages): New argument `external'. All callers changed. Keep track of number of externally managed pages. Don't let non-privileged threads exceed the externally-managed page limit. (vm_page_convert): New argument `external'. All callers changed. (vm_page_release): New argument `external'. All callers changed. Keep track of number of externally managed pages. (vm_page_bootstrap): Initialize M->external. * vm/vm_page.h (vm_page_external_limit, vm_page_external_count): New variables. (struct vm_page): New members `external' and `extcounted'. * vm/vm_pageout.c (vm_pageout): Initialize vm_page_external_limit and vm_page_external_target. (VM_PAGE_EXTERNAL_LIMIT, VM_PAGE_EXTERNAL_TARGET): New macro. (vm_pageout_external_target): New variable. (vm_pageout_scan): Regard "too many externally managed pages" as a reason to keep doing work, but if that's the only reason we're doing work, then the only thing we do is schedule cleaning of pages. Help keep track of the number of externally managed pages that we care about. * vm/vm_pageout.c (VM_PAGEOUT_BURST_WAIT): Reduce to 10ms/page. (VM_PAGEOUT_EMPTY_WAIT): Reduce to 75 ms. (VM_PAGE_FREE_RESERVED): Increase to 50 pages. (VM_PAGEOUT_RESERVED_INTERNAL): Adjust to `(reserve) - 25'. (VM_PAGEOUT_RESERVED_REALLY): Adjust to `(reserve) - 40'.
-rw-r--r--vm/vm_fault.c8
-rw-r--r--vm/vm_map.c2
-rw-r--r--vm/vm_page.h17
-rw-r--r--vm/vm_pageout.c83
-rw-r--r--vm/vm_resident.c47
5 files changed, 123 insertions, 34 deletions
diff --git a/vm/vm_fault.c b/vm/vm_fault.c
index e45687c..a74d41b 100644
--- a/vm/vm_fault.c
+++ b/vm/vm_fault.c
@@ -443,7 +443,7 @@ vm_fault_return_t vm_fault_page(first_object, first_offset,
* need to allocate a real page.
*/
- real_m = vm_page_grab();
+ real_m = vm_page_grab(!object->internal);
if (real_m == VM_PAGE_NULL) {
vm_fault_cleanup(object, first_m);
return(VM_FAULT_MEMORY_SHORTAGE);
@@ -625,7 +625,7 @@ vm_fault_return_t vm_fault_page(first_object, first_offset,
* won't block for pages.
*/
- if (m->fictitious && !vm_page_convert(m)) {
+ if (m->fictitious && !vm_page_convert(m, FALSE)) {
VM_PAGE_FREE(m);
vm_fault_cleanup(object, first_m);
return(VM_FAULT_MEMORY_SHORTAGE);
@@ -742,7 +742,7 @@ vm_fault_return_t vm_fault_page(first_object, first_offset,
assert(m->object == object);
first_m = VM_PAGE_NULL;
- if (m->fictitious && !vm_page_convert(m)) {
+ if (m->fictitious && !vm_page_convert(m, !object->internal)) {
VM_PAGE_FREE(m);
vm_fault_cleanup(object, VM_PAGE_NULL);
return(VM_FAULT_MEMORY_SHORTAGE);
@@ -828,7 +828,7 @@ vm_fault_return_t vm_fault_page(first_object, first_offset,
/*
* Allocate a page for the copy
*/
- copy_m = vm_page_grab();
+ copy_m = vm_page_grab(!first_object->internal);
if (copy_m == VM_PAGE_NULL) {
RELEASE_PAGE(m);
vm_fault_cleanup(object, first_m);
diff --git a/vm/vm_map.c b/vm/vm_map.c
index c71b858..8d17a49 100644
--- a/vm/vm_map.c
+++ b/vm/vm_map.c
@@ -1828,7 +1828,7 @@ vm_map_copy_t copy;
* Page was not stolen, get a new
* one and do the copy now.
*/
- while ((new_m = vm_page_grab()) == VM_PAGE_NULL) {
+ while ((new_m = vm_page_grab(FALSE)) == VM_PAGE_NULL) {
VM_PAGE_WAIT((void(*)()) 0);
}
diff --git a/vm/vm_page.h b/vm/vm_page.h
index f7fa80a..6ca1c0c 100644
--- a/vm/vm_page.h
+++ b/vm/vm_page.h
@@ -93,6 +93,8 @@ struct vm_page {
laundry:1, /* page is being cleaned now (P)*/
free:1, /* page is on free list (P) */
reference:1, /* page has been used (P) */
+ external:1, /* page considered external (P) */
+ extcounted:1, /* page counted in ext counts (P) */
:0; /* (force to 'long' boundary) */
#ifdef ns32000
int pad; /* extra space for ns32000 bit ops */
@@ -184,6 +186,17 @@ extern
int vm_page_free_reserved; /* How many pages reserved to do pageout */
extern
int vm_page_laundry_count; /* How many pages being laundered? */
+extern
+int vm_page_external_limit; /* Max number of pages for external objects */
+
+/* Only objects marked with the extcounted bit are included in this total.
+ Pages which we scan for possible pageout, but which are not actually
+ dirty, don't get considered against the external page limits any more
+ in this way. */
+extern
+int vm_page_external_count; /* How many pages for external objects? */
+
+
decl_simple_lock_data(extern,vm_page_queue_lock)/* lock on active and inactive
page queues */
@@ -209,9 +222,9 @@ extern vm_page_t vm_page_lookup(
vm_offset_t offset);
extern vm_page_t vm_page_grab_fictitious(void);
extern void vm_page_release_fictitious(vm_page_t);
-extern boolean_t vm_page_convert(vm_page_t);
+extern boolean_t vm_page_convert(vm_page_t, boolean_t);
extern void vm_page_more_fictitious(void);
-extern vm_page_t vm_page_grab(void);
+extern vm_page_t vm_page_grab(boolean_t);
extern void vm_page_release(vm_page_t);
extern void vm_page_wait(void (*)(void));
extern vm_page_t vm_page_alloc(
diff --git a/vm/vm_pageout.c b/vm/vm_pageout.c
index 411531b..c36e2b3 100644
--- a/vm/vm_pageout.c
+++ b/vm/vm_pageout.c
@@ -63,11 +63,11 @@
#endif VM_PAGEOUT_BURST_MIN
#ifndef VM_PAGEOUT_BURST_WAIT
-#define VM_PAGEOUT_BURST_WAIT 30 /* milliseconds per page */
+#define VM_PAGEOUT_BURST_WAIT 10 /* milliseconds per page */
#endif VM_PAGEOUT_BURST_WAIT
#ifndef VM_PAGEOUT_EMPTY_WAIT
-#define VM_PAGEOUT_EMPTY_WAIT 200 /* milliseconds */
+#define VM_PAGEOUT_EMPTY_WAIT 75 /* milliseconds */
#endif VM_PAGEOUT_EMPTY_WAIT
#ifndef VM_PAGEOUT_PAUSE_MAX
@@ -108,16 +108,30 @@
#define VM_PAGE_FREE_MIN(free) (10 + (free) / 100)
#endif VM_PAGE_FREE_MIN
+/* When vm_page_external_count exceeds vm_page_external_limit,
+ * allocations of externally paged pages stops.
+ */
+
+#ifndef VM_PAGE_EXTERNAL_LIMIT
+#define VM_PAGE_EXTERNAL_LIMIT(free) ((free) / 2)
+#endif VM_PAGE_EXTERNAL_LIMIT
+
+/* Attempt to keep the number of externally paged pages less
+ * than vm_pages_external_target.
+ */
+#ifndef VM_PAGE_EXTERNAL_TARGET
+#define VM_PAGE_EXTERNAL_TARGET(free) ((free) / 4)
+#endif VM_PAGE_EXTERNAL_TARGET
+
/*
* When vm_page_free_count falls below vm_page_free_reserved,
* only vm-privileged threads can allocate pages. vm-privilege
* allows the pageout daemon and default pager (and any other
* associated threads needed for default pageout) to continue
- * operation by dipping into the reserved pool of pages.
- */
+ * operation by dipping into the reserved pool of pages. */
#ifndef VM_PAGE_FREE_RESERVED
-#define VM_PAGE_FREE_RESERVED 15
+#define VM_PAGE_FREE_RESERVED 50
#endif VM_PAGE_FREE_RESERVED
/*
@@ -129,7 +143,7 @@
*/
#ifndef VM_PAGEOUT_RESERVED_INTERNAL
-#define VM_PAGEOUT_RESERVED_INTERNAL(reserve) ((reserve) - 5)
+#define VM_PAGEOUT_RESERVED_INTERNAL(reserve) ((reserve) - 25)
#endif VM_PAGEOUT_RESERVED_INTERNAL
/*
@@ -141,7 +155,7 @@
*/
#ifndef VM_PAGEOUT_RESERVED_REALLY
-#define VM_PAGEOUT_RESERVED_REALLY(reserve) ((reserve) - 10)
+#define VM_PAGEOUT_RESERVED_REALLY(reserve) ((reserve) - 40)
#endif VM_PAGEOUT_RESERVED_REALLY
extern void vm_pageout_continue();
@@ -150,6 +164,8 @@ extern void vm_pageout_scan_continue();
unsigned int vm_pageout_reserved_internal = 0;
unsigned int vm_pageout_reserved_really = 0;
+unsigned int vm_pageout_external_target = 0;
+
unsigned int vm_pageout_burst_max = 0;
unsigned int vm_pageout_burst_min = 0;
unsigned int vm_pageout_burst_wait = 0; /* milliseconds per page */
@@ -172,6 +188,7 @@ unsigned int vm_pageout_inactive_used = 0; /* debugging */
unsigned int vm_pageout_inactive_clean = 0; /* debugging */
unsigned int vm_pageout_inactive_dirty = 0; /* debugging */
unsigned int vm_pageout_inactive_double = 0; /* debugging */
+unsigned int vm_pageout_inactive_cleaned_external = 0;
#if NORMA_VM
/*
@@ -503,6 +520,7 @@ vm_pageout_page(m, initial, flush)
void vm_pageout_scan()
{
unsigned int burst_count;
+ unsigned int want_pages;
/*
* We want to gradually dribble pages from the active queue
@@ -616,17 +634,20 @@ void vm_pageout_scan()
}
/*
- * We are done if we have met our target *and*
+ * We are done if we have met our targets *and*
* nobody is still waiting for a page.
*/
simple_lock(&vm_page_queue_free_lock);
free_count = vm_page_free_count;
- if ((free_count >= vm_page_free_target) &
+ if ((free_count >= vm_page_free_target) &&
+ (vm_page_external_count <= vm_page_external_target) &&
(vm_page_free_wanted == 0)) {
vm_page_unlock_queues();
break;
}
+ want_pages = ((free_count < vm_page_free_target) ||
+ vm_page_free_wanted);
simple_unlock(&vm_page_queue_free_lock);
/*
@@ -680,8 +701,10 @@ void vm_pageout_scan()
}
vm_pageout_inactive++;
- m = (vm_page_t) queue_first(&vm_page_queue_inactive);
- assert(!m->active && m->inactive);
+ for (m = (vm_page_t) queue_first(&vm_page_queue_inactive);
+ want_pages || m->external;
+ m = m->queue_next(m))
+ assert(!m->active && m->inactive);
object = m->object;
/*
@@ -727,7 +750,7 @@ void vm_pageout_scan()
* If it's absent, we can reclaim the page.
*/
- if (m->absent) {
+ if (want_pages && m->absent) {
vm_pageout_inactive_absent++;
reclaim_page:
vm_page_free(m);
@@ -760,6 +783,34 @@ void vm_pageout_scan()
if (!m->dirty)
m->dirty = pmap_is_modified(m->phys_addr);
+ if (m->external) {
+ /* Figure out if we still care about this
+ page in the limit of externally managed pages.
+ Clean pages don't actually cause system hosage,
+ so it's ok to stop considering them as
+ "consumers" of memory. */
+ if (m->dirty && !m->extcounted) {
+ m->extcounted = TRUE;
+ vm_page_external_count++;
+ else if (!m->dirty && m->extcounted) {
+ m->extcounted = FALSE;
+ vm_page_external_count--;
+ }
+ }
+
+ /* If we don't actually need more memory, and the page
+ is not dirty, put it on the tail of the inactive queue
+ and move on to the next page. */
+ if (!want_pages && !m->dirty) {
+ queue_remove (&vm_page_queue_inactive, m,
+ vm_page_t, pageq);
+ queue_enter (&vm_page_queue_inactive, m,
+ vm_page_t, pageq);
+ vm_page_unlock_queues();
+ vm_pageout_inactive_cleaned_external++;
+ continue;
+ }
+
/*
* If it's clean and not precious, we can free the page.
*/
@@ -904,6 +955,14 @@ void vm_pageout()
free_after_reserve = vm_page_free_count - vm_page_free_reserved;
+ if (vm_page_external_limit == 0)
+ vm_page_external_limit =
+ VM_PAGE_EXTERNAL_LIMIT (free_after_reserve);
+
+ if (vm_page_external_target == 0)
+ vm_page_external_target =
+ VM_PAGE_EXTERNAL_TARGET (free_after_reserve);
+
if (vm_page_free_min == 0)
vm_page_free_min = vm_page_free_reserved +
VM_PAGE_FREE_MIN(free_after_reserve);
diff --git a/vm/vm_resident.c b/vm/vm_resident.c
index eba0157..5014da4 100644
--- a/vm/vm_resident.c
+++ b/vm/vm_resident.c
@@ -111,6 +111,7 @@ decl_simple_lock_data(,vm_page_queue_free_lock)
unsigned int vm_page_free_wanted;
int vm_page_free_count;
int vm_page_fictitious_count;
+int vm_page_external_count;
unsigned int vm_page_free_count_minimum; /* debugging */
@@ -201,6 +202,7 @@ void vm_page_bootstrap(
m->active = FALSE;
m->laundry = FALSE;
m->free = FALSE;
+ m->external = FALSE;
m->busy = TRUE;
m->wanted = FALSE;
@@ -396,7 +398,7 @@ void pmap_startup(
*/
for (i = pages_initialized; i > 0; i--) {
- vm_page_release(&pages[i - 1]);
+ vm_page_release(&pages[i - 1], FALSE);
}
/*
@@ -449,7 +451,7 @@ void vm_page_create(
panic("vm_page_create");
vm_page_init(m, paddr);
- vm_page_release(m);
+ vm_page_release(m, FALSE);
}
}
@@ -816,11 +818,12 @@ void vm_page_more_fictitious(void)
*/
boolean_t vm_page_convert(
- register vm_page_t m)
+ register vm_page_t m,
+ boolean_t external)
{
register vm_page_t real_m;
- real_m = vm_page_grab();
+ real_m = vm_page_grab(external);
if (real_m == VM_PAGE_NULL)
return FALSE;
@@ -841,7 +844,8 @@ boolean_t vm_page_convert(
* Returns VM_PAGE_NULL if the free list is too small.
*/
-vm_page_t vm_page_grab(void)
+vm_page_t vm_page_grab(
+ boolean_t external)
{
register vm_page_t mem;
@@ -849,10 +853,12 @@ vm_page_t vm_page_grab(void)
/*
* Only let privileged threads (involved in pageout)
- * dip into the reserved pool.
+ * dip into the reserved pool or exceed the limit
+ * for externally-managed pages.
*/
- if ((vm_page_free_count < vm_page_free_reserved) &&
+ if (((vm_page_free_count < vm_page_free_reserved) ||
+ (vm_page_external_count >= vm_page_external_limit)) &&
!current_thread()->vm_privilege) {
simple_unlock(&vm_page_queue_free_lock);
return VM_PAGE_NULL;
@@ -863,9 +869,12 @@ vm_page_t vm_page_grab(void)
if (--vm_page_free_count < vm_page_free_count_minimum)
vm_page_free_count_minimum = vm_page_free_count;
+ if (external)
+ vm_page_external_count++;
mem = vm_page_queue_free;
vm_page_queue_free = (vm_page_t) mem->pageq.next;
mem->free = FALSE;
+ mem->extcounted = mem->external = external;
simple_unlock(&vm_page_queue_free_lock);
/*
@@ -887,9 +896,9 @@ vm_page_t vm_page_grab(void)
return mem;
}
-vm_offset_t vm_page_grab_phys_addr(void)
+vm_offset_t vm_page_grab_phys_addr()
{
- vm_page_t p = vm_page_grab();
+ vm_page_t p = vm_page_grab(FALSE);
if (p == VM_PAGE_NULL)
return -1;
else
@@ -915,7 +924,8 @@ kern_return_t
vm_page_grab_contiguous_pages(
int npages,
vm_page_t pages[],
- natural_t *bits)
+ natural_t *bits,
+ boolean_t external)
{
register int first_set;
int size, alloc_size;
@@ -959,7 +969,8 @@ vm_page_grab_contiguous_pages(
* Do not dip into the reserved pool.
*/
- if (vm_page_free_count < vm_page_free_reserved) {
+ if ((vm_page_free_count < vm_page_free_reserved)
+ || (vm_page_external_count >= vm_page_external_limit)) {
simple_unlock(&vm_page_queue_free_lock);
return KERN_RESOURCE_SHORTAGE;
}
@@ -1063,7 +1074,8 @@ found_em:
vm_page_free_count -= npages;
if (vm_page_free_count < vm_page_free_count_minimum)
vm_page_free_count_minimum = vm_page_free_count;
-
+ if (external)
+ vm_page_external_count += npages;
{
register vm_offset_t first_phys, last_phys;
@@ -1087,6 +1099,7 @@ found_em:
prevmem->pageq.next = mem->pageq.next;
pages[(addr - first_phys) >> PAGE_SHIFT] = mem;
mem->free = FALSE;
+ mem->extcounted = mem->external = external;
/*
* Got them all ?
*/
@@ -1131,7 +1144,8 @@ out:
*/
void vm_page_release(
- register vm_page_t mem)
+ register vm_page_t mem,
+ boolean_t external)
{
simple_lock(&vm_page_queue_free_lock);
if (mem->free)
@@ -1140,6 +1154,8 @@ void vm_page_release(
mem->pageq.next = (queue_entry_t) vm_page_queue_free;
vm_page_queue_free = mem;
vm_page_free_count++;
+ if (external)
+ vm_page_external_count--;
/*
* Check if we should wake up someone waiting for page.
@@ -1225,7 +1241,7 @@ vm_page_t vm_page_alloc(
{
register vm_page_t mem;
- mem = vm_page_grab();
+ mem = vm_page_grab(!object->internal);
if (mem == VM_PAGE_NULL)
return VM_PAGE_NULL;
@@ -1280,8 +1296,9 @@ void vm_page_free(
mem->fictitious = TRUE;
vm_page_release_fictitious(mem);
} else {
+ int external = mem->external && mem->extcounted;
vm_page_init(mem, mem->phys_addr);
- vm_page_release(mem);
+ vm_page_release(mem, external);
}
}