summaryrefslogtreecommitdiffstats
path: root/sys/vm/vm_phys.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2013-08-07 16:36:38 +0000
committerkib <kib@FreeBSD.org>2013-08-07 16:36:38 +0000
commit8de1718b6098ce10c7adafd754331072122d1b3a (patch)
tree958d5d7311cef3751ddc3af3de19306b77bec18d /sys/vm/vm_phys.c
parenta3142db9ac39863c9280f1ec60c165e521b66fd3 (diff)
downloadFreeBSD-src-8de1718b6098ce10c7adafd754331072122d1b3a.zip
FreeBSD-src-8de1718b6098ce10c7adafd754331072122d1b3a.tar.gz
Split the pagequeues per NUMA domains, and split pageademon process
into threads each processing queue in a single domain. The structure of the pagedaemons and queues is kept intact, most of the changes come from the need for code to find an owning page queue for given page, calculated from the segment containing the page. The tie between NUMA domain and pagedaemon thread/pagequeue split is rather arbitrary, the multithreaded daemon could be allowed for the single-domain machines, or one domain might be split into several page domains, to further increase concurrency. Right now, each pagedaemon thread tries to reach the global target, precalculated at the start of the pass. This is not optimal, since it could cause excessive page deactivation and freeing. The code should be changed to re-check the global page deficit state in the loop after some number of iterations. The pagedaemons reach the quorum before starting the OOM, since one thread inability to meet the target is normal for split queues. Only when all pagedaemons fail to produce enough reusable pages, OOM is started by single selected thread. Launder is modified to take into account the segments layout with regard to the region for which cleaning is performed. Based on the preliminary patch by jeff, sponsored by EMC / Isilon Storage Division. Reviewed by: alc Tested by: pho Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'sys/vm/vm_phys.c')
-rw-r--r--sys/vm/vm_phys.c45
1 files changed, 27 insertions, 18 deletions
diff --git a/sys/vm/vm_phys.c b/sys/vm/vm_phys.c
index e55f841..1fa223b 100644
--- a/sys/vm/vm_phys.c
+++ b/sys/vm/vm_phys.c
@@ -65,26 +65,15 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_page.h>
#include <vm/vm_phys.h>
-struct vm_freelist {
- struct pglist pl;
- int lcnt;
-};
-
-struct vm_phys_seg {
- vm_paddr_t start;
- vm_paddr_t end;
- vm_page_t first_page;
- int domain;
- struct vm_freelist (*free_queues)[VM_NFREEPOOL][VM_NFREEORDER];
-};
+_Static_assert(sizeof(long) * NBBY >= VM_PHYSSEG_MAX,
+ "Too many physsegs.");
struct mem_affinity *mem_affinity;
int vm_ndomains = 1;
-static struct vm_phys_seg vm_phys_segs[VM_PHYSSEG_MAX];
-
-static int vm_phys_nsegs;
+struct vm_phys_seg vm_phys_segs[VM_PHYSSEG_MAX];
+int vm_phys_nsegs;
#define VM_PHYS_FICTITIOUS_NSEGS 8
static struct vm_phys_fictitious_seg {
@@ -140,6 +129,22 @@ vm_rr_selectdomain(void)
#endif
}
+boolean_t
+vm_phys_domain_intersects(long mask, vm_paddr_t low, vm_paddr_t high)
+{
+ struct vm_phys_seg *s;
+ int idx;
+
+ while ((idx = ffsl(mask)) != 0) {
+ idx--; /* ffsl counts from 1 */
+ mask &= ~(1UL << idx);
+ s = &vm_phys_segs[idx];
+ if (low < s->end && high > s->start)
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
/*
* Outputs the state of the physical memory allocator, specifically,
* the amount of physical memory in each free list.
@@ -378,12 +383,16 @@ void
vm_phys_add_page(vm_paddr_t pa)
{
vm_page_t m;
+ struct vm_domain *vmd;
cnt.v_page_count++;
m = vm_phys_paddr_to_vm_page(pa);
m->phys_addr = pa;
m->queue = PQ_NONE;
m->segind = vm_phys_paddr_to_segind(pa);
+ vmd = vm_phys_domain(m);
+ vmd->vmd_page_count++;
+ vmd->vmd_segs |= 1UL << m->segind;
m->flags = PG_FREE;
KASSERT(m->order == VM_NFREEORDER,
("vm_phys_add_page: page %p has unexpected order %d",
@@ -391,7 +400,7 @@ vm_phys_add_page(vm_paddr_t pa)
m->pool = VM_FREEPOOL_DEFAULT;
pmap_page_init(m);
mtx_lock(&vm_page_queue_free_mtx);
- cnt.v_free_count++;
+ vm_phys_freecnt_adj(m, 1);
vm_phys_free_pages(m, 0);
mtx_unlock(&vm_page_queue_free_mtx);
}
@@ -813,12 +822,12 @@ vm_phys_zero_pages_idle(void)
for (m_tmp = m; m_tmp < &m[1 << oind]; m_tmp++) {
if ((m_tmp->flags & (PG_CACHED | PG_ZERO)) == 0) {
vm_phys_unfree_page(m_tmp);
- cnt.v_free_count--;
+ vm_phys_freecnt_adj(m, -1);
mtx_unlock(&vm_page_queue_free_mtx);
pmap_zero_page_idle(m_tmp);
m_tmp->flags |= PG_ZERO;
mtx_lock(&vm_page_queue_free_mtx);
- cnt.v_free_count++;
+ vm_phys_freecnt_adj(m, 1);
vm_phys_free_pages(m_tmp, 0);
vm_page_zero_count++;
cnt_prezero++;
OpenPOWER on IntegriCloud