summaryrefslogtreecommitdiffstats
path: root/sys/vm
diff options
context:
space:
mode:
authornetchild <netchild@FreeBSD.org>2005-12-31 14:39:20 +0000
committernetchild <netchild@FreeBSD.org>2005-12-31 14:39:20 +0000
commit507a9b3e936156202e89c42d2265863c3903254f (patch)
treec13a8d302e0337dbf08ab02516a66627814ead6b /sys/vm
parentcd697cab850aef4c7941ebff10521fc87dbf7aee (diff)
downloadFreeBSD-src-507a9b3e936156202e89c42d2265863c3903254f.zip
FreeBSD-src-507a9b3e936156202e89c42d2265863c3903254f.tar.gz
MI changes:
- provide an interface (macros) to the page coloring part of the VM system, this allows to try different coloring algorithms without the need to touch every file [1] - make the page queue tuning values readable: sysctl vm.stats.pagequeue - autotuning of the page coloring values based upon the cache size instead of options in the kernel config (disabling of the page coloring as a kernel option is still possible) MD changes: - detection of the cache size: only IA32 and AMD64 (untested) contains cache size detection code, every other arch just comes with a dummy function (this results in the use of default values like it was the case without the autotuning of the page coloring) - print some more info on Intel CPU's (like we do on AMD and Transmeta CPU's) Note to AMD owners (IA32 and AMD64): please run "sysctl vm.stats.pagequeue" and report if the cache* values are zero (= bug in the cache detection code) or not. Based upon work by: Chad David <davidc@acns.ab.ca> [1] Reviewed by: alc, arch (in 2004) Discussed with: alc, Chad David, arch (in 2004)
Diffstat (limited to 'sys/vm')
-rw-r--r--sys/vm/vm_contig.c11
-rw-r--r--sys/vm/vm_fault.c5
-rw-r--r--sys/vm/vm_object.c19
-rw-r--r--sys/vm/vm_page.c42
-rw-r--r--sys/vm/vm_page.h115
-rw-r--r--sys/vm/vm_pageout.c12
-rw-r--r--sys/vm/vm_pageq.c152
-rw-r--r--sys/vm/vm_zeroidle.c2
8 files changed, 213 insertions, 145 deletions
diff --git a/sys/vm/vm_contig.c b/sys/vm/vm_contig.c
index 3d57203..c622285 100644
--- a/sys/vm/vm_contig.c
+++ b/sys/vm/vm_contig.c
@@ -141,7 +141,7 @@ vm_contig_launder(int queue)
if ((m->flags & PG_MARKER) != 0)
continue;
- KASSERT(m->queue == queue,
+ KASSERT(VM_PAGE_INQUEUE2(m, queue),
("vm_contig_launder: page %p's queue is not %d", m, queue));
error = vm_contig_launder_page(m);
if (error == 0)
@@ -255,7 +255,7 @@ again1:
for (i = start; i < (start + size / PAGE_SIZE); i++) {
vm_page_t m = &pga[i];
- if ((m->queue - m->pc) == PQ_CACHE) {
+ if (VM_PAGE_INQUEUE1(m, PQ_CACHE)) {
if (m->hold_count != 0) {
start++;
goto again0;
@@ -456,16 +456,15 @@ retry_page:
pqtype = m->queue - m->pc;
if (pass != 0 && pqtype != PQ_FREE &&
pqtype != PQ_CACHE) {
- switch (m->queue) {
- case PQ_ACTIVE:
- case PQ_INACTIVE:
+ if (m->queue == PQ_ACTIVE ||
+ m->queue == PQ_INACTIVE) {
if (vm_contig_launder_page(m) != 0)
goto cleanup_freed;
pqtype = m->queue - m->pc;
if (pqtype == PQ_FREE ||
pqtype == PQ_CACHE)
break;
- default:
+ } else {
cleanup_freed:
vm_page_release_contigl(&pga[i + 1],
start + npages - 1 - i);
diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c
index 4b7151b..a2e0b3a 100644
--- a/sys/vm/vm_fault.c
+++ b/sys/vm/vm_fault.c
@@ -410,7 +410,8 @@ RetryFault:;
vm_pageq_remove_nowakeup(fs.m);
- if ((queue - fs.m->pc) == PQ_CACHE && vm_page_count_severe()) {
+ if ((queue - fs.m->pc) == PQ_CACHE \
+ && vm_page_count_severe()) {
vm_page_activate(fs.m);
vm_page_unlock_queues();
unlock_and_deallocate(&fs);
@@ -1006,7 +1007,7 @@ vm_fault_prefault(pmap_t pmap, vm_offset_t addra, vm_map_entry_t entry)
(m->flags & (PG_BUSY | PG_FICTITIOUS)) == 0) {
vm_page_lock_queues();
- if ((m->queue - m->pc) == PQ_CACHE)
+ if (VM_PAGE_INQUEUE1(m, PQ_CACHE))
vm_page_deactivate(m);
mpte = pmap_enter_quick(pmap, addr, m,
entry->protection, mpte);
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c
index e8239a3..e7d7630 100644
--- a/sys/vm/vm_object.c
+++ b/sys/vm/vm_object.c
@@ -215,12 +215,11 @@ _vm_object_allocate(objtype_t type, vm_pindex_t size, vm_object_t object)
object->flags = 0;
if ((object->type == OBJT_DEFAULT) || (object->type == OBJT_SWAP))
object->flags = OBJ_ONEMAPPING;
- if (size > (PQ_L2_SIZE / 3 + PQ_PRIME1))
- incr = PQ_L2_SIZE / 3 + PQ_PRIME1;
- else
+ incr = PQ_MAXLENGTH;
+ if (size <= incr)
incr = size;
object->pg_color = next_index;
- next_index = (object->pg_color + incr) & PQ_L2_MASK;
+ next_index = (object->pg_color + incr) & PQ_COLORMASK;
object->handle = NULL;
object->backing_object = NULL;
object->backing_object_offset = (vm_ooffset_t) 0;
@@ -1228,15 +1227,13 @@ vm_object_shadow(
source->generation++;
if (length < source->size)
length = source->size;
- if (length > PQ_L2_SIZE / 3 + PQ_PRIME1 ||
- source->generation > 1)
- length = PQ_L2_SIZE / 3 + PQ_PRIME1;
+ if (length > PQ_MAXLENGTH || source->generation > 1)
+ length = PQ_MAXLENGTH;
result->pg_color = (source->pg_color +
- length * source->generation) & PQ_L2_MASK;
+ length * source->generation) & PQ_COLORMASK;
result->flags |= source->flags & OBJ_NEEDGIANT;
VM_OBJECT_UNLOCK(source);
- next_index = (result->pg_color + PQ_L2_SIZE / 3 + PQ_PRIME1) &
- PQ_L2_MASK;
+ next_index = (result->pg_color + PQ_MAXLENGTH) & PQ_COLORMASK;
}
@@ -2127,7 +2124,7 @@ DB_SHOW_COMMAND(vmopag, vm_object_print_pages)
if (rcount) {
padiff = pa + rcount * PAGE_SIZE - VM_PAGE_TO_PHYS(m);
padiff >>= PAGE_SHIFT;
- padiff &= PQ_L2_MASK;
+ padiff &= PQ_COLORMASK;
if (padiff == 0) {
pa = VM_PAGE_TO_PHYS(m) - rcount * PAGE_SIZE;
++rcount;
diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c
index b8e3321..611be84 100644
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -382,7 +382,7 @@ vm_page_unhold(vm_page_t mem)
mtx_assert(&vm_page_queue_mtx, MA_OWNED);
--mem->hold_count;
KASSERT(mem->hold_count >= 0, ("vm_page_unhold: hold count < 0!!!"));
- if (mem->hold_count == 0 && mem->queue == PQ_HOLD)
+ if (mem->hold_count == 0 && VM_PAGE_INQUEUE2(mem, PQ_HOLD))
vm_page_free_toq(mem);
}
@@ -457,9 +457,9 @@ vm_page_sleep_if_busy(vm_page_t m, int also_m_busy, const char *msg)
void
vm_page_dirty(vm_page_t m)
{
- KASSERT(m->queue - m->pc != PQ_CACHE,
+ KASSERT(VM_PAGE_GETKNOWNQUEUE1(m) != PQ_CACHE,
("vm_page_dirty: page in cache!"));
- KASSERT(m->queue - m->pc != PQ_FREE,
+ KASSERT(VM_PAGE_GETKNOWNQUEUE1(m) != PQ_FREE,
("vm_page_dirty: page is free!"));
m->dirty = VM_PAGE_BITS_ALL;
}
@@ -700,7 +700,7 @@ vm_page_rename(vm_page_t m, vm_object_t new_object, vm_pindex_t new_pindex)
vm_page_remove(m);
vm_page_insert(m, new_object, new_pindex);
- if (m->queue - m->pc == PQ_CACHE)
+ if (VM_PAGE_INQUEUE1(m, PQ_CACHE))
vm_page_deactivate(m);
vm_page_dirty(m);
}
@@ -777,9 +777,9 @@ vm_page_alloc(vm_object_t object, vm_pindex_t pindex, int req)
KASSERT(object != NULL,
("vm_page_alloc: NULL object."));
VM_OBJECT_LOCK_ASSERT(object, MA_OWNED);
- color = (pindex + object->pg_color) & PQ_L2_MASK;
+ color = (pindex + object->pg_color) & PQ_COLORMASK;
} else
- color = pindex & PQ_L2_MASK;
+ color = pindex & PQ_COLORMASK;
/*
* The pager is allowed to eat deeper into the free page list.
@@ -946,8 +946,8 @@ vm_page_activate(vm_page_t m)
{
mtx_assert(&vm_page_queue_mtx, MA_OWNED);
- if (m->queue != PQ_ACTIVE) {
- if ((m->queue - m->pc) == PQ_CACHE)
+ if (VM_PAGE_GETKNOWNQUEUE2(m) != PQ_ACTIVE) {
+ if (VM_PAGE_INQUEUE1(m, PQ_CACHE))
cnt.v_reactivated++;
vm_pageq_remove(m);
if (m->wire_count == 0 && (m->flags & PG_UNMANAGED) == 0) {
@@ -1016,12 +1016,12 @@ vm_page_free_toq(vm_page_t m)
("vm_page_free_toq: freeing mapped page %p", m));
cnt.v_tfree++;
- if (m->busy || ((m->queue - m->pc) == PQ_FREE)) {
+ if (m->busy || VM_PAGE_INQUEUE1(m, PQ_FREE)) {
printf(
"vm_page_free: pindex(%lu), busy(%d), PG_BUSY(%d), hold(%d)\n",
(u_long)m->pindex, m->busy, (m->flags & PG_BUSY) ? 1 : 0,
m->hold_count);
- if ((m->queue - m->pc) == PQ_FREE)
+ if (VM_PAGE_INQUEUE1(m, PQ_FREE))
panic("vm_page_free: freeing free page");
else
panic("vm_page_free: freeing busy page");
@@ -1064,10 +1064,10 @@ vm_page_free_toq(vm_page_t m)
if (m->hold_count != 0) {
m->flags &= ~PG_ZERO;
- m->queue = PQ_HOLD;
+ VM_PAGE_SETQUEUE2(m, PQ_HOLD);
} else
- m->queue = PQ_FREE + m->pc;
- pq = &vm_page_queues[m->queue];
+ VM_PAGE_SETQUEUE1(m, PQ_FREE);
+ pq = &vm_page_queues[VM_PAGE_GETQUEUE(m)];
mtx_lock_spin(&vm_page_queue_free_mtx);
pq->lcnt++;
++(*pq->cnt);
@@ -1220,10 +1220,10 @@ _vm_page_deactivate(vm_page_t m, int athead)
/*
* Ignore if already inactive.
*/
- if (m->queue == PQ_INACTIVE)
+ if (VM_PAGE_INQUEUE2(m, PQ_INACTIVE))
return;
if (m->wire_count == 0 && (m->flags & PG_UNMANAGED) == 0) {
- if ((m->queue - m->pc) == PQ_CACHE)
+ if (VM_PAGE_INQUEUE1(m, PQ_CACHE))
cnt.v_reactivated++;
vm_page_flag_clear(m, PG_WINATCFLS);
vm_pageq_remove(m);
@@ -1231,7 +1231,7 @@ _vm_page_deactivate(vm_page_t m, int athead)
TAILQ_INSERT_HEAD(&vm_page_queues[PQ_INACTIVE].pl, m, pageq);
else
TAILQ_INSERT_TAIL(&vm_page_queues[PQ_INACTIVE].pl, m, pageq);
- m->queue = PQ_INACTIVE;
+ VM_PAGE_SETQUEUE2(m, PQ_INACTIVE);
vm_page_queues[PQ_INACTIVE].lcnt++;
cnt.v_inactive_count++;
}
@@ -1307,7 +1307,7 @@ vm_page_cache(vm_page_t m)
printf("vm_page_cache: attempting to cache busy page\n");
return;
}
- if ((m->queue - m->pc) == PQ_CACHE)
+ if (VM_PAGE_INQUEUE1(m, PQ_CACHE))
return;
/*
@@ -1359,8 +1359,8 @@ vm_page_dontneed(vm_page_t m)
* occassionally leave the page alone
*/
if ((dnw & 0x01F0) == 0 ||
- m->queue == PQ_INACTIVE ||
- m->queue - m->pc == PQ_CACHE
+ VM_PAGE_INQUEUE2(m, PQ_INACTIVE) ||
+ VM_PAGE_INQUEUE1(m, PQ_CACHE)
) {
if (m->act_count >= ACT_INIT)
--m->act_count;
@@ -1734,13 +1734,13 @@ DB_SHOW_COMMAND(pageq, vm_page_print_pageq_info)
{
int i;
db_printf("PQ_FREE:");
- for (i = 0; i < PQ_L2_SIZE; i++) {
+ for (i = 0; i < PQ_NUMCOLORS; i++) {
db_printf(" %d", vm_page_queues[PQ_FREE + i].lcnt);
}
db_printf("\n");
db_printf("PQ_CACHE:");
- for (i = 0; i < PQ_L2_SIZE; i++) {
+ for (i = 0; i < PQ_NUMCOLORS; i++) {
db_printf(" %d", vm_page_queues[PQ_CACHE + i].lcnt);
}
db_printf("\n");
diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h
index 4ca7d24..0d1ffc4 100644
--- a/sys/vm/vm_page.h
+++ b/sys/vm/vm_page.h
@@ -146,70 +146,39 @@ CTASSERT(sizeof(u_long) >= 8);
#endif
#endif
-#if !defined(KLD_MODULE)
-/*
- * Page coloring parameters
- */
-
-/* Backward compatibility for existing PQ_*CACHE config options. */
-#if !defined(PQ_CACHESIZE)
-#if defined(PQ_HUGECACHE)
-#define PQ_CACHESIZE 1024
-#elif defined(PQ_LARGECACHE)
-#define PQ_CACHESIZE 512
-#elif defined(PQ_MEDIUMCACHE)
-#define PQ_CACHESIZE 256
-#elif defined(PQ_NORMALCACHE)
-#define PQ_CACHESIZE 64
-#elif defined(PQ_NOOPT)
-#define PQ_CACHESIZE 0
-#else
-#define PQ_CACHESIZE 128
-#endif
-#endif /* !defined(PQ_CACHESIZE) */
-
-#if PQ_CACHESIZE >= 1024
-#define PQ_PRIME1 31 /* Prime number somewhat less than PQ_L2_SIZE */
-#define PQ_PRIME2 23 /* Prime number somewhat less than PQ_L2_SIZE */
-#define PQ_L2_SIZE 256 /* A number of colors opt for 1M cache */
-
-#elif PQ_CACHESIZE >= 512
-#define PQ_PRIME1 31 /* Prime number somewhat less than PQ_L2_SIZE */
-#define PQ_PRIME2 23 /* Prime number somewhat less than PQ_L2_SIZE */
-#define PQ_L2_SIZE 128 /* A number of colors opt for 512K cache */
-
-#elif PQ_CACHESIZE >= 256
-#define PQ_PRIME1 13 /* Prime number somewhat less than PQ_L2_SIZE */
-#define PQ_PRIME2 7 /* Prime number somewhat less than PQ_L2_SIZE */
-#define PQ_L2_SIZE 64 /* A number of colors opt for 256K cache */
-
-#elif PQ_CACHESIZE >= 128
-#define PQ_PRIME1 9 /* Produces a good PQ_L2_SIZE/3 + PQ_PRIME1 */
-#define PQ_PRIME2 5 /* Prime number somewhat less than PQ_L2_SIZE */
-#define PQ_L2_SIZE 32 /* A number of colors opt for 128k cache */
-
-#elif PQ_CACHESIZE >= 64
-#define PQ_PRIME1 5 /* Prime number somewhat less than PQ_L2_SIZE */
-#define PQ_PRIME2 3 /* Prime number somewhat less than PQ_L2_SIZE */
-#define PQ_L2_SIZE 16 /* A reasonable number of colors (opt for 64K cache) */
-
-#else
-#define PQ_PRIME1 1 /* Disable page coloring. */
-#define PQ_PRIME2 1
-#define PQ_L2_SIZE 1
-
-#endif
-
-#define PQ_L2_MASK (PQ_L2_SIZE - 1)
-
-/* PQ_CACHE and PQ_FREE represent PQ_L2_SIZE consecutive queues. */
-#define PQ_NONE 0
-#define PQ_FREE 1
-#define PQ_INACTIVE (1 + 1*PQ_L2_SIZE)
-#define PQ_ACTIVE (2 + 1*PQ_L2_SIZE)
-#define PQ_CACHE (3 + 1*PQ_L2_SIZE)
-#define PQ_HOLD (3 + 2*PQ_L2_SIZE)
-#define PQ_COUNT (4 + 2*PQ_L2_SIZE)
+/* PQ_CACHE and PQ_FREE represents a PQ_NUMCOLORS consecutive queue. */
+#define PQ_NONE 0
+#define PQ_FREE 1
+#define PQ_INACTIVE (page_queue_coloring.inactive)
+#define PQ_ACTIVE (page_queue_coloring.active)
+#define PQ_CACHE (page_queue_coloring.cache)
+#define PQ_HOLD (page_queue_coloring.hold)
+#define PQ_COUNT (page_queue_coloring.count)
+#define PQ_MAXCOLORS 1024
+#define PQ_MAXCOUNT (4 + 2 * PQ_MAXCOLORS)
+#define PQ_NUMCOLORS (page_queue_coloring.numcolors)
+#define PQ_PRIME1 (page_queue_coloring.prime1)
+#define PQ_PRIME2 (page_queue_coloring.prime2)
+#define PQ_COLORMASK (page_queue_coloring.colormask)
+#define PQ_MAXLENGTH (page_queue_coloring.maxlength)
+
+/* Returns the real queue a page is on. */
+#define VM_PAGE_GETQUEUE(m) ((m)->queue)
+
+/* Returns the well known queue a page is on. */
+#define VM_PAGE_GETKNOWNQUEUE1(m) ((m)->queue - (m)->pc)
+#define VM_PAGE_GETKNOWNQUEUE2(m) VM_PAGE_GETQUEUE(m)
+
+/* Given the real queue number and a page color return the well know queue. */
+#define VM_PAGE_RESOLVEQUEUE(m, q) ((q) - (m)->pc)
+
+/* Returns true if the page is in the named well known queue. */
+#define VM_PAGE_INQUEUE1(m, q) (VM_PAGE_GETKNOWNQUEUE1(m) == (q))
+#define VM_PAGE_INQUEUE2(m, q) (VM_PAGE_GETKNOWNQUEUE2(m) == (q))
+
+/* Sets the queue a page is on. */
+#define VM_PAGE_SETQUEUE1(m, q) (VM_PAGE_GETQUEUE(m) = (q) + (m)->pc)
+#define VM_PAGE_SETQUEUE2(m, q) (VM_PAGE_GETQUEUE(m) = (q))
struct vpgqueues {
struct pglist pl;
@@ -217,10 +186,22 @@ struct vpgqueues {
int lcnt;
};
-extern struct vpgqueues vm_page_queues[PQ_COUNT];
-extern struct mtx vm_page_queue_free_mtx;
+struct pq_coloring {
+ int numcolors;
+ int colormask;
+ int prime1;
+ int prime2;
+ int inactive;
+ int active;
+ int cache;
+ int hold;
+ int count;
+ int maxlength;
+};
-#endif /* !defined(KLD_MODULE) */
+extern struct vpgqueues vm_page_queues[PQ_MAXCOUNT];
+extern struct mtx vm_page_queue_free_mtx;
+extern struct pq_coloring page_queue_coloring;
/*
* These are the flags defined for vm_page.
diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c
index 0a56ca1..9d29de3 100644
--- a/sys/vm/vm_pageout.c
+++ b/sys/vm/vm_pageout.c
@@ -741,7 +741,7 @@ rescan0:
cnt.v_pdpages++;
- if (m->queue != PQ_INACTIVE) {
+ if (VM_PAGE_GETQUEUE(m) != PQ_INACTIVE) {
goto rescan0;
}
@@ -957,7 +957,7 @@ rescan0:
* reused for another vnode. The object might
* have been reused for another vnode.
*/
- if (m->queue != PQ_INACTIVE ||
+ if (VM_PAGE_GETQUEUE(m) != PQ_INACTIVE ||
m->object != object ||
object->handle != vp) {
if (object->flags & OBJ_MIGHTBEDIRTY)
@@ -1039,7 +1039,7 @@ unlock_and_continue:
while ((m != NULL) && (pcount-- > 0) && (page_shortage > 0)) {
- KASSERT(m->queue == PQ_ACTIVE,
+ KASSERT(VM_PAGE_INQUEUE2(m, PQ_ACTIVE),
("vm_pageout_scan: page %p isn't active", m));
next = TAILQ_NEXT(m, pageq);
@@ -1132,7 +1132,7 @@ unlock_and_continue:
cache_cur = cache_last_free;
cache_first_failure = -1;
while (cnt.v_free_count < cnt.v_free_reserved && (cache_cur =
- (cache_cur + PQ_PRIME2) & PQ_L2_MASK) != cache_first_failure) {
+ (cache_cur + PQ_PRIME2) & PQ_COLORMASK) != cache_first_failure) {
TAILQ_FOREACH(m, &vm_page_queues[PQ_CACHE + cache_cur].pl,
pageq) {
KASSERT(m->dirty == 0,
@@ -1316,7 +1316,7 @@ vm_pageout_page_stats()
while ((m != NULL) && (pcount-- > 0)) {
int actcount;
- KASSERT(m->queue == PQ_ACTIVE,
+ KASSERT(VM_PAGE_INQUEUE2(m, PQ_ACTIVE),
("vm_pageout_page_stats: page %p isn't active", m));
next = TAILQ_NEXT(m, pageq);
@@ -1407,7 +1407,7 @@ vm_pageout()
cnt.v_pageout_free_min = (2*MAXBSIZE)/PAGE_SIZE +
cnt.v_interrupt_free_min;
cnt.v_free_reserved = vm_pageout_page_count +
- cnt.v_pageout_free_min + (cnt.v_page_count / 768) + PQ_L2_SIZE;
+ cnt.v_pageout_free_min + (cnt.v_page_count / 768) + PQ_NUMCOLORS;
cnt.v_free_severe = cnt.v_free_min / 2;
cnt.v_free_min += cnt.v_free_reserved;
cnt.v_free_severe += cnt.v_free_reserved;
diff --git a/sys/vm/vm_pageq.c b/sys/vm/vm_pageq.c
index 1ed1d3e..a743840 100644
--- a/sys/vm/vm_pageq.c
+++ b/sys/vm/vm_pageq.c
@@ -30,9 +30,11 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/linker_set.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
+#include <sys/sysctl.h>
#include <sys/proc.h>
#include <sys/vmmeter.h>
#include <sys/vnode.h>
@@ -46,18 +48,99 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_pager.h>
#include <vm/vm_extern.h>
-struct vpgqueues vm_page_queues[PQ_COUNT];
+static void vm_coloring_init(void);
+void setPQL2(int *const size, int *const ways);
+
+struct vpgqueues vm_page_queues[PQ_MAXCOUNT];
+struct pq_coloring page_queue_coloring;
+
+static int pq_cachesize = 0; /* size of the cache in KB */
+static int pq_cachenways = 0; /* associativity of the cache */
+
+SYSCTL_DECL(_vm_stats);
+SYSCTL_NODE(_vm_stats, OID_AUTO, pagequeue, CTLFLAG_RW, 0, "VM meter stats");
+SYSCTL_INT(_vm_stats_pagequeue, OID_AUTO, page_colors, CTLFLAG_RD,
+ &(PQ_NUMCOLORS), 0, "Number of colors in the page queue");
+SYSCTL_INT(_vm_stats_pagequeue, OID_AUTO, cachesize, CTLFLAG_RD,
+ &pq_cachesize, 0, "Size of the processor cache in KB");
+SYSCTL_INT(_vm_stats_pagequeue, OID_AUTO, cachenways, CTLFLAG_RD,
+ &pq_cachenways, 0, "Associativity of the processor cache");
+SYSCTL_INT(_vm_stats_pagequeue, OID_AUTO, prime1, CTLFLAG_RD,
+ &(PQ_PRIME1), 0, "Cache tuning value");
+SYSCTL_INT(_vm_stats_pagequeue, OID_AUTO, prime2, CTLFLAG_RD,
+ &(PQ_PRIME2), 0, "Cache tuning value");
+
+static void
+vm_coloring_init(void)
+{
+#ifdef PQ_NOOPT
+ PQ_NUMCOLORS = PQ_PRIME1 = PQ_PRIME2 = 1;
+#else
+
+ setPQL2(&pq_cachesize, &pq_cachenways);
+
+ if (pq_cachesize > 0)
+ PQ_NUMCOLORS = pq_cachesize / (PAGE_SIZE/1024) / \
+ pq_cachenways;
+ else
+ PQ_NUMCOLORS = 32;
+
+ if (PQ_MAXCOLORS < PQ_NUMCOLORS) {
+ printf("VM-PQ color limit (PQ_MAXCOLORS=%u) exceeded (%u), see vm_page.h", PQ_MAXCOLORS, PQ_NUMCOLORS);
+ PQ_NUMCOLORS = PQ_MAXCOLORS;
+ }
+
+ if (PQ_NUMCOLORS >= 128) {
+ PQ_PRIME1 = 31;
+ PQ_PRIME2 = 23;
+ } else if (PQ_NUMCOLORS >= 64) {
+ PQ_PRIME1 = 13;
+ PQ_PRIME2 = 7;
+ } else if (PQ_NUMCOLORS >= 32) {
+ PQ_PRIME1 = 9;
+ PQ_PRIME2 = 5;
+ } else if (PQ_NUMCOLORS >= 16) {
+ PQ_PRIME1 = 5;
+ PQ_PRIME2 = 3;
+ } else
+ PQ_NUMCOLORS = PQ_PRIME1 = PQ_PRIME2 = 1;
+#endif
+
+ /*
+ * PQ_CACHE represents a
+ * PQ_NUMCOLORS consecutive queue.
+ */
+ PQ_COLORMASK = PQ_NUMCOLORS - 1;
+ PQ_INACTIVE = 1 + PQ_NUMCOLORS;
+ PQ_ACTIVE = 2 + PQ_NUMCOLORS;
+ PQ_CACHE = 3 + PQ_NUMCOLORS;
+ PQ_HOLD = 3 + 2 * PQ_NUMCOLORS;
+ PQ_COUNT = 4 + 2 * PQ_NUMCOLORS;
+ PQ_MAXLENGTH = PQ_NUMCOLORS / 3 + PQ_PRIME1;
+
+#if 0
+ /* XXX: is it possible to allocate vm_page_queues[PQ_COUNT] here? */
+#error XXX: vm_page_queues = malloc(PQ_COUNT * sizeof(struct vpgqueues));
+#endif
+
+ if (bootverbose)
+ if (PQ_NUMCOLORS > 1)
+ printf("Using %d colors for the VM-PQ tuning (%d, %d)\n",
+ PQ_NUMCOLORS, pq_cachesize, pq_cachenways);
+}
void
-vm_pageq_init(void)
+vm_pageq_init(void)
{
int i;
- for (i = 0; i < PQ_L2_SIZE; i++) {
+ vm_coloring_init();
+
+ for (i = 0; i < PQ_NUMCOLORS; ++i) {
vm_page_queues[PQ_FREE+i].cnt = &cnt.v_free_count;
}
- for (i = 0; i < PQ_L2_SIZE; i++) {
- vm_page_queues[PQ_CACHE+i].cnt = &cnt.v_cache_count;
+ for (i = 0; i < PQ_NUMCOLORS; ++i) {
+ vm_page_queues[PQ_CACHE + i].cnt = &cnt.v_cache_count;
}
vm_page_queues[PQ_INACTIVE].cnt = &cnt.v_inactive_count;
vm_page_queues[PQ_ACTIVE].cnt = &cnt.v_active_count;
@@ -71,7 +154,7 @@ vm_pageq_init(void)
void
vm_pageq_requeue(vm_page_t m)
{
- int queue = m->queue;
+ int queue = VM_PAGE_GETQUEUE(m);
struct vpgqueues *vpq;
if (queue != PQ_NONE) {
@@ -90,7 +173,7 @@ vm_pageq_enqueue(int queue, vm_page_t m)
struct vpgqueues *vpq;
vpq = &vm_page_queues[queue];
- m->queue = queue;
+ VM_PAGE_SETQUEUE2(m, queue);
TAILQ_INSERT_TAIL(&vpq->pl, m, pageq);
++*vpq->cnt;
++vpq->lcnt;
@@ -142,7 +225,7 @@ vm_pageq_add_new_page(vm_paddr_t pa)
m = PHYS_TO_VM_PAGE(pa);
m->phys_addr = pa;
m->flags = 0;
- m->pc = (pa >> PAGE_SHIFT) & PQ_L2_MASK;
+ m->pc = (pa >> PAGE_SHIFT) & PQ_COLORMASK;
pmap_page_init(m);
vm_pageq_enqueue(m->pc + PQ_FREE, m);
return (m);
@@ -159,11 +242,11 @@ vm_pageq_add_new_page(vm_paddr_t pa)
void
vm_pageq_remove_nowakeup(vm_page_t m)
{
- int queue = m->queue;
+ int queue = VM_PAGE_GETQUEUE(m);
struct vpgqueues *pq;
if (queue != PQ_NONE) {
pq = &vm_page_queues[queue];
- m->queue = PQ_NONE;
+ VM_PAGE_SETQUEUE2(m, PQ_NONE);
TAILQ_REMOVE(&pq->pl, m, pageq);
(*pq->cnt)--;
pq->lcnt--;
@@ -181,11 +264,11 @@ vm_pageq_remove_nowakeup(vm_page_t m)
void
vm_pageq_remove(vm_page_t m)
{
- int queue = m->queue;
+ int queue = VM_PAGE_GETQUEUE(m);
struct vpgqueues *pq;
if (queue != PQ_NONE) {
- m->queue = PQ_NONE;
+ VM_PAGE_SETQUEUE2(m, PQ_NONE);
pq = &vm_page_queues[queue];
TAILQ_REMOVE(&pq->pl, m, pageq);
(*pq->cnt)--;
@@ -197,7 +280,7 @@ vm_pageq_remove(vm_page_t m)
}
}
-#if PQ_L2_SIZE > 1
+#ifndef PQ_NOOPT
/*
* vm_pageq_find:
@@ -230,37 +313,44 @@ _vm_pageq_find(int basequeue, int index)
* same place. Even though this is not totally optimal, we've already
* blown it by missing the cache case so we do not care.
*/
- for (i = PQ_L2_SIZE / 2; i > 0; --i) {
- if ((m = TAILQ_FIRST(&pq[(index + i) & PQ_L2_MASK].pl)) != NULL)
+ for (i = PQ_NUMCOLORS / 2; i > 0; --i) {
+ if ((m = TAILQ_FIRST(&pq[(index + i) & PQ_COLORMASK].pl)) \
+ != NULL)
break;
- if ((m = TAILQ_FIRST(&pq[(index - i) & PQ_L2_MASK].pl)) != NULL)
+ if ((m = TAILQ_FIRST(&pq[(index - i) & PQ_COLORMASK].pl)) \
+ != NULL)
break;
}
return (m);
}
-#endif /* PQ_L2_SIZE > 1 */
+#endif /* PQ_NOOPT */
vm_page_t
vm_pageq_find(int basequeue, int index, boolean_t prefer_zero)
{
vm_page_t m;
-#if PQ_L2_SIZE > 1
- if (prefer_zero) {
- m = TAILQ_LAST(&vm_page_queues[basequeue+index].pl, pglist);
- } else {
- m = TAILQ_FIRST(&vm_page_queues[basequeue+index].pl);
- }
- if (m == NULL) {
- m = _vm_pageq_find(basequeue, index);
+#ifndef PQ_NOOPT
+ if (PQ_NUMCOLORS > 1) {
+ if (prefer_zero) {
+ m = TAILQ_LAST(&vm_page_queues[basequeue+index].pl, \
+ pglist);
+ } else {
+ m = TAILQ_FIRST(&vm_page_queues[basequeue+index].pl);
+ }
+ if (m == NULL) {
+ m = _vm_pageq_find(basequeue, index);
+ }
+ } else {
+#endif
+ if (prefer_zero) {
+ m = TAILQ_LAST(&vm_page_queues[basequeue].pl, pglist);
+ } else {
+ m = TAILQ_FIRST(&vm_page_queues[basequeue].pl);
+ }
+#ifndef PQ_NOOPT
}
-#else
- if (prefer_zero) {
- m = TAILQ_LAST(&vm_page_queues[basequeue].pl, pglist);
- } else {
- m = TAILQ_FIRST(&vm_page_queues[basequeue].pl);
- }
#endif
return (m);
}
diff --git a/sys/vm/vm_zeroidle.c b/sys/vm/vm_zeroidle.c
index 46e1c26..68babd0 100644
--- a/sys/vm/vm_zeroidle.c
+++ b/sys/vm/vm_zeroidle.c
@@ -120,7 +120,7 @@ vm_page_zero_idle(void)
if (vm_page_zero_count >= ZIDLE_HI(cnt.v_free_count))
zero_state = 1;
}
- free_rover = (free_rover + PQ_PRIME2) & PQ_L2_MASK;
+ free_rover = (free_rover + PQ_PRIME2) & PQ_COLORMASK;
mtx_unlock_spin(&vm_page_queue_free_mtx);
return (1);
}
OpenPOWER on IntegriCloud