diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2015-04-07 11:07:57 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2015-04-07 11:07:57 +0000 |
commit | 6d4418247995c8e872eb2c0d2acadb3aac1928c5 (patch) | |
tree | 5de5f9cf8f496cb9189f269d9097a12d2510ef3b /sys/kern | |
parent | 50b457b005282f284d4f1bdb343b37fc168f84ce (diff) |
introduce a garbage collector for (very) idle pool pages.
now that idle pool pages are timestamped we can tell how long theyve
been idle. this adds a task that runs every second that iterates
over all the pools looking for pages that have been idle for 8
seconds so it can free them.
this idea probably came from a conversation with tedu@ months ago.
ok tedu@ kettenis@
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/init_main.c | 8 | ||||
-rw-r--r-- | sys/kern/subr_pool.c | 55 |
2 files changed, 60 insertions, 3 deletions
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index ded66b1cfd8..3446df6f8ec 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: init_main.c,v 1.235 2015/02/10 05:28:18 guenther Exp $ */ +/* $OpenBSD: init_main.c,v 1.236 2015/04/07 11:07:56 dlg Exp $ */ /* $NetBSD: init_main.c,v 1.84.4.1 1996/06/02 09:08:06 mrg Exp $ */ /* @@ -147,6 +147,7 @@ void crypto_init(void); void init_exec(void); void kqueue_init(void); void taskq_init(void); +void pool_gc_pages(void *); extern char sigcode[], esigcode[]; #ifdef SYSCALL_DEBUG @@ -549,6 +550,11 @@ main(void *framep) timeout_set(&setperf_to, setperf_auto, NULL); #endif + /* + * Start the idle pool page garbage collector + */ + pool_gc_pages(NULL); + /* * proc0: nothing to do, back to sleep */ diff --git a/sys/kern/subr_pool.c b/sys/kern/subr_pool.c index 1dd260024e8..c160f5e59fa 100644 --- a/sys/kern/subr_pool.c +++ b/sys/kern/subr_pool.c @@ -1,4 +1,4 @@ -/* $OpenBSD: subr_pool.c,v 1.182 2015/03/20 11:33:17 dlg Exp $ */ +/* $OpenBSD: subr_pool.c,v 1.183 2015/04/07 11:07:56 dlg Exp $ */ /* $NetBSD: subr_pool.c,v 1.61 2001/09/26 07:14:56 chs Exp $ */ /*- @@ -40,6 +40,8 @@ #include <sys/syslog.h> #include <sys/rwlock.h> #include <sys/sysctl.h> +#include <sys/task.h> +#include <sys/timeout.h> #include <uvm/uvm_extern.h> @@ -161,6 +163,14 @@ void pool_print1(struct pool *, const char *, int (*)(const char *, ...) #define pool_sleep(pl) msleep(pl, &pl->pr_mtx, PSWP, pl->pr_wchan, 0) +/* stale page garbage collectors */ +void pool_gc_sched(void *); +struct timeout pool_gc_tick = TIMEOUT_INITIALIZER(pool_gc_sched, NULL); +void pool_gc_pages(void *); +struct task pool_gc_task = TASK_INITIALIZER(pool_gc_pages, NULL); +int pool_wait_free = 1; +int pool_wait_gc = 8; + static inline int phtree_compare(struct pool_item_header *a, struct pool_item_header *b) { @@ -691,7 +701,7 @@ pool_put(struct pool *pp, void *v) /* is it time to free a page? */ if (pp->pr_nidle > pp->pr_maxpages && (ph = TAILQ_FIRST(&pp->pr_emptypages)) != NULL && - (ticks - ph->ph_tick) > hz) { + (ticks - ph->ph_tick) > (hz * pool_wait_free)) { freeph = ph; pool_p_remove(pp, freeph); } @@ -1351,6 +1361,47 @@ done: return (rv); } +void +pool_gc_sched(void *null) +{ + task_add(systqmp, &pool_gc_task); +} + +void +pool_gc_pages(void *null) +{ + extern int ticks; + struct pool *pp; + struct pool_item_header *ph, *freeph; + int s; + + rw_enter_read(&pool_lock); + s = splvm(); /* XXX go to splvm until all pools _setipl properly */ + SIMPLEQ_FOREACH(pp, &pool_head, pr_poollist) { + if (pp->pr_nidle <= pp->pr_minpages || /* guess */ + !mtx_enter_try(&pp->pr_mtx)) /* try */ + continue; + + /* is it time to free a page? */ + if (pp->pr_nidle > pp->pr_minpages && + (ph = TAILQ_FIRST(&pp->pr_emptypages)) != NULL && + (ticks - ph->ph_tick) > (hz * pool_wait_gc)) { + freeph = ph; + pool_p_remove(pp, freeph); + } else + freeph = NULL; + + mtx_leave(&pp->pr_mtx); + + if (freeph != NULL) + pool_p_free(pp, freeph); + } + splx(s); + rw_exit_read(&pool_lock); + + timeout_add_sec(&pool_gc_tick, 1); +} + /* * Pool backend allocators. */ |