Module Name: src Committed By: matt Date: Tue Jan 18 21:43:29 UTC 2011
Modified Files: src/sys/uvm: uvm_page.h uvm_pglist.c Log Message: Improve the efficiency of searching for a contiguous set of free pages. To generate a diff of this commit: cvs rdiff -u -r1.69 -r1.70 src/sys/uvm/uvm_page.h cvs rdiff -u -r1.51 -r1.52 src/sys/uvm/uvm_pglist.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/uvm/uvm_page.h diff -u src/sys/uvm/uvm_page.h:1.69 src/sys/uvm/uvm_page.h:1.70 --- src/sys/uvm/uvm_page.h:1.69 Fri Nov 26 00:45:27 2010 +++ src/sys/uvm/uvm_page.h Tue Jan 18 21:43:29 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: uvm_page.h,v 1.69 2010/11/26 00:45:27 uebayasi Exp $ */ +/* $NetBSD: uvm_page.h,v 1.70 2011/01/18 21:43:29 matt Exp $ */ /* * Copyright (c) 1997 Charles D. Cranor and Washington University. @@ -235,9 +235,11 @@ paddr_t end; /* (PF# of last page in segment) + 1 */ paddr_t avail_start; /* PF# of first free page in segment */ paddr_t avail_end; /* (PF# of last free page in segment) +1 */ - int free_list; /* which free list they belong on */ struct vm_page *pgs; /* vm_page structures (from start) */ struct vm_page *lastpg; /* vm_page structure for end */ + int free_list; /* which free list they belong on */ + u_int start_hint; /* start looking for free pages here */ + /* protected by uvm_fpageqlock */ #ifdef __HAVE_PMAP_PHYSSEG struct pmap_physseg pmseg; /* pmap specific (MD) data */ #endif Index: src/sys/uvm/uvm_pglist.c diff -u src/sys/uvm/uvm_pglist.c:1.51 src/sys/uvm/uvm_pglist.c:1.52 --- src/sys/uvm/uvm_pglist.c:1.51 Thu Nov 25 04:45:30 2010 +++ src/sys/uvm/uvm_pglist.c Tue Jan 18 21:43:29 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: uvm_pglist.c,v 1.51 2010/11/25 04:45:30 uebayasi Exp $ */ +/* $NetBSD: uvm_pglist.c,v 1.52 2011/01/18 21:43:29 matt Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uvm_pglist.c,v 1.51 2010/11/25 04:45:30 uebayasi Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uvm_pglist.c,v 1.52 2011/01/18 21:43:29 matt Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -82,9 +82,6 @@ uvm_pglist_add(struct vm_page *pg, struct pglist *rlist) { int free_list, color, pgflidx; -#ifdef NOT_DEBUG - struct vm_page *tp; -#endif KASSERT(mutex_owned(&uvm_fpageqlock)); @@ -96,10 +93,10 @@ color = VM_PGCOLOR_BUCKET(pg); pgflidx = (pg->flags & PG_ZERO) ? PGFL_ZEROS : PGFL_UNKNOWN; #ifdef NOT_DEBUG - for (tp = LIST_FIRST(&uvm.page_free[ - free_list].pgfl_buckets[color].pgfl_queues[pgflidx]); - tp != NULL; - tp = LIST_NEXT(tp, pageq.list)) { + struct vm_page *tp; + LIST_FOREACH(tp, + &uvm.page_free[free_list].pgfl_buckets[color].pgfl_queues[pgflidx], + pageq.list) { if (tp == pg) break; } @@ -124,9 +121,10 @@ uvm_pglistalloc_c_ps(struct vm_physseg *ps, int num, paddr_t low, paddr_t high, paddr_t alignment, paddr_t boundary, struct pglist *rlist) { - int try, limit, tryidx, end, idx; + signed int try, limit, tryidx, end, idx, skip; struct vm_page *pgs; int pagemask; + bool second_pass; #ifdef DEBUG paddr_t idxpa, lastidxpa; int cidx = 0; /* XXX: GCC */ @@ -138,16 +136,42 @@ KASSERT(mutex_owned(&uvm_fpageqlock)); - try = roundup(max(atop(low), ps->avail_start), atop(alignment)); - limit = min(atop(high), ps->avail_end); + low = atop(low); + high = atop(high); + alignment = atop(alignment); + + /* + * We start our search at the just after where the last allocation + * succeeded. + */ + try = roundup2(max(low, ps->avail_start + ps->start_hint), alignment); + limit = min(high, ps->avail_end); pagemask = ~((boundary >> PAGE_SHIFT) - 1); + skip = 0; + second_pass = false; + pgs = ps->pgs; for (;;) { + bool ok = true; + signed int cnt; + if (try + num > limit) { + if (ps->start_hint == 0 || second_pass) { + /* + * We've run past the allowable range. + */ + return 0; /* FAIL = 0 pages*/ + } /* - * We've run past the allowable range. + * We've wrapped around the end of this segment + * so restart at the beginning but now our limit + * is were we started. */ - return (0); /* FAIL */ + second_pass = true; + try = roundup2(max(low, ps->avail_start), alignment); + limit = min(high, ps->avail_start + ps->start_hint); + skip = 0; + continue; } if (boundary != 0 && ((try ^ (try + num - 1)) & pagemask) != 0) { @@ -156,7 +180,8 @@ * just crossed and ensure alignment. */ try = (try + num - 1) & pagemask; - try = roundup(try, atop(alignment)); + try = roundup2(try, alignment); + skip = 0; continue; } #ifdef DEBUG @@ -175,18 +200,31 @@ #endif tryidx = try - ps->start; end = tryidx + num; - pgs = ps->pgs; /* * Found a suitable starting page. See if the range is free. */ - for (idx = tryidx; idx < end; idx++) { - if (VM_PAGE_IS_FREE(&pgs[idx]) == 0) +#ifdef PGALLOC_VERBOSE + printf("%s: ps=%p try=%#x end=%#x skip=%#x, align=%#x", + __func__, ps, tryidx, end, skip, alignment); +#endif + /* + * We start at the end and work backwards since if we find a + * non-free page, it makes no sense to continue. + * + * But on the plus size we have "vetted" some number of free + * pages. If this iteration fails, we may be able to skip + * testing most of those pages again in the next pass. + */ + for (idx = end - 1; idx >= tryidx + skip; idx--) { + if (VM_PAGE_IS_FREE(&pgs[idx]) == 0) { + ok = false; break; + } #ifdef DEBUG - idxpa = VM_PAGE_TO_PHYS(&pgs[idx]); if (idx > tryidx) { + idxpa = VM_PAGE_TO_PHYS(&pgs[idx]); lastidxpa = VM_PAGE_TO_PHYS(&pgs[idx - 1]); if ((lastidxpa + PAGE_SIZE) != idxpa) { /* @@ -205,23 +243,53 @@ } #endif } - if (idx == end) + + if (ok) { + while (skip-- > 0) { + KDASSERT(VM_PAGE_IS_FREE(&pgs[tryidx + skip])); + } +#ifdef PGALLOC_VERBOSE + printf(": ok\n"); +#endif break; + } - try += atop(alignment); +#ifdef PGALLOC_VERBOSE + printf(": non-free at %#x\n", idx - tryidx); +#endif + /* + * count the number of pages we can advance + * since we know they aren't all free. + */ + cnt = idx + 1 - tryidx; + /* + * now round up that to the needed alignment. + */ + cnt = roundup2(cnt, alignment); + /* + * The number of pages we can skip checking + * (might be 0 if cnt > num). + */ + skip = max(num - cnt, 0); + try += cnt; } /* * we have a chunk of memory that conforms to the requested constraints. */ - idx = tryidx; - while (idx < end) - uvm_pglist_add(&pgs[idx++], rlist); + for (idx = tryidx, pgs += idx; idx < end; idx++, pgs++) + uvm_pglist_add(pgs, rlist); + + /* + * the next time we need to search this segment, start after this + * chunk of pages we just allocated. + */ + ps->start_hint = tryidx + num; #ifdef PGALLOC_VERBOSE printf("got %d pgs\n", num); #endif - return (num); /* number of pages allocated */ + return num; /* number of pages allocated */ } static int @@ -287,6 +355,7 @@ { int todo, limit, try; struct vm_page *pg; + bool second_pass; #ifdef DEBUG int cidx = 0; /* XXX: GCC */ #endif @@ -297,26 +366,45 @@ KASSERT(mutex_owned(&uvm_fpageqlock)); + low = atop(low); + high = atop(high); todo = num; - limit = min(atop(high), ps->avail_end); - - for (try = max(atop(low), ps->avail_start); - try < limit; try ++) { + try = max(low, ps->avail_start + ps->start_hint); + limit = min(high, ps->avail_end); + pg = &ps->pgs[try - ps->start]; + second_pass = false; + + for (;; try++, pg++) { + if (try >= limit) { + if (ps->start_hint == 0 || second_pass) + break; + second_pass = true; + try = max(low, ps->avail_start); + limit = min(high, ps->avail_start + ps->start_hint); + pg = &ps->pgs[try - ps->start]; + continue; + } #ifdef DEBUG if (vm_physseg_find(try, &cidx) != ps - vm_physmem) panic("pgalloc simple: botch1"); if (cidx != (try - ps->start)) panic("pgalloc simple: botch2"); #endif - pg = &ps->pgs[try - ps->start]; if (VM_PAGE_IS_FREE(pg) == 0) continue; uvm_pglist_add(pg, rlist); - if (--todo == 0) + if (--todo == 0) { break; + } } + /* + * The next time we need to search this segment, + * start just after the pages we just allocated. + */ + ps->start_hint = try + 1 - ps->start; + #ifdef PGALLOC_VERBOSE printf("got %d pgs\n", num - todo); #endif @@ -411,7 +499,7 @@ if (boundary != 0 && boundary < size) return (EINVAL); num = atop(round_page(size)); - low = roundup(low, alignment); + low = roundup2(low, alignment); TAILQ_INIT(rlist);