summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2015-04-07 11:07:57 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2015-04-07 11:07:57 +0000
commit6d4418247995c8e872eb2c0d2acadb3aac1928c5 (patch)
tree5de5f9cf8f496cb9189f269d9097a12d2510ef3b /sys/kern
parent50b457b005282f284d4f1bdb343b37fc168f84ce (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.c8
-rw-r--r--sys/kern/subr_pool.c55
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.
*/