Module Name:    src
Committed By:   matt
Date:           Fri Jan 22 05:17:32 UTC 2010

Modified Files:
        src/sys/uvm [matt-nb5-mips64]: uvm_pglist.c

Log Message:
Rework the algorithm to allocate contiguous pages to be much much faster.
(read the comments if you want to know how it's done).


To generate a diff of this commit:
cvs rdiff -u -r1.42 -r1.42.16.1 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_pglist.c
diff -u src/sys/uvm/uvm_pglist.c:1.42 src/sys/uvm/uvm_pglist.c:1.42.16.1
--- src/sys/uvm/uvm_pglist.c:1.42	Wed Jun  4 12:45:28 2008
+++ src/sys/uvm/uvm_pglist.c	Fri Jan 22 05:17:32 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: uvm_pglist.c,v 1.42 2008/06/04 12:45:28 ad Exp $	*/
+/*	$NetBSD: uvm_pglist.c,v 1.42.16.1 2010/01/22 05:17:32 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.42 2008/06/04 12:45:28 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_pglist.c,v 1.42.16.1 2010/01/22 05:17:32 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 DEBUG
-	struct vm_page *tp;
-#endif
 
 	KASSERT(mutex_owned(&uvm_fpageqlock));
 
@@ -95,11 +92,11 @@
 	free_list = uvm_page_lookup_freelist(pg);
 	color = VM_PGCOLOR_BUCKET(pg);
 	pgflidx = (pg->flags & PG_ZERO) ? PGFL_ZEROS : PGFL_UNKNOWN;
-#ifdef DEBUG
-	for (tp = LIST_FIRST(&uvm.page_free[
-		free_list].pgfl_buckets[color].pgfl_queues[pgflidx]);
-	     tp != NULL;
-	     tp = LIST_NEXT(tp, pageq.list)) {
+#if defined(DEBUG) && DEBUG > 1
+	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,7 +121,8 @@
 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;
+	const signed int align = atop(alignment);
 	struct vm_page *pgs;
 	int pagemask;
 #ifdef DEBUG
@@ -138,11 +136,15 @@
 
 	KASSERT(mutex_owned(&uvm_fpageqlock));
 
-	try = roundup(max(atop(low), ps->avail_start), atop(alignment));
+	try = roundup(max(atop(low), ps->avail_start), align);
 	limit = min(atop(high), ps->avail_end);
 	pagemask = ~((boundary >> PAGE_SHIFT) - 1);
+	skip = 0;
 
 	for (;;) {
+		bool ok = true;
+		int cnt;
+
 		if (try + num > limit) {
 			/*
 			 * We've run past the allowable range.
@@ -156,7 +158,7 @@
 			 * just crossed and ensure alignment.
 			 */
 			try = (try + num - 1) & pagemask;
-			try = roundup(try, atop(alignment));
+			try = roundup(try, align);
 			continue;
 		}
 #ifdef DEBUG
@@ -180,9 +182,42 @@
 		/*
 		 * 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, align);
+#endif
+		/*
+		 * Test both the ending and starting pages to see if they are
+		 * both free.  If the ending and starting pages are same page,
+		 * we only test one of them.  If the pages aren't free, there
+		 * is no reason to continue this iteration so advance to the
+		 * next address and try again.
+		 */
+		if (VM_PAGE_IS_FREE(&pgs[end - 1]) == 0
+		    || end - 1 == tryidx + skip
+		    || VM_PAGE_IS_FREE(&pgs[tryidx + skip]) == 0) {
+			try += roundup(num, align);
+			skip = 0;
+			continue;
+		}
+
+		/*
+		 * We start at the end since if we find a non-free page, it
+		 * make no sense to ever test any pages before it since the
+		 * conditions for this allocation could never be satisified.
+		 *
+		 * Also since we have "vetted" these free pages, if this
+		 * iteration fails, we may be able to skip testing those pages
+		 * in the next iteration.
+		 *
+		 * The loop condition will never be satisfied if we've already
+		 * found enough pages (either one or two).
+		 */
+		for (idx = end - 2; idx >= tryidx + skip + 1; idx--) {
+			if (VM_PAGE_IS_FREE(&pgs[idx]) == 0) {
+				ok = false;
 				break;
+			}
 
 #ifdef DEBUG
 			idxpa = VM_PAGE_TO_PHYS(&pgs[idx]);
@@ -205,18 +240,42 @@
 			}
 #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 = roundup(cnt, align);
+		/*
+		 * The number of pages we can skip checking 
+		 * (might be 0 is 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);
 
 #ifdef PGALLOC_VERBOSE
 	printf("got %d pgs\n", num);

Reply via email to