diff options
author | netchild <netchild@FreeBSD.org> | 2005-12-31 14:39:20 +0000 |
---|---|---|
committer | netchild <netchild@FreeBSD.org> | 2005-12-31 14:39:20 +0000 |
commit | 507a9b3e936156202e89c42d2265863c3903254f (patch) | |
tree | c13a8d302e0337dbf08ab02516a66627814ead6b /sys/vm | |
parent | cd697cab850aef4c7941ebff10521fc87dbf7aee (diff) | |
download | FreeBSD-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.c | 11 | ||||
-rw-r--r-- | sys/vm/vm_fault.c | 5 | ||||
-rw-r--r-- | sys/vm/vm_object.c | 19 | ||||
-rw-r--r-- | sys/vm/vm_page.c | 42 | ||||
-rw-r--r-- | sys/vm/vm_page.h | 115 | ||||
-rw-r--r-- | sys/vm/vm_pageout.c | 12 | ||||
-rw-r--r-- | sys/vm/vm_pageq.c | 152 | ||||
-rw-r--r-- | sys/vm/vm_zeroidle.c | 2 |
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); } |