diff options
author | Bob Beck <beck@cvs.openbsd.org> | 2007-08-07 04:32:46 +0000 |
---|---|---|
committer | Bob Beck <beck@cvs.openbsd.org> | 2007-08-07 04:32:46 +0000 |
commit | 2d5b677a9e990c57ed21b7fe0b972373d7258107 (patch) | |
tree | 4ca9ac1a405795b3892be0739623f5c40bd3b5f4 | |
parent | 27ce1dca8fd2447fb99333a0f6166ef7ed8bae7b (diff) |
A few changes to deal with multi-user performance issues seen. this
brings us back roughly to 4.1 level performance, although this is still
far from optimal as we have seen in a number of cases. This change
1) puts a lower bound on buffer cache queues to prevent starvation
2) fixes the code which looks for a buffer to recycle
3) reduces the number of vnodes back to 4.1 levels to avoid complex
performance issues better addressed after 4.2
ok art@ deraadt@, tested by many
-rw-r--r-- | sys/kern/vfs_bio.c | 41 | ||||
-rw-r--r-- | sys/kern/vfs_subr.c | 9 |
2 files changed, 33 insertions, 17 deletions
diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 12896be67a2..d70e8d577c4 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_bio.c,v 1.98 2007/07/09 15:30:25 miod Exp $ */ +/* $OpenBSD: vfs_bio.c,v 1.99 2007/08/07 04:32:45 beck Exp $ */ /* $NetBSD: vfs_bio.c,v 1.44 1996/06/11 11:15:36 pk Exp $ */ /*- @@ -84,6 +84,8 @@ u_long bufhash; TAILQ_HEAD(bqueues, buf) bufqueues[BQUEUES]; +int bqpages[BQUEUES]; /* pages allocated, per queue */ +int bqpagelow; int needbuffer; struct bio_ops bioops; @@ -162,6 +164,7 @@ void bremfree(struct buf *bp) { struct bqueues *dp = NULL; + int queue; /* * We only calculate the head of the freelist when removing @@ -178,9 +181,12 @@ bremfree(struct buf *bp) panic("bremfree: lost tail"); } numfreepages -= btoc(bp->b_bufsize); - if (!ISSET(bp->b_flags, B_DELWRI)) + if (!ISSET(bp->b_flags, B_DELWRI)) { + int qs = bp->b_bufsize; + queue = size2cqueue(&qs); numcleanpages -= btoc(bp->b_bufsize); - else + bqpages[queue] -= btoc(bp->b_bufsize); + } else numdirtypages -= btoc(bp->b_bufsize); TAILQ_REMOVE(dp, bp, b_freelist); } @@ -188,7 +194,7 @@ bremfree(struct buf *bp) void buf_init(struct buf *bp, int size) { - int npages; + int npages, queue; splassert(IPL_BIO); @@ -198,10 +204,12 @@ buf_init(struct buf *bp, int size) bp->b_freelist.tqe_next = NOLIST; bp->b_synctime = time_uptime + 300; bp->b_dev = NODEV; + queue = size2cqueue(&size); LIST_INIT(&bp->b_dep); numbufpages += npages; numfreepages += npages; numcleanpages += npages; + bqpages[queue] += npages; if (maxcleanpages < numcleanpages) maxcleanpages = numcleanpages; } @@ -339,6 +347,12 @@ bufinit(void) buf_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, ptoa(bufpages), 0, FALSE, NULL); + /* + * XXX don't starve any one queue below 5% of the total number + * of buffer cache pages. + */ + bqpagelow = bufpages / 20; + bufhashtbl = hashinit(bufpages / 4, M_CACHE, M_WAITOK, &bufhash); hidirtypages = (bufpages / 4) * 3; lodirtypages = bufpages / 2; @@ -769,6 +783,7 @@ brelse(struct buf *bp) qs = bp->b_bufsize; queue = size2cqueue(&qs); numcleanpages += btoc(bp->b_bufsize); + bqpages[queue] += btoc(bp->b_bufsize); if (maxcleanpages < numcleanpages) maxcleanpages = numcleanpages; binsheadfree(bp, &bufqueues[queue]); @@ -784,6 +799,7 @@ brelse(struct buf *bp) if (!ISSET(bp->b_flags, B_DELWRI)) { numcleanpages += btoc(bp->b_bufsize); + bqpages[queue] += btoc(bp->b_bufsize); if (maxcleanpages < numcleanpages) maxcleanpages = numcleanpages; bufq = &bufqueues[queue]; @@ -960,11 +976,14 @@ getsome: queue = size2cqueue(&qs); bp = buf_get(qs); /* XXX use qs instead and no need in buf_get? */ if (bp == NULL) { - /* no free ones, try to reuse a clean one.. */ - for (bp = TAILQ_FIRST(&bufqueues[queue]); - bp != NULL && queue < BQUEUES; queue++) { - /* XXX */ - } + /* + * No free ones, try to reuse a clean one of the same or + * larger size. + */ + do { + bp = TAILQ_FIRST(&bufqueues[queue]); + queue++; + } while (bp == NULL && queue < BQUEUES); } if (bp == NULL) { /* we couldn't reuse a free one, nothing of the right size */ @@ -975,7 +994,9 @@ getsome: int freemax = 20; for (q = 1; q < BQUEUES; q++) { int i = freemax; - while ((bp = TAILQ_FIRST(&bufqueues[q])) && i--) { + while (bqpages[q] > bqpagelow + && (bp = TAILQ_FIRST(&bufqueues[q])) + && i--) { gotsome++; bremfree(bp); if (LIST_FIRST(&bp->b_dep) != NULL) diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index a8b6aba5047..f39b05bcc05 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_subr.c,v 1.154 2007/06/01 17:29:10 beck Exp $ */ +/* $OpenBSD: vfs_subr.c,v 1.155 2007/08/07 04:32:45 beck Exp $ */ /* $NetBSD: vfs_subr.c,v 1.53 1996/04/22 01:39:13 christos Exp $ */ /* @@ -120,12 +120,7 @@ void vntblinit(void) { /* buffer cache may need a vnode for each buffer */ - /* - * XXX note this is different from desiredvnodes, which is - * XXX the old static value computed from MAXUSERS which is - * XXX used for sizing may other subsystems (namecache, softdeps, etc) - */ - maxvnodes = bufpages; + maxvnodes = desiredvnodes; pool_init(&vnode_pool, sizeof(struct vnode), 0, 0, 0, "vnodes", &pool_allocator_nointr); TAILQ_INIT(&vnode_hold_list); |